mission_control-jobs 1.0.1 → 1.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.
@@ -4,7 +4,7 @@ module MissionControl::Jobs::JobFilters
4
4
  included do
5
5
  before_action :set_filters
6
6
 
7
- helper_method :active_filters?
7
+ helper_method :active_filters?, :jobs_filter_param
8
8
  end
9
9
 
10
10
  private
@@ -20,6 +20,14 @@ module MissionControl::Jobs::JobFilters
20
20
  @job_filters.any?
21
21
  end
22
22
 
23
+ def jobs_filter_param
24
+ if @job_filters&.any?
25
+ { filter: @job_filters }
26
+ else
27
+ {}
28
+ end
29
+ end
30
+
23
31
  def finished_at_range_params
24
32
  range_start, range_end = params.dig(:filter, :finished_at_start), params.dig(:filter, :finished_at_end)
25
33
  if range_start || range_end
@@ -12,6 +12,7 @@ class MissionControl::Jobs::ApplicationController < MissionControl::Jobs.base_co
12
12
  include MissionControl::Jobs::BasicAuthentication
13
13
  include MissionControl::Jobs::ApplicationScoped, MissionControl::Jobs::NotFoundRedirections
14
14
  include MissionControl::Jobs::AdapterFeatures
15
+ include MissionControl::Jobs::JobFilters
15
16
 
16
17
  around_action :set_current_locale
17
18
 
@@ -13,6 +13,6 @@ class MissionControl::Jobs::DiscardsController < MissionControl::Jobs::Applicati
13
13
 
14
14
  def redirect_location
15
15
  status = @job.status.presence_in(supported_job_statuses) || :failed
16
- application_jobs_url(@application, status)
16
+ application_jobs_url(@application, status, **jobs_filter_param)
17
17
  end
18
18
  end
@@ -1,5 +1,5 @@
1
1
  class MissionControl::Jobs::JobsController < MissionControl::Jobs::ApplicationController
2
- include MissionControl::Jobs::JobScoped, MissionControl::Jobs::JobFilters
2
+ include MissionControl::Jobs::JobScoped
3
3
 
4
4
  skip_before_action :set_job, only: :index
5
5
 
@@ -3,7 +3,7 @@ class MissionControl::Jobs::RetriesController < MissionControl::Jobs::Applicatio
3
3
 
4
4
  def create
5
5
  @job.retry
6
- redirect_to application_jobs_url(@application, :failed), notice: "Retried job with id #{@job.job_id}"
6
+ redirect_to application_jobs_url(@application, :failed, **jobs_filter_param), notice: "Retried job with id #{@job.job_id}"
7
7
  end
8
8
 
9
9
  private
@@ -4,5 +4,6 @@ module MissionControl::Jobs
4
4
  #
5
5
  # We can't rely on +config.action_controller.include_all_helpers = true+ in the host app.
6
6
  include DatesHelper, JobsHelper, NavigationHelper, InterfaceHelper
7
+ include MissionControl::Jobs::Engine.routes.url_helpers
7
8
  end
8
9
  end
@@ -37,14 +37,6 @@ module MissionControl::Jobs::NavigationHelper
37
37
  MissionControl::Jobs::Current.server.name == server.name
38
38
  end
39
39
 
40
- def jobs_filter_param
41
- if @job_filters&.any?
42
- { filter: @job_filters }
43
- else
44
- {}
45
- end
46
- end
47
-
48
40
  def jobs_count_with_status(status)
49
41
  count = ActiveJob.jobs.with_status(status).count
50
42
  if count.infinite?
@@ -1,6 +1,9 @@
1
1
  <nav class="navbar" role="navigation" aria-label="main navigation">
2
2
  <div class="navbar-menu is-active mb-4">
3
3
  <div class="navbar-start">
4
+ <% if defined?(main_app.root_path) %>
5
+ <%= link_to "Back to main app", main_app.root_path %>
6
+ <% end %>
4
7
  </div>
5
8
 
6
9
  <div class="navbar-end">
