rocketjob_mission_control 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/javascripts/rocket_job_mission_control/base.js.coffee +3 -13
- data/app/assets/stylesheets/rocket_job_mission_control/base.scss +38 -5
- data/app/assets/stylesheets/rocket_job_mission_control/bootstrap_and_overrides.scss +1 -1
- data/app/controllers/rocket_job_mission_control/active_processes_controller.rb +8 -7
- data/app/controllers/rocket_job_mission_control/jobs/index_filters_controller.rb +14 -14
- data/app/controllers/rocket_job_mission_control/jobs_controller.rb +9 -4
- data/app/controllers/rocket_job_mission_control/workers_controller.rb +1 -1
- data/app/datatables/rocket_job_mission_control/active_processes_datatable.rb +11 -11
- data/app/datatables/rocket_job_mission_control/completed_jobs_datatable.rb +2 -1
- data/app/datatables/rocket_job_mission_control/interrupted_jobs_datatable.rb +1 -0
- data/app/datatables/rocket_job_mission_control/jobs_datatable.rb +40 -3
- data/app/datatables/rocket_job_mission_control/queued_jobs_datatable.rb +1 -0
- data/app/datatables/rocket_job_mission_control/running_jobs_datatable.rb +1 -0
- data/app/datatables/rocket_job_mission_control/scheduled_jobs_datatable.rb +1 -6
- data/app/helpers/rocket_job_mission_control/jobs_helper.rb +1 -9
- data/app/views/layouts/rocket_job_mission_control/partials/_header.html.haml +3 -4
- data/app/views/rocket_job_mission_control/active_processes/index.html.haml +1 -1
- data/app/views/rocket_job_mission_control/dirmon_entries/_sidebar.html.haml +1 -1
- data/app/views/rocket_job_mission_control/jobs/edit.html.haml +34 -0
- data/app/views/rocket_job_mission_control/jobs/index.html.haml +2 -1
- data/app/views/rocket_job_mission_control/jobs/index_filters/aborted.html.haml +2 -1
- data/app/views/rocket_job_mission_control/jobs/index_filters/completed.html.haml +2 -1
- data/app/views/rocket_job_mission_control/jobs/index_filters/failed.html.haml +2 -1
- data/app/views/rocket_job_mission_control/jobs/index_filters/paused.html.haml +2 -1
- data/app/views/rocket_job_mission_control/jobs/index_filters/queued.html.haml +2 -1
- data/app/views/rocket_job_mission_control/jobs/index_filters/running.html.haml +2 -1
- data/app/views/rocket_job_mission_control/jobs/index_filters/scheduled.html.haml +2 -2
- data/app/views/rocket_job_mission_control/jobs/show.html.haml +21 -36
- data/app/views/rocket_job_mission_control/workers/index.html.haml +1 -1
- data/config/routes.rb +1 -1
- data/lib/rocket_job_mission_control/engine.rb +6 -0
- data/lib/rocket_job_mission_control/version.rb +1 -1
- data/spec/controllers/dirmon_entries/index_filters_controller_spec.rb +74 -0
- data/spec/controllers/jobs/index_filters_controller_spec.rb +65 -0
- data/spec/controllers/jobs_controller_spec.rb +1 -1
- data/spec/controllers/workers/index_filters_controller_spec.rb +59 -0
- data/spec/dummy/log/test.log +792 -0
- data/spec/rails_helper.rb +2 -0
- metadata +16 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ffb6fd358569ee47288a00a2f5d909bc37ffb7fe
|
4
|
+
data.tar.gz: 20914808b3f576db0c45b607e72cb1998bad3327
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc99088dbcaff508741d44553f8003c3c471030925219d7c38cf647e62d76a67c491e4f3adc195a1cd0ba89af34c0b9804b0b090bd0d1036ce97a21a2a8efd10
|
7
|
+
data.tar.gz: e9f4f0278190e8fb8f6d0cbe567e305ac7a3b6363a45b3a7671f3f562bbee998ca6cfa4366df2ce43cf75995011240c15928ff82758f6a26158e3ccd73d0677e
|
@@ -1,17 +1,7 @@
|
|
1
|
-
$(document).load ->
|
2
|
-
registerJobPriority()
|
3
|
-
|
4
|
-
$(document).on 'ready page:change', ->
|
5
|
-
registerJobPriority()
|
6
|
-
|
7
|
-
registerJobPriority = ->
|
8
|
-
$('#increase_priority').on 'click', ->
|
9
|
-
$('#job_priority').val(parseInt($('#job_priority').val(), 10) + 1)
|
10
|
-
|
11
|
-
$('#decrease_priority').on 'click', ->
|
12
|
-
$('#job_priority').val(parseInt($('#job_priority').val(), 10) - 1)
|
13
|
-
|
14
1
|
$(document).ready ->
|
2
|
+
toggleCanvas()
|
3
|
+
|
4
|
+
toggleCanvas = ->
|
15
5
|
$('[data-toggle=offcanvas]').click ->
|
16
6
|
$(this).toggleClass 'visible-xs text-center'
|
17
7
|
$(this).find('i').toggleClass 'fa-chevron-right fa-chevron-left'
|
@@ -2,6 +2,10 @@ html, body, #wrapper, #wrapper > .container-fluid, #main, .row.row-offcanvas.row
|
|
2
2
|
height: 100%
|
3
3
|
}
|
4
4
|
|
5
|
+
.navbar-default {
|
6
|
+
background-image: linear-gradient(90deg, #000000, #99120f);
|
7
|
+
}
|
8
|
+
|
5
9
|
#wrapper {
|
6
10
|
background-color: #f7f7f7;
|
7
11
|
}
|
@@ -13,6 +17,8 @@ html, body, #wrapper, #wrapper > .container-fluid, #main, .row.row-offcanvas.row
|
|
13
17
|
padding-top:20px;
|
14
18
|
}
|
15
19
|
|
20
|
+
/* Datatables */
|
21
|
+
|
16
22
|
table.datatable {
|
17
23
|
border-collapse: collapse;
|
18
24
|
}
|
@@ -42,11 +48,35 @@ table.dataTable thead > tr > th {
|
|
42
48
|
padding-left: 30px;
|
43
49
|
}
|
44
50
|
|
51
|
+
.datatable .card td {
|
52
|
+
vertical-align: middle;
|
53
|
+
}
|
54
|
+
|
55
|
+
.inline-job-actions > a {
|
56
|
+
display: inline-block;
|
57
|
+
padding: 1px 5px;
|
58
|
+
font-size: 12px;
|
59
|
+
line-height: 1.5;
|
60
|
+
border-radius: 1px;
|
61
|
+
}
|
62
|
+
|
45
63
|
.job-list {
|
46
64
|
height: 100%;
|
47
65
|
min-height: 768px;
|
48
66
|
}
|
49
67
|
|
68
|
+
|
69
|
+
/* Job Edit Page */
|
70
|
+
|
71
|
+
.edit_job {
|
72
|
+
textarea.description-block {
|
73
|
+
height: 166px;
|
74
|
+
}
|
75
|
+
.buttons {
|
76
|
+
margin-top: 1em;
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
50
80
|
.job-status {
|
51
81
|
.lead {
|
52
82
|
color: #50555b;
|
@@ -167,6 +197,7 @@ table.dataTable thead > tr > th {
|
|
167
197
|
|
168
198
|
#sidebar .nav li > a:hover {
|
169
199
|
color: #000;
|
200
|
+
background-color: #dddddd;
|
170
201
|
}
|
171
202
|
|
172
203
|
@media screen and (max-width: 768px) {
|
@@ -214,16 +245,20 @@ table.dataTable thead > tr > th {
|
|
214
245
|
left: 50%;
|
215
246
|
margin-left: -96px !important;
|
216
247
|
display: block;
|
248
|
+
img {
|
249
|
+
display: inline;
|
250
|
+
height: 40px;
|
251
|
+
}
|
217
252
|
}
|
218
253
|
|
219
254
|
.first { left: 15px; }
|
220
255
|
.last { right: 15px; }
|
221
256
|
|
222
257
|
a.navbar-brand.brand {
|
223
|
-
font-size:
|
224
|
-
color:
|
258
|
+
font-size: 36px;
|
259
|
+
color: white;
|
225
260
|
font-weight: bold;
|
226
|
-
margin-top: -
|
261
|
+
margin-top: -10px;
|
227
262
|
|
228
263
|
span {
|
229
264
|
display: inline-block;
|
@@ -246,8 +281,6 @@ table.dataTable thead > tr > th {
|
|
246
281
|
.job-search-box { padding: 20px 100px; }
|
247
282
|
|
248
283
|
.list {
|
249
|
-
a { display: block; }
|
250
|
-
|
251
284
|
.card:nth-child(1) { border-top: 1px solid #ddd; }
|
252
285
|
.card:nth-child(odd) { background-color: #fff; }
|
253
286
|
|
@@ -17,7 +17,7 @@ $text-color: $gray-dark;
|
|
17
17
|
$link-color: $brand-primary;
|
18
18
|
$link-hover-color: darken($link-color, 15%);
|
19
19
|
|
20
|
-
$font-family-sans-serif:
|
20
|
+
$font-family-sans-serif: Arial, sans-serif;
|
21
21
|
$font-family-serif: Georgia, "Times New Roman", Times, serif;
|
22
22
|
$font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace;
|
23
23
|
$font-family-base: $font-family-sans-serif;
|
@@ -4,19 +4,20 @@ module RocketJobMissionControl
|
|
4
4
|
# The list of workers actively processing jobs
|
5
5
|
# [Array[Array<worker_name [String], job [RocketJob::Job], slice_id [String]]]
|
6
6
|
sorted = true
|
7
|
-
t = Time.new
|
8
7
|
busy = []
|
9
|
-
|
10
|
-
|
8
|
+
# Need paused, failed or aborted since workers may still be working on active slices
|
9
|
+
RocketJob::Job.where(state: [:running, :paused, :failed, :aborted]).sort(:worker_name).collect do |job|
|
10
|
+
if job.respond_to?(:input) && job.sub_state == :processing
|
11
11
|
sorted = false
|
12
12
|
job.input.each('state' => 'running') do |slice|
|
13
|
-
busy <<
|
13
|
+
busy << {worker_name: slice.worker_name, klass: job.class.name, description: job.description, started_at: slice.started_at, id: job.id}
|
14
14
|
end
|
15
|
-
|
16
|
-
busy <<
|
15
|
+
elsif job.running?
|
16
|
+
busy << {worker_name: job.worker_name, klass: job.class.name, description: job.description, started_at: job.started_at, id: job.id}
|
17
17
|
end
|
18
18
|
end
|
19
|
-
@busy = sorted ? busy : busy.sort_by { |
|
19
|
+
@busy = sorted ? busy : busy.sort_by { |h| h[:worker_name] }
|
20
|
+
|
20
21
|
respond_to do |format|
|
21
22
|
format.html
|
22
23
|
format.json { render(json: ActiveProcessesDatatable.new(view_context, @busy)) }
|
@@ -4,58 +4,58 @@ module RocketJobMissionControl
|
|
4
4
|
before_filter :show_sidebar
|
5
5
|
|
6
6
|
def running
|
7
|
-
|
7
|
+
@jobs = RocketJob::Job.where(state: :running).sort(_id: :desc)
|
8
8
|
respond_to do |format|
|
9
9
|
format.html
|
10
|
-
format.json { render(json: RunningJobsDatatable.new(view_context,
|
10
|
+
format.json { render(json: RunningJobsDatatable.new(view_context, @jobs)) }
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
14
|
def paused
|
15
|
-
|
15
|
+
@jobs = RocketJob::Job.where(state: :paused).sort(_id: :desc)
|
16
16
|
respond_to do |format|
|
17
17
|
format.html
|
18
|
-
format.json { render(json: InterruptedJobsDatatable.new(view_context,
|
18
|
+
format.json { render(json: InterruptedJobsDatatable.new(view_context, @jobs)) }
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
22
|
def completed
|
23
|
-
|
23
|
+
@jobs = RocketJob::Job.where(state: :completed).sort(_id: :desc)
|
24
24
|
respond_to do |format|
|
25
25
|
format.html
|
26
|
-
format.json { render(json: CompletedJobsDatatable.new(view_context,
|
26
|
+
format.json { render(json: CompletedJobsDatatable.new(view_context, @jobs)) }
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
30
|
def aborted
|
31
|
-
|
31
|
+
@jobs = RocketJob::Job.where(state: :aborted).sort(_id: :desc)
|
32
32
|
respond_to do |format|
|
33
33
|
format.html
|
34
|
-
format.json { render(json: InterruptedJobsDatatable.new(view_context,
|
34
|
+
format.json { render(json: InterruptedJobsDatatable.new(view_context, @jobs)) }
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
38
|
def failed
|
39
|
-
|
39
|
+
@jobs = RocketJob::Job.where(state: :failed).sort(_id: :desc)
|
40
40
|
respond_to do |format|
|
41
41
|
format.html
|
42
|
-
format.json { render(json: InterruptedJobsDatatable.new(view_context,
|
42
|
+
format.json { render(json: InterruptedJobsDatatable.new(view_context, @jobs)) }
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
46
|
def queued
|
47
|
-
|
47
|
+
@jobs = RocketJob::Job.queued_now.sort(_id: :desc)
|
48
48
|
respond_to do |format|
|
49
49
|
format.html
|
50
|
-
format.json { render(json: QueuedJobsDatatable.new(view_context,
|
50
|
+
format.json { render(json: QueuedJobsDatatable.new(view_context, @jobs)) }
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
54
|
def scheduled
|
55
|
-
|
55
|
+
@jobs = RocketJob::Job.scheduled.sort(_id: :desc)
|
56
56
|
respond_to do |format|
|
57
57
|
format.html
|
58
|
-
format.json { render(json: ScheduledJobsDatatable.new(view_context,
|
58
|
+
format.json { render(json: ScheduledJobsDatatable.new(view_context, @jobs)) }
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
@@ -13,9 +13,11 @@ module RocketJobMissionControl
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def update
|
16
|
-
@job.update_attributes
|
17
|
-
|
18
|
-
|
16
|
+
if @job.update_attributes(job_params)
|
17
|
+
redirect_to job_path(@job)
|
18
|
+
else
|
19
|
+
render :edit
|
20
|
+
end
|
19
21
|
end
|
20
22
|
|
21
23
|
def abort
|
@@ -66,6 +68,9 @@ module RocketJobMissionControl
|
|
66
68
|
def show
|
67
69
|
end
|
68
70
|
|
71
|
+
def edit
|
72
|
+
end
|
73
|
+
|
69
74
|
private
|
70
75
|
|
71
76
|
def show_sidebar
|
@@ -87,7 +92,7 @@ module RocketJobMissionControl
|
|
87
92
|
end
|
88
93
|
|
89
94
|
def job_params
|
90
|
-
params.require(:job).permit(
|
95
|
+
params.require(:job).permit(RocketJob::Job.rocket_job_properties)
|
91
96
|
end
|
92
97
|
|
93
98
|
def error_occurred(exception)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module RocketJobMissionControl
|
2
2
|
class ActiveProcessesDatatable
|
3
|
-
delegate :params, :link_to, :job_path, :
|
3
|
+
delegate :params, :link_to, :job_path, :state_icon, to: :@view
|
4
4
|
delegate :h, to: 'ERB::Util'
|
5
5
|
|
6
6
|
def initialize(view, processes)
|
@@ -20,12 +20,12 @@ module RocketJobMissionControl
|
|
20
20
|
private
|
21
21
|
|
22
22
|
def data
|
23
|
-
processes.map do |
|
23
|
+
processes.map do |h|
|
24
24
|
{
|
25
|
-
'0' => worker_name_with_icon(worker_name
|
26
|
-
'1' => job_name_with_link(
|
27
|
-
'2' => h(
|
28
|
-
'3' => h(duration(started_at)),
|
25
|
+
'0' => worker_name_with_icon(h[:worker_name]),
|
26
|
+
'1' => job_name_with_link(h[:klass], h[:id]),
|
27
|
+
'2' => h(h[:description].try!(:truncate, 50)),
|
28
|
+
'3' => h(duration(h[:started_at])),
|
29
29
|
'DT_RowClass' => "card callout callout-running"
|
30
30
|
}
|
31
31
|
end
|
@@ -57,17 +57,17 @@ module RocketJobMissionControl
|
|
57
57
|
Kaminari.paginate_array(records).page(page).per(per_page)
|
58
58
|
end
|
59
59
|
|
60
|
-
def worker_name_with_icon(worker_name
|
60
|
+
def worker_name_with_icon(worker_name)
|
61
61
|
<<-EOS
|
62
|
-
<i class="fa #{
|
62
|
+
<i class="fa #{state_icon(:running)}" style="font-size: 75%" title="running"></i>
|
63
63
|
#{worker_name}
|
64
64
|
EOS
|
65
65
|
end
|
66
66
|
|
67
|
-
def job_name_with_link(
|
67
|
+
def job_name_with_link(job_class_name, job_id)
|
68
68
|
<<-EOS
|
69
|
-
<a href="#{job_path(
|
70
|
-
#{
|
69
|
+
<a href="#{job_path(job_id)}">
|
70
|
+
#{job_class_name}
|
71
71
|
</a>
|
72
72
|
EOS
|
73
73
|
end
|
@@ -9,13 +9,14 @@ module RocketJobMissionControl
|
|
9
9
|
'1' => h(job.description.try(:truncate, 50)),
|
10
10
|
'2' => h(job.duration),
|
11
11
|
'3' => h(completed_ago(job)),
|
12
|
+
'4' => action_buttons(job),
|
12
13
|
'DT_RowClass' => "card callout callout-#{job.state}"
|
13
14
|
}
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
17
18
|
def sort_column(index)
|
18
|
-
columns = %w[_type description
|
19
|
+
columns = %w[_type description machine_duration completed_at]
|
19
20
|
columns[index.to_i]
|
20
21
|
end
|
21
22
|
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module RocketJobMissionControl
|
2
2
|
class JobsDatatable
|
3
|
-
delegate :params, :link_to, :job_path, :job_icon,
|
3
|
+
delegate :params, :link_to, :job_path, :job_icon, :edit_job_path,
|
4
|
+
:abort_job_path, :job_path, :fail_job_path, :run_now_job_path, :pause_job_path,
|
5
|
+
:resume_job_path, :retry_job_path, :job_failures_path, :job_action_link, to: :@view
|
4
6
|
delegate :h, to: 'ERB::Util'
|
5
7
|
|
6
8
|
def initialize(view, jobs)
|
@@ -26,6 +28,7 @@ module RocketJobMissionControl
|
|
26
28
|
'1' => h(job.description.try(:truncate, 50)),
|
27
29
|
'2' => h(job.created_at),
|
28
30
|
'3' => h(job.duration),
|
31
|
+
'4' => action_buttons(job),
|
29
32
|
'DT_RowClass' => "card callout callout-#{job.state}"
|
30
33
|
}
|
31
34
|
end
|
@@ -49,13 +52,48 @@ module RocketJobMissionControl
|
|
49
52
|
|
50
53
|
def class_with_link(job)
|
51
54
|
<<-EOS
|
52
|
-
<a href="#{job_path(job.id)}">
|
55
|
+
<a class='job-link' href="#{job_path(job.id)}">
|
53
56
|
<i class="fa #{job_icon(job)}" style="font-size: 75%" title="#{job.state}"></i>
|
54
57
|
#{job.class.name}
|
55
58
|
</a>
|
56
59
|
EOS
|
57
60
|
end
|
58
61
|
|
62
|
+
def action_buttons(job)
|
63
|
+
events = valid_events(job)
|
64
|
+
buttons = "<div class='inline-job-actions'>"
|
65
|
+
buttons += "#{ link_to( 'Edit', edit_job_path(job), class: 'btn btn-default', title: 'Edit job') }"
|
66
|
+
if job.scheduled?
|
67
|
+
buttons += "#{ job_action_link('Run', run_now_job_path(job), :patch) }"
|
68
|
+
end
|
69
|
+
if events.include?(:abort)
|
70
|
+
buttons += "#{ job_action_link('Abort', abort_job_path(job), :patch) }"
|
71
|
+
end
|
72
|
+
if job.completed? || job.aborted?
|
73
|
+
buttons += "#{ job_action_link('Destroy', job_path(job), :delete) }"
|
74
|
+
end
|
75
|
+
if events.include?(:fail)
|
76
|
+
buttons += "#{ job_action_link('Fail', fail_job_path(job), :patch) }"
|
77
|
+
end
|
78
|
+
if events.include?(:pause)
|
79
|
+
buttons += "#{ job_action_link('Pause', pause_job_path(job), :patch) }"
|
80
|
+
end
|
81
|
+
if events.include?(:resume)
|
82
|
+
buttons += "#{ job_action_link('Resume', resume_job_path(job), :patch) }"
|
83
|
+
end
|
84
|
+
if events.include?(:retry)
|
85
|
+
buttons += "#{ job_action_link('Retry', retry_job_path(job), :patch) }"
|
86
|
+
end
|
87
|
+
if job.respond_to?(:input) && job.input.failed_count > 0
|
88
|
+
buttons += "#{ link_to('view errors', job_failures_path(job), class: 'btn btn-default') }"
|
89
|
+
end
|
90
|
+
buttons += "</div>"
|
91
|
+
end
|
92
|
+
|
93
|
+
def valid_events(job)
|
94
|
+
job.aasm.events.collect{ |e| e.name }
|
95
|
+
end
|
96
|
+
|
59
97
|
def page
|
60
98
|
(params[:start].to_i / per_page) + 1
|
61
99
|
end
|
@@ -84,7 +122,6 @@ module RocketJobMissionControl
|
|
84
122
|
def filter_records(records)
|
85
123
|
return records unless (params[:search].present? && params[:search][:value].present?)
|
86
124
|
conditions = params[:search][:value]
|
87
|
-
ap conditions
|
88
125
|
records = RocketJobMissionControl::Jobs::Search.new(conditions, records).execute if conditions
|
89
126
|
records
|
90
127
|
end
|