rocketjob_mission_control 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +26 -0
  4. data/app/assets/javascripts/rocket_job_mission_control/application.js +18 -0
  5. data/app/assets/javascripts/rocket_job_mission_control/base.js.coffee +24 -0
  6. data/app/assets/javascripts/rocket_job_mission_control/jobs.js.coffee +11 -0
  7. data/app/assets/stylesheets/rocket_job_mission_control/application.scss +18 -0
  8. data/app/assets/stylesheets/rocket_job_mission_control/base.scss +468 -0
  9. data/app/assets/stylesheets/rocket_job_mission_control/bootstrap_and_overrides.scss +6 -0
  10. data/app/assets/stylesheets/rocket_job_mission_control/callout.scss +40 -0
  11. data/app/assets/stylesheets/rocket_job_mission_control/jobs.scss +16 -0
  12. data/app/assets/stylesheets/rocket_job_mission_control/jquery.bootstrap-touchspin.scss +45 -0
  13. data/app/controllers/rocket_job_mission_control/application_controller.rb +15 -0
  14. data/app/controllers/rocket_job_mission_control/jobs/inputs_controller.rb +9 -0
  15. data/app/controllers/rocket_job_mission_control/jobs/slices_controller.rb +10 -0
  16. data/app/controllers/rocket_job_mission_control/jobs_controller.rb +97 -0
  17. data/app/controllers/rocket_job_mission_control/workers_controller.rb +79 -0
  18. data/app/helpers/rocket_job_mission_control/application_helper.rb +16 -0
  19. data/app/helpers/rocket_job_mission_control/jobs_helper.rb +57 -0
  20. data/app/helpers/rocket_job_mission_control/workers_helper.rb +14 -0
  21. data/app/views/layouts/rocket_job_mission_control/application.html.haml +43 -0
  22. data/app/views/layouts/rocket_job_mission_control/partials/_header.html.haml +16 -0
  23. data/app/views/layouts/rocket_job_mission_control/partials/_sidebar.html.haml +20 -0
  24. data/app/views/rocket_job_mission_control/jobs/_list.html.haml +33 -0
  25. data/app/views/rocket_job_mission_control/jobs/_status.html.haml +39 -0
  26. data/app/views/rocket_job_mission_control/jobs/index.html.haml +8 -0
  27. data/app/views/rocket_job_mission_control/jobs/running.html.haml +37 -0
  28. data/app/views/rocket_job_mission_control/jobs/show.html.haml +50 -0
  29. data/app/views/rocket_job_mission_control/workers/_actions.html.haml +9 -0
  30. data/app/views/rocket_job_mission_control/workers/index.html.haml +51 -0
  31. data/config/locales/en.yml +57 -0
  32. data/config/routes.rb +28 -0
  33. data/lib/rocket_job_mission_control/engine.rb +15 -0
  34. data/lib/rocket_job_mission_control/version.rb +3 -0
  35. data/lib/rocketjob_mission_control.rb +4 -0
  36. data/lib/tasks/rocket_job_mission_control_tasks.rake +4 -0
  37. data/spec/controllers/application_controller_spec.rb +47 -0
  38. data/spec/controllers/jobs_controller_spec.rb +217 -0
  39. data/spec/controllers/workers_controller_spec.rb +125 -0
  40. data/spec/dummy/README.rdoc +28 -0
  41. data/spec/dummy/Rakefile +6 -0
  42. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  43. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  44. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  45. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  46. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  47. data/spec/dummy/bin/bundle +3 -0
  48. data/spec/dummy/bin/rails +4 -0
  49. data/spec/dummy/bin/rake +4 -0
  50. data/spec/dummy/config.ru +4 -0
  51. data/spec/dummy/config/application.rb +25 -0
  52. data/spec/dummy/config/boot.rb +5 -0
  53. data/spec/dummy/config/database.yml +25 -0
  54. data/spec/dummy/config/environment.rb +5 -0
  55. data/spec/dummy/config/environments/development.rb +34 -0
  56. data/spec/dummy/config/environments/test.rb +39 -0
  57. data/spec/dummy/config/initializers/assets.rb +8 -0
  58. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  59. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  60. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  61. data/spec/dummy/config/initializers/inflections.rb +16 -0
  62. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  63. data/spec/dummy/config/initializers/session_store.rb +3 -0
  64. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  65. data/spec/dummy/config/locales/en.yml +23 -0
  66. data/spec/dummy/config/routes.rb +4 -0
  67. data/spec/dummy/config/secrets.yml +22 -0
  68. data/spec/dummy/log/test.log +2459 -0
  69. data/spec/dummy/public/404.html +67 -0
  70. data/spec/dummy/public/422.html +67 -0
  71. data/spec/dummy/public/500.html +66 -0
  72. data/spec/dummy/public/favicon.ico +0 -0
  73. data/spec/helpers/jobs_helper_spec.rb +100 -0
  74. data/spec/rails_helper.rb +47 -0
  75. data/spec/spec_helper.rb +81 -0
  76. data/spec/views/workers/index.html.haml_spec.rb +17 -0
  77. data/vendor/assets/javascripts/jquery.bootstrap-touchspin.js +686 -0
  78. data/vendor/assets/javascripts/prism.js +6 -0
  79. data/vendor/assets/stylesheets/jquery.bootstrap-touchspin.css +45 -0
  80. data/vendor/assets/stylesheets/prism.scss +160 -0
  81. metadata +319 -0
