graffable 0.0.2 → 0.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 46adff9ed7f91eaf984f65e4dea871ce51de43df
4
- data.tar.gz: 18c69537813f8d22bcceec67793f6377b1937f1f
3
+ metadata.gz: e2223326e8c8ba239381e37e462493512fc7b5f9
4
+ data.tar.gz: 3e469d9a364e2e146204ad14cc2edefec26f61c7
5
5
  SHA512:
6
- metadata.gz: 29fd8acb103da34e6674e26d2c0e6f43087de388d46a5dd7d5dac7c99e0eb574ceee77f7bdc6996d1a781b62dcff8be2ba22170a3af1d14018c0e75cde9f2eae
7
- data.tar.gz: c690f97cb951290a6380a8a1ae30613617891172c9f6fee5b2828df41bd8658d1f704c183c883a1eedc372bd7e916ba1c7e721b842e0b5e7a41d9dd410689bcc
6
+ metadata.gz: 607a1e4529864ba28870a84ec4c4e8f984544829a57aa336c53c2593e3316ef4def2eac44d2331e89599522ece482ad7f50eaf92d16c2909e68748c97c8ad6db
7
+ data.tar.gz: 32cca37a38e3c92137b2fed6e49aa4160a2f99c245ee828e961b0268909b46b6deb24a1a67511507481d9db66b07e129e4421a286ac8a670ba1c60e12bc95674
data/.gitignore CHANGED
@@ -1,5 +1,8 @@
1
1
  .*.swp
2
+ .DS_Store
3
+
2
4
  /.env
