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
-
-
- © 2022 Symphony
-
-
+
+
+
+ Desktop Application
+
+
- -
-
+
-
+
POD:
-
-
- N/A
+
+
+ N/A
+
- -
-
+
-
+
SBE:
-
-
- N/A (N/A)
+
+
+ N/A (N/A)
+
- -
-
+
-
+
SDA:
-
-
- N/A (N/A)
+
+
+ N/A (N/A)
+
- -
-
- SFE-Lite
- :
-
-
- N/A
-
+
-
+
+ SFE:
+
+
+ N/A undefined
+
-
-
-
+
+
+
+
+
+
+
+
+ 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 (
-
-
-
-
-
{appName}
-
{copyright}
-
+
+
+
+ {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}
+
+ ))}
+
+
+
+
+
+
-
-
+
);
@@ -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;