rrrspec-web 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/assets/javascripts/helpers.coffee +27 -0
  4. data/assets/javascripts/index.coffee +75 -0
  5. data/{app/js → assets/javascripts}/models.coffee +41 -69
  6. data/assets/javascripts/tasksets.coffee +400 -0
  7. data/{app/js → assets/javascripts}/vendor/backbone-min.js +0 -0
  8. data/{app/js → assets/javascripts}/vendor/backbone-min.map +0 -0
  9. data/{app/js → assets/javascripts}/vendor/backbone.js +0 -0
  10. data/assets/javascripts/vendor/handlebars-v1.3.0.js +2746 -0
  11. data/{app/js → assets/javascripts}/vendor/jquery-1.10.2.js +0 -0
  12. data/{app/js → assets/javascripts}/vendor/jquery-1.10.2.min.js +0 -0
  13. data/{app/js → assets/javascripts}/vendor/jquery-1.10.2.min.map +0 -0
  14. data/{app/js → assets/javascripts}/vendor/moment.min.js +0 -0
  15. data/{app/js → assets/javascripts}/vendor/underscore-min.js +0 -0
  16. data/{app/js → assets/javascripts}/vendor/underscore-min.map +0 -0
  17. data/{app/js → assets/javascripts}/vendor/underscore.js +0 -0
  18. data/assets/stylesheets/application.sass +188 -0
  19. data/lib/rrrspec/web/api.rb +61 -0
  20. data/lib/rrrspec/web/app.rb +9 -30
  21. data/lib/rrrspec/web/configuration.rb +1 -0
  22. data/lib/rrrspec/web/persistent_models.rb +7 -2
  23. data/lib/rrrspec/web/version.rb +1 -1
  24. data/rrrspec-web.gemspec +9 -7
  25. data/spec/rrrspec/web/api_spec.rb +278 -47
  26. data/tasks/assets.rake +3 -6
  27. data/views/index.haml +4 -14
  28. data/views/taskset.haml +61 -68
  29. data/views/user.haml +2 -2
  30. metadata +108 -84
  31. data/app/css/application.sass +0 -124
  32. data/app/css/vendor/bootstrap-theme.css +0 -384
  33. data/app/css/vendor/bootstrap-theme.min.css +0 -1
  34. data/app/css/vendor/bootstrap.css +0 -6805
  35. data/app/css/vendor/bootstrap.min.css +0 -9
  36. data/app/js/index.coffee +0 -51
  37. data/app/js/tasksets.coffee +0 -305
  38. data/app/js/vendor/bootstrap.js +0 -1999
  39. data/app/js/vendor/bootstrap.min.js +0 -6
  40. data/app/js/vendor/mustache.js +0 -551
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 277ae2e299b382cb2256456b336e2a4289ae05bb
4
- data.tar.gz: 263d5aa2200ddfed889fd73841d0aef5cb8cd7cf
3
+ metadata.gz: 835ae4268801f3543334a082fd65379340cdb734
4
+ data.tar.gz: 4dbebd2858d865f3b4912496ae3089fbace9e9c1
5
5
  SHA512:
