dj_mon 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -35,10 +35,15 @@ If the credentials are not set, then the username and password are assumed to be
35
35
 
36
36
  Now visit `http://localhost:3000/dj_mon` and profit!
37
37
 
38
+ ## Features
39
+ * See Jobs by status
40
+ * Inspect the payload
41
+ * Inspect the last run error.
42
+
38
43
  ## ROADMAP
39
-
44
+ * Delete failed or queued jobs
45
+ * Restart failed jobs
40
46
  * Filter by queue.
41
- * Option to periodically auto refresh views.
42
47
  * `rake` tasks to know job status from command line.
43
48
 
44
49
 
@@ -0,0 +1,218 @@
1
+ /* =========================================================
2
+ * bootstrap-modal.js v2.0.4
3
+ * http://twitter.github.com/bootstrap/javascript.html#modals
4
+ * =========================================================
5
+ * Copyright 2012 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
+ "use strict"; // jshint ;_;
24
+
25
+
26
+ /* MODAL CLASS DEFINITION
27
+ * ====================== */
28
+
29
+ var Modal = function (content, options) {
30
+ this.options = options
31
+ this.$element = $(content)
32
+ .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
33
+ }
34
+
35
+ Modal.prototype = {
36
+
37
+ constructor: Modal
38
+
39
+ , toggle: function () {
40
+ return this[!this.isShown ? 'show' : 'hide']()
41
+ }
42
+
43
+ , show: function () {
44
+ var that = this
45
+ , e = $.Event('show')
46
+
47
+ this.$element.trigger(e)
48
+
49
+ if (this.isShown || e.isDefaultPrevented()) return
50
+
51
+ $('body').addClass('modal-open')
52
+
53
+ this.isShown = true
54
+
55
+ escape.call(this)
56
+ backdrop.call(this, function () {
57
+ var transition = $.support.transition && that.$element.hasClass('fade')
58
+
59
+ if (!that.$element.parent().length) {
60
+ that.$element.appendTo(document.body) //don't move modals dom position
61
+ }
62
+
63
+ that.$element
64
+ .show()
65
+
66
+ if (transition) {
67
+ that.$element[0].offsetWidth // force reflow
68
+ }
69
+
70
+ that.$element.addClass('in')
71
+
72
+ transition ?
73
+ that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) :
74
+ that.$element.trigger('shown')
75
+
76
+ })
77
+ }
78
+
79
+ , hide: function (e) {
80
+ e && e.preventDefault()
81
+
82
+ var that = this
83
+
84
+ e = $.Event('hide')
85
+
86
+ this.$element.trigger(e)
87
+
88
+ if (!this.isShown || e.isDefaultPrevented()) return
89
+
90
+ this.isShown = false
91
+
92
+ $('body').removeClass('modal-open')
93
+
94
+ escape.call(this)
95
+
96
+ this.$element.removeClass('in')
97
+
98
+ $.support.transition && this.$element.hasClass('fade') ?
99
+ hideWithTransition.call(this) :
100
+ hideModal.call(this)
101
+ }
102
+
103
+ }
104
+
105
+
106
+ /* MODAL PRIVATE METHODS
107
+ * ===================== */
108
+
109
+ function hideWithTransition() {
110
+ var that = this
111
+ , timeout = setTimeout(function () {
112
+ that.$element.off($.support.transition.end)
113
+ hideModal.call(that)
114
+ }, 500)
115
+
116
+ this.$element.one($.support.transition.end, function () {
117
+ clearTimeout(timeout)
118
+ hideModal.call(that)
119
+ })
120
+ }
121
+
122
+ function hideModal(that) {
123
+ this.$element
124
+ .hide()
125
+ .trigger('hidden')
126
+
127
+ backdrop.call(this)
128
+ }
129
+
130
+ function backdrop(callback) {
131
+ var that = this
132
+ , animate = this.$element.hasClass('fade') ? 'fade' : ''
133
+
134
+ if (this.isShown && this.options.backdrop) {
135
+ var doAnimate = $.support.transition && animate
136
+
137
+ this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
138
+ .appendTo(document.body)
139
+
140
+ if (this.options.backdrop != 'static') {
141
+ this.$backdrop.click($.proxy(this.hide, this))
142
+ }
143
+
144
+ if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
145
+
146
+ this.$backdrop.addClass('in')
147
+
148
+ doAnimate ?
149
+ this.$backdrop.one($.support.transition.end, callback) :
150
+ callback()
151
+
152
+ } else if (!this.isShown && this.$backdrop) {
153
+ this.$backdrop.removeClass('in')
154
+
155
+ $.support.transition && this.$element.hasClass('fade')?
156
+ this.$backdrop.one($.support.transition.end, $.proxy(removeBackdrop, this)) :
157
+ removeBackdrop.call(this)
158
+
159
+ } else if (callback) {
160
+ callback()
161
+ }
162
+ }
163
+
164
+ function removeBackdrop() {
165
+ this.$backdrop.remove()
166
+ this.$backdrop = null
167
+ }
168
+
169
+ function escape() {
170
+ var that = this
171
+ if (this.isShown && this.options.keyboard) {
172
+ $(document).on('keyup.dismiss.modal', function ( e ) {
173
+ e.which == 27 && that.hide()
174
+ })
175
+ } else if (!this.isShown) {
176
+ $(document).off('keyup.dismiss.modal')
177
+ }
178
+ }
179
+
180
+
181
+ /* MODAL PLUGIN DEFINITION
182
+ * ======================= */
183
+
184
+ $.fn.modal = function (option) {
185
+ return this.each(function () {
186
+ var $this = $(this)
187
+ , data = $this.data('modal')
188
+ , options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option)
189
+ if (!data) $this.data('modal', (data = new Modal(this, options)))
190
+ if (typeof option == 'string') data[option]()
191
+ else if (options.show) data.show()
192
+ })
193
+ }
194
+
195
+ $.fn.modal.defaults = {
196
+ backdrop: true
197
+ , keyboard: true
198
+ , show: true
199
+ }
200
+
201
+ $.fn.modal.Constructor = Modal
202
+
203
+
204
+ /* MODAL DATA-API
205
+ * ============== */
206
+
207
+ $(function () {
208
+ $('body').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) {
209
+ var $this = $(this), href
210
+ , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
211
+ , option = $target.data('modal') ? 'toggle' : $.extend({}, $target.data(), $this.data())
212
+
213
+ e.preventDefault()
214
+ $target.modal(option)
215
+ })
216
+ })
217
+
218
+ }(window.jQuery);
@@ -0,0 +1,98 @@
1
+ /* ===========================================================
2
+ * bootstrap-popover.js v2.0.4
3
+ * http://twitter.github.com/bootstrap/javascript.html#popovers
4
+ * ===========================================================
5
+ * Copyright 2012 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
+ "use strict"; // jshint ;_;
24
+
25
+
26
+ /* POPOVER PUBLIC CLASS DEFINITION
27
+ * =============================== */
28
+
29
+ var Popover = function ( element, options ) {
30
+ this.init('popover', element, options)
31
+ }
32
+
33
+
34
+ /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js
35
+ ========================================== */
36
+
37
+ Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, {
38
+
39
+ constructor: Popover
40
+
41
+ , setContent: function () {
42
+ var $tip = this.tip()
43
+ , title = this.getTitle()
44
+ , content = this.getContent()
45
+
46
+ $tip.find('.popover-title')[this.isHTML(title) ? 'html' : 'text'](title)
47
+ $tip.find('.popover-content > *')[this.isHTML(content) ? 'html' : 'text'](content)
48
+
49
+ $tip.removeClass('fade top bottom left right in')
50
+ }
51
+
52
+ , hasContent: function () {
53
+ return this.getTitle() || this.getContent()
54
+ }
55
+
56
+ , getContent: function () {
57
+ var content
58
+ , $e = this.$element
59
+ , o = this.options
60
+
61
+ content = $e.attr('data-content')
62
+ || (typeof o.content == 'function' ? o.content.call($e[0]) : o.content)
63
+
64
+ return content
65
+ }
66
+
67
+ , tip: function () {
68
+ if (!this.$tip) {
69
+ this.$tip = $(this.options.template)
70
+ }
71
+ return this.$tip
72
+ }
73
+
74
+ })
75
+
76
+
77
+ /* POPOVER PLUGIN DEFINITION
78
+ * ======================= */
79
+
80
+ $.fn.popover = function (option) {
81
+ return this.each(function () {
82
+ var $this = $(this)
83
+ , data = $this.data('popover')
84
+ , options = typeof option == 'object' && option
85
+ if (!data) $this.data('popover', (data = new Popover(this, options)))
86
+ if (typeof option == 'string') data[option]()
87
+ })
88
+ }
89
+
90
+ $.fn.popover.Constructor = Popover
91
+
92
+ $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {
93
+ placement: 'right'
94
+ , content: ''
95
+ , template: '<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>'
96
+ })
97
+
98
+ }(window.jQuery);
@@ -1,5 +1,5 @@
1
1
  /* ========================================================
2
- * bootstrap-tab.js v2.0.3
2
+ * bootstrap-tab.js v2.0.4
3
3
  * http://twitter.github.com/bootstrap/javascript.html#tabs
4
4
  * ========================================================
5
5
  * Copyright 2012 Twitter, Inc.
@@ -18,7 +18,6 @@
18
18
  * ======================================================== */
