visage-app 0.9.4 → 0.9.5
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/Gemfile.lock +62 -0
- data/README.md +4 -0
- data/VERSION +1 -1
- data/features/json.feature +0 -26
- data/features/meta.feature +12 -0
- data/features/step_definitions/json_steps.rb +12 -0
- data/features/step_definitions/site_steps.rb +5 -0
- data/features/step_definitions/webrat_steps.rb +4 -4
- data/features/support/env.rb +1 -0
- data/lib/visage-app/collectd/json.rb +29 -8
- data/lib/visage-app/collectd/rrds.rb +0 -1
- data/lib/visage-app/config/file.rb +2 -2
- data/lib/visage-app/config.ru +1 -0
- data/lib/visage-app/patches.rb +5 -5
- data/lib/visage-app/profile.rb +1 -1
- data/lib/visage-app/public/javascripts/graph.js +47 -20
- data/lib/visage-app/types.rb +37 -0
- data/lib/visage-app/views/profile.haml +1 -0
- data/lib/visage-app.rb +24 -4
- data/visage-app.gemspec +1 -1
- metadata +6 -3
data/Gemfile.lock
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
builder (3.0.0)
|
5
|
+
cucumber (0.10.0)
|
6
|
+
builder (>= 2.1.2)
|
7
|
+
diff-lcs (~> 1.1.2)
|
8
|
+
gherkin (~> 2.3.2)
|
9
|
+
json (~> 1.4.6)
|
10
|
+
term-ansicolor (~> 1.0.5)
|
11
|
+
diff-lcs (1.1.2)
|
12
|
+
errand (0.7.2)
|
13
|
+
gherkin (2.3.3)
|
14
|
+
json (~> 1.4.6)
|
15
|
+
git (1.2.5)
|
16
|
+
haml (3.0.25)
|
17
|
+
jeweler (1.5.2)
|
18
|
+
bundler (~> 1.0.0)
|
19
|
+
git (>= 1.2.5)
|
20
|
+
rake
|
21
|
+
json (1.4.6)
|
22
|
+
nokogiri (1.4.4)
|
23
|
+
rack (1.2.1)
|
24
|
+
rack-test (0.5.7)
|
25
|
+
rack (>= 1.0)
|
26
|
+
rake (0.8.7)
|
27
|
+
rspec (2.4.0)
|
28
|
+
rspec-core (~> 2.4.0)
|
29
|
+
rspec-expectations (~> 2.4.0)
|
30
|
+
rspec-mocks (~> 2.4.0)
|
31
|
+
rspec-core (2.4.0)
|
32
|
+
rspec-expectations (2.4.0)
|
33
|
+
diff-lcs (~> 1.1.2)
|
34
|
+
rspec-mocks (2.4.0)
|
35
|
+
shotgun (0.8)
|
36
|
+
rack (>= 1.0)
|
37
|
+
sinatra (1.1.2)
|
38
|
+
rack (~> 1.1)
|
39
|
+
tilt (~> 1.2)
|
40
|
+
term-ansicolor (1.0.5)
|
41
|
+
tilt (1.2.2)
|
42
|
+
webrat (0.7.1)
|
43
|
+
nokogiri (>= 1.2.0)
|
44
|
+
rack (>= 1.0)
|
45
|
+
rack-test (>= 0.5.3)
|
46
|
+
yajl-ruby (0.7.9)
|
47
|
+
|
48
|
+
PLATFORMS
|
49
|
+
ruby
|
50
|
+
|
51
|
+
DEPENDENCIES
|
52
|
+
cucumber
|
53
|
+
errand
|
54
|
+
haml
|
55
|
+
jeweler
|
56
|
+
rack-test
|
57
|
+
rspec
|
58
|
+
shotgun
|
59
|
+
sinatra
|
60
|
+
tilt
|
61
|
+
webrat
|
62
|
+
yajl-ruby
|
data/README.md
CHANGED
@@ -35,6 +35,10 @@ On CentOS, to install dependencies run:
|
|
35
35
|
|
36
36
|
$ sudo yum install -y ruby-RRDtool ruby rubygems collectd
|
37
37
|
|
38
|
+
If you are using Ruby Enterprise Edition, instead of installing librrd-ruby or ruby-RRDtool, run
|
39
|
+
|
40
|
+
$ gem install librrd
|
41
|
+
|
38
42
|
Then install the app with:
|
39
43
|
|
40
44
|
$ gem install visage-app
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.9.
|
1
|
+
0.9.5
|
data/features/json.feature
CHANGED
@@ -36,32 +36,6 @@ Feature: Export data
|
|
36
36
|
When I visit "cpu-0?callback=foobar" on the first available host
|
37
37
|
Then I should receive JSON wrapped in a callback named "foobar"
|
38
38
|
|
39
|
-
Scenario: Retrieve multiple plugin instances without color definition
|
40
|
-
Given a list of hosts exist
|
41
|
-
When I visit "memory" on the first available host
|
42
|
-
Then the request should succeed
|
43
|
-
Then I should receive valid JSON
|
44
|
-
And each plugin instance should have a different color
|
45
|
-
|
46
|
-
Scenario Outline: Return only one colour per metric
|
47
|
-
Given a list of hosts exist
|
48
|
-
When I visit "<path>" on the first available host
|
49
|
-
Then the request should succeed
|
50
|
-
Then I should receive valid JSON
|
51
|
-
And each plugin instance should have a different color
|
52
|
-
|
53
|
-
Examples:
|
54
|
-
| path |
|
55
|
-
| cpu-0/cpu-user |
|
56
|
-
| memory/memory-used |
|
57
|
-
|
58
|
-
Scenario: Retrieve single plugin instance with a color definition
|
59
|
-
Given a list of hosts exist
|
60
|
-
When I visit "load/load" on the first available host
|
61
|
-
Then the request should succeed
|
62
|
-
Then I should receive valid JSON
|
63
|
-
And the plugin instance should have a color
|
64
|
-
|
65
39
|
Scenario: Retrieve multiple plugins through a glob
|
66
40
|
Given a list of hosts exist
|
67
41
|
When I visit "disk*/disk_ops" on the first available host
|
@@ -0,0 +1,12 @@
|
|
1
|
+
Feature: Metric metadata
|
2
|
+
To view the data
|
3
|
+
In an identifiable way
|
4
|
+
A user
|
5
|
+
Needs meaningful labels
|
6
|
+
|
7
|
+
Scenario: Retreive a list of types
|
8
|
+
When I go to /meta/types
|
9
|
+
Then the request should succeed
|
10
|
+
Then I should receive valid JSON
|
11
|
+
And the JSON should have a list of types
|
12
|
+
|
@@ -5,6 +5,8 @@ Then /^I should receive valid JSON$/ do
|
|
5
5
|
}.should_not raise_error
|
6
6
|
|
7
7
|
case
|
8
|
+
when @response.class == Array
|
9
|
+
next
|
8
10
|
when @response.keys.first == "hosts"
|
9
11
|
@response["hosts"].should respond_to(:size)
|
10
12
|
when @response[@response.keys.first].respond_to?(:size)
|
@@ -121,3 +123,13 @@ Then /^the JSON should have a list of plugins$/ do
|
|
121
123
|
plugins = @response[host]
|
122
124
|
plugins.size.should > 0
|
123
125
|
end
|
126
|
+
|
127
|
+
Then /^the JSON should have a list of types$/ do
|
128
|
+
@response.size.should > 0
|
129
|
+
@response.each do |type|
|
130
|
+
%w(dataset datasource type min max).each do |attr|
|
131
|
+
type[attr].should_not be_nil
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
@@ -14,19 +14,19 @@ When /^I follow "(.*)"$/ do |link|
|
|
14
14
|
end
|
15
15
|
|
16
16
|
When /^I fill in "(.*)" with "(.*)"$/ do |field, value|
|
17
|
-
fill_in(field, :with => value)
|
17
|
+
fill_in(field, :with => value)
|
18
18
|
end
|
19
19
|
|
20
20
|
When /^I select "(.*)" from "(.*)"$/ do |value, field|
|
21
|
-
select(value, :from => field)
|
21
|
+
select(value, :from => field)
|
22
22
|
end
|
23
23
|
|
24
24
|
When /^I check "(.*)"$/ do |field|
|
25
|
-
check(field)
|
25
|
+
check(field)
|
26
26
|
end
|
27
27
|
|
28
28
|
When /^I uncheck "(.*)"$/ do |field|
|
29
|
-
uncheck(field)
|
29
|
+
uncheck(field)
|
30
30
|
end
|
31
31
|
|
32
32
|
When /^I choose "(.*)"$/ do |field|
|
data/features/support/env.rb
CHANGED
@@ -14,6 +14,7 @@ class CollectdJSON
|
|
14
14
|
|
15
15
|
def initialize(opts={})
|
16
16
|
@rrddir = opts[:rrddir] || CollectdJSON.rrddir
|
17
|
+
@types = opts[:types] || CollectdJSON.types
|
17
18
|
end
|
18
19
|
|
19
20
|
# Entry point.
|
@@ -22,24 +23,40 @@ class CollectdJSON
|
|
22
23
|
plugin = opts[:plugin]
|
23
24
|
plugin_instances = opts[:plugin_instances][/\w.*/]
|
24
25
|
instances = plugin_instances.blank? ? '*' : '{' + plugin_instances.split('/').join(',') + '}'
|
25
|
-
|
26
|
+
rrdglob = "#{@rrddir}/#{host}/#{plugin}/#{instances}.rrd"
|
27
|
+
|
28
|
+
start = case
|
29
|
+
when opts[:start] && opts[:start].index('.')
|
30
|
+
opts[:start].split('.').first
|
31
|
+
when opts[:start]
|
32
|
+
opts[:start]
|
33
|
+
else
|
34
|
+
(Time.now - 3600).to_i
|
35
|
+
end
|
26
36
|
|
27
|
-
|
28
|
-
|
37
|
+
finish = case
|
38
|
+
when opts[:finish] && opts[:finish].index('.')
|
39
|
+
opts[:finish].split('.').first
|
40
|
+
when opts[:finish]
|
41
|
+
opts[:finish]
|
42
|
+
else
|
43
|
+
Time.now.to_i
|
44
|
+
end
|
29
45
|
|
30
46
|
data = []
|
31
47
|
|
32
48
|
Dir.glob(rrdglob).map do |rrdname|
|
33
49
|
parts = rrdname.gsub(/#{@rrddir}\//, '').split('/')
|
34
|
-
|
50
|
+
host_name = parts[0]
|
35
51
|
plugin_name = parts[1]
|
36
|
-
instance_name = parts[2]
|
52
|
+
instance_name = File.basename(parts[2], '.rrd')
|
37
53
|
rrd = Errand.new(:filename => rrdname)
|
38
54
|
|
55
|
+
|
39
56
|
data << { :plugin => plugin_name, :instance => instance_name,
|
40
|
-
:host =>
|
41
|
-
:start =>
|
42
|
-
:finish =>
|
57
|
+
:host => host_name,
|
58
|
+
:start => start,
|
59
|
+
:finish => finish,
|
43
60
|
:rrd => rrd }
|
44
61
|
end
|
45
62
|
|
@@ -105,6 +122,10 @@ class CollectdJSON
|
|
105
122
|
@rrddir ||= Visage::Config.rrddir
|
106
123
|
end
|
107
124
|
|
125
|
+
def types
|
126
|
+
@types ||= Visage::Config.types
|
127
|
+
end
|
128
|
+
|
108
129
|
def hosts
|
109
130
|
if @rrddir
|
110
131
|
Dir.glob("#{@rrddir}/*").map {|e| e.split('/').last }.sort
|
@@ -19,7 +19,7 @@ module Visage
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def self.load(filename, opts={})
|
22
|
-
|
22
|
+
if not path = self.find(filename, opts)
|
23
23
|
if opts[:create]
|
24
24
|
path = @@config_directories.first.join(filename)
|
25
25
|
begin
|
@@ -41,7 +41,7 @@ module Visage
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def initialize(filename, opts={})
|
44
|
-
|
44
|
+
if not ::File.exists?(filename)
|
45
45
|
path = @@config_directories.first.join(filename)
|
46
46
|
FileUtils.touch(path)
|
47
47
|
end
|
data/lib/visage-app/config.ru
CHANGED
data/lib/visage-app/patches.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
# extracted from Extlib.
|
1
|
+
# extracted from Extlib.
|
2
2
|
# FIXME: what's the licensing here?
|
3
3
|
class String
|
4
|
-
def camel_case
|
5
|
-
return self if self !~ /_/ && self =~ /[A-Z]+.*/
|
6
|
-
split('_').map{|e| e.capitalize}.join
|
7
|
-
end
|
4
|
+
def camel_case
|
5
|
+
return self if self !~ /_/ && self =~ /[A-Z]+.*/
|
6
|
+
split('_').map{|e| e.capitalize}.join
|
7
|
+
end
|
8
8
|
|
9
9
|
def blank?
|
10
10
|
strip.empty?
|
data/lib/visage-app/profile.rb
CHANGED
@@ -24,7 +24,7 @@ module Visage
|
|
24
24
|
def self.all(opts={})
|
25
25
|
sort = opts[:sort]
|
26
26
|
profiles = self.load
|
27
|
-
profiles = sort == "name" ? profiles.
|
27
|
+
profiles = sort == "name" ? profiles.sort_by {|k,v| v[:profile_name]}.map {|i| i.last } : profiles.values
|
28
28
|
profiles.map { |prof| self.new(prof) }
|
29
29
|
end
|
30
30
|
|
@@ -185,10 +185,10 @@ var visageBase = new Class({
|
|
185
185
|
},
|
186
186
|
getData: function() {
|
187
187
|
this.request = new Request.JSONP({
|
188
|
-
url:
|
189
|
-
data:
|
190
|
-
secure:
|
191
|
-
method:
|
188
|
+
url: this.dataURL(),
|
189
|
+
data: this.requestData,
|
190
|
+
secure: this.options.secureJSON,
|
191
|
+
method: this.options.httpMethod,
|
192
192
|
onComplete: function(json) {
|
193
193
|
this.graphData(json);
|
194
194
|
}.bind(this),
|
@@ -228,13 +228,33 @@ var visageGraph = new Class({
|
|
228
228
|
graphData: function(data) {
|
229
229
|
this.response = data
|
230
230
|
this.buildDataStructures()
|
231
|
+
this.lastStart = this.series[0].data[0][0]
|
232
|
+
this.lastFinish = this.series[0].data.getLast()[0]
|
233
|
+
|
234
|
+
switch(true) {
|
235
|
+
case $defined(this.chart) && this.requestData['live']:
|
236
|
+
this.series.each(function(series, index) {
|
237
|
+
var point = series.data[1];
|
238
|
+
this.chart.series[index].addPoint(point, false);
|
239
|
+
}, this);
|
240
|
+
this.chart.redraw();
|
241
|
+
break;
|
242
|
+
case $defined(this.chart):
|
243
|
+
this.series.each(function(series, index) {
|
244
|
+
this.chart.series[index].setData(series.data, false);
|
245
|
+
}, this);
|
246
|
+
|
247
|
+
/* Reset the zoom */
|
248
|
+
this.chart.toolbar.remove('zoom');
|
249
|
+
this.chart.xAxis.concat(this.chart.yAxis).each(function(axis) {
|
250
|
+
axis.setExtremes(null,null,false);
|
251
|
+
});
|
231
252
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
this.drawChart()
|
253
|
+
this.chart.redraw();
|
254
|
+
break;
|
255
|
+
default:
|
256
|
+
this.drawChart()
|
257
|
+
break;
|
238
258
|
}
|
239
259
|
},
|
240
260
|
buildDataStructures: function (data) {
|
@@ -294,6 +314,10 @@ var visageGraph = new Class({
|
|
294
314
|
load: function(e) {
|
295
315
|
setInterval(function() {
|
296
316
|
if (this.options.live) {
|
317
|
+
var data = { 'start': this.lastFinish,
|
318
|
+
'finish': this.lastFinish + 10,
|
319
|
+
'live': true };
|
320
|
+
this.requestData = data;
|
297
321
|
this.getData()
|
298
322
|
}
|
299
323
|
}.bind(this), 10000);
|
@@ -411,11 +435,10 @@ var visageGraph = new Class({
|
|
411
435
|
'submit': function(e, foo) {
|
412
436
|
e.stop();
|
413
437
|
e.target.getElement('select').getSelected().each(function(option) {
|
414
|
-
|
415
|
-
|
416
|
-
data.set(split[0], split[1])
|
438
|
+
value = parseInt(option.value.split('=')[1])
|
439
|
+
data = { 'start': value }
|
417
440
|
});
|
418
|
-
this.requestData = data
|
441
|
+
this.requestData = data;
|
419
442
|
|
420
443
|
/* Draw everything again. */
|
421
444
|
this.getData();
|
@@ -446,6 +469,7 @@ var visageGraph = new Class({
|
|
446
469
|
'type': 'checkbox',
|
447
470
|
'id': this.parentElement + '-live',
|
448
471
|
'name': 'live',
|
472
|
+
'checked': this.options.live,
|
449
473
|
'events': {
|
450
474
|
'click': function() {
|
451
475
|
this.options.live = !this.options.live
|
@@ -478,12 +502,15 @@ var visageGraph = new Class({
|
|
478
502
|
},
|
479
503
|
'events': {
|
480
504
|
'mouseover': function(e) {
|
481
|
-
|
482
|
-
var
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
505
|
+
e.stop();
|
506
|
+
var url = e.target.get('href'),
|
507
|
+
extremes = this.chart.xAxis[0].getExtremes(),
|
508
|
+
options = { 'start': extremes.dataMin,
|
509
|
+
'finish': parseInt(extremes.dataMax) };
|
510
|
+
|
511
|
+
var options = new Hash(options).toQueryString(),
|
512
|
+
baseurl = this.dataURL(),
|
513
|
+
url = baseurl += '?' + options;
|
487
514
|
|
488
515
|
e.target.set('href', url)
|
489
516
|
}.bind(this)
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
module Visage
|
4
|
+
class Types
|
5
|
+
attr_reader :types
|
6
|
+
|
7
|
+
def initialize(opts={})
|
8
|
+
@filename = opts[:filename] || "/usr/share/collectd/types.db"
|
9
|
+
@types = []
|
10
|
+
build
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_json
|
14
|
+
@types.to_json
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def build
|
19
|
+
file = File.new(@filename)
|
20
|
+
file.each_line do |line|
|
21
|
+
next if line =~ /^#/
|
22
|
+
next if line =~ /^\s*$/
|
23
|
+
attrs = {}
|
24
|
+
spec = line.strip.split(/\t+|,\s+/)
|
25
|
+
dataset = spec.shift
|
26
|
+
spec.each do |source|
|
27
|
+
parts = source.split(':')
|
28
|
+
@types << { "dataset" => dataset,
|
29
|
+
"datasource" => parts[0],
|
30
|
+
"type" => parts[1],
|
31
|
+
"min" => parts[2],
|
32
|
+
"max" => parts[3] }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/visage-app.rb
CHANGED
@@ -12,6 +12,7 @@ require 'lib/visage-app/config'
|
|
12
12
|
require 'lib/visage-app/config/file'
|
13
13
|
require 'lib/visage-app/collectd/rrds'
|
14
14
|
require 'lib/visage-app/collectd/json'
|
15
|
+
require 'lib/visage-app/types'
|
15
16
|
require 'yajl/json_gem'
|
16
17
|
|
17
18
|
module Visage
|
@@ -27,7 +28,11 @@ module Visage
|
|
27
28
|
Visage::Config.use do |c|
|
28
29
|
# FIXME: make this configurable through file
|
29
30
|
c['rrddir'] = ENV["RRDDIR"] ? Pathname.new(ENV["RRDDIR"]).expand_path : Pathname.new("/var/lib/collectd/rrd").expand_path
|
31
|
+
c['types'] = ENV["TYPES"] ? Visage::Types.new(:filename => ENV["TYPES"]) : Visage::Types.new
|
30
32
|
end
|
33
|
+
|
34
|
+
# Load up the profile.yaml. Creates it if it doesn't already exist.
|
35
|
+
Visage::Profile.load
|
31
36
|
end
|
32
37
|
end
|
33
38
|
|
@@ -41,6 +46,7 @@ module Visage
|
|
41
46
|
raise Sinatra::NotFound unless @profile
|
42
47
|
@start = params[:start]
|
43
48
|
@finish = params[:finish]
|
49
|
+
@live = params[:live] ? true : false
|
44
50
|
haml :profile
|
45
51
|
end
|
46
52
|
|
@@ -83,19 +89,27 @@ module Visage
|
|
83
89
|
class JSON < Application
|
84
90
|
|
85
91
|
# JSON data backend
|
92
|
+
mime_type :json, "application/json"
|
93
|
+
mime_type :jsonp, "text/javascript"
|
94
|
+
|
95
|
+
before do
|
96
|
+
content_type :jsonp
|
97
|
+
end
|
86
98
|
|
87
99
|
# /data/:host/:plugin/:optional_plugin_instance
|
88
100
|
get %r{/data/([^/]+)/([^/]+)((/[^/]+)*)} do
|
89
101
|
host = params[:captures][0].gsub("\0", "")
|
90
102
|
plugin = params[:captures][1].gsub("\0", "")
|
91
103
|
plugin_instances = params[:captures][2].gsub("\0", "")
|
104
|
+
start = params[:start]
|
105
|
+
finish = params[:finish]
|
92
106
|
|
93
107
|
collectd = CollectdJSON.new(:rrddir => Visage::Config.rrddir)
|
94
|
-
json = collectd.json(:host
|
95
|
-
:plugin
|
108
|
+
json = collectd.json(:host => host,
|
109
|
+
:plugin => plugin,
|
96
110
|
:plugin_instances => plugin_instances,
|
97
|
-
:start
|
98
|
-
:finish
|
111
|
+
:start => start,
|
112
|
+
:finish => finish)
|
99
113
|
# if the request is cross-domain, we need to serve JSONP
|
100
114
|
maybe_wrap_with_callback(json)
|
101
115
|
end
|
@@ -120,4 +134,10 @@ module Visage
|
|
120
134
|
end
|
121
135
|
|
122
136
|
end
|
137
|
+
|
138
|
+
class Meta < Application
|
139
|
+
get '/meta/types' do
|
140
|
+
Visage::Config.types.to_json
|
141
|
+
end
|
142
|
+
end
|
123
143
|
end
|
data/visage-app.gemspec
CHANGED
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 9
|
8
|
-
-
|
9
|
-
version: 0.9.
|
8
|
+
- 5
|
9
|
+
version: 0.9.5
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Lindsay Holmwood
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-
|
17
|
+
date: 2011-05-08 00:00:00 +10:00
|
18
18
|
default_executable: visage-app
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -230,6 +230,7 @@ extra_rdoc_files:
|
|
230
230
|
files:
|
231
231
|
- AUTHORS
|
232
232
|
- Gemfile
|
233
|
+
- Gemfile.lock
|
233
234
|
- LICENCE
|
234
235
|
- README.md
|
235
236
|
- Rakefile
|
@@ -239,6 +240,7 @@ files:
|
|
239
240
|
- features/cli.feature
|
240
241
|
- features/data/config/with_no_profiles/.stub
|
241
242
|
- features/json.feature
|
243
|
+
- features/meta.feature
|
242
244
|
- features/profiles.feature
|
243
245
|
- features/step_definitions/form_steps.rb
|
244
246
|
- features/step_definitions/json_steps.rb
|
@@ -272,6 +274,7 @@ files:
|
|
272
274
|
- lib/visage-app/public/javascripts/mootools-1.2.3-core.js
|
273
275
|
- lib/visage-app/public/javascripts/mootools-1.2.5.1-more.js
|
274
276
|
- lib/visage-app/public/stylesheets/screen.css
|
277
|
+
- lib/visage-app/types.rb
|
275
278
|
- lib/visage-app/views/builder.haml
|
276
279
|
- lib/visage-app/views/layout.haml
|
277
280
|
- lib/visage-app/views/profile.haml
|