towerops/lib/towerops_web/live/maintenance_live/show.html.heex
Graham McIntire 532d88ffb9
perf: disable Req retry for faster error tests
- Add retry: false to VISP Client HTTP requests
- Add retry: false to ReleaseChecker GitHub API requests
- Remove unused Plug.Conn import from RemoteIpLogger
- Remove unused default parameter from req_get/2

Results:
- VISP sync test: 7007ms → 113ms (62x faster)
- ReleaseChecker test: 7004ms → 17ms (402x faster)
- UserResetPasswordLive test: 1495ms → 284ms (5x faster)

Req's default retry behavior (1s, 2s, 4s exponential backoff) was
causing 7-second delays for HTTP 500/503 error responses in tests.
For these clients, immediate failure is preferred over retries.
2026-03-10 16:19:31 -05:00

144 lines
5.3 KiB
Text

<Layouts.authenticated
flash={@flash}
current_scope={@current_scope}
active_page="maintenance"
>
<div class="mb-6">
<.link
navigate={~p"/maintenance"}
class="inline-flex items-center gap-1 text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
>
<.icon name="hero-arrow-left" class="h-4 w-4" />
{t("Back to Maintenance Windows")}
</.link>
</div>
<% status = status_for(@window) %>
<%!-- Active banner --%>
<%= if status == :active do %>
<div class="mb-6 rounded-lg bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 p-4">
<div class="flex items-center gap-3">
<.icon name="hero-wrench-screwdriver" class="h-6 w-6 text-green-600 dark:text-green-400" />
<div>
<h3 class="text-sm font-semibold text-green-800 dark:text-green-300">
{t("Currently Active")}
</h3>
<p class="text-sm text-green-700 dark:text-green-400">
{t("This maintenance window is currently in effect. Alerts are being suppressed.")}
</p>
</div>
</div>
</div>
<% end %>
<div class="flex items-start justify-between mb-6">
<div>
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">{@window.name}</h1>
<span class={[
"inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium mt-2",
status == :active &&
"bg-green-100 text-green-800 dark:bg-green-900/40 dark:text-green-300",
status == :upcoming && "bg-blue-100 text-blue-800 dark:bg-blue-900/40 dark:text-blue-300",
status == :past && "bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400"
]}>
{status_label(status)}
</span>
</div>
<div class="flex items-center gap-2">
<.link
navigate={~p"/maintenance/#{@window.id}/edit"}
class="inline-flex items-center gap-2 rounded-lg bg-gray-100 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-200 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700 transition-colors"
>
<.icon name="hero-pencil" class="h-4 w-4" />
{t("Edit")}
</.link>
<button
type="button"
phx-click="delete"
data-confirm={t("Are you sure you want to delete this maintenance window?")}
class="inline-flex items-center gap-2 rounded-lg bg-red-100 px-4 py-2 text-sm font-medium text-red-700 hover:bg-red-200 dark:bg-red-900/30 dark:text-red-300 dark:hover:bg-red-900/50 transition-colors"
>
<.icon name="hero-trash" class="h-4 w-4" />
{t("Delete")}
</button>
</div>
</div>
<div class="rounded-lg border border-gray-200 dark:border-white/10 bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-white/10">
<%!-- Reason --%>
<%= if @window.reason do %>
<div class="px-6 py-4">
<dt class="text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 mb-1">
{t("Reason")}
</dt>
<dd class="text-sm text-gray-900 dark:text-white whitespace-pre-wrap">
{@window.reason}
</dd>
</div>
<% end %>
<%!-- Scope --%>
<div class="px-6 py-4">
<dt class="text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 mb-1">
{t("Scope")}
</dt>
<dd class="text-sm text-gray-900 dark:text-white">{scope_label(@window)}</dd>
</div>
<%!-- Time Range --%>
<div class="px-6 py-4">
<dt class="text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 mb-1">
{t("Time Range")}
</dt>
<dd class="text-sm text-gray-900 dark:text-white">
{format_datetime(@window.starts_at, @timezone)} — {format_datetime(
@window.ends_at,
@timezone
)}
</dd>
</div>
<%!-- Recurring --%>
<div class="px-6 py-4">
<dt class="text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 mb-1">
{t("Recurring")}
</dt>
<dd class="text-sm text-gray-900 dark:text-white">
<%= if @window.recurring do %>
{t("Yes")} — {@window.recurrence_rule || t("No rule specified")}
<% else %>
{t("No")}
<% end %>
</dd>
</div>
<%!-- Suppress Alerts --%>
<div class="px-6 py-4">
<dt class="text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 mb-1">
{t("Suppress Alerts")}
</dt>
<dd class="text-sm text-gray-900 dark:text-white">
<%= if @window.suppress_alerts do %>
<span class="inline-flex items-center gap-1 text-green-700 dark:text-green-400">
<.icon name="hero-check-circle" class="h-4 w-4" /> {t("Yes")}
</span>
<% else %>
<span class="inline-flex items-center gap-1 text-gray-500 dark:text-gray-400">
<.icon name="hero-x-circle" class="h-4 w-4" /> {t("No")}
</span>
<% end %>
</dd>
</div>
<%!-- Created By --%>
<div class="px-6 py-4">
<dt class="text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 mb-1">
{t("Created By")}
</dt>
<dd class="text-sm text-gray-900 dark:text-white">
{if @window.created_by, do: @window.created_by.email, else: "—"}
</dd>
</div>
</div>
</Layouts.authenticated>