From 57ef49d2f011f020dc0515e863f9934f354144a8 Mon Sep 17 00:00:00 2001 From: Rosa Gutierrez Date: Mon, 2 Dec 2024 22:19:24 +0100 Subject: [PATCH 1/3] Go back to relative, in-words times The absolute times are quite hard to use, and we can force the locale for these instead. --- .../mission_control/jobs/dates_helper.rb | 18 +++++ .../mission_control/jobs/jobs_helper.rb | 2 +- .../jobs/jobs/_general_information.html.erb | 8 +- .../mission_control/jobs/jobs/_job.html.erb | 2 +- .../jobs/jobs/blocked/_job.html.erb | 2 +- .../jobs/jobs/failed/_job.html.erb | 2 +- .../jobs/jobs/in_progress/_job.html.erb | 2 +- .../jobs/jobs/scheduled/_job.html.erb | 2 +- .../mission_control/jobs/queues/_job.html.erb | 2 +- .../recurring_tasks/_recurring_task.html.erb | 4 +- .../mission_control/jobs/shared/_job.html.erb | 6 +- .../jobs/workers/_worker.html.erb | 2 +- test/controllers/jobs_controller_test.rb | 24 ++++-- .../recurring_tasks_controller_test.rb | 79 ++++--------------- test/controllers/retries_controller_test.rb | 24 +++--- 15 files changed, 79 insertions(+), 100 deletions(-) diff --git a/app/helpers/mission_control/jobs/dates_helper.rb b/app/helpers/mission_control/jobs/dates_helper.rb index f559ea59..89264c7f 100644 --- a/app/helpers/mission_control/jobs/dates_helper.rb +++ b/app/helpers/mission_control/jobs/dates_helper.rb @@ -1,4 +1,22 @@ module MissionControl::Jobs::DatesHelper + def time_ago_in_words_with_title(time) + tag.span time_ago_in_words(time), title: time.to_fs(:long) + end + + def time_distance_in_words_with_title(time) + tag.span distance_of_time_in_words_to_now(time, include_seconds: true), title: "Since #{time.to_fs(:long)}" + end + + def bidirectional_time_distance_in_words_with_title(time) + time_distance = if time.past? + "#{distance_of_time_in_words_to_now(time, include_seconds: true)} ago" + else + "in #{distance_of_time_in_words_to_now(time, include_seconds: true)}" + end + + tag.span time_distance, title: time.to_fs(:long) + end + def formatted_time(time) time.in_time_zone.strftime("%Y-%m-%d %H:%M:%S.%3N %Z") end diff --git a/app/helpers/mission_control/jobs/jobs_helper.rb b/app/helpers/mission_control/jobs/jobs_helper.rb index 146504bc..f55f02d7 100644 --- a/app/helpers/mission_control/jobs/jobs_helper.rb +++ b/app/helpers/mission_control/jobs/jobs_helper.rb @@ -29,7 +29,7 @@ def attribute_names_for_job_status(status) when "blocked" then [ "Queue", "Blocked by", "" ] when "finished" then [ "Queue", "Finished" ] when "scheduled" then [ "Queue", "Scheduled", "" ] - when "in_progress" then [ "Queue", "Run by", "Running since" ] + when "in_progress" then [ "Queue", "Run by", "Running for" ] else [] end end diff --git a/app/views/mission_control/jobs/jobs/_general_information.html.erb b/app/views/mission_control/jobs/jobs/_general_information.html.erb index 0b15d7f5..1569699c 100644 --- a/app/views/mission_control/jobs/jobs/_general_information.html.erb +++ b/app/views/mission_control/jobs/jobs/_general_information.html.erb @@ -23,14 +23,14 @@ Enqueued - <%= formatted_time(job.enqueued_at.to_datetime) %> + <%= time_ago_in_words_with_title(job.enqueued_at.to_datetime) %> ago <% if job.scheduled? %> Scheduled - <%= formatted_time(job.scheduled_at) %> + <%= bidirectional_time_distance_in_words_with_title(job.scheduled_at) %> <% if job_delayed?(job) %>
delayed
<% end %> @@ -41,7 +41,7 @@ Failed - <%= formatted_time(job.failed_at) %> + <%= time_ago_in_words_with_title(job.failed_at) %> ago <% end %> @@ -49,7 +49,7 @@ Finished at - <%= formatted_time(job.finished_at) %> + <%= time_ago_in_words_with_title(job.finished_at) %> ago <% end %> diff --git a/app/views/mission_control/jobs/jobs/_job.html.erb b/app/views/mission_control/jobs/jobs/_job.html.erb index bdf8ba54..881eaba6 100644 --- a/app/views/mission_control/jobs/jobs/_job.html.erb +++ b/app/views/mission_control/jobs/jobs/_job.html.erb @@ -6,7 +6,7 @@
<%= job_arguments(job) %>
<% end %> -
Enqueued <%= formatted_time(job.enqueued_at.to_datetime) %>
+
Enqueued <%= time_ago_in_words_with_title(job.enqueued_at.to_datetime) %> ago
<%= render "mission_control/jobs/jobs/#{jobs_status}/job", job: job %> diff --git a/app/views/mission_control/jobs/jobs/blocked/_job.html.erb b/app/views/mission_control/jobs/jobs/blocked/_job.html.erb index 64f00af4..4521ea91 100644 --- a/app/views/mission_control/jobs/jobs/blocked/_job.html.erb +++ b/app/views/mission_control/jobs/jobs/blocked/_job.html.erb @@ -1,6 +1,6 @@ <%= link_to job.queue_name, application_queue_path(@application, job.queue) %>
<%= job.blocked_by %>
-
Until <%= formatted_time(job.blocked_until) %>
+
Expires <%= bidirectional_time_distance_in_words_with_title(job.blocked_until) %>
<%= render "mission_control/jobs/jobs/blocked/actions", job: job %> diff --git a/app/views/mission_control/jobs/jobs/failed/_job.html.erb b/app/views/mission_control/jobs/jobs/failed/_job.html.erb index 5291336c..54f39510 100644 --- a/app/views/mission_control/jobs/jobs/failed/_job.html.erb +++ b/app/views/mission_control/jobs/jobs/failed/_job.html.erb @@ -1,6 +1,6 @@ <%= link_to failed_job_error(job), application_job_path(@application, job.job_id, anchor: "error") %> -
<%= formatted_time(job.failed_at) %>
+
<%= time_ago_in_words_with_title(job.failed_at) %> ago
<%= render "mission_control/jobs/jobs/failed/actions", job: job %> diff --git a/app/views/mission_control/jobs/jobs/in_progress/_job.html.erb b/app/views/mission_control/jobs/jobs/in_progress/_job.html.erb index f428b28f..48491725 100644 --- a/app/views/mission_control/jobs/jobs/in_progress/_job.html.erb +++ b/app/views/mission_control/jobs/jobs/in_progress/_job.html.erb @@ -6,4 +6,4 @@ — <% end %> -
<%= job.started_at ? formatted_time(job.started_at) : "(Finished)" %>
+
<%= job.started_at ? time_distance_in_words_with_title(job.started_at) : "(Finished)" %>
diff --git a/app/views/mission_control/jobs/jobs/scheduled/_job.html.erb b/app/views/mission_control/jobs/jobs/scheduled/_job.html.erb index b337a04e..78b5a366 100644 --- a/app/views/mission_control/jobs/jobs/scheduled/_job.html.erb +++ b/app/views/mission_control/jobs/jobs/scheduled/_job.html.erb @@ -1,6 +1,6 @@ <%= link_to job.queue_name, application_queue_path(@application, job.queue) %> - <%= formatted_time(job.scheduled_at) %> + <%= bidirectional_time_distance_in_words_with_title(job.scheduled_at) %> <% if job_delayed?(job) %>
delayed
<% end %> diff --git a/app/views/mission_control/jobs/queues/_job.html.erb b/app/views/mission_control/jobs/queues/_job.html.erb index 34c0ae8e..36cd2c7b 100644 --- a/app/views/mission_control/jobs/queues/_job.html.erb +++ b/app/views/mission_control/jobs/queues/_job.html.erb @@ -3,7 +3,7 @@ <%= link_to application_job_path(@application, job.job_id, filter: { queue_name: job.queue }) do %> <%= job_title(job) %> <% end %> -
Enqueued on <%= formatted_time(job.enqueued_at.to_datetime) %>
+
Enqueued <%= time_ago_in_words_with_title(job.enqueued_at.to_datetime) %> ago
<% if job.serialized_arguments.present? %> diff --git a/app/views/mission_control/jobs/recurring_tasks/_recurring_task.html.erb b/app/views/mission_control/jobs/recurring_tasks/_recurring_task.html.erb index f3c40e60..3a40f396 100644 --- a/app/views/mission_control/jobs/recurring_tasks/_recurring_task.html.erb +++ b/app/views/mission_control/jobs/recurring_tasks/_recurring_task.html.erb @@ -14,8 +14,8 @@ <% end %> <%= recurring_task.schedule %> -
<%= recurring_task.last_enqueued_at ? formatted_time(recurring_task.last_enqueued_at) : "Never" %>
-
<%= formatted_time(recurring_task.next_time) %>
+
<%= recurring_task.last_enqueued_at ? bidirectional_time_distance_in_words_with_title(recurring_task.last_enqueued_at) : "Never" %>
+
<%= bidirectional_time_distance_in_words_with_title(recurring_task.next_time) %>
<%= render "mission_control/jobs/recurring_tasks/actions", recurring_task: recurring_task %> diff --git a/app/views/mission_control/jobs/shared/_job.html.erb b/app/views/mission_control/jobs/shared/_job.html.erb index 52075dba..22780568 100644 --- a/app/views/mission_control/jobs/shared/_job.html.erb +++ b/app/views/mission_control/jobs/shared/_job.html.erb @@ -3,7 +3,7 @@ <%= link_to application_job_path(@application, job.job_id, filter: { queue_name: job.queue }) do %> <%= job_title(job) %> <% end %> -
Enqueued on <%= formatted_time(job.enqueued_at.to_datetime) %>
+
Enqueued <%= time_ago_in_words_with_title(job.enqueued_at.to_datetime) %> ago
<% if job.serialized_arguments.present? %> @@ -16,9 +16,9 @@
<% if job.started_at %> - Running since <%= formatted_time(job.started_at) %> + Running for <%= time_distance_in_words_with_title(job.started_at) %> <% elsif job.finished_at %> - Finished on <%= formatted_time(job.finished_at) %> + Finished <%= time_ago_in_words_with_title(job.finished_at) %> ago <% else %> Pending <% end %> diff --git a/app/views/mission_control/jobs/workers/_worker.html.erb b/app/views/mission_control/jobs/workers/_worker.html.erb index a10a3d07..be9eaadf 100644 --- a/app/views/mission_control/jobs/workers/_worker.html.erb +++ b/app/views/mission_control/jobs/workers/_worker.html.erb @@ -17,5 +17,5 @@ <% end %> -
<%= formatted_time(worker.last_heartbeat_at) %>
+
<%= time_ago_in_words_with_title(worker.last_heartbeat_at) %> ago
diff --git a/test/controllers/jobs_controller_test.rb b/test/controllers/jobs_controller_test.rb index 4d79fc1d..e78f999a 100644 --- a/test/controllers/jobs_controller_test.rb +++ b/test/controllers/jobs_controller_test.rb @@ -24,7 +24,6 @@ class MissionControl::Jobs::JobsControllerTest < ActionDispatch::IntegrationTest end test "get jobs and job details when there are multiple instances of the same job due to automatic retries" do - time = Time.now job = AutoRetryingJob.perform_later perform_enqueued_jobs_async @@ -33,7 +32,7 @@ class MissionControl::Jobs::JobsControllerTest < ActionDispatch::IntegrationTest assert_response :ok assert_select "tr.job", 2 - assert_select "tr.job", /AutoRetryingJob\s+Enqueued #{time_pattern(time)}\s+default/ + assert_select "tr.job", /AutoRetryingJob\s+Enqueued less than a minute ago\s+default/ get mission_control_jobs.application_job_url(@application, job.job_id) assert_response :ok @@ -72,16 +71,17 @@ class MissionControl::Jobs::JobsControllerTest < ActionDispatch::IntegrationTest end test "get scheduled jobs" do - time = Time.now DummyJob.set(wait: 3.minutes).perform_later DummyJob.set(wait: 1.minute).perform_later + travel_to 2.minutes.from_now + get mission_control_jobs.application_jobs_url(@application, :scheduled) assert_response :ok assert_select "tr.job", 2 - assert_select "tr.job", /DummyJob\s+Enqueued #{time_pattern(time)}\s+queue_1\s+#{time_pattern(time + 3.minute)}/ - assert_select "tr.job", /DummyJob\s+Enqueued #{time_pattern(time)}\s+queue_1\s+#{time_pattern(time + 1.minute)}/ + assert_select "tr.job", /DummyJob\s+Enqueued 2 minutes ago\s+queue_1\s+in 1 minute/ + assert_select "tr.job", /DummyJob\s+Enqueued 2 minutes ago\s+queue_1\s+(1 minute ago|less than a minute ago)/ assert_select "tr.job", /Discard/ end @@ -104,8 +104,16 @@ class MissionControl::Jobs::JobsControllerTest < ActionDispatch::IntegrationTest end end - private - def time_pattern(time) - /#{time.utc.strftime("%Y-%m-%d %H:%M")}:\d{2}\.\d{3} UTC/ + test "get jobs and job details the default locale is set to another language than English" do + I18n.available_locales = %i[en nl] + + DummyJob.set(wait: 3.minutes).perform_later + + I18n.with_locale(:nl) do + get mission_control_jobs.application_jobs_url(@application, :scheduled) + assert_response :ok + + assert_select "tr.job", /DummyJob\s+Enqueued less than a minute ago\s+queue_1\s+in 3 minutes/ end + end end diff --git a/test/controllers/recurring_tasks_controller_test.rb b/test/controllers/recurring_tasks_controller_test.rb index 77f2dcbb..21102b75 100644 --- a/test/controllers/recurring_tasks_controller_test.rb +++ b/test/controllers/recurring_tasks_controller_test.rb @@ -13,33 +13,27 @@ class MissionControl::Jobs::RecurringTasksControllerTest < ActionDispatch::Integ end test "get recurring task list" do - travel_to Time.parse("2024-10-30 19:07:10 UTC") do - schedule_recurring_tasks_async(wait: 2.seconds) do - get mission_control_jobs.application_recurring_tasks_url(@application) - assert_response :ok - - assert_select "tr.recurring_task", 1 - assert_select "td a", "periodic_pause_job" - assert_select "td", "PauseJob" - assert_select "td", "every second" - assert_select "td", /2024-10-30 19:07:1\d\.\d{3}/ - assert_select "button", "Run now" - end + schedule_recurring_tasks_async(wait: 2.seconds) do + get mission_control_jobs.application_recurring_tasks_url(@application) + assert_response :ok + + assert_select "tr.recurring_task", 1 + assert_select "td a", "periodic_pause_job" + assert_select "td", "PauseJob" + assert_select "td", "every second" + assert_select "td", /less than \d+ seconds ago/ end end test "get recurring task details and job list" do - travel_to Time.parse("2024-10-30 19:07:10 UTC") do - schedule_recurring_tasks_async(wait: 1.seconds) do - get mission_control_jobs.application_recurring_task_url(@application, "periodic_pause_job") - assert_response :ok - - assert_select "h1", /periodic_pause_job/ - assert_select "h2", "1 job" - assert_select "tr.job", 1 - assert_select "td a", "PauseJob" - assert_select "td", /2024-10-30 19:07:1\d\.\d{3}/ - end + schedule_recurring_tasks_async(wait: 1.seconds) do + get mission_control_jobs.application_recurring_task_url(@application, "periodic_pause_job") + assert_response :ok + assert_select "h1", /periodic_pause_job/ + assert_select "h2", "1 job" + assert_select "tr.job", 1 + assert_select "td a", "PauseJob" + assert_select "td", /less than \d+ seconds ago/ end end @@ -53,43 +47,4 @@ class MissionControl::Jobs::RecurringTasksControllerTest < ActionDispatch::Integ assert_select "article.is-danger", /Recurring task with id 'invalid_key' not found/ end end - - test "get recurring task with undefined class" do - # simulate recurring task inserted from another app, no validations or callbacks - SolidQueue::RecurringTask.insert({ key: "missing_class_task", class_name: "MissingJob", schedule: "every minute" }) - get mission_control_jobs.application_recurring_tasks_url(@application) - assert_response :ok - - assert_select "tr.recurring_task", 1 - assert_select "td a", "missing_class_task" - assert_select "td", "MissingJob" - assert_select "td", "every minute" - assert_select "button", text: "Run now", count: 0 # Can't be run because the class doesn't exist - end - - test "enqueue recurring task successfully" do - schedule_recurring_tasks_async(wait: 0.1.seconds) - - assert_difference -> { ActiveJob.jobs.pending.count } do - put mission_control_jobs.application_recurring_task_url(@application, "periodic_pause_job") - assert_response :redirect - end - - job = ActiveJob.jobs.pending.last - assert_equal "PauseJob", job.job_class_name - assert_match /jobs\/#{job.job_id}\?server_id=solid_queue\z/, response.location - end - - test "fail to enqueue recurring task with undefined class" do - # simulate recurring task inserted from another app, no validations or callbacks - SolidQueue::RecurringTask.insert({ key: "missing_class_task", class_name: "MissingJob", schedule: "every minute" }) - - assert_no_difference -> { ActiveJob.jobs.pending.count } do - put mission_control_jobs.application_recurring_task_url(@application, "missing_class_task") - assert_response :redirect - - follow_redirect! - assert_select "article.is-danger", /This task can.t be enqueued/ - end - end end diff --git a/test/controllers/retries_controller_test.rb b/test/controllers/retries_controller_test.rb index c7f24a21..ea02f662 100644 --- a/test/controllers/retries_controller_test.rb +++ b/test/controllers/retries_controller_test.rb @@ -10,23 +10,21 @@ class MissionControl::Jobs::JobsControllerTest < ActionDispatch::IntegrationTest end test "retry jobs when there are multiple instances of the same job due to automatic retries" do - travel_to Time.parse("2024-10-30 19:07:10 UTC") do - job = AutoRetryingJob.perform_later + job = AutoRetryingJob.perform_later - perform_enqueued_jobs_async + perform_enqueued_jobs_async - get mission_control_jobs.application_jobs_url(@application, :failed) - assert_response :ok + get mission_control_jobs.application_jobs_url(@application, :failed) + assert_response :ok - assert_select "tr.job", 1 - assert_select "tr.job", /AutoRetryingJob\s+Enqueued 2024-10-30 19:07:1\d\.\d{3} UTC\s+AutoRetryingJob::RandomError/ + assert_select "tr.job", 1 + assert_select "tr.job", /AutoRetryingJob\s+Enqueued less than 5 seconds ago\s+AutoRetryingJob::RandomError/ - post mission_control_jobs.application_job_retry_url(@application, job.job_id) - assert_redirected_to mission_control_jobs.application_jobs_url(@application, :failed) - follow_redirect! + post mission_control_jobs.application_job_retry_url(@application, job.job_id) + assert_redirected_to mission_control_jobs.application_jobs_url(@application, :failed) + follow_redirect! - assert_select "article.is-danger", text: /Job with id '#{job.job_id}' not found/, count: 0 - assert_select "tr.job", 0 - end + assert_select "article.is-danger", text: /Job with id '#{job.job_id}' not found/, count: 0 + assert_select "tr.job", 0 end end From de4116c71ca56ac4f014ee87683255d49d596812 Mon Sep 17 00:00:00 2001 From: Rosa Gutierrez Date: Mon, 2 Dec 2024 22:28:03 +0100 Subject: [PATCH 2/3] Simplify time helpers One of them is basically the same as another one. --- app/helpers/mission_control/jobs/dates_helper.rb | 10 +--------- .../jobs/jobs/_general_information.html.erb | 6 +++--- app/views/mission_control/jobs/jobs/_job.html.erb | 2 +- .../mission_control/jobs/jobs/failed/_job.html.erb | 2 +- .../mission_control/jobs/jobs/finished/_job.html.erb | 2 +- app/views/mission_control/jobs/queues/_job.html.erb | 2 +- app/views/mission_control/jobs/shared/_job.html.erb | 4 ++-- .../mission_control/jobs/workers/_worker.html.erb | 2 +- 8 files changed, 11 insertions(+), 19 deletions(-) diff --git a/app/helpers/mission_control/jobs/dates_helper.rb b/app/helpers/mission_control/jobs/dates_helper.rb index 89264c7f..115d5760 100644 --- a/app/helpers/mission_control/jobs/dates_helper.rb +++ b/app/helpers/mission_control/jobs/dates_helper.rb @@ -1,10 +1,6 @@ module MissionControl::Jobs::DatesHelper - def time_ago_in_words_with_title(time) - tag.span time_ago_in_words(time), title: time.to_fs(:long) - end - def time_distance_in_words_with_title(time) - tag.span distance_of_time_in_words_to_now(time, include_seconds: true), title: "Since #{time.to_fs(:long)}" + tag.span time_ago_in_words(time, include_seconds: true), title: "Since #{time.to_fs(:long)}" end def bidirectional_time_distance_in_words_with_title(time) @@ -16,8 +12,4 @@ def bidirectional_time_distance_in_words_with_title(time) tag.span time_distance, title: time.to_fs(:long) end - - def formatted_time(time) - time.in_time_zone.strftime("%Y-%m-%d %H:%M:%S.%3N %Z") - end end diff --git a/app/views/mission_control/jobs/jobs/_general_information.html.erb b/app/views/mission_control/jobs/jobs/_general_information.html.erb index 1569699c..e962e763 100644 --- a/app/views/mission_control/jobs/jobs/_general_information.html.erb +++ b/app/views/mission_control/jobs/jobs/_general_information.html.erb @@ -23,7 +23,7 @@ Enqueued - <%= time_ago_in_words_with_title(job.enqueued_at.to_datetime) %> ago + <%= time_distance_in_words_with_title(job.enqueued_at.to_datetime) %> ago <% if job.scheduled? %> @@ -41,7 +41,7 @@ Failed - <%= time_ago_in_words_with_title(job.failed_at) %> ago + <%= time_distance_in_words_with_title(job.failed_at) %> ago <% end %> @@ -49,7 +49,7 @@ Finished at - <%= time_ago_in_words_with_title(job.finished_at) %> ago + <%= time_distance_in_words_with_title(job.finished_at) %> ago <% end %> diff --git a/app/views/mission_control/jobs/jobs/_job.html.erb b/app/views/mission_control/jobs/jobs/_job.html.erb index 881eaba6..716dfdbc 100644 --- a/app/views/mission_control/jobs/jobs/_job.html.erb +++ b/app/views/mission_control/jobs/jobs/_job.html.erb @@ -6,7 +6,7 @@
<%= job_arguments(job) %>
<% end %> -
Enqueued <%= time_ago_in_words_with_title(job.enqueued_at.to_datetime) %> ago
+
Enqueued <%= time_distance_in_words_with_title(job.enqueued_at.to_datetime) %> ago
<%= render "mission_control/jobs/jobs/#{jobs_status}/job", job: job %> diff --git a/app/views/mission_control/jobs/jobs/failed/_job.html.erb b/app/views/mission_control/jobs/jobs/failed/_job.html.erb index 54f39510..22bcd146 100644 --- a/app/views/mission_control/jobs/jobs/failed/_job.html.erb +++ b/app/views/mission_control/jobs/jobs/failed/_job.html.erb @@ -1,6 +1,6 @@ <%= link_to failed_job_error(job), application_job_path(@application, job.job_id, anchor: "error") %> -
<%= time_ago_in_words_with_title(job.failed_at) %> ago
+
<%= time_distance_in_words_with_title(job.failed_at) %> ago
<%= render "mission_control/jobs/jobs/failed/actions", job: job %> diff --git a/app/views/mission_control/jobs/jobs/finished/_job.html.erb b/app/views/mission_control/jobs/jobs/finished/_job.html.erb index b0e9f201..5488bed7 100644 --- a/app/views/mission_control/jobs/jobs/finished/_job.html.erb +++ b/app/views/mission_control/jobs/jobs/finished/_job.html.erb @@ -1,2 +1,2 @@ <%= link_to job.queue_name, application_queue_path(@application, job.queue) %> -
<%= formatted_time(job.finished_at) %>
+
<%= time_distance_in_words_with_title(job.finished_at) %> ago
diff --git a/app/views/mission_control/jobs/queues/_job.html.erb b/app/views/mission_control/jobs/queues/_job.html.erb index 36cd2c7b..5635abec 100644 --- a/app/views/mission_control/jobs/queues/_job.html.erb +++ b/app/views/mission_control/jobs/queues/_job.html.erb @@ -3,7 +3,7 @@ <%= link_to application_job_path(@application, job.job_id, filter: { queue_name: job.queue }) do %> <%= job_title(job) %> <% end %> -
Enqueued <%= time_ago_in_words_with_title(job.enqueued_at.to_datetime) %> ago
+
Enqueued <%= time_distance_in_words_with_title(job.enqueued_at.to_datetime) %> ago
<% if job.serialized_arguments.present? %> diff --git a/app/views/mission_control/jobs/shared/_job.html.erb b/app/views/mission_control/jobs/shared/_job.html.erb index 22780568..c42a3851 100644 --- a/app/views/mission_control/jobs/shared/_job.html.erb +++ b/app/views/mission_control/jobs/shared/_job.html.erb @@ -3,7 +3,7 @@ <%= link_to application_job_path(@application, job.job_id, filter: { queue_name: job.queue }) do %> <%= job_title(job) %> <% end %> -
Enqueued <%= time_ago_in_words_with_title(job.enqueued_at.to_datetime) %> ago
+
Enqueued <%= time_distance_in_words_with_title(job.enqueued_at.to_datetime) %> ago
<% if job.serialized_arguments.present? %> @@ -18,7 +18,7 @@ <% if job.started_at %> Running for <%= time_distance_in_words_with_title(job.started_at) %> <% elsif job.finished_at %> - Finished <%= time_ago_in_words_with_title(job.finished_at) %> ago + Finished <%= time_distance_in_words_with_title(job.finished_at) %> ago <% else %> Pending <% end %> diff --git a/app/views/mission_control/jobs/workers/_worker.html.erb b/app/views/mission_control/jobs/workers/_worker.html.erb index be9eaadf..3d1aee48 100644 --- a/app/views/mission_control/jobs/workers/_worker.html.erb +++ b/app/views/mission_control/jobs/workers/_worker.html.erb @@ -17,5 +17,5 @@ <% end %> -
<%= time_ago_in_words_with_title(worker.last_heartbeat_at) %> ago
+
<%= time_distance_in_words_with_title(worker.last_heartbeat_at) %> ago
From b449afed73226fa897ee35ebb9a4315d2865e46f Mon Sep 17 00:00:00 2001 From: Rosa Gutierrez Date: Mon, 2 Dec 2024 23:07:51 +0100 Subject: [PATCH 3/3] Create a custom I18n config class to set available locales Without interferring with the host application's I18n configuration. I18n's available_locales unfortunately is not thread-safe so we can't just change that, but I18n.config is thread-safe [1], so we can use our own there, that just relies on all I18n defaults except for available locales. [1] https://github.com/ruby-i18n/i18n/blob/3b65f6548245411bc9802f5a547954d370b57821/lib/i18n.rb#L56-L64 --- .../jobs/application_controller.rb | 11 +++++++++ .../mission_control/jobs/dates_helper.rb | 10 +++++--- lib/mission_control/jobs/i18n_config.rb | 5 ++++ test/controllers/jobs_controller_test.rb | 23 +++++++++++++++---- 4 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 lib/mission_control/jobs/i18n_config.rb diff --git a/app/controllers/mission_control/jobs/application_controller.rb b/app/controllers/mission_control/jobs/application_controller.rb index d1c56c09..6f5d1af2 100644 --- a/app/controllers/mission_control/jobs/application_controller.rb +++ b/app/controllers/mission_control/jobs/application_controller.rb @@ -13,8 +13,19 @@ class MissionControl::Jobs::ApplicationController < MissionControl::Jobs.base_co include MissionControl::Jobs::ApplicationScoped, MissionControl::Jobs::NotFoundRedirections include MissionControl::Jobs::AdapterFeatures + around_action :set_current_locale + private def default_url_options { server_id: MissionControl::Jobs::Current.server } end + + def set_current_locale(&block) + @previous_config = I18n.config + I18n.config = MissionControl::Jobs::I18nConfig.new + I18n.with_locale(:en, &block) + ensure + I18n.config = @previous_config + @previous_config = nil + end end diff --git a/app/helpers/mission_control/jobs/dates_helper.rb b/app/helpers/mission_control/jobs/dates_helper.rb index 115d5760..ad8a63ad 100644 --- a/app/helpers/mission_control/jobs/dates_helper.rb +++ b/app/helpers/mission_control/jobs/dates_helper.rb @@ -1,15 +1,19 @@ module MissionControl::Jobs::DatesHelper def time_distance_in_words_with_title(time) - tag.span time_ago_in_words(time, include_seconds: true), title: "Since #{time.to_fs(:long)}" + tag.span time_ago_in_words_with_default_options(time), title: "Since #{time.to_fs(:long)}" end def bidirectional_time_distance_in_words_with_title(time) time_distance = if time.past? - "#{distance_of_time_in_words_to_now(time, include_seconds: true)} ago" + "#{time_ago_in_words_with_default_options(time)} ago" else - "in #{distance_of_time_in_words_to_now(time, include_seconds: true)}" + "in #{time_ago_in_words_with_default_options(time)}" end tag.span time_distance, title: time.to_fs(:long) end + + def time_ago_in_words_with_default_options(time) + time_ago_in_words(time, include_seconds: true, locale: :en) + end end diff --git a/lib/mission_control/jobs/i18n_config.rb b/lib/mission_control/jobs/i18n_config.rb new file mode 100644 index 00000000..442d61f6 --- /dev/null +++ b/lib/mission_control/jobs/i18n_config.rb @@ -0,0 +1,5 @@ +class MissionControl::Jobs::I18nConfig < ::I18n::Config + def available_locales + [ :en ] + end +end diff --git a/test/controllers/jobs_controller_test.rb b/test/controllers/jobs_controller_test.rb index e78f999a..54a36120 100644 --- a/test/controllers/jobs_controller_test.rb +++ b/test/controllers/jobs_controller_test.rb @@ -32,7 +32,7 @@ class MissionControl::Jobs::JobsControllerTest < ActionDispatch::IntegrationTest assert_response :ok assert_select "tr.job", 2 - assert_select "tr.job", /AutoRetryingJob\s+Enqueued less than a minute ago\s+default/ + assert_select "tr.job", /AutoRetryingJob\s+Enqueued less than 5 seconds ago\s+default/ get mission_control_jobs.application_job_url(@application, job.job_id) assert_response :ok @@ -104,8 +104,8 @@ class MissionControl::Jobs::JobsControllerTest < ActionDispatch::IntegrationTest end end - test "get jobs and job details the default locale is set to another language than English" do - I18n.available_locales = %i[en nl] + test "get jobs and job details when the default locale is set to another language than English" do + previous_locales, I18n.available_locales = I18n.available_locales, %i[ en nl ] DummyJob.set(wait: 3.minutes).perform_later @@ -113,7 +113,22 @@ class MissionControl::Jobs::JobsControllerTest < ActionDispatch::IntegrationTest get mission_control_jobs.application_jobs_url(@application, :scheduled) assert_response :ok - assert_select "tr.job", /DummyJob\s+Enqueued less than a minute ago\s+queue_1\s+in 3 minutes/ + assert_select "tr.job", /DummyJob\s+Enqueued less than 5 seconds ago\s+queue_1\s+in 3 minutes/ end + ensure + I18n.available_locales = previous_locales + end + + test "get jobs and job details when English is not included among the locales" do + previous_locales, I18n.available_locales = I18n.available_locales, %i[ es nl ] + + DummyJob.set(wait: 3.minutes).perform_later + + get mission_control_jobs.application_jobs_url(@application, :scheduled) + assert_response :ok + + assert_select "tr.job", /DummyJob\s+Enqueued less than 5 seconds ago\s+queue_1\s+in 3 minutes/ + ensure + I18n.available_locales = previous_locales end end