Skip to content

Commit c3e2665

Browse files
Merge pull request #454 from MetaCell/feature/311_confirmation_dialog
Feature/311 confirmation dialog
2 parents 0d9dbf8 + f703088 commit c3e2665

File tree

11 files changed

+204
-21
lines changed

11 files changed

+204
-21
lines changed

webapp/components/NetPyNE.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
LayoutManager,
99
Drawer,
1010
Dialog,
11+
ConfirmationDialog,
1112
LaunchDialog,
1213
} from 'netpyne/components';
1314

@@ -140,6 +141,7 @@ class NetPyNE extends React.Component {
140141
</Box>
141142
</div>
142143
<Dialog />
144+
<ConfirmationDialog />
143145
<ErrorDialog />
144146
<LaunchDialog />
145147
</div>
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import React from 'react';
2+
import Dialog from '@material-ui/core/Dialog/Dialog';
3+
import Button from '@material-ui/core/Button';
4+
import DialogActions from '@material-ui/core/DialogActions';
5+
import DialogContent from '@material-ui/core/DialogContent';
6+
import DialogTitle from '@material-ui/core/DialogTitle';
7+
import { withStyles } from '@material-ui/core/styles';
8+
import { PYTHON_CALL, LOAD_TUTORIAL } from '../../redux/actions/general';
9+
10+
const styles = () => ({
11+
cancel: { marginRight: 10 },
12+
});
13+
14+
class ConfirmationDialog extends React.Component {
15+
constructor (props) {
16+
super(props);
17+
this.state = { hide: !this.props.open };
18+
}
19+
20+
handleConfirmation = () => {
21+
if (this.props.confirmationDialogOnConfirm) {
22+
if (this.props.confirmationDialogOnConfirm.type === PYTHON_CALL) {
23+
this.props.pythonCall(this.props.confirmationDialogOnConfirm.cmd, this.props.confirmationDialogOnConfirm.args);
24+
} else if (this.props.confirmationDialogOnConfirm.type === LOAD_TUTORIAL) {
25+
if (this.props.confirmationDialogOnConfirm.payload !== undefined) {
26+
this.props.dispatchAction(this.props.confirmationDialogOnConfirm.action(this.props.confirmationDialogOnConfirm.payload));
27+
} else {
28+
this.props.dispatchAction(this.props.confirmationDialogOnConfirm.action);
29+
}
30+
}
31+
} else {
32+
console.log('Command/desired behaviour not passed to confirmation dialog');
33+
}
34+
}
35+
36+
render () {
37+
const {
38+
confirmationDialogOpen,
39+
confirmationDialogTitle,
40+
confirmationDialogMessage,
41+
closeConfirmationDialog,
42+
} = this.props;
43+
44+
return (
45+
<Dialog
46+
fullWidth
47+
maxWidth="sm"
48+
open={confirmationDialogOpen}
49+
onClose={() => closeConfirmationDialog()}
50+
>
51+
<DialogTitle>{confirmationDialogTitle}</DialogTitle>
52+
<DialogContent style={{ color: 'white' }}>
53+
{confirmationDialogMessage}
54+
</DialogContent>
55+
<DialogActions>
56+
<Button
57+
onClick={closeConfirmationDialog}
58+
style={styles.cancel}
59+
key="CANCEL"
60+
>
61+
CANCEL
62+
</Button>
63+
<Button
64+
color="primary"
65+
variant="contained"
66+
onClick={() => { this.handleConfirmation(); closeConfirmationDialog(); }}
67+
key="CONFIRM"
68+
>
69+
CONFIRM
70+
</Button>
71+
</DialogActions>
72+
</Dialog>
73+
);
74+
}
75+
}
76+
77+
export default withStyles(styles)(ConfirmationDialog);

webapp/components/index.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { openBackendErrorDialog, closeBackendErrorDialog } from '../redux/action
1616
import {
1717
updateCards, editModel, simulateNetwork, createNetwork, closeDialog,
1818
createAndSimulateNetwork, showNetwork, pythonCall, modelLoaded, deleteNetParamsObj, resetModel,
19-
setDefaultWidgets, changeInstanceColor,
19+
setDefaultWidgets, changeInstanceColor, openConfirmationDialog, closeConfirmationDialog,
2020
} from '../redux/actions/general';
2121

2222
import {
@@ -58,6 +58,7 @@ import _Topbar from './topbar/Topbar';
5858
import _SwitchPageButton from './topbar/SwitchPageButton';
5959
import _NetPyNEThumbnail from './general/NetPyNEThumbnail';
6060
import _Dialog from './general/Dialog';
61+
import _ConfirmationDialog from './general/ConfirmationDialog';
6162
import _SelectCellTemplate from './definition/cellRules/SelectCellTemplate';
6263
import _Experiments from './experiments/Experiments';
6364
import _ExperimentEdit from './experiments/ExperimentEdit';
@@ -322,6 +323,7 @@ export const Topbar = connect(
322323
dispatchAction: (action) => dispatch(action),
323324
closeDialog: () => dispatch(closeTopbarDialog),
324325
resetModel: () => dispatch(resetModel),
326+
openConfirmationDialog: (payload) => dispatch(openConfirmationDialog(payload)),
325327
}),
326328
)(_Topbar);
327329

