feat: build recent activity timeline with color-coded events

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Graham McIntire 2026-02-06 18:35:55 -06:00 committed by Graham McIntire
parent 8bceb6dce2
commit 1eaf6d9ac5
No known key found for this signature in database
3 changed files with 52 additions and 0 deletions

View file

@ -88,6 +88,7 @@ defmodule Towerops.JobMonitoring do
limit: ^limit
)
|> Repo.all()
|> preload_device_context()
end
# Add helper to fetch device context

View file

@ -31,6 +31,7 @@ defmodule ToweropsWeb.Admin.MonitoringLive do
|> assign(:failed_jobs, [])
|> assign(:failed_jobs_count, 0)
|> assign(:recent_jobs, [])
|> assign(:recent_events, [])
|> assign(:metrics, %{})
|> assign(:health_metrics, %{})
|> load_monitoring_data()
@ -76,6 +77,7 @@ defmodule ToweropsWeb.Admin.MonitoringLive do
|> assign(:failed_jobs, failed_jobs)
|> assign(:failed_jobs_count, length(failed_jobs))
|> assign(:recent_jobs, recent_jobs)
|> assign(:recent_events, recent_jobs)
|> assign(:metrics, metrics)
|> assign(:health_metrics, metrics)
end
@ -94,4 +96,18 @@ defmodule ToweropsWeb.Admin.MonitoringLive do
true -> "#{div(minutes, 60)}h #{rem(minutes, 60)}m"
end
end
defp event_border_color("completed"), do: "border-green-500"
defp event_border_color("cancelled"), do: "border-red-500"
defp event_border_color("discarded"), do: "border-gray-400"
defp event_border_color(_), do: "border-gray-300"
defp event_outcome(job) do
case job.state do
"completed" -> "Completed"
"cancelled" -> "Failed"
"discarded" -> "Discarded"
_ -> String.capitalize(job.state)
end
end
end

View file

@ -269,5 +269,40 @@
</p>
</div>
</div>
<!-- Recent Activity -->
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10 p-4">
<h2 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">
Recent Activity
</h2>
<%= if length(@recent_events) == 0 do %>
<p class="text-gray-600 dark:text-gray-400 text-sm">No recent activity</p>
<% else %>
<div class="space-y-2 max-h-96 overflow-y-auto">
<%= for job <- Enum.take(@recent_events, 50) do %>
<div class="text-sm border-l-2 pl-3 py-2 <%= event_border_color(job.state) %>">
<div class="flex items-start justify-between">
<div class="flex-1">
<p class="font-medium text-gray-900 dark:text-white">
<%= if job.device do %>
<%= job.device.name %>
<% else %>
Device #{get_in(job.args, ["device_id"])}
<% end %>
</p>
<p class="text-xs text-gray-600 dark:text-gray-400">
<%= worker_name(job.worker) %> · <%= event_outcome(job) %>
</p>
</div>
<span class="text-xs text-gray-500 dark:text-gray-500 whitespace-nowrap ml-2">
<%= ToweropsWeb.TimeHelpers.format_time_ago(job.completed_at || job.updated_at) %>
</span>
</div>
</div>
<% end %>
</div>
<% end %>
</div>
</div>
</Layouts.admin>