[MM-39491] Force Add Server modal to stay until server has been added (#1869)
* [MM-39491] Force Add Server modal to stay until server has been added * Make the parameter optional * Actually do the logic, add a test for the logic * Add remove event listener
This commit is contained in:
parent
b4903d24c9
commit
a4a275bd73
|
@ -4,6 +4,8 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const robot = require('robotjs');
|
||||
|
||||
const env = require('../../modules/environment');
|
||||
|
||||
describe('startup/app', function desc() {
|
||||
|
@ -27,6 +29,17 @@ describe('startup/app', function desc() {
|
|||
modalTitle.should.equal('Add Server');
|
||||
});
|
||||
|
||||
it('MM-T4419 should not allow the user to close the new server modal when no servers exist', async () => {
|
||||
const newServerModal = this.app.windows().find((window) => window.url().includes('newServer'));
|
||||
|
||||
const existing = await newServerModal.isVisible('#cancelNewServerModal');
|
||||
existing.should.be.false;
|
||||
|
||||
robot.keyTap('escape');
|
||||
const existingModal = this.app.windows().find((window) => window.url().includes('newServer'));
|
||||
existingModal.should.not.be.null;
|
||||
});
|
||||
|
||||
it('MM-T4399_2 should show no servers configured in dropdown when no servers exist', async () => {
|
||||
const mainWindow = this.app.windows().find((window) => window.url().includes('index'));
|
||||
const dropdownButtonText = await mainWindow.innerText('.TeamDropdownButton');
|
||||
|
|
|
@ -104,3 +104,6 @@ export const GET_AVAILABLE_SPELL_CHECKER_LANGUAGES = 'get-available-spell-checke
|
|||
|
||||
export const GET_VIEW_NAME = 'get-view-name';
|
||||
export const GET_VIEW_WEBCONTENTS_ID = 'get-view-webcontents-id';
|
||||
|
||||
export const GET_MODAL_UNCLOSEABLE = 'get-modal-uncloseable';
|
||||
export const MODAL_UNCLOSEABLE = 'modal-uncloseable';
|
||||
|
|
|
@ -554,7 +554,7 @@ function handleNewServerModal() {
|
|||
if (!mainWindow) {
|
||||
return;
|
||||
}
|
||||
const modalPromise = addModal<unknown, Team>('newServer', html, modalPreload, {}, mainWindow);
|
||||
const modalPromise = addModal<unknown, Team>('newServer', html, modalPreload, {}, mainWindow, config.teams.length === 0);
|
||||
if (modalPromise) {
|
||||
modalPromise.then((data) => {
|
||||
const teams = config.teams;
|
||||
|
|
|
@ -6,10 +6,29 @@
|
|||
|
||||
import {ipcRenderer} from 'electron';
|
||||
|
||||
import {MODAL_CANCEL, MODAL_RESULT, MODAL_INFO, RETRIEVE_MODAL_INFO, MODAL_SEND_IPC_MESSAGE, GET_DARK_MODE, DARK_MODE_CHANGE} from 'common/communication';
|
||||
import {
|
||||
MODAL_CANCEL,
|
||||
MODAL_RESULT,
|
||||
MODAL_INFO,
|
||||
RETRIEVE_MODAL_INFO,
|
||||
MODAL_SEND_IPC_MESSAGE,
|
||||
GET_DARK_MODE,
|
||||
DARK_MODE_CHANGE,
|
||||
GET_MODAL_UNCLOSEABLE,
|
||||
MODAL_UNCLOSEABLE,
|
||||
} from 'common/communication';
|
||||
|
||||
console.log('preloaded for the modal!');
|
||||
|
||||
let uncloseable = false;
|
||||
const createKeyDownListener = () => {
|
||||
window.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape' && !uncloseable) {
|
||||
ipcRenderer.send(MODAL_CANCEL);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
window.addEventListener('message', async (event) => {
|
||||
switch (event.data.type) {
|
||||
case MODAL_CANCEL: {
|
||||
|
@ -26,6 +45,12 @@ window.addEventListener('message', async (event) => {
|
|||
console.log('getting modal data');
|
||||
window.postMessage({type: MODAL_INFO, data: await ipcRenderer.invoke(RETRIEVE_MODAL_INFO)}, window.location.href);
|
||||
break;
|
||||
case GET_MODAL_UNCLOSEABLE:
|
||||
console.log('get modal uncloseable');
|
||||
uncloseable = await ipcRenderer.invoke(GET_MODAL_UNCLOSEABLE);
|
||||
createKeyDownListener();
|
||||
window.postMessage({type: MODAL_UNCLOSEABLE, data: uncloseable}, window.location.href);
|
||||
break;
|
||||
case MODAL_SEND_IPC_MESSAGE:
|
||||
console.log('sending custom ipc message');
|
||||
ipcRenderer.send(event.data.data.type, ...event.data.data.args);
|
||||
|
@ -40,11 +65,7 @@ window.addEventListener('message', async (event) => {
|
|||
}
|
||||
});
|
||||
|
||||
window.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
ipcRenderer.send(MODAL_CANCEL);
|
||||
}
|
||||
});
|
||||
createKeyDownListener();
|
||||
|
||||
ipcRenderer.on(DARK_MODE_CHANGE, (event, darkMode) => {
|
||||
window.postMessage({type: DARK_MODE_CHANGE, data: darkMode}, window.location.href);
|
||||
|
|
|
@ -6,7 +6,16 @@ import {IpcMainEvent, IpcMainInvokeEvent} from 'electron/main';
|
|||
|
||||
import {CombinedConfig} from 'types/config';
|
||||
|
||||
import {RETRIEVE_MODAL_INFO, MODAL_CANCEL, MODAL_RESULT, MODAL_OPEN, MODAL_CLOSE, EMIT_CONFIGURATION, DARK_MODE_CHANGE} from 'common/communication';
|
||||
import {
|
||||
RETRIEVE_MODAL_INFO,
|
||||
MODAL_CANCEL,
|
||||
MODAL_RESULT,
|
||||
MODAL_OPEN,
|
||||
MODAL_CLOSE,
|
||||
EMIT_CONFIGURATION,
|
||||
DARK_MODE_CHANGE,
|
||||
GET_MODAL_UNCLOSEABLE,
|
||||
} from 'common/communication';
|
||||
|
||||
import * as WindowManager from '../windows/windowManager';
|
||||
|
||||
|
@ -16,11 +25,11 @@ let modalQueue: Array<ModalView<any, any>> = [];
|
|||
const modalPromises: Map<string, Promise<any>> = new Map();
|
||||
|
||||
// TODO: add a queue/add differentiation, in case we need to put a modal first in line
|
||||
export function addModal<T, T2>(key: string, html: string, preload: string, data: T, win: BrowserWindow) {
|
||||
export function addModal<T, T2>(key: string, html: string, preload: string, data: T, win: BrowserWindow, uncloseable = false) {
|
||||
const foundModal = modalQueue.find((modal) => modal.key === key);
|
||||
if (!foundModal) {
|
||||
const modalPromise = new Promise((resolve: (value: T2) => void, reject) => {
|
||||
const mv = new ModalView<T, T2>(key, html, preload, data, resolve, reject, win);
|
||||
const mv = new ModalView<T, T2>(key, html, preload, data, resolve, reject, win, uncloseable);
|
||||
modalQueue.push(mv);
|
||||
});
|
||||
|
||||
|
@ -34,6 +43,7 @@ export function addModal<T, T2>(key: string, html: string, preload: string, data
|
|||
return modalPromises.get(key) as Promise<T2>;
|
||||
}
|
||||
|
||||
ipcMain.handle(GET_MODAL_UNCLOSEABLE, handleGetModalUncloseable);
|
||||
ipcMain.handle(RETRIEVE_MODAL_INFO, handleInfoRequest);
|
||||
ipcMain.on(MODAL_RESULT, handleModalResult);
|
||||
ipcMain.on(MODAL_CANCEL, handleModalCancel);
|
||||
|
@ -118,3 +128,9 @@ ipcMain.on(EMIT_CONFIGURATION, (event: IpcMainEvent, config: CombinedConfig) =>
|
|||
modal.view.webContents.send(DARK_MODE_CHANGE, config.darkMode);
|
||||
});
|
||||
});
|
||||
|
||||
function handleGetModalUncloseable(event: IpcMainInvokeEvent) {
|
||||
const modalView = modalQueue.find((modal) => modal.view.webContents.id === event.sender.id);
|
||||
return modalView?.uncloseable;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,8 +24,9 @@ export class ModalView<T, T2> {
|
|||
windowAttached?: BrowserWindow;
|
||||
status: Status;
|
||||
contextMenu: ContextMenu;
|
||||
uncloseable: boolean;
|
||||
|
||||
constructor(key: string, html: string, preload: string, data: T, onResolve: (value: T2) => void, onReject: (value: T2) => void, currentWindow: BrowserWindow) {
|
||||
constructor(key: string, html: string, preload: string, data: T, onResolve: (value: T2) => void, onReject: (value: T2) => void, currentWindow: BrowserWindow, uncloseable: boolean) {
|
||||
this.key = key;
|
||||
this.html = html;
|
||||
this.data = data;
|
||||
|
@ -42,6 +43,7 @@ export class ModalView<T, T2> {
|
|||
this.onReject = onReject;
|
||||
this.onResolve = onResolve;
|
||||
this.window = currentWindow;
|
||||
this.uncloseable = uncloseable;
|
||||
|
||||
this.status = Status.ACTIVE;
|
||||
try {
|
||||
|
|
|
@ -10,7 +10,7 @@ import {TeamWithIndex} from 'types/config';
|
|||
import urlUtils from 'common/utils/url';
|
||||
|
||||
type Props = {
|
||||
onClose: () => void;
|
||||
onClose?: () => void;
|
||||
onSave?: (team: TeamWithIndex) => void;
|
||||
team?: TeamWithIndex;
|
||||
editMode?: boolean;
|
||||
|
@ -175,7 +175,7 @@ export default class NewTeamModal extends React.PureComponent<Props, State> {
|
|||
e.stopPropagation();
|
||||
break;
|
||||
case 'Escape':
|
||||
this.props.onClose();
|
||||
this.props.onClose?.();
|
||||
break;
|
||||
}
|
||||
}}
|
||||
|
@ -237,17 +237,25 @@ export default class NewTeamModal extends React.PureComponent<Props, State> {
|
|||
{this.getError()}
|
||||
</div>
|
||||
|
||||
<Button
|
||||
id='cancelNewServerModal'
|
||||
onClick={this.props.onClose}
|
||||
variant='link'
|
||||
>{'Cancel'}</Button>
|
||||
<Button
|
||||
id='saveNewServerModal'
|
||||
onClick={this.save}
|
||||
disabled={!this.validateForm()}
|
||||
variant='primary'
|
||||
>{this.getSaveButtonLabel()}</Button>
|
||||
{this.props.onClose &&
|
||||
<Button
|
||||
id='cancelNewServerModal'
|
||||
onClick={this.props.onClose}
|
||||
variant='link'
|
||||
>
|
||||
{'Cancel'}
|
||||
</Button>
|
||||
}
|
||||
{this.props.onSave &&
|
||||
<Button
|
||||
id='saveNewServerModal'
|
||||
onClick={this.save}
|
||||
disabled={!this.validateForm()}
|
||||
variant='primary'
|
||||
>
|
||||
{this.getSaveButtonLabel()}
|
||||
</Button>
|
||||
}
|
||||
</Modal.Footer>
|
||||
|
||||
</Modal>
|
||||
|
|
|
@ -4,12 +4,13 @@
|
|||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
import 'renderer/css/modals.css';
|
||||
|
||||
import React from 'react';
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import {TeamWithIndex} from 'types/config';
|
||||
import {ModalMessage} from 'types/modals';
|
||||
|
||||
import {MODAL_CANCEL, MODAL_RESULT} from 'common/communication';
|
||||
import {GET_MODAL_UNCLOSEABLE, MODAL_CANCEL, MODAL_RESULT, MODAL_UNCLOSEABLE} from 'common/communication';
|
||||
|
||||
import NewTeamModal from '../../components/NewTeamModal'; //'./addServer.jsx';
|
||||
|
||||
|
@ -25,14 +26,42 @@ const onSave = (data: TeamWithIndex) => {
|
|||
window.postMessage({type: MODAL_RESULT, data}, window.location.href);
|
||||
};
|
||||
|
||||
const start = async () => {
|
||||
ReactDOM.render(
|
||||
const NewServerModalWrapper: React.FC = () => {
|
||||
const [unremoveable, setUnremovable] = useState<boolean>();
|
||||
|
||||
const handleNewServerMessage = (event: {data: ModalMessage<boolean>}) => {
|
||||
switch (event.data.type) {
|
||||
case MODAL_UNCLOSEABLE: {
|
||||
setUnremovable(event.data.data);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('message', handleNewServerMessage);
|
||||
window.postMessage({type: GET_MODAL_UNCLOSEABLE}, window.location.href);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('message', handleNewServerMessage);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<NewTeamModal
|
||||
onClose={onClose}
|
||||
onClose={unremoveable ? undefined : onClose}
|
||||
onSave={onSave}
|
||||
editMode={false}
|
||||
show={true}
|
||||
/>,
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const start = async () => {
|
||||
ReactDOM.render(
|
||||
<NewServerModalWrapper/>,
|
||||
document.getElementById('app'),
|
||||
);
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue