riemann-dash 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +9 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +52 -0
- data/README.markdown +29 -5
- data/Rakefile.rb +11 -0
- data/bin/riemann-dash +2 -2
- data/example/config.rb +17 -0
- data/lib/riemann/dash/app.rb +32 -0
- data/lib/riemann/dash/config.rb +154 -0
- data/lib/riemann/dash/controller/css.rb +1 -1
- data/lib/riemann/dash/controller/index.rb +6 -36
- data/lib/riemann/dash/public/dash.js +44 -18
- data/lib/riemann/dash/public/format.js +3 -3
- data/lib/riemann/dash/public/persistence.js +2 -2
- data/lib/riemann/dash/public/subs.js +63 -48
- data/lib/riemann/dash/public/util.js +37 -44
- data/lib/riemann/dash/public/vendor/backbone.js +1571 -0
- data/lib/riemann/dash/public/vendor/jquery/jquery-1.9.1.min.js +5 -0
- data/lib/riemann/dash/public/{jquery-ui-1.9.0.custom.min.js → vendor/jquery/jquery-ui-1.9.0.custom.min.js} +0 -0
- data/lib/riemann/dash/public/{jquery.quickfit.js → vendor/jquery/jquery.quickfit.js} +0 -0
- data/lib/riemann/dash/public/vendor/jquery/jquery.simplemodal.1.4.4.min.js +26 -0
- data/lib/riemann/dash/public/vendor/lodash.min.js +40 -0
- data/lib/riemann/dash/public/vendor/smoothie.js +376 -0
- data/lib/riemann/dash/public/{toastr.css → vendor/toastr/toastr.css} +1 -1
- data/lib/riemann/dash/public/{toastr.js → vendor/toastr/toastr.js} +0 -0
- data/lib/riemann/dash/public/views/gauge.js +8 -5
- data/lib/riemann/dash/public/views/grid.js +138 -67
- data/lib/riemann/dash/public/views/timeseries.js +230 -0
- data/lib/riemann/dash/public/views/title.js +6 -3
- data/lib/riemann/dash/version.rb +2 -2
- data/lib/riemann/dash/views/css.scss +52 -2
- data/lib/riemann/dash/views/index.erubis +38 -192
- data/lib/riemann/dash.rb +3 -97
- data/riemann-dash.gemspec +28 -0
- data/sh/c +1 -0
- data/sh/env.rb +2 -0
- data/sh/test +1 -0
- data/test/config_test.rb +114 -0
- data/test/fixtures/config/basic_config.rb +2 -0
- data/test/fixtures/config/ws_config.rb +1 -0
- data/test/fixtures/ws_config/dummy_config.json +1 -0
- data/test/fixtures/ws_config/pretty_printed_config.json +6 -0
- data/test/test_helper.rb +10 -0
- metadata +43 -18
- data/lib/riemann/dash/public/jquery-1.7.2.min.js +0 -4
- data/lib/riemann/dash/public/jquery.json-2.2.min.js +0 -31
- data/lib/riemann/dash/public/jquery.simplemodal.1.4.3.min.js +0 -26
- data/lib/riemann/dash/public/mustache.js +0 -597
- data/lib/riemann/dash/public/underscore-min.js +0 -5
@@ -6,6 +6,7 @@
|
|
6
6
|
this.query = json.query;
|
7
7
|
this.title = json.title;
|
8
8
|
this.max = json.max || "all";
|
9
|
+
this.by = json.by || "host";
|
9
10
|
this.clickFocusable = true;
|
10
11
|
|
11
12
|
// Initial display
|
@@ -18,8 +19,12 @@
|
|
18
19
|
this.el.find('h2').text(this.title);
|
19
20
|
|
20
21
|
// State
|
22
|
+
this.columns = [];
|
23
|
+
this.rows = [];
|
24
|
+
|
21
25
|
this.hosts = [];
|
22
26
|
this.services = [];
|
27
|
+
|
23
28
|
this.events = {};
|
24
29
|
if (this.max === "service" || this.max === "host") {
|
25
30
|
this.currentMax = {};
|
@@ -44,26 +49,33 @@
|
|
44
49
|
title: this.title,
|
45
50
|
query: this.query,
|
46
51
|
max: this.max,
|
52
|
+
by: this.by
|
47
53
|
});
|
48
54
|
}
|
55
|
+
|
56
|
+
var editTemplate = _.template(
|
57
|
+
"<label for='title'>Title</label>" +
|
58
|
+
"<input type='text' name='title' value='{{title}}' /><br />" +
|
59
|
+
"<label for='query'>Query</label><br />" +
|
60
|
+
"<textarea name='query' class='query'>{{query}}</textarea><br />" +
|
61
|
+
"<label for='by'>group by</label>" +
|
62
|
+
"<input type='text' name='by' value='{{by}}' /><br />" +
|
63
|
+
"<span class='desc'>'host' or 'service'</span><br />" +
|
64
|
+
"<label for='max'>Max</label>" +
|
65
|
+
"<input type='text' name='max' value='{{max}}' /><br />" +
|
66
|
+
"<span class='desc'>'all', 'host', 'service', or any number.</span>"
|
67
|
+
)
|
49
68
|
|
50
69
|
Grid.prototype.editForm = function() {
|
51
|
-
return
|
52
|
-
'<input type="text" name="title" value="{{title}}" /><br />' +
|
53
|
-
'<label for="query">Query</label><br />' +
|
54
|
-
'<textarea name="query" class="query">{{query}}</textarea><br />' +
|
55
|
-
'<label for="max">Max</label>' +
|
56
|
-
'<input type="text" name="max" value="{{max}}" /><br />' +
|
57
|
-
'<span class="desc">"all", "host", "service", or any number.</span>',
|
58
|
-
this)
|
70
|
+
return editTemplate(this);
|
59
71
|
}
|
60
72
|
|
61
73
|
// Returns all events, flat.
|
62
74
|
Grid.prototype.allEvents = function() {
|
63
75
|
var events = [];
|
64
|
-
for (
|
65
|
-
for (
|
66
|
-
events.push(this.events[
|
76
|
+
for (row in this.events) {
|
77
|
+
for (column in this.events[row]) {
|
78
|
+
events.push(this.events[row][column]);
|
67
79
|
}
|
68
80
|
}
|
69
81
|
}
|
@@ -96,9 +108,16 @@
|
|
96
108
|
event.description);
|
97
109
|
|
98
110
|
// Bar chart
|
99
|
-
if (event.metric) {
|
111
|
+
if (event.metric == 0) {
|
112
|
+
// Zero
|
113
|
+
element.find('.bar').css('width', 0);
|
114
|
+
} else if (0 < event.metric) {
|
115
|
+
// Positive
|
100
116
|
element.find('.bar').css('width',
|
101
117
|
(event.metric / this.eventMax(event) * 100) + "%");
|
118
|
+
} else {
|
119
|
+
// Nil or negative
|
120
|
+
element.find('.bar').css('width', 0);
|
102
121
|
}
|
103
122
|
}
|
104
123
|
|
@@ -106,10 +125,15 @@
|
|
106
125
|
// Render a single event if there's been no change to table structure.
|
107
126
|
Grid.prototype.partialRender = function(event) {
|
108
127
|
var table = this.el.find('table');
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
128
|
+
if (this.by === "host") {
|
129
|
+
var rowIndex = this.rows.indexOf(event.host);
|
130
|
+
var columnIndex = this.columns.indexOf(event.service);
|
131
|
+
} else {
|
132
|
+
var rowIndex = this.rows.indexOf(event.service);
|
133
|
+
var columnIndex = this.columns.indexOf(event.host)
|
134
|
+
}
|
135
|
+
var row = this.el.find('tbody tr')[rowIndex];
|
136
|
+
var td = $($(row).find('td')[columnIndex]);
|
113
137
|
|
114
138
|
this.renderElement(td, event);
|
115
139
|
}
|
@@ -122,18 +146,18 @@
|
|
122
146
|
// Header
|
123
147
|
table.append("<thead><tr><th></th></tr></thead>");
|
124
148
|
var row = table.find("thead tr");
|
125
|
-
this.
|
149
|
+
this.columns.forEach(function(name) {
|
126
150
|
var element = $('<th>');
|
127
|
-
element.text(
|
151
|
+
element.text(name);
|
128
152
|
row.append(element);
|
129
153
|
});
|
130
154
|
|
131
|
-
this.
|
155
|
+
this.rows.forEach(function(name) {
|
132
156
|
row = $("<tr><th></th>");
|
133
157
|
table.append(row);
|
134
|
-
row.find('th').text(
|
135
|
-
this.
|
136
|
-
var event = this.events[
|
158
|
+
row.find('th').text(name);
|
159
|
+
this.columns.forEach(function(subName) {
|
160
|
+
var event = this.events[name][subName];
|
137
161
|
var element = $('<td><span class="bar"><span class="metric"/></span></td>');
|
138
162
|
this.renderElement(element, event);
|
139
163
|
row.append(element);
|
@@ -151,30 +175,53 @@
|
|
151
175
|
}
|
152
176
|
|
153
177
|
var e;
|
178
|
+
|
154
179
|
if (this.max === "all") {
|
155
180
|
this.currentMax = -1/0;
|
156
|
-
for (
|
157
|
-
for (
|
158
|
-
e = this.events[
|
181
|
+
for (name in this.events) {
|
182
|
+
for (subName in this.events[name]) {
|
183
|
+
e = this.events[name][subName];
|
159
184
|
this.currentMax = Math.max(e.metric, this.currentMax || -1/0);
|
160
185
|
}
|
161
186
|
}
|
162
|
-
} else if (this.
|
163
|
-
this.
|
164
|
-
|
165
|
-
for (
|
166
|
-
|
167
|
-
|
168
|
-
|
187
|
+
} else if (this.by == "host") {
|
188
|
+
if (this.max == "host") {
|
189
|
+
this.currentMax = {};
|
190
|
+
for (host in this.events) {
|
191
|
+
for (service in this.events[host]) {
|
192
|
+
e = this.events[host][service];
|
193
|
+
this.currentMax[e.host] =
|
194
|
+
Math.max(e.metric, this.currentMax[e.host] || -1/0)
|
195
|
+
}
|
196
|
+
}
|
197
|
+
} else if (this.max === "service") {
|
198
|
+
this.currentMax = {};
|
199
|
+
for (host in this.events) {
|
200
|
+
for (service in this.events[host]) {
|
201
|
+
e = this.events[host][service];
|
202
|
+
this.currentMax[e.service] =
|
203
|
+
Math.max(e.metric, this.currentMax[e.service] || -1/0);
|
204
|
+
}
|
169
205
|
}
|
170
206
|
}
|
171
|
-
} else if (this.
|
172
|
-
this.
|
173
|
-
|
174
|
-
for (service in this.events
|
175
|
-
|
176
|
-
|
177
|
-
|
207
|
+
} else if (this.by === "service") {
|
208
|
+
if (this.max == "host") {
|
209
|
+
this.currentMax = {};
|
210
|
+
for (service in this.events) {
|
211
|
+
for (host in this.events[service]) {
|
212
|
+
e = this.events[service][host];
|
213
|
+
this.currentMax[e.host] =
|
214
|
+
Math.max(e.metric, this.currentMax[e.host] || -1/0)
|
215
|
+
}
|
216
|
+
}
|
217
|
+
} else if (this.max === "service") {
|
218
|
+
this.currentMax = {};
|
219
|
+
for (service in this.events) {
|
220
|
+
for (host in this.events[service]) {
|
221
|
+
e = this.events[service][host];
|
222
|
+
this.currentMax[e.service] =
|
223
|
+
Math.max(e.metric, this.currentMax[e.service] || -1/0);
|
224
|
+
}
|
178
225
|
}
|
179
226
|
}
|
180
227
|
} else {
|
@@ -188,34 +235,58 @@
|
|
188
235
|
// Stores an event in the internal state tables. Returns true if we
|
189
236
|
// haven't seen this host/service before.
|
190
237
|
Grid.prototype.saveEvent = function(e) {
|
191
|
-
|
192
|
-
|
193
|
-
this.
|
194
|
-
|
195
|
-
|
238
|
+
if (this.by === "host") {
|
239
|
+
// Host list
|
240
|
+
if (this.rows.indexOf(e.host) === -1) {
|
241
|
+
this.rows.push(e.host);
|
242
|
+
this.rows = _.uniq(this.rows.sort(), true);
|
243
|
+
}
|
196
244
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
245
|
+
// Services list
|
246
|
+
if (this.columns.indexOf(e.service) === -1) {
|
247
|
+
this.columns.push(e.service);
|
248
|
+
this.columns = _.uniq(this.columns.sort(), true);
|
249
|
+
}
|
202
250
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
251
|
+
// Events map
|
252
|
+
if (this.events[e.host] === undefined) {
|
253
|
+
// New host
|
254
|
+
this.events[e.host] = {};
|
255
|
+
}
|
256
|
+
var newEvent = (this.events[e.host][e.service] === undefined);
|
257
|
+
|
258
|
+
// Store event
|
259
|
+
this.events[e.host][e.service] = e;
|
260
|
+
|
261
|
+
return newEvent;
|
262
|
+
|
263
|
+
} else if (this.by === "service") {
|
264
|
+
// Services list
|
265
|
+
if (this.rows.indexOf(e.service) === -1) {
|
266
|
+
this.rows.push(e.service);
|
267
|
+
this.rows = _.uniq(this.rows.sort(), true);
|
268
|
+
}
|
214
269
|
|
215
|
-
|
216
|
-
|
270
|
+
// Host list
|
271
|
+
if (this.columns.indexOf(e.host) === -1) {
|
272
|
+
this.columns.push(e.host);
|
273
|
+
this.columns = _.uniq(this.columns.sort(), true);
|
274
|
+
}
|
275
|
+
|
276
|
+
// Events map
|
277
|
+
if (this.events[e.service] === undefined) {
|
278
|
+
// New host
|
279
|
+
this.events[e.service] = {};
|
280
|
+
}
|
281
|
+
var newEvent = (this.events[e.service][e.host] === undefined);
|
282
|
+
|
283
|
+
// Store event
|
284
|
+
this.events[e.service][e.host] = e;
|
285
|
+
|
286
|
+
return newEvent;
|
287
|
+
|
288
|
+
}
|
217
289
|
|
218
|
-
return newEvent;
|
219
290
|
}
|
220
291
|
|
221
292
|
// Add an event.
|
@@ -263,10 +334,10 @@
|
|
263
334
|
}
|
264
335
|
|
265
336
|
Grid.prototype.reflow = function() {
|
266
|
-
//
|
267
|
-
|
268
|
-
|
269
|
-
|
337
|
+
// this.el.find('table').height(
|
338
|
+
// this.height() -
|
339
|
+
// this.el.find('h2').height()
|
340
|
+
// );
|
270
341
|
}
|
271
342
|
|
272
343
|
Grid.prototype.delete = function() {
|
@@ -0,0 +1,230 @@
|
|
1
|
+
(function() {
|
2
|
+
var fitopts = {min: 6, max: 1000};
|
3
|
+
|
4
|
+
var nameFor = function(event) {
|
5
|
+
return event.host ? event.host + ":" + event.service : event.service
|
6
|
+
return event.host + ":" + event.service;
|
7
|
+
};
|
8
|
+
|
9
|
+
var hextoRGB = function(hex) { // converts hex string to rgb triple
|
10
|
+
// only works for full 6 char hex, not shorthand
|
11
|
+
if (hex[0]=="#") hex=hex.substr(1);
|
12
|
+
var hexp = "([a-f0-9]{2})";
|
13
|
+
var colorGroups = RegExp('^'+hexp+hexp+hexp+'$', 'i').exec(hex).slice(1);
|
14
|
+
return _.map(colorGroups, function(color) { return parseInt(color, 16) });
|
15
|
+
}
|
16
|
+
|
17
|
+
var rateLimit = 500; // ms
|
18
|
+
|
19
|
+
var TimeSeriesView = function(json) {
|
20
|
+
|
21
|
+
var self = this;
|
22
|
+
|
23
|
+
self.smoothie = new SmoothieChart({
|
24
|
+
grid: {strokeStyle:'#ccc', fillStyle:'rgba(255, 255, 255, 0.0)', lineWidth: 1, millisPerLine: 1000},
|
25
|
+
labels: { fillStyle:'#262626' }
|
26
|
+
});
|
27
|
+
|
28
|
+
// colors
|
29
|
+
var colorTemplate = _.template("rgba({{red}},{{green}},{{blue}},{{alpha}})");
|
30
|
+
|
31
|
+
var colorPallette = function() {
|
32
|
+
// should be customizable in future...
|
33
|
+
// default color pallette borrowed from http://code.shutterstock.com/rickshaw/examples/colors.html
|
34
|
+
// Array.prototype.reduce.call(svg.childNodes, function(accum, path) { accum.push(path.getAttribute("fill")); return accum; }, [])
|
35
|
+
var DEFAULT = ["#57306f", "#514c76", "#646583", "#738394",
|
36
|
+
"#6b9c7d", "#84b665", "#a7ca50", "#bfe746",
|
37
|
+
"#e2f528", "#fff726", "#ecdd00", "#d4b11d",
|
38
|
+
"#de8800", "#de4800", "#c91515", "#9a0000",
|
39
|
+
"#7b0429", "#580839", "#31082b"];
|
40
|
+
return DEFAULT;
|
41
|
+
};
|
42
|
+
this.pallette = colorPallette();
|
43
|
+
|
44
|
+
var takeColor = function() {
|
45
|
+
// pops a color off the pallette stack, or regenerates the
|
46
|
+
// stack if we're out of colors
|
47
|
+
var color = self.pallette.shift();
|
48
|
+
if (color) {
|
49
|
+
return color;
|
50
|
+
} else {
|
51
|
+
self.pallette = colorPallette();
|
52
|
+
return self.pallette.shift();
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
// map event names to colors
|
57
|
+
var colorMap = {};
|
58
|
+
|
59
|
+
var colorFromString = function(s) {
|
60
|
+
// caches a color in the color table
|
61
|
+
var color = colorMap[s];
|
62
|
+
if (color) return color;
|
63
|
+
color = colorMap[s] = takeColor()
|
64
|
+
return color;
|
65
|
+
}
|
66
|
+
|
67
|
+
var RGBfromString = function(s) {
|
68
|
+
// returns an RGB triple from a string
|
69
|
+
return hextoRGB(colorFromString(s));
|
70
|
+
};
|
71
|
+
|
72
|
+
var rgbaFromTriple = function(rgb, alpha) {
|
73
|
+
return colorTemplate({
|
74
|
+
red: rgb[0],
|
75
|
+
green: rgb[1],
|
76
|
+
blue: rgb[2],
|
77
|
+
alpha: alpha
|
78
|
+
});
|
79
|
+
}
|
80
|
+
|
81
|
+
// smoothiecharts timeseries
|
82
|
+
var seriesCollection = {};
|
83
|
+
|
84
|
+
// throttle appends to graph
|
85
|
+
var appendEvent = function(series, event) {
|
86
|
+
series.append(event);
|
87
|
+
return series.append(new Date(event.time).getTime(), format.float(event.metric));
|
88
|
+
};
|
89
|
+
|
90
|
+
var createTimeSeries = function(name, event) {
|
91
|
+
var seriesColor = RGBfromString(name),
|
92
|
+
series = new TimeSeries(),
|
93
|
+
color = rgbaFromTriple(seriesColor, 1),
|
94
|
+
seriesOpts = {lineWidth: self.lineWidth || 2,
|
95
|
+
strokeStyle: color,
|
96
|
+
fillStyle: rgbaFromTriple(seriesColor, self.opacity || 0)};
|
97
|
+
|
98
|
+
series.appendEvent = _.throttle(function(event) {
|
99
|
+
series.append(new Date(event.time).getTime(), format.float(event.metric));
|
100
|
+
}, rateLimit);;
|
101
|
+
|
102
|
+
self.smoothie.addTimeSeries(series, seriesOpts);
|
103
|
+
return series;
|
104
|
+
};
|
105
|
+
|
106
|
+
// stream data into series
|
107
|
+
var intoSeries = function(event) {
|
108
|
+
var seriesName = nameFor(event)
|
109
|
+
var cachedSeries = seriesCollection[seriesName];
|
110
|
+
|
111
|
+
if (cachedSeries) {
|
112
|
+
cachedSeries.appendEvent(event);
|
113
|
+
} else {
|
114
|
+
var newSeries = seriesCollection[seriesName] = createTimeSeries(seriesName, event);
|
115
|
+
newSeries.appendEvent(event);
|
116
|
+
};
|
117
|
+
};
|
118
|
+
|
119
|
+
var legendCollection = {};
|
120
|
+
|
121
|
+
var updateLegend = function(event) {
|
122
|
+
var eventName = nameFor(event),
|
123
|
+
cachedEl = legendCollection[eventName];
|
124
|
+
|
125
|
+
if (cachedEl) {
|
126
|
+
cachedEl.text(eventName + ": " + format.float(event.metric))
|
127
|
+
} else {
|
128
|
+
var $el = $("<div></div>");
|
129
|
+
var color = rgbaFromTriple(RGBfromString(eventName), 0.7);
|
130
|
+
$el.addClass('event-legend').css({"background-color": color});
|
131
|
+
$el.text = _.throttle($el.text, rateLimit);
|
132
|
+
setTimeout(function() {
|
133
|
+
if ($el) {
|
134
|
+
$el.text(eventName + ": " + format.float(event.metric));
|
135
|
+
}
|
136
|
+
}, +self.delay || 0);
|
137
|
+
legendCollection[eventName] = $el;
|
138
|
+
self.$legend.append($el)
|
139
|
+
}
|
140
|
+
|
141
|
+
}
|
142
|
+
|
143
|
+
view.View.call(this, json);
|
144
|
+
this.query = json.query;
|
145
|
+
this.title = json.title;
|
146
|
+
this.delay = json.delay;
|
147
|
+
this.opacity = json.opacity;
|
148
|
+
this.lineWidth = json.lineWidth;
|
149
|
+
|
150
|
+
this.clickFocusable = true;
|
151
|
+
this.el.append(
|
152
|
+
'<div class="time-series-container">' +
|
153
|
+
'<div class="legend"></div>' +
|
154
|
+
'<div class="title">' + this.title +
|
155
|
+
'</div>' +
|
156
|
+
'<canvas class="timeseries"></canvas>' +
|
157
|
+
'</div>'
|
158
|
+
);
|
159
|
+
|
160
|
+
this.$canvas = this.el.find(".timeseries");
|
161
|
+
this.$legend = this.el.find(".legend");
|
162
|
+
this.$titlecontainer = this.el.find("div.title");
|
163
|
+
|
164
|
+
this.$title = this.$titlecontainer.find("h2");
|
165
|
+
this.canvas = this.$canvas.get(0);
|
166
|
+
|
167
|
+
|
168
|
+
this.$legend = this.el.find(".legend");
|
169
|
+
|
170
|
+
this.reflow();
|
171
|
+
|
172
|
+
this.smoothie.streamTo(this.canvas, this.delay);
|
173
|
+
|
174
|
+
if (this.query) {
|
175
|
+
this.sub = subs.subscribe(this.query, function(event) {
|
176
|
+
updateLegend(event)
|
177
|
+
intoSeries(event)
|
178
|
+
});
|
179
|
+
}
|
180
|
+
}
|
181
|
+
|
182
|
+
view.inherit(view.View, TimeSeriesView);
|
183
|
+
view.TimeSeries = TimeSeriesView;
|
184
|
+
view.types.TimeSeries = TimeSeriesView;
|
185
|
+
|
186
|
+
TimeSeriesView.prototype.json = function() {
|
187
|
+
return $.extend(view.View.prototype.json.call(this), {
|
188
|
+
type: 'TimeSeries',
|
189
|
+
title: this.title,
|
190
|
+
delay: this.delay,
|
191
|
+
query: this.query,
|
192
|
+
opacity: this.opacity,
|
193
|
+
lineWidth: this.lineWidth,
|
194
|
+
});
|
195
|
+
}
|
196
|
+
|
197
|
+
var editTemplate = _.template(
|
198
|
+
'<label for="title">title</label>' +
|
199
|
+
'<input type="text" name="title" value="{{title}}" /><br />' +
|
200
|
+
'<label for="query">query</label>' +
|
201
|
+
'<textarea type="text" name="query">{{ query }}</textarea><br />' +
|
202
|
+
'<label for="lineWidth">line width</label>' +
|
203
|
+
'<input type="text" name="lineWidth" value="{{lineWidth}}" /><br />' +
|
204
|
+
'<label for="opacity">fill opacity</label>' +
|
205
|
+
'<input type="text" name="opacity" value="{{opacity}}" /><br />' +
|
206
|
+
'<label for="delay">delay (smoother animation)</label>' +
|
207
|
+
'<input type="text" name="delay" value="{{delay}}" />'
|
208
|
+
)
|
209
|
+
|
210
|
+
TimeSeriesView.prototype.editForm = function() {
|
211
|
+
return editTemplate(this);
|
212
|
+
}
|
213
|
+
|
214
|
+
TimeSeriesView.prototype.reflow = function() {
|
215
|
+
// Size metric
|
216
|
+
var width = this.el.width();
|
217
|
+
var height = this.el.height();
|
218
|
+
this.$canvas.attr("width", width - 10);
|
219
|
+
this.$canvas.attr("height", height - 10);
|
220
|
+
|
221
|
+
}
|
222
|
+
|
223
|
+
TimeSeriesView.prototype.delete = function() {
|
224
|
+
if (this.sub) {
|
225
|
+
subs.unsubscribe(this.sub);
|
226
|
+
}
|
227
|
+
view.View.prototype.delete.call(this);
|
228
|
+
}
|
229
|
+
})();
|
230
|
+
|
@@ -23,10 +23,13 @@
|
|
23
23
|
});
|
24
24
|
}
|
25
25
|
|
26
|
+
var editTemplate = _.template(
|
27
|
+
'<label for="title">Title</label>' +
|
28
|
+
'<input type="title" name="title" value="{{title}}" />'
|
29
|
+
);
|
30
|
+
|
26
31
|
Title.prototype.editForm = function() {
|
27
|
-
return
|
28
|
-
'<input type="title" name="title" value="{{title}}" />',
|
29
|
-
this);
|
32
|
+
return editTemplate(this);
|
30
33
|
}
|
31
34
|
|
32
35
|
Title.prototype.reflow = function() {
|
data/lib/riemann/dash/version.rb
CHANGED
@@ -14,6 +14,13 @@ $grey: #888;
|
|
14
14
|
$green: #06FA23;
|
15
15
|
$yellow: #FEF206;
|
16
16
|
|
17
|
+
@mixin vendor-prefix($name, $argument) {
|
18
|
+
#{$name}: $argument;
|
19
|
+
-webkit-#{$name}: $argument;
|
20
|
+
-ms-#{$name}: $argument;
|
21
|
+
-moz-#{$name}: $argument;
|
22
|
+
}
|
23
|
+
|
17
24
|
html {
|
18
25
|
height: 100%;
|
19
26
|
margin: 0;
|
@@ -153,7 +160,11 @@ html,table {
|
|
153
160
|
border-radius: 3px;
|
154
161
|
}
|
155
162
|
|
156
|
-
.state
|
163
|
+
.state {
|
164
|
+
@include vendor-prefix(transition, all 0.3s linear);
|
165
|
+
}
|
166
|
+
|
167
|
+
.state.ok, .state.okay, .bar.ok, .bar.okay {
|
157
168
|
background: $green;
|
158
169
|
color: #000;
|
159
170
|
}
|
@@ -161,7 +172,7 @@ html,table {
|
|
161
172
|
background: $amber;
|
162
173
|
color: #000;
|
163
174
|
}
|
164
|
-
.state.critical, .bar.critical {
|
175
|
+
.state.critical, .state.failure, .bar.critical, .bar.failure {
|
165
176
|
background: $orange;
|
166
177
|
color: #000;
|
167
178
|
}
|
@@ -380,3 +391,42 @@ h2 {
|
|
380
391
|
width: 1px;
|
381
392
|
}
|
382
393
|
}
|
394
|
+
|
395
|
+
.time-series-container {
|
396
|
+
.title {
|
397
|
+
font-weight: 700;
|
398
|
+
font-size: 1.5em;
|
399
|
+
background-color: hsla(0, 0%, 100%, 0.8);
|
400
|
+
z-index: 10;
|
401
|
+
position: absolute;
|
402
|
+
bottom: -5px;
|
403
|
+
right: 10px;
|
404
|
+
padding: 2px;
|
405
|
+
display: block;
|
406
|
+
}
|
407
|
+
.legend {
|
408
|
+
height: 100%;
|
409
|
+
font-size: 16px;
|
410
|
+
text-shadow: hsl(0, 0%, 95%) 0px 0px 1px;
|
411
|
+
color: hsl(0, 0%, 5%);
|
412
|
+
position: absolute;
|
413
|
+
bottom: 0px;
|
414
|
+
display: -webkit-flex;
|
415
|
+
display: -moz-flex;
|
416
|
+
display: -ms-flex;
|
417
|
+
display: flex;
|
418
|
+
@include vendor-prefix(flex-flow, column wrap);
|
419
|
+
@include vendor-prefix(align-content, flex-start);
|
420
|
+
@include vendor-prefix(justify-content, flex-start);
|
421
|
+
@include vendor-prefix(align-items, stretch);
|
422
|
+
}
|
423
|
+
.event-legend {
|
424
|
+
padding: 4px;
|
425
|
+
@include vendor-prefix(flex, 1 1 auto);
|
426
|
+
@include vendor-prefix(transition, all 0.3s ease-out);
|
427
|
+
}
|
428
|
+
.event-legend:hover {
|
429
|
+
background-color: hsla(0, 0%, 100%, .8) !important;
|
430
|
+
}
|
431
|
+
|
432
|
+
}
|