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
@@ -1,6 +1,5 @@
1
1
  module RocketJobMissionControl
2
2
  class ScheduledJobsDatatable < JobsDatatable
3
- delegate :run_now_job_path, to: :@view
4
3
  private
5
4
 
6
5
  def data
@@ -10,7 +9,7 @@ module RocketJobMissionControl
10
9
  '1' => h(job.description.try(:truncate, 50)),
11
10
  '2' => h(time_till_run(job)),
12
11
  '3' => h(cron_schedule(job)),
13
- '4' => run_now(job),
12
+ '4' => action_buttons(job),
14
13
  'DT_RowClass' => "card callout callout-#{job.state}"
15
14
  }
16
15
  end
@@ -28,9 +27,5 @@ module RocketJobMissionControl
28
27
  def cron_schedule(job)
29
28
  job.cron_schedule if job.respond_to?(:cron_schedule)
30
29
  end
31
-
32
- def run_now(job)
33
- "#{ link_to 'Run', run_now_job_path(job), method: :patch, class: 'btn btn-default btn-xs', data: { confirm: "Run #{job.class.name} now?" } }"
34
- end
35
30
  end
36
31
  end
@@ -20,20 +20,12 @@ module RocketJobMissionControl
20
20
  action,
21
21
  path,
22
22
  method: http_method,
23
+ title: "#{action} job",
23
24
  class: 'btn btn-default',
24
25
  data: {confirm: t(:confirm, scope: [:job, :action], action: action)}
25
26
  )
26
27
  end
27
28
 
28
- def view_logs_link(job)
29
- link_to(
30
- 'view logs',
31
- "http://localhost:5601/app/kibana#/discover?_g=(refreshInterval:(display:'5%20seconds',pause:!f,section:1,value:5000),time:(from:now-15m,mode:quick,to:now))&_a=(columns:!(level,duration,name,message,host),index:'semantic_logger-*',interval:auto,query:(query_string:(analyze_wildcard:!t,query:'tags:#{job.id.to_s}')),sort:!(timestamp,desc))",
32
- class: 'btn btn-default',
33
- target: '_blank'
34
- )
35
- end
36
-
37
29
  def job_states
38
30
  @job_states ||= RocketJob::Job.aasm.states.map { |state| state.name.to_s }
39
31
  end
@@ -7,9 +7,8 @@
7
7
  %span.icon-bar
8
8
  %span.icon-bar
9
9
  %a.navbar-brand.brand{ href: 'http://rocketjob.io', target: '_blank'}
10
- = image_tag('rocket_job_mission_control/rocket-icon-64x64.png', size: '32x32')
11
- Rocket
12
- %span Job
10
+ = image_tag('rocket_job_mission_control/rocket-icon-64x64.png')
11
+ Rocket Job
13
12
  .navbar-collapse.collapse
14
13
  %ul.nav.navbar-nav
15
14
  %li
@@ -30,4 +29,4 @@
30
29
  Directory Monitors
31
30
  %ul.nav.navbar-nav.navbar-right
32
31
  %li
33
- %a{:href => main_app.root_path } Home
32
+ %a{:href => '/' } Home
@@ -2,7 +2,7 @@
2
2
  .list
3
3
  .row
4
4
  .col-sm-10
5
- %h2 Active Processes
5
+ %h2 Active Workers
6
6
  .col-sm-2
7
7
  .btn.btn-default.pull-right.dt-reload{ data: { behavior: 'reload' } }
8
8
  %i.fa.fa-refresh
@@ -2,7 +2,7 @@
2
2
  %li
3
3
  = link_to(new_dirmon_entry_path) do
4
4
  %i.fa.fa-plus
5
- New Entry
5
+ Create
6
6
  %li
7
7
  = link_to(dirmon_entries_path) do
8
8
  %i.fa.fa-list
@@ -0,0 +1,34 @@
1
+ .container-fluid
2
+ .lead= "Edit #{@job._type}"
3
+
4
+ - if @job.errors.present?
5
+ .alert.alert-alert
6
+ Invalid Job!
7
+ - @job.errors.messages.each_pair do |field, message|
8
+ .message
9
+ = "#{field.to_s.humanize} is not valid."
10
+
11
+ = form_for(@job, as: :job, url: job_path(@job)) do |f|
12
+ .row
13
+ .col-md-8
14
+ = f.label :description
15
+ = f.text_area :description, value: @job.description, class: 'form-control description-block'
16
+ .col-md-4
17
+ = f.label :priority
18
+ = f.number_field :priority, value: @job.priority, class: 'form-control'
19
+ .col-md-4
20
+ = f.label :log_level
21
+ = f.select :log_level, ['', 'trace', 'debug', 'info', 'warn', 'error', 'fatal'], {}, { class: 'form-control' }
22
+ - if @job.method_exists?(:max_active_workers)
23
+ .col-md-4
24
+ = f.label :max_active_workers
25
+ = f.number_field :max_active_workers, class: 'form-control'
26
+ - if @job.method_exists?(:cron_schedule)
27
+ .col-md-4
28
+ = f.label :cron_schedule
29
+ = f.text_field :cron_schedule, class: 'form-control'
30
+ .row
31
+ .col-md-12
32
+ .buttons
33
+ = f.submit 'Update', class: 'btn btn-primary'
34
+ = link_to 'Cancel', :back, class: 'btn btn-default'
@@ -13,12 +13,13 @@
13
13
  %th Description
