feat: enhance active operations display with device context

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Graham McIntire 2026-02-06 18:32:06 -06:00 committed by Graham McIntire
parent 2fb0101bab
commit daa223c49d
No known key found for this signature in database
3 changed files with 50 additions and 27 deletions

View file

@ -29,6 +29,7 @@ defmodule Towerops.JobMonitoring do
order_by: [asc: j.attempted_at]
)
|> Repo.all()
|> preload_device_context()
end
@doc """
@ -86,4 +87,13 @@ defmodule Towerops.JobMonitoring do
)
|> Repo.all()
end
# Add helper to fetch device context
defp preload_device_context(jobs) do
Enum.map(jobs, fn job ->
device_id = get_in(job.args, ["device_id"])
device = device_id && Towerops.Repo.get(Towerops.Devices.Device, device_id)
Map.put(job, :device, device)
end)
end
end

View file

@ -25,6 +25,7 @@ defmodule ToweropsWeb.Admin.MonitoringLive do
socket
|> assign(:page_title, "Job Monitoring")
|> assign(:active_jobs, [])
|> assign(:executing_jobs, [])
|> assign(:stuck_jobs_count, 0)
|> assign(:failed_jobs_count, 0)
|> assign(:recent_jobs, [])
@ -59,15 +60,21 @@ defmodule ToweropsWeb.Admin.MonitoringLive do
@spec load_monitoring_data(Phoenix.LiveView.Socket.t()) :: Phoenix.LiveView.Socket.t()
defp load_monitoring_data(socket) do
executing_jobs = JobMonitoring.list_active_jobs()
stuck_jobs = JobMonitoring.list_stuck_jobs()
failed_jobs = JobMonitoring.list_failed_jobs()
recent_jobs = JobMonitoring.list_recent_completions(20)
metrics = Metrics.calculate_all()
socket
|> assign(:executing_jobs, executing_jobs)
|> assign(:stuck_jobs_count, length(stuck_jobs))
|> assign(:failed_jobs_count, length(failed_jobs))
|> assign(:recent_jobs, recent_jobs)
|> assign(:health_metrics, metrics)
end
defp worker_name("Towerops.Workers.DevicePollerWorker"), do: "Device Poll"
defp worker_name("Towerops.Workers.DiscoveryWorker"), do: "SNMP Discovery"
defp worker_name(worker), do: worker
end

View file

@ -49,35 +49,41 @@
</div>
<!-- Active Operations -->
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10">
<div class="px-4 py-3 border-b border-gray-200 dark:border-white/10">
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">Active Operations</h2>
</div>
<div class="p-4">
<%= if @active_jobs == [] do %>
<p class="text-gray-500 dark:text-gray-400 text-center py-8">
No active jobs
</p>
<% else %>
<div class="space-y-2">
<%= for job <- @active_jobs do %>
<div class="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-900/50 rounded">
<div>
<span class="font-mono text-sm text-gray-900 dark:text-white">
{job.worker |> String.split(".") |> List.last()}
</span>
<span class="text-sm text-gray-500 dark:text-gray-400 ml-2">
Device ID: {job.device_id}
</span>
<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">
Active Operations ({length(@executing_jobs)})
</h2>
<%= if length(@executing_jobs) == 0 do %>
<p class="text-gray-600 dark:text-gray-400 text-sm">No jobs currently executing</p>
<% else %>
<div class="space-y-3">
<%= for job <- @executing_jobs do %>
<div class="border border-gray-200 dark:border-gray-700 rounded p-3">
<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-sm text-gray-600 dark:text-gray-400">
<%= worker_name(job.worker) %>
</p>
<p class="text-xs text-gray-500 dark:text-gray-500 mt-1">
Started <%= ToweropsWeb.TimeHelpers.format_time_ago(job.attempted_at) %>
</p>
</div>
<div class="flex items-center">
<.icon name="hero-arrow-path" class="w-4 h-4 animate-spin text-blue-600" />
</div>
<span class="text-xs text-gray-500 dark:text-gray-400">
Started: {Calendar.strftime(job.timestamp, "%H:%M:%S")}
</span>
</div>
<% end %>
</div>
<% end %>
</div>
</div>
<% end %>
</div>
<% end %>
</div>
<!-- Problems -->