6
- metadata.gz: 02e13c86dd5e08ee7f7be6122d586606e931180e178d98909f6e24870c933a53ef3438ac46f8d6624bcb5d2ce1319f1ba7ba1db1383042a4c18fe4afdca7f123
7
- data.tar.gz: 05e9e2a072f98dfaf702dc53d0c318c0d0f4699fb93a3bdd5dc246eae27161d3e692babab41ce02495d1b90fa7ef87282f5ba8c32abc745943f109adce525ea9
6
+ metadata.gz: 21535194f756e7243f6376c101905bed8d1dc5e4a289aa77a63e3e9dffe43ac6c2ec0393904dfccd5a23f4230889c8f1994704a22121374a758311deed2cdae0
7
+ data.tar.gz: 91e8cc2b487d8e9ab99ae481992ac1b3a88dc4379c0a707a2ba9b3436eac66feaa973e677ed4894bdf40981c5237f29e9187008ceed888d3105ced00e7e043ae
@@ -0,0 +1 @@
1
+ public
@@ -0,0 +1,27 @@
1
+ formatDate = (date)->
2
+ if date
3
+ moment(date).format("YYYY-MM-DD HH:mm:ss z")
4
+ else
5
+ ""
6
+
7
+ formatDateWithHumanized = (date) ->
8
+ if date
9
+ "#{moment(date).format("YYYY-MM-DD HH:mm:ss z")} (#{moment(date).fromNow()})"
10
+ else
11
+ ""
12
+
13
+ formatDuration = (start, finish)->
14
+ moment.duration(moment(finish).diff(moment(start))).humanize()
15
+
16
+ formatDateWithDuration = (date, start)->
17
+ if date && start
18
+ "#{formatDate(date)} (#{formatDuration(start, date)})"
19
+ else if date
20
+ "#{formatDate(date)}"
21
+ else
22
+ ""
23
+
24
+ Handlebars.registerHelper('date', formatDate)
25
+ Handlebars.registerHelper('dateWithHumanized', formatDateWithHumanized)
26
+ Handlebars.registerHelper('duration', formatDuration)
27
+ Handlebars.registerHelper('dateWithDuration', formatDateWithDuration)
@@ -0,0 +1,75 @@
1
+ #= require vendor/jquery-1.10.2
2
+ #= require vendor/handlebars-v1.3.0
3
+ #= require vendor/moment.min
4
+ #= require vendor/underscore
5
+ #= require vendor/backbone
6
+ #= require bootstrap
7
+ #= require helpers
8
+ #= require models
9
+
10
+ $(->
11
+ class TasksetsView extends Backbone.View
12
+ initialize: (options) ->
13
+ @subviews = []
14
+ @listenTo(@collection, "add", @appendItem)
15
+ @listenTo(@collection, "reset", @resetItems)
16
+ if @collection.hasPages
17
+ @$('.previous').click(=>
18
+ if @collection.hasPrevious()
19
+ @$('.tasksets').empty()
20
+ @subviews = []
21
+ @collection.fetchPreviousPage(success: -> @render)
22
+ @updatePager()
23
+ )
24
+ @$('.next').click(=>
25
+ @$('.tasksets').empty()
26
+ @subviews = []
27
+ @collection.fetchNextPage(success: -> @render)
28
+ @updatePager()
29
+ )
30
+ @resetItems(@collection)
31
+
32
+ appendItem: (model) ->
33
+ view = new TasksetView({model: model})
34
+ @subviews.push(view)
35
+ view.render()
36
+ @$('.tasksets').append(view.$el)
37
+
38
+ resetItems: (collection) ->
39
+ @collection = collection
40
+ @$('.tasksets').empty()
41
+ @subviews = []
42
+ for model in collection.models
43
+ @appendItem(model)
44
+
45
+ render: ->
46
+ for view in @subviews
47
+ view.render()
48
+ @updatePager()
49
+
50
+ updatePager: ->
51
+ if @collection.hasPages
52
+ @$('.pagenum').text("Page #{@collection.currentPage}")
53
+ if @collection.hasPrevious()
54
+ @$('.previous').removeClass('disabled')
55
+ else
56
+ @$('.previous').addClass('disabled')
57
+
58
+ class TasksetView extends Backbone.View
59
+ tagName: 'li'
60
+ className: 'list-group-item'
61
+ template: Handlebars.compile($('#taskset-template').html())
62
+
63
+ render: ->
64
+ @$el.html(@template(@model.attributes))
65
+
66
+ actives = new ActiveTasksets()
67
+ actives.fetch()
68
+ activesView = new TasksetsView({collection: actives, el: '.active-tasksets'})
69
+ activesView.render()
70
+
71
+ recents = new RecentTasksets()
72
+ recents.fetch()
73
+ recentsView = new TasksetsView({collection: recents, el: '.recent-tasksets'})
74
+ recentsView.render()
75
+ )
@@ -1,40 +1,39 @@
1
- dateFormat = (date)->
2
- moment(date).format("YYYY-MM-DD HH:mm:ss z")
3
-
4
- dateDuration = (start, finish)->
5
- moment.duration(moment(finish).diff(moment(start))).humanize()
6
-
7
1
  class @Taskset extends Backbone.Model
