From cc3d3920109af0cba6c040b2bb9dfba86d896a65 Mon Sep 17 00:00:00 2001 From: Simon Howe Date: Wed, 9 Mar 2016 10:15:59 +0100 Subject: [PATCH] Adds < and > keyboard shortcuts for next/prev metric-on-canvas --- client/app/scripts/actions/app-actions.js | 12 ++++++++++ client/app/scripts/components/app.js | 10 +++++++- .../app/scripts/components/metric-selector.js | 24 +++++++------------ client/app/scripts/stores/app-store.js | 11 +++++++++ client/app/scripts/utils/math-utils.js | 6 +++++ client/app/scripts/utils/string-utils.js | 5 ++-- 6 files changed, 48 insertions(+), 20 deletions(-) create mode 100644 client/app/scripts/utils/math-utils.js diff --git a/client/app/scripts/actions/app-actions.js b/client/app/scripts/actions/app-actions.js index 1237dc4de..272d7088d 100644 --- a/client/app/scripts/actions/app-actions.js +++ b/client/app/scripts/actions/app-actions.js @@ -3,6 +3,7 @@ import debug from 'debug'; import AppDispatcher from '../dispatcher/app-dispatcher'; import ActionTypes from '../constants/action-types'; import { saveGraph } from '../utils/file-utils'; +import { modulo } from '../utils/math-utils'; import { updateRoute } from '../utils/router-utils'; import { bufferDeltaUpdate, resumeUpdate, resetUpdateBuffer } from '../utils/update-buffer-utils'; @@ -19,6 +20,17 @@ export function selectMetric(metricId) { }); } +export function lockNextMetric(delta) { + const metrics = AppStore.getAvailableCanvasMetrics().map(m => m.id); + const currentIndex = metrics.indexOf(AppStore.getSelectedMetric()); + const nextMetric = metrics[modulo(currentIndex + delta, metrics.length)]; + + AppDispatcher.dispatch({ + type: ActionTypes.LOCK_METRIC, + metricId: nextMetric + }); +} + export function lockMetric(metricId) { AppDispatcher.dispatch({ type: ActionTypes.LOCK_METRIC, diff --git a/client/app/scripts/components/app.js b/client/app/scripts/components/app.js index e2a9cc7eb..8fc19e087 100644 --- a/client/app/scripts/components/app.js +++ b/client/app/scripts/components/app.js @@ -8,7 +8,7 @@ import Status from './status.js'; import Topologies from './topologies.js'; import TopologyOptions from './topology-options.js'; import { getApiDetails, getTopologies } from '../utils/web-api-utils'; -import { hitEsc } from '../actions/app-actions'; +import { lockNextMetric, hitEsc } from '../actions/app-actions'; import Details from './details'; import Nodes from './nodes'; import MetricSelector from './metric-selector'; @@ -17,6 +17,8 @@ import { getRouter } from '../utils/router-utils'; import { showingDebugToolbar, DebugToolbar } from './debug-toolbar.js'; const ESC_KEY_CODE = 27; +const RIGHT_ANGLE_KEY_IDENTIFIER = 'U+003C'; +const LEFT_ANGLE_KEY_IDENTIFIER = 'U+003E'; function getStateFromStores() { return { @@ -32,6 +34,7 @@ function getStateFromStores() { highlightedNodeIds: AppStore.getHighlightedNodeIds(), hostname: AppStore.getHostname(), lockedMetric: AppStore.getLockedMetric(), + availableCanvasMetrics: AppStore.getAvailableCanvasMetrics(), nodeDetails: AppStore.getNodeDetails(), nodes: AppStore.getNodes(), selectedNodeId: AppStore.getSelectedNodeId(), @@ -73,6 +76,10 @@ export default class App extends React.Component { onKeyPress(ev) { if (ev.keyCode === ESC_KEY_CODE) { hitEsc(); + } else if (ev.keyIdentifier === RIGHT_ANGLE_KEY_IDENTIFIER) { + lockNextMetric(-1); + } else if (ev.keyIdentifier === LEFT_ANGLE_KEY_IDENTIFIER) { + lockNextMetric(1); } } @@ -120,6 +127,7 @@ export default class App extends React.Component { diff --git a/client/app/scripts/components/metric-selector.js b/client/app/scripts/components/metric-selector.js index e2d79f3f3..89761daa0 100644 --- a/client/app/scripts/components/metric-selector.js +++ b/client/app/scripts/components/metric-selector.js @@ -1,14 +1,7 @@ import React from 'react'; -import _ from 'lodash'; import { selectMetric, lockMetric } from '../actions/app-actions'; import classNames from 'classnames'; -const METRICS = { - 'CPU': 'process_cpu_usage_percent', - 'Memory': 'process_memory_usage_bytes', - 'Open Files': 'open_files_count' -}; - // docker_cpu_total_usage // docker_memory_usage @@ -21,26 +14,25 @@ function onMouseClick(k) { } function onMouseOut(k) { - console.log('onMouseOut', k); selectMetric(k); } -export default function MetricSelector({selectedMetric, lockedMetric}) { +export default function MetricSelector({availableCanvasMetrics, selectedMetric, lockedMetric}) { return (
onMouseOut(lockedMetric)}> - {_.map(METRICS, (key, name) => { + {availableCanvasMetrics.map(({id, label}) => { return (
onMouseOver(key)} - onClick={() => onMouseClick(key)}> - {name} + onMouseOver={() => onMouseOver(id)} + onClick={() => onMouseClick(id)}> + {label}
); })} diff --git a/client/app/scripts/stores/app-store.js b/client/app/scripts/stores/app-store.js index 569142208..37d66125c 100644 --- a/client/app/scripts/stores/app-store.js +++ b/client/app/scripts/stores/app-store.js @@ -61,6 +61,12 @@ 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'} +]; + const topologySorter = topology => topology.get('rank'); @@ -175,6 +181,10 @@ export class AppStore extends Store { return selectedMetric; } + getAvailableCanvasMetrics() { + return availableCanvasMetrics; + } + getControlStatus() { return controlStatus.toJS(); } @@ -419,6 +429,7 @@ export class AppStore extends Store { } case ActionTypes.LOCK_METRIC: { lockedMetric = payload.metricId; + selectedMetric = payload.metricId; this.__emitChange(); break; } diff --git a/client/app/scripts/utils/math-utils.js b/client/app/scripts/utils/math-utils.js new file mode 100644 index 000000000..7389776d4 --- /dev/null +++ b/client/app/scripts/utils/math-utils.js @@ -0,0 +1,6 @@ + +// http://stackoverflow.com/questions/4467539/javascript-modulo-not-behaving +export function modulo(i, n) { + return ((i % n) + n) % n; +} + diff --git a/client/app/scripts/utils/string-utils.js b/client/app/scripts/utils/string-utils.js index 40dee2791..046efb71c 100644 --- a/client/app/scripts/utils/string-utils.js +++ b/client/app/scripts/utils/string-utils.js @@ -4,7 +4,7 @@ import d3 from 'd3'; const formatLargeValue = d3.format('s'); -function toHtml(text, unit) { +function renderHtml(text, unit) { return ( {text} @@ -18,7 +18,6 @@ function makeFormatters(renderFn) { const formatters = { filesize(value) { const obj = filesize(value, {output: 'object'}); - console.log('rendering', value); return renderFn(obj.value, obj.suffix); }, @@ -45,7 +44,7 @@ function makeFormatters(renderFn) { } -const formatters = makeFormatters(toHtml); +const formatters = makeFormatters(renderHtml); const svgFormatters = makeFormatters((text, unit) => `${text}${unit}`); export function formatMetric(value, opts, svg) {