14
14
  %th Created
15
15
  %th Duration
16
+ %th Actions
16
17
  %tbody
17
18
 
18
19
  :javascript
19
20
  jQuery(function() {
20
21
  new RjmcDatatable(
21
22
  $(".jobs-datatable"),
22
- [{data: '0'}, {data: '1'}, {data: '2'}, {data: '3', orderable: false}]
23
+ [{data: '0'}, {data: '1'}, {data: '2'}, {data: '3', orderable: false}, {data: '4', orderable: false}]
23
24
  );
24
25
  });
@@ -12,11 +12,12 @@
12
12
  %th Class
13
13
  %th Description
14
14
  %th Aborted
15
+ %th Actions
15
16
  %tbody
16
17
 
17
18
  :javascript
18
19
  jQuery(function() {
19
20
  new RjmcDatatable(
20
21
  $(".jobs-datatable"),
21
- [{data: '0'}, {data: '1'}, {data: '2'}]);
22
+ [{data: '0', width: '30%'}, {data: '1', width: '30%'}, {data: '2'}, {data: '3', orderable: false}]);
22
23
  });
@@ -13,11 +13,12 @@
13
13
  %th Description
14
14
  %th Duration
15
15
  %th Completed
16
+ %th Actions
16
17
  %tbody
17
18
 
18
19
  :javascript
19
20
  jQuery(function() {
20
21
  new RjmcDatatable(
21
22
  $(".jobs-datatable"),
22
- [{data: '0'}, {data: '1'}, {data: '2', orderable: false}, {data: '3'}]);
23
+ [{data: '0'}, {data: '1'}, {data: '2', orderable: false}, {data: '3'}, {data: '4', orderable: false}]);
23
24
  });
@@ -12,11 +12,12 @@
12
12
  %th Class
13
13
  %th Description
14
14
  %th Failed
15
+ %th Actions
15
16
  %tbody
16
17
 
17
18
  :javascript
18
19
  jQuery(function() {
19
20
  new RjmcDatatable(
20
21
  $(".jobs-datatable"),
21
- [{data: '0'}, {data: '1'}, {data: '2'}]);
22
+ [{data: '0', width: '30%'}, {data: '1', width: '30%'}, {data: '2'}, {data: '3', orderable: false}]);
22
23
  });
@@ -12,11 +12,12 @@
12
12
  %th Class
13
13
  %th Description
14
14
  %th Paused
15
+ %th Actions
15
16
  %tbody
16
17
 
17
18
  :javascript
18
19
  jQuery(function() {
19
20
  new RjmcDatatable(
20
21
  $(".jobs-datatable"),
21
- [{data: '0'}, {data: '1'}, {data: '2'}]);
22
+ [{data: '0', width: '30%'}, {data: '1', width: '30%'}, {data: '2'}, {data: '3', orderable: false}]);
22
23
  });
@@ -13,11 +13,12 @@
13
13
  %th Description
14
14
  %th Priority
15
15
  %th Queued For
16
+ %th Actions
16
17
  %tbody
17
18
 
18
19
  :javascript
19
20
  jQuery(function() {
20
21
  new RjmcDatatable(
21
22
  $(".jobs-datatable"),
22
- [{data: '0'}, {data: '1'}, {data: '2'}, {data: '3', orderable: false}]);
23
+ [{data: '0'}, {data: '1'}, {data: '2'}, {data: '3', orderable: false}, {data: '4', orderable: false}]);
23
24
  });
@@ -14,11 +14,12 @@
14
14
  %th Progress
15
15
  %th Priority
16
16
  %th Started
17
+ %th Actions
17
18
  %tbody
18
19
 
19
20
  :javascript
20
21
  jQuery(function() {
21
22
  new RjmcDatatable(
22
23
  $(".jobs-datatable"),
23
- [{data: '0'}, {data: '1'}, {data: '2', orderable: false}, {data: '3'}, {data: '4'}]);
24
+ [{data: '0'}, {data: '1'}, {data: '2', orderable: false}, {data: '3'}, {data: '4'}, {data: '5', orderable: false}]);
24
25
  });
@@ -13,12 +13,12 @@
13
13
  %th Description
