SDA-4369: Ability to Cancel changes made on pod URL (#1987)

This commit is contained in:
NguyenTranHoangSym 2023-10-19 15:30:41 +07:00 committed by GitHub
parent 069d83711d
commit c6dbb20222
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 88 additions and 14 deletions

View File

@ -6,7 +6,7 @@ import { ipcRenderer } from './__mocks__/electron';
describe('about app', () => { describe('about app', () => {
const aboutAppDataLabel = 'about-app-data'; const aboutAppDataLabel = 'about-app-data';
const aboutDataMock = { const aboutDataMockClipboard = {
sbeVersion: '1', sbeVersion: '1',
userConfig: {}, userConfig: {},
globalConfig: { isPodUrlEditable: true }, globalConfig: { isPodUrlEditable: true },
@ -31,6 +31,9 @@ describe('about app', () => {
httpParserVersion: '11.12', httpParserVersion: '11.12',
swiftSearchVersion: '1.55.3-beta.1', swiftSearchVersion: '1.55.3-beta.1',
swiftSearchSupportedVersion: 'N/A', swiftSearchSupportedVersion: 'N/A',
};
const aboutDataMockState = {
...aboutDataMockClipboard,
updatedHostname: 'N/A', updatedHostname: 'N/A',
}; };
const onLabelEvent = 'on'; const onLabelEvent = 'on';
@ -60,19 +63,19 @@ describe('about app', () => {
it('should call `updateState` when component is mounted', () => { it('should call `updateState` when component is mounted', () => {
const spy = jest.spyOn(AboutApp.prototype, 'setState'); const spy = jest.spyOn(AboutApp.prototype, 'setState');
shallow(React.createElement(AboutApp)); shallow(React.createElement(AboutApp));
ipcRenderer.send('about-app-data', aboutDataMock); ipcRenderer.send('about-app-data', aboutDataMockState);
expect(spy).toBeCalledWith(aboutDataMock); expect(spy).toBeCalledWith(aboutDataMockState);
}); });
it('should copy the correct data on to clipboard', () => { it('should copy the correct data on to clipboard', () => {
const spyIpc = jest.spyOn(ipcRenderer, ipcSendEvent); const spyIpc = jest.spyOn(ipcRenderer, ipcSendEvent);
const wrapper = shallow(React.createElement(AboutApp)); const wrapper = shallow(React.createElement(AboutApp));
ipcRenderer.send('about-app-data', aboutDataMock); ipcRenderer.send('about-app-data', aboutDataMockClipboard);
const copyButtonSelector = `[data-testid="COPY_BUTTON"]`; const copyButtonSelector = `[data-testid="COPY_BUTTON"]`;
wrapper.find(copyButtonSelector).simulate('click'); wrapper.find(copyButtonSelector).simulate('click');
const expectedData = { const expectedData = {
cmd: apiCmds.aboutAppClipBoardData, cmd: apiCmds.aboutAppClipBoardData,
clipboard: aboutDataMock, clipboard: aboutDataMockClipboard,
clipboardType: 'clipboard', clipboardType: 'clipboard',
}; };
expect(spyIpc).toBeCalledWith('symphony-api', expectedData); expect(spyIpc).toBeCalledWith('symphony-api', expectedData);
@ -80,7 +83,7 @@ describe('about app', () => {
it('should display input when triple clicked on pod', () => { it('should display input when triple clicked on pod', () => {
const wrapper = shallow(React.createElement(AboutApp)); const wrapper = shallow(React.createElement(AboutApp));
ipcRenderer.send('about-app-data', aboutDataMock); ipcRenderer.send('about-app-data', aboutDataMockState);
const pod = wrapper.find(`[data-testid="POD_INFO"]`); const pod = wrapper.find(`[data-testid="POD_INFO"]`);
pod.simulate('click', { detail: 1 }); pod.simulate('click', { detail: 1 });
pod.simulate('click', { detail: 2 }); pod.simulate('click', { detail: 2 });
@ -90,7 +93,7 @@ describe('about app', () => {
}); });
it('should not display input when triple clicked on pod', () => { it('should not display input when triple clicked on pod', () => {
const cloneAboutDataMock = aboutDataMock; const cloneAboutDataMock = aboutDataMockState;
cloneAboutDataMock.globalConfig = { isPodUrlEditable: false }; cloneAboutDataMock.globalConfig = { isPodUrlEditable: false };
cloneAboutDataMock.userConfig = { isPodUrlEditable: true }; cloneAboutDataMock.userConfig = { isPodUrlEditable: true };
@ -106,7 +109,7 @@ describe('about app', () => {
}); });
it('should not display config based on global config only', () => { it('should not display config based on global config only', () => {
const cloneAboutDataMock = aboutDataMock; const cloneAboutDataMock = aboutDataMockState;
cloneAboutDataMock.globalConfig = { isPodUrlEditable: false }; cloneAboutDataMock.globalConfig = { isPodUrlEditable: false };
cloneAboutDataMock.userConfig = { isPodUrlEditable: false }; cloneAboutDataMock.userConfig = { isPodUrlEditable: false };
@ -122,7 +125,7 @@ describe('about app', () => {
}); });
it('should display config based on global config only', () => { it('should display config based on global config only', () => {
const cloneAboutDataMock = aboutDataMock; const cloneAboutDataMock = aboutDataMockState;
cloneAboutDataMock.globalConfig = { isPodUrlEditable: true }; cloneAboutDataMock.globalConfig = { isPodUrlEditable: true };
cloneAboutDataMock.userConfig = { isPodUrlEditable: false }; cloneAboutDataMock.userConfig = { isPodUrlEditable: false };
@ -136,4 +139,21 @@ describe('about app', () => {
const podInput = wrapper.find('.AboutApp-pod-input'); const podInput = wrapper.find('.AboutApp-pod-input');
expect(podInput.exists()).toEqual(true); expect(podInput.exists()).toEqual(true);
}); });
it('should display cancel button on triple click and behave correctly', () => {
const cloneAboutDataMock = aboutDataMockState;
cloneAboutDataMock.globalConfig = { isPodUrlEditable: true };
cloneAboutDataMock.userConfig = { isPodUrlEditable: false };
const wrapper = shallow(React.createElement(AboutApp));
ipcRenderer.send('about-app-data', cloneAboutDataMock);
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('[data-testid="CANCEL_BUTTON"]');
podInput.simulate('click');
expect(wrapper.find(`[data-testid="POD_INFO"]`).exists()).toEqual(true);
});
}); });

View File

@ -1277,7 +1277,9 @@ export class WindowHandler {
...filteredConfig, ...filteredConfig,
}; };
const host = parse( const host = parse(
(userConfig as IConfig).url || (globalConfig as IConfig).url, this.url
? this.url
: (userConfig as IConfig).url || (globalConfig as IConfig).url,
); );
const aboutInfo = { const aboutInfo = {
userConfig, userConfig,

View File

@ -10,7 +10,8 @@
"Close": "Close", "Close": "Close",
"Copyright": "Copyright", "Copyright": "Copyright",
"Desktop Application": "Desktop Application", "Desktop Application": "Desktop Application",
"Save and Restart": "Save and Restart" "Save and Restart": "Save and Restart",
"Cancel": "Cancel"
}, },
"Actual Size": "Actual Size", "Actual Size": "Actual Size",
"Always on Top": "Always on Top", "Always on Top": "Always on Top",

View File

@ -10,7 +10,8 @@
"Close": "Close", "Close": "Close",
"Copyright": "Copyright", "Copyright": "Copyright",
"Desktop Application": "Desktop Application", "Desktop Application": "Desktop Application",
"Save and Restart": "Save and Restart" "Save and Restart": "Save and Restart",
"Cancel": "Cancel"
}, },
"Actual Size": "Actual Size", "Actual Size": "Actual Size",
"Always on Top": "Always on Top", "Always on Top": "Always on Top",

View File

@ -37,7 +37,7 @@ interface IState {
swiftSearchVersion?: string; swiftSearchVersion?: string;
swiftSearchSupportedVersion?: string; swiftSearchSupportedVersion?: string;
client?: string; client?: string;
updatedHostname: string; updatedHostname?: string;
isPodEditing: boolean; isPodEditing: boolean;
isValidHostname: boolean; isValidHostname: boolean;
didUpdateHostname: boolean; didUpdateHostname: boolean;
@ -57,6 +57,7 @@ export default class AboutApp extends React.Component<{}, IState> {
private readonly eventHandlers = { private readonly eventHandlers = {
onCopy: () => this.copy(), onCopy: () => this.copy(),
onClose: () => this.close(), onClose: () => this.close(),
onCancel: () => this.cancel(),
onPodClick: (event) => this.onPodClick(event), onPodClick: (event) => this.onPodClick(event),
onPodChange: (event) => this.handlePodChange(event), onPodChange: (event) => this.handlePodChange(event),
onPodInputBlur: (event) => this.handlePodInputBlur(event), onPodInputBlur: (event) => this.handlePodInputBlur(event),
@ -149,6 +150,7 @@ export default class AboutApp extends React.Component<{}, IState> {
isValidHostname && didUpdateHostname isValidHostname && didUpdateHostname
? i18n.t('Save and Restart', ABOUT_SYMPHONY_NAMESPACE)() ? i18n.t('Save and Restart', ABOUT_SYMPHONY_NAMESPACE)()
: i18n.t('Close', ABOUT_SYMPHONY_NAMESPACE)(); : i18n.t('Close', ABOUT_SYMPHONY_NAMESPACE)();
const cancelText = i18n.t('Cancel', ABOUT_SYMPHONY_NAMESPACE)();
return ( return (
<div className='AboutApp' lang={i18n.getLocale()}> <div className='AboutApp' lang={i18n.getLocale()}>
@ -186,6 +188,16 @@ export default class AboutApp extends React.Component<{}, IState> {
</button> </button>
</div> </div>
<div className='AboutApp-close-container'> <div className='AboutApp-close-container'>
{this.state.isPodEditing && (
<button
className='AboutApp-cancel-button'
onClick={this.eventHandlers.onCancel}
title={cancelText}
data-testid={'CANCEL_BUTTON'}
>
{cancelText}
</button>
)}
<button <button
className='AboutApp-close-button' className='AboutApp-close-button'
onClick={this.eventHandlers.onClose} onClick={this.eventHandlers.onClose}
@ -231,6 +243,7 @@ export default class AboutApp extends React.Component<{}, IState> {
...rest, ...rest,
}; };
if (data) { if (data) {
delete data.updatedHostname;
ipcRenderer.send(apiName.symphonyApi, { ipcRenderer.send(apiName.symphonyApi, {
cmd: apiCmds.aboutAppClipBoardData, cmd: apiCmds.aboutAppClipBoardData,
clipboard: data, clipboard: data,
@ -250,6 +263,18 @@ export default class AboutApp extends React.Component<{}, IState> {
} }
} }
/**
* Cancel modal and restore old url
*/
public cancel(): void {
this.setState({
updatedHostname: this.previousUrl,
isPodEditing: false,
isValidHostname: true,
hostname: this.previousUrl,
});
}
/** /**
* Enables editing mode * Enables editing mode
*/ */
@ -298,7 +323,7 @@ export default class AboutApp extends React.Component<{}, IState> {
*/ */
public handlePodInputBlur = (_event) => { public handlePodInputBlur = (_event) => {
const { updatedHostname, hostname } = this.state; const { updatedHostname, hostname } = this.state;
if (!HOSTNAME_REGEX.test(updatedHostname)) { if (!HOSTNAME_REGEX.test(updatedHostname || '')) {
this.setState({ this.setState({
isPodEditing: false, isPodEditing: false,
isValidHostname: false, isValidHostname: false,

View File

@ -188,6 +188,31 @@ body {
} }
} }
&-cancel-button {
box-shadow: none;
border: none;
border-radius: 20px;
font-size: 0.875rem;
text-align: center;
display: inline-block;
text-decoration: none;
line-height: 12px;
background-color: @electricity-ui-50;
color: @electricity-ui-05;
cursor: pointer;
box-sizing: border-box;
text-transform: uppercase;
font-weight: 600;
width: 120px;
margin-right: 8px;
height: 36px;
&:focus {
box-shadow: 0 0 10px rgba(61, 162, 253, 1);
outline: none;
}
}
&-version-container { &-version-container {
width: 100%; width: 100%;
} }