diff --git a/client/app/scripts/actions/app-actions.js b/client/app/scripts/actions/app-actions.js index 0c5ad6d01..e8ccc77f6 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) { @@ -144,16 +142,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 }); } @@ -203,7 +203,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 c495a8b22..b6f3bfcd4 100644 --- a/client/app/scripts/components/app.js +++ b/client/app/scripts/components/app.js @@ -19,8 +19,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(), @@ -82,9 +81,8 @@ export default class App extends React.Component {
{showingDebugToolbar() && } {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 65fae450b..fca513c1e 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() { @@ -230,10 +230,6 @@ export class AppStore extends Store { return version; } - isControlPending() { - return controlPending; - } - isRouteSet() { return routeSet; } @@ -269,7 +265,7 @@ export class AppStore extends Store { break; case ActionTypes.CLEAR_CONTROL_ERROR: - controlError = null; + controlStatus = controlStatus.removeIn([payload.nodeId, 'error']); this.__emitChange(); break; @@ -307,8 +303,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; @@ -346,14 +344,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); } });