5
+ /db/*.sql
3
6
  /db/*.sqlite3
4
7
  /db/seed.rb
5
8
  /Gemfile.lock
data/CHANGES.md CHANGED
@@ -2,6 +2,20 @@
2
2
  Graffable Changes
3
3
  =================
4
4
 
5
+ 2014-03-12 Graffable v0.0.3
6
+ ---------------------------
7
+ * Added hourly reports
8
+ * Reports now include label totals
9
+ * Reports now sort labels by total
10
+ * Reports have more descriptive `<title>` and `<h1>` tags
11
+ * Reports now ordered by description
12
+ * Reports no longer attempt to plot data when there is no data to plot
13
+ * Reports now have an optional `txt` column
14
+ * Update JQuery to v2.1.0
15
+ * Update jquery.flot.tooltip to v0.6.6
16
+ * Update Twitter Bootstrap to v3.1.1
17
+
18
+
5
19
  2014-02-06 Graffable v0.0.2
6
20
  ---------------------------
7
21
  * `Graffable::Database.connect()` now connects to `ENV['DATABASE_URL']` (was `ENV['GRAFFABLE_DATABASE_URL']`)
@@ -0,0 +1,2 @@
1
+ web: bundle exec rackup config.ru
2
+
data/Rakefile CHANGED
@@ -1,5 +1,9 @@
1
1
  require 'bundler/gem_tasks'
2
2
 
3
+ require 'dotenv'
4
+ Dotenv.load
5
+ require 'dotenv/tasks'
6
+
3
7
  require './lib/graffable.rb'
4
8
  ENV['GRAFFABLE_DATABASE_URL'] ||= 'sqlite://db/development.sqlite3'
5
9
 
@@ -0,0 +1,12 @@
1
+
2
+ Sequel.migration do
3
+ transaction
4
+
5
+ change do
6
+ alter_table(:reports) do
7
+ add_column :txt, String, size: 255
8
+ end
9
+ end
10
+
11
+ end
12
+
@@ -25,6 +25,8 @@ Gem::Specification.new do |spec|
25
25
  spec.add_dependency 'sinatra-flash'
26
26
 
27
27
  spec.add_development_dependency 'bundler', '~> 1.3'
28
+ spec.add_development_dependency 'dotenv'
29
+ spec.add_development_dependency 'foreman'
28
30
  spec.add_development_dependency 'rake'
29
31
  spec.add_development_dependency 'sqlite3'
30
32
  end
@@ -26,12 +26,36 @@ module Graffable
26
26
  end
27
27
 
28
28
 
29
+ # /:group/:report/:year/:month/:day.json
30
+ get %r{/(.+)/(.+)/(\d{4})/(\d{2})/(\d{2}).(csv|json)} do |group_name, report_name, year, month, day, extension|
31
+ group = assert_group group_name
32
+ report = assert_report group, report_name
33
+
34
+ # TODO DRY!
35
+ query = "SELECT year,month,day,hour,label,#{ report[:aggregate].to_s.upcase }(value) AS value " +
36
+ "FROM numbers " +
37
+ "WHERE report_id=:report_id " +
38
+ "AND year=:year " +
39
+ "AND month=:month " +
40
+ "AND day=:day " +
41
+ "GROUP BY year,month,day,hour,label " +
42
+ "ORDER BY year,month,day,hour,label"
43
+ dataset = @db.fetch( query, day: day, month: month, report_id: report[:id], year: year )
44
+
45
+ case extension
46
+ when 'csv'
47
+ return_csv dataset
48
+ when 'json'
49
+ return_json dataset, date_formatter: lambda { |y,m,d,h| h }
50
+ end
51
+ end
52
+
29
53
  # /:group/:report/:year/:month.json
30
54
  get %r{/(.+)/(.+)/(\d{4})/(\d{2}).(csv|json)} do |group_name, report_name, year, month, extension|
31
55
  group = assert_group group_name
32
56
  report = assert_report group, report_name
33
57
 
34
- # TODO DRY?
58
+ # TODO DRY!
35
59
  query = "SELECT year,month,day,label,#{ report[:aggregate].to_s.upcase }(value) AS value " +
36
60
  "FROM numbers " +
37
61
  "WHERE report_id=:report_id " +
@@ -54,7 +78,7 @@ module Graffable
54
78
  group = assert_group group_name
55
79
  report = assert_report group, report_name
56
80
 
57
- # TODO DRY?
81
+ # TODO DRY!
58
82
  query = "SELECT year,month,label,#{ report[:aggregate].to_s.upcase }(value) AS value " +
59
83
  "FROM numbers " +
60
84
  "WHERE report_id=:report_id " +
@@ -76,7 +100,7 @@ module Graffable
76
100
  group = assert_group group_name
77
101
  report = assert_report group, report_name
78
102
 
79
- # TODO DRY?
103
+ # TODO DRY!
80
104
  query = "SELECT year,month,day,label,#{ report[:aggregate].to_s.upcase }(value) AS value " +
81
105
  "FROM numbers " +
82
106
  "WHERE report_id=:report_id " +
@@ -93,12 +117,35 @@ module Graffable
93
117
  end
94
118
  end
95
119
 
96
- # TODO DRY
120
+ # TODO DRY!
121
+ get %r{/(.+)/(.+)/(\d{4})/(\d{2})/(\d{2})} do |group_name, report_name, year, month, day|
122
+ @group = @groups.detect { |g| group_name == g[:name] }
123
+ redirect_with_warning( '/', "Report group not found: #{group_name}" ) unless @group
124
+
125
+ @reports = @db[:reports].where( group_id: @group[:id] ).order(:description).all
126
+ @report = @reports.detect { |r| report_name == r[:name] }
127
+ redirect_with_warning( "/#{group_name}", "Report not found: #{report_name}" ) unless @report
128
+
129
+ @data_url = "/#{group_name}/#{report_name}/#{year}/#{month}/#{day}.json"
130
+ @interval = "#{year}-#{month}-#{day}"
131
+
132
+ date = Date.parse( "#{year}-#{month}-#{day}" )
133
+ prev_day = date - 1
134
+ next_day = date + 1
135
+ @previous = "/#{group_name}/#{report_name}/#{ prev_day.year }/#{ prev_day.strftime('%m') }/#{ prev_day.strftime('%d') }"
136
+ @next = "/#{group_name}/#{report_name}/#{ next_day.year }/#{ next_day.strftime('%m') }/#{ next_day.strftime('%d') }"
137
+
138
+ @title = "#{ @report[:description] } - #{ @interval }"
139
+
140
+ haml :report
141
+ end
142
+
143
+ # TODO DRY!
97
144
  get %r{/(.+)/(.+)/(\d{4})/(\d{2})} do |group_name, report_name, year, month|
98
145
  @group = @groups.detect { |g| group_name == g[:name] }
99
146
  redirect_with_warning( '/', "Report group not found: #{group_name}" ) unless @group
100
147
 
101
- @reports = @db[:reports].where( group_id: @group[:id] ).all
148
+ @reports = @db[:reports].where( group_id: @group[:id] ).order(:description).all
102
149
  @report = @reports.detect { |r| report_name == r[:name] }
103
150
  redirect_with_warning( "/#{group_name}", "Report not found: #{report_name}" ) unless @report
104
151
 
@@ -109,15 +156,17 @@ module Graffable
109
156
  @previous = "/#{group_name}/#{report_name}/#{ date.prev_month.year }/#{ date.prev_month.strftime('%m') }"
110
157
  @next = "/#{group_name}/#{report_name}/#{ date.next_month.year }/#{ date.next_month.strftime('%m') }"
111
158
 
159
+ @title = "#{ @report[:description] } - #{ @interval }"
160
+
112
161
  haml :report
113
162
  end
114
163
 
115
- # TODO DRY
164
+ # TODO DRY!
116
165
  get %r{/(.+)/(.+)/(\d{4})} do |group_name, report_name, year|
117
166
  @group = @groups.detect { |g| group_name == g[:name] }
118
167
  redirect_with_warning( '/', "Report group not found: #{group_name}" ) unless @group
119
168
 
120
- @reports = @db[:reports].where( group_id: @group[:id] ).all
169
+ @reports = @db[:reports].where( group_id: @group[:id] ).order(:description).all
121
170
  @report = @reports.detect { |r| report_name == r[:name] }
122
171
  redirect_with_warning( "/#{group_name}", "Report not found: #{report_name}" ) unless @report
123
172
 
@@ -128,21 +177,25 @@ module Graffable
128
177
  @previous = "/#{group_name}/#{report_name}/#{ date.prev_year.year }"
129
178
  @next = "/#{group_name}/#{report_name}/#{ date.next_year.year }"
130
179
 
180
+ @title = "#{ @report[:description] } - #{ @interval }"
181
+
131
182
  haml :report
132
183
  end
133
184
 
134
- # TODO DRY
185
+ # TODO DRY!
135
186
  get '/:group/:report' do
136
187
  @group = @groups.detect { |g| params[:group] == g[:name] }
137
188
  redirect_with_warning( '/', "Report group not found: #{ params[:group] }" ) unless @group
138
189
 
139
- @reports = @db[:reports].where( group_id: @group[:id] ).all
190
+ @reports = @db[:reports].where( group_id: @group[:id] ).order(:description).all
140
191
  @report = @reports.detect { |r| params[:report] == r[:name] }
141
192
  redirect_with_warning( "/#{ params[:group] }", "Report not found: #{ params[:report] }" ) unless @report
142
193
 
143
194
  @data_url = "/#{ params[:group] }/#{ params[:report] }.json"
144
195
  @interval = 'Recent'
145
196
 
197
+ @title = "#{ @report[:description] } - #{ @interval }"
198
+
146
199
  haml :report
147
200
  end
148
201
 
@@ -150,7 +203,7 @@ module Graffable
150
203
  @group = @groups.detect{ |g| params[:group] == g[:name] }
151
204
  redirect_with_warning( '/', "Report group not found: #{ params[:group] }" ) unless @group
152
205
 
153
- @reports = @db[:reports].where( group_id: @group[:id] ).all
206
+ @reports = @db[:reports].where( group_id: @group[:id] ).order(:description).all
154
207
  haml :group
155
208
  end
156
209
 
@@ -227,14 +280,16 @@ module Graffable
227
280
 
228
281
  values = values.sort.reverse.slice( 0 .. opts[:max] - 1 ).reverse if opts[:max] > - 1
229
282
  values.each do |tuple|
230
- date = date_mapping[ tuple.first ]
283
+ date = date_mapping[ tuple.first ]
231
284
  pairs = tuple.last
232
285
  pairs.each_pair do |label, value|
233
286
  unless data.key?(label)
234
- data[label] = { data: [] }
287
+ data[label] = { data: [], total: 0 }
235
288
  data[label][:label] = label unless label.empty?
236
289
  end
237
290
  data[label][:data].push [ date, value ]
291
+ data[label][:total] = data[label][:total] + value
292
+ data[label][:label] = "#{label} (#{ data[label][:total] })" unless label.empty?
238
293
  end
239
294
  end
240
295
 
@@ -0,0 +1,12 @@
1
+ /*
2
+ * jquery.flot.tooltip
3
+ *
4
+ * description: easy-to-use tooltips for Flot charts
5
+ * version: 0.6.6
6
+ * author: Krzysztof Urbas @krzysu [myviews.pl]
7
+ * website: https://github.com/krzysu/flot.tooltip
8
+ *
9
+ * build on 2014-02-10
10
+ * released under MIT License, 2012
11
+ */
12
+ !function(a){var b={tooltip:!1,tooltipOpts:{content:"%s | X: %x | Y: %y",xDateFormat:null,yDateFormat:null,monthNames:null,dayNames:null,shifts:{x:10,y:20},defaultTheme:!0,onHover:function(){}}},c=function(a){this.tipPosition={x:0,y:0},this.init(a)};c.prototype.init=function(b){function c(a){var b={};b.x=a.pageX,b.y=a.pageY,e.updateTooltipPosition(b)}function d(a,b,c){var d=e.getDomElement();if(c){var f;f=e.stringFormat(e.tooltipOptions.content,c),d.html(f),e.updateTooltipPosition({x:b.pageX,y:b.pageY}),d.css({left:e.tipPosition.x+e.tooltipOptions.shifts.x,top:e.tipPosition.y+e.tooltipOptions.shifts.y}).show(),"function"==typeof e.tooltipOptions.onHover&&e.tooltipOptions.onHover(c,d)}else d.hide().html("")}var e=this;b.hooks.bindEvents.push(function(b,f){if(e.plotOptions=b.getOptions(),e.plotOptions.tooltip!==!1&&"undefined"!=typeof e.plotOptions.tooltip){e.tooltipOptions=e.plotOptions.tooltipOpts;{e.getDomElement()}a(b.getPlaceholder()).bind("plothover",d),a(f).bind("mousemove",c)}}),b.hooks.shutdown.push(function(b,e){a(b.getPlaceholder()).unbind("plothover",d),a(e).unbind("mousemove",c)})},c.prototype.getDomElement=function(){var b;return a("#flotTip").length>0?b=a("#flotTip"):(b=a("<div />").attr("id","flotTip"),b.appendTo("body").hide().css({position:"absolute"}),this.tooltipOptions.defaultTheme&&b.css({background:"#fff","z-index":"1040",padding:"0.4em 0.6em","border-radius":"0.5em","font-size":"0.8em",border:"1px solid #111",display:"none","white-space":"nowrap"})),b},c.prototype.updateTooltipPosition=function(b){var c=a("#flotTip").outerWidth()+this.tooltipOptions.shifts.x,d=a("#flotTip").outerHeight()+this.tooltipOptions.shifts.y;b.x-a(window).scrollLeft()>a(window).innerWidth()-c&&(b.x-=c),b.y-a(window).scrollTop()>a(window).innerHeight()-d&&(b.y-=d),this.tipPosition.x=b.x,this.tipPosition.y=b.y},c.prototype.stringFormat=function(a,b){var c,d,e=/%p\.{0,1}(\d{0,})/,f=/%s/,g=/%x\.{0,1}(\d{0,})/,h=/%y\.{0,1}(\d{0,})/,i="%x",j="%y";if("undefined"!=typeof b.series.threshold?(c=b.datapoint[0],d=b.datapoint[1]):(c=b.series.data[b.dataIndex][0],d=b.series.data[b.dataIndex][1]),null===b.series.label&&b.series.originSeries&&(b.series.label=b.series.originSeries.label),"function"==typeof a&&(a=a(b.series.label,c,d,b)),"undefined"!=typeof b.series.percent&&(a=this.adjustValPrecision(e,a,b.series.percent)),a="undefined"!=typeof b.series.label?a.replace(f,b.series.label):a.replace(f,""),this.isTimeMode("xaxis",b)&&this.isXDateFormat(b)&&(a=a.replace(g,this.timestampToDate(c,this.tooltipOptions.xDateFormat))),this.isTimeMode("yaxis",b)&&this.isYDateFormat(b)&&(a=a.replace(h,this.timestampToDate(d,this.tooltipOptions.yDateFormat))),"number"==typeof c&&(a=this.adjustValPrecision(g,a,c)),"number"==typeof d&&(a=this.adjustValPrecision(h,a,d)),"undefined"!=typeof b.series.xaxis.ticks&&b.series.xaxis.ticks.length>b.dataIndex&&!this.isTimeMode("xaxis",b)&&(a=a.replace(g,b.series.xaxis.ticks[b.dataIndex].label)),"undefined"!=typeof b.series.yaxis.ticks)for(var k in b.series.yaxis.ticks)if(b.series.yaxis.ticks.hasOwnProperty(k)){var l=this.isCategoriesMode("yaxis",b)?b.series.yaxis.ticks[k].label:b.series.yaxis.ticks[k].v;l===d&&(a=a.replace(h,b.series.yaxis.ticks[k].label))}return"undefined"!=typeof b.series.xaxis.tickFormatter&&(a=a.replace(i,b.series.xaxis.tickFormatter(c,b.series.xaxis).replace(/\$/g,"$$"))),"undefined"!=typeof b.series.yaxis.tickFormatter&&(a=a.replace(j,b.series.yaxis.tickFormatter(d,b.series.yaxis).replace(/\$/g,"$$"))),a},c.prototype.isTimeMode=function(a,b){return"undefined"!=typeof b.series[a].options.mode&&"time"===b.series[a].options.mode},c.prototype.isXDateFormat=function(){return"undefined"!=typeof this.tooltipOptions.xDateFormat&&null!==this.tooltipOptions.xDateFormat},c.prototype.isYDateFormat=function(){return"undefined"!=typeof this.tooltipOptions.yDateFormat&&null!==this.tooltipOptions.yDateFormat},c.prototype.isCategoriesMode=function(a,b){return"undefined"!=typeof b.series[a].options.mode&&"categories"===b.series[a].options.mode},c.prototype.timestampToDate=function(b,c){var d=new Date(1*b);return a.plot.formatDate(d,c,this.tooltipOptions.monthNames,this.tooltipOptions.dayNames)},c.prototype.adjustValPrecision=function(a,b,c){var d,e=b.match(a);return null!==e&&""!==RegExp.$1&&(d=RegExp.$1,c=c.toFixed(d),b=b.replace(a,c)),b};var d=function(a){new c(a)};a.plot.plugins.push({init:d,options:b,name:"tooltip",version:"0.6.6"})}(jQuery);
@@ -1,4 +1,4 @@
1
1
  module Graffable
