mirror of
https://github.com/weaveworks/scope.git
synced 2026-05-06 09:18:27 +00:00
No preview for overflow health items
This commit is contained in:
@@ -4,17 +4,18 @@ import Sparkline from '../sparkline';
|
||||
import { formatMetric } from '../../utils/string-utils';
|
||||
|
||||
function NodeDetailsHealthItem(props) {
|
||||
const labelStyle = { color: props.labelColor };
|
||||
return (
|
||||
<div className="node-details-health-item">
|
||||
{!props.valueEmpty && <div className="node-details-health-item-value">{formatMetric(props.value, props)}</div>}
|
||||
{!props.valueEmpty && <div className="node-details-health-item-value" style={labelStyle}>{formatMetric(props.value, props)}</div>}
|
||||
<div className="node-details-health-item-sparkline">
|
||||
<Sparkline
|
||||
data={props.samples} max={props.max} format={props.format}
|
||||
first={props.first} last={props.last} hoverColor={props.metricColor}
|
||||
hovered={props.samples && props.hovered}
|
||||
hovered={props.hovered}
|
||||
/>
|
||||
</div>
|
||||
<div className="node-details-health-item-label" style={{ color: props.labelColor }}>
|
||||
<div className="node-details-health-item-label" style={labelStyle}>
|
||||
{props.label}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,6 +3,7 @@ import React from 'react';
|
||||
import NodeDetailsHealthItem from './node-details-health-item';
|
||||
import CloudLink from '../cloud-link';
|
||||
import { getMetricColor } from '../../utils/metric-utils';
|
||||
import { darkenColor } from '../../utils/color-utils';
|
||||
import { trackMixpanelEvent } from '../../utils/tracking-utils';
|
||||
|
||||
export default class NodeDetailsHealthLinkItem extends React.Component {
|
||||
@@ -33,6 +34,7 @@ export default class NodeDetailsHealthLinkItem extends React.Component {
|
||||
render() {
|
||||
const { id, url, ...props } = this.props;
|
||||
const metricColor = getMetricColor(id);
|
||||
const labelColor = this.state.hovered && !props.valueEmpty && darkenColor(metricColor);
|
||||
|
||||
return (
|
||||
<CloudLink
|
||||
@@ -46,6 +48,7 @@ export default class NodeDetailsHealthLinkItem extends React.Component {
|
||||
<NodeDetailsHealthItem
|
||||
{...props}
|
||||
hovered={this.state.hovered}
|
||||
labelColor={labelColor}
|
||||
metricColor={metricColor}
|
||||
/>
|
||||
</CloudLink>
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { formatMetric } from '../../utils/string-utils';
|
||||
|
||||
function NodeDetailsHealthOverflowItem(props) {
|
||||
return (
|
||||
<div className="node-details-health-overflow-item">
|
||||
<div className="node-details-health-overflow-item-value">
|
||||
{!props.valueEmpty && formatMetric(props.value, props)}
|
||||
</div>
|
||||
<div className="node-details-health-overflow-item-label truncate">{props.label}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default NodeDetailsHealthOverflowItem;
|
||||
@@ -1,26 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import NodeDetailsHealthOverflowItem from './node-details-health-overflow-item';
|
||||
|
||||
export default class NodeDetailsHealthOverflow extends React.Component {
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
|
||||
handleClick(ev) {
|
||||
ev.preventDefault();
|
||||
this.props.handleClick();
|
||||
}
|
||||
|
||||
render() {
|
||||
const items = this.props.items.slice(0, 4);
|
||||
|
||||
return (
|
||||
<div className="node-details-health-overflow" onClick={this.handleClick} title="Expand metrics">
|
||||
{items.map(item => <NodeDetailsHealthOverflowItem key={item.id} {...item} />)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
import ShowMore from '../show-more';
|
||||
import NodeDetailsHealthOverflow from './node-details-health-overflow';
|
||||
import NodeDetailsHealthLinkItem from './node-details-health-link-item';
|
||||
|
||||
export default class NodeDetailsHealth extends React.Component {
|
||||
@@ -25,30 +24,38 @@ export default class NodeDetailsHealth extends React.Component {
|
||||
topologyId,
|
||||
} = this.props;
|
||||
|
||||
const primeCutoff = metrics.length > 3 && !this.state.expanded ? 2 : metrics.length;
|
||||
const primeMetrics = metrics.slice(0, primeCutoff);
|
||||
const overflowMetrics = metrics.slice(primeCutoff);
|
||||
const showOverflow = overflowMetrics.length > 0 && !this.state.expanded;
|
||||
const flexWrap = showOverflow || !this.state.expanded ? 'nowrap' : 'wrap';
|
||||
const justifyContent = showOverflow || !this.state.expanded ? 'space-around' : 'flex-start';
|
||||
const notShown = overflowMetrics.length;
|
||||
let primeMetrics = metrics.filter(m => !m.valueEmpty);
|
||||
let emptyMetrics = metrics.filter(m => m.valueEmpty);
|
||||
|
||||
if (primeMetrics.length === 0 && emptyMetrics.length > 0) {
|
||||
primeMetrics = emptyMetrics;
|
||||
emptyMetrics = [];
|
||||
}
|
||||
|
||||
const shownWithData = this.state.expanded ? primeMetrics : primeMetrics.slice(0, 3);
|
||||
const shownEmpty = this.state.expanded ? emptyMetrics : [];
|
||||
const notShown = metrics.length - shownWithData.length - shownEmpty.length;
|
||||
|
||||
return (
|
||||
<div className="node-details-health" style={{flexWrap, justifyContent}}>
|
||||
<div className="node-details-health" style={{ justifyContent: 'space-around' }}>
|
||||
<div className="node-details-health-wrapper">
|
||||
{primeMetrics.map(item => <NodeDetailsHealthLinkItem
|
||||
{shownWithData.map(item => <NodeDetailsHealthLinkItem
|
||||
{...item}
|
||||
key={item.id}
|
||||
topologyId={topologyId}
|
||||
/>)}
|
||||
</div>
|
||||
<div className="node-details-health-wrapper">
|
||||
{shownEmpty.map(item => <NodeDetailsHealthLinkItem
|
||||
{...item}
|
||||
key={item.id}
|
||||
topologyId={topologyId}
|
||||
/>)}
|
||||
{showOverflow && <NodeDetailsHealthOverflow
|
||||
items={overflowMetrics}
|
||||
handleClick={this.handleClickMore}
|
||||
/>}
|
||||
</div>
|
||||
<ShowMore
|
||||
handleClick={this.handleClickMore} collection={this.props.metrics}
|
||||
expanded={this.state.expanded} notShown={notShown} hideNumber />
|
||||
handleClick={this.handleClickMore} collection={metrics}
|
||||
expanded={this.state.expanded} notShown={notShown} hideNumber={this.state.expanded}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,11 +7,11 @@ import { line, curveLinear } from 'd3-shape';
|
||||
import { scaleLinear } from 'd3-scale';
|
||||
|
||||
import { formatMetricSvg } from '../utils/string-utils';
|
||||
import { brightenColor, darkenColor } from '../utils/color-utils';
|
||||
|
||||
|
||||
const HOVER_RADIUS_MULTIPLY = 1.5;
|
||||
const HOVER_STROKE_MULTIPLY = 5;
|
||||
const MARGIN = 2;
|
||||
|
||||
export default class Sparkline extends React.Component {
|
||||
constructor(props, context) {
|
||||
@@ -24,11 +24,15 @@ export default class Sparkline extends React.Component {
|
||||
.y(d => this.y(d.value));
|
||||
}
|
||||
|
||||
initRanges() {
|
||||
initRanges(hasCircle) {
|
||||
// adjust scales and leave some room for the circle on the right, upper, and lower edge
|
||||
const padding = 2 + Math.ceil(this.props.circleRadius * HOVER_RADIUS_MULTIPLY);
|
||||
this.x.range([2, this.props.width - padding]);
|
||||
this.y.range([this.props.height - padding, padding]);
|
||||
let circleSpace = MARGIN;
|
||||
if (hasCircle) {
|
||||
circleSpace += Math.ceil(this.props.circleRadius * HOVER_RADIUS_MULTIPLY);
|
||||
}
|
||||
|
||||
this.x.range([MARGIN, this.props.width - circleSpace]);
|
||||
this.y.range([this.props.height - circleSpace, circleSpace]);
|
||||
this.line.curve(this.props.curve);
|
||||
}
|
||||
|
||||
@@ -36,7 +40,7 @@ export default class Sparkline extends React.Component {
|
||||
// data is of shape [{date, value}, ...] and is sorted by date (ASC)
|
||||
let data = this.props.data;
|
||||
|
||||
this.initRanges();
|
||||
this.initRanges(true);
|
||||
|
||||
// Convert dates into D3 dates
|
||||
data = data.map(d => ({
|
||||
@@ -75,7 +79,7 @@ export default class Sparkline extends React.Component {
|
||||
}
|
||||
|
||||
getEmptyGraphData() {
|
||||
this.initRanges();
|
||||
this.initRanges(false);
|
||||
const first = new Date(0);
|
||||
const last = new Date(15);
|
||||
this.x.domain([first, last]);
|
||||
@@ -93,43 +97,30 @@ export default class Sparkline extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
let strokeColor = this.props.strokeColor;
|
||||
let strokeWidth = this.props.strokeWidth;
|
||||
let radius = this.props.circleRadius;
|
||||
let fillOpacity = 0.6;
|
||||
let circleColor;
|
||||
let graph = {};
|
||||
|
||||
if (!this.props.data || this.props.data.length === 0 || this.props.data[0].date === undefined) {
|
||||
// no data means just a dead line w/o circle
|
||||
graph = this.getEmptyGraphData();
|
||||
strokeColor = brightenColor(strokeColor);
|
||||
radius = 0;
|
||||
} else {
|
||||
graph = this.getGraphData();
|
||||
|
||||
if (this.props.hovered) {
|
||||
strokeColor = this.props.hoverColor;
|
||||
circleColor = strokeColor;
|
||||
strokeWidth *= HOVER_STROKE_MULTIPLY;
|
||||
radius *= HOVER_RADIUS_MULTIPLY;
|
||||
fillOpacity = 1;
|
||||
} else {
|
||||
circleColor = darkenColor(strokeColor);
|
||||
}
|
||||
}
|
||||
const dash = 5;
|
||||
const hasData = this.props.data && this.props.data.length > 0;
|
||||
const strokeColor = this.props.hovered && hasData
|
||||
? this.props.hoverColor
|
||||
: this.props.strokeColor;
|
||||
const strokeWidth = this.props.strokeWidth * (this.props.hovered ? HOVER_STROKE_MULTIPLY : 1);
|
||||
const strokeDasharray = hasData || `${dash}, ${dash}`;
|
||||
const radius = this.props.circleRadius * (this.props.hovered ? HOVER_RADIUS_MULTIPLY : 1);
|
||||
const fillOpacity = this.props.hovered ? 1 : 0.6;
|
||||
const circleColor = hasData && this.props.hovered ? strokeColor : strokeColor;
|
||||
const graph = hasData ? this.getGraphData() : this.getEmptyGraphData();
|
||||
|
||||
return (
|
||||
<div title={graph.title}>
|
||||
<svg width={this.props.width} height={this.props.height}>
|
||||
<path
|
||||
className="sparkline" fill="none" stroke={strokeColor}
|
||||
strokeWidth={strokeWidth} d={this.line(graph.data)}
|
||||
strokeWidth={strokeWidth} strokeDasharray={strokeDasharray}
|
||||
d={this.line(graph.data)}
|
||||
/>
|
||||
<circle
|
||||
{hasData && <circle
|
||||
className="sparkcircle" cx={graph.lastX} cy={graph.lastY} fill={circleColor}
|
||||
fillOpacity={fillOpacity} stroke="none" r={radius}
|
||||
/>
|
||||
/>}
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user