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