2
- VERSION = '0.0.2'
2
+ VERSION = '0.0.3'
3
3
  end
4
4
 
@@ -1,16 +1,16 @@
1
1
  %html
2
2
  %head
3
3
  %meta{ name: 'viewport', content: 'width=device-width, initial-scale=1.0' }
4
- %link{ rel: 'stylesheet', type: 'text/css', href: '//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css' }
4
+ %link{ rel: 'stylesheet', type: 'text/css', href: '//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/css/bootstrap.min.css' }
5
5
  %link{ rel: 'stylesheet', type: 'text/css', href: url('/stylesheets/graffable.css') }
6
- %title= 'Metrics'
6
+ %title= @title ? "Metrics - #{ @title }" : 'Metrics'
7
7
  %body
8
- %script{ type: 'text/javascript', src: '//cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js' }
9
- %script{ type: 'text/javascript', src: '//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js' }
8
+ %script{ type: 'text/javascript', src: '//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js' }
9
+ %script{ type: 'text/javascript', src: '//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/js/bootstrap.min.js' }
10
10
  %script{ type: 'text/javascript', src: '//cdnjs.cloudflare.com/ajax/libs/flot/0.8.2/jquery.flot.min.js' }
11
11
  %script{ type: 'text/javascript', src: '//cdnjs.cloudflare.com/ajax/libs/flot/0.8.2/jquery.flot.categories.min.js' }
