visage-app 1.0.0 → 2.0.0
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 +10 -0
- data/CHANGELOG.md +12 -0
- data/Gemfile +1 -15
- data/Gemfile.lock +44 -42
- data/README.md +123 -49
- data/Rakefile +16 -26
- data/bin/visage-app +17 -4
- data/features/cli.feature +10 -3
- data/features/json.feature +37 -0
- data/features/step_definitions/{visage_steps.rb → cli_steps.rb} +1 -1
- data/features/step_definitions/json_steps.rb +50 -8
- data/features/step_definitions/site_steps.rb +1 -1
- data/features/support/config/default/profiles.yaml +335 -0
- data/features/{data → support}/config/with_no_profiles/.stub +0 -0
- data/features/support/config/with_no_profiles/profiles.yaml +0 -0
- data/features/support/config/with_old_profile_yaml/profiles.yaml +116 -0
- data/features/support/env.rb +2 -3
- data/lib/visage-app.rb +35 -25
- data/lib/visage-app/collectd/json.rb +115 -118
- data/lib/visage-app/collectd/rrds.rb +25 -19
- data/lib/visage-app/helpers.rb +17 -0
- data/lib/visage-app/profile.rb +18 -25
- data/lib/visage-app/public/images/caution.png +0 -0
- data/lib/visage-app/public/images/ok.png +0 -0
- data/lib/visage-app/public/images/questions.png +0 -0
- data/lib/visage-app/public/javascripts/builder.js +607 -0
- data/lib/visage-app/public/javascripts/graph.js +179 -142
- data/lib/visage-app/public/javascripts/message.js +520 -0
- data/lib/visage-app/public/javascripts/mootools-core-1.4.0-full-compat.js +6285 -0
- data/lib/visage-app/public/javascripts/mootools-more-1.4.0.1.js +6399 -0
- data/lib/visage-app/public/stylesheets/message.css +61 -0
- data/lib/visage-app/public/stylesheets/screen.css +149 -38
- data/lib/visage-app/version.rb +5 -0
- data/lib/visage-app/views/builder.haml +38 -49
- data/lib/visage-app/views/builder_form.haml +14 -0
- data/lib/visage-app/views/layout.haml +5 -2
- data/lib/visage-app/views/profile.haml +44 -25
- data/visage-app.gemspec +29 -132
- metadata +93 -150
- data/VERSION +0 -1
- data/features/builder.feature +0 -16
- data/lib/visage-app/collectd/profile.rb +0 -36
@@ -0,0 +1,61 @@
|
|
1
|
+
@charset "utf-8";
|
2
|
+
/* CSS Document */
|
3
|
+
|
4
|
+
/* Message Boxes */
|
5
|
+
.msgBox{
|
6
|
+
font-family:Arial, Helvetica, sans-serif;
|
7
|
+
opacity: 0;
|
8
|
+
position:absolute;
|
9
|
+
top:-1000px;
|
10
|
+
left:0px;
|
11
|
+
max-width: 250px;
|
12
|
+
min-width: 150px;
|
13
|
+
color:#aaa;
|
14
|
+
background: rgb(0, 0, 0); /* compatibility fallback */
|
15
|
+
background: rgba(0, 0, 0, 0.8);
|
16
|
+
padding: 10px;
|
17
|
+
border-radius: 15px;
|
18
|
+
box-shadow: 2px 2px 6px #666;
|
19
|
+
-moz-border-radius: 15px;
|
20
|
+
-webkit-border-radius: 15px;
|
21
|
+
-moz-box-shadow: 2px 2px 6px #666;
|
22
|
+
-webkit-box-shadow: 2px 2px 5px #666;
|
23
|
+
z-index:-1;
|
24
|
+
}
|
25
|
+
|
26
|
+
.msgBoxImage{
|
27
|
+
width: 40px;
|
28
|
+
height: 40px;
|
29
|
+
}
|
30
|
+
|
31
|
+
.msgBoxIcon{
|
32
|
+
float:left;
|
33
|
+
width: 40px;
|
34
|
+
height: 40px;
|
35
|
+
padding-right: 7px;
|
36
|
+
}
|
37
|
+
|
38
|
+
.msgBoxTitle{
|
39
|
+
float:left;
|
40
|
+
color: #FFFFFF;
|
41
|
+
}
|
42
|
+
|
43
|
+
.msgBoxContent{
|
44
|
+
float:left;
|
45
|
+
max-width: 80%;
|
46
|
+
font-size:12px;
|
47
|
+
}
|
48
|
+
|
49
|
+
.msgBoxMessage{ float:left;}
|
50
|
+
.msgBoxLink{ color:#6699CC;}
|
51
|
+
.msgBoxLink:hover{ color:#FF9900;}
|
52
|
+
|
53
|
+
.msgEditable{
|
54
|
+
font-family:Arial, Helvetica, sans-serif;
|
55
|
+
font-size:12px;
|
56
|
+
width:250px;
|
57
|
+
background: rgb(0, 0, 0); /* compatibility fallback */
|
58
|
+
background: rgba(255, 255, 255, 0.1);
|
59
|
+
border:#000;
|
60
|
+
color:#FFF;
|
61
|
+
}
|
@@ -12,6 +12,10 @@ a {
|
|
12
12
|
text-decoration: none;
|
13
13
|
}
|
14
14
|
|
15
|
+
input:focus {
|
16
|
+
outline: none;
|
17
|
+
}
|
18
|
+
|
15
19
|
/* styles */
|
16
20
|
|
17
21
|
a { color: #3465a4; padding: 2px 0px; }
|
@@ -124,10 +128,9 @@ background-image: -moz-linear-gradient(
|
|
124
128
|
);
|
125
129
|
}
|
126
130
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
}
|
131
|
+
/*
|
132
|
+
* BUILDER
|
133
|
+
*/
|
131
134
|
|
132
135
|
div.builder {
|
133
136
|
float: left;
|
@@ -145,25 +148,49 @@ div.builder input.text {
|
|
145
148
|
-webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.25);
|
146
149
|
}
|
147
150
|
|
148
|
-
div.builder
|
149
|
-
border: 1px solid #
|
151
|
+
div.builder div.tokenWrapper {
|
152
|
+
border: 1px solid #bbb;
|
153
|
+
font-size: 16px;
|
154
|
+
padding: 4px;
|
155
|
+
padding-top: 0;
|
156
|
+
width: 350px;
|
157
|
+
height: 20px;
|
158
|
+
-moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
|
159
|
+
-webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.25);
|
150
160
|
}
|
151
161
|
|
152
|
-
div.builder
|
153
|
-
|
162
|
+
div.builder div.tokenWrapper div.token {
|
163
|
+
float: left;
|
164
|
+
margin: 2px 4px 2px 0px;
|
165
|
+
font-family: Lucida Grande, sans-serif;
|
166
|
+
font-size: 16px;
|
154
167
|
}
|
155
168
|
|
156
|
-
div.builder
|
157
|
-
|
169
|
+
div.builder div.tokenWrapper div.token.finalized {
|
170
|
+
padding: 0 2px;
|
171
|
+
background-color: #D1E5FF;
|
172
|
+
color: black;
|
173
|
+
border: 1px solid #2F5A92;
|
174
|
+
font-size: 14px;
|
158
175
|
}
|
159
176
|
|
160
|
-
div.builder
|
161
|
-
|
177
|
+
div.builder div.tokenWrapper div.token.finalized.selected {
|
178
|
+
background-color: #2F5A92;
|
179
|
+
color: white;
|
162
180
|
}
|
163
181
|
|
164
|
-
div.builder
|
165
|
-
|
166
|
-
|
182
|
+
div.builder div.tokenWrapper div.token input.token {
|
183
|
+
border: 0;
|
184
|
+
font-size: 16px;
|
185
|
+
width: 80px;
|
186
|
+
}
|
187
|
+
|
188
|
+
div.builder input.text:focus {
|
189
|
+
border: 1px solid #666;
|
190
|
+
}
|
191
|
+
|
192
|
+
div.builder img.icon {
|
193
|
+
float: right;
|
167
194
|
}
|
168
195
|
|
169
196
|
div.builder h5 {
|
@@ -171,43 +198,48 @@ div.builder h5 {
|
|
171
198
|
margin-left: 8px;
|
172
199
|
}
|
173
200
|
|
174
|
-
div.builder ul.
|
175
|
-
|
201
|
+
div.builder ul.results {
|
202
|
+
font-family: Lucida Grande, sans-serif;
|
203
|
+
font-size: 16px;
|
204
|
+
position: absolute;
|
205
|
+
z-index: 10;
|
176
206
|
}
|
177
207
|
|
178
|
-
div.builder ul.
|
179
|
-
|
208
|
+
div.builder ul.results li {
|
209
|
+
list-style-type: none;
|
210
|
+
padding: 4px 5px;
|
211
|
+
border-left: 1px #BBBBBB solid;
|
212
|
+
border-right: 1px #BBBBBB solid;
|
213
|
+
border-bottom: 1px #BBBBBB solid;
|
214
|
+
background-color: white;
|
215
|
+
width: 348px;
|
180
216
|
}
|
181
217
|
|
182
|
-
div.builder li
|
183
|
-
|
218
|
+
div.builder ul.results li.active {
|
219
|
+
background-color: #4C94F0;
|
220
|
+
color: white;
|
184
221
|
}
|
185
222
|
|
186
|
-
div.builder li
|
187
|
-
|
223
|
+
div.builder ul.results li.all {
|
224
|
+
color: gray;
|
188
225
|
}
|
189
226
|
|
190
|
-
div.builder li
|
191
|
-
|
227
|
+
div.builder ul.results li.all.active {
|
228
|
+
background-color: #A0BD29;
|
229
|
+
color: white;
|
192
230
|
}
|
193
231
|
|
194
|
-
div.builder li td.meta {
|
195
|
-
width: 80px;
|
196
|
-
text-align: right;
|
197
|
-
padding-right: 8px;
|
198
|
-
}
|
199
232
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
margin-top: 8px;
|
205
|
-
}
|
233
|
+
|
234
|
+
/*
|
235
|
+
* GRAPHS + PROFILE VIEWER
|
236
|
+
*/
|
206
237
|
|
207
238
|
div#graphs {
|
239
|
+
clear: both;
|
208
240
|
padding: 0 2em;
|
209
|
-
border-top: 1px dashed #babdb6;
|
210
|
-
margin
|
241
|
+
/* border-top: 1px dashed #babdb6; */
|
242
|
+
margin: 16px 0;
|
211
243
|
}
|
212
244
|
|
213
245
|
div.graph {
|
@@ -235,6 +267,21 @@ h1 span.project-name {
|
|
235
267
|
color: white;
|
236
268
|
}
|
237
269
|
|
270
|
+
a#edit {
|
271
|
+
float: right;
|
272
|
+
display: block;
|
273
|
+
}
|
274
|
+
|
275
|
+
div#chart-builder-slider {
|
276
|
+
clear: both;
|
277
|
+
overflow-x: hidden;
|
278
|
+
overflow-y: hidden;
|
279
|
+
}
|
280
|
+
|
281
|
+
div#profile {
|
282
|
+
clear: both;
|
283
|
+
}
|
284
|
+
|
238
285
|
h2#profile_name {
|
239
286
|
margin: 36px 0;
|
240
287
|
}
|
@@ -331,3 +378,67 @@ div#shortcuts table td, div#shortcuts table th {
|
|
331
378
|
div#shortcuts table th {
|
332
379
|
text-align: left;
|
333
380
|
}
|
381
|
+
|
382
|
+
|
383
|
+
.button {
|
384
|
+
-moz-border-radius: 5px;
|
385
|
+
-webkit-border-radius: 5px;
|
386
|
+
-moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
|
387
|
+
-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
|
388
|
+
background-color: #637020;
|
389
|
+
background-repeat: repeat-x;
|
390
|
+
background: -moz-linear-gradient(100% 100% 90deg, #244671, #4C94F0);
|
391
|
+
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#4C94F0), to(#244671));
|
392
|
+
border: medium none;
|
393
|
+
color: white;
|
394
|
+
cursor: pointer;
|
395
|
+
font-family: Lucida Grande,sans-serif;
|
396
|
+
font-weight: bold;
|
397
|
+
padding: 4px;
|
398
|
+
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.75);
|
399
|
+
}
|
400
|
+
|
401
|
+
.button:hover, .button:focus {
|
402
|
+
text-shadow: 0 2px 1px rgba(255,255,255,0.1);
|
403
|
+
background: -webkit-gradient(linear, left top, left bottom, from(#529EFF), to(#274C7A));
|
404
|
+
background: -moz-linear-gradient(top, #529EFF, #274C7A);
|
405
|
+
outline: none;
|
406
|
+
}
|
407
|
+
|
408
|
+
input#show {
|
409
|
+
float: right;
|
410
|
+
font-size: 80%;
|
411
|
+
padding: 4px 8px;
|
412
|
+
font-family: 'Bitstream Vera Sans', 'Helvetica Neue', sans-serif;
|
413
|
+
margin-bottom: 16px;
|
414
|
+
margin-left: 16px;
|
415
|
+
}
|
416
|
+
|
417
|
+
input#save {
|
418
|
+
float: right;
|
419
|
+
font-size: 80%;
|
420
|
+
padding: 4px 8px;
|
421
|
+
font-family: 'Bitstream Vera Sans', 'Helvetica Neue', sans-serif;
|
422
|
+
margin-bottom: 16px;
|
423
|
+
margin-left: 16px;
|
424
|
+
}
|
425
|
+
|
426
|
+
button::-moz-focus-inner,
|
427
|
+
input[type="reset"]::-moz-focus-inner,
|
428
|
+
input[type="button"]::-moz-focus-inner,
|
429
|
+
input[type="submit"]::-moz-focus-inner,
|
430
|
+
input[type="file"] > input[type="button"]::-moz-focus-inner {
|
431
|
+
border: none;
|
432
|
+
}
|
433
|
+
|
434
|
+
input#profile_name {
|
435
|
+
border: 1px solid #bbb;
|
436
|
+
font-size: 16px;
|
437
|
+
padding: 4px;
|
438
|
+
padding-top: 0;
|
439
|
+
width: 200px;
|
440
|
+
height: 20px;
|
441
|
+
-moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
|
442
|
+
-webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.25);
|
443
|
+
float: right;
|
444
|
+
}
|
@@ -1,52 +1,41 @@
|
|
1
1
|
- page_title "Profile builder"
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
%img{:src => link_to("/images/metrics.png"), :class => "icon metrics"}
|
41
|
-
%span{:class => "glob example"} e.g. “cpu*/*”, “disk*/*ops, disk*/*time”
|
42
|
-
|
43
|
-
%ul.selected
|
44
|
-
- @profile.selected_metrics.each do |name|
|
45
|
-
%li= name
|
46
|
-
|
47
|
-
%h5 Available
|
48
|
-
%ul.available
|
49
|
-
- @profile.metrics.each do |name|
|
50
|
-
%li= name
|
2
|
+
- require_js "builder"
|
3
|
+
:javascript
|
4
|
+
window.addEvent('domready', function() {
|
5
|
+
new ChartBuilder('chart-builder');
|
6
|
+
});
|
7
|
+
|
8
|
+
%div#chart-builder
|
9
|
+
%div#hosts.builder
|
10
|
+
%h2 Hosts
|
11
|
+
%img{:src => link_to("/images/hosts.png"), :class => "icon hosts"}
|
12
|
+
%div.search
|
13
|
+
|
14
|
+
%div#metrics.builder
|
15
|
+
%h2 Metrics
|
16
|
+
%img{:src => link_to("/images/metrics.png"), :class => "icon metrics"}
|
17
|
+
%div.search
|
18
|
+
|
19
|
+
%input#show{:value => "Show graphs", :type => "button", :class => "button"}
|
20
|
+
|
21
|
+
%div{:style => "text-align: left; margin-left: 24px;"}
|
22
|
+
%strong{:style => "font-family: sans-serif; font-size: 12px;"}
|
23
|
+
Global Time Period:
|
24
|
+
<select id="timescale" class="date timescale" style="margin-bottom: 3px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(170, 170, 170); border-right-color: rgb(170, 170, 170); border-bottom-color: rgb(170, 170, 170); border-left-color: rgb(170, 170, 170); "><option value="start=1321692809">last 1 hour</option><option value="start=1321689209">last 2 hours</option><option value="start=1321674809">last 6 hours</option><option value="start=1321653209">last 12 hours</option><option value="start=1321610009">last 1 day</option><option value="start=1321523609">last 2 days</option><option value="start=1321437209">last 3 days</option><option value="start=1321091609">last 1 week</option><option value="start=1320486809">last 2 weeks</option><option value="start=1318910009">last 1 month</option><option value="start=1290160409">last 1 year</option><option value="start=1258624409">last 2 years</option></select>
|
25
|
+
:javascript
|
26
|
+
window.addEvent('domready', function() {
|
27
|
+
var timescale = $('timescale');
|
28
|
+
timescale.addEvent('change', function(e) {
|
29
|
+
e.stop();
|
30
|
+
window.Graphs.each(function(graph) {
|
31
|
+
var selected = timescale.getSelected()[0]
|
32
|
+
|
33
|
+
graph.setTimePeriodTo(selected);
|
34
|
+
});
|
35
|
+
|
36
|
+
});
|
37
|
+
});
|
38
|
+
|
39
|
+
%div#graphs
|
51
40
|
|
52
41
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
%div#chart-builder
|
2
|
+
%div#hosts.builder
|
3
|
+
%h2 Hosts
|
4
|
+
%img{:src => link_to("/images/hosts.png"), :class => "icon hosts"}
|
5
|
+
%div.search
|
6
|
+
|
7
|
+
%div#metrics.builder
|
8
|
+
%h2 Metrics
|
9
|
+
%img{:src => link_to("/images/metrics.png"), :class => "icon metrics"}
|
10
|
+
%div.search
|
11
|
+
|
12
|
+
%input#show{:value => "Show graphs", :type => "button", :class => "button"}
|
13
|
+
|
14
|
+
%div#graph
|
@@ -4,11 +4,14 @@
|
|
4
4
|
%title= include_page_title
|
5
5
|
%link{:rel => "icon", :type => "image/gif", :href => "/favicon.gif"}
|
6
6
|
%link{:rel => 'stylesheet', :href => '/stylesheets/screen.css', :type => 'text/css'}
|
7
|
-
%
|
8
|
-
%script{:type => "text/javascript", :src => link_to("/javascripts/mootools-1.
|
7
|
+
%link{:rel => 'stylesheet', :href => '/stylesheets/message.css', :type => 'text/css'}
|
8
|
+
%script{:type => "text/javascript", :src => link_to("/javascripts/mootools-core-1.4.0-full-compat.js")}
|
9
|
+
%script{:type => "text/javascript", :src => link_to("/javascripts/mootools-more-1.4.0.1.js")}
|
9
10
|
%script{:type => "text/javascript", :src => link_to("/javascripts/highcharts.js")}
|
10
11
|
%script{:type => "text/javascript", :src => link_to("/javascripts/graph.js")}
|
11
12
|
%script{:type => "text/javascript", :src => link_to("/javascripts/keyboard.js")}
|
13
|
+
%script{:type => "text/javascript", :src => link_to("/javascripts/message.js")}
|
14
|
+
= include_required_js
|
12
15
|
|
13
16
|
%body
|
14
17
|
%div#wrapper
|
@@ -1,33 +1,52 @@
|
|
1
1
|
- profile_name = @profile.options[:profile_name]
|
2
2
|
- page_title(profile_name)
|
3
|
+
- require_js "builder"
|
4
|
+
|
5
|
+
%a{:href=>"#edit", :id => "edit"} edit profile
|
6
|
+
%div#chart-builder-slider
|
7
|
+
= haml :builder_form
|
8
|
+
|
9
|
+
:javascript
|
10
|
+
window.addEvent('domready', function() {
|
11
|
+
var builder = new ChartBuilder('chart-builder', {
|
12
|
+
hosts: ['#{@profile.options[:hosts].join("','") }'],
|
13
|
+
metrics: ['#{@profile.options[:metrics].join("','") }']
|
14
|
+
});
|
15
|
+
|
16
|
+
$('chart-builder-slider').fade('hide').setStyle('height', '0');
|
17
|
+
|
18
|
+
$('edit').addEvent('click', function(e) {
|
19
|
+
e.stop();
|
20
|
+
$('chart-builder-slider').setStyle('height', 'auto').fade('in');
|
21
|
+
e.target.destroy();
|
22
|
+
});
|
23
|
+
});
|
3
24
|
|
4
25
|
%div#profile
|
5
|
-
%h2#
|
6
|
-
|
7
|
-
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
%
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
#{ "baseurl: '" + ENV['BASE_URL'].gsub(/^\//, '') if ENV['BASE_URL'] }
|
26
|
+
%h2#name= profile_name
|
27
|
+
%div#graphs
|
28
|
+
- @profile.graphs.each do |graph|
|
29
|
+
- id = URI.escape(graph.id)
|
30
|
+
- host = URI.escape(graph.host)
|
31
|
+
- plugin = URI.escape(graph.plugin)
|
32
|
+
- instance = URI.escape(graph.instances.join(','))
|
33
|
+
%div{:id => id, :class => 'graph'}
|
34
|
+
%img{:src => link_to("/images/loader.gif")}
|
35
|
+
:javascript
|
36
|
+
window.addEvent('domready', function() {
|
37
|
+
var graph = new VisageGraph('#{id}', '#{host}', '#{plugin}', {
|
38
|
+
pluginInstance: '#{instance}',
|
39
|
+
#{ "baseurl: '" + ENV['BASE_URL'].gsub(/^\//, '') if ENV['BASE_URL'] }
|
40
|
+
});
|
21
41
|
});
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
Metrics: #{@profile.options[:metrics]}
|
42
|
+
- if @profile.graphs.size == 0
|
43
|
+
%div.graph
|
44
|
+
%h4.error Oops! Looks like there aren't any graphs matching the specified patterns.
|
45
|
+
%p These are the patterns:
|
46
|
+
%pre
|
47
|
+
:preserve
|
48
|
+
Host: #{@profile.options[:hosts]}
|
49
|
+
Metrics: #{@profile.options[:metrics]}
|
31
50
|
|
32
51
|
%div#bottom_nav
|
33
52
|
%a{:href => link_to("/profiles")} ← Back to profiles
|