jnewland-god_web 0.0.2 → 0.1.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/Readme.textile ADDED
@@ -0,0 +1,82 @@
1
+ h2. Description
2
+
3
+ iPhone friendly web UI "God":http://god.rubyforge.org/
4
+
5
+ h2. Screenshots
6
+
7
+ "!http://farm3.static.flickr.com/2281/2505507050_2f8fc39795_m.jpg!":http://www.flickr.com/photos/jnewland/2505507050/
8
+ "!http://farm3.static.flickr.com/2420/2504730261_06ac1ba923_m.jpg!":http://www.flickr.com/photos/jnewland/2504730261/
9
+
10
+ h2. Requirements
11
+
12
+ * "God":http://god.rubyforge.org/
13
+ * "Sinatra":http://sinatrarb.com/
14
+
15
+ h2. Install
16
+
17
+ <pre>
18
+ <code>
19
+ git clone git://github.com/jnewland/god_web.git
20
+ cd god_web
21
+ gem build god_web.gemspec
22
+ sudo gem install -l god_web-*.gem
23
+ </code>
24
+ </pre>
25
+
26
+ h2. Usage
27
+
28
+ In your God config:
29
+
30
+ <pre>
31
+ <code>
32
+ require 'god_web'
33
+ GodWeb.watch
34
+ </code>
35
+ </pre>
36
+
37
+ This will create a God watch that runs and monitors GodWeb on port 8888.
38
+
39
+ Optionally, you can password protect your @god_web@ instance. To do so, create
40
+ a YAML config file with username and password keys, like so:
41
+
42
+ <pre>
43
+ <code>
44
+ username: foo
45
+ password: sekret
46
+ </code>
47
+ </pre>
48
+
49
+ Then provide the full path to that yaml file as an option to the @GodWeb.watch@
50
+ call:
51
+
52
+ <pre>
53
+ <code>
54
+ require 'god_web'
55
+ GodWeb.watch(:config => '/full/path/to/god_web.yaml')
56
+ </code>
57
+ </pre>
58
+
59
+ h2. Contributing
60
+
61
+ god_web uses "ditz":http://ditz.rubyforge.org for issue tracking. Fork
62
+ god_web, clone your copy and then run:
63
+
64
+ @ditz todo@
65
+
66
+ For more details on a specific issue:
67
+
68
+ @ditz show god_web-1@
69
+
70
+ Make your changes that fix a bug, then resolve it.
71
+
72
+ @ditz close god_web-1@
73
+
74
+ Commit, push your changes to GitHub, then send a pull request!
75
+
76
+ h3. Author
77
+
78
+ "Jesse Newland":http://jnewland.com/
79
+
80
+ h3. License
81
+
82
+ "WTFPL":http://sam.zoy.org/wtfpl/
data/bin/god_web CHANGED
@@ -1,36 +1,57 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'rubygems'
4
- require 'god'
5
- require 'sinatra'
6
- require 'stringio'
7
- require 'yaml'
8
- #included until http://sinatra.lighthouseapp.com/projects/9779/tickets/16-patch-http-authentication is in a released version
9
- require File.dirname(__FILE__) + '/../lib/sinatra_http_auth'
10
-
11
- config = {
12
- 'god_port' => 17165,
13
- 'username' => nil,
14
- 'password' => nil
15
- }
16
- begin
17
- config.merge!(YAML.load(File.read(ARGV[0])))
18
- rescue
19
- end
3
+ require File.dirname(__FILE__) + '/../lib/environment'
20
4
 
21
5
  before do
22
- unless config['username'].nil? && config['password'].nil?
6
+ unless (GODWEB_CONFIG['username'].nil? && GODWEB_CONFIG['password'].nil?) || self.request.path_info == '/heartbeat'
23
7
  authenticate_or_request_with_http_basic "GodWeb" do
24
- |user, pass| user == config['username'] && pass == config['password']
8
+ |user, pass| user == GODWEB_CONFIG['username'] && pass == GODWEB_CONFIG['password']
25
9
  end
26
10
  end
11
+ GODWEB.ping
27
12
  end
28
13
 
29
14
  get '/' do
30
- io = StringIO.new
31
- $stdout = io
32
- response.header['Content-Type'] = 'text/plain'
33
- God::CLI::Command.new('status', {:port => config['god_port']}, [])
34
- $stdout = STDOUT
35
- io.string
15
+ @statuses = GODWEB.status
16
+ @watches = []
17
+ @statuses.each do |watch, status|
18
+ @watches << watch.to_s
19
+ end
20
+ @watches.sort!
21
+ @groups = GODWEB.groups
22
+ show(:status)
23
+ end
24
+
25
+ get '/w/:watch' do
26
+ @watch = params["watch"]
27
+ @status = GODWEB.status[@watch][:state]
28
+ @commands = GodWeb.possible_statuses(@status)
29
+ show(:watch, "#{@watch} [#{@status}]")
36
30
  end
