ifttt-gdash 0.0.5 → 0.0.7

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,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- ZGU3ZjlhYTQ1ZGVkOTlhMTgwZGVjNzU2MzZkNmFjNGYzN2ViMTY0Yw==
5
- data.tar.gz: !binary |-
6
- NjczNGNiZGYyNTY2NzZmOWJmMWZjN2FiZDVkNTdiNmI5ZThmZWM0MA==
2
+ SHA1:
3
+ metadata.gz: a905ac9bf55f0dcf3f1e033d6f994592f453578f
4
+ data.tar.gz: 668819d176f3a2e3ac0a0971d73bc7bfa1839ad3
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- MDNmNjgyNjNjNWIyZjRjMTYzMzg1YmFkNDQ1YjM4NDZlYzA2YTFkNjBiNTQ0
10
- OGFiNzczOTUxOGMxNzI5MDM0YzljMjM5YzJiZWY3NTI5YWJhMzQzMTgwZmE4
11
- MWQ3NTg2MzViNDViNDMzMDIwZGY0NTJmMTExMGQ5YjBkOWI2NjE=
12
- data.tar.gz: !binary |-
13
- OGIyZGRkYjc2MDNmMDViYjkzYjZhMjY5ZjQ1MjRhZDA0MGYxZmVhMzJhOThk
14
- ZGI0YjU3YzBiOTFhZmY4MTk2ZjJlYjQ1NzI2OGIwZmNlNDU0Y2Y2NzQxZWVl
15
- MTYzNmIwZmRlOWIzMjgwNTQwNmYxNWQxNjU3NjQ0MGRkYmZkNTM=
6
+ metadata.gz: b3924408b437fcadd12d50a1900266fb002e18177285b9690162dc2bf2dd55a257f315e1a73764411fa435d7ae0625d458ba82226c0f4f67af1f277a698cd478
7
+ data.tar.gz: 21a0514bb3ccfa2c553cf73fa1f9dcd67af640935865b6fec76bde7e5734f856a237fa1266b1b6b1ffc0064e4170f3df1e01d89bf205bae9e547f49a3820d73d
data/lib/gdash.rb ADDED
@@ -0,0 +1,56 @@
1
+ require 'rubygems'
2
+ require 'sinatra/base'
3
+ require 'yaml'
4
+ require 'erb'
5
+ require 'redcarpet'
6
+
7
+ class GDash
8
+ require 'gdash/dashboard'
9
+ require 'gdash/monkey_patches'
10
+ require 'gdash/sinatra_app'
11
+ require 'graphite_graph'
12
+
13
+ attr_reader :graphite_base, :graphite_render, :dash_templates, :height, :width, :from, :until
14
+
15
+ def initialize(graphite_base, render_url, dash_templates, options={})
16
+ @graphite_base = graphite_base
17
+ @graphite_render = [@graphite_base, "/render/"].join
18
+ @dash_templates = dash_templates
19
+ @height = options.delete(:height)
20
+ @width = options.delete(:width)
21
+ @from = options.delete(:from)
22
+ @until = options.delete(:until)
23
+
24
+ raise "Dashboard templates directory #{@dash_templates} does not exist" unless File.directory?(@dash_templates)
25
+ end
26
+
27
+ def dashboard(name, options={})
28
+ options[:width] ||= @width
29
+ options[:height] ||= @height
30
+ options[:from] ||= @from
31
+ options[:until] ||= @until
32
+
33
+ Dashboard.new(name, dash_templates, options)
34
+ end
35
+
36
+ def list
37
+ dashboards.map {|dash| dash[:link]}
38
+ end
39
+
40
+ def dashboards
41
+ dashboards = []
42
+
43
+ Dir.entries(dash_templates).each do |dash|
44
+ begin
45
+ yaml_file = File.join(dash_templates, dash, "dash.yaml")
46
+ if File.exist?(yaml_file)
47
+ dashboards << YAML.load_file(yaml_file).merge({:link => dash})
48
+ end
49
+ rescue Exception => e
50
+ p e
51
+ end
52
+ end
53
+
54
+ dashboards.sort_by{|d| d[:name].to_s}
55
+ end
56
+ end
@@ -0,0 +1,52 @@
1
+ class GDash
2
+ class Dashboard
3
+ attr_accessor :properties
4
+
5
+ def initialize(short_name, dir, options={})
6
+ raise "Cannot find dashboard directory #{dir}" unless File.directory?(dir)
7
+
8
+ @properties = {:graph_width => nil,
9
+ :graph_height => nil,
10
+ :graph_from => nil,
11
+ :graph_until => nil}
12
+
13
+ @properties[:short_name] = short_name
14
+ @properties[:directory] = File.join(dir, short_name)
15
+ @properties[:yaml] = File.join(dir, short_name, "dash.yaml")
16
+
17
+ raise "Cannot find YAML file #{yaml}" unless File.exist?(yaml)
18
+
19
+ @properties.merge!(YAML.load_file(yaml))
20
+
21
+ # Properties defined in dashboard config file are overridden when given on initialization
22
+ @properties[:graph_width] = options.delete(:width) || graph_width
23
+ @properties[:graph_height] = options.delete(:height) || graph_height
24
+ @properties[:graph_from] = options.delete(:from) || graph_from
25
+ @properties[:graph_until] = options.delete(:until) || graph_until
26
+ @properties[:options] = options
27
+ end
28
+
29
+ def graphs(options={})
30
+ options[:width] ||= graph_width
31
+ options[:height] ||= graph_height
32
+ options[:from] ||= graph_from
33
+ options[:until] ||= graph_until
34
+
35
+ graphs = Dir.entries(directory).select{|f| f.match(/\.graph$/)}
36
+
37
+ overrides = options.reject { |k,v| v.nil? }
38
+
39
+ graphs.sort.map do |graph|
40
+ {:name => File.basename(graph, ".graph"), :graphite => GraphiteGraph.new(File.join(directory, graph), overrides)}
41
+ end
42
+ end
43
+
44
+ def method_missing(method, *args)
45
+ if properties.include?(method)
46
+ properties[method]
47
+ else
48
+ super
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,37 @@
1
+ class Array
2
+ def in_groups_of(chunk_size, padded_with=nil)
3
+ if chunk_size <= 1
4
+ if block_given?
5
+ self.each{|a| yield([a])}
6
+ else
7
+ self
8
+ end
9
+ else
10
+ arr = self.clone
11
+
12
+ # how many to add
13
+ padding = chunk_size - (arr.size % chunk_size)
14
+ padding = 0 if padding == chunk_size
15
+
16
+ # pad at the end
17
+ arr.concat([padded_with] * padding)
18
+
19
+ # how many chunks we'll make
20
+ count = arr.size / chunk_size
21
+
22
+ # make that many arrays
23
+ result = []
24
+ count.times {|s| result << arr[s * chunk_size, chunk_size]}
25
+
26
+ if block_given?
27
+ result.each{|a| yield(a)}
28
+ else
29
+ result
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ class GraphiteGraph
36
+ attr_accessor :properties, :file
37
+ end
@@ -0,0 +1,202 @@
1
+ class GDash
2
+ class SinatraApp < ::Sinatra::Base
3
+ def initialize(graphite_base, graph_templates, options = {})
4
+ # where the whisper data is
5
+ @whisper_dir = options.delete(:whisper_dir) || "/var/lib/carbon/whisper"
6
+
7
+ # where graphite lives
8
+ @graphite_base = graphite_base
9
+
10
+ # where the graphite renderer is
11
+ @graphite_render = [@graphite_base, "/render/"].join
12
+
13
+ # where to find graph, dash etc templates
14
+ @graph_templates = graph_templates
15
+
16
+ # the dash site might have a prefix for its css etc
17
+ @prefix = options.delete(:prefix) || ""
18
+
19
+ # the page refresh rate
20
+ @refresh_rate = options.delete(:refresh_rate) || 60
21
+
22
+ # how many columns of graphs do you want on a page
23
+ @graph_columns = options.delete(:graph_columns) || 2
24
+
25
+ # how wide each graph should be
26
+ @graph_width = options.delete(:graph_width)
27
+
28
+ # how hight each graph sould be
29
+ @graph_height = options.delete(:graph_height)
30
+
31
+ # Dashboard title
32
+ @dash_title = options.delete(:title) || "Graphite Dashboard"
33
+
34
+ # Time filters in interface
35
+ @interval_filters = options.delete(:interval_filters) || Array.new
36
+
37
+ @intervals = options.delete(:intervals) || []
38
+
39
+ @top_level = Hash.new
40
+ Dir.entries(@graph_templates).each do |category|
41
+ if File.directory?("#{@graph_templates}/#{category}")
42
+ unless ("#{category}" =~ /^\./ )
43
+ @top_level["#{category}"] = GDash.new(@graphite_base, "/render/", File.join(@graph_templates, "/#{category}"), {:width => @graph_width, :height => @graph_height})
44
+ end
45
+ end
46
+ end
47
+
48
+ super()
49
+ end
50
+
51
+ set :static, true
52
+ set :views, File.join(File.expand_path(File.dirname(__FILE__)), "../..", "views")
53
+ if Sinatra.const_defined?("VERSION") && Gem::Version.new(Sinatra::VERSION) >= Gem::Version.new("1.3.0")
54
+ set :public_folder, File.join(File.expand_path(File.dirname(__FILE__)), "../..", "public")
55
+ else
56
+ set :public, File.join(File.expand_path(File.dirname(__FILE__)), "../..", "public")
57
+ end
58
+
59
+ get '/' do
60
+ if @top_level.empty?
61
+ @error = "No dashboards found in the templates directory"
62
+ end
63
+
64
+ erb :index
65
+ end
66
+
67
+ get '/:category/:dash/details/:name' do
68
+ options = query_params.except(:from, :until)
69
+ if @top_level["#{params[:category]}"].list.include?(params[:dash])
70
+ @dashboard = @top_level[@params[:category]].dashboard(params[:dash], options)
71
+ else
72
+ @error = "No dashboard called #{params[:dash]} found in #{params[:category]}/#{@top_level[params[:category]].list.join ','}."
73
+ end
74
+
75
+ if @intervals.empty?
76
+ @error = "No intervals defined in configuration"
77
+ end
78
+
79
+ if main_graph = @dashboard.graphs[params[:name].to_i][:graphite]
80
+ @graphs = @intervals.map do |e|
81
+ new_props = {:from => e[0], :title => "#{main_graph.properties[:title]} - #{e[1]}"}
82
+ new_props = main_graph.properties.merge new_props
83
+ GraphiteGraph.new(main_graph.file, new_props)
84
+ end
85
+ else
86
+ @error = "No such graph available"
87
+ end
88
+
89
+ erb :detailed_dashboard
90
+ end
91
+
92
+ get '/:category/:dash/full/?*' do
93
+ options = {}
94
+ params["splat"] = params["splat"].first.split("/")
95
+
96
+ params["columns"] = params["splat"][0].to_i || @graph_columns
97
+
98
+ if params["splat"].size == 3
99
+ options[:width] = params["splat"][1].to_i
100
+ options[:height] = params["splat"][2].to_i
101
+ else
102
+ options[:width] = @graph_width
103
+ options[:height] = @graph_height
104
+ end
105
+
106
+ options.merge!(query_params)
107
+
108
+ if @top_level["#{params[:category]}"].list.include?(params[:dash])
109
+ @dashboard = @top_level[@params[:category]].dashboard(params[:dash], options)
110
+ else
111
+ @error = "No dashboard called #{params[:dash]} found in #{params[:category]}/#{@top_level[params[:category]].list.join ','}"
112
+ end
113
+
114
+ erb :full_size_dashboard, :layout => false
115
+ end
116
+
117
+ get '/:category/:dash/?*' do
118
+ options = {}
119
+ params["splat"] = params["splat"].first.split("/")
120
+
121
+ case params["splat"][0]
122
+ when 'time'
123
+ options[:from] = params["splat"][1] || "-1hour"
124
+ options[:until] = params["splat"][2] || "now"
125
+ end
126
+
127
+ options.merge!(query_params)
128
+
129
+ if @top_level["#{params[:category]}"].list.include?(params[:dash])
130
+ @dashboard = @top_level[@params[:category]].dashboard(params[:dash], options)
131
+ else
132
+ @error = "No dashboard called #{params[:dash]} found in #{params[:category]}/#{@top_level[params[:category]].list.join ','}."
133
+ end
134
+
135
+ erb :dashboard
136
+ end
137
+
138
+ get '/docs/' do
139
+ markdown :README, :layout_engine => :erb
140
+ end
141
+
142
+ helpers do
143
+ include Rack::Utils
144
+
145
+ alias_method :h, :escape_html
146
+
147
+ def current_top_level
148
+ @top_level[@params[:category]]
149
+ end
150
+
151
+ def query_params
152
+ hash = {}
153
+ protected_keys = [:category, :dash, :splat]
154
+
155
+ params.each do |k, v|
156
+ hash[k.to_sym] = v unless protected_keys.include?(k.to_sym)
157
+ end
158
+
159
+ hash
160
+ end
161
+
162
+ def uri_to_dashboard(dash, options = {})
163
+ category = options[:category] || params[:category]
164
+ if options[:from]
165
+ uri = URI([@prefix, category, dash, 'time', h(options[:from]), h(options[:to])].join('/'))
166
+ else
167
+ uri = URI([@prefix, category, dash].join('/'))
168
+ end
169
+ query = request.query_string.empty? ? {} : Rack::Utils.parse_nested_query(request.query_string)
170
+ query.merge!((options[:query] || {}).stringify_keys)
171
+ uri.query = query.to_query unless query.empty?
172
+ uri.to_s
173
+ end
174
+
175
+ def uri_to_interval(options)
176
+ uri = URI([@prefix, params[:category], params[:dash], 'time', h(options[:from]), h(options[:to])].join('/'))
177
+ uri.query = request.query_string unless request.query_string.empty?
178
+ uri.to_s
179
+ end
180
+
181
+ def link_to_interval(options)
182
+ "<a href=\"#{ uri_to_interval(options) }\">#{ h(options[:label]) }</a>"
183
+ end
184
+
185
+ def uri_to_details(index)
186
+ uri = URI([@prefix, params[:category], @params[:dash], 'details', index].join('/'))
187
+ uri.query = request.query_string unless request.query_string.empty?
188
+ uri.to_s
189
+ end
190
+
191
+ # To be overriden by base classes, should they so desire.
192
+ # @dashboard holds the dashboard
193
+ def dashboard_preheader; ''; end
194
+ def dashboard_header; ''; end
195
+ def graph_caption(graph); ''; end
196
+ end
197
+
198
+ before do
199
+ content_type :html, 'charset' => 'utf-8'
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,104 @@
1
+ /* ==========================================================
2
+ * bootstrap-alerts.js v1.3.0
3
+ * http://twitter.github.com/bootstrap/javascript.html#alerts
4
+ * ==========================================================
5
+ * Copyright 2011 Twitter, Inc.
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ * ========================================================== */
19
+
20
+
21
+ !function( $ ){
22
+
23
+ /* CSS TRANSITION SUPPORT (https://gist.github.com/373874)
24
+ * ======================================================= */
25
+
26
+ var transitionEnd
27
+
28
+ $(document).ready(function () {
29
+
30
+ $.support.transition = (function () {
31
+ var thisBody = document.body || document.documentElement
32
+ , thisStyle = thisBody.style
33
+ , support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined
34
+ return support
35
+ })()
36
+
37
+ // set CSS transition event type
38
+ if ( $.support.transition ) {
39
+ transitionEnd = "TransitionEnd"
40
+ if ( $.browser.webkit ) {
41
+ transitionEnd = "webkitTransitionEnd"
42
+ } else if ( $.browser.mozilla ) {
43
+ transitionEnd = "transitionend"
44
+ } else if ( $.browser.opera ) {
45
+ transitionEnd = "oTransitionEnd"
46
+ }
47
+ }
48
+
49
+ })
50
+
51
+ /* ALERT CLASS DEFINITION
52
+ * ====================== */
53
+
54
+ var Alert = function ( content, selector ) {
55
+ this.$element = $(content)
56
+ .delegate(selector || '.close', 'click', this.close)
57
+ }
58
+
59
+ Alert.prototype = {
60
+
61
+ close: function (e) {
62
+ var $element = $(this).parent('.alert-message')
63
+
64
+ e && e.preventDefault()
65
+ $element.removeClass('in')
66
+
67
+ function removeElement () {
68
+ $element.remove()
69
+ }
70
+
71
+ $.support.transition && $element.hasClass('fade') ?
72
+ $element.bind(transitionEnd, removeElement) :
73
+ removeElement()
74
+ }
75
+
76
+ }
77
+
78
+
79
+ /* ALERT PLUGIN DEFINITION
80
+ * ======================= */
81
+
82
+ $.fn.alert = function ( options ) {
83
+
84
+ if ( options === true ) {
85
+ return this.data('alert')
86
+ }
87
+
88
+ return this.each(function () {
89
+ var $this = $(this)
90
+
91
+ if ( typeof options == 'string' ) {
92
+ return $this.data('alert')[options]()
93
+ }
94
+
95
+ $(this).data('alert', new Alert( this ))
96
+
97
+ })
98
+ }
99
+
100
+ $(document).ready(function () {
101
+ new Alert($('body'), '.alert-message[data-alert] .close')
102
+ })
103
+
104
+ }( window.jQuery || window.ender );