-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/client/app/scripts/components/metric-selector.js b/client/app/scripts/components/metric-selector.js
index 89761daa0..cb5d4255f 100644
--- a/client/app/scripts/components/metric-selector.js
+++ b/client/app/scripts/components/metric-selector.js
@@ -1,16 +1,24 @@
import React from 'react';
-import { selectMetric, lockMetric } from '../actions/app-actions';
+import { selectMetric, lockMetric, unlockMetric } from '../actions/app-actions';
import classNames from 'classnames';
+const CROSS = '\u274C';
+// const MINUS = '\u2212';
+// const DOT = '\u2022';
+
// docker_cpu_total_usage
// docker_memory_usage
function onMouseOver(k) {
- return selectMetric(k);
+ selectMetric(k);
}
-function onMouseClick(k) {
- return lockMetric(k);
+function onMouseClick(k, lockedMetric) {
+ if (k === lockedMetric) {
+ unlockMetric(k);
+ } else {
+ lockMetric(k);
+ }
}
function onMouseOut(k) {
@@ -23,16 +31,25 @@ export default function MetricSelector({availableCanvasMetrics, selectedMetric,
className="available-metrics"
onMouseLeave={() => onMouseOut(lockedMetric)}>
{availableCanvasMetrics.map(({id, label}) => {
+ const isLocked = (id === lockedMetric);
+ const isSelected = (id === selectedMetric);
+ const className = classNames('sidebar-item', {
+ 'locked': isLocked,
+ 'selected': isSelected
+ });
+
return (
onMouseOver(id)}
- onClick={() => onMouseClick(id)}>
+ onClick={() => onMouseClick(id, lockedMetric)}>
{label}
+ {isLocked &&
+
+ {CROSS}
+
+ }
);
})}
diff --git a/client/app/scripts/constants/action-types.js b/client/app/scripts/constants/action-types.js
index ab5a20ca2..151143483 100644
--- a/client/app/scripts/constants/action-types.js
+++ b/client/app/scripts/constants/action-types.js
@@ -24,6 +24,7 @@ const ACTION_TYPES = [
'LEAVE_EDGE',
'LEAVE_NODE',
'LOCK_METRIC',
+ 'UNLOCK_METRIC',
'OPEN_WEBSOCKET',
'RECEIVE_CONTROL_PIPE',
'RECEIVE_CONTROL_PIPE_STATUS',
diff --git a/client/app/scripts/stores/app-store.js b/client/app/scripts/stores/app-store.js
index 37d66125c..ca61ad508 100644
--- a/client/app/scripts/stores/app-store.js
+++ b/client/app/scripts/stores/app-store.js
@@ -61,11 +61,7 @@ let websocketClosed = true;
let selectedMetric = 'process_cpu_usage_percent';
let lockedMetric = selectedMetric;
-const availableCanvasMetrics = [
- {label: 'CPU', id: 'process_cpu_usage_percent'},
- {label: 'Memory', id: 'process_memory_usage_bytes'},
- {label: 'Open Files', id: 'open_files_count'}
-];
+let availableCanvasMetrics = [];
const topologySorter = topology => topology.get('rank');
@@ -402,6 +398,7 @@ export class AppStore extends Store {
setTopology(payload.topologyId);
nodes = nodes.clear();
}
+ availableCanvasMetrics = [];
this.__emitChange();
break;
}
@@ -412,6 +409,7 @@ export class AppStore extends Store {
setTopology(payload.topologyId);
nodes = nodes.clear();
}
+ availableCanvasMetrics = [];
this.__emitChange();
break;
}
@@ -433,6 +431,11 @@ export class AppStore extends Store {
this.__emitChange();
break;
}
+ case ActionTypes.UNLOCK_METRIC: {
+ lockedMetric = null;
+ this.__emitChange();
+ break;
+ }
case ActionTypes.DESELECT_NODE: {
closeNodeDetails();
this.__emitChange();
@@ -623,6 +626,16 @@ export class AppStore extends Store {
setDefaultTopologyOptions(topologies);
}
topologiesLoaded = true;
+
+ availableCanvasMetrics = nodes
+ .valueSeq()
+ .flatMap(n => (n.get('metrics') || makeMap()).keys())
+ .toSet()
+ .sort()
+ .toJS()
+ .map(v => {
+ return {id: v, label: v};
+ });
this.__emitChange();
break;
}
diff --git a/client/app/styles/main.less b/client/app/styles/main.less
index e9d80b75b..8e1a0cf36 100644
--- a/client/app/styles/main.less
+++ b/client/app/styles/main.less
@@ -409,7 +409,7 @@ h2 {
.metric-fill {
stroke: none;
- fill: yellowgreen;
+ fill: @background-darker-color;
}
.shadow {
@@ -1054,9 +1054,15 @@ h2 {
.debug-panel {
.shadow-2;
background-color: #fff;
- top: 10px;
+ top: 80px;
position: absolute;
padding: 10px;
left: 10px;
z-index: 10000;
+
+ opacity: 0.3;
+
+ &:hover {
+ opacity: 1;
+ }
}