good_job 2.9.6 → 2.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 64642ab1c4e807f67310c70fca0d57ae636955b923dbf1c9a0e09a88a4c66a5d
4
- data.tar.gz: 69a4d004af970032be6583bfd5a7281c3ee185dedbeb7250cb7d64d9adfc2d46
3
+ metadata.gz: 6b22cbc6d37af9dd8db290a1dc8073d2cae14c63e5cf7180b06dce1a33fb9992
4
+ data.tar.gz: 8cd87b2d69afea84db87125bad625558783adea98fee138be852e6a51c43dc50
5
5
  SHA512:
6
- metadata.gz: 9c154d015c820d314a4f2b7e7b611d4d858c75950bdef0fbde8d89b7264271b85a43669607e274ea1eca46234e603d48a441fb7a291b6a1969f8c5fb3896bf86
7
- data.tar.gz: 5d9534cc68b264fe3901f447383de0265d301ddea893b435b39542575f2b16410569a4442ddb5a5187e803546cf721e3cf1e49a1f81a3c4439f59c4b46b42249
6
+ metadata.gz: 230b335c5b6a03397c3212cd2bc59d87b2c735073233d068cf2c3045933b2aace533b0699a6fa1ecd41d77890af5aa18e1685b2c85f4c97c868773a3211736b7
7
+ data.tar.gz: b3fb4cb11f129fa8576e36c4e7401cdab927cf309bda963c3b82480dbe92663847b46a8e641b123e5ad7b28c53aa361d5fb6968131e23e85b0302768cc38e5d0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## [v2.10.0](https://github.com/bensheldon/good_job/tree/v2.10.0) (2022-02-18)
4
+
5
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v2.9.6...v2.10.0)
6
+
7
+ **Closed issues:**
8
+
9
+ - Cron jobs not getting run [\#519](https://github.com/bensheldon/good_job/issues/519)
10
+ - Slow queries with many finished entries and concurrency control [\#514](https://github.com/bensheldon/good_job/issues/514)
11
+ - Make default retry behaviour safer [\#505](https://github.com/bensheldon/good_job/issues/505)
12
+
13
+ **Merged pull requests:**
14
+
15
+ - Fix Benchmark job throughput script [\#522](https://github.com/bensheldon/good_job/pull/522) ([douglara](https://github.com/douglara))
16
+ - Update development Gemfile.lock [\#521](https://github.com/bensheldon/good_job/pull/521) ([bensheldon](https://github.com/bensheldon))
17
+ - Ensure Rails 6.0 is tested against Ruby 3.0; use Ruby 3.0 in demo environment [\#520](https://github.com/bensheldon/good_job/pull/520) ([bensheldon](https://github.com/bensheldon))
18
+ - Dashboard: update search filters and some small UI updates [\#518](https://github.com/bensheldon/good_job/pull/518) ([multiplegeorges](https://github.com/multiplegeorges))
19
+ - Document safer setting for retry\_on\_unhandled\_error [\#517](https://github.com/bensheldon/good_job/pull/517) ([tamaloa](https://github.com/tamaloa))
20
+
3
21
  ## [v2.9.6](https://github.com/bensheldon/good_job/tree/v2.9.6) (2022-02-07)
4
22
 
5
23
  [Full Changelog](https://github.com/bensheldon/good_job/compare/v2.9.5...v2.9.6)
data/README.md CHANGED
@@ -276,7 +276,7 @@ Available configuration options are:
276
276
  - `cleanup_interval_seconds` (integer) Number of seconds a Scheduler will wait before cleaning up preserved jobs. Defaults to `nil`. Can also be set with the environment variable `GOOD_JOB_CLEANUP_INTERVAL_SECONDS`.
277
277
  - `logger` ([Rails Logger](https://api.rubyonrails.org/classes/ActiveSupport/Logger.html)) lets you set a custom logger for GoodJob. It should be an instance of a Rails `Logger` (Default: `Rails.logger`).
278
278
  - `preserve_job_records` (boolean) keeps job records in your database even after jobs are completed. (Default: `false`)
279
- - `retry_on_unhandled_error` (boolean) causes jobs to be re-queued and retried if they raise an instance of `StandardError`. Instances of `Exception`, like SIGINT, will *always* be retried, regardless of this attribute’s value. (Default: `true`)
279
+ - `retry_on_unhandled_error` (boolean) causes jobs to be re-queued and retried if they raise an instance of `StandardError`. Be advised this may lead to jobs being repeated infinitely ([see below for more on retries](#retries)). Instances of `Exception`, like SIGINT, will *always* be retried, regardless of this attribute’s value. (Default: `true`)
280
280
  - `on_thread_error` (proc, lambda, or callable) will be called when an Exception. It can be useful for logging errors to bug tracking services, like Sentry or Airbrake. Example:
281
281
 
282
282
  ```ruby
@@ -307,7 +307,7 @@ Good Job’s general behavior can also be configured via attributes directly on
307
307
  - **`GoodJob.active_record_parent_class`** (string) The ActiveRecord parent class inherited by GoodJob's ActiveRecord model `GoodJob::Job` (defaults to `"ActiveRecord::Base"`). Configure this when using [multiple databases with ActiveRecord](https://guides.rubyonrails.org/active_record_multiple_databases.html) or when other custom configuration is necessary for the ActiveRecord model to connect to the Postgres database. _The value must be a String to avoid premature initialization of ActiveRecord._
308
308
  - **`GoodJob.logger`** ([Rails Logger](https://api.rubyonrails.org/classes/ActiveSupport/Logger.html)) lets you set a custom logger for GoodJob. It should be an instance of a Rails `Logger`.
309
309
  - **`GoodJob.preserve_job_records`** (boolean) keeps job records in your database even after jobs are completed. (Default: `false`)
310
- - **`GoodJob.retry_on_unhandled_error`** (boolean) causes jobs to be re-queued and retried if they raise an instance of `StandardError`. Instances of `Exception`, like SIGINT, will *always* be retried, regardless of this attribute’s value. (Default: `true`)
310
+ - **`GoodJob.retry_on_unhandled_error`** (boolean) causes jobs to be re-queued and retried if they raise an instance of `StandardError`. Be advised this may lead to jobs being repeated infinitely ([see below for more on retries](#retries)). Instances of `Exception`, like SIGINT, will *always* be retried, regardless of this attribute’s value. (Default: `true`)
311
311
  - **`GoodJob.on_thread_error`** (proc, lambda, or callable) will be called when an Exception. It can be useful for logging errors to bug tracking services, like Sentry or Airbrake.
312
312
 
313
313
  You’ll generally want to configure these in `config/initializers/good_job.rb`, like so:
@@ -529,7 +529,7 @@ class ApplicationJob < ActiveJob::Base
529
529
  end
530
530
  ```
531
531
 
532
- When using `retry_on` with _a limited number of retries_, the final exception will not be rescued and will raise to GoodJob. GoodJob can be configured to discard un-handled exceptions instead of retrying them:
532
+ When using `retry_on` with _a limited number of retries_, the final exception will not be rescued and will raise to GoodJob. GoodJob can be configured to discard un-handled exceptions instead of retrying them. Be aware that if NOT setting `retry_on_unhandled_error` to `false` good_job will by default retry the failing job and may do this infinitely without pause thereby at least causing high load. In most cases `retry_on_unhandled_error` should be set as following:
533
533
 
534
534
  ```ruby
535
535
  # config/initializers/good_job.rb
@@ -2,7 +2,7 @@
2
2
  module GoodJob
3
3
  class ExecutionsFilter < BaseFilter
4
4
  def states
5
- {
5
+ @_states ||= {
6
6
  'finished' => base_query.finished.count,
7
7
  'unfinished' => base_query.unfinished.count,
8
8
  'running' => base_query.running.count,
@@ -5,5 +5,20 @@ module GoodJob
5
5
  text = timestamp.future? ? "in #{time_ago_in_words(timestamp)}" : "#{time_ago_in_words(timestamp)} ago"
6
6
  tag.time(text, datetime: timestamp, title: timestamp)
7
7
  end
8
+
9
+ def status_badge(status)
10
+ classes = case status
11
+ when :finished
12
+ "badge rounded-pill bg-success"
13
+ when :queued, :scheduled, :retried
14
+ "badge rounded-pill bg-secondary"
15
+ when :running
16
+ "badge rounded-pill bg-primary"
17
+ when :discarded
18
+ "badge rounded-pill bg-danger"
19
+ end
20
+
21
+ content_tag :span, status.to_s, class: classes
22
+ end
8
23
  end
9
24
  end
@@ -1,3 +1,7 @@
1
+ <div class="my-3 flex">
2
+ <h2>Cron Schedules</h2>
3
+ </div>
4
+
1
5
  <% if @cron_entries.present? %>
2
6
  <div class="card my-3">
3
7
  <div class="table-responsive">
@@ -47,5 +51,11 @@
47
51
  </div>
48
52
  </div>
49
53
  <% else %>
50
- <em>No cron schedules present.</em>
54
+ <div class="card my-3">
55
+ <div class="card-body">
56
+ <p class="card-text">
57
+ <em>No cron schedules found.</em>
58
+ </p>
59
+ </div>
60
+ </div>
51
61
  <% end %>
@@ -1,6 +1,6 @@
1
1
  <div class="card my-3">
2
2
  <div class="table-responsive">
3
- <table class="table card-table table-bordered table-hover table-sm mb-0">
3
+ <table class="table card-table table-bordered table-hover table-sm mb-0" id="executions_index_table">
4
4
  <thead>
5
5
  <tr>
6
6
  <th>ActiveJob ID</th>
@@ -20,34 +20,40 @@
20
20
  </tr>
21
21
  </thead>
22
22
  <tbody>
23
- <% executions.each do |execution| %>
24
- <tr id="<%= dom_id(execution) %>">
25
- <td>
26
- <%= link_to job_path(execution.serialized_params['job_id']) do %>
27
- <code><%= execution.active_job_id %></code>
28
- <% end %>
29
- </td>
30
- <td>
31
- <%= link_to job_path(execution.active_job_id, anchor: dom_id(execution)) do %>
32
- <code><%= execution.id %></code>
33
- <% end %>
34
- </td>
35
- <td><%= execution.serialized_params['job_class'] %></td>
36
- <td><%= execution.queue_name %></td>
37
- <td><%= relative_time(execution.scheduled_at || execution.created_at) %></td>
38
- <td class="text-break"><%= truncate(execution.error, length: 1_000) %></td>
39
- <td>
40
- <%= tag.button "Preview", type: "button", class: "btn btn-sm btn-outline-primary", role: "button",
41
- data: { bs_toggle: "collapse", bs_target: "##{dom_id(execution, 'params')}" },
42
- aria: { expanded: false, controls: dom_id(execution, "params") }
43
- %>
44
- <%= tag.pre JSON.pretty_generate(execution.serialized_params), id: dom_id(execution, "params"), class: "collapse job-params" %>
45
- </td>
46
- <td>
47
- <%= button_to execution_path(execution.id), method: :delete, class: "btn btn-sm btn-outline-danger", title: "Delete execution", data: { confirm: "Confirm delete" } do %>
48
- <%= render "good_job/shared/icons/trash" %>
49
- <% end %>
50
- </td>
23
+ <% if executions.present? %>
24
+ <% executions.each do |execution| %>
25
+ <tr id="<%= dom_id(execution) %>">
26
+ <td>
27
+ <%= link_to job_path(execution.serialized_params['job_id']) do %>
28
+ <code><%= execution.active_job_id %></code>
29
+ <% end %>
30
+ </td>
31
+ <td>
32
+ <%= link_to job_path(execution.active_job_id, anchor: dom_id(execution)) do %>
33
+ <code><%= execution.id %></code>
34
+ <% end %>
35
+ </td>
36
+ <td><%= execution.serialized_params['job_class'] %></td>
37
+ <td><%= execution.queue_name %></td>
38
+ <td><%= relative_time(execution.scheduled_at || execution.created_at) %></td>
39
+ <td class="text-break"><%= truncate(execution.error, length: 1_000) %></td>
40
+ <td>
41
+ <%= tag.button "Preview", type: "button", class: "btn btn-sm btn-outline-primary", role: "button",
42
+ data: { bs_toggle: "collapse", bs_target: "##{dom_id(execution, 'params')}" },
43
+ aria: { expanded: false, controls: dom_id(execution, "params") }
44
+ %>
45
+ <%= tag.pre JSON.pretty_generate(execution.serialized_params), id: dom_id(execution, "params"), class: "collapse job-params" %>
46
+ </td>
47
+ <td>
48
+ <%= button_to execution_path(execution.id), method: :delete, class: "btn btn-sm btn-outline-danger", title: "Delete execution", data: { confirm: "Confirm delete" } do %>
49
+ <%= render "good_job/shared/icons/trash" %>
50
+ <% end %>
51
+ </td>
52
+ </tr>
53
+ <% end %>
54
+ <% else %>
55
+ <tr>
56
+ <td colspan="8" class="py-2 text-center text-muted">No executions found.</td>
51
57
  </tr>
52
58
  <% end %>
53
59
  </tbody>
@@ -4,9 +4,9 @@
4
4
 
5
5
  <%= render 'good_job/shared/filter', filter: @filter %>
6
6
 
7
- <% if @filter.records.present? %>
8
- <%= render 'good_job/executions/table', executions: @filter.records %>
7
+ <%= render 'good_job/executions/table', executions: @filter.records %>
9
8
 
9
+ <% if @filter.records.present? %>
10
10
  <nav aria-label="Job pagination" class="mt-3">
11
11
  <ul class="pagination">
12
12
  <li class="page-item">
@@ -16,6 +16,4 @@
16
16
  </li>
17
17
  </ul>
18
18
  </nav>
19
- <% else %>
20
- <em>No executions present.</em>
21
19
  <% end %>
@@ -21,45 +21,49 @@
21
21
  </tr>
22
22
  </thead>
23
23
  <tbody>
24
- <% jobs.each do |job| %>
25
- <tr class="<%= dom_class(job) %>" id="<%= dom_id(job) %>">
26
- <td>
27
- <%= link_to job_path(job.id) do %>
28
- <code><%= job.id %></code>
29
- <% end %>
30
- </td>
31
- <td>
32
- <span class="badge bg-secondary"><%= job.status %></span>
33
- </td>
34
- <td><%= job.job_class %></td>
35
- <td><%= job.queue_name %></td>
36
- <td><%= relative_time(job.scheduled_at || job.created_at) %></td>
37
- <td><%= job.executions_count %></td>
38
- <td class="text-break"><%= truncate(job.recent_error, length: 1_000) %></td>
39
- <td>
40
- <%= tag.button "Preview", type: "button", class: "btn btn-sm btn-outline-primary", role: "button",
41
- data: { bs_toggle: "collapse", bs_target: "##{dom_id(job, 'params')}" },
42
- aria: { expanded: false, controls: dom_id(job, "params") }
43
- %>
44
- <%= tag.pre JSON.pretty_generate(job.serialized_params), id: dom_id(job, "params"), class: "collapse job-params" %>
45
- </td>
46
- <td>
47
- <div class="text-nowrap">
48
- <% job_reschedulable = job.status.in? [:scheduled, :retried, :queued] %>
49
- <%= button_to reschedule_job_path(job.id), method: :put, class: "btn btn-sm #{job_reschedulable ? 'btn-outline-primary' : 'btn-outline-secondary'}", form_class: "d-inline-block", disabled: !job_reschedulable, aria: { label: "Reschedule job" }, title: "Reschedule job", data: { confirm: "Confirm reschedule" } do %>
50
- <%= render "good_job/shared/icons/skip_forward" %>
24
+ <% if jobs.present? %>
25
+ <% jobs.each do |job| %>
26
+ <tr class="<%= dom_class(job) %>" id="<%= dom_id(job) %>">
27
+ <td>
28
+ <%= link_to job_path(job.id) do %>
29
+ <code><%= job.id %></code>
51
30
  <% end %>
31
+ </td>
32
+ <td><%= status_badge(job.status) %></td>
33
+ <td><%= job.job_class %></td>
34
+ <td><%= job.queue_name %></td>
35
+ <td><%= relative_time(job.scheduled_at || job.created_at) %></td>
36
+ <td><%= job.executions_count %></td>
37
+ <td class="text-break"><%= truncate(job.recent_error, length: 1_000) %></td>
38
+ <td>
39
+ <%= tag.button "Preview", type: "button", class: "btn btn-sm btn-outline-primary", role: "button",
40
+ data: { bs_toggle: "collapse", bs_target: "##{dom_id(job, 'params')}" },
41
+ aria: { expanded: false, controls: dom_id(job, "params") }
42
+ %>
43
+ <%= tag.pre JSON.pretty_generate(job.serialized_params), id: dom_id(job, "params"), class: "collapse job-params" %>
44
+ </td>
45
+ <td>
46
+ <div class="text-nowrap">
47
+ <% job_reschedulable = job.status.in? [:scheduled, :retried, :queued] %>
48
+ <%= button_to reschedule_job_path(job.id), method: :put, class: "btn btn-sm #{job_reschedulable ? 'btn-outline-primary' : 'btn-outline-secondary'}", form_class: "d-inline-block", disabled: !job_reschedulable, aria: { label: "Reschedule job" }, title: "Reschedule job", data: { confirm: "Confirm reschedule" } do %>
49
+ <%= render "good_job/shared/icons/skip_forward" %>
50
+ <% end %>
52
51
 
53
- <% job_discardable = job.status.in? [:scheduled, :retried, :queued] %>
54
- <%= button_to discard_job_path(job.id), method: :put, class: "btn btn-sm #{job_discardable ? 'btn-outline-primary' : 'btn-outline-secondary'}", form_class: "d-inline-block", disabled: !job_discardable, aria: { label: "Discard job" }, title: "Discard job", data: { confirm: "Confirm discard" } do %>
55
- <%= render "good_job/shared/icons/stop" %>
56
- <% end %>
52
+ <% job_discardable = job.status.in? [:scheduled, :retried, :queued] %>
53
+ <%= button_to discard_job_path(job.id), method: :put, class: "btn btn-sm #{job_discardable ? 'btn-outline-primary' : 'btn-outline-secondary'}", form_class: "d-inline-block", disabled: !job_discardable, aria: { label: "Discard job" }, title: "Discard job", data: { confirm: "Confirm discard" } do %>
54
+ <%= render "good_job/shared/icons/stop" %>
55
+ <% end %>
57
56
 
58
- <%= button_to retry_job_path(job.id), method: :put, class: "btn btn-sm #{job.status == :discarded ? 'btn-outline-primary' : 'btn-outline-secondary'}", form_class: "d-inline-block", disabled: job.status != :discarded, aria: { label: "Retry job" }, title: "Retry job", data: { confirm: "Confirm retry" } do %>
59
- <%= render "good_job/shared/icons/arrow_clockwise" %>
60
- <% end %>
61
- </div>
62
- </td>
57
+ <%= button_to retry_job_path(job.id), method: :put, class: "btn btn-sm #{job.status == :discarded ? 'btn-outline-primary' : 'btn-outline-secondary'}", form_class: "d-inline-block", disabled: job.status != :discarded, aria: { label: "Retry job" }, title: "Retry job", data: { confirm: "Confirm retry" } do %>
58
+ <%= render "good_job/shared/icons/arrow_clockwise" %>
59
+ <% end %>
60
+ </div>
61
+ </td>
62
+ </tr>
63
+ <% end %>
64
+ <% else %>
65
+ <tr>
66
+ <td colspan="8" class="py-2 text-center text-muted">No jobs found.</td>
63
67
  </tr>
64
68
  <% end %>
65
69
  </tbody>
@@ -1,11 +1,16 @@
1
+ <div class="my-3 flex">
2
+ <h2>All Jobs</h2>
3
+ </div>
4
+
1
5
  <div class="card my-3 p-6">
2
6
  <%= render 'good_job/shared/chart', chart_data: GoodJob::ScheduledByQueueChart.new(@filter).data %>
3
7
  </div>
4
8
 
5
9
  <%= render 'good_job/shared/filter', filter: @filter %>
6
10
 
11
+ <%= render 'good_job/jobs/table', jobs: @filter.records %>
12
+
7
13
  <% if @filter.records.present? %>
8
- <%= render 'good_job/jobs/table', jobs: @filter.records %>
9
14
  <nav aria-label="Job pagination" class="mt-3">
10
15
  <ul class="pagination">
11
16
  <li class="page-item">
@@ -15,6 +20,4 @@
15
20
  </li>
16
21
  </ul>
17
22
  </nav>
18
- <% else %>
19
- <em>No jobs present.</em>
20
23
  <% end %>
@@ -1,3 +1,7 @@
1
+ <div class="my-3 flex">
2
+ <h2>Processes</h2>
3
+ </div>
4
+
1
5
  <% if !GoodJob::Process.migrated? %>
2
6
  <div class="card my-3">
3
7
  <div class="card-body">
@@ -1,66 +1,58 @@
1
- <div class='card mb-2'>
2
- <div class='card-body d-flex flex-wrap'>
3
- <div class='mb-2 me-4'>
4
- <small>Filter by job class</small>
5
- <br>
6
- <% filter.job_classes.each do |name, count| %>
7
- <% if params[:job_class] == name %>
8
- <%= link_to(filter.to_params(job_class: nil), class: 'btn btn-sm btn-outline-secondary active', role: "button", "aria-pressed": true) do %>
9
- <%= name %> (<%= count %>)
10
- <% end %>
11
- <% else %>
12
- <%= link_to(filter.to_params(job_class: name), class: 'btn btn-sm btn-outline-secondary', role: "button") do %>
13
- <%= name %> (<%= count %>)
14
- <% end %>
1
+ <%= form_with(url: "", method: :get, local: true, id: "filter_form") do |form| %>
2
+ <div class="d-flex flex-row w-100">
3
+ <div class="me-2">
4
+ <label for="job_class_filter">Job class</label>
5
+ <select name="job_class" id="job_class_filter" class="form-select">
6
+ <option value="" <%= "selected='selected'" if params[:job_class].blank? %>>All jobs</option>
7
+
8
+ <% filter.job_classes.each do |name, count| %>
9
+ <option value="<%= name.to_param %>" <%= "selected='selected'" if params[:job_class] == name %>><%= name %> (<%= count %>)</option>
15
10
  <% end %>
16
- <% end %>
11
+ </select>
17
12
  </div>
18
13
 
19
- <div class='mb-2 me-4'>
20
- <small>Filter by state</small>
21
- <br>
22
- <% filter.states.each do |name, count| %>
23
- <% if params[:state] == name %>
24
- <%= link_to(filter.to_params(state: nil), class: 'btn btn-sm btn-outline-secondary active', role: "button", "aria-pressed": true) do %>
25
- <%= name %> (<%= count %>)
26
- <% end %>
27
- <% else %>
28
- <%= link_to(filter.to_params(state: name), class: 'btn btn-sm btn-outline-secondary', role: "button") do %>
29
- <%= name %> (<%= count %>)
30
- <% end %>
14
+ <div class="me-2">
15
+ <label for="job_state_filter">State</label>
16
+ <select name="state" id="job_state_filter" class="form-select">
17
+ <option value="" <%= "selected='selected'" if params[:state].blank? %>>All states</option>
18
+
19
+ <% filter.states.each do |name, count| %>
20
+ <option value="<%= name.to_param %>" <%= "selected='selected'" if params[:state] == name %>><%= name %> (<%= count %>)</option>
31
21
  <% end %>
32
- <% end %>
22
+ </select>
33
23
  </div>
34
24
 
35
- <div class='mb-2 me-4'>
36
- <small>Filter by queue</small>
37
- <br>
38
- <% filter.queues.each do |name, count| %>
39
- <% if params[:queue_name] == name %>
40
- <%= link_to(filter.to_params(queue_name: nil), class: 'btn btn-sm btn-outline-secondary active', role: "button", "aria-pressed": true) do %>
41
- <%= name %> (<%= count %>)
42
- <% end %>
43
- <% else %>
44
- <%= link_to(filter.to_params(queue_name: name), class: 'btn btn-sm btn-outline-secondary', role: "button") do %>
45
- <%= name %> (<%= count %>)
46
- <% end %>
25
+ <div class="me-2">
26
+ <label for="job_queue_filter">Queue</label>
27
+ <select name="queue_name" id="job_queue_filter" class="form-select">
28
+ <option value="" <%= "selected='selected'" if params[:queue_name].blank? %>>All queues</option>
29
+
30
+ <% filter.queues.each do |name, count| %>
31
+ <option value="<%= name.to_param %>" <%= "selected='selected'" if params[:queue_name] == name %>><%= name %> (<%= count %>)</option>
47
32
  <% end %>
48
- <% end %>
33
+ </select>
49
34
  </div>
50
35
 
51
- <div class="mb-2">
52
- <%= form_with(url: "", method: :get, local: true) do |form| %>
53
- <% filter.to_params(query: nil).each do |key, value| %>
54
- <%= form.hidden_field(key.to_sym, value: value) %>
55
- <% end %>
36
+ <div class="me-2 flex-fill d-flex flex-col align-items-end">
37
+ <label class="visually-hidden" for="query" aria-label="Search by class, job id, job params, and error text.">Search by class, job id, job params, and error text.</label>
38
+ <%= search_field_tag "query", params[:query], class: "form-control", placeholder: "Search by class, job id, job params, and error text." %>
39
+ </div>
56
40
 
57
- <small><%= form.label :query, "Search" %></small>
58
- <div class="input-group input-group-sm">
59
- <%= form.search_field :query, value: params[:query], class: "form-control" %>
60
- <%= form.button "Search", type: "submit", name: nil, class: "btn btn-sm btn-outline-secondary" %>
61
- <%= link_to "Clear", filter.to_params(query: nil), class: "btn btn-sm btn-outline-secondary" %>
62
- </div>
63
- <% end %>
41
+ <div class="d-flex flex-col align-items-end">
42
+ <div>
43
+ <%= form.submit "Search", name: nil, class: "btn btn-primary" %>
44
+ <%= link_to "Clear all", filter.to_params(job_class: nil, state: nil, queue_name: nil, query: nil), class: "btn btn-secondary" %>
45
+ </div>
64
46
  </div>
65
47
  </div>
66
- </div>
48
+ <% end %>
49
+
50
+ <%= javascript_tag nonce: true do %>
51
+ document.addEventListener("DOMContentLoaded", () => {
52
+ document.querySelectorAll("#job_class_filter, #job_state_filter, #job_queue_filter").forEach((filter) => {
53
+ filter.addEventListener("change", () => {
54
+ document.querySelector("#filter_form").submit();
55
+ });
56
+ })
57
+ })
58
+ <% end %>
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  module GoodJob
3
3
  # GoodJob gem version.
4
- VERSION = '2.9.6'
4
+ VERSION = '2.10.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: good_job
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.9.6
4
+ version: 2.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Sheldon
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-02-07 00:00:00.000000000 Z
11
+ date: 2022-02-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob
@@ -448,7 +448,7 @@ metadata:
448
448
  homepage_uri: https://github.com/bensheldon/good_job
449
449
  source_code_uri: https://github.com/bensheldon/good_job
450
450
  rubygems_mfa_required: 'true'
451
- post_install_message:
451
+ post_install_message:
452
452
  rdoc_options:
453
453
  - "--title"
454
454
  - GoodJob - a multithreaded, Postgres-based ActiveJob backend for Ruby on Rails
@@ -471,8 +471,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
471
471
  - !ruby/object:Gem::Version
472
472
  version: '0'
473
473
  requirements: []
474
- rubygems_version: 3.1.6
475
- signing_key:
474
+ rubygems_version: 3.3.7
475
+ signing_key:
476
476
  specification_version: 4
477
477
  summary: A multithreaded, Postgres-based ActiveJob backend for Ruby on Rails
478
478
  test_files: []