14
14
  %th Runs in
15
15
  %th Cron Schedule
16
- %th Run Now
16
+ %th Actions
17
17
  %tbody
18
18
 
19
19
  :javascript
20
20
  jQuery(function() {
21
21
  new RjmcDatatable(
22
22
  $(".jobs-datatable"),
23
- [{data: '0'}, {data: '1'}, {data: '2', orderable: false}, {data: '3'}, {data: '4', orderable: false}]);
23
+ [{data: '0'}, {data: '1'}, {data: '2'}, {data: '3'}, {data: '4', orderable: false}]);
24
24
  });
@@ -8,46 +8,31 @@
8
8
  .right{ class: @job.state.to_s }
9
9
  = @job.state
10
10
 
11
- .priority.pull-right
12
- = form_for(@job, as: :job, url: job_path(@job), html: {method: :patch}) do |f|
11
+ .btn-toolbar.job-actions.pull-right
12
+ .btn-group
13
+ - valid_events = @job.aasm.events.collect{ |e| e.name }
14
+ - if valid_events.include?(:abort)
15
+ = job_action_link('Abort', rocket_job_mission_control.abort_job_path(@job), :patch)
13
16
 
14
- .input-group.priority-group
15
- = f.text_field(:priority, value: @job.priority, class: 'form-control')
17
+ - if @job.completed? || @job.aborted?
18
+ = job_action_link('Destroy', rocket_job_mission_control.job_path(@job), :delete)
16
19
 
17
- .input-group-btn-vertical
18
- %button#increase_priority.btn.btn-default.up{ type: 'button' }
19
- %i.fa.fa-caret-up
20
+ - if valid_events.include?(:fail)
21
+ = job_action_link('Fail', rocket_job_mission_control.fail_job_path(@job), :patch)
20
22
 
21
- %button#decrease_priority.btn.btn-default.down{ type: 'button' }
22
- %i.fa.fa-caret-down
23
+ - if valid_events.include?(:pause)
24
+ = job_action_link('Pause', rocket_job_mission_control.pause_job_path(@job), :patch)
23
25
 
24
- = submit_tag "set", class: "btn btn-sm btn-primary priority-set"
26
+ - if valid_events.include?(:resume)
27
+ = job_action_link('Resume', rocket_job_mission_control.resume_job_path(@job), :patch)
25
28
 
26
- .job-actions.btn-group.pull-right{ style: 'margin-right: 1em;' }
27
- - valid_events = @job.aasm.events.collect{ |e| e.name }
28
- - if valid_events.include?(:abort)
29
- = job_action_link('abort', rocket_job_mission_control.abort_job_path(@job), :patch)
29
+ - if valid_events.include?(:retry)
30
+ = job_action_link('Retry', rocket_job_mission_control.retry_job_path(@job), :patch)
30
31
 
31
- - if @job.completed? || @job.aborted?
32
- = job_action_link('destroy', rocket_job_mission_control.job_path(@job), :delete)
32
+ - if @job.respond_to?(:input) && @job.input.failed_count > 0
33
+ = link_to('view errors', job_failures_path(@job), class: 'btn btn-default')
34
+ .btn-group
35
+ = link_to "Edit", edit_job_path(@job), class: "btn btn-default"
33
36
 
34
- - if valid_events.include?(:fail)
35
- = job_action_link('fail', rocket_job_mission_control.fail_job_path(@job), :patch)
36
-
37
- - if valid_events.include?(:pause)
38
- = job_action_link('pause', rocket_job_mission_control.pause_job_path(@job), :patch)
39
-
40
- - if valid_events.include?(:resume)
41
- = job_action_link('resume', rocket_job_mission_control.resume_job_path(@job), :patch)
42
-
43
- - if valid_events.include?(:retry)
44
- = job_action_link('retry', rocket_job_mission_control.retry_job_path(@job), :patch)
45
-
46
- - if @job.respond_to?(:input) && @job.input.failed_count > 0
47
- = link_to('view errors', job_failures_path(@job), class: 'btn btn-default')
48
-
49
- = view_logs_link(@job)
50
-
51
- .clearfix
52
-
53
- = render partial: 'status', locals: { job: @job }
37
+ .col-md-12
38
+ = render partial: 'status', locals: { job: @job }
@@ -33,5 +33,5 @@
33
33
  jQuery(function() {
34
34
  new RjmcDatatable(
35
35
  $('.workers-datatable'),
36
- [{data: '0'}, {data: '1', orderable: false}, {data: '2', orderable: false}, {data: '3', orderable: false}, {data: '4', orderable: false}]);
36
+ [{data: '0'}, {data: '1', orderable: false}, {data: '2'}, {data: '3'}, {data: '4', orderable: false}]);
37
37
  });
@@ -1,6 +1,6 @@
1
1
  RocketJobMissionControl::Engine.routes.draw do