31
+
32
+ get '/g/:group' do
33
+ @watch = @group = params["group"]
34
+ @status = nil
35
+ @commands = GodWeb.possible_statuses(@status)
36
+ show(:watch, "#{@group} [group]")
37
+ end
38
+
39
+ get '/w/:watch/:command' do
40
+ @watch = params["watch"]
41
+ @command = params["command"]
42
+ @success = GODWEB.send(@command, @watch)
43
+ @success = false if @success == []
44
+ show(:command, "#{@command}ing #{@watch}")
45
+ end
46
+
47
+ get '/heartbeat' do
48
+ @statuses = GODWEB.status
49
+ 'OK'
50
+ end
51
+
52
+ private
53
+
54
+ def show(template, title = 'GodWeb')
55
+ @title = title
56
+ erb(template)
57
+ end
@@ -0,0 +1,26 @@
1
+ require 'rubygems'
2
+ require 'god'
3
+ require 'sinatra'
4
+ require 'stringio'
5
+ require 'yaml'
6
+ require 'erb'
7
+ #included until http://sinatra.lighthouseapp.com/projects/9779/tickets/16-patch-http-authentication is in a released version
8
+ require File.dirname(__FILE__) + '/sinatra_http_auth'
9
+ require File.dirname(__FILE__) + '/god_web'
10
+
11
+ config = {
12
+ 'god_port' => 17165,
13
+ 'username' => nil,
14
+ 'password' => nil
15
+ }
16
+ begin
17
+ config.merge!(YAML.load(File.read(ARGV[0])))
18
+ GODWEB_CONFIG = config
19
+ rescue
20
+ GODWEB_CONFIG = config
21
+ end
22
+
23
+ GODWEB = GodWeb.new(config)
24
+
25
+ Sinatra.application.options.public = File.dirname(__FILE__) + "/../public"
26
+ Sinatra.application.options.views = File.dirname(__FILE__) + "/../views"
data/lib/god_web.rb ADDED
@@ -0,0 +1,165 @@
1
+ class GodWeb
2
+ def initialize(config)
3
+ @config = config
4
+ setup
5
+ ping
6
+ end
7
+
8
+ def self.watch(options = {})
9
+ options[:port] ||= 8888
10
+ options[:environment] ||= 'production'
11
+ start_string = "god_web #{options[:config]} -e #{options[:environment]} -p #{options[:port]}"
12
+ God.watch do |w|
13
+ w.name = "god_web"
14
+ w.interval = 1.minute
15
+ w.start = "god_web -e production -p 8888"
16
+ w.start_grace = 10.seconds
17
+ w.restart_grace = 10.seconds
18
+
19
+ w.start_if do |start|
20
+ start.condition(:process_running) do |c|
21
+ c.running = false
22
+ end
23
+ end
24
+
25
+ w.restart_if do |restart|
26
+ restart.condition(:memory_usage) do |c|
27
+ c.above = 20.megabytes
28
+ c.times = [3, 5]
29
+ end
30
+
31
+ restart.condition(:cpu_usage) do |c|
32
+ c.above = 25.percent
33
+ c.times = 5
34
+ end
35
+ end
36
+
37
+ w.lifecycle do |on|
38
+ on.condition(:flapping) do |c|
39
+ c.to_state = [:start, :restart]
40
+ c.times = 5
41
+ c.within = 5.minute
42
+ c.transition = :unmonitored
43
+ c.retry_in = 10.minutes
44
+ c.retry_times = 5
45
+ c.retry_within = 2.hours
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ def setup
52
+ DRb.start_service
53
+ @server = DRbObject.new(nil, God::Socket.socket(@config['god_port']))
54
+ end
55
+
56
+ # ping server to ensure that it is responsive
57
+ def ping
58
+ tries = 3
59
+ begin
60
+ @server.ping
61
+ rescue Exception => e
62
+ if (tries -= 1) > 0
63
+ retry
64
+ end
65
+ raise e, "The server is not available (or you do not have permissions to access it)"
66
+ end
67
+ end
68
+
69
+ def self.possible_statuses(status)
70
+ case status
71
+ when :up
72
+ return %w{stop restart unmonitor}
73
+ when :unmonitored
74
+ return %w{start monitor}
75
+ else
76
+ return %w{start stop restart}
77
+ end
78
+ end
79
+
80
+ private
81
+
82
+ def method_missing(meth,*args)
83
+ if %w{groups status log quit terminate}.include?(meth.to_s)
84
+ ping
85
+ send("#{meth}_command")
86
+ elsif %w{start stop restart unmonitor monitor}.include?(meth.to_s)
87
+ ping
88
+ lifecycle_command(args.first, meth.to_s)
89
+ else
90
+ raise NoMethodError
91
+ end
92
+ end
93
+
94
+ def groups_command
95
+ groups = []
96
+ @server.groups.each do |key, value|
97
+ groups << key
98
+ end
99
+ groups.sort
100
+ end
101
+
102
+ def status_command
103
+ @server.status
104
+ end
105
+
106
+ #TODO
107
+ # def log_command
108
+ # begin
109
+ # Signal.trap('INT') { exit }
110
+ # name = @args[1]
111
+ #
112
+ # unless name
113
+ # puts "You must specify a Task or Group name"
114
+ # exit!
115
+ # end
116
+ #
117
+ # t = Time.at(0)
118
+ # loop do
119
+ # print @server.running_log(name, t)
120
+ # t = Time.now
121
+ # sleep 1
122
+ # end
123
+ # rescue God::NoSuchWatchError
124
+ # puts "No such watch"
125
+ # rescue DRb::DRbConnError
126
+ # puts "The server went away"
127
+ # end
128
+ # end
129
+
130
+ def quit_command
131
+ begin
132
+ @server.terminate
133
+ return false
134
+ rescue DRb::DRbConnError
135
+ return true
136
+ end
137
+ end
138
+
139
+ def terminate_command
140
+ stopped_all = false
141
+ if @server.stop_all
142
+ stopped_all = true
143
+ end
144
+
145
+ begin
146
+ @server.terminate
147
+ return false
148
+ rescue DRb::DRbConnError
149
+ return stopped_all
150
+ end
151
+ end
152
+
153
+
154
+ def lifecycle_command(*args)
155
+ # get the name of the watch/group
156
+ name = args.first
157
+ command = args.last
158
+
159
+ # send @command
160
+ watches = @server.control(name, command)
161
+
162
+ watches.empty? ? [] : watches
163
+ end
164
+
165
+ end
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,372 @@
1
+ /* iui.css (c) 2007 by iUI Project Members, see LICENSE.txt for license */
2
+ body {
3
+ margin: 0;
4
+ font-family: Helvetica;
5
+ background: #FFFFFF;
6
+ color: #000000;
7
+ overflow-x: hidden;
8
+ -webkit-user-select: none;
9
+ -webkit-text-size-adjust: none;
10
+ }
11
+
12
+ body > *:not(.toolbar) {
13
+ display: none;
14
+ position: absolute;
15
+ margin: 0;
16
+ padding: 0;
17
+ left: 0;
18
+ top: 45px;
19
+ width: 100%;
20
+ min-height: 372px;
21
+ }
22
+
23
+ body[orient="landscape"] > *:not(.toolbar) {
24
+ min-height: 268px;
25
+ }
26
+
27
+ body > *[selected="true"] {
28
+ display: block;
29
+ }
30
+
31
+ a[selected], a:active {
32
+ background-color: #194fdb !important;
33
+ background-image: url(listArrowSel.png), url(selection.png) !important;
34
+ background-repeat: no-repeat, repeat-x;
35
+ background-position: right center, left top;
36
+ color: #FFFFFF !important;
37
+ }
38
+
39
+ a[selected="progress"] {
40
+ background-image: url(loading.gif), url(selection.png) !important;
41
+ }
42
+
43
+ /************************************************************************************************/
44
+
45
+ body > .toolbar {
46
+ box-sizing: border-box;
47
+ -moz-box-sizing: border-box;
48
+ -webkit-box-sizing: border-box;
49
+ border-bottom: 1px solid #2d3642;
50
+ border-top: 1px solid #6d84a2;
51
+ padding: 10px;
52
+ height: 45px;
53
+ background: url(toolbar.png) #6d84a2 repeat-x;
54
+ }
55
+
56
+ .toolbar > h1 {
57
+ position: absolute;
58
+ overflow: hidden;
59
+ left: 50%;
60
+ margin: 1px 0 0 -75px;
61
+ height: 45px;
62
+ font-size: 20px;
63
+ width: 150px;
64
+ font-weight: bold;
65
+ text-shadow: rgba(0, 0, 0, 0.4) 0px -1px 0;
66
+ text-align: center;
67
+ text-overflow: ellipsis;
68
+ white-space: nowrap;
69
+ color: #FFFFFF;
70
+ }
71
+
72
+ body[orient="landscape"] > .toolbar > h1 {
73
+ margin-left: -125px;
74
+ width: 250px;
75
+ }
76
+
77
+ .button {
78
+ position: absolute;
79
+ overflow: hidden;
80
+ top: 8px;
81
+ right: 6px;
82
+ margin: 0;
83
+ border-width: 0 5px;
84
+ padding: 0 3px;
85
+ width: auto;
86
+ height: 30px;
87
+ line-height: 30px;
88
+ font-family: inherit;
89
+ font-size: 12px;
90
+ font-weight: bold;
91
+ color: #FFFFFF;
92
+ text-shadow: rgba(0, 0, 0, 0.6) 0px -1px 0;
93
+ text-overflow: ellipsis;
94
+ text-decoration: none;
95
+ white-space: nowrap;
96
+ background: none;
97
+ -webkit-border-image: url(toolButton.png) 0 5 0 5;
98
+ }
99
+
100
+ .blueButton {
101
+ -webkit-border-image: url(blueButton.png) 0 5 0 5;
102
+ border-width: 0 5px;
103
+ }
104
+
105
+ .leftButton {
106
+ left: 6px;
107
+ right: auto;
108
+ }
109
+
110
+ #backButton {
111
+ display: none;
112
+ left: 6px;
113
+ right: auto;
114
+ padding: 0;
115
+ max-width: 55px;
116
+ border-width: 0 8px 0 14px;
117
+ -webkit-border-image: url(backButton.png) 0 8 0 14;
118
+ }
119
+
120
+ .whiteButton,
121
+ .grayButton {
122
+ display: block;
123
+ border-width: 0 12px;
124
+ padding: 10px;
125
+ text-align: center;
126
+ font-size: 20px;
127
+ font-weight: bold;
128
+ text-decoration: inherit;
129
+ color: inherit;
130
+ }
131
+
132
+ .whiteButton {
133
+ -webkit-border-image: url(whiteButton.png) 0 12 0 12;
134
+ text-shadow: rgba(255, 255, 255, 0.7) 0 1px 0;
135
+ }
136
+
137
+ .grayButton {
138
+ -webkit-border-image: url(grayButton.png) 0 12 0 12;
139
+ color: #FFFFFF;
140
+ }
141
+
142
+ /************************************************************************************************/
143
+
144
+ body > ul > li {
145
+ position: relative;
146
+ margin: 0;
147
+ border-bottom: 1px solid #E0E0E0;
148
+ padding: 8px 0 8px 10px;
149
+ font-size: 20px;
150
+ font-weight: bold;
151
+ list-style: none;
152
+ }
153
+
154
+ body > ul > li.group {
155
+ position: relative;
156
+ top: -1px;
157
+ margin-bottom: -2px;
158
+ border-top: 1px solid #7d7d7d;
159
+ border-bottom: 1px solid #999999;
160
+ padding: 1px 10px;
161
+ background: url(listGroup.png) repeat-x;
162
+ font-size: 17px;
163
+ font-weight: bold;
164
+ text-shadow: rgba(0, 0, 0, 0.4) 0 1px 0;
165
+ color: #FFFFFF;
166
+ }
167
+
168
+ body > ul > li.group:first-child {
169
+ top: 0;
170
+ border-top: none;
171
+ }
172
+
173
+ body > ul > li > a {
174
+ display: block;
175
+ margin: -8px 0 -8px -10px;
176
+ padding: 8px 32px 8px 10px;
177
+ text-decoration: none;
178
+ color: inherit;
179
+ background: url(listArrow.png) no-repeat right center;
180
+ }
181
+
182
+ a[target="_replace"] {
183
+ box-sizing: border-box;
184
+ -webkit-box-sizing: border-box;
185
+ padding-top: 25px;
186
+ padding-bottom: 25px;
187
+ font-size: 18px;
188
+ color: cornflowerblue;
189
+ background-color: #FFFFFF;
190
+ background-image: none;
191
+ }
192
+
193
+ /************************************************************************************************/
194
+
195
+ body > .dialog {
196
+ top: 0;
197
+ width: 100%;
198
+ min-height: 417px;
199
+ z-index: 2;
200
+ background: rgba(0, 0, 0, 0.8);
201
+ padding: 0;
202
+ text-align: right;
203
+ }
204
+
205
+ .dialog > fieldset {
206
+ box-sizing: border-box;
207
+ -webkit-box-sizing: border-box;
208
+ width: 100%;
209
+ margin: 0;
210
+ border: none;
211
+ border-top: 1px solid #6d84a2;
212
+ padding: 10px 6px;
213
+ background: url(toolbar.png) #7388a5 repeat-x;
214
+ }
215
+
216
+ .dialog > fieldset > h1 {
217
+ margin: 0 10px 0 10px;
218
+ padding: 0;
219
+ font-size: 20px;
220
+ font-weight: bold;
221
+ color: #FFFFFF;
222
+ text-shadow: rgba(0, 0, 0, 0.4) 0px -1px 0;
223
+ text-align: center;
224
+ }
225
+
226
+ .dialog > fieldset > label {
227
+ position: absolute;
228
+ margin: 16px 0 0 6px;
229
+ font-size: 14px;
230
+ color: #999999;
231
+ }
232
+
233
+ input {
234
+ box-sizing: border-box;
235
+ -webkit-box-sizing: border-box;
236
+ width: 100%;
237
+ margin: 8px 0 0 0;
238
+ padding: 6px 6px 6px 44px;
239
+ font-size: 16px;
240
+ font-weight: normal;
241
+ }
242
+
243
+ /************************************************************************************************/
244
+
245
+ body > .panel {
246
+ box-sizing: border-box;
247
+ -webkit-box-sizing: border-box;
248
+ padding: 10px;
249
+ background: #c8c8c8 url(pinstripes.png);
250
+ }
251
+
252
+ .panel > fieldset {
253
+ position: relative;
254
+ margin: 0 0 20px 0;
255
+ padding: 0;
256
+ background: #FFFFFF;
257
+ -webkit-border-radius: 10px;
258
+ border: 1px solid #999999;
259
+ text-align: right;
260
+ font-size: 16px;
261
+ }
262
+
263
+ .row {
264
+ position: relative;
265
+ min-height: 42px;
266
+ border-bottom: 1px solid #999999;
267
+ -webkit-border-radius: 0;
268
+ text-align: right;
269
+ }
270
+
271
+ fieldset > .row:last-child {
272
+ border-bottom: none !important;
273
+ }
274
+
275
+ .row > input {
276
+ box-sizing: border-box;
277
+ -webkit-box-sizing: border-box;
278
+ margin: 0;
279
+ border: none;
280
+ padding: 12px 10px 0 110px;
281
+ height: 42px;
282
+ background: none;
283
+ }
284
+
285
+ .row > label {
286
+ position: absolute;
287
+ margin: 0 0 0 14px;
288
+ line-height: 42px;
289
+ font-weight: bold;
290
+ }
291
+
292
+ .row > .toggle {
293
+ position: absolute;
294
+ top: 6px;
295
+ right: 6px;
296
+ width: 100px;
297
+ height: 28px;
298
+ }
299
+
300
+ .toggle {
301
+ border: 1px solid #888888;
302
+ -webkit-border-radius: 6px;
303
+ background: #FFFFFF url(toggle.png) repeat-x;
304
+ font-size: 19px;
305
+ font-weight: bold;
306
+ line-height: 30px;
307
+ }
308
+
309
+ .toggle[toggled="true"] {
310
+ border: 1px solid #143fae;
311
+ background: #194fdb url(toggleOn.png) repeat-x;
312
+ }
313
+
314
+ .toggleOn {
315
+ display: none;
316
+ position: absolute;
317
+ width: 60px;
318
+ text-align: center;
319
+ left: 0;
320
+ top: 0;
321
+ color: #FFFFFF;
322
+ text-shadow: rgba(0, 0, 0, 0.4) 0px -1px 0;
323
+ }
324
+
325
+ .toggleOff {
326
+ position: absolute;
327
+ width: 60px;
328
+ text-align: center;
329
+ right: 0;
330
+ top: 0;
331
+ color: #666666;
332
+ }
333
+
334
+ .toggle[toggled="true"] > .toggleOn {
335
+ display: block;
336
+ }
337
+
338
+ .toggle[toggled="true"] > .toggleOff {
339
+ display: none;
340
+ }
341
+
342
+ .thumb {
343
+ position: absolute;
344
+ top: -1px;
345
+ left: -1px;
346
+ width: 40px;
347
+ height: 28px;
348
+ border: 1px solid #888888;
349
+ -webkit-border-radius: 6px;
350
+ background: #ffffff url(thumb.png) repeat-x;
351
+ }
352
+
353
+ .toggle[toggled="true"] > .thumb {
354
+ left: auto;
355
+ right: -1px;
356
+ }
357
+
358
+ .panel > h2 {
359
+ margin: 0 0 8px 14px;
360
+ font-size: inherit;
361
+ font-weight: bold;
362
+ color: #4d4d70;
363
+ text-shadow: rgba(255, 255, 255, 0.75) 2px 2px 0;
364
+ }
365
+
366
+ /************************************************************************************************/
367
+
368
+ #preloader {
369
+ display: none;
370
+ background-image: url(loading.gif), url(selection.png),
371
+ url(blueButton.png), url(listArrowSel.png), url(listGroup.png);
372
+ }
data/public/iui/iui.js ADDED
@@ -0,0 +1,383 @@
1
+ /*
2
+ Copyright (c) 2007, iUI Project Members
3
+ See LICENSE.txt for licensing terms
4
+ */
5
+
6
+
7
+ (function() {
8
+
9
+ var slideSpeed = 20;
10
+ var slideInterval = 0;
11
+
12
+ var currentPage = null;
13
+ var currentDialog = null;
14
+ var currentWidth = 0;
15
+ var currentHash = location.hash;
16
+ var hashPrefix = "#_";
17
+ var pageHistory = [];
18
+ var newPageCount = 0;
19
+ var checkTimer;
20
+
21
+ // *************************************************************************************************
22
+
23
+ window.iui =
24
+ {
25
+ showPage: function(page, backwards)
26
+ {
27
+ if (page)
28
+ {
29
+ if (currentDialog)
30
+ {
31
+ currentDialog.removeAttribute("selected");
32
+ currentDialog = null;
33
+ }
34
+
35
+ if (hasClass(page, "dialog"))
36
+ showDialog(page);
37
+ else
38
+ {
39
+ var fromPage = currentPage;
40
+ currentPage = page;
41
+
42
+ if (fromPage)
43
+ setTimeout(slidePages, 0, fromPage, page, backwards);
44
+ else
45
+ updatePage(page, fromPage);
46
+ }
47
+ }
48
+ },
49
+
50
+ showPageById: function(pageId)
51
+ {
52
+ var page = $(pageId);
53
+ if (page)
54
+ {
55
+ var index = pageHistory.indexOf(pageId);
56
+ var backwards = index != -1;
57
+ if (backwards)
58
+ pageHistory.splice(index, pageHistory.length);
59
+
60
+ iui.showPage(page, backwards);
61
+ }
62
+ },
63
+
64
+ showPageByHref: function(href, args, method, replace, cb)
65
+ {
66
+ var req = new XMLHttpRequest();
67
+ req.onerror = function()
68
+ {
69
+ if (cb)
70
+ cb(false);
71
+ };
72
+
73
+ req.onreadystatechange = function()
74
+ {
75
+ if (req.readyState == 4)
76
+ {
77
+ if (replace)
78
+ replaceElementWithSource(replace, req.responseText);
79
+ else
80
+ {
81
+ var frag = document.createElement("div");
82
+ frag.innerHTML = req.responseText;
83
+ iui.insertPages(frag.childNodes);
84
+ }
85
+ if (cb)
86
+ setTimeout(cb, 1000, true);
87
+ }
88
+ };
89
+
90
+ if (args)
91
+ {
92
+ req.open(method || "GET", href, true);
93
+ req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
94
+ req.setRequestHeader("Content-Length", args.length);
95
+ req.send(args.join("&"));
96
+ }
97
+ else
98
+ {
99
+ req.open(method || "GET", href, true);
100
+ req.send(null);
101
+ }
102
+ },
103
+
104
+ insertPages: function(nodes)
105
+ {
106
+ var targetPage;
107
+ for (var i = 0; i < nodes.length; ++i)
108
+ {
109
+ var child = nodes[i];
110
+ if (child.nodeType == 1)
111
+ {
112
+ if (!child.id)
113
+ child.id = "__" + (++newPageCount) + "__";
114
+
115
+ var clone = $(child.id);
116
+ if (clone)
117
+ clone.parentNode.replaceChild(child, clone);
118
+ else
119
+ document.body.appendChild(child);
120
+
121
+ if (child.getAttribute("selected") == "true" || !targetPage)
122
+ targetPage = child;
123
+
124
+ --i;
125
+ }
126
+ }
127
+
128
+ if (targetPage)
129
+ iui.showPage(targetPage);
130
+ },
131
+
132
+ getSelectedPage: function()
133
+ {
134
+ for (var child = document.body.firstChild; child; child = child.nextSibling)
135
+ {
136
+ if (child.nodeType == 1 && child.getAttribute("selected") == "true")
137
+ return child;
138
+ }
139
+ }
140
+ };
141
+
142
+ // *************************************************************************************************
143
+
144
+ addEventListener("load", function(event)
145
+ {
146
+ var page = iui.getSelectedPage();
147
+ if (page)
148
+ iui.showPage(page);
149
+
150
+ setTimeout(preloadImages, 0);
151
+ setTimeout(checkOrientAndLocation, 0);
152
+ checkTimer = setInterval(checkOrientAndLocation, 300);
153
+ }, false);
154
+
155
+ addEventListener("click", function(event)
156
+ {
157
+ var link = findParent(event.target, "a");
158
+ if (link)
159
+ {
160
+ function unselect() { link.removeAttribute("selected"); }
161
+
162
+ if (link.href && link.hash && link.hash != "#")
163
+ {
164
+ link.setAttribute("selected", "true");
165
+ iui.showPage($(link.hash.substr(1)));
166
+ setTimeout(unselect, 500);
167
+ }
168
+ else if (link == $("backButton"))
169
+ history.back();
170
+ else if (link.getAttribute("type") == "submit")
171
+ submitForm(findParent(link, "form"));
172
+ else if (link.getAttribute("type") == "cancel")
173
+ cancelDialog(findParent(link, "form"));
174
+ else if (link.target == "_replace")
175
+ {
176
+ link.setAttribute("selected", "progress");
177
+ iui.showPageByHref(link.href, null, null, link, unselect);
178
+ }
179
+ else if (!link.target)
180
+ {
181
+ link.setAttribute("selected", "progress");
182
+ iui.showPageByHref(link.href, null, null, null, unselect);
183
+ }
184
+ else
185
+ return;
186
+
187
+ event.preventDefault();
188
+ }
189
+ }, true);
190
+
191
+ addEventListener("click", function(event)
192
+ {
193
+ var div = findParent(event.target, "div");
194
+ if (div && hasClass(div, "toggle"))
195
+ {
196
+ div.setAttribute("toggled", div.getAttribute("toggled") != "true");
197
+ event.preventDefault();
198
+ }
199
+ }, true);
200
+
201
+ function checkOrientAndLocation()
202
+ {
203
+ if (window.innerWidth != currentWidth)
204
+ {
205
+ currentWidth = window.innerWidth;
206
+ var orient = currentWidth == 320 ? "profile" : "landscape";
207
+ document.body.setAttribute("orient", orient);
208
+ setTimeout(scrollTo, 100, 0, 1);
209
+ }
210
+
211
+ if (location.hash != currentHash)
212
+ {
213
+ var pageId = location.hash.substr(hashPrefix.length)
214
+ iui.showPageById(pageId);
215
+ }
216
+ }
217
+
218
+ function showDialog(page)
219
+ {
220
+ currentDialog = page;
221
+ page.setAttribute("selected", "true");
222
+
223
+ if (hasClass(page, "dialog") && !page.target)
224
+ showForm(page);
225
+ }
226
+
227
+ function showForm(form)
228
+ {
229
+ form.onsubmit = function(event)
230
+ {
231
+ event.preventDefault();
232
+ submitForm(form);
233
+ };
234
+
235
+ form.onclick = function(event)
236
+ {
237
+ if (event.target == form && hasClass(form, "dialog"))
238
+ cancelDialog(form);
239
+ };
240
+ }
241
+
242
+ function cancelDialog(form)
243
+ {
244
+ form.removeAttribute("selected");
245
+ }
246
+
247
+ function updatePage(page, fromPage)
248
+ {
249
+ if (!page.id)
250
+ page.id = "__" + (++newPageCount) + "__";
251
+
252
+ location.href = currentHash = hashPrefix + page.id;
253
+ pageHistory.push(page.id);
254
+
255
+ var pageTitle = $("pageTitle");
256
+ if (page.title)
257
+ pageTitle.innerHTML = page.title;
258
+
259
+ if (page.localName.toLowerCase() == "form" && !page.target)
260
+ showForm(page);
261
+
262
+ var backButton = $("backButton");
263
+ if (backButton)
264
+ {
265
+ var prevPage = $(pageHistory[pageHistory.length-2]);
266
+ if (prevPage && !page.getAttribute("hideBackButton"))
267
+ {
268
+ backButton.style.display = "inline";
269
+ backButton.innerHTML = prevPage.title ? prevPage.title : "Back";
270
+ }
271
+ else
272
+ backButton.style.display = "none";
273
+ }
274
+ }
275
+
276
+ function slidePages(fromPage, toPage, backwards)
277
+ {
278
+ var axis = (backwards ? fromPage : toPage).getAttribute("axis");
279
+ if (axis == "y")
280
+ (backwards ? fromPage : toPage).style.top = "100%";
281
+ else
282
+ toPage.style.left = "100%";
283
+
284
+ toPage.setAttribute("selected", "true");
285
+ scrollTo(0, 1);
286
+ clearInterval(checkTimer);
287
+
288
+ var percent = 100;
289
+ slide();
290
+ var timer = setInterval(slide, slideInterval);
291
+
292
+ function slide()
293
+ {
294
+ percent -= slideSpeed;
295
+ if (percent <= 0)
296
+ {
297
+ percent = 0;
298
+ if (!hasClass(toPage, "dialog"))
299
+ fromPage.removeAttribute("selected");
300
+ clearInterval(timer);
301
+ checkTimer = setInterval(checkOrientAndLocation, 300);
302
+ setTimeout(updatePage, 0, toPage, fromPage);
303
+ }
304
+
305
+ if (axis == "y")
306
+ {
307
+ backwards
308
+ ? fromPage.style.top = (100-percent) + "%"
309
+ : toPage.style.top = percent + "%";
310
+ }
311
+ else
312
+ {
313
+ fromPage.style.left = (backwards ? (100-percent) : (percent-100)) + "%";
314
+ toPage.style.left = (backwards ? -percent : percent) + "%";
315
+ }
316
+ }
317
+ }
318
+
319
+ function preloadImages()
320
+ {
321
+ var preloader = document.createElement("div");
322
+ preloader.id = "preloader";
323
+ document.body.appendChild(preloader);
324
+ }
325
+
326
+ function submitForm(form)
327
+ {
328
+ iui.showPageByHref(form.action || "POST", encodeForm(form), form.method);
329
+ }
330
+
331
+ function encodeForm(form)
332
+ {
333
+ function encode(inputs)
334
+ {
335
+ for (var i = 0; i < inputs.length; ++i)
336
+ {
337
+ if (inputs[i].name)
338
+ args.push(inputs[i].name + "=" + escape(inputs[i].value));
339
+ }
340
+ }
341
+
342
+ var args = [];
343
+ encode(form.getElementsByTagName("input"));
344
+ encode(form.getElementsByTagName("select"));
345
+ return args;
346
+ }
347
+
348
+ function findParent(node, localName)
349
+ {
350
+ while (node && (node.nodeType != 1 || node.localName.toLowerCase() != localName))
351
+ node = node.parentNode;
352
+ return node;
353
+ }
354
+
355
+ function hasClass(self, name)
356
+ {
357
+ var re = new RegExp("(^|\\s)"+name+"($|\\s)");
358
+ return re.exec(self.getAttribute("class")) != null;
359
+ }
360
+
361
+ function replaceElementWithSource(replace, source)
362
+ {
363
+ var page = replace.parentNode;
364
+ var parent = replace;
365
+ while (page.parentNode != document.body)
366
+ {
367
+ page = page.parentNode;
368
+ parent = parent.parentNode;
369
+ }
370
+
371
+ var frag = document.createElement(parent.localName);
372
+ frag.innerHTML = source;
373
+
374
+ page.removeChild(parent);
375
+
376
+ while (frag.firstChild)
377
+ page.appendChild(frag.firstChild);
378
+ }
379
+
380
+ function $(id) { return document.getElementById(id); }
381
+ function ddd() { console.log.apply(console, arguments); }
382
+
383
+ })();
@@ -0,0 +1 @@
1
+ body{margin:0;font-family:Helvetica;background:#FFF;color:#000;overflow-x:hidden;-webkit-user-select:none;-webkit-text-size-adjust:none;}body>*:not(.toolbar){display:none;position:absolute;margin:0;padding:0;left:0;top:45px;width:100%;min-height:372px;}body[orient="landscape"]>*:not(.toolbar){min-height:268px;}body>*[selected="true"]{display:block;}a[selected],a:active{background-color:#194fdb!important;background-image:url(listArrowSel.png),url(selection.png)!important;background-repeat:no-repeat,repeat-x;background-position:right center,left top;color:#FFF!important;}a[selected="progress"]{background-image:url(loading.gif),url(selection.png)!important;}body>.toolbar{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;border-bottom:1px solid #2d3642;border-top:1px solid #6d84a2;padding:10px;height:45px;background:url(toolbar.png) #6d84a2 repeat-x;}.toolbar>h1{position:absolute;overflow:hidden;left:50%;margin:1px 0 0 -75px;height:45px;font-size:20px;width:150px;font-weight:bold;text-shadow:rgba(0,0,0,0.4) 0 -1px 0;text-align:center;text-overflow:ellipsis;white-space:nowrap;color:#FFF;}body[orient="landscape"]>.toolbar>h1{margin-left:-125px;width:250px;}.button{position:absolute;overflow:hidden;top:8px;right:6px;margin:0;border-width:0 5px;padding:0 3px;width:auto;height:30px;line-height:30px;font-family:inherit;font-size:12px;font-weight:bold;color:#FFF;text-shadow:rgba(0,0,0,0.6) 0 -1px 0;text-overflow:ellipsis;text-decoration:none;white-space:nowrap;background:none;-webkit-border-image:url(toolButton.png) 0 5 0 5;}.blueButton{-webkit-border-image:url(blueButton.png) 0 5 0 5;border-width:0 5px;}.leftButton{left:6px;right:auto;}#backButton{display:none;left:6px;right:auto;padding:0;max-width:55px;border-width:0 8px 0 14px;-webkit-border-image:url(backButton.png) 0 8 0 14;}.whiteButton,.grayButton{display:block;border-width:0 12px;padding:10px;text-align:center;font-size:20px;font-weight:bold;text-decoration:inherit;color:inherit;}.whiteButton{-webkit-border-image:url(whiteButton.png) 0 12 0 12;text-shadow:rgba(255,255,255,0.7) 0 1px 0;}.grayButton{-webkit-border-image:url(grayButton.png) 0 12 0 12;color:#FFF;}body>ul>li{position:relative;margin:0;border-bottom:1px solid #E0E0E0;padding:8px 0 8px 10px;font-size:20px;font-weight:bold;list-style:none;}body>ul>li.group{position:relative;top:-1px;margin-bottom:-2px;border-top:1px solid #7d7d7d;border-bottom:1px solid #999;padding:1px 10px;background:url(listGroup.png) repeat-x;font-size:17px;font-weight:bold;text-shadow:rgba(0,0,0,0.4) 0 1px 0;color:#FFF;}body>ul>li.group:first-child{top:0;border-top:none;}body>ul>li>a{display:block;margin:-8px 0 -8px -10px;padding:8px 32px 8px 10px;text-decoration:none;color:inherit;background:url(listArrow.png) no-repeat right center;}a[target="_replace"]{box-sizing:border-box;-webkit-box-sizing:border-box;padding-top:25px;padding-bottom:25px;font-size:18px;color:cornflowerblue;background-color:#FFF;background-image:none;}body>.dialog{top:0;width:100%;min-height:417px;z-index:2;background:rgba(0,0,0,0.8);padding:0;text-align:right;}.dialog>fieldset{box-sizing:border-box;-webkit-box-sizing:border-box;width:100%;margin:0;border:none;border-top:1px solid #6d84a2;padding:10px 6px;background:url(toolbar.png) #7388a5 repeat-x;}.dialog>fieldset>h1{margin:0 10px 0 10px;padding:0;font-size:20px;font-weight:bold;color:#FFF;text-shadow:rgba(0,0,0,0.4) 0 -1px 0;text-align:center;}.dialog>fieldset>label{position:absolute;margin:16px 0 0 6px;font-size:14px;color:#999;}input{box-sizing:border-box;-webkit-box-sizing:border-box;width:100%;margin:8px 0 0 0;padding:6px 6px 6px 44px;font-size:16px;font-weight:normal;}body>.panel{box-sizing:border-box;-webkit-box-sizing:border-box;padding:10px;background:#c8c8c8 url(pinstripes.png);}.panel>fieldset{position:relative;margin:0 0 20px 0;padding:0;background:#FFF;-webkit-border-radius:10px;border:1px solid #999;text-align:right;font-size:16px;}.row{position:relative;min-height:42px;border-bottom:1px solid #999;-webkit-border-radius:0;text-align:right;}fieldset>.row:last-child{border-bottom:none!important;}.row>input{box-sizing:border-box;-webkit-box-sizing:border-box;margin:0;border:none;padding:12px 10px 0 110px;height:42px;background:none;}.row>label{position:absolute;margin:0 0 0 14px;line-height:42px;font-weight:bold;}.row>.toggle{position:absolute;top:6px;right:6px;width:100px;height:28px;}.toggle{border:1px solid #888;-webkit-border-radius:6px;background:#FFF url(toggle.png) repeat-x;font-size:19px;font-weight:bold;line-height:30px;}.toggle[toggled="true"]{border:1px solid #143fae;background:#194fdb url(toggleOn.png) repeat-x;}.toggleOn{display:none;position:absolute;width:60px;text-align:center;left:0;top:0;color:#FFF;text-shadow:rgba(0,0,0,0.4) 0 -1px 0;}.toggleOff{position:absolute;width:60px;text-align:center;right:0;top:0;color:#666;}.toggle[toggled="true"]>.toggleOn{display:block;}.toggle[toggled="true"]>.toggleOff{display:none;}.thumb{position:absolute;top:-1px;left:-1px;width:40px;height:28px;border:1px solid #888;-webkit-border-radius:6px;background:#fff url(thumb.png) repeat-x;}.toggle[toggled="true"]>.thumb{left:auto;right:-1px;}.panel>h2{margin:0 0 8px 14px;font-size:inherit;font-weight:bold;color:#4d4d70;text-shadow:rgba(255,255,255,0.75) 2px 2px 0;}#preloader{display:none;background-image:url(loading.gif),url(selection.png),url(blueButton.png),url(listArrowSel.png),url(listGroup.png);}
@@ -0,0 +1 @@
1
+ (function(){var _1=20;var _2=0;var _3=null;var _4=null;var _5=0;var _6=location.hash;var _7="#_";var _8=[];var _9=0;var _a;window.iui={showPage:function(_b,_c){if(_b){if(_4){_4.removeAttribute("selected");_4=null;}if(hasClass(_b,"dialog")){showDialog(_b);}else{var _d=_3;_3=_b;if(_d){setTimeout(slidePages,0,_d,_b,_c);}else{updatePage(_b,_d);}}}},showPageById:function(_e){var _f=$(_e);if(_f){var _10=_8.indexOf(_e);var _11=_10!=-1;if(_11){_8.splice(_10,_8.length);}iui.showPage(_f,_11);}},showPageByHref:function(_12,_13,_14,_15,cb){var req=new XMLHttpRequest();req.onerror=function(){if(cb){cb(false);}};req.onreadystatechange=function(){if(req.readyState==4){if(_15){replaceElementWithSource(_15,req.responseText);}else{var _18=document.createElement("div");_18.innerHTML=req.responseText;iui.insertPages(_18.childNodes);}if(cb){setTimeout(cb,1000,true);}}};if(_13){req.open(_14||"GET",_12,true);req.setRequestHeader("Content-Type","application/x-www-form-urlencoded");req.setRequestHeader("Content-Length",_13.length);req.send(_13.join("&"));}else{req.open(_14||"GET",_12,true);req.send(null);}},insertPages:function(_19){var _1a;for(var i=0;i<_19.length;++i){var _1c=_19[i];if(_1c.nodeType==1){if(!_1c.id){_1c.id="__"+(++_9)+"__";}var _1d=$(_1c.id);if(_1d){_1d.parentNode.replaceChild(_1c,_1d);}else{document.body.appendChild(_1c);}if(_1c.getAttribute("selected")=="true"||!_1a){_1a=_1c;}--i;}}if(_1a){iui.showPage(_1a);}},getSelectedPage:function(){for(var _1e=document.body.firstChild;_1e;_1e=_1e.nextSibling){if(_1e.nodeType==1&&_1e.getAttribute("selected")=="true"){return _1e;}}}};addEventListener("load",function(_1f){var _20=iui.getSelectedPage();if(_20){iui.showPage(_20);}setTimeout(preloadImages,0);setTimeout(checkOrientAndLocation,0);_a=setInterval(checkOrientAndLocation,300);},false);addEventListener("click",function(_21){var _22=findParent(_21.target,"a");if(_22){function unselect(){_22.removeAttribute("selected");}if(_22.href&&_22.hash&&_22.hash!="#"){_22.setAttribute("selected","true");iui.showPage($(_22.hash.substr(1)));setTimeout(unselect,500);}else{if(_22==$("backButton")){history.back();}else{if(_22.getAttribute("type")=="submit"){submitForm(findParent(_22,"form"));}else{if(_22.getAttribute("type")=="cancel"){cancelDialog(findParent(_22,"form"));}else{if(_22.target=="_replace"){_22.setAttribute("selected","progress");iui.showPageByHref(_22.href,null,null,_22,unselect);}else{if(!_22.target){_22.setAttribute("selected","progress");iui.showPageByHref(_22.href,null,null,null,unselect);}else{return;}}}}}}_21.preventDefault();}},true);addEventListener("click",function(_23){var div=findParent(_23.target,"div");if(div&&hasClass(div,"toggle")){div.setAttribute("toggled",div.getAttribute("toggled")!="true");_23.preventDefault();}},true);function checkOrientAndLocation(){if(window.innerWidth!=_5){_5=window.innerWidth;var _25=_5==320?"profile":"landscape";document.body.setAttribute("orient",_25);setTimeout(scrollTo,100,0,1);}if(location.hash!=_6){var _26=location.hash.substr(_7.length);iui.showPageById(_26);}}function showDialog(_27){_4=_27;_27.setAttribute("selected","true");if(hasClass(_27,"dialog")&&!_27.target){showForm(_27);}}function showForm(_28){_28.onsubmit=function(_29){_29.preventDefault();submitForm(_28);};_28.onclick=function(_2a){if(_2a.target==_28&&hasClass(_28,"dialog")){cancelDialog(_28);}};}function cancelDialog(_2b){_2b.removeAttribute("selected");}function updatePage(_2c,_2d){if(!_2c.id){_2c.id="__"+(++_9)+"__";}location.href=_6=_7+_2c.id;_8.push(_2c.id);var _2e=$("pageTitle");if(_2c.title){_2e.innerHTML=_2c.title;}if(_2c.localName.toLowerCase()=="form"&&!_2c.target){showForm(_2c);}var _2f=$("backButton");if(_2f){var _30=$(_8[_8.length-2]);if(_30&&!_2c.getAttribute("hideBackButton")){_2f.style.display="inline";_2f.innerHTML=_30.title?_30.title:"Back";}else{_2f.style.display="none";}}}function slidePages(_31,_32,_33){var _34=(_33?_31:_32).getAttribute("axis");if(_34=="y"){(_33?_31:_32).style.top="100%";}else{_32.style.left="100%";}_32.setAttribute("selected","true");scrollTo(0,1);clearInterval(_a);var _35=100;slide();var _36=setInterval(slide,_2);function slide(){_35-=_1;if(_35<=0){_35=0;if(!hasClass(_32,"dialog")){_31.removeAttribute("selected");}clearInterval(_36);_a=setInterval(checkOrientAndLocation,300);setTimeout(updatePage,0,_32,_31);}if(_34=="y"){_33?_31.style.top=(100-_35)+"%":_32.style.top=_35+"%";}else{_31.style.left=(_33?(100-_35):(_35-100))+"%";_32.style.left=(_33?-_35:_35)+"%";}}}function preloadImages(){var _37=document.createElement("div");_37.id="preloader";document.body.appendChild(_37);}function submitForm(_38){iui.showPageByHref(_38.action||"POST",encodeForm(_38),_38.method);}function encodeForm(_39){function encode(_3a){for(var i=0;i<_3a.length;++i){if(_3a[i].name){args.push(_3a[i].name+"="+escape(_3a[i].value));}}}var _3c=[];encode(_39.getElementsByTagName("input"));encode(_39.getElementsByTagName("select"));return _3c;}function findParent(_3d,_3e){while(_3d&&(_3d.nodeType!=1||_3d.localName.toLowerCase()!=_3e)){_3d=_3d.parentNode;}return _3d;}function hasClass(_3f,_40){var re=new RegExp("(^|\\s)"+_40+"($|\\s)");return re.exec(_3f.getAttribute("class"))!=null;}function replaceElementWithSource(_42,_43){var _44=_42.parentNode;var _45=_42;while(_44.parentNode!=document.body){_44=_44.parentNode;_45=_45.parentNode;}var _46=document.createElement(_45.localName);_46.innerHTML=_43;_44.removeChild(_45);while(_46.firstChild){_44.appendChild(_46.firstChild);}}function $(id){return document.getElementById(id);}function ddd(){console.log.apply(console,arguments);}})();
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
data/views/command.erb ADDED
@@ -0,0 +1,3 @@
1
+ <div id="<%= @command %>ing_<%= @watch %>" class="panel" title="<%= @title %>">
2
+ <h2><%= @success ? 'Success' : 'Failed' %></h2>
3
+ </div>
data/views/status.erb ADDED
@@ -0,0 +1,27 @@
1
+ <html>
2
+ <head>
3
+ <title><%= @title %></title>
4
+ <meta name="viewport" content="width=320; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/>
5
+ <style type="text/css" media="screen">@import "/iui/iui.css";</style>
6
+ <script type="application/x-javascript" src="/iui/iui.js"></script>
7
+ </head>
8
+ <body>
9
+ <div class="toolbar">
10
+ <h1 id="pageTitle"><%= @title %></h1>
11
+ <a id="backButton" class="button" href="#"></a>
12
+ <a class="button" href="/" target="_self">Refresh</a>
13
+ </div>
14
+ <ul id="home" selected="true" title="GodWeb">
15
+ <% unless @groups.empty? %>
16
+ <li class="group">Groups</li>
17
+ <% @groups.each do |watch| %>
18
+ <li id="<%= watch %>"><a href="/g/<%= watch %>"><%= watch %></a></li>
19
+ <% end %>
20
+ <% end %>
21
+ <li class="group">Watches</li>
22
+ <% @watches.each do |watch| %>
23
+ <li id="<%= watch %>" class="<%= @statuses[watch][:state] %>"><a href="/w/<%= watch %>"><%= watch %>[<%= @statuses[watch][:state] %>]</a></li>
24
+ <% end %>
25
+ </ul>
26
+ </body>
27
+ </html>
data/views/watch.erb ADDED
@@ -0,0 +1,5 @@
1
+ <ul id="<%= @watch %>_commands" title="<%= @title %>">
2
+ <% @commands.each do |command| %>
3
+ <li id="<%= command %>_<%= @watch %>" class="<%= command %>"><a href="/w/<%= @watch %>/<%= command %>"><%= command %></a></li>
4
+ <% end %>
5
+ </ul>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jnewland-god_web
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jesse Newland
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-05-02 00:00:00 -07:00
12
+ date: 2008-05-19 00:00:00 -07:00
13
13
  default_executable: god_web
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -30,18 +30,43 @@ dependencies:
30
30
  - !ruby/object:Gem::Version
31
31
  version: 0.2.2
32
32
  version:
33
- description: Sinatra web frontend for God
33
+ description: iPhone friendly web UI for God
34
34
  email: jnewland@gmail.com
35
35
  executables:
36
36
  - god_web
37
37
  extensions: []
38
38
 
39
39
  extra_rdoc_files:
40
- - Readme.txt
40
+ - Readme.textile
41
41
  files:
42
42
  - bin/god_web
43
+ - lib/environment.rb
44
+ - lib/god_web.rb
43
45
  - lib/sinatra_http_auth.rb
44
- - Readme.txt
46
+ - views/command.erb
47
+ - views/status.erb
48
+ - views/watch.erb
49
+ - public/iui/backButton.png
50
+ - public/iui/blueButton.png
51
+ - public/iui/cancel.png
52
+ - public/iui/grayButton.png
53
+ - public/iui/iui.css
54
+ - public/iui/iui.js
55
+ - public/iui/iuix.css
56
+ - public/iui/iuix.js
57
+ - public/iui/listArrow.png
58
+ - public/iui/listArrowSel.png
59
+ - public/iui/listGroup.png
60
+ - public/iui/loading.gif
61
+ - public/iui/pinstripes.png
62
+ - public/iui/selection.png
63
+ - public/iui/thumb.png
64
+ - public/iui/toggle.png
65
+ - public/iui/toggleOn.png
66
+ - public/iui/toolButton.png
67
+ - public/iui/toolbar.png
68
+ - public/iui/whiteButton.png
69
+ - Readme.textile
45
70
  has_rdoc: false
46
71
  homepage: http://github.com/jnewland/god_web
47
72
  post_install_message:
@@ -64,9 +89,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
64
89
  requirements: []
65
90
 
66
91
  rubyforge_project: god_web
67
- rubygems_version: 1.0.1
92
+ rubygems_version: 1.2.0
68
93
  signing_key:
69
94
  specification_version: 2
70
- summary: Sinatra web frontend for God
95
+ summary: iPhone friendly web UI for God
71
96
  test_files: []
72
97
 
data/Readme.txt DELETED
@@ -1,55 +0,0 @@
1
- = god_web
2
-
3
- * http://github.com/jnewland/god_web
4
-
5
- == DESCRIPTION:
6
-
7
- Sinatra web frontend for God
8
-
9
- == REQUIREMENTS:
10
-
11
- * God
12
- * Sinatra
13
-
14
- == INSTALL:
15
-
16
- * sudo gem install jnewland-god_web -s http://gems.github.com
17
-
18
- == USAGE:
19
-
20
- * sudo god_web -p PORT_TO_RUN_ON -e production
21
-
22
- Optionally, you can password protect your god_web instance. To do so, create
23
- a YAML config file with username and password keys, like so:
24
-
25
- username: foo
26
- password: sekret
27
-
28
- Then provide that yaml file as the first argument to god_web:
29
-
30
- * sudo god_web /path/to/god_web.yml -p PORT_TO_RUN_ON -e production
31
-
32
- == LICENSE:
33
-
34
- (The MIT License)
35
-
36
- Copyright (c) 2008 Jesse Newland
37
-
38
- Permission is hereby granted, free of charge, to any person obtaining
39
- a copy of this software and associated documentation files (the
40
- 'Software'), to deal in the Software without restriction, including
41
- without limitation the rights to use, copy, modify, merge, publish,
42
- distribute, sublicense, and/or sell copies of the Software, and to
43
- permit persons to whom the Software is furnished to do so, subject to
44
- the following conditions:
45
-
46
- The above copyright notice and this permission notice shall be
47
- included in all copies or substantial portions of the Software.
48
-
49
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
50
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
51
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
52
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
53
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
54
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
55
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.