@@ -357,6 +359,20 @@ export const Dialog = connect(
357359
(dispatch) => ({ handleClose: () => dispatch(closeDialog) }),
358360
)(_Dialog);
359361

362+
export const ConfirmationDialog = connect(
363+
(state) => ({
364+
confirmationDialogOpen: state.general.confirmationDialogOpen,
365+
confirmationDialogTitle: state.general.confirmationDialogTitle,
366+
confirmationDialogMessage: state.general.confirmationDialogMessage,
367+
confirmationDialogOnConfirm: state.general.confirmationDialogOnConfirm,
368+
}),
369+
(dispatch) => ({
370+
dispatchAction: (action) => dispatch(action),
371+
closeConfirmationDialog: () => dispatch(closeConfirmationDialog),
372+
pythonCall: (cmd, args) => dispatch(pythonCall(cmd, args)),
373+
}),
374+
)(_ConfirmationDialog);
375+
360376
export const SelectCellTemplate = connect(
361377
null,
362378
(dispatch) => ({

webapp/components/topbar/Topbar.js

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ import ImportExportHLSDialog from './dialogs/ImportExportHLS';
2020
import ImportCellParamsDialog from './dialogs/ImportCellParams';
2121
import UploadDownloadFilesDialog from './dialogs/UploadDownloadFiles';
2222

23-
import { TOPBAR_CONSTANTS } from '../../constants';
23+
import { TOPBAR_CONSTANTS, MODEL_STATE, DEFAULT_CONFIRMATION_DIALOG_MESSAGE } from '../../constants';
24+
import { LOAD_TUTORIAL } from '../../redux/actions/general';
2425

2526
const styles = () => ({
2627
topbar: {
@@ -85,6 +86,26 @@ class Topbar extends Component {
8586
}
8687
break;
8788
}
89+
case 'handleTutorial': {
90+
const [action, payload] = click.parameters;
91+
if (this.props.modelState === MODEL_STATE.INSTANTIATED || this.props.modelState === MODEL_STATE.SIMULATED) {
92+
this.props.openConfirmationDialog({
93+
title: 'Warning',
94+
message: DEFAULT_CONFIRMATION_DIALOG_MESSAGE,
95+
onConfirm: {
96+
type: LOAD_TUTORIAL,
97+
action,
98+
payload,
99+
},
100+
});
101+
} else if (payload !== undefined) {
102+
this.props.dispatchAction(action(payload));
103+
} else {
104+
this.props.dispatchAction(action);
105+
}
106+
107+
break;
108+
}
88109

89110
default:
90111
console.log(`Menu action not mapped, it is ${click}`);
@@ -101,9 +122,12 @@ class Topbar extends Component {
101122
classes,
102123
modelLoaded,
103124
dialogOpen,
125+
modelState,
104126
topbarDialogName,
105127
topbarDialogMetadata,
128+
openConfirmationDialog,
106129
} = this.props;
130+
107131
let content;
108132
if (dialogOpen) {
109133
switch (topbarDialogName) {
@@ -129,6 +153,8 @@ class Topbar extends Component {
129153
open={dialogOpen}
130154
onRequestClose={() => this.handleClose()}
131155
mode="IMPORT"
156+
modelState={modelState}
157+
openConfirmationDialog={(payload) => openConfirmationDialog(payload)}
132158
/>
133159
);
134160
break;

webapp/components/topbar/dialogs/ActionDialog.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,12 @@ class ActionDialog extends React.Component {
3838
performAction = () => {
3939
if (this.props.command) {
4040
if (this.props.isFormValid === undefined || this.props.isFormValid()) {
41-
GEPPETTO.trigger(GEPPETTO.Events.Show_spinner, this.props.message);
42-
this.props.pythonCall(this.props.command, this.props.args);
41+
if (typeof this.props.callback !== 'undefined' || this.props.callback !== null) {
42+
this.props.callback(this.props.command, this.props.args);
43+
} else {
44+
// GEPPETTO.trigger(GEPPETTO.Events.Show_spinner, this.props.message);
45+
this.props.pythonCall(this.props.command, this.props.args);
46+
}
4347
}
4448
}
4549
this.setState({ hide: true });

webapp/components/topbar/dialogs/ImportExportHLS.js

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import Box from '@material-ui/core/Box';
77
import { withStyles } from '@material-ui/core/styles';
88

99
import { ActionDialog, Tooltip } from 'netpyne/components';
10-
import { NETPYNE_COMMANDS } from '../../../constants';
10+
import { NETPYNE_COMMANDS, MODEL_STATE, DEFAULT_CONFIRMATION_DIALOG_MESSAGE } from '../../../constants';
11+
import { PYTHON_CALL } from '../../../redux/actions/general';
1112
import FileBrowser from '../../general/FileBrowser';
1213
import Checkbox from '../../general/Checkbox';
1314

@@ -179,8 +180,20 @@ class ImportExportHLS extends React.Component {
179180
}
180181
}
181182

183+
handleConfirmation (command, args) {
184+
this.props.openConfirmationDialog({
185+
title: 'Warning',
186+
message: DEFAULT_CONFIRMATION_DIALOG_MESSAGE,
187+
onConfirm: {
188+
type: PYTHON_CALL,
189+
cmd: command,
190+
args,
191+
},
192+
});
193+
}
194+
182195
render () {
183-
const { classes } = this.props;
196+
const { classes, modelState } = this.props;
184197
switch (this.props.mode) {
185198
case 'IMPORT':
186199
var content = (
@@ -309,18 +322,34 @@ class ImportExportHLS extends React.Component {
309322
var title = 'Export as Python script';
310323
break;
311324
}
325+
312326
return (
313-
<ActionDialog
314-
command={command}
315-
message={message}
316-
buttonLabel={buttonLabel}
317-
args={this.state}
318-
title={title}
319-
isFormValid={this.isFormValid}
320-
{...this.props}
321-
>
322-
{content}
323-
</ActionDialog>
327+
this.props.mode === 'IMPORT' ? (
328+
<ActionDialog
329+
command={command}
330+
message={message}
331+
buttonLabel={buttonLabel}
332+
args={this.state}
333+
title={title}
334+
isFormValid={this.isFormValid}
335+
callback={modelState === MODEL_STATE.INSTANTIATED || modelState === MODEL_STATE.SIMULATED ? (command, args) => { this.handleConfirmation(command, args); } : undefined}
336+
{...this.props}
337+
>
338+
{content}
339+
</ActionDialog>
340+
) : (
341+
<ActionDialog
342+
command={command}
343+
message={message}
344+
buttonLabel={buttonLabel}
345+
args={this.state}
346+
title={title}
347+
isFormValid={this.isFormValid}
348+
{...this.props}
349+
>
350+
{content}
351+
</ActionDialog>
352+
)
324353
);
325354
}
326355
}

webapp/components/topbar/menuConfiguration.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export const getTutorials = () => {
8383
label: tutLabel,
8484
icon: '',
8585
action: {
86-
handlerAction: 'redux',
86+
handlerAction: 'handleTutorial',
8787
parameters: [loadTutorial, tutFile],
8888
},
8989
};

webapp/constants.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ export const MINIMIZED_PANEL = 'border_bottom';
44
export { WidgetStatus };
55
export const TOP_PANEL = 'hlsPanel';
66
export const TOOLS_LIST = 'tools';
7+
8+
export const DEFAULT_CONFIRMATION_DIALOG_MESSAGE = 'A NetPyNE model has already been instantiated or simulated.'
9+
+ ' Continuing with this action will use the old value of netParams and simConfig for the new model. Do you want to continue?';
10+
711
export const THEMES = {
812
DARK: 'gui',
913
BLACK: 'guiBlack',

webapp/redux/actions/general.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export const DELETE_NETPARAMS_OBJ = 'DELETE_NETPARAMS_OBJ';
1515
export const CLOSE_DIALOG = 'CLOSE_DIALOG';
1616
export const OPEN_DIALOG = 'OPEN_DIALOG';
1717
export const LOAD_TUTORIAL = 'LOAD_TUTORIAL';
18+
export const OPEN_CONFIRMATION_DIALOG = 'OPEN_CONFIRMATION_DIALOG';
19+
export const CLOSE_CONFIRMATION_DIALOG = 'CLOSE_CONFIRMATION_DIALOG';
1820
export const AUTOMATIC_INSTANTIATION = 'AUTOMATIC_INSTANTIATION';
1921
export const AUTOMATIC_SIMULATION = 'AUTOMATIC_SIMULATION';
2022
export const IMPORT_APPLICATION_STATE = 'IMPORT_APPLICATION_STATE';
@@ -59,6 +61,13 @@ export const openDialog = (payload) => ({
5961
payload,
6062
});
6163

64+
export const openConfirmationDialog = (payload) => ({
65+
type: OPEN_CONFIRMATION_DIALOG,
66+
payload,
67+
});
68+
69+
export const closeConfirmationDialog = { type: CLOSE_CONFIRMATION_DIALOG };
70+
6271
export const setTheme = (themeName) => ({
6372
type: SET_THEME,
6473
payload: themeName,

webapp/redux/reducers/general.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@ export const GENERAL_DEFAULT_STATE = {
1111
dialogOpen: false,
1212
dialogTitle: '',
1313
dialogMessage: '',
14+
confirmationDialogTitle: '',
15+
confirmationDialogMessage: '',
16+
confirmationDialogOnConfirm: {},
1417
automaticSimulation: false,
1518
automaticInstantiation: false,
19+
confirmationDialogOpen: false,
1620
theme: 'gui',
1721
instances: [],
1822
};
@@ -42,6 +46,18 @@ export default function reduceGeneral (state = GENERAL_DEFAULT_STATE, action) {
4246
};
4347
case Actions.CLOSE_DIALOG:
4448
return { ...state, dialogOpen: false };
49+
case Actions.OPEN_CONFIRMATION_DIALOG:
50+
return {
51+
...state,
52+
confirmationDialogOpen: true,
53+
confirmationDialogTitle: action.payload.title,
54+
confirmationDialogMessage: action.payload.message,
55+
confirmationDialogOnConfirm: action.payload.onConfirm,
56+
};
57+
case Actions.CLOSE_CONFIRMATION_DIALOG:
58+
return {
59+
...state, confirmationDialogOpen: false, dialogTitle: '', dialogMessage: '', confirmationDialogOnConfirm: {},
60+
};
4561
case Actions.AUTOMATIC_INSTANTIATION: {
4662
return { ...state, automaticInstantiation: action.payload, automaticSimulation: state.automaticSimulation && action.payload };
4763
}

0 commit comments

Comments
 (0)