[MM-62724] Refresh error page screen to match branding, remove react-bootstrap (#3300)

* [MM-62724] Refresh error page screen to match branding, remove react-bootstrap

* Fix links on error page to open externally

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
This commit is contained in:
Devin Binnie
2025-01-31 10:26:24 -05:00
committed by GitHub
parent d7d851a480
commit 17300dfd4a
14 changed files with 255 additions and 188 deletions

View File

@@ -165,12 +165,13 @@
"renderer.components.configureServer.url.urlUpdated": "The server URL provided has been updated to match the configured Site URL on your Mattermost server. Server version: {serverVersion}",
"renderer.components.configureServer.url.validating": "Validating...",
"renderer.components.developerModeIndicator.tooltip": "Developer mode is enabled. You should only have this enabled if a Mattermost developer has instructed you to.",
"renderer.components.errorView.cannotConnectToAppName": "Cannot connect to {appName}",
"renderer.components.errorView.havingTroubleConnecting": "We're having trouble connecting to {appName}. We'll continue to try and establish a connection.",
"renderer.components.errorView.refreshThenVerify": "If refreshing this page (Ctrl+R or Command+R) does not work please verify that:",
"renderer.components.errorView.troubleshooting.computerIsConnected": "Your computer is connected to the internet.",
"renderer.components.errorView.troubleshooting.urlIsCorrect.appNameIsCorrect": "The {appName} URL <link>{url}</link> is correct",
"renderer.components.errorView.troubleshooting.webContentsView.canReachFromBrowserWindow": "You can reach <link>{url}</link> from a browser window.",
"renderer.components.errorView.cannotConnectToThisServer": "Couldn't connect to this server",
"renderer.components.errorView.contactAdmin": "If the issue persists, please contact your admin",
"renderer.components.errorView.havingTroubleConnecting": "We're having trouble connecting to this {appName} server. We'll keep trying to establish a connection.",
"renderer.components.errorView.refreshThenVerify": "If refreshing this page (Ctrl+R or Command+R) doesn't help, please check the following:",
"renderer.components.errorView.troubleshooting.computerIsConnected": "Ensure your computer is connected to the internet.",
"renderer.components.errorView.troubleshooting.urlIsCorrect.appNameIsCorrect": "Verify that the URL <link>{url}</link> is correct.",
"renderer.components.errorView.troubleshooting.webContentsView.canReachFromBrowserWindow": "Try opening <link>{url}</link> in a browser window.",
"renderer.components.input.required": "This field is required",
"renderer.components.mainPage.contextMenu.ariaLabel": "Context menu",
"renderer.components.mainPage.titleBar": "{appName}",

View File

@@ -101,7 +101,7 @@ export const UPDATE_PATHS = 'update-paths';
export const UPDATE_URL_VIEW_WIDTH = 'update-url-view-width';
export const RELOAD_CURRENT_VIEW = 'reload-current-view';
export const OPEN_SERVER_EXTERNALLY = 'open-server-externally';
export const PING_DOMAIN = 'ping-domain';

View File

@@ -17,7 +17,7 @@ import {
EXIT_FULLSCREEN,
DOUBLE_CLICK_ON_WINDOW,
FOCUS_BROWSERVIEW,
RELOAD_CURRENT_VIEW,
OPEN_SERVER_EXTERNALLY,
CLOSE_DOWNLOADS_DROPDOWN,
CLOSE_DOWNLOADS_DROPDOWN_MENU,
OPEN_DOWNLOADS_DROPDOWN,
@@ -119,7 +119,7 @@ contextBridge.exposeInMainWorld('desktop', {
exitFullScreen: () => ipcRenderer.send(EXIT_FULLSCREEN),
doubleClickOnWindow: (windowName) => ipcRenderer.send(DOUBLE_CLICK_ON_WINDOW, windowName),
focusCurrentView: () => ipcRenderer.send(FOCUS_BROWSERVIEW),
reloadCurrentView: () => ipcRenderer.send(RELOAD_CURRENT_VIEW),
openServerExternally: () => ipcRenderer.send(OPEN_SERVER_EXTERNALLY),
closeDownloadsDropdown: () => ipcRenderer.send(CLOSE_DOWNLOADS_DROPDOWN),
closeDownloadsDropdownMenu: () => ipcRenderer.send(CLOSE_DOWNLOADS_DROPDOWN_MENU),
openDownloadsDropdown: () => ipcRenderer.send(OPEN_DOWNLOADS_DROPDOWN),

View File

@@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import type {IpcMainEvent, IpcMainInvokeEvent} from 'electron';
import {WebContentsView, ipcMain} from 'electron';
import {WebContentsView, ipcMain, shell} from 'electron';
import isDev from 'electron-is-dev';
import ServerViewState from 'app/serverViewState';
@@ -18,7 +18,7 @@ import {
UPDATE_URL_VIEW_WIDTH,
SERVERS_UPDATE,
REACT_APP_INITIALIZED,
RELOAD_CURRENT_VIEW,
OPEN_SERVER_EXTERNALLY,
HISTORY,
GET_VIEW_INFO_FOR_TEST,
SESSION_EXPIRED,
@@ -81,7 +81,7 @@ export class ViewManager {
ipcMain.on(REACT_APP_INITIALIZED, this.handleReactAppInitialized);
ipcMain.on(BROWSER_HISTORY_PUSH, this.handleBrowserHistoryPush);
ipcMain.on(TAB_LOGIN_CHANGED, this.handleTabLoginChanged);
ipcMain.on(RELOAD_CURRENT_VIEW, this.handleReloadCurrentView);
ipcMain.on(OPEN_SERVER_EXTERNALLY, this.handleOpenServerExternally);
ipcMain.on(UNREADS_AND_MENTIONS, this.handleUnreadsAndMentionsChanged);
ipcMain.on(SESSION_EXPIRED, this.handleSessionExpired);
@@ -559,15 +559,14 @@ export class ViewManager {
}
};
private handleReloadCurrentView = () => {
log.debug('handleReloadCurrentView');
private handleOpenServerExternally = () => {
log.debug('handleOpenServerExternally');
const view = this.getCurrentView();
if (!view) {
return;
}
view?.reload();
this.showById(view?.id);
shell.openExternal(view.view.server.url.toString());
};
private handleUnreadsAndMentionsChanged = (e: IpcMainEvent, isUnread: boolean, mentionCount: number) => {

View File

@@ -4,61 +4,36 @@
// ErrorCode: https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h
import classNames from 'classnames';
import React from 'react';
import {Container, Row, Col} from 'react-bootstrap';
import {FormattedMessage} from 'react-intl';
// TODO: Will remove in https://mattermost.atlassian.net/browse/MM-62724
import 'bootstrap/dist/css/bootstrap.min.css';
import AlertImage from './Images/alert';
import 'renderer/css/components/ErrorView.scss';
type Props = {
darkMode: boolean;
errorInfo?: string;
url?: string;
id?: string;
active?: boolean;
appName?: string;
handleLink: () => void;
};
export default function ErrorView(props: Props) {
const classNames = ['container', 'ErrorView'];
if (!props.active) {
classNames.push('ErrorView-hidden');
}
return (
<Container
id={props.id}
>
<div className='ErrorView-table'>
<div className='ErrorView-cell'>
<Row>
<Col
xs={0}
sm={1}
md={1}
lg={2}
/>
<Col
xs={12}
sm={10}
md={10}
lg={8}
>
<h2>
<div className={classNames('ErrorView', {darkMode: props.darkMode})}>
<AlertImage/>
<span className='ErrorView-header'>
<FormattedMessage
id='renderer.components.errorView.cannotConnectToAppName'
defaultMessage='Cannot connect to {appName}'
values={{
appName: props.appName,
}}
id='renderer.components.errorView.cannotConnectToThisServer'
defaultMessage="Couldn't connect to this server"
/>
</h2>
<hr/>
<p>
</span>
<span>
<FormattedMessage
id='renderer.components.errorView.havingTroubleConnecting'
defaultMessage={'We\'re having trouble connecting to {appName}. We\'ll continue to try and establish a connection.'}
defaultMessage={'We\'re having trouble connecting to this {appName} server. We\'ll keep trying to establish a connection.'}
values={{
appName: props.appName,
}}
@@ -66,26 +41,25 @@ export default function ErrorView(props: Props) {
<br/>
<FormattedMessage
id='renderer.components.errorView.refreshThenVerify'
defaultMessage='If refreshing this page (Ctrl+R or Command+R) does not work please verify that:'
defaultMessage="If refreshing this page (Ctrl+R or Command+R) doesn't help, please check the following:"
/>
</p>
</span>
<ul className='ErrorView-bullets'>
<li>
<FormattedMessage
id='renderer.components.errorView.troubleshooting.computerIsConnected'
defaultMessage='Your computer is connected to the internet.'
defaultMessage='Ensure your computer is connected to the internet.'
/>
</li>
<li>
<FormattedMessage
id='renderer.components.errorView.troubleshooting.urlIsCorrect.appNameIsCorrect'
defaultMessage='The {appName} URL <link>{url}</link> is correct'
defaultMessage='Verify that the URL <link>{url}</link> is correct.'
values={{
appName: props.appName,
url: props.url,
link: (msg: React.ReactNode) => (
<a
onClick={props.handleLink}
href='#'
>
@@ -98,12 +72,11 @@ export default function ErrorView(props: Props) {
<li>
<FormattedMessage
id='renderer.components.errorView.troubleshooting.webContentsView.canReachFromBrowserWindow'
defaultMessage='You can reach <link>{url}</link> from a browser window.'
defaultMessage='Try opening <link>{url}</link> in a browser window.'
values={{
url: props.url,
link: (msg: React.ReactNode) => (
<a
onClick={props.handleLink}
href='#'
>
@@ -114,20 +87,15 @@ export default function ErrorView(props: Props) {
/>
</li>
</ul>
<br/>
<div className='ErrorView-techInfo'>
{props.errorInfo}
</div>
</Col>
<Col
xs={0}
sm={1}
md={1}
lg={2}
<span>
<FormattedMessage
id='renderer.components.errorView.contactAdmin'
defaultMessage='If the issue persists, please contact your admin'
/>
</Row>
</span>
<span className='ErrorView-techInfo'>
{props.errorInfo}
</span>
</div>
</div>
</Container>
);
}

View File

@@ -0,0 +1,76 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
const AlertImage = () => (
<svg
width='133'
height='106'
viewBox='0 0 87 70'
fill='none'
xmlns='http://www.w3.org/2000/svg'
>
<rect
x='8.00098'
y='7'
width='72'
height='24'
rx='3.75'
fill='var(--button-bg)'
fillOpacity='0.12'
/>
<rect
x='0.000976562'
y='34'
width='87'
height='25'
rx='3.75'
fill='var(--button-bg)'
fillOpacity='0.12'
/>
<path
d='M38.3214 2.31098C39.4303 0.112261 42.5697 0.112256 43.6786 2.31098L71.7146 57.899C72.7209 59.8943 71.2707 62.25 69.0359 62.25H12.9641C10.7294 62.25 9.27912 59.8943 10.2854 57.899L38.3214 2.31098Z'
fill='var(--center-channel-bg)'
/>
<path
d='M40.3214 4.31098C41.4303 2.11226 44.5697 2.11226 45.6786 4.31098L73.7146 59.899C74.7209 61.8943 73.2707 64.25 71.0359 64.25H14.9641C12.7294 64.25 11.2791 61.8943 12.2854 59.899L40.3214 4.31098Z'
fill='#FFBC1F'
/>
<path
d='M43.2322 2.53614L71.2681 58.1242C72.1067 59.7869 70.8982 61.75 69.0359 61.75H12.9641C11.1018 61.75 9.89327 59.7869 10.7319 58.1242L38.7678 2.53614C39.6919 0.703873 42.3081 0.703871 43.2322 2.53614Z'
stroke='var(--center-channel-color)'
/>
<path
d='M49.542 4.23999L52.8888 10.72M74.922 53.38L68.5073 40.96L66.8339 37.72L64.6027 33.4L61.5348 27.46M59.3036 23.14L55.12 15.04'
stroke='var(--center-channel-color)'
strokeOpacity='0.56'
strokeWidth='1.08'
strokeLinecap='round'
/>
<path
d='M38.0164 25.2833L40.2971 39.9301C40.3191 40.2208 40.4554 40.4927 40.6786 40.6912C40.9018 40.8897 41.1954 41 41.5002 41C41.8051 41 42.0986 40.8897 42.3219 40.6912C42.5451 40.4927 42.6814 40.2208 42.7034 39.9301L44.984 25.2833C45.3987 19.5722 37.5955 19.5722 38.0164 25.2833Z'
fill='#3F4350'
/>
<path
d='M41.0072 47C41.798 47.0014 42.5706 47.2372 43.2275 47.6776C43.8843 48.118 44.396 48.7432 44.6976 49.4742C44.9993 50.2053 45.0774 51.0093 44.9222 51.7848C44.7671 52.5602 44.3856 53.2723 43.8259 53.831C43.2662 54.3897 42.5535 54.7699 41.7777 54.9237C41.002 55.0774 40.1981 54.9978 39.4676 54.6948C38.7371 54.3919 38.1128 53.8792 37.6736 53.2215C37.2344 52.5639 37 51.7908 37 51C37 50.4741 37.1036 49.9534 37.3051 49.4676C37.5066 48.9818 37.8019 48.5406 38.1741 48.169C38.5463 47.7975 38.9881 47.503 39.4743 47.3024C39.9604 47.1018 40.4813 46.9991 41.0072 47Z'
fill='#3F4350'
/>
<path
d='M48.4619 68.5H70.0619'
stroke='var(--center-channel-color)'
strokeOpacity='0.56'
strokeWidth='1.08'
strokeLinecap='round'
/>
<path
d='M10.001 50L26.001 19'
stroke='var(--center-channel-color)'
strokeOpacity='0.56'
strokeWidth='1.08'
strokeLinecap='round'
/>
</svg>
);
export default AlertImage;

View File

@@ -20,6 +20,7 @@ import TabBar from './TabBar';
import {playSound} from '../notificationSounds';
import '../css/components/UpgradeButton.scss';
import '../css/components/MainPage.css';
enum Status {
LOADING = 1,
@@ -343,10 +344,6 @@ class MainPage extends React.PureComponent<Props, State> {
this.handleCloseDropdowns();
};
reloadCurrentView = () => {
window.desktop.reloadCurrentView();
};
showHideDownloadsBadge(value = false) {
this.setState({showDownloadsBadge: value});
}
@@ -374,6 +371,10 @@ class MainPage extends React.PureComponent<Props, State> {
});
};
openServerExternally = () => {
window.desktop.openServerExternally();
};
render() {
const {intl} = this.props;
let currentTabs: UniqueView[] = [];
@@ -507,12 +508,11 @@ class MainPage extends React.PureComponent<Props, State> {
case Status.FAILED:
component = (
<ErrorView
id={activeServer.name + '-fail'}
darkMode={this.props.darkMode}
errorInfo={tabStatus.extra?.error}
url={tabStatus.extra ? tabStatus.extra.url : ''}
active={true}
appName={this.props.appName}
handleLink={this.reloadCurrentView}
handleLink={this.openServerExternally}
/>);
break;
case Status.LOADING:
@@ -525,7 +525,7 @@ class MainPage extends React.PureComponent<Props, State> {
const viewsRow = (
<Fragment>
<div>
<div className={classNames('MainPage__body', {darkMode: this.props.darkMode})}>
{views()}
</div>
</Fragment>);
@@ -535,11 +535,9 @@ class MainPage extends React.PureComponent<Props, State> {
className='MainPage'
onClick={this.focusOnWebView}
>
<div>
{topRow}
{viewsRow}
</div>
</div>
);
}
}

View File

@@ -69,7 +69,7 @@
--mention-highlight-link: #1b1d22;
}
.LoadingScreen--darkMode {
.LoadingScreen--darkMode, .ErrorView.darkMode {
/* Onyx - used for dark mode*/
--away-indicator-rgb: 245, 171, 0;
--button-bg-rgb: 74, 124, 232;

View File

@@ -1,36 +0,0 @@
.ErrorView {
position: absolute;
top: 32px;
right: 0px;
bottom: 0px;
left: 0px;
}
.ErrorView-hidden {
visibility: hidden;
}
.ErrorView-tableStyle {
display: table;
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
.ErrorView-cellStyle {
display: table-cell;
vertical-align: top;
padding-top: 2em;
}
.ErrorView-bullets {
padding-left: 15px;
line-height: 1.7;
}
.ErrorView-techInfo {
font-size: 12px;
color: #aaa;
}

View File

@@ -0,0 +1,52 @@
@use 'sass:color';
@import url("../_css_variables.scss");
@import url("../fonts.css");
.ErrorView {
color: var(--center-channel-color);
font-family: 'Open Sans';
font-size: 14px;
line-height: 20px;
display: flex;
max-width: 672px;
flex-direction: column;
margin-top: -40px;
a {
color: var(--link-color);
text-decoration: none;
&:hover, &:focus {
filter: brightness(90%);
}
}
.ErrorView-header {
font-family: 'Metropolis';
font-style: normal;
font-weight: 600;
font-size: 40px;
line-height: 48px;
letter-spacing: -0.02em;
}
> span {
margin-top: 16px;
}
.ErrorView-bullets {
margin-top: 8px;
margin-bottom: 0;
padding-inline-start: 18px;
> li {
margin-top: 8px;
margin-bottom: 0;
}
}
.ErrorView-techInfo {
color: rgba(var(--center-channel-color-rgb), 0.56);
}
}

View File

@@ -1,13 +1,18 @@
/*.mainPage,.mainPage > .container-fluid, .mainPage-viewsRow {
.MainPage {
display: flex;
flex-direction: column;
height: 100%;
}*/
.MainPage .HoveringURL {
max-width: 95%;
position: absolute;
bottom: 0px;
}
div[id*="-permissionDialog"] {
max-width: 350px;
.MainPage__body {
display: flex;
align-items: center;
justify-content: center;
flex: 1;
background-size: cover;
background-image: url('renderer/assets/svg/background-light.svg');
}
.MainPage__body.darkMode {
background-image: url('renderer/assets/svg/background-dark.svg');
}

View File

@@ -1,4 +1,3 @@
@import url("ErrorView.css");
@import url("HoveringURL.css");
@import url("MainPage.css");
@import url("MattermostView.css");

View File

@@ -10,6 +10,10 @@ body {
min-height: 100%;
}
#app {
height: 100vh;
}
.hovering-enter {
opacity: 0.01;
}
@@ -39,6 +43,7 @@ body {
.topBar {
height: 40px;
z-index: 9;
}
.topBar>.topBar-bg {

View File

@@ -37,7 +37,7 @@ declare global {
exitFullScreen: () => void;
doubleClickOnWindow: (windowName?: string) => void;
focusCurrentView: () => void;
reloadCurrentView: () => void;
openServerExternally: () => void;
closeDownloadsDropdown: () => void;
closeDownloadsDropdownMenu: () => void;
openDownloadsDropdown: () => void;