rocketjob_mission_control 2.0.0 → 2.1.0

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/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