mirror of
https://github.com/finos/SymphonyElectron.git
synced 2024-11-22 00:47:29 -06:00
SDA-3901 (Add new implementation for welcome screen) (#1519)
* SDA-3901 - Add new welcome screen * SDA-3901 - Change to global config * SDA-3901 - Add locale * SDA-3901 - Reposition protocol handling * SDA-3901 - Fix protocol handler * SDA-3901 - Fix protocol handler * SDA-3901 - Fix welcome screen load * SDA-3901 - Fix seamless login url * SDA-3901 - Validate if pod is configured for SSO
This commit is contained in:
parent
fb5a98136f
commit
df14fa19d1
@ -4,6 +4,7 @@
|
||||
"autoUpdateChannel": "latest",
|
||||
"isAutoUpdateEnabled": true,
|
||||
"autoUpdateCheckInterval": "30",
|
||||
"enableSeamlessLogin": true,
|
||||
"overrideUserAgent": false,
|
||||
"minimizeOnClose" : "ENABLED",
|
||||
"launchOnStartup" : "ENABLED",
|
||||
|
28
package-lock.json
generated
28
package-lock.json
generated
@ -5013,15 +5013,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001265",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz",
|
||||
"integrity": "sha1-BhPJ5ski5CJ5Lm/O/fmjr+7k+MM=",
|
||||
"version": "1.0.30001420",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/caniuse-lite/-/caniuse-lite-1.0.30001420.tgz",
|
||||
"integrity": "sha1-9i818FHgttJVMs83Z3bUHkW0fvY=",
|
||||
"dev": true,
|
||||
"license": "CC-BY-4.0",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/browserslist"
|
||||
}
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/browserslist"
|
||||
},
|
||||
{
|
||||
"type": "tidelift",
|
||||
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
|
||||
}
|
||||
],
|
||||
"license": "CC-BY-4.0"
|
||||
},
|
||||
"node_modules/capture-exit": {
|
||||
"version": "2.0.0",
|
||||
@ -25181,9 +25187,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001265",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz",
|
||||
"integrity": "sha1-BhPJ5ski5CJ5Lm/O/fmjr+7k+MM=",
|
||||
"version": "1.0.30001420",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/caniuse-lite/-/caniuse-lite-1.0.30001420.tgz",
|
||||
"integrity": "sha1-9i818FHgttJVMs83Z3bUHkW0fvY=",
|
||||
"dev": true
|
||||
},
|
||||
"capture-exit": {
|
||||
|
@ -264,6 +264,7 @@ export const BrowserWindow = {
|
||||
export const session = {
|
||||
defaultSession: {
|
||||
clearCache: jest.fn(),
|
||||
cookies: jest.fn(),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -4,47 +4,93 @@ exports[`welcome should render correctly 1`] = `
|
||||
<div
|
||||
className="Welcome"
|
||||
lang="en-US"
|
||||
style={
|
||||
Object {
|
||||
"height": "494px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="Welcome-image-container"
|
||||
className="Welcome-content"
|
||||
>
|
||||
<img
|
||||
alt="Symphony Logo"
|
||||
src="../renderer/assets/symphony-logo-plain.png"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="Welcome-main-container"
|
||||
>
|
||||
<h3
|
||||
className="Welcome-name"
|
||||
>
|
||||
Pod URL
|
||||
</h3>
|
||||
<div
|
||||
className="Welcome-main-container-input-div"
|
||||
className="Welcome-image-container"
|
||||
>
|
||||
<div
|
||||
className="Welcome-main-container-input-selection"
|
||||
<img
|
||||
alt="Symphony Logo"
|
||||
src="../renderer/assets/welcome-symphony-logo.svg"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="Welcome-about-symphony-text"
|
||||
style={
|
||||
Object {
|
||||
"marginTop": "8px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span>
|
||||
Welcome to the largest global community in financial services with over
|
||||
</span>
|
||||
<span
|
||||
className="Welcome-text-bold"
|
||||
>
|
||||
<input
|
||||
className="Welcome-main-container-podurl-box"
|
||||
onChange={[Function]}
|
||||
type="url"
|
||||
value="https://[POD].symphony.com"
|
||||
/>
|
||||
half a million users
|
||||
</span>
|
||||
<span>
|
||||
and more than
|
||||
</span>
|
||||
<span
|
||||
className="Welcome-text-bold"
|
||||
>
|
||||
1,000 institutions.
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
className="Welcome-login-text"
|
||||
>
|
||||
<span>
|
||||
Log in with your pod URL
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="Welcome-input-container"
|
||||
>
|
||||
<span>
|
||||
Pod URL
|
||||
</span>
|
||||
<div>
|
||||
<input
|
||||
className="Welcome-main-container-podurl-box"
|
||||
data-testid="Welcome-main-container-podurl-box"
|
||||
onChange={[Function]}
|
||||
type="url"
|
||||
value="https://[POD].symphony.com"
|
||||
/>
|
||||
<label
|
||||
className="Welcome-input-message"
|
||||
>
|
||||
Find your pod URL in your invitation email.
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<label
|
||||
className="Welcome-message-label"
|
||||
/>
|
||||
<button
|
||||
className="Welcome-continue-button-disabled"
|
||||
className="Welcome-continue-button"
|
||||
disabled={true}
|
||||
onClick={[Function]}
|
||||
style={Object {}}
|
||||
>
|
||||
Continue
|
||||
log in
|
||||
</button>
|
||||
<div
|
||||
className="Welcome-redirect-info-text-container"
|
||||
>
|
||||
<span>
|
||||
You’ll momentarily be redirected to your web browser.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
@ -12,6 +12,14 @@ jest.mock('../src/common/utils', () => {
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('../src/app/window-handler', () => {
|
||||
return {
|
||||
windowHandler: {
|
||||
url: '',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('../src/common/env', () => {
|
||||
return {
|
||||
isWindowsOS: false,
|
||||
@ -34,6 +42,14 @@ jest.mock('../src/common/logger', () => {
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('../src/app/config-handler', () => {
|
||||
return {
|
||||
config: {
|
||||
getUserConfigFields: jest.fn(() => ''),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
describe('protocol handler', () => {
|
||||
let protocolHandlerInstance;
|
||||
|
||||
|
@ -9,6 +9,8 @@ describe('welcome', () => {
|
||||
url: 'https://my.symphony.com',
|
||||
message: '',
|
||||
urlValid: true,
|
||||
isPodConfigured: false,
|
||||
isSeamlessLoginEnabled: true,
|
||||
};
|
||||
const onLabelEvent = 'on';
|
||||
const removeListenerLabelEvent = 'removeListener';
|
||||
@ -94,7 +96,7 @@ describe('welcome', () => {
|
||||
|
||||
it('should set pod url', () => {
|
||||
const spy = jest.spyOn(Welcome.prototype, 'setState');
|
||||
const setPodUrlSpy = jest.spyOn(Welcome.prototype, 'setPodUrl');
|
||||
const setPodUrlSpy = jest.spyOn(Welcome.prototype, 'login');
|
||||
|
||||
const wrapper = shallow(React.createElement(Welcome));
|
||||
ipcRenderer.send('welcome', welcomeMock);
|
||||
@ -104,4 +106,18 @@ describe('welcome', () => {
|
||||
expect(setPodUrlSpy).toBeCalled();
|
||||
expect(spy).toBeCalledWith(welcomeMock);
|
||||
});
|
||||
|
||||
it('should not show pod url input field', () => {
|
||||
const welcomeMock = {
|
||||
url: 'https://my.symphony.com',
|
||||
message: '',
|
||||
urlValid: true,
|
||||
isPodConfigured: true,
|
||||
isSeamlessLoginEnabled: true,
|
||||
};
|
||||
const wrapper = shallow(React.createElement(Welcome));
|
||||
ipcRenderer.send('welcome', welcomeMock);
|
||||
const podUrlBox = `input.Welcome-main-container-podurl-box`;
|
||||
expect(wrapper.find(podUrlBox).getElements()).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
@ -58,6 +58,7 @@ export interface IConfig {
|
||||
installVariant?: string;
|
||||
bootCount?: number;
|
||||
startedAfterAutoUpdate?: boolean;
|
||||
enableSeamlessLogin: boolean;
|
||||
}
|
||||
|
||||
export interface IGlobalConfig {
|
||||
|
@ -1,20 +1,23 @@
|
||||
import {
|
||||
app,
|
||||
BrowserWindow,
|
||||
clipboard,
|
||||
desktopCapturer,
|
||||
dialog,
|
||||
ipcMain,
|
||||
shell,
|
||||
systemPreferences,
|
||||
} from 'electron';
|
||||
import fetch from 'electron-fetch';
|
||||
import {
|
||||
apiCmds,
|
||||
apiName,
|
||||
IApiArgs,
|
||||
IAuthResponse,
|
||||
INotificationData,
|
||||
} from '../common/api-interface';
|
||||
import { i18n, LocaleType } from '../common/i18n';
|
||||
import { logger } from '../common/logger';
|
||||
import { whitelistHandler } from '../common/whitelist-handler';
|
||||
import { activityDetection } from './activity-detection';
|
||||
import { analytics } from './analytics-handler';
|
||||
import appStateHandler from './app-state-handler';
|
||||
@ -63,6 +66,9 @@ const broadcastMessage = (method, data) => {
|
||||
mainEvents.publish(apiCmds.onSwiftSearchMessage, [method, data]);
|
||||
};
|
||||
|
||||
const getSeamLessLoginUrl = (pod: string) =>
|
||||
`https://${pod}/login/sso/initsso?RelayState=https://${pod}/client-bff/device-login/index.html?callbackScheme=symphony&action=login`;
|
||||
const AUTH_STATUS_PATH = '/login/checkauth?type=user';
|
||||
/**
|
||||
* Handle API related ipc messages from renderers. Only messages from windows
|
||||
* we have created are allowed.
|
||||
@ -350,10 +356,43 @@ ipcMain.on(
|
||||
mainWebContents.focus();
|
||||
}
|
||||
break;
|
||||
case apiCmds.setPodUrl:
|
||||
await config.updateUserConfig({ url: arg.newPodUrl });
|
||||
app.relaunch();
|
||||
app.exit();
|
||||
case apiCmds.seamlessLogin:
|
||||
if (!arg.isPodConfigured) {
|
||||
await config.updateUserConfig({ url: arg.newPodUrl });
|
||||
}
|
||||
const { subdomain, domain, tld } = whitelistHandler.parseDomain(
|
||||
arg.newPodUrl,
|
||||
);
|
||||
const loginUrl = getSeamLessLoginUrl(`${subdomain}.${domain}${tld}`);
|
||||
logger.info(
|
||||
'main-api-handler:',
|
||||
'check if sso is enabled for the pod',
|
||||
loginUrl,
|
||||
);
|
||||
const response = await fetch(`${loginUrl}${AUTH_STATUS_PATH}`);
|
||||
const authResponse = (await response.json()) as IAuthResponse;
|
||||
logger.info('main-api-handler:', 'check auth response', authResponse);
|
||||
if (
|
||||
arg.isSeamlessLoginEnabled &&
|
||||
authResponse.authenticationType === 'sso'
|
||||
) {
|
||||
logger.info(
|
||||
'main-api-handler:',
|
||||
'seamless login is enabled - logging in',
|
||||
loginUrl,
|
||||
);
|
||||
await shell.openExternal(loginUrl);
|
||||
} else {
|
||||
logger.info(
|
||||
'main-api-handler:',
|
||||
'seamless login is not enabled - loading main window with',
|
||||
arg.newPodUrl,
|
||||
);
|
||||
const mainWebContents = windowHandler.getMainWebContents();
|
||||
if (mainWebContents && !mainWebContents.isDestroyed()) {
|
||||
mainWebContents.loadURL(arg.newPodUrl);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case apiCmds.setBroadcastMessage:
|
||||
if (swiftSearchInstance) {
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { WebContents } from 'electron';
|
||||
import { session, WebContents } from 'electron';
|
||||
import { apiName } from '../common/api-interface';
|
||||
import { isMac } from '../common/env';
|
||||
import { logger } from '../common/logger';
|
||||
import { getCommandLineArgs } from '../common/utils';
|
||||
import { config } from './config-handler';
|
||||
import { activate } from './window-actions';
|
||||
import { windowHandler } from './window-handler';
|
||||
|
||||
enum protocol {
|
||||
SymphonyProtocol = 'symphony://',
|
||||
@ -45,7 +47,10 @@ class ProtocolHandler {
|
||||
* @param url {String}
|
||||
* @param isAppRunning {Boolean} - whether the application is running
|
||||
*/
|
||||
public sendProtocol(url: string, isAppRunning: boolean = true): void {
|
||||
public async sendProtocol(
|
||||
url: string,
|
||||
isAppRunning: boolean = true,
|
||||
): Promise<void> {
|
||||
if (url && url.length > 2083) {
|
||||
logger.info(
|
||||
`protocol-handler: protocol handler url length is greater than 2083, not performing any action!`,
|
||||
@ -55,6 +60,12 @@ class ProtocolHandler {
|
||||
logger.info(
|
||||
`protocol handler: processing protocol request for the url ${url}!`,
|
||||
);
|
||||
// Handle protocol for Seamless login
|
||||
if (url?.includes('skey') && url?.includes('anticsrf')) {
|
||||
await this.handleSeamlessLogin(url);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.preloadWebContents || !isAppRunning) {
|
||||
logger.info(
|
||||
`protocol handler: app was started from the protocol request. Caching the URL ${url}!`,
|
||||
@ -62,6 +73,7 @@ class ProtocolHandler {
|
||||
this.protocolUri = url;
|
||||
return;
|
||||
}
|
||||
|
||||
// This is needed for mac OS as it brings pop-outs to foreground
|
||||
// (if it has been previously focused) instead of main window
|
||||
if (isMac) {
|
||||
@ -95,6 +107,38 @@ class ProtocolHandler {
|
||||
this.sendProtocol(protocolUriFromArgv, isAppAlreadyOpen);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets session cookies and navigates to the pod url
|
||||
*/
|
||||
public async handleSeamlessLogin(protocolUri: string): Promise<void> {
|
||||
const { url } = config.getUserConfigFields(['url']);
|
||||
if (protocolUri) {
|
||||
const urlParams = new URLSearchParams(new URL(protocolUri).search);
|
||||
const skeyValue = urlParams.get('skey');
|
||||
const anticsrfValue = urlParams.get('anticsrf');
|
||||
if (skeyValue) {
|
||||
await session.defaultSession.cookies.set({
|
||||
url,
|
||||
name: 'skey',
|
||||
value: skeyValue,
|
||||
});
|
||||
}
|
||||
if (anticsrfValue) {
|
||||
await session.defaultSession.cookies.set({
|
||||
url,
|
||||
name: 'anti-csrf-cookie',
|
||||
value: anticsrfValue,
|
||||
});
|
||||
}
|
||||
logger.info('protocol-handler: cookies has been set');
|
||||
const mainWebContents = windowHandler.getMainWebContents();
|
||||
if (mainWebContents && !mainWebContents?.isDestroyed() && url) {
|
||||
logger.info('protocol-handler: redirecting main webContents', url);
|
||||
mainWebContents?.loadURL(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const protocolHandler = new ProtocolHandler();
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { ExecException, execFile } from 'child_process';
|
||||
import {
|
||||
app,
|
||||
BrowserView,
|
||||
BrowserWindow,
|
||||
BrowserWindowConstructorOptions,
|
||||
crashReporter,
|
||||
@ -102,8 +101,6 @@ export interface ICustomBrowserView extends Electron.BrowserView {
|
||||
// Default window width & height
|
||||
export const DEFAULT_WIDTH: number = 900;
|
||||
export const DEFAULT_HEIGHT: number = 900;
|
||||
export const DEFAULT_WELCOME_SCREEN_WIDTH: number = 542;
|
||||
export const DEFAULT_WELCOME_SCREEN_HEIGHT: number = 333;
|
||||
export const TITLE_BAR_HEIGHT: number = 32;
|
||||
export const IS_SAND_BOXED: boolean = true;
|
||||
export const IS_NODE_INTEGRATION_ENABLED: boolean = false;
|
||||
@ -143,7 +140,6 @@ export class WindowHandler {
|
||||
public isLoggedIn: boolean = false;
|
||||
public isAutoUpdating: boolean = false;
|
||||
public screenShareIndicatorFrameUtil: string;
|
||||
private defaultPodUrl: string = 'https://[POD].symphony.com';
|
||||
private contextIsolation: boolean = true;
|
||||
private backgroundThrottling: boolean = false;
|
||||
private windowOpts: ICustomBrowserWindowConstructorOpts = {} as ICustomBrowserWindowConstructorOpts;
|
||||
@ -155,7 +151,6 @@ export class WindowHandler {
|
||||
private loadFailError: string | undefined;
|
||||
private mainWindow: ICustomBrowserWindow | null = null;
|
||||
private aboutAppWindow: Electron.BrowserWindow | null = null;
|
||||
private welcomeScreenWindow: Electron.BrowserWindow | null = null;
|
||||
private screenPickerWindow: Electron.BrowserWindow | null = null;
|
||||
private screenPickerPlaceholderWindow: Electron.BrowserWindow | null = null;
|
||||
private screenSharingIndicatorWindow: Electron.BrowserWindow | null = null;
|
||||
@ -165,6 +160,9 @@ export class WindowHandler {
|
||||
private snippingToolWindow: Electron.BrowserWindow | null = null;
|
||||
private finishedLoading: boolean = false;
|
||||
private readonly opts: Electron.BrowserViewConstructorOptions | undefined;
|
||||
private isPodConfigured: boolean = false;
|
||||
private shouldShowWelcomeScreen: boolean = true;
|
||||
private didShowWelcomeScreen: boolean = false;
|
||||
|
||||
constructor(opts?: Electron.BrowserViewConstructorOptions) {
|
||||
this.opts = opts;
|
||||
@ -208,6 +206,7 @@ export class WindowHandler {
|
||||
'customFlags',
|
||||
'clientSwitch',
|
||||
'enableRendererLogs',
|
||||
'enableSeamlessLogin',
|
||||
]);
|
||||
logger.info(
|
||||
`window-handler: main windows initialized with following config data`,
|
||||
@ -233,6 +232,13 @@ export class WindowHandler {
|
||||
this.isCustomTitleBar =
|
||||
isWindowsOS &&
|
||||
this.config.isCustomTitleBar === CloudConfigDataTypes.ENABLED;
|
||||
// Get url to load from cmd line or from global config file
|
||||
const urlFromCmd = getCommandLineArgs(process.argv, '--url=', false);
|
||||
this.isPodConfigured = !config.isFirstTimeLaunch();
|
||||
this.didShowWelcomeScreen = false;
|
||||
this.shouldShowWelcomeScreen =
|
||||
config.isFirstTimeLaunch() || this.config.enableSeamlessLogin;
|
||||
|
||||
this.windowOpts = {
|
||||
...this.getWindowOpts(
|
||||
{
|
||||
@ -280,20 +286,6 @@ export class WindowHandler {
|
||||
);
|
||||
logger.info(`window-handler: setting url ${this.url} from config file!`);
|
||||
|
||||
// Get url to load from cmd line or from global config file
|
||||
const urlFromCmd = getCommandLineArgs(process.argv, '--url=', false);
|
||||
|
||||
// Displays welcome screen instead of starting the main application
|
||||
if (
|
||||
config.isFirstTimeLaunch() &&
|
||||
this.globalConfig.url.indexOf('https://my.symphony.com') >= 0 &&
|
||||
urlFromCmd === null
|
||||
) {
|
||||
this.url = this.defaultPodUrl;
|
||||
this.showWelcomeScreen();
|
||||
return;
|
||||
}
|
||||
|
||||
// set window opts with additional config
|
||||
this.mainWindow = new BrowserWindow({
|
||||
...this.windowOpts,
|
||||
@ -377,6 +369,20 @@ export class WindowHandler {
|
||||
logger.info(`Loading main window with url ${this.url}`);
|
||||
const userAgent = this.getUserAgent(this.mainWindow.webContents);
|
||||
|
||||
// Displays welcome screen instead of starting the main application
|
||||
if (this.shouldShowWelcomeScreen) {
|
||||
this.url = format({
|
||||
pathname: require.resolve('../renderer/react-window.html'),
|
||||
protocol: 'file',
|
||||
query: {
|
||||
componentName: 'welcome',
|
||||
locale: i18n.getLocale(),
|
||||
title: i18n.t('WelcomeText', 'Welcome')(),
|
||||
},
|
||||
slashes: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
this.config.isCustomTitleBar === CloudConfigDataTypes.ENABLED &&
|
||||
isWindowsOS &&
|
||||
@ -508,9 +514,34 @@ export class WindowHandler {
|
||||
await this.mainWebContents?.loadURL(url, { userAgent });
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info('window-handler: did-finish-load, url: ' + this.url);
|
||||
|
||||
if (this.mainWebContents && !this.mainWebContents.isDestroyed()) {
|
||||
// Load welcome screen
|
||||
if (this.shouldShowWelcomeScreen && !this.didShowWelcomeScreen) {
|
||||
const userConfigUrl =
|
||||
this.userConfig.url &&
|
||||
this.userConfig.url.indexOf('/login/sso/initsso') > -1
|
||||
? this.userConfig.url.slice(
|
||||
0,
|
||||
this.userConfig.url.indexOf('/login/sso/initsso'),
|
||||
)
|
||||
: this.userConfig.url;
|
||||
this.mainWebContents.send('page-load-welcome', {
|
||||
locale: i18n.getLocale(),
|
||||
resources: i18n.loadedResources,
|
||||
});
|
||||
this.mainWebContents.send('welcome', {
|
||||
url: userConfigUrl,
|
||||
message: '',
|
||||
urlValid: !!userConfigUrl,
|
||||
isPodConfigured: this.isPodConfigured,
|
||||
isSeamlessLoginEnabled: this.config.enableSeamlessLogin,
|
||||
});
|
||||
this.didShowWelcomeScreen = true;
|
||||
}
|
||||
|
||||
// Injects custom title bar and snack bar css into the webContents
|
||||
await injectStyles(this.mainWebContents, this.isCustomTitleBar);
|
||||
this.mainWebContents.send('page-load', {
|
||||
@ -719,120 +750,6 @@ export class WindowHandler {
|
||||
return this.mainWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the use case of showing
|
||||
* welcome screen for first time installs
|
||||
*/
|
||||
public showWelcomeScreen() {
|
||||
if (!this.url) {
|
||||
return;
|
||||
}
|
||||
const opts: ICustomBrowserWindowConstructorOpts = this.getWindowOpts(
|
||||
{
|
||||
width: DEFAULT_WELCOME_SCREEN_WIDTH,
|
||||
height: DEFAULT_WELCOME_SCREEN_HEIGHT,
|
||||
frame: !this.isCustomTitleBar,
|
||||
alwaysOnTop: isMac,
|
||||
resizable: false,
|
||||
minimizable: true,
|
||||
fullscreenable: false,
|
||||
},
|
||||
{
|
||||
devTools: isDevEnv,
|
||||
},
|
||||
);
|
||||
|
||||
this.welcomeScreenWindow = createComponentWindow('welcome', opts);
|
||||
(this.welcomeScreenWindow as ICustomBrowserWindow).winName =
|
||||
apiName.welcomeScreenName;
|
||||
|
||||
if (
|
||||
this.config.isCustomTitleBar === CloudConfigDataTypes.ENABLED &&
|
||||
isWindowsOS
|
||||
) {
|
||||
const titleBarView = new BrowserView({
|
||||
webPreferences: {
|
||||
sandbox: IS_SAND_BOXED,
|
||||
nodeIntegration: IS_NODE_INTEGRATION_ENABLED,
|
||||
preload: path.join(__dirname, '../renderer/_preload-component.js'),
|
||||
devTools: isDevEnv,
|
||||
disableBlinkFeatures: AUX_CLICK,
|
||||
},
|
||||
}) as ICustomBrowserView;
|
||||
const titleBarWindowUrl = format({
|
||||
pathname: require.resolve('../renderer/react-window.html'),
|
||||
protocol: 'file',
|
||||
query: {
|
||||
componentName: 'title-bar',
|
||||
locale: i18n.getLocale(),
|
||||
title: i18n.t('WelcomeText', 'Welcome')(),
|
||||
},
|
||||
slashes: true,
|
||||
});
|
||||
|
||||
titleBarView.webContents.once('did-finish-load', async () => {
|
||||
if (!titleBarView || titleBarView.webContents.isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
titleBarView?.webContents.send('page-load', {
|
||||
isWindowsOS,
|
||||
locale: i18n.getLocale(),
|
||||
resource: i18n.loadedResources,
|
||||
isMainWindow: true,
|
||||
});
|
||||
// disables action buttons in title bar
|
||||
titleBarView.webContents.send('disable-action-button');
|
||||
});
|
||||
titleBarView.webContents.loadURL(titleBarWindowUrl);
|
||||
titleBarView.setBounds({
|
||||
x: 0,
|
||||
y: 0,
|
||||
height: TITLE_BAR_HEIGHT,
|
||||
width: DEFAULT_WELCOME_SCREEN_WIDTH,
|
||||
});
|
||||
this.welcomeScreenWindow.setBrowserView(titleBarView);
|
||||
}
|
||||
|
||||
this.welcomeScreenWindow.webContents.on('did-finish-load', () => {
|
||||
if (!this.welcomeScreenWindow || this.welcomeScreenWindow.isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
logger.info(`finished loading welcome screen.`);
|
||||
const ssoValue = !!(
|
||||
this.userConfig.url &&
|
||||
this.userConfig.url.indexOf('/login/sso/initsso') > -1
|
||||
);
|
||||
|
||||
this.welcomeScreenWindow.webContents.send('page-load-welcome', {
|
||||
locale: i18n.getLocale(),
|
||||
resource: i18n.loadedResources,
|
||||
});
|
||||
|
||||
const userConfigUrl =
|
||||
this.userConfig.url &&
|
||||
this.userConfig.url.indexOf('/login/sso/initsso') > -1
|
||||
? this.userConfig.url.slice(
|
||||
0,
|
||||
this.userConfig.url.indexOf('/login/sso/initsso'),
|
||||
)
|
||||
: this.userConfig.url;
|
||||
this.welcomeScreenWindow.webContents.send('welcome', {
|
||||
url: userConfigUrl || this.startUrl,
|
||||
message: '',
|
||||
urlValid: !!userConfigUrl,
|
||||
sso: ssoValue,
|
||||
});
|
||||
this.appMenu = new AppMenu();
|
||||
this.addWindow(opts.winKey, this.welcomeScreenWindow);
|
||||
this.mainWindow = this.welcomeScreenWindow as ICustomBrowserWindow;
|
||||
});
|
||||
|
||||
this.welcomeScreenWindow.once('closed', () => {
|
||||
this.removeWindow(opts.winKey);
|
||||
this.welcomeScreenWindow = null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the main window
|
||||
*/
|
||||
@ -840,13 +757,6 @@ export class WindowHandler {
|
||||
return this.mainWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the welcome screen window
|
||||
*/
|
||||
public getWelcomeScreenWindow(): BrowserWindow | null {
|
||||
return this.welcomeScreenWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the main browser webContents
|
||||
*/
|
||||
|
@ -384,8 +384,7 @@ export const updateLocale = async (locale: LocaleType): Promise<void> => {
|
||||
* Displays a popup menu
|
||||
*/
|
||||
export const showPopupMenu = (opts: Electron.PopupOptions): void => {
|
||||
const browserWindow =
|
||||
windowHandler.getMainWindow() || windowHandler.getWelcomeScreenWindow();
|
||||
const browserWindow = windowHandler.getMainWindow();
|
||||
if (
|
||||
browserWindow &&
|
||||
windowExists(browserWindow) &&
|
||||
|
@ -57,7 +57,6 @@ export enum apiCmds {
|
||||
isAeroGlassEnabled = 'is-aero-glass-enabled',
|
||||
showScreenSharePermissionDialog = 'show-screen-share-permission-dialog',
|
||||
getMediaAccessStatus = 'get-media-access-status',
|
||||
setPodUrl = 'set-pod-url',
|
||||
setBroadcastMessage = 'set-broadcast-message',
|
||||
handleSwiftSearchMessageEvents = 'handle-shift-search-message-events',
|
||||
onSwiftSearchMessage = 'on-shift-search-message',
|
||||
@ -71,6 +70,7 @@ export enum apiCmds {
|
||||
updateAndRestart = 'update-and-restart',
|
||||
downloadUpdate = 'download-update',
|
||||
checkForUpdates = 'check-for-updates',
|
||||
seamlessLogin = 'seamless-login',
|
||||
}
|
||||
|
||||
export enum apiName {
|
||||
@ -118,6 +118,9 @@ export interface IApiArgs {
|
||||
requestId: number;
|
||||
mediaStatus: IMediaPermission;
|
||||
newPodUrl: string;
|
||||
startUrl: string;
|
||||
isPodConfigured: boolean;
|
||||
isSeamlessLoginEnabled: boolean;
|
||||
swiftSearchData: any;
|
||||
types: string[];
|
||||
thumbnailSize: Size;
|
||||
@ -282,3 +285,13 @@ export interface ICloud9Pipe {
|
||||
write(data: Uint8Array): void;
|
||||
close(): void;
|
||||
}
|
||||
|
||||
export type AuthType = 'password' | 'sso';
|
||||
|
||||
export interface IAuthResponse {
|
||||
status: string;
|
||||
podVersion: string;
|
||||
authenticationType: AuthType;
|
||||
ssoDisabledForMobile: boolean;
|
||||
keymanagerUrl: string;
|
||||
}
|
||||
|
@ -214,6 +214,13 @@
|
||||
"Welcome": {
|
||||
"Continue": "Continue",
|
||||
"Enable Single Sign On": "Enable Single Sign On",
|
||||
"Find your pod URL in your invitation email.": "Find your pod URL in your invitation email.",
|
||||
"Welcome to the largest global community in financial services with over": "Welcome to the largest global community in financial services with over",
|
||||
" half a million users": " half a million users",
|
||||
" 1,000 institutions.": " 1,000 institutions.",
|
||||
"Log in with your pod URL": "Log in with your pod URL",
|
||||
"You’ll momentarily be redirected to your web browser.": "You’ll momentarily be redirected to your web browser.",
|
||||
"log in": "log in",
|
||||
"Please enter a valid url": "Please enter a valid url",
|
||||
"Pod URL": "Pod URL",
|
||||
"SSO": "SSO",
|
||||
|
@ -214,6 +214,13 @@
|
||||
"Welcome": {
|
||||
"Continue": "Continue",
|
||||
"Enable Single Sign On": "Enable Single Sign On",
|
||||
"Find your pod URL in your invitation email.": "Find your pod URL in your invitation email.",
|
||||
"Welcome to the largest global community in financial services with over": "Welcome to the largest global community in financial services with over",
|
||||
" half a million users": " half a million users",
|
||||
" 1,000 institutions.": " 1,000 institutions.",
|
||||
"Log in with your pod URL": "Log in with your pod URL",
|
||||
"You’ll momentarily be redirected to your web browser.": "You’ll momentarily be redirected to your web browser.",
|
||||
"log in": "log in",
|
||||
"Please enter a valid url": "Please enter a valid url",
|
||||
"Pod URL": "Pod URL",
|
||||
"SSO": "SSO",
|
||||
|
11
src/renderer/assets/welcome-symphony-logo.svg
Normal file
11
src/renderer/assets/welcome-symphony-logo.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<svg width="296" height="70" viewBox="0 0 296 70" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M44.0497 27.1163V18.546C44.0497 16.7907 43.1018 15.1409 41.5765 14.2407C39.2929 12.8926 34.3464 10.6321 26.8796 10.6321C19.4127 10.6321 14.4663 12.8926 12.1826 14.2407C10.6573 15.1409 9.70941 16.7907 9.70941 18.546V31.4166L36.8955 39.3004V45.034C36.8955 45.8102 36.409 46.3542 35.582 46.7584L26.8796 51.126L18.1321 46.7362C17.3501 46.3542 16.8636 45.8102 16.8636 45.034V40.7338L9.70941 38.5836V45.034C9.70941 48.5753 11.7369 51.5883 14.9563 53.1579L26.8796 59.3681L38.7585 53.1801C42.0222 51.5883 44.0497 48.5753 44.0497 45.034V34.2834L16.8636 26.3996V19.8554C18.806 18.9165 22.1177 17.7991 26.8796 17.7991C31.6414 17.7991 34.9531 18.9165 36.8955 19.8554V24.9662L44.0497 27.1163Z" fill="#008EFF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M79.6153 47.1841C75.3165 47.1841 71.6321 45.7833 68.3233 43.6982L70.3703 40.5877C73.6791 42.7072 76.7152 43.7326 80.1269 43.7326C84.1189 43.7326 85.9951 42.1941 85.9951 40.3832C85.9951 35.1886 69.1076 38.2981 69.1076 30.0275C69.1076 25.9949 73.1336 22.8167 79.6153 22.8167C83.9821 22.8167 87.7685 24.4574 89.9863 26.6782L87.4617 29.2764C85.5515 27.6013 82.6174 26.2682 79.5474 26.2682C75.7601 26.2682 73.2016 27.6357 73.2016 29.5832C73.2016 34.4022 90.1231 31.8393 90.1231 39.9733C90.1231 44.2792 85.7903 47.1841 79.6153 47.1841Z" fill="#F8F8F8"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M106.67 37.2388V46.3637H102.576V37.2044L92.3418 23.6025H97.1172L104.794 34.1283L112.061 23.6025H116.768L106.67 37.2388Z" fill="#F8F8F8"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M145.324 46.3637V28.5238L144.198 30.9501L136.146 46.3637H133.69L125.742 30.9501L124.616 28.5238V46.3637H120.692V23.6025H126.389L134.031 38.913L135.089 41.237L136.146 38.913L143.686 23.6025H149.315V46.3637H145.324Z" fill="#F8F8F8"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M171.582 30.3695C171.582 28.4899 170.32 27.089 167.216 27.089H159.676V34.4365H167.386C170.49 34.4365 171.582 32.9324 171.582 31.0871V30.3695ZM166.772 37.7859H159.676V46.3642H155.582V23.603H166.772C172.981 23.603 175.71 26.4048 175.71 30.3695V30.9849C175.71 34.9487 172.981 37.7859 166.772 37.7859Z" fill="#F8F8F8"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M198.016 46.3637V36.5555H184.335V46.3637H180.242V23.6025H184.335V33.2406H198.016V23.6025H202.11V46.3637H198.016Z" fill="#F8F8F8"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M226.83 33.5818C226.83 29.6858 224.135 26.3365 219.155 26.3365C214.173 26.3365 211.512 29.6858 211.512 33.5818V36.3501C211.512 40.246 214.173 43.6642 219.155 43.6642C224.135 43.6642 226.83 40.246 226.83 36.3501V33.5818ZM219.154 47.1837C211.853 47.1837 207.383 41.9891 207.383 36.419V33.5818C207.383 27.9085 211.853 22.8162 219.154 22.8162C226.488 22.8162 230.957 27.9085 230.957 33.5818V36.419C230.957 41.9891 226.488 47.1837 219.154 47.1837Z" fill="#F8F8F8"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M254.595 46.3637L241.87 31.9754L240.232 29.8569V46.3637H236.172V23.6025H239.959L252.275 38.0252L253.946 40.1438V23.6025H257.972V46.3637H254.595Z" fill="#F8F8F8"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M276.192 37.2388V46.3637H272.098V37.2044L261.864 23.6025H266.64L274.316 34.1283L281.583 23.6025H286.29L276.192 37.2388Z" fill="#F8F8F8"/>
|
||||
</svg>
|
After Width: | Height: | Size: 3.3 KiB |
@ -7,21 +7,29 @@ interface IState {
|
||||
url: string;
|
||||
message: string;
|
||||
urlValid: boolean;
|
||||
isPodConfigured: boolean;
|
||||
isSeamlessLoginEnabled: boolean;
|
||||
}
|
||||
|
||||
const WELCOME_NAMESPACE = 'Welcome';
|
||||
const DEFAULT_MESSAGE = 'Find your pod URL in your invitation email.';
|
||||
const HEIGHT_WITH_POD_INPUT = '494px';
|
||||
const HEIGHT_WITHOUT_POD_INPUT = '376px';
|
||||
const DEFAULT_POD_URL = 'https://[POD].symphony.com';
|
||||
|
||||
export default class Welcome extends React.Component<{}, IState> {
|
||||
private readonly eventHandlers = {
|
||||
onSetPodUrl: () => this.setPodUrl(),
|
||||
onLogin: () => this.login(),
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
url: 'https://[POD].symphony.com',
|
||||
url: DEFAULT_POD_URL,
|
||||
message: '',
|
||||
urlValid: false,
|
||||
isPodConfigured: false,
|
||||
isSeamlessLoginEnabled: true,
|
||||
};
|
||||
this.updateState = this.updateState.bind(this);
|
||||
}
|
||||
@ -30,41 +38,84 @@ export default class Welcome extends React.Component<{}, IState> {
|
||||
* Render the component
|
||||
*/
|
||||
public render(): JSX.Element {
|
||||
const { url, message, urlValid } = this.state;
|
||||
const { url, message, urlValid, isPodConfigured } = this.state;
|
||||
return (
|
||||
<div className='Welcome' lang={i18n.getLocale()}>
|
||||
<div className='Welcome-image-container'>
|
||||
<img
|
||||
src='../renderer/assets/symphony-logo-plain.png'
|
||||
alt={i18n.t('Symphony Logo', WELCOME_NAMESPACE)()}
|
||||
/>
|
||||
</div>
|
||||
<div className='Welcome-main-container'>
|
||||
<h3 className='Welcome-name'>
|
||||
{i18n.t('Pod URL', WELCOME_NAMESPACE)()}
|
||||
</h3>
|
||||
<div className='Welcome-main-container-input-div'>
|
||||
<div className='Welcome-main-container-input-selection'>
|
||||
<input
|
||||
className='Welcome-main-container-podurl-box'
|
||||
type='url'
|
||||
value={url}
|
||||
onChange={this.updatePodUrl.bind(this)}
|
||||
></input>
|
||||
</div>
|
||||
<div
|
||||
className='Welcome'
|
||||
style={{
|
||||
height: isPodConfigured
|
||||
? HEIGHT_WITHOUT_POD_INPUT
|
||||
: HEIGHT_WITH_POD_INPUT,
|
||||
}}
|
||||
lang={i18n.getLocale()}
|
||||
>
|
||||
<div className='Welcome-content'>
|
||||
<div className='Welcome-image-container'>
|
||||
<img
|
||||
src='../renderer/assets/welcome-symphony-logo.svg'
|
||||
alt={i18n.t('Symphony Logo', WELCOME_NAMESPACE)()}
|
||||
/>
|
||||
</div>
|
||||
<label className='Welcome-message-label'>{message}</label>
|
||||
<button
|
||||
className={
|
||||
!urlValid
|
||||
? 'Welcome-continue-button-disabled'
|
||||
: 'Welcome-continue-button'
|
||||
}
|
||||
disabled={!urlValid}
|
||||
onClick={this.eventHandlers.onSetPodUrl}
|
||||
<div
|
||||
className='Welcome-about-symphony-text'
|
||||
style={{ marginTop: isPodConfigured ? '35px' : '8px' }}
|
||||
>
|
||||
{i18n.t('Continue', WELCOME_NAMESPACE)()}
|
||||
<span>
|
||||
{i18n.t(
|
||||
'Welcome to the largest global community in financial services with over',
|
||||
WELCOME_NAMESPACE,
|
||||
)()}
|
||||
</span>
|
||||
<span className='Welcome-text-bold'>
|
||||
{i18n.t(' half a million users', WELCOME_NAMESPACE)()}
|
||||
</span>
|
||||
<span>{i18n.t(' and more than', WELCOME_NAMESPACE)()}</span>
|
||||
<span className='Welcome-text-bold'>
|
||||
{i18n.t(' 1,000 institutions.', WELCOME_NAMESPACE)()}
|
||||
</span>
|
||||
</div>
|
||||
{!isPodConfigured && (
|
||||
<div>
|
||||
<div className='Welcome-login-text'>
|
||||
<span>
|
||||
{i18n.t('Log in with your pod URL', WELCOME_NAMESPACE)()}
|
||||
</span>
|
||||
</div>
|
||||
<div className='Welcome-input-container'>
|
||||
<span>{i18n.t('Pod URL', WELCOME_NAMESPACE)()}</span>
|
||||
<div>
|
||||
<input
|
||||
data-testid={'Welcome-main-container-podurl-box'}
|
||||
className='Welcome-main-container-podurl-box'
|
||||
type='url'
|
||||
value={url}
|
||||
onChange={this.updatePodUrl.bind(this)}
|
||||
/>
|
||||
<label className='Welcome-input-message'>
|
||||
{message
|
||||
? message
|
||||
: i18n.t(DEFAULT_MESSAGE, WELCOME_NAMESPACE)()}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<button
|
||||
className='Welcome-continue-button'
|
||||
disabled={!isPodConfigured && !urlValid}
|
||||
onClick={this.eventHandlers.onLogin}
|
||||
style={isPodConfigured ? { marginTop: '40px' } : {}}
|
||||
>
|
||||
{i18n.t('log in', WELCOME_NAMESPACE)()}
|
||||
</button>
|
||||
<div className='Welcome-redirect-info-text-container'>
|
||||
<span>
|
||||
{i18n.t(
|
||||
'You’ll momentarily be redirected to your web browser.',
|
||||
WELCOME_NAMESPACE,
|
||||
)()}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@ -85,13 +136,15 @@ export default class Welcome extends React.Component<{}, IState> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set pod url and pass it to the main process
|
||||
* Handle seamless login
|
||||
*/
|
||||
public setPodUrl(): void {
|
||||
const { url } = this.state;
|
||||
public login(): void {
|
||||
const { url, isPodConfigured, isSeamlessLoginEnabled } = this.state;
|
||||
ipcRenderer.send(apiName.symphonyApi, {
|
||||
cmd: apiCmds.setPodUrl,
|
||||
cmd: apiCmds.seamlessLogin,
|
||||
newPodUrl: url,
|
||||
isPodConfigured,
|
||||
isSeamlessLoginEnabled,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@ import ScreenPicker from './components/screen-picker';
|
||||
import ScreenSharingFrame from './components/screen-sharing-frame';
|
||||
import ScreenSharingIndicator from './components/screen-sharing-indicator';
|
||||
import SnippingTool from './components/snipping-tool';
|
||||
import Welcome from './components/welcome';
|
||||
import WindowsTitleBar from './components/windows-title-bar';
|
||||
|
||||
const enum components {
|
||||
@ -87,11 +86,6 @@ const load = () => {
|
||||
loadStyle(components.notificationSettings);
|
||||
component = NotificationSettings;
|
||||
break;
|
||||
case components.welcome:
|
||||
document.title = i18n.t('WelcomeText', 'Welcome')();
|
||||
loadStyle(components.welcome);
|
||||
component = Welcome;
|
||||
break;
|
||||
case components.titleBar:
|
||||
if (title) {
|
||||
document.title = title;
|
||||
|
@ -9,6 +9,7 @@ import DownloadManager from './components/download-manager';
|
||||
import MessageBanner from './components/message-banner';
|
||||
import NetworkError from './components/network-error';
|
||||
import SnackBar from './components/snack-bar';
|
||||
import Welcome from './components/welcome';
|
||||
import { SSFApi } from './ssf-api';
|
||||
|
||||
interface ISSFWindow extends Window {
|
||||
@ -183,3 +184,16 @@ ipcRenderer.on('exit-html-fullscreen', async () => {
|
||||
await document.exitFullscreen();
|
||||
}
|
||||
});
|
||||
|
||||
ipcRenderer.on('page-load-welcome', (_event, { locale, resources }) => {
|
||||
i18n.setResource(locale, resources);
|
||||
document.title = i18n.t('WelcomeText', 'Welcome')();
|
||||
const styles = document.createElement('link');
|
||||
styles.rel = 'stylesheet';
|
||||
styles.type = 'text/css';
|
||||
styles.href = `./styles/welcome.css`;
|
||||
document.getElementsByTagName('head')[0].appendChild(styles);
|
||||
const component = Welcome;
|
||||
const element = React.createElement(component);
|
||||
ReactDOM.render(element, document.getElementById('Root'));
|
||||
});
|
||||
|
@ -15,10 +15,10 @@
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
</head>
|
||||
<body>
|
||||
<div id="Root"></div>
|
||||
</body>
|
||||
</html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="Root" class="components-window-root"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -12,3 +12,6 @@
|
||||
@graphite-20: #cdcfd4;
|
||||
@graphite-05: #f1f1f3;
|
||||
@graphite-80: #27292c;
|
||||
@graphite-30: #b0b3ba;
|
||||
@graphite-40: #8f959e;
|
||||
@graphite-90: #141618;
|
||||
|
@ -9,12 +9,19 @@
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: white;
|
||||
background-color: @graphite-90;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.components-window-root {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.Welcome:lang(ja-JP) {
|
||||
font-family: @font-family-ja;
|
||||
|
||||
@ -34,18 +41,64 @@ body {
|
||||
}
|
||||
|
||||
.Welcome {
|
||||
width: 360px;
|
||||
height: 494px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
font-family: @font-family;
|
||||
background-color: @graphite-80;
|
||||
box-shadow: 0 24px 48px rgba(9, 10, 11, 0.64),
|
||||
0 4px 8px rgba(15, 27, 36, 0.16);
|
||||
border-radius: 8px;
|
||||
|
||||
&-content {
|
||||
width: 300px;
|
||||
padding: 48px 32px 24px;
|
||||
}
|
||||
|
||||
&-text-container {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
line-height: 20px;
|
||||
color: @graphite-05;
|
||||
}
|
||||
|
||||
&-image-container {
|
||||
text-align: center;
|
||||
margin: 50px 0 10px;
|
||||
}
|
||||
|
||||
&-image-container img {
|
||||
width: 200px;
|
||||
&-about-symphony-text {
|
||||
span {
|
||||
color: @white;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
&-login-text {
|
||||
margin-top: 32px;
|
||||
|
||||
span {
|
||||
color: @white;
|
||||
font-size: 18px;
|
||||
line-height: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
&-text-bold {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
&-input-container {
|
||||
margin-top: 24px;
|
||||
|
||||
span {
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: @graphite-20;
|
||||
}
|
||||
}
|
||||
|
||||
&-header-content {
|
||||
@ -65,17 +118,26 @@ body {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&-main-container-input-selection {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&-main-container-podurl-box {
|
||||
float: left;
|
||||
width: 100%;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #000;
|
||||
padding: 5px;
|
||||
max-width: -webkit-fill-available;
|
||||
height: 26px;
|
||||
background-color: @graphite-90;
|
||||
border: 2px solid @graphite-40;
|
||||
padding: 6px 12px;
|
||||
border-radius: 4px;
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
&-input-message {
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
margin-top: 4px;
|
||||
color: @graphite-20;
|
||||
}
|
||||
|
||||
&-main-container-sso-box {
|
||||
@ -140,6 +202,8 @@ body {
|
||||
}
|
||||
|
||||
&-continue-button {
|
||||
width: 300px;
|
||||
height: 40px;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
@ -149,40 +213,31 @@ body {
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
line-height: 12px;
|
||||
background-color: #3da2fd;
|
||||
background-color: @electricity-ui-50;
|
||||
color: #ffffff;
|
||||
cursor: pointer;
|
||||
text-transform: uppercase;
|
||||
float: right;
|
||||
margin: 24px 0px 4px 0;
|
||||
margin: 24px 0 4px 0;
|
||||
|
||||
&:focus {
|
||||
box-shadow: 0 0 10px rgba(61, 162, 253, 1);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background-color: @graphite-20;
|
||||
}
|
||||
}
|
||||
|
||||
&-continue-button-disabled {
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
font-size: 0.8rem;
|
||||
text-align: center;
|
||||
padding: 10px 32px;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
line-height: 12px;
|
||||
color: #ffffff;
|
||||
text-transform: uppercase;
|
||||
float: right;
|
||||
margin: 24px 0px 4px 0;
|
||||
cursor: not-allowed;
|
||||
background-color: #cccccc;
|
||||
pointer-events: none;
|
||||
&-redirect-info-text-container {
|
||||
margin-top: 32px;
|
||||
|
||||
&:focus {
|
||||
box-shadow: 0 0 10px rgba(61, 162, 253, 1);
|
||||
outline: none;
|
||||
span {
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
text-align: center;
|
||||
color: @graphite-30;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user