Adds < and > keyboard shortcuts for next/prev metric-on-canvas

This commit is contained in:
Simon Howe
2016-03-09 10:15:59 +01:00
parent a104962aa2
commit cc3d392010
6 changed files with 48 additions and 20 deletions

View File

@@ -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,

View File

@@ -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 {
<Sidebar>
<MetricSelector
availableCanvasMetrics={this.state.availableCanvasMetrics}
lockedMetric={this.state.lockedMetric}
selectedMetric={this.state.selectedMetric}
/>

View File

@@ -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 (
<div
className="available-metrics"
onMouseLeave={() => onMouseOut(lockedMetric)}>
{_.map(METRICS, (key, name) => {
{availableCanvasMetrics.map(({id, label}) => {
return (
<div
key={key}
key={id}
className={classNames('sidebar-item', {
'locked': (key === lockedMetric),
'selected': (key === selectedMetric)
'locked': (id === lockedMetric),
'selected': (id === selectedMetric)
})}
onMouseOver={() => onMouseOver(key)}
onClick={() => onMouseClick(key)}>
{name}
onMouseOver={() => onMouseOver(id)}
onClick={() => onMouseClick(id)}>
{label}
</div>
);
})}

View File

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

View File

@@ -0,0 +1,6 @@
// http://stackoverflow.com/questions/4467539/javascript-modulo-not-behaving
export function modulo(i, n) {
return ((i % n) + n) % n;
}

View File

@@ -4,7 +4,7 @@ import d3 from 'd3';
const formatLargeValue = d3.format('s');
function toHtml(text, unit) {
function renderHtml(text, unit) {
return (
<span className="metric-formatted">
<span className="metric-value">{text}</span>
@@ -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) {