8
- url: -> "/v1/tasksets/#{encodeURIComponent(@get('key'))}"
2
+ url: -> "/v2/tasksets/#{encodeURIComponent(@get('key'))}"
9
3
 
10
4
  parse: (obj, options) ->
11
5
  obj.created_at = new Date(obj.created_at) if obj.created_at
12
6
  obj.finished_at = new Date(obj.finished_at) if obj.finished_at
13
- obj.slaves = new Slaves(obj.slaves, {parse: true, silent: false})
7
+ obj.log_text = obj.log
8
+
14
9
  obj.tasks = new Tasks(obj.tasks, {parse: true, silent: false})
15
10
  obj.worker_logs = new WorkerLogs(obj.worker_logs, {parse: true, silent: false})
11
+ obj.worker_logs.tasksetId = obj.id
12
+ obj.slaves = new Slaves(obj.slaves, {parse: true, silent: false})
13
+ obj.slaves.tasksetId = obj.id
16
14
  obj
17
15
 
18
- isFull: -> !!@get('is_full')
19
- isFinished: -> !!@get('finished_at')
20
-
21
- forTemplate: ->
22
- j = @toJSON()
23
- j['duration'] = dateDuration(j['created_at'], j['finished_at'])
24
- if created_at = j['created_at']
25
- j['created_at'] = dateFormat(created_at)
26
- j['created_at_humanized'] = moment(created_at).fromNow()
27
- j['finished_at'] = dateFormat(j['finished_at'])
28
- j
16
+ isFinished: ->
17
+ status = @get('status')
18
+ return status == 'succeeded' || status == 'cancelled' || status == 'failed'
19
+ outputFetched: -> !!@get('log')
20
+ fetchOutput: ->
21
+ $.getJSON("/v2/tasksets/#{@attributes.id}/log", (data)=>
22
+ @attributes.log = data.log
23
+ )
29
24
 
30
25
  class @Task extends Backbone.Model
31
- url: -> "/v1/tasks/#{encodeURIComponent(@get('key'))}"
26
+ url: -> "/v2/tasks/#{@get('id')}"
32
27
  parse: (obj, options) ->
33
28
  if obj.trials
34
29
  obj.trials = _.filter(obj.trials, (trial) -> trial['status'])
35
30
  obj.trials = _.map(obj.trials, (trial) -> new Trial(trial, {parse: true}))
36
31
  obj
37
32
 
33
+ isSuccess: ->
34
+ status = @get('status')
35
+ return status == 'passed' || status == 'pending'
36
+
38
37
  numExamples: ->
39
38
  passed = null
40
39
  pending = null
@@ -53,9 +52,6 @@ class @Task extends Backbone.Model
53
52
  return [0, 0, 0]
54
53
  return [preferred.get('passed'), preferred.get('pending'), preferred.get('failed')]
55
54
 
56
- forTemplate: ->
57
- @toJSON()
58
-
59
55
  class @Tasks extends Backbone.Collection
60
56
  initialize: (options) ->
61
57
  @numTask = 0
@@ -88,65 +84,55 @@ class @Tasks extends Backbone.Collection
88
84
  @numFailedExample += failed
89
85
 
90
86
  class @Trial extends Backbone.Model
91
- url: -> "/v1/trials/#{encodeURIComponent(@get('key'))}"
92
87
  parse: (obj, options) ->
93
88
  obj.started_at = new Date(obj.started_at) if obj.started_at
94
89
  obj.finished_at = new Date(obj.finished_at) if obj.finished_at
95
90
  obj
