Skip to content

Commit

Permalink
Merge pull request #267 from Kitware/button-bar-disablers
Browse files Browse the repository at this point in the history
fix(ui): buttonbar buttons state dependant on state of network calls …
  • Loading branch information
TristanWright committed Mar 22, 2016
2 parents f0dd2ca + 2af52f3 commit 6e44c5b
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 40 deletions.
42 changes: 28 additions & 14 deletions src/pages/Preferences/Cluster/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,20 @@ function applyPreset(obj, name) {
}
}

function getActions(disabled, test) {
if (test) {
return [
{ name: 'removeItem', label: 'Delete', icon: style.deleteIcon, disabled },
{ name: 'saveItem', label: 'Save', icon: style.saveIcon, disabled },
{ name: 'testCluster', label: 'Test', icon: style.testIcon, disabled },
];
}
return [
{ name: 'removeItem', label: 'Delete', icon: style.deleteIcon, disabled },
{ name: 'saveItem', label: 'Save', icon: style.saveIcon, disabled },
];
}

// Fetch cluster preferences only once
client.getClusterPresets()
.then(
Expand Down Expand Up @@ -90,6 +104,7 @@ export default React.createClass({
return {
active: 0,
clusters: [],
buttonsDisabled: false,
};
},

Expand Down Expand Up @@ -156,10 +171,15 @@ export default React.createClass({

console.log('about to remove?', clusterToDelete._id);
if (clusterToDelete._id && confirm('Are you sure you want to delete this cluster?')) {
this.setState({ active: newActive, actionsDisabled: true });
client.deleteCluster(clusterToDelete._id)
.then(resp => this.updateState())
.then(resp => {
this.setState({ actionsDisabled: false });
this.updateState();
})
.catch(err => {
console.log('Error deleting cluster', err);
this.setState({ actionsDisabled: false });
this.updateState();
});
}
Expand All @@ -168,27 +188,29 @@ export default React.createClass({
saveItem() {
const clusters = this.state.clusters;
const cluster = clusters[this.state.active];

this.setState({ actionsDisabled: true });
client.saveCluster(cluster)
.then(resp => {
clusters[this.state.active] = resp.data;
this.setState({ error: null, clusters });
this.setState({ error: null, clusters, actionsDisabled: false });
})
.catch(err => {
this.setState({ error: err.data.message });
this.setState({ error: err.data.message, actionsDisabled: false });
console.log('Error: Pref/Cluster/save', err);
});
},

testCluster() {
console.log('test');
const cluster = this.state.clusters[this.state.active];
this.setState({ actionsDisabled: true });
if (cluster._id) {
client.testCluster(cluster._id)
.then(resp => {
this.setState({ actionsDisabled: false });
console.log('success test', resp.data);
})
.catch(err => {
this.setState({ actionsDisabled: false });
console.log('error test', err);
});
}
Expand All @@ -200,14 +222,6 @@ export default React.createClass({

render() {
const activeData = this.state.active < this.state.clusters.length ? this.state.clusters[this.state.active] : null;
const actions = [
{ name: 'removeItem', label: 'Delete', icon: style.deleteIcon },
{ name: 'saveItem', label: 'Save', icon: style.saveIcon },
];

if (activeData && activeData.config.ssh.publicKey && activeData.status !== 'running') {
actions.push({ name: 'testCluster', label: 'Test', icon: style.testIcon });
}

updateClusterStatusAsClassPrefix(this.state.clusters);
return (
Expand All @@ -234,7 +248,7 @@ export default React.createClass({
visible={!!activeData}
onAction={ this.formAction }
error={ this.state.error }
actions={actions}
actions={getActions(this.state.buttonsDisabled, activeData && activeData.config.ssh.publicKey && activeData.status !== 'running')}
/>
</div>
</div>
Expand Down
4 changes: 4 additions & 0 deletions src/pages/Project/New/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ export default React.createClass({
metadata = data.metadata || {},
project = { name, description, type, steps, metadata };

if (name.length === 0) {
this.setState({ _error: 'Name is required' });
return;
}

client.saveProject(project, attachements)
.then(resp => {
Expand Down
22 changes: 17 additions & 5 deletions src/pages/Simulation/New/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ import client from '../../../network';

import breadCrumbStyle from 'HPCCloudStyle/Theme.mcss';

function getActions(disabled) {
return [
{ name: 'cancel', label: 'Cancel', disabled },
{ name: 'newSimulation', label: 'Create simulation', disabled },
];
}

export default React.createClass({

displayName: 'Simulation/New',
Expand All @@ -21,6 +28,7 @@ export default React.createClass({
getInitialState() {
return {
project: null,
buttonsDisabled: false,
};
},

Expand Down Expand Up @@ -58,14 +66,21 @@ export default React.createClass({
active = stepsInfo._active || stepsInfo._order[0],
simulation = { name, description, steps, metadata, projectId, active, disabled };

if (name.length === 0) {
this.setState({ _error: 'Name is required' });
return;
}

this.setState({ buttonsDisabled: true });
client.saveSimulation(simulation, attachements)
.then(resp => {
if (resp.status >= 400) {
this.setState({ _error: resp.data.message });
this.setState({ _error: resp.data.message, buttonsDisabled: false });
console.log('Error: Sim/New-save', resp.data.message);
return;
}

this.setState({ buttonsDisabled: false });
const simId = Array.isArray(resp) ? resp[resp.length - 1]._id : resp._id;
this.context.router.replace(`/View/Simulation/${simId}`);
})
Expand Down Expand Up @@ -99,10 +114,7 @@ export default React.createClass({
error={this.state._error}
ref="container"
title="New Simulation"
actions={[
{ name: 'cancel', label: 'Cancel' },
{ name: 'newSimulation', label: 'Create simulation' },
]}
actions={ getActions(this.state.buttonsDisabled) }
onAction={ this.onAction }
>
{ workflowAddOn }
Expand Down
1 change: 1 addition & 0 deletions src/workflows/pyfr/common/steps/Simulation/Start/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export default React.createClass({

client.createTaskflow(this.props.taskFlowName)
.then((resp) => {
taskflowId = resp.data._id;
const meshFile = this.props.simulation.metadata.inputFolder.files.mesh || this.props.project.metadata.inputFolder.files.mesh;
return client.startTaskflow(taskflowId, Object.assign({},
this.state[this.state.serverType].runtime || {},
Expand Down
2 changes: 1 addition & 1 deletion src/workflows/pyfr/common/steps/Simulation/View/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export default React.createClass({
simNeedsUpdate = true;
actionsDisabled = false;
// some running -> terminate
} else if (!allComplete && (pkt.jobs.length + pkt.tasks.length) > 0) {
} else if (!allComplete && (pkt.jobs.length + pkt.tasks.length) > 0 && !pkt.jobs.some(job => job.status === 'terminating')) {
this.props.simulation.metadata.status = 'running';
actions.push('terminate');
simNeedsUpdate = true;
Expand Down
30 changes: 19 additions & 11 deletions src/workflows/pyfr/common/steps/Visualization/View/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ const ACTIONS = {
rerun: { name: 'deleteTaskflow', label: 'Rerun', icon: '' },
};

function getActions(actionsList, disabled) {
return actionsList.map((action) => Object.assign({ disabled }, ACTIONS[action]));
}

export default React.createClass({
displayName: 'pyfr/common/steps/Visualization/View',

Expand All @@ -32,8 +36,9 @@ export default React.createClass({
taskflowId: '',
error: '',
actions: [
ACTIONS.terminate,
'terminate',
],
actionsDisabled: false,
};
},

Expand All @@ -44,22 +49,24 @@ export default React.createClass({
this.subscription = TaskflowManager.monitorTaskflow(taskflowId, (pkt) => {
const actions = [];
var simNeedsUpdate = false;
var actionsDisabled = this.state.actionsDisabled;
var allComplete = pkt.jobs.every(job => job.status === 'complete') && pkt.tasks.every(task => task.status === 'complete');

// name is paraview and status is running -> visualize
if (pkt.jobs.some(job => job.name === 'paraview' && job.status === 'running')) {
actions.push(ACTIONS.visualize);
actions.push('visualize');
}

// jobs are still running -> terminate
if (!allComplete && (pkt.jobs.length + pkt.tasks.length) > 0) {
this.props.simulation.metadata.status = 'running';
actions.push(ACTIONS.terminate);
simNeedsUpdate = true;
// every job complete && task complete -> rerun
} else if (allComplete || pkt.jobs.every(job => job.status === 'terminated')) {
if (allComplete || pkt.jobs.every(job => job.status === 'terminated')) {
this.props.simulation.metadata.status = 'complete';
actions.push(ACTIONS.rerun);
actions.push('rerun');
simNeedsUpdate = true;
actionsDisabled = false;
// jobs are still running -> terminate
} else if (!allComplete && (pkt.jobs.length + pkt.tasks.length) > 0 && !pkt.jobs.some(job => job.status === 'terminating')) {
this.props.simulation.metadata.status = 'running';
actions.push('terminate');
simNeedsUpdate = true;
}

Expand All @@ -71,7 +78,7 @@ export default React.createClass({
}

// Refresh ui
this.setState({ actions, allComplete });
this.setState({ actions, allComplete, actionsDisabled });
});
},

Expand All @@ -97,6 +104,7 @@ export default React.createClass({
},

terminateTaskflow() {
this.setState({ actionsDisabled: true });
TaskflowManager.terminateTaskflow(this.props.simulation.steps[this.props.simulation.active].metadata.taskflowId);
},

Expand Down Expand Up @@ -131,7 +139,7 @@ export default React.createClass({
<section>
<ButtonBar
onAction={ this.buttonBarAction }
actions={ this.state.actions }
actions={ getActions(this.state.actions, this.state.actionsDisabled) }
error={this.state.error}
/>
</section>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export default React.createClass({
newSim.steps[this.props.step].metadata = {
taskflowId, sessionId,
};
newSim.metadata.status = 'running';
client.invalidateSimulation(newSim);

this.context.router.replace({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ const ACTIONS = {
rerun: { name: 'deleteTaskflow', label: 'New visualization', icon: '' },
};

function getActions(actionsList, disabled) {
return actionsList.map((action) => Object.assign({ disabled }, ACTIONS[action]));
}

export default React.createClass({
displayName: 'pvw/view-visualization',

Expand All @@ -32,8 +36,9 @@ export default React.createClass({
taskflowId: '',
error: '',
actions: [
ACTIONS.terminate,
'terminate',
],
actionsDisabled: false,
};
},

Expand All @@ -43,23 +48,38 @@ export default React.createClass({

this.subscription = TaskflowManager.monitorTaskflow(taskflowId, (pkt) => {
const actions = [];
var simNeedsUpdate = false;
var actionsDisabled = this.state.actionsDisabled;
var allComplete = pkt.jobs.every(job => job.status === 'complete') && pkt.tasks.every(task => task.status === 'complete');

// name is paraview and status is running -> visualize
if (pkt.jobs.some(job => job.name === 'paraview' && job.status === 'running')) {
actions.push(ACTIONS.visualize);
actions.push('visualize');
}

// some running -> terminate
if (pkt.jobs.some(job => job.status === 'running')) {
actions.push(ACTIONS.terminate);
// every status complete || terminated -> rerun
} else if (pkt.jobs.every(job => job.status === 'complete') ||
if (pkt.jobs.every(job => job.status === 'complete') ||
pkt.jobs.every(job => job.status === 'terminated')) {
actions.push(ACTIONS.rerun);
this.props.simulation.metadata.status = 'terminated';
actions.push('rerun');
simNeedsUpdate = true;
actionsDisabled = false;
// some running -> terminate
} else if (!allComplete && (pkt.jobs.length + pkt.tasks.length) > 0 && !pkt.jobs.some(job => job.status === 'terminating')) {
this.props.simulation.metadata.status = 'running';
actions.push('terminate');
simNeedsUpdate = true;
}

if (simNeedsUpdate) {
client.saveSimulation(this.props.simulation)
.then(resp => {
client.invalidateSimulation(resp);
});
}

// Refresh ui
this.setState({ actions });
this.setState({ actions, actionsDisabled });
});
},

Expand All @@ -83,6 +103,7 @@ export default React.createClass({
},

terminateTaskflow() {
this.setState({ actionsDisabled: true });
TaskflowManager.terminateTaskflow(this.props.simulation.steps[this.props.simulation.active].metadata.taskflowId);
},

Expand Down Expand Up @@ -113,7 +134,7 @@ export default React.createClass({
<section>
<ButtonBar
onAction={ this.onAction }
actions={ this.state.actions }
actions={ getActions(this.state.actions, this.state.actionsDisabled)}
error={this.state.error}
/>
</section>
Expand Down

0 comments on commit 6e44c5b

Please sign in to comment.