19
19
 
20
20
 
21
-
22
21
  !function ($) {
23
22
 
24
23
  "use strict"; // jshint ;_;
@@ -133,4 +132,4 @@
133
132
  })
134
133
  })
135
134
 
136
- }(window.jQuery);
135
+ }(window.jQuery);
@@ -0,0 +1,275 @@
1
+ /* ===========================================================
2
+ * bootstrap-tooltip.js v2.0.4
3
+ * http://twitter.github.com/bootstrap/javascript.html#tooltips
4
+ * Inspired by the original jQuery.tipsy by Jason Frame
5
+ * ===========================================================
6
+ * Copyright 2012 Twitter, Inc.
7
+ *
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * you may not use this file except in compliance with the License.
10
+ * You may obtain a copy of the License at
11
+ *
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ * ========================================================== */
20
+
21
+
22
+ !function ($) {
23
+
24
+ "use strict"; // jshint ;_;
25
+
26
+
27
+ /* TOOLTIP PUBLIC CLASS DEFINITION
28
+ * =============================== */
29
+
30
+ var Tooltip = function (element, options) {
31
+ this.init('tooltip', element, options)
32
+ }
33
+
34
+ Tooltip.prototype = {
35
+
36
+ constructor: Tooltip
37
+
38
+ , init: function (type, element, options) {
39
+ var eventIn
40
+ , eventOut
41
+
42
+ this.type = type
43
+ this.$element = $(element)
44
+ this.options = this.getOptions(options)
45
+ this.enabled = true
46
+
47
+ if (this.options.trigger != 'manual') {
48
+ eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
49
+ eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'
50
+ this.$element.on(eventIn, this.options.selector, $.proxy(this.enter, this))
51
+ this.$element.on(eventOut, this.options.selector, $.proxy(this.leave, this))
52
+ }
53
+
54
+ this.options.selector ?
55
+ (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
56
+ this.fixTitle()
57
+ }
58
+
59
+ , getOptions: function (options) {
60
+ options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())
61
+
62
+ if (options.delay && typeof options.delay == 'number') {
63
+ options.delay = {
64
+ show: options.delay
65
+ , hide: options.delay
66
+ }
67
+ }
68
+
69
+ return options
70
+ }
71
+
72
+ , enter: function (e) {
73
+ var self = $(e.currentTarget)[this.type](this._options).data(this.type)
74
+
75
+ if (!self.options.delay || !self.options.delay.show) return self.show()
76
+
77
+ clearTimeout(this.timeout)
78
+ self.hoverState = 'in'
79
+ this.timeout = setTimeout(function() {
80
+ if (self.hoverState == 'in') self.show()
81
+ }, self.options.delay.show)
82
+ }
83
+
84
+ , leave: function (e) {
85
+ var self = $(e.currentTarget)[this.type](this._options).data(this.type)
86
+
87
+ if (this.timeout) clearTimeout(this.timeout)
88
+ if (!self.options.delay || !self.options.delay.hide) return self.hide()
89
+
90
+ self.hoverState = 'out'
91
+ this.timeout = setTimeout(function() {
92
+ if (self.hoverState == 'out') self.hide()
93
+ }, self.options.delay.hide)
94
+ }
95
+
96
+ , show: function () {
97
+ var $tip
98
+ , inside
99
+ , pos
100
+ , actualWidth
101
+ , actualHeight
102
+ , placement
103
+ , tp
104
+
105
+ if (this.hasContent() && this.enabled) {
106
+ $tip = this.tip()
107
+ this.setContent()
108
+
109
+ if (this.options.animation) {
110
+ $tip.addClass('fade')
111
+ }
112
+
113
+ placement = typeof this.options.placement == 'function' ?
114
+ this.options.placement.call(this, $tip[0], this.$element[0]) :
115
+ this.options.placement
116
+
117
+ inside = /in/.test(placement)
118
+
119
+ $tip
120
+ .remove()
121
+ .css({ top: 0, left: 0, display: 'block' })
122
+ .appendTo(inside ? this.$element : document.body)
123
+
124
+ pos = this.getPosition(inside)
125
+
126
+ actualWidth = $tip[0].offsetWidth
127
+ actualHeight = $tip[0].offsetHeight
128
+
129
+ switch (inside ? placement.split(' ')[1] : placement) {
130
+ case 'bottom':
131
+ tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
132
+ break
133
+ case 'top':
134
+ tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
135
+ break
136
+ case 'left':
137
+ tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
138
+ break
139
+ case 'right':
140
+ tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
141
+ break
142
+ }
143
+
144
+ $tip
145
+ .css(tp)
146
+ .addClass(placement)
147
+ .addClass('in')
148
+ }
149
+ }
150
+
151
+ , isHTML: function(text) {
152
+ // html string detection logic adapted from jQuery
153
+ return typeof text != 'string'
154
+ || ( text.charAt(0) === "<"
155
+ && text.charAt( text.length - 1 ) === ">"
156
+ && text.length >= 3
157
+ ) || /^(?:[^<]*<[\w\W]+>[^>]*$)/.exec(text)
158
+ }
159
+
160
+ , setContent: function () {
161
+ var $tip = this.tip()
162
+ , title = this.getTitle()
163
+
164
+ $tip.find('.tooltip-inner')[this.isHTML(title) ? 'html' : 'text'](title)
165
+ $tip.removeClass('fade in top bottom left right')
166
+ }
167
+
168
+ , hide: function () {
169
+ var that = this
170
+ , $tip = this.tip()
171
+
172
+ $tip.removeClass('in')
173
+
174
+ function removeWithAnimation() {
175
+ var timeout = setTimeout(function () {
176
+ $tip.off($.support.transition.end).remove()
177
+ }, 500)
178
+
179
+ $tip.one($.support.transition.end, function () {
180
+ clearTimeout(timeout)
181
+ $tip.remove()
182
+ })
183
+ }
184
+
185
+ $.support.transition && this.$tip.hasClass('fade') ?
186
+ removeWithAnimation() :
187
+ $tip.remove()
188
+ }
189
+
190
+ , fixTitle: function () {
191
+ var $e = this.$element
192
+ if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
193
+ $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')
194
+ }
195
+ }
196
+
197
+ , hasContent: function () {
198
+ return this.getTitle()
199
+ }
200
+
201
+ , getPosition: function (inside) {
202
+ return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), {
203
+ width: this.$element[0].offsetWidth
204
+ , height: this.$element[0].offsetHeight
205
+ })
206
+ }
207
+
208
+ , getTitle: function () {
209
+ var title
210
+ , $e = this.$element
211
+ , o = this.options
212
+
213
+ title = $e.attr('data-original-title')
214
+ || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
215
+
216
+ return title
217
+ }
218
+
219
+ , tip: function () {
220
+ return this.$tip = this.$tip || $(this.options.template)
221
+ }
222
+
223
+ , validate: function () {
224
+ if (!this.$element[0].parentNode) {
225
+ this.hide()
226
+ this.$element = null
227
+ this.options = null
228
+ }
229
+ }
230
+
231
+ , enable: function () {
232
+ this.enabled = true
233
+ }
234
+
235
+ , disable: function () {
236
+ this.enabled = false
237
+ }
238
+
239
+ , toggleEnabled: function () {
240
+ this.enabled = !this.enabled
241
+ }
242
+
243
+ , toggle: function () {
244
+ this[this.tip().hasClass('in') ? 'hide' : 'show']()
245
+ }
246
+
247
+ }
248
+
249
+
250
+ /* TOOLTIP PLUGIN DEFINITION
251
+ * ========================= */
252
+
253
+ $.fn.tooltip = function ( option ) {
254
+ return this.each(function () {
255
+ var $this = $(this)
256
+ , data = $this.data('tooltip')
257
+ , options = typeof option == 'object' && option
258
+ if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
259
+ if (typeof option == 'string') data[option]()
260
+ })
261
+ }
262
+
263
+ $.fn.tooltip.Constructor = Tooltip
264
+
265
+ $.fn.tooltip.defaults = {
266
+ animation: true
267
+ , placement: 'top'
268
+ , selector: false
269
+ , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
270
+ , trigger: 'hover'
271
+ , title: ''
272
+ , delay: 0
273
+ }
274
+
275
+ }(window.jQuery);
@@ -1,5 +1,8 @@
1
- //= require dj_mon_bootstrap_tab
2
- //= require dj_mon_mustache
1
+ //= require dj_mon/bootstrap_tooltip
2
+ //= require dj_mon/bootstrap_tab
3
+ //= require dj_mon/bootstrap_popover
4
+ //= require dj_mon/bootstrap_modal
5
+ //= require dj_mon/mustache
3
6
 