2
2
 
3
- resources :jobs, only: [:index, :show, :update, :destroy] do
3
+ resources :jobs, only: [:index, :show, :update, :destroy, :edit] do
4
4
  collection do
5
5
  get :running, to: 'jobs/index_filters#running'
6
6
  get :scheduled, to: 'jobs/index_filters#scheduled'
@@ -13,5 +13,11 @@ module RocketJobMissionControl
13
13
  require 'coffee-rails'
14
14
  require 'kaminari'
15
15
  require 'jquery-datatables-rails'
16
+
17
+ config.to_prepare do
18
+ Rails.application.config.assets.precompile += %w(
19
+ rocket_job_mission_control/rocket-icon-64x64.png
20
+ )
21
+ end
16
22
  end
17
23
  end
@@ -1,3 +1,3 @@
1
1
  module RocketJobMissionControl
2
- VERSION = '2.0.0'
2
+ VERSION = '2.1.0'
3
3
  end
@@ -0,0 +1,74 @@
1
+ require 'rails_helper'
2
+
3
+ class AJob < RocketJob::Job
4
+ def perform(id)
5
+ id
6
+ end
7
+ end
8
+
9
+ module RocketJobMissionControl
10
+ module DirmonEntries
11
+ RSpec.describe IndexFiltersController do
12
+ routes { Engine.routes }
13
+
14
+ states = %w(pending enabled failed disabled)
15
+
16
+ states.each_with_index do |state, i|
17
+ describe "GET ##{state}" do
18
+ describe "with no #{state} dirmons" do
19
+ before do
20
+ get state.to_sym
21
+ end
22
+
23
+ it "succeeds" do
24
+ expect(response.status).to be(200)
25
+ end
26
+
27
+ it 'renders template' do
28
+ expect(response).to render_template(state)
29
+ end
30
+
31
+ it "returns no jobs" do
32
+ expect(assigns(:dirmons).count).to eq(0)
33
+ end
34
+ end
35
+
36
+ describe "with #{state} dirmons" do
37
+ let(:not_state) { states[i-1] }
38
+ let!(:state_dirmon) { RocketJob::DirmonEntry.create!(state: state,
39
+ pattern: '21',
40
+ arguments: ['42'],
41
+ job_class_name: 'AJob') }
42
+
43
+ before do
44
+ RocketJob::DirmonEntry.create!(
45
+ name: 'Test',
46
+ state: not_state,
47
+ arguments: ['42'],
48
+ pattern: '21',
49
+ job_class_name: 'AJob')
50
+ get state.to_sym
51
+ end
52
+
53
+ after do
54
+ DatabaseCleaner.clean
55
+ end
56
+
57
+ it "succeeds" do
58
+ expect(response.status).to be(200)
59
+ end
60
+
61
+ it 'renders template' do
62
+ expect(response).to render_template(state)
63
+ end
64
+
65
+ it "grabs a filtered list of dirmons" do
66
+ expect(assigns(:dirmons)).to match_array([state_dirmon])
67
+
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,65 @@
1
+ require 'rails_helper'
2
+
3
+ module RocketJobMissionControl
4
+ module Jobs
5
+ RSpec.describe IndexFiltersController do
6
+ routes { Engine.routes }
7
+
8
+ states = %w(running paused completed aborted failed queued scheduled)
9
+
10
+ states.each_with_index do |state, i|
11
+ describe "GET ##{state}" do
12
+ describe "with no #{state} jobs" do
13
+ before do
14
+ get state.to_sym
15
+ end
16
+
17
+ it "succeeds" do
18
+ expect(response.status).to be(200)
19
+ end
20
+
21
+ it 'renders template' do
22
+ expect(response).to render_template(state)
23
+ end
24
+
25
+ it "returns no jobs" do
26
+ expect(assigns(:jobs).count).to eq(0)
27
+ end
28
+ end
29
+
30
+ describe "with #{state} jobs" do
31
+ let(:not_state) { states[i-1] }
32
+ let(:state_job) {
33
+ if state == 'scheduled'
34
+ RocketJob::Job.create(state: :queued, run_at: Date.tomorrow)
35
+ else
36
+ RocketJob::Job.create(state: state)
37
+ end
38
+ }
39
+
40
+ before do
41
+ RocketJob::Job.create(state: not_state)
42
+ get state.to_sym
43
+ end
44
+
45
+ after do
46
+ DatabaseCleaner.clean
47
+ end
48
+
49
+ it "succeeds" do
50
+ expect(response.status).to be(200)
51
+ end
52
+
53
+ it 'renders template' do
54
+ expect(response).to render_template(state)
55
+ end
56
+
57
+ it "grabs a filtered list of rocket jobs" do
58
+ expect(assigns(:jobs)).to match_array([state_job])
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end