96
- forTemplate: ->
97
- j = @toJSON()
98
- j['duration'] = dateDuration(j['started_at'], j['finished_at'])
99
- j['started_at'] = dateFormat(j['started_at']) if j['started_at']
100
- j['finished_at'] = dateFormat(j['finished_at']) if j['finished_at']
101
- j
91
+
92
+ outputsFetched: -> !!@attributes.stdout
93
+
94
+ fetchOutput: ->
95
+ $.getJSON("/v2/trials/#{@attributes.id}/outputs", (data)=>
96
+ @attributes.stdout = data.stdout
97
+ @attributes.stderr = data.stderr
98
+ )
102
99
 
103
100
  class @WorkerLog extends Backbone.Model
104
- url: -> "/v1/worker_logs/#{encodeURIComponent(@get('key'))}"
105
101
  parse: (obj, options) ->
106
102
  obj.started_at = new Date(obj.started_at)
107
103
  obj.rsync_finished_at = new Date(obj.rsync_finished_at) if obj.rsync_finished_at
108
104
  obj.setup_finished_at = new Date(obj.setup_finished_at) if obj.setup_finished_at
109
- obj.finished_at = new Date(obj.finished_at) if obj.finished_at
105
+ obj.rspec_finished_at = new Date(obj.rspec_finished_at) if obj.rspec_finished_at
106
+ obj.log_text = obj.log
110
107
  obj
111
108
 
112
- forTemplate: ->
113
- j = @toJSON()
114
- j['rsync_duration'] = dateDuration(j['started_at'], j['rsync_finished_at'])
115
- j['setup_duration'] = dateDuration(j['rsync_finished_at'], j['setup_finished_at'])
116
- j['test_duration'] = dateDuration(j['setup_finished_at'], j['finished_at'])
117
-
118
- j['started_at'] = dateFormat(j['started_at']) if j['started_at']
119
- j['rsync_finished_at'] = dateFormat(j['rsync_finished_at']) if j['rsync_finished_at']
120
- j['setup_finished_at'] = dateFormat(j['setup_finished_at']) if j['setup_finished_at']
121
- j['finished_at'] = dateFormat(j['finished_at']) if j['finished_at']
122
- j
123
-
124
109
  class @WorkerLogs extends Backbone.Collection
110
+ url: -> "/v2/tasksets/#{@tasksetId}/worker_logs"
125
111
  parse: (obj, options) ->
126
112
  obj.map((worker_log) -> new WorkerLog(worker_log, options))
113
+ fetched: -> !@isEmpty
127
114
 
128
115
  class @Slave extends Backbone.Model
129
- url: -> "/v1/slaves/#{encodeURIComponent(@get('key'))}"
130
- forTemplate: ->
131
- j = @toJSON()
132
- j['trials'] = _.map(j['trials'], (trial) ->
133
- trial['encoded_key'] = encodeURIComponent(trial['key'])
134
- trial
135
- )
136
- j
116
+ parse: (obj, options) ->
117
+ obj.log_text = obj.log
118
+ obj
137
119
 
138
120
  class @Slaves extends Backbone.Collection
121
+ url: -> "/v2/tasksets/#{@tasksetId}/slaves"
139
122
  parse: (obj, options) ->
140
123
  obj.map((slave) -> new Slave(slave, options))
124
+ fetched: -> !@isEmpty
141
125
 
142
126
  class @ActiveTasksets extends Backbone.Collection
143
- url: "/v1/tasksets/actives"
127
+ url: "/v2/tasksets/actives"
144
128
  parse: (obj, options) ->
145
129
  obj.map((taskset) -> new Taskset(taskset, options))
130
+ hasPages: false
146
131
 
147
132
  class @RecentTasksets extends Backbone.Collection
148
133
  currentPage: 1
149
- url: -> "/v1/tasksets/recents?page=#{@currentPage}"
134
+ url: -> "/v2/tasksets/recents?page=#{@currentPage}"
135
+ hasPages: true
150
136
 
151
137
  fetchNextPage: ->
152
138
  @currentPage++