@@ -1,45 +1,55 @@
1
1
  <div class="filter level-left">
2
- <div class="field is-grouped">
3
- <div class="control">
4
- <%= form_for :filter, url: application_jobs_path(MissionControl::Jobs::Current.application, jobs_status), method: :get,
5
- data: { controller: "form", action: "input->form#debouncedSubmit" } do |form| %>
2
+ <%= form_for :filter, url: application_jobs_path(MissionControl::Jobs::Current.application, jobs_status), method: :get,
3
+ data: { controller: "form", action: "input->form#debouncedSubmit" } do |form| %>
6
4
 
5
+ <div class="field is-grouped">
6
+ <div class="control">
7
+ <%= form.label :job_class_name, class: "label" %>
7
8
  <div class="select is-rounded">
8
- <%= form.text_field :job_class_name, value: @job_filters[:job_class_name], class: "input", list: "job-classes", placeholder: "Filter by job class..." %>
9
+ <%= form.text_field :job_class_name, value: @job_filters[:job_class_name], class: "input", list: "job-classes", placeholder: "Filter by job class...", autocomplete: "off" %>
9
10
  </div>
11
+ </div>
10
12
 
13
+ <div class="control">
14
+ <%= form.label :queue_name, class: "label" %>
11
15
  <div class="select is-rounded">
12
- <%= form.text_field :queue_name, value: @job_filters[:queue_name], class: "input", list: "queue-names", placeholder: "Filter by queue name..." %>
16
+ <%= form.text_field :queue_name, value: @job_filters[:queue_name], class: "input", list: "queue-names", placeholder: "Filter by queue name...", autocomplete: "off" %>
13
17
  </div>
18
+ </div>
14
19
 
15
- <% if jobs_status == "finished" %>
20
+ <% if jobs_status == "finished" %>
21
+ <div class="control">
22
+ <%= form.label :finished_at_start, class: "label" %>
16
23
  <div class="select is-rounded">
17
24
  <%= form.datetime_field :finished_at_start, value: @job_filters[:finished_at]&.begin, class: "input", placeholder: "Finished from" %>
18
25
  </div>
26
+ </div>
19
27
 
28
+ <div class="control">
29
+ <%= form.label :finished_at_end, class: "label" %>
20
30
  <div class="select is-rounded">
21
31
  <%= form.datetime_field :finished_at_end, value: @job_filters[:finished_at]&.end, class: "input", placeholder: "Finished to" %>
22
32
  </div>
23
- <% end %>
33
+ </div>
34
+ <% end %>
24
35
 
25
- <%= hidden_field_tag :server_id, MissionControl::Jobs::Current.server.id %>
36
+ <%= hidden_field_tag :server_id, MissionControl::Jobs::Current.server.id %>
26
37
 
27
- <datalist id="job-classes" class="is-hidden">
28
- <% job_class_names.each do |job_class_name| %>
29
- <option value="<%= job_class_name %>"></option>
30
- <% end %>
31
- </datalist>
38
+ <datalist id="job-classes" class="is-hidden">
39
+ <% job_class_names.each do |job_class_name| %>
40
+ <option value="<%= job_class_name %>"></option>
41
+ <% end %>
42
+ </datalist>
32
43
 
33
- <datalist id="queue-names" class="is-hidden">
34
- <% queue_names.each do |queue_name| %>
35
- <option value="<%= queue_name %>"></option>
36
- <% end %>
37
- </datalist>
38
- <% end %>
39
- </div>
44
+ <datalist id="queue-names" class="is-hidden">
45
+ <% queue_names.each do |queue_name| %>
46
+ <option value="<%= queue_name %>"></option>
47
+ <% end %>
48
+ </datalist>
40
49
 
41
- <div class="control">
42
- <%= link_to "Clear", application_jobs_path(MissionControl::Jobs::Current.application, jobs_status, job_class_name: nil, queue_name: nil, finished_at: nil..nil), class: "button" %>
50
+ <div class="control is-align-self-flex-end">
51
+ <%= link_to "Clear", application_jobs_path(MissionControl::Jobs::Current.application, jobs_status, job_class_name: nil, queue_name: nil, finished_at: nil..nil), class: "button" %>
52
+ </div>
43
53
  </div>
