From 17300dfd4a87a5bec8752777c9645cd4d8c8f7b6 Mon Sep 17 00:00:00 2001 From: Devin Binnie <52460000+devinbinnie@users.noreply.github.com> Date: Fri, 31 Jan 2025 10:26:24 -0500 Subject: [PATCH] [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 --- i18n/en.json | 13 +- src/common/communication.ts | 2 +- src/main/preload/internalAPI.js | 4 +- src/main/views/viewManager.ts | 13 +- src/renderer/components/ErrorView.tsx | 192 +++++++++------------ src/renderer/components/Images/alert.tsx | 76 ++++++++ src/renderer/components/MainPage.tsx | 22 ++- src/renderer/css/_css_variables.scss | 2 +- src/renderer/css/components/ErrorView.css | 36 ---- src/renderer/css/components/ErrorView.scss | 52 ++++++ src/renderer/css/components/MainPage.css | 23 ++- src/renderer/css/components/index.css | 1 - src/renderer/css/index.css | 5 + src/types/window.ts | 2 +- 14 files changed, 255 insertions(+), 188 deletions(-) create mode 100644 src/renderer/components/Images/alert.tsx delete mode 100644 src/renderer/css/components/ErrorView.css create mode 100644 src/renderer/css/components/ErrorView.scss diff --git a/i18n/en.json b/i18n/en.json index 1bccff51..d0c4555e 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -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 {url} is correct", - "renderer.components.errorView.troubleshooting.webContentsView.canReachFromBrowserWindow": "You can reach {url} 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 {url} is correct.", + "renderer.components.errorView.troubleshooting.webContentsView.canReachFromBrowserWindow": "Try opening {url} in a browser window.", "renderer.components.input.required": "This field is required", "renderer.components.mainPage.contextMenu.ariaLabel": "Context menu", "renderer.components.mainPage.titleBar": "{appName}", diff --git a/src/common/communication.ts b/src/common/communication.ts index 5d41cc72..71109655 100644 --- a/src/common/communication.ts +++ b/src/common/communication.ts @@ -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'; diff --git a/src/main/preload/internalAPI.js b/src/main/preload/internalAPI.js index caf1fe21..1d8aefc1 100644 --- a/src/main/preload/internalAPI.js +++ b/src/main/preload/internalAPI.js @@ -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), diff --git a/src/main/views/viewManager.ts b/src/main/views/viewManager.ts index 0eae9689..d7bb9571 100644 --- a/src/main/views/viewManager.ts +++ b/src/main/views/viewManager.ts @@ -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) => { diff --git a/src/renderer/components/ErrorView.tsx b/src/renderer/components/ErrorView.tsx index dfa0f8cd..06ab5fec 100644 --- a/src/renderer/components/ErrorView.tsx +++ b/src/renderer/components/ErrorView.tsx @@ -4,130 +4,98 @@ // 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 ( - -
-
- - - -

- -

-
-

- -
- -

- -
-
- {props.errorInfo} -
- - -
-
-
-
+
+ + + + + + +
+ +
+ + + + + + {props.errorInfo} + +
); } diff --git a/src/renderer/components/Images/alert.tsx b/src/renderer/components/Images/alert.tsx new file mode 100644 index 00000000..7999b84d --- /dev/null +++ b/src/renderer/components/Images/alert.tsx @@ -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 = () => ( + + + + + + + + + + + + +); + +export default AlertImage; diff --git a/src/renderer/components/MainPage.tsx b/src/renderer/components/MainPage.tsx index 72500cc1..7cbb0bfb 100644 --- a/src/renderer/components/MainPage.tsx +++ b/src/renderer/components/MainPage.tsx @@ -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 { this.handleCloseDropdowns(); }; - reloadCurrentView = () => { - window.desktop.reloadCurrentView(); - }; - showHideDownloadsBadge(value = false) { this.setState({showDownloadsBadge: value}); } @@ -374,6 +371,10 @@ class MainPage extends React.PureComponent { }); }; + openServerExternally = () => { + window.desktop.openServerExternally(); + }; + render() { const {intl} = this.props; let currentTabs: UniqueView[] = []; @@ -507,12 +508,11 @@ class MainPage extends React.PureComponent { case Status.FAILED: component = ( ); break; case Status.LOADING: @@ -525,7 +525,7 @@ class MainPage extends React.PureComponent { const viewsRow = ( -
+
{views()}
); @@ -535,10 +535,8 @@ class MainPage extends React.PureComponent { className='MainPage' onClick={this.focusOnWebView} > -
- {topRow} - {viewsRow} -
+ {topRow} + {viewsRow}
); } diff --git a/src/renderer/css/_css_variables.scss b/src/renderer/css/_css_variables.scss index 50c09086..25065709 100644 --- a/src/renderer/css/_css_variables.scss +++ b/src/renderer/css/_css_variables.scss @@ -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; diff --git a/src/renderer/css/components/ErrorView.css b/src/renderer/css/components/ErrorView.css deleted file mode 100644 index 2abfc61a..00000000 --- a/src/renderer/css/components/ErrorView.css +++ /dev/null @@ -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; -} diff --git a/src/renderer/css/components/ErrorView.scss b/src/renderer/css/components/ErrorView.scss new file mode 100644 index 00000000..3986c9d1 --- /dev/null +++ b/src/renderer/css/components/ErrorView.scss @@ -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); + } +} diff --git a/src/renderer/css/components/MainPage.css b/src/renderer/css/components/MainPage.css index e5097959..e285d8a5 100644 --- a/src/renderer/css/components/MainPage.css +++ b/src/renderer/css/components/MainPage.css @@ -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'); +} \ No newline at end of file diff --git a/src/renderer/css/components/index.css b/src/renderer/css/components/index.css index bdce1efe..a21c3dbd 100644 --- a/src/renderer/css/components/index.css +++ b/src/renderer/css/components/index.css @@ -1,4 +1,3 @@ -@import url("ErrorView.css"); @import url("HoveringURL.css"); @import url("MainPage.css"); @import url("MattermostView.css"); diff --git a/src/renderer/css/index.css b/src/renderer/css/index.css index 67ee54f1..26ea1099 100644 --- a/src/renderer/css/index.css +++ b/src/renderer/css/index.css @@ -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 { diff --git a/src/types/window.ts b/src/types/window.ts index a0616e03..d64a82e2 100644 --- a/src/types/window.ts +++ b/src/types/window.ts @@ -37,7 +37,7 @@ declare global { exitFullScreen: () => void; doubleClickOnWindow: (windowName?: string) => void; focusCurrentView: () => void; - reloadCurrentView: () => void; + openServerExternally: () => void; closeDownloadsDropdown: () => void; closeDownloadsDropdownMenu: () => void; openDownloadsDropdown: () => void;