From 7992dae4ec59ffaeaae41a8b3a86a14c10bf2d92 Mon Sep 17 00:00:00 2001 From: NguyenTranHoangSym <97150869+NguyenTranHoangSym@users.noreply.github.com> Date: Thu, 13 Oct 2022 19:59:36 +0700 Subject: [PATCH] SDA-3892: About Symphony redesign (#1511) --- crowdin.yml | 21 ++- spec/__snapshots__/aboutApp.spec.ts.snap | 137 +++++++++------ spec/aboutApp.spec.ts | 2 +- spectron/about-app.spec.ts | 65 ++++++++ src/app/window-handler.ts | 23 ++- src/locale/en-US.json | 8 +- src/locale/en.json | 8 +- src/locale/fr-FR.json | 8 +- src/locale/fr.json | 8 +- src/locale/ja-JP.json | 8 +- src/locale/ja.json | 8 +- src/renderer/assets/copy-icon.svg | 4 + src/renderer/assets/new-symphony-logo.svg | 11 ++ src/renderer/components/about-app.tsx | 113 +++++++++---- src/renderer/styles/about-app.less | 194 +++++++++++++--------- src/renderer/styles/theme.less | 8 + 16 files changed, 429 insertions(+), 197 deletions(-) create mode 100644 spectron/about-app.spec.ts create mode 100644 src/renderer/assets/copy-icon.svg create mode 100644 src/renderer/assets/new-symphony-logo.svg diff --git a/crowdin.yml b/crowdin.yml index a747d7b3..9a7bf8de 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -1,29 +1,28 @@ # # Your Crowdin credentials # -"project_id": "420172" # Crowdin project Settings > API & Webhooks > API > Project Id -"api_token_env": "CROWDIN_PERSONAL_TOKEN" # Low priority: superseded by user-specific credentials file ~/.crowdin.yaml -"base_path": "." -"base_url": "https://api.crowdin.com" +'project_id': '420172' # Crowdin project Settings > API & Webhooks > API > Project Id +'api_token_env': 'CROWDIN_API_TOKEN' # Low priority: superseded by user-specific credentials file ~/.crowdin.yaml +'base_path': '.' +'base_url': 'https://api.crowdin.com' # # Choose file structure in Crowdin # e.g. true or false # -"preserve_hierarchy": true +'preserve_hierarchy': true # # Files configuration # -files: - [ +files: [ { - "source": "/src/locale/en-US.json", - "translation": "/src/locale/%locale%.json", + 'source': '/src/locale/en-US.json', + 'translation': '/src/locale/%locale%.json', }, # Duplicate file { - "source": "/src/locale/en.json", - "translation": "/src/locale/%two_letters_code%.json", + 'source': '/src/locale/en.json', + 'translation': '/src/locale/%two_letters_code%.json', }, ] diff --git a/spec/__snapshots__/aboutApp.spec.ts.snap b/spec/__snapshots__/aboutApp.spec.ts.snap index 1bbdd2c9..7be0e204 100644 --- a/spec/__snapshots__/aboutApp.spec.ts.snap +++ b/spec/__snapshots__/aboutApp.spec.ts.snap @@ -8,78 +8,107 @@ exports[`about app should render correctly 1`] = `
-
- Symphony Logo -
-
-

- Symphony -

-

- © 2022 Symphony -

-
+ Symphony Logo
+
+ + Desktop Application + +
-
-
- + +
+
+ +
+ +
+

+ Copyright © 2022 Symphony +

`; diff --git a/spec/aboutApp.spec.ts b/spec/aboutApp.spec.ts index 84dbd268..a23e8c77 100644 --- a/spec/aboutApp.spec.ts +++ b/spec/aboutApp.spec.ts @@ -67,7 +67,7 @@ describe('about app', () => { const spyIpc = jest.spyOn(ipcRenderer, ipcSendEvent); const wrapper = shallow(React.createElement(AboutApp)); ipcRenderer.send('about-app-data', aboutDataMock); - const copyButtonSelector = `button.AboutApp-copy-button[title="Copy all the version information in this page"]`; + const copyButtonSelector = `[data-testid="COPY_BUTTON"]`; wrapper.find(copyButtonSelector).simulate('click'); const expectedData = { cmd: apiCmds.aboutAppClipBoardData, diff --git a/spectron/about-app.spec.ts b/spectron/about-app.spec.ts new file mode 100644 index 00000000..25d1c6ec --- /dev/null +++ b/spectron/about-app.spec.ts @@ -0,0 +1,65 @@ +import test from 'ava'; +import * as robot from 'robotjs'; +import { Application } from 'spectron'; +import { robotActions } from './fixtures/robot-actions'; +import { + loadURL, + podUrl, + sleep, + startApplication, + stopApplication, + Timeouts, +} from './fixtures/spectron-setup'; + +let app; + +test.before(async (t) => { + app = (await startApplication()) as Application; + t.true(app.isRunning()); + + await loadURL(app, podUrl); + await app.client.waitUntilWindowLoaded(Timeouts.fiveSec); + + await sleep(Timeouts.fiveSec); +}); + +test.after.always(async () => { + await stopApplication(app); +}); + +test('about-app: verify about application feature', async (t) => { + robotActions.clickAppMenu(); + robot.keyTap('down'); + robot.keyTap('enter'); + + // wait for about window to load + await sleep(Timeouts.halfSec); + await app.client.windowByIndex(1); + await app.client.waitUntilWindowLoaded(Timeouts.fiveSec); + t.truthy(await app.browserWindow.getTitle(), 'About Symphony'); +}); + +test('about-app: verify copy button with few data validation', async (t) => { + await sleep(Timeouts.oneSec); + await app.client.click('.AboutApp-copy-button'); + const clipboard = JSON.parse( + await app.client.electron.remote.clipboard.readText(), + ); + + t.log(clipboard); + t.true(clipboard.hasOwnProperty('appName')); + t.true(clipboard.hasOwnProperty('clientVersion')); + t.true(clipboard.hasOwnProperty('sfeVersion')); + t.true(clipboard.hasOwnProperty('sfeClientType')); + t.true(clipboard.hasOwnProperty('sdaVersion')); + t.true(clipboard.hasOwnProperty('sdaBuildNumber')); + robotActions.closeWindow(); +}); + +test('about-app: verify close button will close modal', async (t) => { + await sleep(Timeouts.oneSec); + await app.client.click('[data-testid="CLOSE_BUTTON"]'); + + t.false(app.client.$('[data-testid="CLOSE_BUTTON"]')); + robotActions.closeWindow(); +}); diff --git a/src/app/window-handler.ts b/src/app/window-handler.ts index bd58d7a8..6e63184c 100644 --- a/src/app/window-handler.ts +++ b/src/app/window-handler.ts @@ -1099,9 +1099,10 @@ export class WindowHandler { const opts: BrowserWindowConstructorOptions = this.getWindowOpts( { - width: 440, - height: 315, + width: 404, + height: 480, modal: true, + frame: false, alwaysOnTop: isMac, resizable: false, fullscreenable: false, @@ -1111,6 +1112,16 @@ export class WindowHandler { }, ); + const closeAboutApp = () => { + if ( + this.aboutAppWindow && + windowExists(this.aboutAppWindow as BrowserWindow) + ) { + this.aboutAppWindow.close(); + this.aboutAppWindow = null; + } + }; + if ( this.mainWindow && windowExists(this.mainWindow) && @@ -1119,7 +1130,7 @@ export class WindowHandler { opts.alwaysOnTop = true; } - if (isWindowsOS && selectedParentWindow) { + if (selectedParentWindow) { opts.parent = selectedParentWindow; } @@ -1127,6 +1138,12 @@ export class WindowHandler { this.moveWindow(this.aboutAppWindow); this.aboutAppWindow.setVisibleOnAllWorkspaces(true); + this.aboutAppWindow.once('close', () => { + ipcMain.removeListener('close-about-app', closeAboutApp); + }); + + ipcMain.once('close-about-app', closeAboutApp); + this.aboutAppWindow.webContents.once('did-finish-load', async () => { let client = ''; if (this.url && this.url.startsWith('https://corporate.symphony.com')) { diff --git a/src/locale/en-US.json b/src/locale/en-US.json index cd733025..4fea7106 100644 --- a/src/locale/en-US.json +++ b/src/locale/en-US.json @@ -2,12 +2,14 @@ "About Symphony": "About Symphony", "AboutSymphony": { "About Symphony": "About Symphony", - "Copy": "Copy", - "Copy all the version information in this page": "Copy all the version information in this page", "Others": "Others", "Swift Search": "Swift Search", "Swift Search API": "Swift Search API", - "Symphony Logo": "Symphony Logo" + "Symphony Logo": "Symphony Logo", + "Copy config to clipboard": "Copy config to clipboard", + "Close": "Close", + "Copyright": "Copyright", + "Desktop Application": "Desktop Application" }, "Actual Size": "Actual Size", "Always on Top": "Always on Top", diff --git a/src/locale/en.json b/src/locale/en.json index cd733025..4fea7106 100644 --- a/src/locale/en.json +++ b/src/locale/en.json @@ -2,12 +2,14 @@ "About Symphony": "About Symphony", "AboutSymphony": { "About Symphony": "About Symphony", - "Copy": "Copy", - "Copy all the version information in this page": "Copy all the version information in this page", "Others": "Others", "Swift Search": "Swift Search", "Swift Search API": "Swift Search API", - "Symphony Logo": "Symphony Logo" + "Symphony Logo": "Symphony Logo", + "Copy config to clipboard": "Copy config to clipboard", + "Close": "Close", + "Copyright": "Copyright", + "Desktop Application": "Desktop Application" }, "Actual Size": "Actual Size", "Always on Top": "Always on Top", diff --git a/src/locale/fr-FR.json b/src/locale/fr-FR.json index b569e440..b6277f63 100644 --- a/src/locale/fr-FR.json +++ b/src/locale/fr-FR.json @@ -2,12 +2,14 @@ "About Symphony": "À propos de Symphony", "AboutSymphony": { "About Symphony": "À propos de Symphony", - "Copy": "Copier", - "Copy all the version information in this page": "Copier toutes les informations de version dans cette page", "Others": "Autres", "Swift Search": "Recherche Rapide", "Swift Search API": "API Recherche Rapide", - "Symphony Logo": "Logo Symphony" + "Symphony Logo": "Logo de Symphony", + "Copy config to clipboard": "Copier la configuration", + "Close": "Fermer", + "Copyright": "Copyright", + "Desktop Application": "Application de bureau" }, "Actual Size": "Taille actuelle", "Always on Top": "Garder Symphony au premier plan", diff --git a/src/locale/fr.json b/src/locale/fr.json index b569e440..b6277f63 100644 --- a/src/locale/fr.json +++ b/src/locale/fr.json @@ -2,12 +2,14 @@ "About Symphony": "À propos de Symphony", "AboutSymphony": { "About Symphony": "À propos de Symphony", - "Copy": "Copier", - "Copy all the version information in this page": "Copier toutes les informations de version dans cette page", "Others": "Autres", "Swift Search": "Recherche Rapide", "Swift Search API": "API Recherche Rapide", - "Symphony Logo": "Logo Symphony" + "Symphony Logo": "Logo de Symphony", + "Copy config to clipboard": "Copier la configuration", + "Close": "Fermer", + "Copyright": "Copyright", + "Desktop Application": "Application de bureau" }, "Actual Size": "Taille actuelle", "Always on Top": "Garder Symphony au premier plan", diff --git a/src/locale/ja-JP.json b/src/locale/ja-JP.json index 24b67fcb..1295a180 100644 --- a/src/locale/ja-JP.json +++ b/src/locale/ja-JP.json @@ -2,12 +2,14 @@ "About Symphony": "Symphonyについて", "AboutSymphony": { "About Symphony": "Symphonyについて", - "Copy": "コピー", - "Copy all the version information in this page": "このページのすべてのバージョン情報をコピー", "Others": "その他", "Swift Search": "Swift検索", "Swift Search API": "Swift検索API", - "Symphony Logo": "Symphonyロゴ" + "Symphony Logo": "Symphonyロゴ", + "Copy config to clipboard": "コンフィグをクリップボードにコピー", + "Close": "閉じる", + "Copyright": "Copyright", + "Desktop Application": "デスクトップアプリケーション" }, "Actual Size": "実際のサイズ", "Always on Top": "つねに前面に表示", diff --git a/src/locale/ja.json b/src/locale/ja.json index f694baf7..3ec27103 100644 --- a/src/locale/ja.json +++ b/src/locale/ja.json @@ -2,12 +2,14 @@ "About Symphony": "Symphonyについて", "AboutSymphony": { "About Symphony": "Symphonyについて", - "Copy": "コピー", - "Copy all the version information in this page": "このページのすべてのバージョン情報をコピー", "Others": "その他", "Swift Search": "Swift検索", "Swift Search API": "Swift検索API", - "Symphony Logo": "Symphonyロゴ" + "Symphony Logo": "Symphonyロゴ", + "Copy config to clipboard": "コンフィグをクリップボードにコピー", + "Close": "閉じる", + "Copyright": "Copyright", + "Desktop Application": "デスクトップアプリケーション" }, "Actual Size": "実際のサイズ", "Always on Top": "つねに前面に表示", diff --git a/src/renderer/assets/copy-icon.svg b/src/renderer/assets/copy-icon.svg new file mode 100644 index 00000000..f780de90 --- /dev/null +++ b/src/renderer/assets/copy-icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/renderer/assets/new-symphony-logo.svg b/src/renderer/assets/new-symphony-logo.svg new file mode 100644 index 00000000..d2ed25ca --- /dev/null +++ b/src/renderer/assets/new-symphony-logo.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/renderer/components/about-app.tsx b/src/renderer/components/about-app.tsx index 1437b3ce..43d320d8 100644 --- a/src/renderer/components/about-app.tsx +++ b/src/renderer/components/about-app.tsx @@ -40,6 +40,7 @@ const ABOUT_SYMPHONY_NAMESPACE = 'AboutSymphony'; export default class AboutApp extends React.Component<{}, IState> { private readonly eventHandlers = { onCopy: () => this.copy(), + onClose: () => this.close(), }; constructor(props) { @@ -89,10 +90,32 @@ export default class AboutApp extends React.Component<{}, IState> { } = this.state; const appName = productName || 'Symphony'; - const copyright = `\xA9 ${new Date().getFullYear()} ${appName}`; + const copyright = `${i18n.t( + 'Copyright', + ABOUT_SYMPHONY_NAMESPACE, + )()} \xA9 ${new Date().getFullYear()} ${appName}`; const podVersion = `${clientVersion} (${buildNumber})`; const sdaVersionBuild = `${sdaVersion} (${sdaBuildNumber})`; let sfeClientTypeName = 'SFE'; + const symphonySectionItems = [ + { + key: 'POD:', + value: `${hostname || 'N/A'}`, + }, + { + key: 'SBE:', + value: podVersion, + }, + { + key: 'SDA:', + value: sdaVersionBuild, + }, + { + key: `${sfeClientTypeName}:`, + value: `${sfeVersion} ${client}`, + }, + ]; + if (sfeClientType !== '1.5') { sfeClientTypeName = 'SFE-Lite'; } @@ -100,47 +123,60 @@ export default class AboutApp extends React.Component<{}, IState> { return (
-
- {i18n.t('Symphony -
-
-

{appName}

-

{copyright}

-
+ {i18n.t('Symphony
+
+ + {i18n.t('Desktop Application', ABOUT_SYMPHONY_NAMESPACE)()} + +
    -
  • - POD: {hostname || 'N/A'} -
  • -
  • - SBE: {podVersion} -
  • -
  • - SDA: {sdaVersionBuild} -
  • -
  • - {sfeClientTypeName}: {sfeVersion} {client} -
  • + {symphonySectionItems.map((item, key) => ( +
  • + {item.key} + {item.value} +
  • + ))}
+
+ +
+
+ +
-
- +
+

{copyright}

); @@ -175,6 +211,13 @@ export default class AboutApp extends React.Component<{}, IState> { } } + /** + * Close modal + */ + public close(): void { + ipcRenderer.send('close-about-app'); + } + /** * Sets the component state * diff --git a/src/renderer/styles/about-app.less b/src/renderer/styles/about-app.less index f88cb1d2..e3eec501 100644 --- a/src/renderer/styles/about-app.less +++ b/src/renderer/styles/about-app.less @@ -14,126 +14,170 @@ body { margin: 0; height: 100%; width: 100%; + box-sizing: border-box; } .AboutApp:lang(ja-JP) { font-family: @font-family-ja; - - h4 { - margin: 3px 0; - } - - .AboutApp-symphony-section { - padding-left: 10px; - } -} - -.AboutApp:lang(fr-FR) { - .AboutApp-symphony-section { - padding-left: 10px; - } } .AboutApp { - text-align: center; + padding: 32px 64px; display: flex; + text-align: center; flex-direction: column; - padding: 10px; font-family: @font-family; + background: @graphite-80; + align-items: flex-start; + flex: 1; + height: 480px; + box-sizing: border-box; + + &-main-title { + text-align: left; + font-family: @font-family; + font-style: normal; + font-weight: 500; + font-size: 1.125rem; + line-height: 24px; + color: @graphite-05; + margin-bottom: 24px; + } + + &-symphony-section { + padding: 0px; + margin: 0px 0px 24px 0; + list-style: none; + text-align: left; + } + + &-symphony-section > li { + padding-bottom: 8px; + } + + &-symphony-section > li:last-child { + padding-bottom: 0px; + } + + &-symphony-section > li > span { + padding-left: 8px; + } + + &-symphony-section > li > * { + text-align: left; + font-family: @font-family; + font-style: normal; + font-weight: 500; + font-size: 0.875rem; + line-height: 24px; + color: @graphite-20; + } + + &-symphony-section > li > strong { + font-weight: 600; + color: @graphite-05; + } &-header-container { flex-direction: row; display: flex; align-items: center; + justify-content: center; + margin-bottom: 32px; } &-header-content { display: flex; flex-direction: column; + align-items: center; justify-content: center; align-items: flex-start; } &-main-container { - padding: 10px 20px; + display: flex; + justify-content: center; + flex-direction: column; + margin-bottom: 32px; + grid-area: main; } - &-name { - font-size: 1.8em; - padding-left: @text-padding; - font-weight: bold; - margin: 0; - } - - &-copyrightText { - padding-left: @text-padding; - font-size: 0.9em; - margin: 0; - color: @copyright-text-color; - } - - &-logo { - margin: auto; - } - - &-symphony-section { - padding-left: 10px; - } - - hr { - width: 90%; - } - - ul { - list-style: none; - clear: both; - display: table; - text-align: right; - margin: 0; - } - - h4 { - text-align: start; - margin: 6px 0; - } - - li { - display: table-row; - text-align: left; - line-height: 20px; - } - - b { - display: table-cell; - padding-right: 1em; - text-align: left; - font-weight: normal; + &-copy-container { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + margin-bottom: 32px; + padding: 8px 16px; + gap: 4px; + flex: 1; } &-copy-button { - text-transform: capitalize; + text-transform: uppercase; + box-shadow: none; + border: none; + background-color: transparent; + text-align: center; + text-decoration: none; + line-height: 12px; + color: @electricity-ui-30; + cursor: pointer; + font-family: @font-family; + font-style: normal; + font-weight: 600; + font-size: 0.75rem; + line-height: 16px; + display: flex; + align-items: center; + justify-content: center; + + img { + padding-right: 8px; + color: @electricity-ui-30; + } } - &-copy-button { + &-close-container { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + } + + &-close-button { box-shadow: none; border: none; border-radius: 20px; - font-size: 0.8rem; + font-size: 0.875rem; text-align: center; - padding: 10px 32px; - margin: 4px 20px; display: inline-block; text-decoration: none; line-height: 12px; - background-color: rgba(61, 162, 253, 1); - color: rgba(255, 255, 255, 1); + background-color: @electricity-ui-50; + color: @electricity-ui-05; cursor: pointer; + padding: 12px 118px; + box-sizing: border-box; text-transform: uppercase; - float: right; + font-weight: 600; &:focus { box-shadow: 0 0 10px rgba(61, 162, 253, 1); outline: none; } } + + &-version-container { + width: 100%; + } + + &-copyright-text { + font-size: 0.75rem; + margin: 0; + font-style: normal; + font-weight: 400; + line-height: 16px; + color: @graphite-20; + } } diff --git a/src/renderer/styles/theme.less b/src/renderer/styles/theme.less index 1b9dc8fd..b3e41ccb 100644 --- a/src/renderer/styles/theme.less +++ b/src/renderer/styles/theme.less @@ -4,3 +4,11 @@ @text-color-primary: #ffffff; @text-color-primary-dark: #2f3237; @text-color-secondary: #6a707c; + +// Color palette +@electricity-ui-05: #e9f2f9; +@electricity-ui-50: #0277d6; +@electricity-ui-30: #6eb9fd; +@graphite-20: #cdcfd4; +@graphite-05: #f1f1f3; +@graphite-80: #27292c;