44
- </div>
54
+ <% end %>
45
55
  </div>
@@ -47,11 +47,17 @@
47
47
  <% end %>
48
48
  <% if job.finished_at.present? %>
49
49
  <tr>
50
- <th>Finished at</th>
50
+ <th>Finished</th>
51
51
  <td>
52
52
  <%= time_distance_in_words_with_title(job.finished_at) %> ago
53
53
  </td>
54
54
  </tr>
55
+ <tr>
56
+ <th>Duration</th>
57
+ <td>
58
+ <%= job.duration.round(3) %> seconds
59
+ </td>
60
+ </tr>
55
61
  <% end %>
56
62
  <% if job.worker_id.present? %>
57
63
  <tr>
@@ -1,6 +1,7 @@
1
1
  <td><%= link_to job.queue_name, application_queue_path(@application, job.queue) %></td>
2
- <td><div class="is-family-monospace is-size-7"><%= job.blocked_by %></div>
3
- <div class="has-text-grey is-size-7">Expires <%= bidirectional_time_distance_in_words_with_title(job.blocked_until) %></div>
2
+ <td>
3
+ <div class="is-family-monospace is-size-7"><%= job.blocked_by %></div>
4
+ <div class="has-text-grey is-size-7"><%= job.blocked_until ? "Expires #{bidirectional_time_distance_in_words_with_title(job.blocked_until)}" : "" %></div>
4
5
  </td>
5
6
  <td class="pr-0">
6
7
  <%= render "mission_control/jobs/jobs/blocked/actions", job: job %>
@@ -1,5 +1,5 @@
1
1
  <div class="buttons is-right">
2
- <%= button_to "Discard", application_job_discard_path(@application, job.job_id), class: "button is-danger is-light mr-0",
2
+ <%= button_to "Discard", application_job_discard_path(@application, job.job_id, params: jobs_filter_param), class: "button is-danger is-light mr-0",
3
3
  form: { data: { turbo_confirm: "This will delete the job and can't be undone. Are you sure?" } } %>
4
- <%= button_to "Retry", application_job_retry_path(@application, job.job_id), class: "button is-warning is-light mr-0" %>
4
+ <%= button_to "Retry", application_job_retry_path(@application, job.job_id, params: jobs_filter_param), class: "button is-warning is-light mr-0" %>
5
5
  </div>
@@ -1,6 +1,6 @@
1
1
  <tr class="queue">
2
2
  <td>
3
- <%= link_to queue.name, application_queue_path(@application, queue.name) %>
3
+ <%= link_to queue.name, application_queue_path(@application, queue) %>
4
4
  <% if queue.paused? %>
5
5
  <span class="ml-4 tag is-warning">Paused</span>
6
6
  <% end %>
@@ -24,6 +24,10 @@ class ActiveJob::JobProxy < ActiveJob::Base
24
24
  raise UnsupportedError, "A JobProxy doesn't support immediate execution, only enqueuing."
25
25
  end
26
26
 
27
+ def duration
28
+ finished_at - scheduled_at
29
+ end
30
+
27
31
  ActiveJob::JobsRelation::STATUSES.each do |status|
28
32
  define_method "#{status}?" do
29
33
  self.status == status
@@ -13,17 +13,21 @@ class ActiveJob::Queues
13
13
  include Enumerable
14
14
 
15
15
  delegate :each, to: :values
16
- delegate :values, to: :queues_by_name, private: true
17
- delegate :[], :size, :length, :to_s, :inspect, to: :queues_by_name
16
+ delegate :values, to: :queues_by_id, private: true
17
+ delegate :size, :length, :to_s, :inspect, to: :queues_by_id
18
18
 
19
19
  def initialize(queues)