@@ -157,21 +143,7 @@ class @RecentTasksets extends Backbone.Collection
157
143
  @currentPage--
158
144
  @fetch()
159
145
 
160
- parse: (obj, options) ->
161
- obj.map((taskset) -> new Taskset(taskset, options))
162
-
163
- class @SlaveFailedTasksets extends Backbone.Collection
164
- currentPage: 1
165
- url: -> "/v1/tasksets/failure_slaves?page=#{@currentPage}"
166
-
167
- fetchNextPage: ->
168
- @currentPage++
169
- @fetch()
170
-
171
- fetchPreviousPage: ->
172
- if @currentPage != 1
173
- @currentPage--
174
- @fetch()
146
+ hasPrevious: -> @currentPage != 1
175
147
 
176
148
  parse: (obj, options) ->
177
149
  obj.map((taskset) -> new Taskset(taskset, options))
@@ -0,0 +1,400 @@
1
+ #= require vendor/jquery-1.10.2
2
+ #= require vendor/handlebars-v1.3.0
3
+ #= require vendor/moment.min
4
+ #= require vendor/underscore
5
+ #= require vendor/backbone
6
+ #= require bootstrap
7
+ #= require helpers
8
+ #= require models
9
+
10
+ $(->
11
+ class TasksetRouter extends Backbone.Router
12
+ routes:
13
+ 'taskset': 'taskset'
14
+ 'tasks/:task_id': 'task'
15
+ 'trials/:trial_id': 'trial'
16
+ 'worker_logs/:worker_log_id': 'worker_log'
17
+ 'slaves/:slave_id': 'slave'
18
+
19
+ class TasksetView extends Backbone.View
20
+ el: '.taskset'
21
+
22
+ initialize: ->
23
+ @headView = new HeadView({model: @model})
24
+ @progressbarView = new ProgressBarView({model: @model})
25
+ @taskListView = new TaskListView({collection: @model.get('tasks')})
26
+ @workerLogListView = new WorkerLogListView({collection: @model.get('worker_logs')})
27
+ @slaveListView = new SlaveListView({collection: @model.get('slaves')})
28
+
29
+ render: ->
30
+ @headView.render()
31
+ @progressbarView.render()
32
+ @taskListView.render()
33
+ @workerLogListView.render()
34
+ @slaveListView.render()
35
+
36
+ class HeadView extends Backbone.View
37
+ el: '.head'
38
+ template: Handlebars.compile($('#head-template').html())
39
+
40
+ initialize: (options) ->
41
+ @showing = false
42
+ router.on('route:taskset', => @show())
43
+
44
+ render: ->
45
+ @$el.html(@template(@model.attributes))
46
+ @$('.panel-heading .status').addClass(@model.get('status'))
47
+
48
+ @$('.panel-title').click(=>
49
+ router.navigate("taskset")
50
+ @toggle()
51
+ )
52
+
53
+ show: ->
54
+ @showing = true
55
+ @$('.taskset-info').collapse('show')
56
+ unless @model.outputFetched()
57
+ @model.fetchOutput().done(=>
58
+ @$('.log').html(@model.get('log'))
59
+ )
60
+
61
+ hide: ->
62
+ @showing = false
63
+ @$('.taskset-info').collapse('hide')
64
+
65
+ toggle: ->
66
+ @showing = !@showing
67
+ if @showing
68
+ @show()
69
+ else
70
+ @hide()
71
+
72
+ class ProgressBarView extends Backbone.View
73
+ el: '.progressbars'
74
+
75
+ showBar: (bar, percentage, text) ->
76
+ if percentage == 0
77
+ bar.attr('style', 'width: 0%')
78
+ bar.text('')
79
+ else
80
+ bar.attr('style', "width: #{100*percentage}%")
81
+ bar.text(text)
82
+ hideBar: (bar) -> @showBar(bar, 0, '')
83
+
84
+ renderSpecBar: (tasks) ->
85
+ if @model.isFinished()
86
+ @$('.spec-progress').removeClass('progress-striped active')
87
+ @hideBar(@$('.spec-progress-bar'))
88
+ @showBar(@$('.passed-spec-bar'), tasks.numPassedTask/tasks.numTask, tasks.numPassedTask)
89
+ @showBar(@$('.pending-spec-bar'), tasks.numPendingTask/tasks.numTask, tasks.numPendingTask)
90
+ @showBar(@$('.failed-spec-bar'), tasks.numFailedTask/tasks.numTask, tasks.numFailedTask)
91
+ else
92
+ numFinishedTask = tasks.numPassedTask + tasks.numPendingTask + tasks.numFailedTask
93
+ percentage = numFinishedTask/tasks.numTask
94
+ @$('.spec-progress').addClass('progress-striped active')
95
+ @showBar(@$('.spec-progress-bar'), percentage, "#{numFinishedTask}/#{tasks.numTask} (#{100*percentage}%)")
96
+ @hideBar(@$('.passed-spec-bar'))
97
+ @hideBar(@$('.pending-spec-bar'))
98
+ @hideBar(@$('.failed-spec-bar'))
99
+
100
+ renderExampleBar: (tasks) ->
101
+ @showBar(@$('.passed-example-bar'), tasks.numPassedExample/tasks.numExample, tasks.numPassedExample)
102
+ @showBar(@$('.pending-example-bar'), tasks.numPendingExample/tasks.numExample, tasks.numPendingExample)
103
+ @showBar(@$('.failed-example-bar'), tasks.numFailedExample/tasks.numExample, tasks.numFailedExample)
104
+
105
+ render: ->
106
+ tasks = @model.get('tasks')
107
+ @renderSpecBar(tasks)
108
+ @renderExampleBar(tasks)
109
+
110
+ class TaskListView extends Backbone.View
111
+ el: '.tasks'
112
+
113
+ initialize: (options) ->
114
+ @showHeaders = false
115
+ @$('.tasks-heading').click(=>
116
+ @showHeaders = !@showHeaders
117
+ if @showHeaders
118
+ @$('.tasks-heading').text("TASKS")
119
+ for key, view of @subviews
120
+ view.showHeader()
121
+ else
122
+ @$('.tasks-heading').text("FAILED TASKS")
123
+ for key, view of @subviews
124
+ view.hideHeaderIfSuccess()
125
+ )
126
+ router.on('route:task', (taskId) =>
127
+ view = @subviews[taskId]
128
+ view.showHeader()
129
+ view.showBody()
130
+ view.scrollIntoView()
131
+ )
132
+ router.on('route:trial', (trialId) =>
133
+ for key, view of @subviews
134
+ if view.hasTrial(trialId)
135
+ view.showHeader()
136
+ view.showBody()
137
+ view.scrollIntoViewOfTrial(trialId)
138
+ break
139
+ )
140
+ @resetItems(@collection)
141
+
142
+ resetItems: (collection) ->
143
+ @collection = collection
144
+ @$('.tasks-list').html('')
145
+ @subviews = {}
146
+ @listenTo(collection, "add", @appendItem)
147
+ @listenTo(collection, "reset", @resetItems)
148
+ for model in collection.models
149
+ @appendItem(model)
150
+
151
+ appendItem: (model) ->
152
+ view = new TaskView({model: model})
153
+ @subviews[model.attributes.id] = view
154
+ view.render()
155
+ @$('.tasks-list').append(view.$el)
156
+
157
+ render: ->
158
+ for key, view in @subviews
159
+ view.render()
160
+
161
+ class TaskView extends Backbone.View
162
+ tagName: 'li'
163
+ className: 'list-group-item'
164
+ template: Handlebars.compile($('#tasks-list-template').html())
165
+
166
+ initialize: (options) ->
167
+ @subviews = {}
168
+ @bodyShowing = false
169
+
170
+ hasTrial: (trialId) -> !!@subviews[trialId]
171
+
172
+ render: ->
173
+ @$el.html(@template(@model.attributes))
174
+ @$el.addClass(@model.get('status'))
175
+ @hideHeaderIfSuccess()
176
+ @$('.tasks-list-item-header').click(=>
177
+ router.navigate("tasks/#{@model.get('id')}")
178
+ @toggleBody()
179
+ )
180
+ for trial in @model.get('trials')
181
+ @appendTrial(trial)
182
+
183
+ appendTrial: (trial) ->
184
+ view = new TrialView({model: trial})
185
+ @subviews[trial.attributes.id] = view
186
+ view.render()
187
+ @$('.trials').append(view.$el)
188
+
189
+ showHeader: ->
190
+ @$el.removeClass('hidden')
191
+
192
+ hideHeaderIfSuccess: ->
193
+ if @model.isSuccess()
194
+ @$el.addClass('hidden')
195
+
196
+ showBody: ->
197
+ @bodyShowing = true
198
+ for key, view of @subviews
199
+ view.showBody()
200
+ @$('.body').collapse('show')
201
+ @scrollIntoView()
202
+
203
+ hideBody: ->
204
+ @bodyShowing = false
205
+ @$('.body').collapse('hide')
206
+
207
+ toggleBody: ->
208
+ @bodyShowing = !@bodyShowing
209
+ if @bodyShowing
210
+ @showBody()
211
+ else
212
+ @hideBody()
213
+
214
+ scrollIntoView: -> $('html, body').animate(scrollTop: @$el.offset().top)
215
+
216
+ scrollIntoViewOfTrial: (trialId) ->
217
+ @subviews[trialId].scrollIntoView()
218
+
219
+ class TrialView extends Backbone.View
220
+ className: 'panel'
221
+ template: Handlebars.compile($('#trial-template').html())
222
+
223
+ render: ->
224
+ @$el.html(@template(@model.attributes))
225
+
226
+ showBody: ->
227
+ unless @model.outputsFetched()
228
+ @model.fetchOutput().done(=>
229
+ @$('.stdout').text(@model.get('stdout'))
230
+ @$('.stderr').text(@model.get('stderr'))
231
+ )
232
+
233
+ scrollIntoView: -> $('html, body').animate(scrollTop: @$el.offset().top)
234
+
235
+ class WorkerLogListView extends Backbone.View
236
+ el: '.worker-logs'
237
+
238
+ initialize: (options) ->
239
+ @showHeaders = false
240
+ @$('.worker-logs-heading').click(=> @toggle())
241
+ router.on('route:worker_log', (workerLogId) =>
242
+ @show().done(=>
243
+ target = @subviews[workerLogId]
244
+ target.scrollIntoView()
245
+ target.showBody()
246
+ )
247
+ )
248
+ @resetItems(@collection)
249
+
250
+ resetItems: (collection) ->
251
+ @collection = collection
252
+ @$('.worker-logs-list').html('')
253
+ @subviews = {}
254
+ @listenTo(collection, "add", @appendItem)
255
+ @listenTo(collection, "reset", @resetItems)
256
+ for model in collection.models
257
+ @appendItem(model)
258
+
259
+ appendItem: (model) ->
260
+ view = new WorkerLogView({model: model})
261
+ @subviews[model.attributes.id] = view
262
+ view.render()
263
+ @$('.worker-logs-list').append(view.$el)
264
+
265
+ render: ->
266
+ for key, view in @subviews
267
+ view.render()
268
+
269
+ show: ->
270
+ @showHeaders = true
271
+ (
272
+ unless @collection.fetched()
273
+ @collection.fetch({reset: true})
274
+ else
275
+ $.Defferred()
276
+ ).done(=> @$('.worker-logs-list').collapse('show'))
277
+
278
+ hide: ->
279
+ @showHeaders = false
280
+ @$('.worker-logs-list').collapse('hide')
281
+
282
+ toggle: ->
283
+ @showHeaders = !@showHeaders
284
+ if @showHeaders
285
+ @show()
286
+ else
287
+ @hide()
288
+
289
+ class WorkerLogView extends Backbone.View
290
+ tagName: 'li'
291
+ className: 'list-group-item'
292
+ template: Handlebars.compile($('#worker-log-template').html())
293
+
294
+ render: ->
295
+ @$el.html(@template(@model.attributes))
296
+ @$('.worker-logs-list-item-header').click(=>
297
+ router.navigate("worker_logs/#{@model.get('id')}")
298
+ @$('.body').collapse('toggle')
299
+ )
300
+
301
+ scrollIntoView: -> $('html, body').animate(scrollTop: @$el.offset().top)
302
+
303
+ showBody: ->
304
+ @$('.body').collapse('show')
305
+
306
+ class SlaveListView extends Backbone.View
307
+ el: '.slaves'
308
+
309
+ initialize: (options) ->
310
+ @showHeaders = false
311
+ @$('.slaves-heading').click(=> @toggle())
312
+ router.on('route:slave', (slaveId) =>
313
+ @show().done(=>
314
+ target = @subviews[slaveId]
315
+ target.scrollIntoView()
316
+ target.showBody()
317
+ )
318
+ )
319
+ @resetItems(@collection)
320
+
321
+ resetItems: (collection) ->
322
+ @collection = collection
323
+ @$('.slaves-list').html('')
324
+ @subviews = {}
325
+ @listenTo(collection, "add", @appendItem)
326
+ @listenTo(collection, "reset", @resetItems)
327
+ for model in collection.models
328
+ @appendItem(model)
329
+
330
+ appendItem: (model) ->
331
+ view = new SlaveView({model: model})
332
+ @subviews[model.attributes.id] = view
333
+ view.render()
334
+ @$('.slaves-list').append(view.$el)
335
+
336
+ render: ->
337
+ for key, view of @subviews
338
+ view.render()
339
+
340
+ show: ->
341
+ @showHeaders = true
342
+ (
343
+ unless @collection.fetched()
344
+ @collection.fetch({reset: true})
345
+ else
346
+ $.Defferred()
347
+ ).done(=>
348
+ @$('.slaves-list').collapse('show')
349
+ )
350
+
351
+ hide: ->
352
+ @showHeaders = false
353
+ @$('.slaves-list').collapse('hide')
354
+
355
+ toggle: ->
356
+ @showHeaders = !@showHeaders
357
+ if @showHeaders
358
+ @show()
359
+ else
360
+ @hide()
361
+
362
+ class SlaveView extends Backbone.View
363
+ tagName: 'li'
364
+ className: 'list-group-item'
365
+ template: Handlebars.compile($('#slave-template').html())
366
+
367
+ render: ->
368
+ @$el.html(@template(@model.attributes))
369
+ @$('.slaves-list-item-header').click(=>
370
+ router.navigate("slaves/#{@model.get('id')}")
371
+ @$('.body').collapse('toggle')
372
+ )
373
+ @$el.addClass(@model.get('status'))
374
+
375
+ scrollIntoView: -> $('html, body').animate(scrollTop: @$el.offset().top)
376
+
377
+ showBody: ->
378
+ @$('.body').collapse('show')
379
+
380
+ router = new TasksetRouter()
381
+ Backbone.history.start()
382
+
383
+ if document.URL.match(/\/tasksets\/(.*?)(#.*)?$/)
384
+ taskset = new Taskset({key: RegExp.$1})
385
+ taskset.fetch({
386
+ success: (model, response, options) ->
387
+ tasksetView = new TasksetView({model: model})
388
+ tasksetView.render()
389
+ tasksetView.$el.removeClass('hidden')
390
+
391
+ # Force re-route
392
+ fragment = Backbone.history.fragment
393
+ router.navigate('')
394
+ router.navigate(fragment, {trigger: true})
395
+ error: (model, response, options) ->
396
+ $('#notfound-modal').modal({keyboard: false})
397
+ })
398
+ else
399
+ $('#notfound-modal').modal({keyboard: false})
400
+ )