mirror of
https://github.com/finos/SymphonyElectron.git
synced 2025-02-25 18:55:29 -06:00
SDA-4186 (Add support to update user POD settings) (#1904)
* SDA-4186 - Add support to update user POD settings Signed-off-by: Kiran Niranjan <kiran.niranjan@symphony.com> * SDA-4186 - Add support to update user POD settings Signed-off-by: Kiran Niranjan <kiran.niranjan@symphony.com> * SDA-4186 - Fix unit test Signed-off-by: Kiran Niranjan <kiran.niranjan@symphony.com> * SDA-4186 - Add unit test Signed-off-by: Kiran Niranjan <kiran.niranjan@symphony.com> * SDA-4186 - Change pod info to user config Signed-off-by: Kiran Niranjan <kiran.niranjan@symphony.com> --------- Signed-off-by: Kiran Niranjan <kiran.niranjan@symphony.com>
This commit is contained in:
parent
8eae1f77a4
commit
2d75704d7f
@ -31,6 +31,7 @@ describe('about app', () => {
|
||||
httpParserVersion: '11.12',
|
||||
swiftSearchVersion: '1.55.3-beta.1',
|
||||
swiftSearchSupportedVersion: 'N/A',
|
||||
updatedHostname: 'N/A',
|
||||
};
|
||||
const onLabelEvent = 'on';
|
||||
const ipcSendEvent = 'send';
|
||||
@ -76,4 +77,15 @@ describe('about app', () => {
|
||||
};
|
||||
expect(spyIpc).toBeCalledWith('symphony-api', expectedData);
|
||||
});
|
||||
|
||||
it('should display input when triple clicked on pod', () => {
|
||||
const wrapper = shallow(React.createElement(AboutApp));
|
||||
ipcRenderer.send('about-app-data', aboutDataMock);
|
||||
const pod = wrapper.find(`[data-testid="POD_INFO"]`);
|
||||
pod.simulate('click', { detail: 1 });
|
||||
pod.simulate('click', { detail: 2 });
|
||||
pod.simulate('click', { detail: 3 });
|
||||
const podInput = wrapper.find('.AboutApp-pod-input');
|
||||
expect(podInput.exists()).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
@ -1184,6 +1184,13 @@ export class WindowHandler {
|
||||
this.aboutAppWindow = null;
|
||||
}
|
||||
};
|
||||
const handleUserPodUpdate = async (_event, hostname) => {
|
||||
logger.info('window-handler: user updated pod url', hostname);
|
||||
const url = new URL(`https://${hostname}`).toString();
|
||||
await config.updateUserConfig({ url });
|
||||
app.relaunch();
|
||||
app.exit();
|
||||
};
|
||||
|
||||
await versionHandler.getClientVersion(true, this.url);
|
||||
|
||||
@ -1208,6 +1215,7 @@ export class WindowHandler {
|
||||
});
|
||||
|
||||
ipcMain.once('close-about-app', closeAboutApp);
|
||||
ipcMain.once('user-pod-updated', handleUserPodUpdate);
|
||||
|
||||
this.aboutAppWindow.webContents.once('did-finish-load', async () => {
|
||||
let client = '';
|
||||
@ -1216,7 +1224,7 @@ export class WindowHandler {
|
||||
}
|
||||
const ABOUT_SYMPHONY_NAMESPACE = 'AboutSymphony';
|
||||
const versionLocalised = i18n.t('Version', ABOUT_SYMPHONY_NAMESPACE)();
|
||||
const { hostname } = parse(this.url || this.globalConfig.url);
|
||||
const { hostname } = parse(this.userConfig.url || this.globalConfig.url);
|
||||
const userConfig = config.userConfig;
|
||||
const globalConfig = config.globalConfig;
|
||||
const cloudConfig = config.cloudConfig;
|
||||
|
@ -9,7 +9,8 @@
|
||||
"Copy config to clipboard": "Copy config to clipboard",
|
||||
"Close": "Close",
|
||||
"Copyright": "Copyright",
|
||||
"Desktop Application": "Desktop Application"
|
||||
"Desktop Application": "Desktop Application",
|
||||
"Save and Restart": "Save and Restart"
|
||||
},
|
||||
"Actual Size": "Actual Size",
|
||||
"Always on Top": "Always on Top",
|
||||
|
@ -9,7 +9,8 @@
|
||||
"Copy config to clipboard": "Copy config to clipboard",
|
||||
"Close": "Close",
|
||||
"Copyright": "Copyright",
|
||||
"Desktop Application": "Desktop Application"
|
||||
"Desktop Application": "Desktop Application",
|
||||
"Save and Restart": "Save and Restart"
|
||||
},
|
||||
"Actual Size": "Actual Size",
|
||||
"Always on Top": "Always on Top",
|
||||
|
@ -1,3 +1,4 @@
|
||||
import classNames from 'classnames';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import * as React from 'react';
|
||||
import { productName } from '../../../package.json';
|
||||
@ -5,6 +6,9 @@ import { apiCmds, apiName } from '../../common/api-interface';
|
||||
import { i18n } from '../../common/i18n-preload';
|
||||
import * as CopyIcon from '../../renderer/assets/copy-icon.svg';
|
||||
import * as SymphonyLogo from '../../renderer/assets/new-symphony-logo.svg';
|
||||
|
||||
const HOSTNAME_REGEX = /^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
||||
|
||||
interface IState {
|
||||
userConfig: object;
|
||||
globalConfig: object;
|
||||
@ -32,6 +36,10 @@ interface IState {
|
||||
swiftSearchVersion?: string;
|
||||
swiftSearchSupportedVersion?: string;
|
||||
client?: string;
|
||||
updatedHostname: string;
|
||||
isPodEditing: boolean;
|
||||
isValidHostname: boolean;
|
||||
didUpdateHostname: boolean;
|
||||
}
|
||||
|
||||
const ABOUT_SYMPHONY_NAMESPACE = 'AboutSymphony';
|
||||
@ -44,6 +52,9 @@ export default class AboutApp extends React.Component<{}, IState> {
|
||||
private readonly eventHandlers = {
|
||||
onCopy: () => this.copy(),
|
||||
onClose: () => this.close(),
|
||||
onPodClick: (event) => this.onPodClick(event),
|
||||
onPodChange: (event) => this.handlePodChange(event),
|
||||
onPodInputBlur: (event) => this.handlePodInputBlur(event),
|
||||
};
|
||||
private closeButtonRef: React.RefObject<HTMLButtonElement>;
|
||||
|
||||
@ -75,6 +86,10 @@ export default class AboutApp extends React.Component<{}, IState> {
|
||||
httpParserVersion: '',
|
||||
swiftSearchVersion: '',
|
||||
swiftSearchSupportedVersion: '',
|
||||
updatedHostname: '',
|
||||
isPodEditing: false,
|
||||
isValidHostname: true,
|
||||
didUpdateHostname: false,
|
||||
};
|
||||
this.updateState = this.updateState.bind(this);
|
||||
}
|
||||
@ -91,6 +106,8 @@ export default class AboutApp extends React.Component<{}, IState> {
|
||||
sdaVersion,
|
||||
sdaBuildNumber,
|
||||
client,
|
||||
didUpdateHostname,
|
||||
isValidHostname,
|
||||
} = this.state;
|
||||
|
||||
const appName = productName || 'Symphony';
|
||||
@ -122,6 +139,10 @@ export default class AboutApp extends React.Component<{}, IState> {
|
||||
value: `${formattedSfeVersion} ${client}`,
|
||||
},
|
||||
];
|
||||
const closeButtonText =
|
||||
isValidHostname && didUpdateHostname
|
||||
? i18n.t('Save and Restart', ABOUT_SYMPHONY_NAMESPACE)()
|
||||
: i18n.t('Close', ABOUT_SYMPHONY_NAMESPACE)();
|
||||
|
||||
return (
|
||||
<div className='AboutApp' lang={i18n.getLocale()}>
|
||||
@ -162,11 +183,11 @@ export default class AboutApp extends React.Component<{}, IState> {
|
||||
<button
|
||||
className='AboutApp-close-button'
|
||||
onClick={this.eventHandlers.onClose}
|
||||
title={i18n.t('Close', ABOUT_SYMPHONY_NAMESPACE)()}
|
||||
title={closeButtonText}
|
||||
data-testid={'CLOSE_BUTTON'}
|
||||
ref={this.closeButtonRef}
|
||||
>
|
||||
{i18n.t('Close', ABOUT_SYMPHONY_NAMESPACE)()}
|
||||
{closeButtonText}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -199,7 +220,10 @@ export default class AboutApp extends React.Component<{}, IState> {
|
||||
*/
|
||||
public copy(): void {
|
||||
const { clientVersion, ...rest } = this.state;
|
||||
const data = { ...{ sbeVersion: clientVersion }, ...rest };
|
||||
const { isPodEditing, isValidHostname, didUpdateHostname, ...data } = {
|
||||
...{ sbeVersion: clientVersion },
|
||||
...rest,
|
||||
};
|
||||
if (data) {
|
||||
ipcRenderer.send(apiName.symphonyApi, {
|
||||
cmd: apiCmds.aboutAppClipBoardData,
|
||||
@ -213,9 +237,53 @@ export default class AboutApp extends React.Component<{}, IState> {
|
||||
* Close modal
|
||||
*/
|
||||
public close(): void {
|
||||
const { isValidHostname, didUpdateHostname, hostname } = this.state;
|
||||
ipcRenderer.send('close-about-app');
|
||||
if (isValidHostname && didUpdateHostname) {
|
||||
ipcRenderer.send('user-pod-updated', hostname);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables editing mode
|
||||
*/
|
||||
public onPodClick(e): void {
|
||||
if (e.detail === 3) {
|
||||
this.setState({
|
||||
isPodEditing: true,
|
||||
didUpdateHostname: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates state with new POD URL
|
||||
* @param e
|
||||
*/
|
||||
public handlePodChange = (e) => {
|
||||
const { value } = e.target;
|
||||
this.setState({ updatedHostname: value });
|
||||
};
|
||||
|
||||
/**
|
||||
* Validates and sets new hostname
|
||||
*/
|
||||
public handlePodInputBlur = (_event) => {
|
||||
const { updatedHostname, hostname } = this.state;
|
||||
if (!HOSTNAME_REGEX.test(updatedHostname)) {
|
||||
this.setState({
|
||||
isPodEditing: false,
|
||||
isValidHostname: false,
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
isPodEditing: false,
|
||||
isValidHostname: true,
|
||||
hostname: updatedHostname || hostname,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the component state
|
||||
*
|
||||
@ -223,7 +291,8 @@ export default class AboutApp extends React.Component<{}, IState> {
|
||||
* @param data {Object} { buildNumber, clientVersion, version }
|
||||
*/
|
||||
private updateState(_event, data): void {
|
||||
this.setState(data as IState);
|
||||
const updatedData = { ...data, updatedHostname: data.hostname };
|
||||
this.setState(updatedData as IState);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -234,14 +303,46 @@ export default class AboutApp extends React.Component<{}, IState> {
|
||||
return (
|
||||
<section>
|
||||
<ul className='AboutApp-symphony-section'>
|
||||
{symphonySectionItems.map((item, key) => (
|
||||
<li key={key}>
|
||||
<strong>{item.key}</strong>
|
||||
<span>{item.value}</span>
|
||||
</li>
|
||||
))}
|
||||
{symphonySectionItems.map((item, key) => {
|
||||
if (item.key === 'POD:') {
|
||||
return this.renderEditablePodElement(item, key);
|
||||
}
|
||||
return (
|
||||
<li key={key}>
|
||||
<strong>{item.key}</strong>
|
||||
<span>{item.value}</span>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
private renderEditablePodElement = (item, key) => {
|
||||
const { isPodEditing, isValidHostname, updatedHostname } = this.state;
|
||||
return (
|
||||
<li key={key}>
|
||||
<strong className={'AboutApp-pod'}>{item.key}</strong>
|
||||
{isPodEditing ? (
|
||||
<input
|
||||
className={'AboutApp-pod-input'}
|
||||
type='text'
|
||||
value={updatedHostname}
|
||||
onChange={this.handlePodChange}
|
||||
onBlur={this.handlePodInputBlur}
|
||||
autoFocus
|
||||
/>
|
||||
) : (
|
||||
<span
|
||||
data-testid={'POD_INFO'}
|
||||
className={classNames({ 'invalid-pod': !isValidHostname })}
|
||||
onClick={this.eventHandlers.onPodClick}
|
||||
>
|
||||
{updatedHostname}
|
||||
</span>
|
||||
)}
|
||||
</li>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
@ -200,4 +200,19 @@ body {
|
||||
line-height: 16px;
|
||||
color: @graphite-20;
|
||||
}
|
||||
|
||||
&-symphony-section > li > input {
|
||||
display: flex;
|
||||
margin: 0 6px;
|
||||
color: @graphite-80;
|
||||
}
|
||||
|
||||
&-symphony-section > li > .invalid-pod {
|
||||
color: red;
|
||||
}
|
||||
|
||||
&-pod {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user