4
7
  $(function(){
5
8
 
@@ -13,7 +16,7 @@ $(function(){
13
16
  if(data.length > 0)
14
17
  var output = Mustache.render(template, data);
15
18
  else
16
- var output = "<div class='alert alert-info centered'>No Jobs</div>";
19
+ var output = "<div class='alert centered'>No Jobs</div>";
17
20
  tabContent.html(output);
18
21
  });
19
22
 
@@ -21,6 +24,20 @@ $(function(){
21
24
 
22
25
  $('.nav.nav-tabs li.active a[data-toggle="tab"]').trigger('shown');
23
26
 
27
+ $('a[rel=popover]').live('mouseenter', function(){
28
+ $(this).popover('show');
29
+ });
30
+
31
+ $('a[rel=modal]').live('click', function(){
32
+ var template = $('#last_error_template').html();
33
+ var output = Mustache.render(template, { last_error: $(this).data('content') });
34
+ $(output).appendTo($('body')).show();
35
+ });
36
+
37
+ $('[data-dismiss="modal"]').live('click', function(){
38
+ $('.modal').hide().remove();
39
+ });
40
+
24
41
  (function refreshCount() {
25
42
  $.getJSON('/dj_mon/dj_reports/dj_counts/').success(function(data){
26
43
  var template = $('#dj_counts_template').html();
@@ -1,4 +1,4 @@
1
- /*= require 'dj_mon_bootstrap' */
1
+ /*= require 'dj_mon/bootstrap' */
2
2
 
3
3
  body {
4
4
  padding: 90px;
@@ -20,6 +20,10 @@ table.table td.date {
20
20
  text-align: center;
21
21
  }
22
22
 
23
+ code.block {
24
+ display: block;
25
+ word-wrap: break-word;
26
+ }
23
27
  #dj-counts-view {
24
28
  position: relative;
25
29
  top: 12px;
@@ -9,19 +9,19 @@ module DjMon
9
9
  end
10
10
 
11
11
  def all
12
- respond_with DjReport.all
12
+ respond_with DjReport.all_reports
13
13
  end
14
14
 
15
15
  def failed
16
- respond_with DjReport.failed
16
+ respond_with DjReport.failed_reports
17
17
  end
18
18
 
19
19
  def active
20
- respond_with DjReport.active
20
+ respond_with DjReport.active_reports
21
21
  end
22
22
 
23
23
  def queued
24
- respond_with DjReport.queued
24
+ respond_with DjReport.queued_reports
25
25
  end
26
26
 
27
27
  def dj_counts
@@ -9,9 +9,11 @@ module DjMon
9
9
  def as_json(options={})
10
10
  {
11
11
  id: delayed_job.id,
12
+ payload: delayed_job.payload_object.object.to_yaml,
12
13
  priority: delayed_job.priority,
13
14
  attempts: delayed_job.attempts,
14
15
  queue: delayed_job.queue,
16
+ last_error_summary: delayed_job.last_error.to_s.truncate(30),
15
17
  last_error: delayed_job.last_error,
16
18
  failed_at: l_date(delayed_job.failed_at),
17
19
  run_at: l_date(delayed_job.run_at),
@@ -21,6 +23,26 @@ module DjMon
21
23
 
22
24
  class << self
23
25
 
26
+ def all
27
+ Delayed::Job.all
28
+ end
29
+
30
+ def failed
31
+ Delayed::Job.where('delayed_jobs.failed_at IS NOT NULL')
32
+ end
33
+
34
+ def active
35
+ Delayed::Job.where('delayed_jobs.locked_by IS NOT NULL')
36
+ end
37
+
38
+ def queued
39
+ Delayed::Job.where('delayed_jobs.failed_at IS NULL AND delayed_jobs.locked_by IS NULL')
40
+ end
41
+
42
+ def reports_for jobs
43
+ jobs.collect { |job| DjReport.new(job) }
44
+ end
45
+
24
46
  def all_reports
25
47
  reports_for all
26
48
  end
@@ -45,25 +67,6 @@ module DjMon
45
67
  }
46
68
  end
47
69
 
48
- def all
49
- Delayed::Job.all
50
- end
51
-
52
- def failed
53
- Delayed::Job.where('delayed_jobs.failed_at IS NOT NULL')
54
- end
55
-
56
- def active
57
- Delayed::Job.where('delayed_jobs.locked_by IS NOT NULL')
58
- end
59
-
60
- def queued
61
- Delayed::Job.where('delayed_jobs.failed_at IS NULL AND delayed_jobs.locked_by IS NULL')
62
- end
63
-
64
- def reports_for jobs
65
- jobs.collect { |job| DjReport.new(job) }
66
- end
67
70
  end
68
71
 
69
72
  private
@@ -41,7 +41,7 @@
41
41
  {{#.}}
42
42
  %tr
43
43
  %td
44
- {{id}}
44
+ <a href="#" data-content="<code class='block'>{{payload}}</code>" rel='popover' title='Payload'> {{id}} </a>
45
45
  %td
46
46
  {{priority}}
47
47
  %td
@@ -49,11 +49,24 @@
49
49
  %td
50
50
  {{queue}}
51
51
  %td
52
- {{last_error}}
52
+ <a href="#" data-content="{{last_error}}" rel='modal' title='Last Error'> {{last_error_summary}} </a>
53
53
  %td.date
54
- {{}} {{failed_at}}
54
+ {{failed_at}}
55
55
  %td.date
56
56
  {{job.run_at}}
57
57
  %td.date
58
58
  {{created_at}}
59
- {{/.}}
59
+ {{/.}}
60
+
61
+ %script#last_error_template{ :type=> "text/x-handlebars-template" }
62
+ .modal.hide#last_error_modal
63
+ .modal-header
64
+ %button{ type: "button", class: "close", 'data-dismiss' => "modal" }
65
+ ×
66
+ %h3
67
+ Last Error
68
+ .modal-body
69
+ %code
70
+ {{last_error}}
71
+ .modal-footer
72
+ = link_to "Close", '#', class: 'btn btn-primary', 'data-dismiss'=> 'modal'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dj_mon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-02 00:00:00.000000000 Z
12
+ date: 2012-06-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -50,11 +50,14 @@ executables: []
50
50
  extensions: []
51
51
  extra_rdoc_files: []
52
52
  files:
53
+ - app/assets/javascripts/dj_mon/bootstrap_modal.js
54
+ - app/assets/javascripts/dj_mon/bootstrap_popover.js
55
+ - app/assets/javascripts/dj_mon/bootstrap_tab.js
56
+ - app/assets/javascripts/dj_mon/bootstrap_tooltip.js
57
+ - app/assets/javascripts/dj_mon/mustache.js
53
58
  - app/assets/javascripts/dj_mon.js
54
- - app/assets/javascripts/dj_mon_bootstrap_tab.js
55
- - app/assets/javascripts/dj_mon_mustache.js
59
+ - app/assets/stylesheets/dj_mon/bootstrap.css
56
60
  - app/assets/stylesheets/dj_mon.css
57
- - app/assets/stylesheets/dj_mon_bootstrap.css
58
61
  - app/controllers/dj_mon/dj_reports_controller.rb
59
62
  - app/models/dj_mon/dj_report.rb
60
63
  - app/views/dj_mon/dj_reports/index.html.haml