towerops/lib/towerops_web/live/admin/monitoring_live.html.heex
mayor daa223c49d
feat: enhance active operations display with device context
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-06 18:32:06 -06:00

127 lines
5.5 KiB
Text

<Layouts.admin flash={@flash} timezone={@timezone}>
<div class="space-y-6">
<div>
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">
Job Monitoring Dashboard
</h1>
<p class="text-gray-600 dark:text-gray-400">
Real-time monitoring of polling and discovery jobs
</p>
</div>
<!-- Health Metrics Cards -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10 p-6">
<h3 class="text-sm font-medium text-gray-600 dark:text-gray-400">Completed (1h)</h3>
<p class="text-3xl font-bold text-gray-900 dark:text-white mt-2">
{Map.get(@health_metrics, :completed_last_hour, 0)}
</p>
<p class="text-sm text-gray-500 dark:text-gray-500 mt-1">jobs completed</p>
</div>
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10 p-6">
<h3 class="text-sm font-medium text-gray-600 dark:text-gray-400">Failed (1h)</h3>
<p class="text-3xl font-bold text-gray-900 dark:text-white mt-2">
{Map.get(@health_metrics, :failed_last_hour, 0)}
</p>
<p class="text-sm text-gray-500 dark:text-gray-500 mt-1">failures</p>
</div>
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10 p-6">
<h3 class="text-sm font-medium text-gray-600 dark:text-gray-400">Avg Duration</h3>
<p class="text-3xl font-bold text-gray-900 dark:text-white mt-2">
<%= if Map.get(@health_metrics, :avg_execution_time_seconds) do %>
{Map.get(@health_metrics, :avg_execution_time_seconds) |> Float.round(1)}s
<% else %>
N/A
<% end %>
</p>
<p class="text-sm text-gray-500 dark:text-gray-500 mt-1">last hour</p>
</div>
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10 p-6">
<h3 class="text-sm font-medium text-gray-600 dark:text-gray-400">Active Jobs</h3>
<p class="text-3xl font-bold text-gray-900 dark:text-white mt-2">
{length(@active_jobs)}
</p>
<p class="text-sm text-gray-500 dark:text-gray-500 mt-1">executing now</p>
</div>
</div>
<!-- Active Operations -->
<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>
</div>
</div>
<% end %>
</div>
<% end %>
</div>
<!-- Problems -->
<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 flex items-center justify-between">
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">Problems</h2>
<div class="flex gap-4">
<span class="text-sm text-orange-600 dark:text-orange-400">
{if @stuck_jobs_count > 0, do: "#{@stuck_jobs_count} stuck", else: ""}
</span>
<span class="text-sm text-red-600 dark:text-red-400">
{if @failed_jobs_count > 0, do: "#{@failed_jobs_count} failed", else: ""}
</span>
</div>
</div>
<div class="p-4">
<%= if @stuck_jobs_count == 0 and @failed_jobs_count == 0 do %>
<p class="text-gray-500 dark:text-gray-400 text-center py-8">
No problems detected
</p>
<% else %>
<p class="text-sm text-gray-600 dark:text-gray-400">
Problems section coming soon
</p>
<% end %>
</div>
</div>
<!-- Health Metrics -->
<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">Health Metrics</h2>
</div>
<div class="p-4">
<p class="text-sm text-gray-600 dark:text-gray-400">
Detailed metrics coming soon
</p>
</div>
</div>
</div>
</Layouts.admin>