diff --git a/client/app/scripts/actions/app-actions.js b/client/app/scripts/actions/app-actions.js index e52b8639e..0a63ffe4d 100644 --- a/client/app/scripts/actions/app-actions.js +++ b/client/app/scripts/actions/app-actions.js @@ -3,7 +3,7 @@ import debug from 'debug'; import AppDispatcher from '../dispatcher/app-dispatcher'; import ActionTypes from '../constants/action-types'; import { updateRoute } from '../utils/router-utils'; -import { doControl as doControlRequest, getNodesDelta, getNodeDetails, +import { doControlRequest, getNodesDelta, getNodeDetails, getTopologies, deletePipe } from '../utils/web-api-utils'; import AppStore from '../stores/app-store'; @@ -79,9 +79,10 @@ export function openWebsocket() { }); } -export function clearControlError() { +export function clearControlError(nodeId) { AppDispatcher.dispatch({ - type: ActionTypes.CLEAR_CONTROL_ERROR + type: ActionTypes.CLEAR_CONTROL_ERROR, + nodeId: nodeId }); } @@ -91,15 +92,12 @@ export function closeWebsocket() { }); } -export function doControl(probeId, nodeId, control) { +export function doControl(nodeId, control) { AppDispatcher.dispatch({ - type: ActionTypes.DO_CONTROL + type: ActionTypes.DO_CONTROL, + nodeId: nodeId }); - doControlRequest( - probeId, - nodeId, - control - ); + doControlRequest(nodeId, control); } export function enterEdge(edgeId) { @@ -138,16 +136,18 @@ export function leaveNode(nodeId) { }); } -export function receiveControlError(err) { +export function receiveControlError(nodeId, err) { AppDispatcher.dispatch({ type: ActionTypes.DO_CONTROL_ERROR, + nodeId: nodeId, error: err }); } -export function receiveControlSuccess() { +export function receiveControlSuccess(nodeId) { AppDispatcher.dispatch({ - type: ActionTypes.DO_CONTROL_SUCCESS + type: ActionTypes.DO_CONTROL_SUCCESS, + nodeId: nodeId }); } @@ -197,7 +197,7 @@ export function receiveControlPipeFromParams(pipeId, rawTty) { } export function receiveControlPipe(pipeId, nodeId, rawTty) { - if (nodeId.split(';').pop() !== AppStore.getSelectedNodeId()) { + if (nodeId !== AppStore.getSelectedNodeId()) { log('Node was deselected before we could set up control!'); deletePipe(pipeId); return; diff --git a/client/app/scripts/components/app.js b/client/app/scripts/components/app.js index 032079b0e..2a262b9dd 100644 --- a/client/app/scripts/components/app.js +++ b/client/app/scripts/components/app.js @@ -18,8 +18,7 @@ const ESC_KEY_CODE = 27; function getStateFromStores() { return { activeTopologyOptions: AppStore.getActiveTopologyOptions(), - controlError: AppStore.getControlError(), - controlPending: AppStore.isControlPending(), + controlStatus: AppStore.getControlStatus(), controlPipe: AppStore.getControlPipe(), currentTopology: AppStore.getCurrentTopology(), currentTopologyId: AppStore.getCurrentTopologyId(), @@ -80,9 +79,8 @@ export default class App extends React.Component { return (
{showingDetails &&
} {showingTerminal && {details.controls && details.controls.length > 0 &&
- +
}
diff --git a/client/app/scripts/components/node-details/node-details-control-button.js b/client/app/scripts/components/node-details/node-details-control-button.js index 48be014ed..99a2629a6 100644 --- a/client/app/scripts/components/node-details/node-details-control-button.js +++ b/client/app/scripts/components/node-details/node-details-control-button.js @@ -20,6 +20,6 @@ export default class NodeDetailsControlButton extends React.Component { handleClick(ev) { ev.preventDefault(); - doControl(this.props.control.probeId, this.props.control.nodeId, this.props.control.id); + doControl(this.props.nodeId, this.props.control); } } diff --git a/client/app/scripts/components/node-details/node-details-controls.js b/client/app/scripts/components/node-details/node-details-controls.js index 153081db5..1c4334fe7 100644 --- a/client/app/scripts/components/node-details/node-details-controls.js +++ b/client/app/scripts/components/node-details/node-details-controls.js @@ -16,7 +16,7 @@ export default class NodeDetailsControls extends React.Component { {this.props.controls && this.props.controls.map(control => { return ( - ); })} diff --git a/client/app/scripts/stores/app-store.js b/client/app/scripts/stores/app-store.js index db0f837e7..f7ac3411b 100644 --- a/client/app/scripts/stores/app-store.js +++ b/client/app/scripts/stores/app-store.js @@ -7,6 +7,7 @@ import AppDispatcher from '../dispatcher/app-dispatcher'; import ActionTypes from '../constants/action-types'; import { EDGE_ID_SEPARATOR } from '../constants/naming'; +const makeMap = Immutable.Map; const makeOrderedMap = Immutable.OrderedMap; const makeSet = Immutable.Set; const log = debug('scope:app-store'); @@ -48,8 +49,7 @@ function makeNode(node) { let topologyOptions = makeOrderedMap(); // topologyId -> options let adjacentNodes = makeSet(); -let controlError = null; -let controlPending = false; +let controlStatus = makeMap(); let currentTopology = null; let currentTopologyId = 'containers'; let errorUrl = null; @@ -143,8 +143,8 @@ export class AppStore extends Store { return adjacentNodes; } - getControlError() { - return controlError; + getControlStatus() { + return controlStatus.toJS(); } getControlPipe() { @@ -232,10 +232,6 @@ export class AppStore extends Store { return version; } - isControlPending() { - return controlPending; - } - isRouteSet() { return routeSet; } @@ -271,7 +267,7 @@ export class AppStore extends Store { break; case ActionTypes.CLEAR_CONTROL_ERROR: - controlError = null; + controlStatus = controlStatus.removeIn([payload.nodeId, 'error']); this.__emitChange(); break; @@ -309,8 +305,10 @@ export class AppStore extends Store { break; case ActionTypes.DO_CONTROL: - controlPending = true; - controlError = null; + controlStatus = controlStatus.set(payload.nodeId, makeMap({ + pending: true, + error: null + })); this.__emitChange(); break; @@ -348,14 +346,18 @@ export class AppStore extends Store { break; case ActionTypes.DO_CONTROL_ERROR: - controlPending = false; - controlError = payload.error; + controlStatus = controlStatus.set(payload.nodeId, makeMap({ + pending: false, + error: payload.error + })); this.__emitChange(); break; case ActionTypes.DO_CONTROL_SUCCESS: - controlPending = false; - controlError = null; + controlStatus = controlStatus.set(payload.nodeId, makeMap({ + pending: false, + error: null + })); this.__emitChange(); break; diff --git a/client/app/scripts/utils/web-api-utils.js b/client/app/scripts/utils/web-api-utils.js index b197ccfd7..2269aa8c9 100644 --- a/client/app/scripts/utils/web-api-utils.js +++ b/client/app/scripts/utils/web-api-utils.js @@ -155,23 +155,23 @@ export function getApiDetails() { }); } -export function doControl(probeId, nodeId, control) { +export function doControlRequest(nodeId, control) { clearTimeout(controlErrorTimer); - const url = `api/control/${encodeURIComponent(probeId)}/` - + `${encodeURIComponent(nodeId)}/${control}`; + const url = `api/control/${encodeURIComponent(control.probeId)}/` + + `${encodeURIComponent(control.nodeId)}/${control.id}`; reqwest({ method: 'POST', url: url, success: function(res) { - receiveControlSuccess(); + receiveControlSuccess(nodeId); if (res && res.pipe) { receiveControlPipe(res.pipe, nodeId, res.raw_tty, true); } }, error: function(err) { - receiveControlError(err.response); + receiveControlError(nodeId, err.response); controlErrorTimer = setTimeout(function() { - clearControlError(); + clearControlError(nodeId); }, 10000); } });