mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-24 07:46:41 +00:00
Return to mock-metrics for now.
- Bring MoC under new linting rules - adds support for immutable-console-renderer - fixes up metrics actually displaying after bad fixes when rebasing. - Mock all metrics client side for demoing
This commit is contained in:
@@ -5,6 +5,7 @@ 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 { addMetrics } from '../utils/data-utils';
|
||||
import { bufferDeltaUpdate, resumeUpdate,
|
||||
resetUpdateBuffer } from '../utils/update-buffer-utils';
|
||||
import { doControlRequest, getNodesDelta, getNodeDetails,
|
||||
@@ -16,7 +17,7 @@ const log = debug('scope:app-actions');
|
||||
export function selectMetric(metricId) {
|
||||
AppDispatcher.dispatch({
|
||||
type: ActionTypes.SELECT_METRIC,
|
||||
metricId: metricId
|
||||
metricId
|
||||
});
|
||||
}
|
||||
|
||||
@@ -34,7 +35,7 @@ export function lockNextMetric(delta) {
|
||||
export function lockMetric(metricId) {
|
||||
AppDispatcher.dispatch({
|
||||
type: ActionTypes.LOCK_METRIC,
|
||||
metricId: metricId
|
||||
metricId
|
||||
});
|
||||
}
|
||||
|
||||
@@ -265,16 +266,18 @@ export function receiveNodeDetails(details) {
|
||||
}
|
||||
|
||||
export function receiveNodesDelta(delta) {
|
||||
const deltaWithMetrics = addMetrics(delta, AppStore.getNodes());
|
||||
if (AppStore.isUpdatePaused()) {
|
||||
bufferDeltaUpdate(delta);
|
||||
bufferDeltaUpdate(deltaWithMetrics);
|
||||
} else {
|
||||
AppDispatcher.dispatch({
|
||||
type: ActionTypes.RECEIVE_NODES_DELTA,
|
||||
delta: delta
|
||||
delta: deltaWithMetrics
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function receiveTopologies(topologies) {
|
||||
AppDispatcher.dispatch({
|
||||
type: ActionTypes.RECEIVE_TOPOLOGIES,
|
||||
|
||||
@@ -8,7 +8,7 @@ export default function NodeShapeCircle({highlighted, size, color, metric}) {
|
||||
const {height, value, formattedValue} = getMetricValue(metric, size);
|
||||
|
||||
const className = classNames('shape', {
|
||||
'metrics': value !== null
|
||||
metrics: value !== null
|
||||
});
|
||||
const metricStyle = {
|
||||
fillOpacity: 0.5,
|
||||
@@ -30,9 +30,10 @@ export default function NodeShapeCircle({highlighted, size, color, metric}) {
|
||||
{highlighted && hightlightNode}
|
||||
<circle r={size * 0.5} className="border" stroke={color} />
|
||||
<circle r={size * 0.45} className="shadow" />
|
||||
<circle r={size * 0.45} className="metric-fill" style={metricStyle} clipPath={`url(#${clipId})`} />
|
||||
<circle r={size * 0.45} className="metric-fill" style={metricStyle}
|
||||
clipPath={`url(#${clipId})`} />
|
||||
{highlighted && value !== null ?
|
||||
<text dy="0.35em" style={{'textAnchor': 'middle'}}>{formattedValue}</text> :
|
||||
<text dy="0.35em" style={{textAnchor: 'middle'}}>{formattedValue}</text> :
|
||||
<circle className="node" r={Math.max(2, (size * 0.125))} />}
|
||||
</g>
|
||||
);
|
||||
|
||||
@@ -27,7 +27,7 @@ export default function NodeShapeHeptagon({highlighted, size, color, metric}) {
|
||||
const {height, value, formattedValue} = getMetricValue(metric, size);
|
||||
|
||||
const className = classNames('shape', {
|
||||
'metrics': value !== null
|
||||
metrics: value !== null
|
||||
});
|
||||
const metricStyle = {
|
||||
fillOpacity: 0.5,
|
||||
@@ -49,9 +49,10 @@ export default function NodeShapeHeptagon({highlighted, size, color, metric}) {
|
||||
{highlighted && <path className="highlighted" {...pathProps(0.7)} />}
|
||||
<path className="border" stroke={color} {...pathProps(0.5)} />
|
||||
<path className="shadow" {...pathProps(0.45)} />
|
||||
<path className="metric-fill" clipPath={`url(#${clipId})`} style={metricStyle} {...pathProps(0.45)} />
|
||||
<path className="metric-fill" clipPath={`url(#${clipId})`}
|
||||
style={metricStyle} {...pathProps(0.45)} />
|
||||
{highlighted && value !== null ?
|
||||
<text dy="0.35em" style={{'textAnchor': 'middle'}}>{formattedValue}</text> :
|
||||
<text dy="0.35em" style={{textAnchor: 'middle'}}>{formattedValue}</text> :
|
||||
<circle className="node" r={Math.max(2, (size * 0.125))} />}
|
||||
</g>
|
||||
);
|
||||
|
||||
@@ -38,7 +38,7 @@ export default function NodeShapeHex({highlighted, size, color, metric}) {
|
||||
const clipId = `mask-${Math.random()}`;
|
||||
const {height, value, formattedValue} = getMetricValue(metric, size);
|
||||
const className = classNames('shape', {
|
||||
'metrics': value !== null
|
||||
metrics: value !== null
|
||||
});
|
||||
const metricStyle = {
|
||||
fillOpacity: 0.5,
|
||||
@@ -59,9 +59,10 @@ export default function NodeShapeHex({highlighted, size, color, metric}) {
|
||||
{highlighted && <path className="highlighted" {...pathProps(0.7)} />}
|
||||
<path className="border" stroke={color} {...pathProps(0.5)} />
|
||||
<path className="shadow" {...pathProps(shadowSize)} />
|
||||
<path className="metric-fill" style={metricStyle} clipPath={`url(#${clipId})`} {...pathProps(shadowSize)} />
|
||||
<path className="metric-fill" style={metricStyle}
|
||||
clipPath={`url(#${clipId})`} {...pathProps(shadowSize)} />
|
||||
{highlighted && value !== null ?
|
||||
<text dy="0.35em" style={{'textAnchor': 'middle'}}>
|
||||
<text dy="0.35em" style={{textAnchor: 'middle'}}>
|
||||
{formattedValue}
|
||||
</text> :
|
||||
<circle className="node" r={Math.max(2, (size * 0.125))} />}
|
||||
|
||||
@@ -17,7 +17,7 @@ export default function NodeShapeSquare({
|
||||
const clipId = `mask-${Math.random()}`;
|
||||
const {height, value, formattedValue} = getMetricValue(metric, size);
|
||||
const className = classNames('shape', {
|
||||
'metrics': value !== null
|
||||
metrics: value !== null
|
||||
});
|
||||
|
||||
const metricStyle = {
|
||||
@@ -40,9 +40,10 @@ export default function NodeShapeSquare({
|
||||
{highlighted && <rect className="highlighted" {...rectProps(0.7)} />}
|
||||
<rect className="border" stroke={color} {...rectProps(0.5, 0.5)} />
|
||||
<rect className="shadow" {...rectProps(0.45, 0.39)} />
|
||||
<rect className="metric-fill" style={metricStyle} clipPath={`url(#${clipId})`} {...rectProps(0.45, 0.39)} />
|
||||
<rect className="metric-fill" style={metricStyle}
|
||||
clipPath={`url(#${clipId})`} {...rectProps(0.45, 0.39)} />
|
||||
{highlighted && value !== null ?
|
||||
<text dy="0.35em" style={{'textAnchor': 'middle'}}>{formattedValue}</text> :
|
||||
<text dy="0.35em" style={{textAnchor: 'middle'}}>{formattedValue}</text> :
|
||||
<circle className="node" r={Math.max(2, (size * 0.125))} />}
|
||||
</g>
|
||||
);
|
||||
|
||||
@@ -244,7 +244,7 @@ export default class NodesChart extends React.Component {
|
||||
initNodes(topology) {
|
||||
// copy relevant fields to state nodes
|
||||
return topology.map((node, id) => makeMap({
|
||||
id:
|
||||
id,
|
||||
label: node.get('label'),
|
||||
pseudo: node.get('pseudo'),
|
||||
metrics: node.get('metrics'),
|
||||
@@ -425,9 +425,9 @@ export default class NodesChart extends React.Component {
|
||||
if (!graph) {
|
||||
return {maxNodesExceeded: true};
|
||||
}
|
||||
stateNodes = graph.nodes.mergeDeep(stateNodes.map(node => {
|
||||
return makeMap({metrics: node.get('metrics')});
|
||||
}));
|
||||
stateNodes = graph.nodes.mergeDeep(stateNodes.map(node => makeMap({
|
||||
metrics: node.get('metrics')
|
||||
})));
|
||||
stateEdges = graph.edges;
|
||||
|
||||
// save coordinates for restore
|
||||
|
||||
@@ -24,7 +24,9 @@ const shapeTypes = {
|
||||
};
|
||||
|
||||
|
||||
const LABEL_PREFIXES = _.range('A'.charCodeAt(), 'Z'.charCodeAt() + 1).map(n => String.fromCharCode(n));
|
||||
const LABEL_PREFIXES = _.range('A'.charCodeAt(), 'Z'.charCodeAt() + 1)
|
||||
.map(n => String.fromCharCode(n));
|
||||
const randomLetter = () => _.sample(LABEL_PREFIXES);
|
||||
|
||||
const deltaAdd = (name, adjacency = [], shape = 'circle', stack = false, nodeCount = 1) => ({
|
||||
adjacency,
|
||||
@@ -34,11 +36,11 @@ const deltaAdd = (name, adjacency = [], shape = 'circle', stack = false, nodeCou
|
||||
node_count: nodeCount,
|
||||
id: name,
|
||||
label: name,
|
||||
label_minor: 'weave-1',
|
||||
label_minor: name,
|
||||
latest: {},
|
||||
metadata: {},
|
||||
origins: [],
|
||||
rank: 'alpine'
|
||||
rank: name
|
||||
});
|
||||
|
||||
|
||||
@@ -49,14 +51,10 @@ function label(shape, stacked) {
|
||||
|
||||
|
||||
function addAllVariants() {
|
||||
const newNodes = _.flattenDeep(STACK_VARIANTS.map(stack => {
|
||||
return SHAPES.map(s => {
|
||||
if (!stack) return [deltaAdd(label(s, stack), [], s, stack, 1)];
|
||||
return NODE_COUNTS.map(n => {
|
||||
return deltaAdd(label(s, stack), [], s, stack, n);
|
||||
});
|
||||
});
|
||||
}));
|
||||
const newNodes = _.flattenDeep(STACK_VARIANTS.map(stack => (SHAPES.map(s => {
|
||||
if (!stack) return [deltaAdd(label(s, stack), [], s, stack, 1)];
|
||||
return NODE_COUNTS.map(n => deltaAdd(label(s, stack), [], s, stack, n));
|
||||
}))));
|
||||
|
||||
receiveNodesDelta({
|
||||
add: newNodes
|
||||
@@ -67,20 +65,19 @@ function addAllVariants() {
|
||||
function addNodes(n) {
|
||||
const ns = AppStore.getNodes();
|
||||
const nodeNames = ns.keySeq().toJS();
|
||||
const newNodeNames = _.range(ns.size, ns.size + n).map(() => {
|
||||
return _.sample(LABEL_PREFIXES, 2).join('') + '-zing';
|
||||
});
|
||||
const newNodeNames = _.range(ns.size, ns.size + n).map(() => (
|
||||
`${randomLetter()}${randomLetter()}-zing`
|
||||
));
|
||||
const allNodes = _(nodeNames).concat(newNodeNames).value();
|
||||
|
||||
receiveNodesDelta({
|
||||
add: newNodeNames.map((name) => {
|
||||
return deltaAdd(
|
||||
name,
|
||||
sample(allNodes),
|
||||
_.sample(SHAPES),
|
||||
_.sample(STACK_VARIANTS),
|
||||
_.sample(NODE_COUNTS));
|
||||
})
|
||||
add: newNodeNames.map((name) => deltaAdd(
|
||||
name,
|
||||
sample(allNodes),
|
||||
_.sample(SHAPES),
|
||||
_.sample(STACK_VARIANTS),
|
||||
_.sample(NODE_COUNTS)
|
||||
))
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
73
client/app/scripts/components/metric-selector-item.js
Normal file
73
client/app/scripts/components/metric-selector-item.js
Normal file
@@ -0,0 +1,73 @@
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { selectMetric, lockMetric, unlockMetric } from '../actions/app-actions';
|
||||
|
||||
|
||||
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'
|
||||
};
|
||||
|
||||
|
||||
export function label(m) {
|
||||
return METRIC_LABELS[m.id];
|
||||
}
|
||||
|
||||
|
||||
export class MetricSelectorItem extends React.Component {
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.onMouseOver = this.onMouseOver.bind(this);
|
||||
this.onMouseClick = this.onMouseClick.bind(this);
|
||||
}
|
||||
|
||||
onMouseOver() {
|
||||
const k = this.props.metric.id;
|
||||
selectMetric(k);
|
||||
}
|
||||
|
||||
onMouseClick() {
|
||||
const k = this.props.metric.id;
|
||||
const lockedMetric = this.props.lockedMetric;
|
||||
|
||||
if (k === lockedMetric) {
|
||||
unlockMetric(k);
|
||||
} else {
|
||||
lockMetric(k);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {metric, selectedMetric, lockedMetric} = this.props;
|
||||
const id = metric.id;
|
||||
const isLocked = (id === lockedMetric);
|
||||
const isSelected = (id === selectedMetric);
|
||||
const className = classNames('sidebar-item', {
|
||||
locked: isLocked,
|
||||
selected: isSelected
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
key={id}
|
||||
className={className}
|
||||
onMouseOver={this.onMouseOver}
|
||||
onClick={this.onMouseClick}>
|
||||
{label(metric)}
|
||||
{isLocked && <span className="sidebar-item-actions">
|
||||
<span className="sidebar-item-action fa fa-thumb-tack"></span>
|
||||
</span>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,76 +1,42 @@
|
||||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import { selectMetric, lockMetric, unlockMetric } from '../actions/app-actions';
|
||||
import classNames from 'classnames';
|
||||
import { selectMetric } from '../actions/app-actions';
|
||||
import { MetricSelectorItem, label } from './metric-selector-item';
|
||||
|
||||
// const CROSS = '\u274C';
|
||||
// const MINUS = '\u2212';
|
||||
// const DOT = '\u2022';
|
||||
//
|
||||
|
||||
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'
|
||||
};
|
||||
|
||||
function onMouseOver(k) {
|
||||
selectMetric(k);
|
||||
}
|
||||
export default class MetricSelector extends React.Component {
|
||||
|
||||
function onMouseClick(k, lockedMetric) {
|
||||
if (k === lockedMetric) {
|
||||
unlockMetric(k);
|
||||
} else {
|
||||
lockMetric(k);
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
this.onMouseOut = this.onMouseOut.bind(this);
|
||||
}
|
||||
|
||||
onMouseOut() {
|
||||
selectMetric(this.props.lockedMetric);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {availableCanvasMetrics} = this.props;
|
||||
|
||||
const items = _.sortBy(availableCanvasMetrics, label).map(metric => (
|
||||
<MetricSelectorItem key={metric.id} metric={metric} {...this.props} />
|
||||
));
|
||||
|
||||
return (
|
||||
<div
|
||||
className="available-metrics"
|
||||
onMouseLeave={this.onMouseOut}>
|
||||
<div className="sidebar-item">
|
||||
METRICS
|
||||
</div>
|
||||
{items}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseOut(k) {
|
||||
selectMetric(k);
|
||||
}
|
||||
|
||||
function label(m) {
|
||||
return METRIC_LABELS[m.id];
|
||||
}
|
||||
|
||||
export default function MetricSelector({availableCanvasMetrics, selectedMetric, lockedMetric}) {
|
||||
return (
|
||||
<div
|
||||
className="available-metrics"
|
||||
onMouseLeave={() => onMouseOut(lockedMetric)}>
|
||||
<div className="sidebar-item">
|
||||
METRICS
|
||||
</div>
|
||||
{_.sortBy(availableCanvasMetrics, label).map(m => {
|
||||
const id = m.id;
|
||||
const isLocked = (id === lockedMetric);
|
||||
const isSelected = (id === selectedMetric);
|
||||
const className = classNames('sidebar-item', {
|
||||
'locked': isLocked,
|
||||
'selected': isSelected
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
key={id}
|
||||
className={className}
|
||||
onMouseOver={() => onMouseOver(id)}
|
||||
onClick={() => onMouseClick(id, lockedMetric)}>
|
||||
{label(m)}
|
||||
{isLocked && <span className="sidebar-item-actions">
|
||||
<span className="sidebar-item-action fa fa-thumb-tack"></span>
|
||||
</span>}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
3
client/app/scripts/debug.js
Normal file
3
client/app/scripts/debug.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import Immutable from 'immutable';
|
||||
import installDevTools from 'immutable-devtools';
|
||||
installDevTools(Immutable);
|
||||
@@ -589,9 +589,9 @@ export class AppStore extends Store {
|
||||
});
|
||||
|
||||
// update existing nodes
|
||||
_.each(payload.delta.update, function(node) {
|
||||
_.each(payload.delta.update, (node) => {
|
||||
if (nodes.has(node.id)) {
|
||||
nodes = nodes.set(node.id, nodes.get(node.id).merge(Immutable.fromJS(node)));
|
||||
nodes = nodes.set(node.id, nodes.get(node.id).merge(fromJS(node)));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -600,6 +600,14 @@ export class AppStore extends Store {
|
||||
nodes = nodes.set(node.id, fromJS(makeNode(node)));
|
||||
});
|
||||
|
||||
availableCanvasMetrics = nodes
|
||||
.valueSeq()
|
||||
.flatMap(n => (n.get('metrics') || makeMap()).keys())
|
||||
.toSet()
|
||||
.sort()
|
||||
.toJS()
|
||||
.map(v => ({id: v, label: v}));
|
||||
|
||||
if (emitChange) {
|
||||
this.__emitChange();
|
||||
}
|
||||
@@ -627,15 +635,6 @@ export class AppStore extends Store {
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import AppStore from '../stores/app-store';
|
||||
|
||||
|
||||
// Inspired by Lee Byron's test data generator.
|
||||
/*eslint-disable */
|
||||
function bumpLayer(n, maxValue) {
|
||||
function bump(a) {
|
||||
const x = 1 / (0.1 + Math.random());
|
||||
@@ -24,6 +25,7 @@ function bumpLayer(n, maxValue) {
|
||||
const s = d3.scale.linear().domain(d3.extent(values)).range([0, maxValue]);
|
||||
return values.map(s);
|
||||
}
|
||||
/*eslint-enable */
|
||||
|
||||
|
||||
const nodeData = {};
|
||||
@@ -40,17 +42,56 @@ function getNextValue(keyValues, maxValue) {
|
||||
}
|
||||
|
||||
|
||||
const METRIC_FORMATS = {
|
||||
docker_cpu_total_usage: 'percent',
|
||||
docker_memory_usage: 'filesize',
|
||||
host_cpu_usage_percent: 'percent',
|
||||
host_mem_usage_bytes: 'filesize',
|
||||
load1: 'number',
|
||||
load15: 'number',
|
||||
load5: 'number',
|
||||
open_files_count: 'integer',
|
||||
process_cpu_usage_percent: 'percent',
|
||||
process_memory_usage_bytes: 'filesize'
|
||||
};
|
||||
|
||||
|
||||
const memoryMetric = (node, name, max = 1024 * 1024 * 1024) => ({
|
||||
samples: [{value: getNextValue([node.id, name], max)}],
|
||||
max
|
||||
});
|
||||
|
||||
const cpuMetric = (node, name, max = 100) => ({
|
||||
samples: [{value: getNextValue([node.id, name], max)}],
|
||||
max
|
||||
});
|
||||
|
||||
const fileMetric = (node, name, max = 10000) => ({
|
||||
samples: [{value: getNextValue([node.id, name], max)}],
|
||||
max
|
||||
});
|
||||
|
||||
const loadMetric = (node, name, max = 10) => ({
|
||||
samples: [{value: getNextValue([node.id, name], max)}],
|
||||
max
|
||||
});
|
||||
|
||||
function mergeMetrics(node) {
|
||||
if (node.pseudo) {
|
||||
return node;
|
||||
}
|
||||
return Object.assign({}, node, {
|
||||
metrics: {
|
||||
'process_cpu_usage_percent': {
|
||||
samples: [{value: getNextValue([node.id, 'cpu'], 100)}],
|
||||
max: 100
|
||||
},
|
||||
'memory': {
|
||||
samples: [{value: getNextValue([node.id, 'memory'], 1024)}],
|
||||
max: 1024
|
||||
}
|
||||
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')
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -66,9 +107,9 @@ function handleAdd(nodes) {
|
||||
|
||||
function handleUpdated(updatedNodes, prevNodes) {
|
||||
const modifiedNodesIndex = _.zipObject((updatedNodes || []).map(n => [n.id, n]));
|
||||
return prevNodes.toIndexedSeq().toJS().map(n => {
|
||||
return Object.assign({}, mergeMetrics(n), modifiedNodesIndex[n.id]);
|
||||
});
|
||||
return prevNodes.toIndexedSeq().toJS().map(n => (
|
||||
Object.assign({}, mergeMetrics(n), modifiedNodesIndex[n.id])
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -79,19 +120,6 @@ export function addMetrics(delta, prevNodes) {
|
||||
});
|
||||
}
|
||||
|
||||
const METRIC_FORMATS = {
|
||||
docker_cpu_total_usage: 'percent',
|
||||
docker_memory_usage: 'filesize',
|
||||
host_cpu_usage_percent: 'percent',
|
||||
host_mem_usage_bytes: 'filesize',
|
||||
load1: 'number',
|
||||
load15: 'number',
|
||||
load5: 'number',
|
||||
open_files_count: 'integer',
|
||||
process_cpu_usage_percent: 'percent',
|
||||
process_memory_usage_bytes: 'filesize'
|
||||
};
|
||||
|
||||
const openFilesScale = d3.scale.log().domain([1, 100000]).range([0, 1]);
|
||||
//
|
||||
// loadScale(1) == 0.5; E.g. a nicely balanced system :).
|
||||
@@ -123,8 +151,8 @@ export function getMetricValue(metric, size) {
|
||||
{}, {format: METRIC_FORMATS[selectedMetric]}, metric.toJS());
|
||||
|
||||
return {
|
||||
height: height,
|
||||
value: value,
|
||||
height,
|
||||
value,
|
||||
formattedValue: formatMetric(value, metricWithFormat, true)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -22,10 +22,11 @@ function makeFormatters(renderFn) {
|
||||
},
|
||||
|
||||
integer(value) {
|
||||
const intNumber = Number(value).toFixed(0);
|
||||
if (value < 1100 && value >= 0) {
|
||||
return Number(value).toFixed(0);
|
||||
return intNumber;
|
||||
}
|
||||
return formatLargeValue(value);
|
||||
return formatLargeValue(intNumber);
|
||||
},
|
||||
|
||||
number(value) {
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
"eslint-plugin-react": "4.2.2",
|
||||
"file-loader": "0.8.5",
|
||||
"http-proxy-rules": "^1.0.1",
|
||||
"immutable-devtools": "0.0.6",
|
||||
"jest-cli": "~0.9.2",
|
||||
"json-loader": "0.5.4",
|
||||
"less": "~2.6.1",
|
||||
|
||||
@@ -26,7 +26,8 @@ module.exports = {
|
||||
'app': [
|
||||
'./app/scripts/main',
|
||||
'webpack-dev-server/client?http://localhost:4041',
|
||||
'webpack/hot/only-dev-server'
|
||||
'webpack/hot/only-dev-server',
|
||||
'./app/scripts/debug'
|
||||
],
|
||||
'contrast-app': [
|
||||
'./app/scripts/contrast-main',
|
||||
|
||||
Reference in New Issue
Block a user