mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-02 17:50:39 +00:00
Merge pull request #797 from weaveworks/758-independent-node-controls
Fix node controls so they behave independently across nodes
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
<div className="app">
|
||||
{showingDebugToolbar() && <DebugToolbar />}
|
||||
{showingDetails && <Details nodes={this.state.nodes}
|
||||
controlError={this.state.controlError}
|
||||
controlPending={this.state.controlPending}
|
||||
nodeId={this.state.selectedNodeId}
|
||||
controlStatus={this.state.controlStatus[this.state.selectedNodeId]}
|
||||
details={this.state.nodeDetails} />}
|
||||
|
||||
{showingTerminal && <EmbeddedTerminal
|
||||
|
||||
@@ -86,6 +86,7 @@ export default class NodeDetails extends React.Component {
|
||||
renderDetails() {
|
||||
const details = this.props.details;
|
||||
const nodeColor = getNodeColorDark(details.rank, details.label_major);
|
||||
const {error, pending} = (this.props.controlStatus || {});
|
||||
const styles = {
|
||||
controls: {
|
||||
'backgroundColor': brightenColor(nodeColor)
|
||||
@@ -109,8 +110,10 @@ export default class NodeDetails extends React.Component {
|
||||
</div>
|
||||
|
||||
{details.controls && details.controls.length > 0 && <div className="node-details-controls-wrapper" style={styles.controls}>
|
||||
<NodeDetailsControls controls={details.controls}
|
||||
pending={this.props.controlPending} error={this.props.controlError} />
|
||||
<NodeDetailsControls nodeId={this.props.nodeId}
|
||||
controls={details.controls}
|
||||
pending={pending}
|
||||
error={error} />
|
||||
</div>}
|
||||
|
||||
<div className="node-details-content">
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ export default class NodeDetailsControls extends React.Component {
|
||||
<span className="node-details-controls-buttons">
|
||||
{this.props.controls && this.props.controls.map(control => {
|
||||
return (
|
||||
<NodeDetailsControlButton control={control}
|
||||
<NodeDetailsControlButton nodeId={this.props.nodeId} control={control}
|
||||
pending={this.props.pending} key={control.id} />
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user