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 +7 -2
- data/app/assets/javascripts/dj_mon/bootstrap_modal.js +218 -0
- data/app/assets/javascripts/dj_mon/bootstrap_popover.js +98 -0
- data/app/assets/javascripts/{dj_mon_bootstrap_tab.js → dj_mon/bootstrap_tab.js} +2 -3
- data/app/assets/javascripts/dj_mon/bootstrap_tooltip.js +275 -0
- data/app/assets/javascripts/{dj_mon_mustache.js → dj_mon/mustache.js} +0 -0
- data/app/assets/javascripts/dj_mon.js +20 -3
- data/app/assets/stylesheets/{dj_mon_bootstrap.css → dj_mon/bootstrap.css} +0 -0
- data/app/assets/stylesheets/dj_mon.css +5 -1
- data/app/controllers/dj_mon/dj_reports_controller.rb +4 -4
- data/app/models/dj_mon/dj_report.rb +22 -19
- data/app/views/dj_mon/dj_reports/index.html.haml +17 -4
- metadata +8 -5
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.
|
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);
|
File without changes
|
@@ -1,5 +1,8 @@
|
|
1
|
-
//= require
|
2
|
-
//= require
|
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
|
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();
|
File without changes
|
@@ -1,4 +1,4 @@
|
|
1
|
-
/*= require '
|
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.
|
12
|
+
respond_with DjReport.all_reports
|
13
13
|
end
|
14
14
|
|
15
15
|
def failed
|
16
|
-
respond_with DjReport.
|
16
|
+
respond_with DjReport.failed_reports
|
17
17
|
end
|
18
18
|
|
19
19
|
def active
|
20
|
-
respond_with DjReport.
|
20
|
+
respond_with DjReport.active_reports
|
21
21
|
end
|
22
22
|
|
23
23
|
def queued
|
24
|
-
respond_with DjReport.
|
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
|
-
{{
|
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
|
+
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-
|
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/
|
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
|