12
12
  %script{ type: 'text/javascript', src: '//cdnjs.cloudflare.com/ajax/libs/flot/0.8.2/jquery.flot.stack.min.js' }
13
- %script{ type: 'text/javascript', src: url('/javascript/jquery.flot.tooltip.min-0.6.5.js') }
13
+ %script{ type: 'text/javascript', src: url('/javascript/jquery.flot.tooltip.min-0.6.6.js') }
14
14
 
15
15
  %nav.navbar.navbar-default{ role: 'navigation' }
16
16
  .navbar-header
@@ -50,12 +50,15 @@
50
50
  - url = "/#{ @group[:name] }/#{ @report[:name] }"
51
51
  - year = Time.now.year
52
52
  - month = Time.now.strftime("%m")
53
+ - day = DateTime.now.strftime("%d")
53
54
  %li
54
55
  %a{ href: url(url) } Recent
55
56
  %li
56
57
  %a{ href: url("#{url}/#{year}") }= year
57
58
  %li
58
59
  %a{ href: url("#{url}/#{year}/#{month}") }= "#{year}-#{month}"
60
+ %li
61
+ %a{ href: url("#{url}/#{year}/#{month}/#{day}") }= "#{year}-#{month}-#{day}"
59
62
 
60
63
  .container
61
64
  .flash