@@ -0,0 +1,6 @@
1
+ @import "bootstrap-sprockets";
2
+ @import "bootstrap";
3
+
4
+ .alert-notice {
5
+ @extend .alert-info
6
+ }
@@ -0,0 +1,40 @@
1
+ .callout {
2
+ border: 1px solid #eee;
3
+ border-left-width: 0.5em;
4
+ }
5
+
6
+ .callout-top {
7
+ border: 1px solid #eee;
8
+ border-top-width: 5px;
9
+ }
10
+
11
+ .callout-info-top {
12
+ border-top-color: #1b809e;
13
+ }
14
+
15
+ .callout-success-top {
16
+ border-top-color: #3c763d;
17
+ }
18
+
19
+ .callout-warning-top {
20
+ border-top-color: #aa6708;
21
+ }
22
+
23
+ .callout-alert-top {
24
+ border-top-color: #ce4844;
25
+ }
26
+ .callout-info {
27
+ border-left-color: #1b809e;
28
+ }
29
+
30
+ .callout-success {
31
+ border-left-color: #3c763d;
32
+ }
33
+
34
+ .callout-warning {
35
+ border-left-color: #aa6708;
36
+ }
37
+
38
+ .callout-alert {
39
+ border-left-color: #ce4844;
40
+ }
@@ -0,0 +1,16 @@
1
+ .job-list {
2
+ .list {
3
+ .progress {
4
+ width: 16em;
5
+ height: 1em;
6
+ margin: 5px 0px 0px 10px;
7
+ -webkit-border-radius: 0 !important;
8
+ -moz-border-radius: 0 !important;
9
+ border-radius: 0 !important;
10
+ }
11
+
12
+ .progress-bar {
13
+ min-width: 1em;
14
+ }
15
+ }
16
+ }
@@ -0,0 +1,45 @@
1
+ /*
2
+ * Bootstrap TouchSpin - v3.0.1
3
+ * A mobile and touch friendly input spinner component for Bootstrap 3.
4
+ * http://www.virtuosoft.eu/code/bootstrap-touchspin/
5
+ *
6
+ * Made by István Ujj-Mészáros
7
+ * Under Apache License v2.0 License
8
+ */
9
+
10
+ .bootstrap-touchspin .input-group-btn-vertical {
11
+ position: relative;
12
+ white-space: nowrap;
13
+ width: 1%;
14
+ vertical-align: middle;
15
+ display: table-cell;
16
+ }
17
+
18
+ .bootstrap-touchspin .input-group-btn-vertical > .btn {
19
+ display: block;
20
+ float: none;
21
+ width: 100%;
22
+ max-width: 100%;
23
+ padding: 8px 10px;
24
+ margin-left: -1px;
25
+ position: relative;
26
+ }
27
+
28
+ .bootstrap-touchspin .input-group-btn-vertical .bootstrap-touchspin-up {
29
+ border-radius: 0;
30
+ border-top-right-radius: 4px;
31
+ }
32
+
33
+ .bootstrap-touchspin .input-group-btn-vertical .bootstrap-touchspin-down {
34
+ margin-top: -2px;
35
+ border-radius: 0;
36
+ border-bottom-right-radius: 4px;
37
+ }
38
+
39
+ .bootstrap-touchspin .input-group-btn-vertical i {
40
+ position: absolute;
41
+ top: 3px;
42
+ left: 5px;
43
+ font-size: 9px;
44
+ font-weight: normal;
45
+ }
@@ -0,0 +1,15 @@
1
+ module RocketJobMissionControl
2
+ class ApplicationController < ActionController::Base
3
+ include ActionController::Live
4
+
5
+ around_action :with_time_zone
6
+
7
+ private
8
+
9
+ def with_time_zone
10
+ if time_zone = session['time_zone'] || 'UTC'
11
+ Time.use_zone(time_zone) { yield }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ module RocketJobMissionControl
2
+ module Jobs
3
+ class SlicesController < RocketJobMissionControl::ApplicationController
4
+ def index
5
+
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ module RocketJobMissionControl
2
+ module Jobs
3
+ class InputsController < RocketJobMissionControl::ApplicationController
4
+ def index
5
+ @job = RocketJob::Job.find(params[:id])
6
+ @inputs = @job.inputs
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,97 @@
1
+ module RocketJobMissionControl
2
+ class JobsController < RocketJobMissionControl::ApplicationController
3
+ before_filter :find_job_or_redirect, except: [:index, :running]
4
+ rescue_from StandardError, with: :error_occurred
5
+
6
+ def running
7
+ @jobs = RocketJob::Job.where(state: 'running')
8
+ end
9
+
10
+ def update
11
+ @job.update_attributes!(job_params)
12
+
13
+ redirect_to job_path(@job)
14
+ end
15
+
16
+ def abort
17
+ @job.abort!
18
+
19
+ redirect_to(job_path(@job))
20
+ end
21
+
22
+ def destroy
23
+ if @job.completed? || @job.aborted?
24
+ @job.destroy
25
+ redirect_to(jobs_path)
26
+ else
27
+ flash[:alert] = "Cannot destroy a job unless it is completed or aborted"
28
+ redirect_to(job_path(@job))
29
+ end
30
+ end
31
+
32
+ def retry
33
+ @job.retry!
34
+
35
+ redirect_to(job_path(@job))
36
+ end
37
+
38
+ def pause
39
+ @job.pause!
40
+
41
+ redirect_to(job_path(@job))
42
+ end
43
+
44
+ def resume
45
+ @job.resume!
46
+
47
+ redirect_to(job_path(@job))
48
+ end
49
+
50
+ def fail
51
+ @job.fail!
52
+
53
+ redirect_to(job_path(@job))
54
+ end
55
+
56
+ def show
57
+ load_jobs
58
+ end
59
+
60
+ def index
61
+ load_jobs
62
+ end
63
+
64
+ private
65
+
66
+ def load_jobs
67
+ @states = jobs_params
68
+ @jobs = RocketJob::Job.limit(1000).sort(created_at: :desc)
69
+ @jobs = @jobs.where(state: @states) unless @states.empty?
70
+ end
71
+
72
+ def find_job_or_redirect
73
+ @job = RocketJob::Job.find(params[:id])
74
+
75
+ if @job.nil?
76
+ flash[:alert] = t(:failure, scope: [:job, :find], id: params[:id])
77
+
78
+ redirect_to(jobs_path)
79
+ end
80
+ end
81
+
82
+ def jobs_params
83
+ params.fetch(:states, [])
84
+ end
85
+
86
+ def job_params
87
+ params.require(:job).permit(:priority)
88
+ end
89
+
90
+ def error_occurred(exception)
91
+ logger.error "Error loading a job", exception
92
+ flash[:danger] = "Error loading jobs."
93
+ raise exception if Rails.env.development?
94
+ redirect_to :back
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,79 @@
1
+ module RocketJobMissionControl
2
+ class WorkersController < RocketJobMissionControl::ApplicationController
3
+ before_filter :find_worker, only: [:stop, :pause, :resume, :destroy]
4
+
5
+ def index
6
+ @workers = RocketJob::Worker.sort(:name)
7
+ end
8
+
9
+ VALID_STATES = { stop: 'stopped', pause: 'paused', resume: 'resumed' }
10
+
11
+ def update_all
12
+ worker_action = params[:worker_action].to_sym
13
+ if VALID_STATES.keys.include?(worker_action)
14
+ RocketJob::Worker.send("#{worker_action}_all".to_sym)
15
+ flash[:notice] = t(:success, scope: [:worker, :update_all], worker_action: VALID_STATES[worker_action])
16
+ else
17
+ flash[:alert] = t(:invalid, scope: [:worker, :update_all])
18
+ end
19
+
20
+ respond_to do |format|
21
+ format.html { redirect_to workers_path }
22
+ end
23
+ end
24
+
25
+ def stop
26
+ if @worker.stop!
27
+ flash[:notice] = t(:success, scope: [:worker, :stop])
28
+ else
29
+ flash[:alert] = t(:failure, scope: [:worker, :stop])
30
+ end
31
+
32
+ respond_to do |format|
33
+ format.html { redirect_to workers_path }
34
+ end
35
+ end
36
+
37
+ def destroy
38
+ if @worker.destroy
39
+ flash[:notice] = t(:success, scope: [:worker, :destroy])
40
+ else
41
+ flash[:alert] = t(:failure, scope: [:worker, :destroy])
42
+ end
43
+
44
+ respond_to do |format|
45
+ format.html { redirect_to workers_path }
46
+ end
47
+ end
48
+
49
+ def pause
50
+ if @worker.pause!
51
+ flash[:notice] = t(:success, scope: [:worker, :pause])
52
+ else
53
+ flash[:alert] = t(:failure, scope: [:worker, :pause])
54
+ end
55
+
56
+ respond_to do |format|
57
+ format.html { redirect_to workers_path }
58
+ end
59
+ end
60
+
61
+ def resume
62
+ if @worker.resume!
63
+ flash[:notice] = t(:success, scope: [:worker, :resume])
64
+ else
65
+ flash[:alert] = t(:failure, scope: [:worker, :resume])
66
+ end
67
+
68
+ respond_to do |format|
69
+ format.html { redirect_to workers_path }
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ def find_worker
76
+ @worker = RocketJob::Worker.find(params[:id])
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,16 @@
1
+ module RocketJobMissionControl
2
+ module ApplicationHelper
3
+ def site_title
4
+ 'Rocket Job Mission Control'
5
+ end
6
+
7
+ def title
8
+ @page_title ||= params[:controller].to_s.titleize
9
+ h(@full_title || [@page_title, site_title].compact.join(' | '))
10
+ end
11
+
12
+ def active_page(path)
13
+ "active" if current_page?(path)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,57 @@
1
+ module RocketJobMissionControl
2
+ module JobsHelper
3
+ STATE_ICON_MAP = {
4
+ queued: 'fa-bed warning',
5
+ paused: 'fa-pause warning',
6
+ running: 'fa-cog fa-spin primary',
7
+ completed: 'fa-check success',
8
+ aborted: 'fa-times warning',
9
+ }
10
+
11
+ STATE_CLASS_MAP = {
12
+ queued: 'warning',
13
+ paused: 'warning',
14
+ running: 'primary',
15
+ completed: 'success',
16
+ aborted: 'danger',
17
+ failed: 'danger',
18
+ }
19
+
20
+ def job_state_icon(state)
21
+ STATE_ICON_MAP[state.to_sym] || 'fa-times danger'
22
+ end
23
+
24
+ def job_class(job)
25
+ STATE_CLASS_MAP[job.state.to_sym] || ""
26
+ end
27
+
28
+ def pretty_print_array_or_hash(arguments)
29
+ return arguments unless arguments.kind_of?(Array) || arguments.kind_of?(Hash)
30
+ json_string_options = {space: ' ', indent: ' ', array_nl: '<br />', object_nl: '<br />'}
31
+ JSON.generate(arguments, json_string_options).html_safe
32
+ end
33
+
34
+ def job_card_class(job)
35
+ map = {
36
+ running: 'callout-info',
37
+ completed: 'callout-success',
38
+ failed: 'callout-alert',
39
+ aborted: 'callout-warning',
40
+ }
41
+ "card callout " << map[job.state.to_sym].to_s
42
+ end
43
+
44
+ def job_selected_class(job, selected_job = nil)
45
+ if selected_job.present? && job.id == selected_job.id
46
+ ' text-info'
47
+ else
48
+ ' text-muted'
49
+ end
50
+ end
51
+
52
+ def job_title(job)
53
+ perform_method = job.perform_method == :perform ? '' : "##{job.perform_method}"
54
+ "#{job.class.name}#{perform_method}"
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,14 @@
1
+ module RocketJobMissionControl
2
+ module WorkersHelper
3
+
4
+ def worker_card_class(worker)
5
+ map = {
6
+ running: 'callout-success-top',
7
+ paused: 'callout-warning-top',
8
+ stopping: 'callout-alert-top',
9
+ }
10
+ map[worker.state] || 'callout-info-top'
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,43 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title= title
5
+
6
+ %link{rel: "icon", type: "image/png", href: "/assets/favicon.png"}
7
+ %link{rel: "apple-touch-icon-precomposed", href: "/assets/apple-touch-icon.png"}
8
+
9
+ %meta{'http-equiv' => "Content-Type", content: "text/html; charset=UTF-8"}
10
+ %meta{'http-equiv' => "Content-Script-Type", content: "text/javascript"}
11
+ %meta{'http-equiv' =>"X-UA-Compatible", content: "IE=edge" }
12
+ %meta{name: "viewport", content: "width=device-width, initial-scale=1"}
13
+ = yield :meta
14
+
15
+
16
+ = stylesheet_link_tag "rocket_job_mission_control/application", :media => "all"
17
+ = javascript_include_tag "rocket_job_mission_control/application"
18
+
19
+ = csrf_meta_tag
20
+
21
+ %link{href: "//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css", rel: "stylesheet"}/
22
+
23
+ %body.rocket_job
24
+ #wrapper.toggled
25
+ = render partial: 'layouts/rocket_job_mission_control/partials/sidebar'
26
+
27
+ #page-content-wrapper
28
+ = render partial: 'layouts/rocket_job_mission_control/partials/header'
29
+
30
+ .flash
31
+ - flash.each do |key, msg|
32
+ - if msg
33
+ .alert{class: "alert-#{key} alert-dismissable", role: 'alert'}
34
+ %button.close{ data: { dismiss: 'alert' } }
35
+ %span &times;
36
+ -if msg.kind_of? Array
37
+ %ul.list-unstyled.margin-bottom-0
38
+ - msg.each do |m|
39
+ %li= m.html_safe
40
+ - else
41
+ = msg.html_safe
42
+
43
+ = yield