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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/rocket_job_mission_control/base.js.coffee +3 -13
  3. data/app/assets/stylesheets/rocket_job_mission_control/base.scss +38 -5
  4. data/app/assets/stylesheets/rocket_job_mission_control/bootstrap_and_overrides.scss +1 -1
  5. data/app/controllers/rocket_job_mission_control/active_processes_controller.rb +8 -7
  6. data/app/controllers/rocket_job_mission_control/jobs/index_filters_controller.rb +14 -14
  7. data/app/controllers/rocket_job_mission_control/jobs_controller.rb +9 -4
  8. data/app/controllers/rocket_job_mission_control/workers_controller.rb +1 -1
  9. data/app/datatables/rocket_job_mission_control/active_processes_datatable.rb +11 -11
  10. data/app/datatables/rocket_job_mission_control/completed_jobs_datatable.rb +2 -1
  11. data/app/datatables/rocket_job_mission_control/interrupted_jobs_datatable.rb +1 -0
  12. data/app/datatables/rocket_job_mission_control/jobs_datatable.rb +40 -3
  13. data/app/datatables/rocket_job_mission_control/queued_jobs_datatable.rb +1 -0
  14. data/app/datatables/rocket_job_mission_control/running_jobs_datatable.rb +1 -0
  15. data/app/datatables/rocket_job_mission_control/scheduled_jobs_datatable.rb +1 -6
  16. data/app/helpers/rocket_job_mission_control/jobs_helper.rb +1 -9
  17. data/app/views/layouts/rocket_job_mission_control/partials/_header.html.haml +3 -4
  18. data/app/views/rocket_job_mission_control/active_processes/index.html.haml +1 -1
  19. data/app/views/rocket_job_mission_control/dirmon_entries/_sidebar.html.haml +1 -1
  20. data/app/views/rocket_job_mission_control/jobs/edit.html.haml +34 -0
  21. data/app/views/rocket_job_mission_control/jobs/index.html.haml +2 -1
  22. data/app/views/rocket_job_mission_control/jobs/index_filters/aborted.html.haml +2 -1
  23. data/app/views/rocket_job_mission_control/jobs/index_filters/completed.html.haml +2 -1
  24. data/app/views/rocket_job_mission_control/jobs/index_filters/failed.html.haml +2 -1
  25. data/app/views/rocket_job_mission_control/jobs/index_filters/paused.html.haml +2 -1
  26. data/app/views/rocket_job_mission_control/jobs/index_filters/queued.html.haml +2 -1
  27. data/app/views/rocket_job_mission_control/jobs/index_filters/running.html.haml +2 -1
  28. data/app/views/rocket_job_mission_control/jobs/index_filters/scheduled.html.haml +2 -2
  29. data/app/views/rocket_job_mission_control/jobs/show.html.haml +21 -36
  30. data/app/views/rocket_job_mission_control/workers/index.html.haml +1 -1
  31. data/config/routes.rb +1 -1
  32. data/lib/rocket_job_mission_control/engine.rb +6 -0
  33. data/lib/rocket_job_mission_control/version.rb +1 -1
  34. data/spec/controllers/dirmon_entries/index_filters_controller_spec.rb +74 -0
  35. data/spec/controllers/jobs/index_filters_controller_spec.rb +65 -0
  36. data/spec/controllers/jobs_controller_spec.rb +1 -1
  37. data/spec/controllers/workers/index_filters_controller_spec.rb +59 -0
  38. data/spec/dummy/log/test.log +792 -0
  39. data/spec/rails_helper.rb +2 -0
  40. metadata +16 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0e4abab0ff95e45876f0040c82ba295c7df6cea6
4
- data.tar.gz: 956f19de4f8194730a9945f98ff980f5494fd219
3
+ metadata.gz: ffb6fd358569ee47288a00a2f5d909bc37ffb7fe
4
+ data.tar.gz: 20914808b3f576db0c45b607e72cb1998bad3327
5
5
  SHA512:
6
- metadata.gz: 551b600165582ad1513873c326afcd05830cdcfbf51030e4a808581a5311f03b460fc90b853f8ed03f851e3abaa8c809558a544e2061e836aa0fce41c99e8cb4
7
- data.tar.gz: 2e617a157fa542861d6b7a2a63b2ab4bc7291527706346aab37af25081192f790bd39e785eee4e7300206293bbc5b76e4fab09a4144a4c0d4cef90cfd0718ae8
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: 28px;
224
- color: orange;
258
+ font-size: 36px;
259
+ color: white;
225
260
  font-weight: bold;
226
- margin-top: -5px;
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: "Helvetica Neue", Helvetica, Arial, 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
- RocketJob::Job.running.sort(:worker_name).collect do |job|
10
- if job.respond_to?(:input)
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 << [slice.worker_name, job, slice.started_at]
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
- else
16
- busy << [job.worker_name, job, job.started_at]
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 { |result| result.first }
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
- running_jobs = RocketJob::Job.where(state: :running).sort(_id: :desc)
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, running_jobs)) }
10
+ format.json { render(json: RunningJobsDatatable.new(view_context, @jobs)) }
11
11
  end