@@ -3,14 +3,18 @@
3
3
  - if @previous
4
4
  %a{ href: url(@previous) }
5
5
  %span.glyphicon.glyphicon-chevron-left
6
- %h1{ style: 'display: inline; padding: 0em 1em;' }= @report[:description]
6
+ %h1{ style: 'display: inline; padding: 0em 1em;' }= @title || @report[:description]
7
7
  - if @next
8
8
  %a{ href: url(@next) }
9
9
  %span.glyphicon.glyphicon-chevron-right
10
10
 
11
11
  #content{ style: 'align: center; margin: auto; padding: 1em; width: 95%;' }
12
12
  #placeholder{ style: 'align: center; height: 75%; margin: auto; padding: 1em; width: 95%;' }
13
- #legend{ style: 'padding-bottom: 1em;' }
13
+ #footer
14
+ %span#legend{ style: 'float: left; padding-bottom: 1em;' }
15
+ - if @report[:txt]
16
+ %span#accordion{ style: 'float: right; padding-bottom: 5em;' }
17
+ %span= @report[:txt]
14
18
 
15
19
  :javascript
16
20
  data_url = "#{ url(@data_url) }";
@@ -51,8 +55,13 @@
51
55
  var data = [];
52
56
 
53
57
  function onDataReceived(series) {
54
- // TODO options['yaxis'] = { max: series['max'], min: series['min'], tickDecimals: 0 }
55
- $.plot( "#placeholder", series.data, options );
58
+ if ( 'undefined' == typeof series.data || ( series.data instanceof Array && 0 == series.data.length ) ) {
59
+ $('#placeholder').html("<p style='color: red' alignment='center'>No data available for this time period</p>");
60
+ }
61
+ else {
62
+ $.plot( "#placeholder", series.data.sort( function(a,b) { return b.total - a.total } ), options );
63
+ $( "#accordion" ).accordion( { active: false, collapsible: true } ); // XXX
64
+ }
56
65
  }