20
- @queues_by_name = queues.index_by(&:name).with_indifferent_access
20
+ @queues_by_id = queues.index_by(&:id).with_indifferent_access
21
21
  end
22
22
 
23
23
  def to_h
24
- queues_by_name.dup
24
+ queues_by_id.dup
25
+ end
26
+
27
+ def [](name)
28
+ queues_by_id[name.to_s.parameterize]
25
29
  end
26
30
 
27
31
  private
28
- attr_reader :queues_by_name
32
+ attr_reader :queues_by_id
29
33
  end
@@ -35,8 +35,8 @@ module MissionControl
35
35
  end
36
36
 
37
37
  initializer "mission_control-jobs.http_basic_auth" do |app|
38
- MissionControl::Jobs.http_basic_auth_user = app.credentials.dig(:mission_control, :http_basic_auth_user)
39
- MissionControl::Jobs.http_basic_auth_password = app.credentials.dig(:mission_control, :http_basic_auth_password)
38
+ MissionControl::Jobs.http_basic_auth_user ||= app.credentials.dig(:mission_control, :http_basic_auth_user)
39
+ MissionControl::Jobs.http_basic_auth_password ||= app.credentials.dig(:mission_control, :http_basic_auth_password)
40
40
  end
41
41
 
42
42
  initializer "mission_control-jobs.active_job.extensions" do
@@ -63,13 +63,6 @@ module MissionControl
63
63
  end
64
64
 
65
65
  config.after_initialize do |app|
66
- unless app.config.eager_load
67
- # When loading classes lazily (development), we want to make sure
68
- # the base host +ApplicationController+ class is loaded when loading the
69
- # Engine's +ApplicationController+, or it will fail to load the class.
70
- MissionControl::Jobs.base_controller_class.constantize
71
- end
72
-
73
66
  if MissionControl::Jobs.applications.empty?
74
67
  queue_adapters_by_name = MissionControl::Jobs.adapters.each_with_object({}) do |adapter, hsh|
75
68
  hsh[adapter] = ActiveJob::QueueAdapters.lookup(adapter).new
@@ -103,10 +96,12 @@ module MissionControl
103
96
 
104
97
  initializer "mission_control-jobs.importmap", after: "importmap" do |app|
105
98
  MissionControl::Jobs.importmap.draw(root.join("config/importmap.rb"))
106
- MissionControl::Jobs.importmap.cache_sweeper(watches: root.join("app/javascript"))
99
+ if app.config.importmap.sweep_cache && app.config.reloading_enabled?
100
+ MissionControl::Jobs.importmap.cache_sweeper(watches: root.join("app/javascript"))
107
101
 
108
- ActiveSupport.on_load(:action_controller_base) do
109
- before_action { MissionControl::Jobs.importmap.cache_sweeper.execute_if_updated }
102
+ ActiveSupport.on_load(:action_controller_base) do
103
+ before_action { MissionControl::Jobs.importmap.cache_sweeper.execute_if_updated }
104
+ end
110
105
  end
111
106
  end
112
107
  end
@@ -1,9 +1,17 @@
1
1
  class MissionControl::Jobs::I18nConfig < ::I18n::Config
2
+ AVAILABLE_LOCALES = [ :en ]
3
+ AVAILABLE_LOCALES_SET = [ :en, "en" ]
4
+ DEFAULT_LOCALE = :en
5
+
2
6
  def available_locales
3
- [ :en ]
7
+ AVAILABLE_LOCALES
8
+ end
9
+
10
+ def available_locales_set
11
+ AVAILABLE_LOCALES_SET
4
12
  end
5
13
 
6
14
  def default_locale
7
- :en
15
+ DEFAULT_LOCALE
8
16
  end
9
17
  end
@@ -1,5 +1,5 @@
1
1
  module MissionControl
2
2
  module Jobs
3
- VERSION = "1.0.1"
3
+ VERSION = "1.1.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mission_control-jobs
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jorge Manrubia
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-12-04 00:00:00.000000000 Z
11
+ date: 2025-07-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord