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);
}
});