57
66
 
58
67
  $.ajax({
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graffable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - blair christensen.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-06 00:00:00.000000000 Z
11
+ date: 2014-03-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: haml
@@ -94,6 +94,34 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '1.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: dotenv
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: foreman
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
97
125
  - !ruby/object:Gem::Dependency
98
126
  name: rake
99
127
  requirement: !ruby/object:Gem::Requirement
@@ -133,13 +161,14 @@ files:
133
161
  - CHANGES.md
134
162
  - Gemfile
135
163
  - LICENSE.txt
164
+ - Procfile
136
165
  - README.md
137
166
  - Rakefile
138
- - TODO.md
139
167
  - config.ru
140
168
  - db/migrations/001_create_groups.rb
141
169
  - db/migrations/002_create_reports.rb
142
170
  - db/migrations/003_create_numbers.rb
171
+ - db/migrations/004_add_reports_txt.rb
143
172
  - graffable.gemspec
144
173
  - lib/graffable.rb
145
174
  - lib/graffable/app.rb
@@ -147,7 +176,7 @@ files:
147
176
  - lib/graffable/importer.rb
148
177
  - lib/graffable/migration_task.rb
149
178
  - lib/graffable/public/favicon.ico
150
- - lib/graffable/public/javascript/jquery.flot.tooltip.min-0.6.5.js
179
+ - lib/graffable/public/javascript/jquery.flot.tooltip.min-0.6.6.js
151
180
  - lib/graffable/public/stylesheets/graffable.css
152
181
  - lib/graffable/seed_task.rb
153
182
  - lib/graffable/version.rb
data/TODO.md DELETED
@@ -1,9 +0,0 @@
1
- Graffable To Do
2
- ===============
3
- # `GET /groups.json`
4
- # `GET /groups`
5
- # `GET /:group.json`
6
- # `GET /:group`
7
- # `GET /:group/:report.json`
8
- # `GET /:group/:report`
9
-
@@ -1,12 +0,0 @@
1
- /*
2
- * jquery.flot.tooltip
3
- *
4
- * description: easy-to-use tooltips for Flot charts
5
- * version: 0.6.5
6
- * author: Krzysztof Urbas @krzysu [myviews.pl]
7
- * website: https://github.com/krzysu/flot.tooltip
8
- *
9
- * build on 2014-01-23
10
- * released under MIT License, 2012
11
- */
12
- (function(t){var i={tooltip:!1,tooltipOpts:{content:"%s | X: %x | Y: %y",xDateFormat:null,yDateFormat:null,monthNames:null,dayNames:null,shifts:{x:10,y:20},defaultTheme:!0,onHover:function(){}}},o=function(t){this.tipPosition={x:0,y:0},this.init(t)};o.prototype.init=function(i){function o(t){var i={};i.x=t.pageX,i.y=t.pageY,s.updateTooltipPosition(i)}function e(t,i,o){var e=s.getDomElement();if(o){var n;n=s.stringFormat(s.tooltipOptions.content,o),e.html(n),s.updateTooltipPosition({x:i.pageX,y:i.pageY}),e.css({left:s.tipPosition.x+s.tooltipOptions.shifts.x,top:s.tipPosition.y+s.tooltipOptions.shifts.y}).show(),"function"==typeof s.tooltipOptions.onHover&&s.tooltipOptions.onHover(o,e)}else e.hide().html("")}var s=this;i.hooks.bindEvents.push(function(i,n){s.plotOptions=i.getOptions(),s.plotOptions.tooltip!==!1&&void 0!==s.plotOptions.tooltip&&(s.tooltipOptions=s.plotOptions.tooltipOpts,s.getDomElement(),t(i.getPlaceholder()).bind("plothover",e),t(n).bind("mousemove",o))}),i.hooks.shutdown.push(function(i,s){t(i.getPlaceholder()).unbind("plothover",e),t(s).unbind("mousemove",o)})},o.prototype.getDomElement=function(){var i;return t("#flotTip").length>0?i=t("#flotTip"):(i=t("<div />").attr("id","flotTip"),i.appendTo("body").hide().css({position:"absolute"}),this.tooltipOptions.defaultTheme&&i.css({background:"#fff","z-index":"100",padding:"0.4em 0.6em","border-radius":"0.5em","font-size":"0.8em",border:"1px solid #111",display:"none","white-space":"nowrap"})),i},o.prototype.updateTooltipPosition=function(i){var o=t("#flotTip").outerWidth()+this.tooltipOptions.shifts.x,e=t("#flotTip").outerHeight()+this.tooltipOptions.shifts.y;i.x-t(window).scrollLeft()>t(window).innerWidth()-o&&(i.x-=o),i.y-t(window).scrollTop()>t(window).innerHeight()-e&&(i.y-=e),this.tipPosition.x=i.x,this.tipPosition.y=i.y},o.prototype.stringFormat=function(t,i){var o,e,s=/%p\.{0,1}(\d{0,})/,n=/%s/,p=/%x\.{0,1}(\d{0,})/,a=/%y\.{0,1}(\d{0,})/,r="%x",l="%y";return i.series.threshold!==void 0?(o=i.datapoint[0],e=i.datapoint[1]):(o=i.series.data[i.dataIndex][0],e=i.series.data[i.dataIndex][1]),null===i.series.label&&i.series.originSeries&&(i.series.label=i.series.originSeries.label),"function"==typeof t&&(t=t(i.series.label,o,e,i)),i.series.percent!==void 0&&(t=this.adjustValPrecision(s,t,i.series.percent)),t=i.series.label!==void 0?t.replace(n,i.series.label):t.replace(n,""),this.isTimeMode("xaxis",i)&&this.isXDateFormat(i)&&(t=t.replace(p,this.timestampToDate(o,this.tooltipOptions.xDateFormat))),this.isTimeMode("yaxis",i)&&this.isYDateFormat(i)&&(t=t.replace(a,this.timestampToDate(e,this.tooltipOptions.yDateFormat))),"number"==typeof o&&(t=this.adjustValPrecision(p,t,o)),"number"==typeof e&&(t=this.adjustValPrecision(a,t,e)),i.series.xaxis.ticks!==void 0&&i.series.xaxis.ticks.length>i.dataIndex&&!this.isTimeMode("xaxis",i)&&(t=t.replace(p,i.series.xaxis.ticks[i.dataIndex].label)),i.series.xaxis.tickFormatter!==void 0&&(t=t.replace(r,i.series.xaxis.tickFormatter(o,i.series.xaxis).replace(/\$/g,"$$"))),i.series.yaxis.tickFormatter!==void 0&&(t=t.replace(l,i.series.yaxis.tickFormatter(e,i.series.yaxis).replace(/\$/g,"$$"))),t},o.prototype.isTimeMode=function(t,i){return i.series[t].options.mode!==void 0&&"time"===i.series[t].options.mode},o.prototype.isXDateFormat=function(){return this.tooltipOptions.xDateFormat!==void 0&&null!==this.tooltipOptions.xDateFormat},o.prototype.isYDateFormat=function(){return this.tooltipOptions.yDateFormat!==void 0&&null!==this.tooltipOptions.yDateFormat},o.prototype.timestampToDate=function(i,o){var e=new Date(1*i);return t.plot.formatDate(e,o,this.tooltipOptions.monthNames,this.tooltipOptions.dayNames)},o.prototype.adjustValPrecision=function(t,i,o){var e,s=i.match(t);return null!==s&&""!==RegExp.$1&&(e=RegExp.$1,o=o.toFixed(e),i=i.replace(t,o)),i};var e=function(t){new o(t)};t.plot.plugins.push({init:e,options:i,name:"tooltip",version:"0.6.1"})})(jQuery);