diff --git a/client/app/scripts/components/node-details/node-details-control-button.js b/client/app/scripts/components/node-details/node-details-control-button.js index b5915b8b8..99a2629a6 100644 --- a/client/app/scripts/components/node-details/node-details-control-button.js +++ b/client/app/scripts/components/node-details/node-details-control-button.js @@ -9,12 +9,12 @@ export default class NodeDetailsControlButton extends React.Component { } render() { - let className = `node-control-button fa ${this.props.control.control.icon}`; + let className = `node-control-button fa ${this.props.control.icon}`; if (this.props.pending) { className += ' node-control-button-pending'; } return ( - + ); } diff --git a/client/app/scripts/components/node-details/node-details-controls.js b/client/app/scripts/components/node-details/node-details-controls.js index 837863ca1..08e91cf06 100644 --- a/client/app/scripts/components/node-details/node-details-controls.js +++ b/client/app/scripts/components/node-details/node-details-controls.js @@ -21,7 +21,7 @@ export default class NodeDetailsControls extends React.Component { {this.props.controls && this.props.controls.map(control => { return ( + pending={this.props.pending} key={control.id} /> ); })} diff --git a/client/app/scripts/components/node-details/node-details-health-item.js b/client/app/scripts/components/node-details/node-details-health-item.js index 1b6f84edd..1c63437ec 100644 --- a/client/app/scripts/components/node-details/node-details-health-item.js +++ b/client/app/scripts/components/node-details/node-details-health-item.js @@ -10,8 +10,8 @@ class NodeDetailsHealthItem extends React.Component {
{formatMetric(this.props.value, this.props)}
- +
{this.props.label}
diff --git a/client/app/scripts/hoc/metric-feeder.js b/client/app/scripts/hoc/metric-feeder.js index dd3eed3fb..306d92899 100644 --- a/client/app/scripts/hoc/metric-feeder.js +++ b/client/app/scripts/hoc/metric-feeder.js @@ -18,7 +18,7 @@ const WINDOW_LENGTH = 60; * `[t1, t2, t3, ...]` will be fed to the wrapped component. * The window slides between the dates provided by the first date of the buffer * and `this.props.last` so that the following invariant is true: - * `this.state.movingFirst <= this.props.wire_metrics.first < this.state.movingLast <= this.props.wire_metrics.last`. + * `this.state.movingFirst <= this.props.first < this.state.movingLast <= this.props.last`. * * Samples have to be of type `[{date: String, value: Number}, ...]`. * This component also keeps a historic max of all samples it sees over time. @@ -60,7 +60,7 @@ export default ComposedComponent => class extends React.Component { updateBuffer(props) { // merge new samples into buffer let buffer = this.state.buffer; - const nextSamples = makeOrderedMap(props.wire_metrics.samples.map(d => [d.date, d.value])); + const nextSamples = makeOrderedMap(props.samples.map(d => [d.date, d.value])); // need to sort again after merge, some new data may have different times for old values buffer = buffer.merge(nextSamples).sortBy(sortDate); const state = {}; diff --git a/client/app/scripts/utils/web-api-utils.js b/client/app/scripts/utils/web-api-utils.js index 4e33cb906..aab8056b4 100644 --- a/client/app/scripts/utils/web-api-utils.js +++ b/client/app/scripts/utils/web-api-utils.js @@ -169,7 +169,7 @@ export function getApiDetails() { export function doControlRequest(nodeId, control) { clearTimeout(controlErrorTimer); const url = `api/control/${encodeURIComponent(control.probeId)}/` - + `${encodeURIComponent(control.nodeId)}/${control.control.id}`; + + `${encodeURIComponent(control.nodeId)}/${control.id}`; reqwest({ method: 'POST', url: url, diff --git a/render/detailed/metrics.go b/render/detailed/metrics.go index b711000ae..5de036b15 100644 --- a/render/detailed/metrics.go +++ b/render/detailed/metrics.go @@ -4,6 +4,7 @@ import ( "math" "github.com/ugorji/go/codec" + "github.com/weaveworks/scope/probe/docker" "github.com/weaveworks/scope/probe/host" "github.com/weaveworks/scope/probe/process" @@ -72,24 +73,33 @@ func (*MetricRow) UnmarshalJSON(b []byte) error { } type wiredMetricRow struct { - ID string `json:"id"` - Label string `json:"label"` - Format string `json:"format,omitempty"` - Group string `json:"group,omitempty"` - Value float64 `json:"value"` - WireMetrics report.WireMetrics `json:"wire_metrics"` + ID string `json:"id"` + Label string `json:"label"` + Format string `json:"format,omitempty"` + Group string `json:"group,omitempty"` + Value float64 `json:"value"` + Samples []report.Sample `json:"samples"` + Min float64 `json:"min"` + Max float64 `json:"max"` + First string `json:"first,omitempty"` + Last string `json:"last,omitempty"` } // CodecEncodeSelf marshals this MetricRow. It takes the basic Metric // rendering, then adds some row-specific fields. func (m *MetricRow) CodecEncodeSelf(encoder *codec.Encoder) { + in := m.Metric.ToIntermediate() encoder.Encode(wiredMetricRow{ - ID: m.ID, - Label: Label(m.ID), - Format: m.Format, - Group: m.Group, - Value: m.Value, - WireMetrics: m.Metric.ToIntermediate(), + ID: m.ID, + Label: Label(m.ID), + Format: m.Format, + Group: m.Group, + Value: m.Value, + Samples: in.Samples, + Min: in.Min, + Max: in.Max, + First: in.First, + Last: in.Last, }) } @@ -97,8 +107,14 @@ func (m *MetricRow) CodecEncodeSelf(encoder *codec.Encoder) { func (m *MetricRow) CodecDecodeSelf(decoder *codec.Decoder) { var in wiredMetricRow decoder.Decode(&in) - - metric := in.WireMetrics.FromIntermediate() + w := report.WireMetrics{ + Samples: in.Samples, + Min: in.Min, + Max: in.Max, + First: in.First, + Last: in.Last, + } + metric := w.FromIntermediate() *m = MetricRow{ ID: in.ID, Format: in.Format, diff --git a/render/detailed/node.go b/render/detailed/node.go index aed8a5909..8846f910b 100644 --- a/render/detailed/node.go +++ b/render/detailed/node.go @@ -3,6 +3,8 @@ package detailed import ( "sort" + "github.com/ugorji/go/codec" + "github.com/weaveworks/scope/probe/docker" "github.com/weaveworks/scope/probe/host" "github.com/weaveworks/scope/probe/process" @@ -24,9 +26,54 @@ type Node struct { // ControlInstance contains a control description, and all the info // needed to execute it. type ControlInstance struct { - ProbeID string `json:"probeId"` - NodeID string `json:"nodeId"` - Control report.Control `json:"control"` + ProbeID string + NodeID string + Control report.Control +} + +// MarshalJSON shouldn't be used, use CodecEncodeSelf instead +func (ControlInstance) MarshalJSON() ([]byte, error) { + panic("MarshalJSON shouldn't be used, use CodecEncodeSelf instead") +} + +// UnmarshalJSON shouldn't be used, use CodecDecodeSelf instead +func (*ControlInstance) UnmarshalJSON(b []byte) error { + panic("UnmarshalJSON shouldn't be used, use CodecDecodeSelf instead") +} + +type wiredControlInstance struct { + ProbeID string `json:"probeId"` + NodeID string `json:"nodeId"` + ID string `json:"id"` + Human string `json:"human"` + Icon string `json:"icon"` +} + +// CodecEncodeSelf marshals this MetricRow. It takes the basic Metric +// rendering, then adds some row-specific fields. +func (c *ControlInstance) CodecEncodeSelf(encoder *codec.Encoder) { + encoder.Encode(wiredControlInstance{ + ProbeID: c.ProbeID, + NodeID: c.NodeID, + ID: c.Control.ID, + Human: c.Control.Human, + Icon: c.Control.Icon, + }) +} + +// CodecDecodeSelf implements codec.Selfer +func (c *ControlInstance) CodecDecodeSelf(decoder *codec.Decoder) { + var in wiredControlInstance + decoder.Decode(&in) + *c = ControlInstance{ + ProbeID: in.ProbeID, + NodeID: in.NodeID, + Control: report.Control{ + ID: in.ID, + Human: in.Human, + Icon: in.Icon, + }, + } } // MakeNode transforms a renderable node to a detailed node. It uses