From b8b8e34438c05c3dca97aeebcd4665c80c724d2e Mon Sep 17 00:00:00 2001 From: Marty Zalega Date: Fri, 22 Nov 2024 07:06:00 +1000 Subject: [PATCH] feat(jobs): Display dates in relative format (#69) --- lib/oban/live_dashboard.ex | 51 +++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/lib/oban/live_dashboard.ex b/lib/oban/live_dashboard.ex index 04665f0..07e86e0 100644 --- a/lib/oban/live_dashboard.ex +++ b/lib/oban/live_dashboard.ex @@ -18,6 +18,8 @@ defmodule Oban.LiveDashboard do @impl true def render(assigns) do + assigns = assign(assigns, :now, DateTime.utc_now()) + ~H"""
Oban
<.live_nav_bar id="oban_states" page={@page} nav_param="job_state" style={:bar} extra_params={["nav"]}> @@ -33,7 +35,7 @@ defmodule Oban.LiveDashboard do <:col field={:queue} header="Queue" sortable={:desc} /> <:col :let={job} field={@timestamp_field} sortable={:desc}> - <%= format_value(timestamp(job, @timestamp_field)) %> + <%= render_time(timestamp(job, @timestamp_field), @now) %> @@ -61,17 +63,30 @@ defmodule Oban.LiveDashboard do <:elem label="Attempts"><%= @job.attempt %>/<%= @job.max_attempts %> <:elem label="Priority"><%= @job.priority %> <:elem label="Attempted at"><%= format_value(@job.attempted_at) %> - <:elem :if={@job.cancelled_at} label="Cancelled at"><%= format_value(@job.cancelled_at) %> - <:elem :if={@job.completed_at} label="Completed at"><%= format_value(@job.completed_at) %> - <:elem :if={@job.discarded_at} label="Discarded at"><%= format_value(@job.discarded_at) %> - <:elem label="Inserted at"><%= format_value(@job.inserted_at) %> - <:elem label="Scheduled at"><%= format_value(@job.scheduled_at) %> + <:elem :if={@job.cancelled_at} label="Cancelled at"><%= render_time(@job.cancelled_at, @now) %> + <:elem :if={@job.completed_at} label="Completed at"><%= render_time(@job.completed_at, @now) %> + <:elem :if={@job.discarded_at} label="Discarded at"><%= render_time(@job.discarded_at, @now) %> + <:elem label="Inserted at"><%= render_time(@job.inserted_at, @now) %> + <:elem label="Scheduled at"><%= render_time(@job.scheduled_at, @now) %> """ end + defp render_time(nil, _), do: nil + + defp render_time(datetime, now) do + assigns = %{ + datetime: datetime, + now: now, + iso8601: DateTime.to_iso8601(datetime), + title: DateTime.to_string(datetime) + } + + ~H|| + end + @impl true def mount(_params, _, socket) do {:ok, socket} @@ -258,6 +273,30 @@ defmodule Oban.LiveDashboard do defp format_value(value), do: value + defp format_relative(%DateTime{} = a, %DateTime{} = b) do + delta = DateTime.diff(a, b, :second) + {prefix, suffix} = if delta < 0, do: {"", " ago"}, else: {"in ", ""} + {d, {h, m, s}} = :calendar.seconds_to_daystime(div(delta, 1000)) + + cond do + d > 1 -> "#{d} days" + d == 1 -> "1 day" + h > 1 -> "#{h} hours" + h == 1 -> "1 hour" + m > 1 -> "#{m} minutes" + m == 1 -> "1 minute" + s == 1 -> "1 second" + true -> "#{s} seconds" + end + |> then(fn x -> "#{prefix}#{x}#{suffix}" end) + end + + defp format_relative(%DateTime{} = a, nil) do + format_relative(a, DateTime.utc_now()) + end + + defp format_relative(nil, _), do: nil + defp timestamp(job, timestamp_field) do Map.get(job, timestamp_field) end