12
12
  end
13
13
 
14
14
  def paused
15
- paused_jobs = RocketJob::Job.where(state: :paused).sort(_id: :desc)
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, paused_jobs)) }
18
+ format.json { render(json: InterruptedJobsDatatable.new(view_context, @jobs)) }
19
19
  end
20
20
  end
21
21
 
22
22
  def completed
23
- completed_jobs = RocketJob::Job.where(state: :completed).sort(_id: :desc)
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, completed_jobs)) }
26
+ format.json { render(json: CompletedJobsDatatable.new(view_context, @jobs)) }
27
27
  end
28
28
  end
29
29
 
30
30
  def aborted
31
- aborted_jobs = RocketJob::Job.where(state: :aborted).sort(_id: :desc)
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, aborted_jobs)) }
34
+ format.json { render(json: InterruptedJobsDatatable.new(view_context, @jobs)) }
35
35
  end
36
36
  end
37
37
 
38
38
  def failed
39
- failed_jobs = RocketJob::Job.where(state: :failed).sort(_id: :desc)
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, failed_jobs)) }
42
+ format.json { render(json: InterruptedJobsDatatable.new(view_context, @jobs)) }
43
43
  end
44
44
  end
45
45
 
46
46
  def queued
47
- queued_jobs = RocketJob::Job.queued_now.sort(_id: :desc)
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, queued_jobs)) }
50
+ format.json { render(json: QueuedJobsDatatable.new(view_context, @jobs)) }
51
51
  end
52
52
  end
53
53
 
54
54
  def scheduled
55
- scheduled_jobs = RocketJob::Job.scheduled.sort(_id: :desc)
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, scheduled_jobs)) }
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!(job_params)
17
-
18
- redirect_to job_path(@job)
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(:priority)
95
+ params.require(:job).permit(RocketJob::Job.rocket_job_properties)
91
96
  end
92
97
 
93
98
  def error_occurred(exception)
@@ -45,7 +45,7 @@ module RocketJobMissionControl
45
45
  end
46
46
 
47
47
  def destroy
48
- if @worker.destroy
48
+ if @worker.nil? || @worker.destroy
49
49
  flash[:notice] = t(:success, scope: [:worker, :destroy])
50
50
  else
51
51
  flash[:alert] = t(:failure, scope: [:worker, :destroy])
@@ -1,6 +1,6 @@
1
1
  module RocketJobMissionControl
2
2
  class ActiveProcessesDatatable
3
- delegate :params, :link_to, :job_path, :job_icon, to: :@view
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 |worker_name, job, started_at|
23
+ processes.map do |h|
24
24
  {
25
- '0' => worker_name_with_icon(worker_name, job),
26
- '1' => job_name_with_link(job),
27
- '2' => h(job.description.try(:truncate, 50)),
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, job)
60
+ def worker_name_with_icon(worker_name)
61
61
  <<-EOS
62
- <i class="fa #{job_icon(job)}" style="font-size: 75%" title="#{job.state}"></i>
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(job)
67
+ def job_name_with_link(job_class_name, job_id)
68
68
  <<-EOS
69
- <a href="#{job_path(job.id)}">
70
- #{job.class.name}
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 duration completed_at]
19
+ columns = %w[_type description machine_duration completed_at]
19
20
  columns[index.to_i]
20
21
  end
21
22
 
@@ -8,6 +8,7 @@ module RocketJobMissionControl
8
8
  '0' => class_with_link(job),
9
9
  '1' => h(job.description.try(:truncate, 50)),
10
10
  '2' => h(interrupted_ago(job)),
11
+ '3' => action_buttons(job),
11
12
  'DT_RowClass' => "card callout callout-#{job.state}"
12
13
  }
13
14
  end
@@ -1,6 +1,8 @@
1
1
  module RocketJobMissionControl
2
2
  class JobsDatatable
3
- delegate :params, :link_to, :job_path, :job_icon, to: :@view
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
@@ -9,6 +9,7 @@ module RocketJobMissionControl
9
9
  '1' => h(job.description.try(:truncate, 50)),
10
10
  '2' => h(job.priority),
11
11
  '3' => h(job.duration),
12
+ '4' => action_buttons(job),
12
13
  'DT_RowClass' => "card callout callout-#{job.state}"
13
14
  }
14
15
  end
@@ -10,6 +10,7 @@ module RocketJobMissionControl
10
10
  '2' => progress(job),
11
11
  '3' => h(job.priority),
12
12
  '4' => h(started(job)),
13
+ '5' => action_buttons(job),
13
14
  'DT_RowClass' => "card callout callout-#{job.state}"
14
15
  }
15
16
  end