From 1710db62626388ef3af921e2f4c365f23affb015 Mon Sep 17 00:00:00 2001 From: Simon Howe Date: Wed, 23 Mar 2016 12:47:53 +0100 Subject: [PATCH] Save locked metric in the url. - introduces "metric type" so we can flick across topos and keep the "type" of metric selected. Cheating and using label as the type atm. --- client/app/scripts/actions/app-actions.js | 9 ++- client/app/scripts/components/app.js | 4 +- .../components/metric-selector-item.js | 3 +- client/app/scripts/stores/app-store.js | 17 +++++- client/app/scripts/utils/data-utils.js | 61 +++++++++++-------- 5 files changed, 63 insertions(+), 31 deletions(-) diff --git a/client/app/scripts/actions/app-actions.js b/client/app/scripts/actions/app-actions.js index 04d29ffe2..cf3314440 100644 --- a/client/app/scripts/actions/app-actions.js +++ b/client/app/scripts/actions/app-actions.js @@ -28,21 +28,26 @@ export function lockNextMetric(delta) { AppDispatcher.dispatch({ type: ActionTypes.LOCK_METRIC, - metricId: nextMetric + metricId: nextMetric, + metricType: AppStore.getAvailableCanvasMetricsTypes()[nextMetric] }); + updateRoute(); } export function lockMetric(metricId) { AppDispatcher.dispatch({ type: ActionTypes.LOCK_METRIC, - metricId + metricId, + metricType: AppStore.getAvailableCanvasMetricsTypes()[metricId] }); + updateRoute(); } export function unlockMetric() { AppDispatcher.dispatch({ type: ActionTypes.UNLOCK_METRIC, }); + updateRoute(); } export function changeTopologyOption(option, value, topologyId) { diff --git a/client/app/scripts/components/app.js b/client/app/scripts/components/app.js index e4a249193..45a6c5df2 100644 --- a/client/app/scripts/components/app.js +++ b/client/app/scripts/components/app.js @@ -139,11 +139,11 @@ export default class App extends React.Component { topologyId={this.state.currentTopologyId} /> - 0 && + />} diff --git a/client/app/scripts/components/metric-selector-item.js b/client/app/scripts/components/metric-selector-item.js index b04fce624..24d628e0a 100644 --- a/client/app/scripts/components/metric-selector-item.js +++ b/client/app/scripts/components/metric-selector-item.js @@ -1,7 +1,6 @@ import React from 'react'; import classNames from 'classnames'; import { selectMetric, lockMetric, unlockMetric } from '../actions/app-actions'; -import { label } from '../utils/data-utils'; export class MetricSelectorItem extends React.Component { @@ -45,7 +44,7 @@ export class MetricSelectorItem extends React.Component { className={className} onMouseOver={this.onMouseOver} onClick={this.onMouseClick}> - {label(metric)} + {metric.label} {isLocked && } diff --git a/client/app/scripts/stores/app-store.js b/client/app/scripts/stores/app-store.js index 1d95e636d..4eea62d0d 100644 --- a/client/app/scripts/stores/app-store.js +++ b/client/app/scripts/stores/app-store.js @@ -62,6 +62,7 @@ let websocketClosed = true; let selectedMetric = null; let lockedMetric = selectedMetric; +let lockedMetricType = null; let availableCanvasMetrics = []; @@ -144,6 +145,7 @@ export class AppStore extends Store { controlPipe: this.getControlPipe(), nodeDetails: this.getNodeDetailsState(), selectedNodeId, + lockedMetricType, topologyId: currentTopologyId, topologyOptions: topologyOptions.toJS() // all options }; @@ -182,6 +184,10 @@ export class AppStore extends Store { return availableCanvasMetrics; } + getAvailableCanvasMetricsTypes() { + return _.fromPairs(this.getAvailableCanvasMetrics().map(m => [m.id, m.label])); + } + getControlStatus() { return controlStatus.toJS(); } @@ -428,12 +434,14 @@ export class AppStore extends Store { } case ActionTypes.LOCK_METRIC: { lockedMetric = payload.metricId; + lockedMetricType = payload.metricType; selectedMetric = payload.metricId; this.__emitChange(); break; } case ActionTypes.UNLOCK_METRIC: { lockedMetric = null; + lockedMetricType = null; this.__emitChange(); break; } @@ -607,7 +615,13 @@ export class AppStore extends Store { .toSet() .sortBy(n => METRIC_LABELS[n]) .toJS() - .map(v => ({id: v, label: v})); + .map(v => ({id: v, label: METRIC_LABELS[v]})); + + const similarTypeMetric = availableCanvasMetrics.find(m => m.label === lockedMetricType); + lockedMetric = similarTypeMetric && similarTypeMetric.id; + if (!availableCanvasMetrics.map(m => m.id).includes(selectedMetric)) { + selectedMetric = lockedMetric; + } if (emitChange) { this.__emitChange(); @@ -654,6 +668,7 @@ export class AppStore extends Store { setTopology(payload.state.topologyId); setDefaultTopologyOptions(topologies); selectedNodeId = payload.state.selectedNodeId; + lockedMetricType = payload.state.lockedMetricType; if (payload.state.controlPipe) { controlPipes = makeOrderedMap({ [payload.state.controlPipe.id]: diff --git a/client/app/scripts/utils/data-utils.js b/client/app/scripts/utils/data-utils.js index 29ef13caf..e9bff6bd0 100644 --- a/client/app/scripts/utils/data-utils.js +++ b/client/app/scripts/utils/data-utils.js @@ -42,16 +42,16 @@ function getNextValue(keyValues, maxValue) { } export const METRIC_LABELS = { - docker_cpu_total_usage: 'Container CPU', - docker_memory_usage: 'Container Memory', - host_cpu_usage_percent: 'Host CPU', - host_mem_usage_bytes: 'Host Memory', - load1: 'Host Load 1', - load15: 'Host Load 15', - load5: 'Host Load 5', - open_files_count: 'Process Open files', - process_cpu_usage_percent: 'Process CPU', - process_memory_usage_bytes: 'Process Memory' + docker_cpu_total_usage: 'CPU', + docker_memory_usage: 'Memory', + host_cpu_usage_percent: 'CPU', + host_mem_usage_bytes: 'Memory', + load1: 'Load 1', + load15: 'Load 15', + load5: 'Load 5', + open_files_count: 'Open files', + process_cpu_usage_percent: 'CPU', + process_memory_usage_bytes: 'Memory' }; @@ -84,7 +84,7 @@ const cpuMetric = (node, name, max = 100) => ({ max }); -const fileMetric = (node, name, max = 10000) => ({ +const fileMetric = (node, name, max = 1000) => ({ samples: [{value: getNextValue([node.id, name], max)}], max }); @@ -94,23 +94,36 @@ const loadMetric = (node, name, max = 10) => ({ max }); +const metrics = { + // process + square: { + process_cpu_usage_percent: cpuMetric, + process_memory_usage_bytes: memoryMetric, + open_files_count: fileMetric + }, + // container + hexagon: { + docker_cpu_total_usage: cpuMetric, + docker_memory_usage: memoryMetric + }, + // host + circle: { + load5: loadMetric, + host_cpu_usage_percent: cpuMetric, + host_mem_usage_bytes: memoryMetric + } +}; + + function mergeMetrics(node) { - if (node.pseudo) { + if (node.pseudo || node.stack) { return node; } return Object.assign({}, node, { - metrics: { - process_cpu_usage_percent: cpuMetric(node, 'process_cpu_usage_percent'), - process_memory_usage_bytes: memoryMetric(node, 'process_memory_usage_bytes'), - open_files_count: fileMetric(node, 'open_files_count'), - load1: loadMetric(node, 'load1'), - load5: loadMetric(node, 'load5'), - load15: loadMetric(node, 'load15'), - docker_cpu_total_usage: cpuMetric(node, 'docker_cpu_total_usage'), - docker_memory_usage: memoryMetric(node, 'docker_memory_usage'), - host_cpu_usage_percent: cpuMetric(node, 'host_cpu_usage_percent'), - host_mem_usage_bytes: memoryMetric(node, 'host_mem_usage_bytes') - } + metrics: _(metrics[node.shape]) + .map((fn, name) => [name, fn(node)]) + .fromPairs() + .value() }); }