chore: update phoenix_live_view 1.1.32→1.2.6, relax constraint to ~> 1.2

This commit is contained in:
Graham McIntire 2026-07-08 10:57:31 -05:00
parent de012ec366
commit 749932082f
42 changed files with 619 additions and 650 deletions

View file

@ -27,8 +27,8 @@ defmodule ToweropsWeb.Components.ConsentPrompt do
<!-- Backdrop -->
<div class="fixed inset-0 bg-gray-500 dark:bg-gray-900 bg-opacity-75 dark:bg-opacity-80 transition-opacity">
</div>
<!-- Modal panel -->
<!-- Modal panel -->
<div class="relative transform overflow-hidden rounded-lg bg-white dark:bg-gray-800 px-4 pb-4 pt-5 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg sm:p-6">
<div class="sm:flex sm:items-start">
<div class="mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-blue-100 dark:bg-blue-900 sm:mx-0 sm:h-10 sm:w-10">

View file

@ -166,8 +166,8 @@ defmodule ToweropsWeb.Layouts do
</div>
</div>
<% end %>
<!-- Slim Top Bar -->
<!-- Slim Top Bar -->
<header class="sticky top-0 z-40 border-b border-gray-200 bg-white dark:border-white/10 dark:bg-gray-900">
<div class="flex h-14 items-center justify-between px-4">
<div class="flex items-center gap-2">
@ -214,8 +214,8 @@ defmodule ToweropsWeb.Layouts do
K
</kbd>
</button>
<!-- Notification bell -->
<!-- Notification bell -->
<.link
:if={@current_organization}
navigate={~p"/alerts"}
@ -233,8 +233,8 @@ defmodule ToweropsWeb.Layouts do
</span>
<% end %>
</.link>
<!-- Help icon -->
<!-- Help icon -->
<.link
navigate={~p"/help"}
class="p-2 rounded-md text-gray-500 hover:text-gray-700 hover:bg-gray-100 dark:text-gray-400 dark:hover:text-gray-200 dark:hover:bg-gray-800 transition-colors"
@ -242,8 +242,8 @@ defmodule ToweropsWeb.Layouts do
>
<.icon name="hero-question-mark-circle" class="h-5 w-5" />
</.link>
<!-- User menu -->
<!-- User menu -->
<button
type="button"
id="org-menu-button"
@ -329,11 +329,10 @@ defmodule ToweropsWeb.Layouts do
</div>
</div>
</header>
<!-- Sidebar + Main content wrapper -->
<!-- Sidebar + Main content wrapper -->
<div class="flex">
<!-- Desktop Sidebar -->
<!-- Desktop Sidebar -->
<aside
:if={@current_organization || (@current_scope && @current_scope.user)}
id="app-sidebar"
@ -385,8 +384,8 @@ defmodule ToweropsWeb.Layouts do
icon="hero-signal"
label={t("Weathermap")}
/> --%>
<!-- RESPOND section -->
<!-- RESPOND section -->
<p
data-sidebar-section
class="px-3 mt-4 mb-1 text-[10px] font-semibold uppercase tracking-wider text-gray-400 dark:text-gray-500"
@ -412,8 +411,8 @@ defmodule ToweropsWeb.Layouts do
icon="hero-calendar-days"
label={t("On-Call")}
/>
<!-- ANALYZE section -->
<!-- ANALYZE section -->
<p
data-sidebar-section
class="px-3 mt-4 mb-1 text-[10px] font-semibold uppercase tracking-wider text-gray-400 dark:text-gray-500"
@ -453,8 +452,8 @@ defmodule ToweropsWeb.Layouts do
label={t("Reports")}
/>
</nav>
<!-- Bottom pinned: org switcher + settings + collapse toggle -->
<!-- Bottom pinned: org switcher + settings + collapse toggle -->
<div class="border-t border-gray-200 dark:border-white/10 px-2 py-3.5 space-y-1">
<!-- Org switcher -->
<div :if={@current_organization} class="relative">
@ -509,8 +508,8 @@ defmodule ToweropsWeb.Layouts do
</div>
</div>
</div>
<!-- Settings link -->
<!-- Settings link -->
<.sidebar_link
:if={@current_organization}
navigate={~p"/orgs/#{@current_organization.slug}/settings"}
@ -518,8 +517,8 @@ defmodule ToweropsWeb.Layouts do
icon="hero-cog-6-tooth"
label={t("Settings")}
/>
<!-- Collapse toggle -->
<!-- Collapse toggle -->
<button
type="button"
data-sidebar-toggle
@ -530,8 +529,8 @@ defmodule ToweropsWeb.Layouts do
</button>
</div>
</aside>
<!-- Mobile slide-out panel -->
<!-- Mobile slide-out panel -->
<div
:if={@current_organization || (@current_scope && @current_scope.user)}
id="mobile-menu"
@ -555,8 +554,8 @@ defmodule ToweropsWeb.Layouts do
<.icon name="hero-x-mark" class="size-5" />
</button>
</div>
<!-- Org name -->
<!-- Org name -->
<div
:if={@current_organization}
class="px-4 py-3 border-b border-gray-100 dark:border-white/5"
@ -568,8 +567,8 @@ defmodule ToweropsWeb.Layouts do
{@current_organization.name}
</p>
</div>
<!-- MONITOR -->
<!-- MONITOR -->
<div class="px-2 py-3">
<p class="px-3 mb-1 text-[10px] font-semibold uppercase tracking-wider text-gray-400 dark:text-gray-500">
{t("Monitor")}
@ -594,8 +593,8 @@ defmodule ToweropsWeb.Layouts do
<.icon name="hero-signal" class="size-5" /> {t("Weathermap")}
</.mobile_nav_link> --%>
</div>
<!-- RESPOND -->
<!-- RESPOND -->
<div class="px-2 py-3 border-t border-gray-100 dark:border-white/5">
<p class="px-3 mb-1 text-[10px] font-semibold uppercase tracking-wider text-gray-400 dark:text-gray-500">
{t("Respond")}
@ -610,8 +609,8 @@ defmodule ToweropsWeb.Layouts do
{t("On-Call")}
</.mobile_nav_link>
</div>
<!-- ANALYZE -->
<!-- ANALYZE -->
<div class="px-2 py-3 border-t border-gray-100 dark:border-white/5">
<p class="px-3 mb-1 text-[10px] font-semibold uppercase tracking-wider text-gray-400 dark:text-gray-500">
{t("Analyze")}
@ -626,8 +625,8 @@ defmodule ToweropsWeb.Layouts do
{t("Activity")}
</.mobile_nav_link>
</div>
<!-- Account -->
<!-- Account -->
<div class="px-2 py-3 border-t border-gray-100 dark:border-white/5">
<p class="px-3 mb-1 text-[10px] font-semibold uppercase tracking-wider text-gray-400 dark:text-gray-500">
{t("Account")}
@ -651,8 +650,8 @@ defmodule ToweropsWeb.Layouts do
</div>
</div>
</div>
<!-- Main content -->
<!-- Main content -->
<div id="main-wrapper" class="flex flex-1 flex-col min-h-[calc(100vh-3.5rem)]">
<main id="main-content" tabindex="-1" class="flex-1 py-6 sm:py-10 page-fade-in">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:pl-4 lg:pr-8">
@ -904,8 +903,8 @@ defmodule ToweropsWeb.Layouts do
<span class="hidden sm:inline">Towerops Admin</span>
<span class="sm:hidden">Admin</span>
</.link>
<!-- Desktop navigation -->
<!-- Desktop navigation -->
<div class="hidden sm:ml-6 sm:flex sm:space-x-8">
<.link
navigate={~p"/admin/users"}
@ -944,8 +943,8 @@ defmodule ToweropsWeb.Layouts do
</div>
</div>
</div>
<!-- Mobile menu -->
<!-- Mobile menu -->
<div class="hidden sm:hidden" id="admin-mobile-menu">
<div class="space-y-1 px-2 pb-3 pt-2 border-t border-gray-200 dark:border-white/10">
<.mobile_nav_link navigate={~p"/admin/users"} active={false}>

View file

@ -10,8 +10,8 @@
/>
<meta name="theme-color" content="#2563eb" />
<meta name="robots" content="index, follow" />
<!-- Open Graph -->
<!-- Open Graph -->
<meta property="og:type" content="website" />
<meta property="og:site_name" content="TowerOps" />
<meta
@ -22,8 +22,8 @@
property="og:description"
content="The only platform that connects network monitoring to subscriber impact and revenue. Built for WISP and ISP operators."
/>
<!-- Twitter Card -->
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image" />
<meta
name="twitter:title"
@ -33,8 +33,8 @@
name="twitter:description"
content="The only platform that connects network monitoring to subscriber impact and revenue. Built for WISP and ISP operators."
/>
<!-- Favicon -->
<!-- Favicon -->
<link id="favicon" rel="icon" type="image/webp" href={~p"/images/towerops_logo.webp"} />
<link rel="icon" type="image/png" href={~p"/images/towerops_logo.png"} />
<link rel="apple-touch-icon" href={~p"/images/towerops_logo.png"} />

View file

@ -103,8 +103,8 @@ defmodule ToweropsWeb.MarketingLayouts do
</li>
</ul>
</div>
<!-- Developers Column -->
<!-- Developers Column -->
<div>
<h3 class="text-sm font-semibold text-slate-900 dark:text-white mb-4">Developers</h3>
<ul class="space-y-3">
@ -134,8 +134,8 @@ defmodule ToweropsWeb.MarketingLayouts do
</li>
</ul>
</div>
<!-- Copyright and Legal -->
<!-- Copyright and Legal -->
<div class="lg:col-span-2">
<div class="flex flex-col items-start gap-4 sm:flex-row sm:justify-between sm:items-end">
<div class="flex flex-col gap-2">

View file

@ -7,8 +7,8 @@
Towerops API
</.link>
</div>
<!-- Navigation -->
<!-- Navigation -->
<nav class="flex flex-1 flex-col">
<ul role="list" class="flex flex-1 flex-col gap-y-7">
<!-- Guides Section -->
@ -44,8 +44,8 @@
</li>
</ul>
</li>
<!-- Resources Section -->
<!-- Resources Section -->
<li>
<h2 class="text-xs font-semibold text-zinc-900 dark:text-white">Resources</h2>
<ul role="list" class="mt-3 space-y-1 border-l border-zinc-900/10 dark:border-white/5">
@ -204,8 +204,8 @@
</li>
</ul>
</li>
<!-- Tools Section -->
<!-- Tools Section -->
<li>
<h2 class="text-xs font-semibold text-zinc-900 dark:text-white">Tools</h2>
<ul role="list" class="mt-3 space-y-1 border-l border-zinc-900/10 dark:border-white/5">
@ -249,8 +249,8 @@
</p>
</div>
</section>
<!-- Authentication -->
<!-- Authentication -->
<section id="authentication" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
Authentication
@ -268,8 +268,8 @@ curl https://towerops.net/api/v1/sites \\
API tokens are created and managed in your organization settings. Each token is scoped to a single organization.
</p>
</section>
<!-- Errors -->
<!-- Errors -->
<section id="errors" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
Errors
@ -336,8 +336,8 @@ curl https://towerops.net/api/v1/sites \\
</section>
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Sites Resource -->
<!-- Sites Resource -->
<section id="sites" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
Sites
@ -345,8 +345,8 @@ curl https://towerops.net/api/v1/sites \\
<p class="mt-4 text-base text-gray-600 dark:text-gray-400">
Sites represent physical locations where your network devices are deployed. Each site can have multiple devices and may have default SNMP configuration.
</p>
<!-- Site Model -->
<!-- Site Model -->
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">The site model</h3>
<div class="mt-6">
@ -411,8 +411,8 @@ curl https://towerops.net/api/v1/sites \\
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- List all sites -->
<!-- List all sites -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">List all sites</h3>
@ -429,8 +429,8 @@ curl https://towerops.net/api/v1/sites \\
Lists all sites for the authenticated organization.
</p>
</div>
<!-- Right column - code example -->
<!-- Right column - code example -->
<div>
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
@ -465,8 +465,8 @@ curl -G https://towerops.net/api/v1/sites \\
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Create a site -->
<!-- Create a site -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Create a site</h3>
@ -528,8 +528,8 @@ curl -G https://towerops.net/api/v1/sites \\
</div>
</dl>
</div>
<!-- Right column -->
<!-- Right column -->
<div>
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
@ -568,8 +568,8 @@ curl https://towerops.net/api/v1/sites \
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Get a site -->
<!-- Get a site -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Retrieve a site</h3>
@ -618,8 +618,8 @@ curl https://towerops.net/api/v1/sites/550e8400-e29b-41d4-a716-446655440000 \
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Update a site -->
<!-- Update a site -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Update a site</h3>
@ -674,8 +674,8 @@ curl -X PATCH https://towerops.net/api/v1/sites/550e8400-e29b-41d4-a716-44665544
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Delete a site -->
<!-- Delete a site -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Delete a site</h3>
@ -721,8 +721,8 @@ curl -X DELETE https://towerops.net/api/v1/sites/550e8400-e29b-41d4-a716-4466554
</section>
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Devices Resource -->
<!-- Devices Resource -->
<section id="devices" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
Devices
@ -730,8 +730,8 @@ curl -X DELETE https://towerops.net/api/v1/sites/550e8400-e29b-41d4-a716-4466554
<p class="mt-4 text-base text-gray-600 dark:text-gray-400">
Devices are network equipment monitored by Towerops. Each device belongs to a site and can be monitored via ICMP ping and SNMP.
</p>
<!-- Device Model -->
<!-- Device Model -->
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">The device model</h3>
<div class="mt-6">
@ -862,8 +862,8 @@ curl -X DELETE https://towerops.net/api/v1/sites/550e8400-e29b-41d4-a716-4466554
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- List all devices -->
<!-- List all devices -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">List all devices</h3>
@ -935,8 +935,8 @@ curl -G https://towerops.net/api/v1/devices \
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Create a device -->
<!-- Create a device -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Create a device</h3>
@ -1108,8 +1108,8 @@ curl https://towerops.net/api/v1/devices \
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Get a device -->
<!-- Get a device -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Retrieve a device</h3>
@ -1164,8 +1164,8 @@ curl https://towerops.net/api/v1/devices/650e8400-e29b-41d4-a716-446655440001 \
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Update a device -->
<!-- Update a device -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Update a device</h3>
@ -1227,8 +1227,8 @@ curl -X PATCH https://towerops.net/api/v1/devices/650e8400-e29b-41d4-a716-446655
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Delete a device -->
<!-- Delete a device -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Delete a device</h3>
@ -1274,8 +1274,8 @@ curl -X DELETE https://towerops.net/api/v1/devices/650e8400-e29b-41d4-a716-44665
</section>
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Account Data Resource (GDPR) -->
<!-- Account Data Resource (GDPR) -->
<section id="account-data" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
Account Data (GDPR)
@ -1307,8 +1307,8 @@ curl -X DELETE https://towerops.net/api/v1/devices/650e8400-e29b-41d4-a716-44665
</div>
</div>
</div>
<!-- Export all account data -->
<!-- Export all account data -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
@ -1351,8 +1351,8 @@ curl -X DELETE https://towerops.net/api/v1/devices/650e8400-e29b-41d4-a716-44665
Requires active browser session with CSRF token. Cannot be accessed via API tokens.
</p>
</div>
<!-- Right column - code example -->
<!-- Right column - code example -->
<div>
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
@ -1476,8 +1476,8 @@ Content-Disposition: attachment; filename="towerops-data-{user_id}-{timestamp}.j
</section>
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Alerts Resource -->
<!-- Alerts Resource -->
<section id="alerts" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
Alerts
@ -1485,8 +1485,8 @@ Content-Disposition: attachment; filename="towerops-data-{user_id}-{timestamp}.j
<p class="mt-4 text-base text-gray-600 dark:text-gray-400">
Alerts represent monitoring events triggered when a device check fails or recovers. You can list, view, acknowledge, and resolve alerts.
</p>
<!-- Alert Model -->
<!-- Alert Model -->
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">The alert model</h3>
<div class="mt-6">
@ -1606,8 +1606,8 @@ Content-Disposition: attachment; filename="towerops-data-{user_id}-{timestamp}.j
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- List alerts -->
<!-- List alerts -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">List all alerts</h3>
@ -1700,8 +1700,8 @@ curl -G https://towerops.net/api/v1/alerts \\
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Show alert -->
<!-- Show alert -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Retrieve an alert</h3>
@ -1733,8 +1733,8 @@ curl https://towerops.net/api/v1/alerts/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \\
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Acknowledge alert -->
<!-- Acknowledge alert -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
@ -1790,8 +1790,8 @@ curl -X POST https://towerops.net/api/v1/alerts/a1b2c3d4-e5f6-7890-abcd-ef123456
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Resolve alert -->
<!-- Resolve alert -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Resolve an alert</h3>
@ -1824,8 +1824,8 @@ curl -X POST https://towerops.net/api/v1/alerts/a1b2c3d4-e5f6-7890-abcd-ef123456
</section>
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Agents Resource -->
<!-- Agents Resource -->
<section id="agents" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
Agents
@ -1833,8 +1833,8 @@ curl -X POST https://towerops.net/api/v1/alerts/a1b2c3d4-e5f6-7890-abcd-ef123456
<p class="mt-4 text-base text-gray-600 dark:text-gray-400">
Agents are lightweight monitoring agents that run on your infrastructure to collect device data. Each agent has a token used for authentication.
</p>
<!-- Agent Model -->
<!-- Agent Model -->
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">The agent model</h3>
<div class="mt-6">
@ -1908,8 +1908,8 @@ curl -X POST https://towerops.net/api/v1/alerts/a1b2c3d4-e5f6-7890-abcd-ef123456
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- List agents -->
<!-- List agents -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">List all agents</h3>
@ -1959,8 +1959,8 @@ curl -G https://towerops.net/api/v1/agents \\
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Create agent -->
<!-- Create agent -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Create an agent</h3>
@ -2027,8 +2027,8 @@ curl -X POST https://towerops.net/api/v1/agents \\
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Show agent -->
<!-- Show agent -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Retrieve an agent</h3>
@ -2079,8 +2079,8 @@ curl https://towerops.net/api/v1/agents/b2c3d4e5-f6a7-8901-bcde-f12345678901 \\
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Delete agent -->
<!-- Delete agent -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Delete an agent</h3>
@ -2121,8 +2121,8 @@ curl -X DELETE https://towerops.net/api/v1/agents/b2c3d4e5-f6a7-8901-bcde-f12345
</section>
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Organization Resource -->
<!-- Organization Resource -->
<section id="organization" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
Organization
@ -2130,8 +2130,8 @@ curl -X DELETE https://towerops.net/api/v1/agents/b2c3d4e5-f6a7-8901-bcde-f12345
<p class="mt-4 text-base text-gray-600 dark:text-gray-400">
Retrieve and update settings for the authenticated organization, including SNMP defaults, MikroTik configuration, and general preferences.
</p>
<!-- Organization Model -->
<!-- Organization Model -->
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
The organization model
@ -2220,8 +2220,8 @@ curl -X DELETE https://towerops.net/api/v1/agents/b2c3d4e5-f6a7-8901-bcde-f12345
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Show organization -->
<!-- Show organization -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
@ -2287,8 +2287,8 @@ curl https://towerops.net/api/v1/organization \\
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Update organization -->
<!-- Update organization -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
@ -2352,8 +2352,8 @@ curl -X PATCH https://towerops.net/api/v1/organization \\
</section>
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Members Resource -->
<!-- Members Resource -->
<section id="members" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
Members
@ -2361,8 +2361,8 @@ curl -X PATCH https://towerops.net/api/v1/organization \\
<p class="mt-4 text-base text-gray-600 dark:text-gray-400">
Manage the users who belong to your organization. You can list members, change roles, and remove members.
</p>
<!-- Member Model -->
<!-- Member Model -->
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">The member model</h3>
<div class="mt-6">
@ -2405,8 +2405,8 @@ curl -X PATCH https://towerops.net/api/v1/organization \\
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- List members -->
<!-- List members -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">List all members</h3>
@ -2461,8 +2461,8 @@ curl -G https://towerops.net/api/v1/members \\
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Change member role -->
<!-- Change member role -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
@ -2514,8 +2514,8 @@ curl -X PATCH https://towerops.net/api/v1/members/user-uuid-2 \\
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Remove member -->
<!-- Remove member -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Remove a member</h3>
@ -2548,8 +2548,8 @@ curl -X DELETE https://towerops.net/api/v1/members/user-uuid-2 \\
</section>
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Invitations Resource -->
<!-- Invitations Resource -->
<section id="invitations" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
Invitations
@ -2557,8 +2557,8 @@ curl -X DELETE https://towerops.net/api/v1/members/user-uuid-2 \\
<p class="mt-4 text-base text-gray-600 dark:text-gray-400">
Invite new users to your organization. Invitations expire after 7 days.
</p>
<!-- Invitation Model -->
<!-- Invitation Model -->
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
The invitation model
@ -2625,8 +2625,8 @@ curl -X DELETE https://towerops.net/api/v1/members/user-uuid-2 \\
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- List invitations -->
<!-- List invitations -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
@ -2679,8 +2679,8 @@ curl -G https://towerops.net/api/v1/invitations \\
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Create invitation -->
<!-- Create invitation -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
@ -2743,8 +2743,8 @@ curl -X POST https://towerops.net/api/v1/invitations \\
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Cancel invitation -->
<!-- Cancel invitation -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
@ -2779,8 +2779,8 @@ curl -X DELETE https://towerops.net/api/v1/invitations/inv-uuid-1 \\
</section>
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Integrations Resource -->
<!-- Integrations Resource -->
<section id="integrations" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
Integrations
@ -2788,8 +2788,8 @@ curl -X DELETE https://towerops.net/api/v1/invitations/inv-uuid-1 \\
<p class="mt-4 text-base text-gray-600 dark:text-gray-400">
Manage third-party integrations for your organization, such as notification providers and external monitoring systems.
</p>
<!-- Integration Model -->
<!-- Integration Model -->
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
The integration model
@ -2867,8 +2867,8 @@ curl -X DELETE https://towerops.net/api/v1/invitations/inv-uuid-1 \\
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- List integrations -->
<!-- List integrations -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
@ -2923,8 +2923,8 @@ curl -G https://towerops.net/api/v1/integrations \\
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Create integration -->
<!-- Create integration -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
@ -3001,8 +3001,8 @@ curl -X POST https://towerops.net/api/v1/integrations \\
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Show integration -->
<!-- Show integration -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
@ -3036,8 +3036,8 @@ curl https://towerops.net/api/v1/integrations/intg-uuid-1 \\
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Update integration -->
<!-- Update integration -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
@ -3073,8 +3073,8 @@ curl -X PATCH https://towerops.net/api/v1/integrations/intg-uuid-1 \\
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Delete integration -->
<!-- Delete integration -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
@ -3108,8 +3108,8 @@ curl -X DELETE https://towerops.net/api/v1/integrations/intg-uuid-1 \\
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Test integration connection -->
<!-- Test integration connection -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Test connection</h3>
@ -3155,8 +3155,8 @@ curl -X POST https://towerops.net/api/v1/integrations/intg-uuid-1/test \\
</section>
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Checks Resource -->
<!-- Checks Resource -->
<section id="checks" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
Checks
@ -3164,8 +3164,8 @@ curl -X POST https://towerops.net/api/v1/integrations/intg-uuid-1/test \\
<p class="mt-4 text-base text-gray-600 dark:text-gray-400">
Service checks monitor the availability and responsiveness of network services. Supported check types: HTTP, TCP, DNS, and ping. SNMP checks are managed internally and are not exposed via this API.
</p>
<!-- Check Model -->
<!-- Check Model -->
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">The check model</h3>
<div class="mt-6">
@ -3263,8 +3263,8 @@ curl -X POST https://towerops.net/api/v1/integrations/intg-uuid-1/test \\
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- List all checks -->
<!-- List all checks -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">List all checks</h3>
@ -3349,8 +3349,8 @@ curl -G https://towerops.net/api/v1/checks \
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Create a check -->
<!-- Create a check -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Create a check</h3>
@ -3483,8 +3483,8 @@ curl https://towerops.net/api/v1/checks \
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Get a check -->
<!-- Get a check -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Retrieve a check</h3>
@ -3518,8 +3518,8 @@ curl https://towerops.net/api/v1/checks/7c9e6679-7425-40de-944b-e07fc1f90ae7 \
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Update a check -->
<!-- Update a check -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Update a check</h3>
@ -3555,8 +3555,8 @@ curl -X PATCH https://towerops.net/api/v1/checks/7c9e6679-7425-40de-944b-e07fc1f
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Delete a check -->
<!-- Delete a check -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Delete a check</h3>
@ -3602,8 +3602,8 @@ curl -X DELETE https://towerops.net/api/v1/checks/7c9e6679-7425-40de-944b-e07fc1
</section>
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Check Results & Metrics Resource -->
<!-- Check Results & Metrics Resource -->
<section id="check-results" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
Check Results & Metrics
@ -3613,8 +3613,8 @@ curl -X DELETE https://towerops.net/api/v1/checks/7c9e6679-7425-40de-944b-e07fc1
</p>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Device checks -->
<!-- Device checks -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
@ -3669,8 +3669,8 @@ curl -G https://towerops.net/api/v1/devices/550e8400-e29b-41d4-a716-446655440000
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Device metrics -->
<!-- Device metrics -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
@ -3754,8 +3754,8 @@ curl -G https://towerops.net/api/v1/devices/550e8400-e29b-41d4-a716-446655440000
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Device interfaces -->
<!-- Device interfaces -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
@ -3812,8 +3812,8 @@ curl -G https://towerops.net/api/v1/devices/550e8400-e29b-41d4-a716-446655440000
</section>
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Activity Feed Resource -->
<!-- Activity Feed Resource -->
<section id="activity" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
Activity Feed
@ -3823,8 +3823,8 @@ curl -G https://towerops.net/api/v1/devices/550e8400-e29b-41d4-a716-446655440000
</p>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- List activity -->
<!-- List activity -->
<div class="mt-12">
<div class="flex items-center gap-x-3">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
@ -3910,8 +3910,8 @@ curl -G https://towerops.net/api/v1/activity \\
</section>
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Coverages Resource -->
<!-- Coverages Resource -->
<section id="coverages" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
RF Coverages
@ -4092,8 +4092,8 @@ curl -X DELETE https://towerops.net/api/v1/coverages/COV_ID \\
</section>
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Maintenance Windows Resource -->
<!-- Maintenance Windows Resource -->
<section id="maintenance-windows" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
Maintenance Windows
@ -4185,8 +4185,8 @@ curl -X DELETE https://towerops.net/api/v1/maintenance_windows/WINDOW_ID \\
</section>
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Schedules Resource -->
<!-- Schedules Resource -->
<section id="schedules" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
On-Call Schedules
@ -4313,8 +4313,8 @@ curl -X POST https://towerops.net/api/v1/schedules/SCHED_ID/overrides \
</section>
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Escalation Policies Resource -->
<!-- Escalation Policies Resource -->
<section id="escalation-policies" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
Escalation Policies
@ -4413,8 +4413,8 @@ curl -X POST https://towerops.net/api/v1/escalation_policies/POLICY_ID/rules/RUL
</section>
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Terraform Provider Section -->
<!-- Terraform Provider Section -->
<section id="terraform" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
Terraform Provider
@ -4446,8 +4446,8 @@ curl -X POST https://towerops.net/api/v1/escalation_policies/POLICY_ID/rules/RUL
</div>
</div>
</div>
<!-- What is Terraform -->
<!-- What is Terraform -->
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">What is Terraform?</h3>
<p class="mt-4 text-sm text-gray-600 dark:text-gray-400">
@ -4473,8 +4473,8 @@ curl -X POST https://towerops.net/api/v1/escalation_policies/POLICY_ID/rules/RUL
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Getting Started -->
<!-- Getting Started -->
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Getting Started</h3>
@ -4499,8 +4499,8 @@ curl -X POST https://towerops.net/api/v1/escalation_policies/POLICY_ID/rules/RUL
<li>Towerops API token (create in Organization Settings)</li>
</ul>
</div>
<!-- Right column - code example -->
<!-- Right column - code example -->
<div>
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
@ -4532,8 +4532,8 @@ provider "towerops" {
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Example Usage -->
<!-- Example Usage -->
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Example Usage</h3>
@ -4607,8 +4607,8 @@ terraform destroy
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Available Resources -->
<!-- Available Resources -->
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Available Resources</h3>
@ -4656,8 +4656,8 @@ terraform destroy
</div>
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Documentation Links -->
<!-- Documentation Links -->
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Full Documentation</h3>
@ -4741,8 +4741,8 @@ terraform destroy
</p>
</div>
</section>
<!-- Footer -->
<!-- Footer -->
<footer class="mt-24 border-t border-gray-200 dark:border-white/10 pt-8 pb-16">
<p class="text-sm text-gray-600 dark:text-gray-400">
© 2026 Towerops. All rights reserved.

View file

@ -11,11 +11,11 @@
<div class="max-w-2xl w-full text-center">
<!-- Logo -->
<img src="/images/towerops_logo.png" alt="Towerops" class="h-16 w-auto mx-auto mb-8" />
<!-- Error Code -->
<!-- Error Code -->
<h1 class="text-9xl font-bold text-blue-600 mb-4">404</h1>
<!-- Squirrel Image -->
<!-- Squirrel Image -->
<div class="mb-8">
<img
src="/images/squirrel.jpg"
@ -23,16 +23,16 @@
class="rounded-2xl shadow-xl mx-auto max-w-md w-full"
/>
</div>
<!-- Error Message -->
<!-- Error Message -->
<h2 class="text-3xl font-bold text-slate-900 mb-4">
{t("Oops, a squirrel must have eaten that wire!")}
</h2>
<p class="text-lg text-slate-600 mb-8">
{t("The page you're looking for could not be found.")}
</p>
<!-- Back Home Button -->
<!-- Back Home Button -->
<a
href="/"
class="inline-flex items-center justify-center rounded-full py-3 px-6 text-sm font-semibold bg-blue-600 text-white hover:bg-blue-500 active:bg-blue-800 transition-colors"

View file

@ -11,19 +11,19 @@
<div class="max-w-2xl w-full text-center">
<!-- Logo -->
<img src="/images/towerops_logo.png" alt="Towerops" class="h-16 w-auto mx-auto mb-8" />
<!-- Error Code -->
<!-- Error Code -->
<h1 class="text-9xl font-bold text-blue-600 mb-4">500</h1>
<!-- Error Message -->
<!-- Error Message -->
<h2 class="text-3xl font-bold text-slate-900 mb-4">
{t("Something went wrong on our end")}
</h2>
<p class="text-lg text-slate-600 mb-8">
{t("We're working on fixing the problem. Please try again later.")}
</p>
<!-- Back Home Button -->
<!-- Back Home Button -->
<a
href="/"
class="inline-flex items-center justify-center rounded-full py-3 px-6 text-sm font-semibold bg-blue-600 text-white hover:bg-blue-500 active:bg-blue-800 transition-colors"

View file

@ -7,8 +7,8 @@
Towerops GraphQL API
</.link>
</div>
<!-- Navigation -->
<!-- Navigation -->
<nav class="flex flex-1 flex-col">
<ul role="list" class="flex flex-1 flex-col gap-y-7">
<!-- Guides Section -->
@ -41,8 +41,8 @@
</li>
</ul>
</li>
<!-- Queries Section -->
<!-- Queries Section -->
<li>
<h2 class="text-xs font-semibold text-zinc-900 dark:text-white">Queries</h2>
<ul role="list" class="mt-3 space-y-1 border-l border-zinc-900/10 dark:border-white/5">
@ -160,8 +160,8 @@
</li>
</ul>
</li>
<!-- Mutations Section -->
<!-- Mutations Section -->
<li>
<h2 class="text-xs font-semibold text-zinc-900 dark:text-white">Mutations</h2>
<ul role="list" class="mt-3 space-y-1 border-l border-zinc-900/10 dark:border-white/5">
@ -255,8 +255,8 @@
</li>
</ul>
</li>
<!-- Subscriptions Section -->
<!-- Subscriptions Section -->
<li>
<h2 class="text-xs font-semibold text-zinc-900 dark:text-white">Subscriptions</h2>
<ul role="list" class="mt-3 space-y-1 border-l border-zinc-900/10 dark:border-white/5">
@ -270,8 +270,8 @@
</li>
</ul>
</li>
<!-- Types Section -->
<!-- Types Section -->
<li>
<h2 class="text-xs font-semibold text-zinc-900 dark:text-white">Types</h2>
<ul role="list" class="mt-3 space-y-1 border-l border-zinc-900/10 dark:border-white/5">
@ -285,8 +285,8 @@
</li>
</ul>
</li>
<!-- Links -->
<!-- Links -->
<li class="mt-auto">
<.link
navigate={~p"/docs/api"}
@ -303,8 +303,7 @@
<!-- Main content -->
<div class="lg:pl-72 xl:pl-80">
<div class="mx-auto max-w-3xl px-6 py-10 lg:px-8">
<!-- Introduction -->
<!-- Introduction -->
<section id="introduction" class="mb-16">
<h1 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">GraphQL API</h1>
<p class="mt-4 text-lg text-gray-600 dark:text-gray-400">
@ -333,8 +332,8 @@
</p>
</div>
</section>
<!-- Authentication -->
<!-- Authentication -->
<section id="authentication" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Authentication
@ -351,8 +350,8 @@
<pre class="text-sm text-green-400 overflow-x-auto"><code>Authorization: Bearer <%= @sample_token %></code></pre>
</div>
</section>
<!-- Endpoint -->
<!-- Endpoint -->
<section id="endpoint" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">Endpoint</h2>
<p class="mt-4 text-gray-600 dark:text-gray-400">
@ -380,8 +379,8 @@
<%= raw(~S|-d '{"query": "{ devices { id name ipAddress status } }"}'|) %></code></pre>
</div>
</section>
<!-- Queries: Devices -->
<!-- Queries: Devices -->
<section id="query-devices" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Query: Devices
@ -461,8 +460,8 @@
}]) %></code></pre>
</div>
</section>
<!-- Queries: Sites -->
<!-- Queries: Sites -->
<section id="query-sites" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Query: Sites
@ -490,8 +489,8 @@
<pre class="text-sm text-green-400 overflow-x-auto"><code><%= raw(~S[{ site(id: "site-uuid") { id name location } }]) %></code></pre>
</div>
</section>
<!-- Queries: Alerts -->
<!-- Queries: Alerts -->
<section id="query-alerts" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Query: Alerts
@ -553,8 +552,8 @@
}]) %></code></pre>
</div>
</section>
<!-- Queries: Agents -->
<!-- Queries: Agents -->
<section id="query-agents" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Query: Agents
@ -577,8 +576,8 @@
{ agent(id: "agent-uuid") { id name enabled deviceCount } }]) %></code></pre>
</div>
</section>
<!-- Queries: Organization -->
<!-- Queries: Organization -->
<section id="query-organization" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Query: Organization
@ -604,8 +603,8 @@
}]) %></code></pre>
</div>
</section>
<!-- Queries: Members -->
<!-- Queries: Members -->
<section id="query-members" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Query: Members
@ -621,8 +620,8 @@
}]) %></code></pre>
</div>
</section>
<!-- Queries: Integrations -->
<!-- Queries: Integrations -->
<section id="query-integrations" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Query: Integrations
@ -640,8 +639,8 @@
}]) %></code></pre>
</div>
</section>
<!-- Queries: Activity -->
<!-- Queries: Activity -->
<section id="query-activity" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Query: Activity
@ -661,8 +660,8 @@
}]) %></code></pre>
</div>
</section>
<!-- Queries: Metrics & Interfaces -->
<!-- Queries: Metrics & Interfaces -->
<section id="query-metrics" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Query: Metrics & Interfaces
@ -732,8 +731,8 @@
}]) %></code></pre>
</div>
</section>
<!-- Queries: Time-Series -->
<!-- Queries: Time-Series -->
<section id="query-time-series" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Query: Time-Series
@ -915,8 +914,8 @@
}]) %></code></pre>
</div>
</section>
<!-- Queries: Service Checks -->
<!-- Queries: Service Checks -->
<section id="query-checks" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Query: Service Checks
@ -955,8 +954,8 @@
}]) %></code></pre>
</div>
</section>
<!-- Queries: Schedules -->
<!-- Queries: Schedules -->
<section id="query-schedules" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Query: On-Call Schedules
@ -1016,8 +1015,8 @@
}]) %></code></pre>
</div>
</section>
<!-- Queries: Escalation Policies -->
<!-- Queries: Escalation Policies -->
<section id="query-escalation-policies" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Query: Escalation Policies
@ -1062,8 +1061,8 @@
}]) %></code></pre>
</div>
</section>
<!-- Queries: Maintenance Windows -->
<!-- Queries: Maintenance Windows -->
<section id="query-maintenance-windows" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Query: Maintenance Windows
@ -1088,8 +1087,8 @@
}]) %></code></pre>
</div>
</section>
<!-- Mutations: Devices -->
<!-- Mutations: Devices -->
<section id="mutation-devices" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Mutation: Devices
@ -1138,8 +1137,8 @@
}]) %></code></pre>
</div>
</section>
<!-- Mutations: Sites -->
<!-- Mutations: Sites -->
<section id="mutation-sites" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Mutation: Sites
@ -1165,8 +1164,8 @@
</h3>
<p class="mt-2 text-gray-600 dark:text-gray-400">Same pattern as device mutations.</p>
</section>
<!-- Mutations: Alerts -->
<!-- Mutations: Alerts -->
<section id="mutation-alerts" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Mutation: Alert Actions
@ -1193,8 +1192,8 @@
}]) %></code></pre>
</div>
</section>
<!-- Mutations: Agents -->
<!-- Mutations: Agents -->
<section id="mutation-agents" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Mutation: Agent Management
@ -1219,8 +1218,8 @@
<pre class="text-sm text-green-400 overflow-x-auto"><code><%= raw(~S[mutation { deleteAgent(id: "agent-uuid") { success message } }]) %></code></pre>
</div>
</section>
<!-- Mutations: Organization -->
<!-- Mutations: Organization -->
<section id="mutation-organization" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Mutation: Organization Settings
@ -1246,8 +1245,8 @@
}]) %></code></pre>
</div>
</section>
<!-- Mutations: Members -->
<!-- Mutations: Members -->
<section id="mutation-members" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Mutation: Members
@ -1284,8 +1283,8 @@
mutation { cancelInvitation(id: "invitation-uuid") { success message } }]) %></code></pre>
</div>
</section>
<!-- Mutations: Integrations -->
<!-- Mutations: Integrations -->
<section id="mutation-integrations" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Mutation: Integrations
@ -1317,8 +1316,8 @@ mutation { cancelInvitation(id: "invitation-uuid") { success message } }]) %></c
}]) %></code></pre>
</div>
</section>
<!-- Mutations: Service Checks -->
<!-- Mutations: Service Checks -->
<section id="mutation-checks" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Mutation: Service Checks
@ -1359,8 +1358,8 @@ mutation {
}]) %></code></pre>
</div>
</section>
<!-- Mutations: Schedules -->
<!-- Mutations: Schedules -->
<section id="mutation-schedules" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Mutation: Schedules
@ -1439,8 +1438,8 @@ mutation {
}]) %></code></pre>
</div>
</section>
<!-- Mutations: Escalation Policies -->
<!-- Mutations: Escalation Policies -->
<section id="mutation-escalation-policies" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Mutation: Escalation Policies
@ -1499,8 +1498,8 @@ mutation {
}]) %></code></pre>
</div>
</section>
<!-- Mutations: Maintenance Windows -->
<!-- Mutations: Maintenance Windows -->
<section id="mutation-maintenance-windows" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Mutation: Maintenance Windows
@ -1535,8 +1534,8 @@ mutation {
}]) %></code></pre>
</div>
</section>
<!-- Subscriptions -->
<!-- Subscriptions -->
<section id="subscriptions" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Subscriptions
@ -1677,8 +1676,8 @@ subscription {
}]) %></code></pre>
</div>
</section>
<!-- Types Reference -->
<!-- Types Reference -->
<section id="types" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Types Reference
@ -1795,8 +1794,8 @@ subscription {
id, name, enabled, token, insertedAt
</p>
</section>
<!-- curl Examples -->
<!-- curl Examples -->
<section id="examples" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
curl Examples

View file

@ -42,8 +42,8 @@
</a>
</div>
</div>
<!-- Pain Point Section -->
<!-- Pain Point Section -->
<section aria-label="Pain points" class="bg-slate-900 py-20 sm:py-24">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="mx-auto max-w-2xl text-center">
@ -81,8 +81,8 @@
</div>
</div>
</section>
<!-- Primary Features Section -->
<!-- Primary Features Section -->
<section
id="features"
aria-label="Features for WISP operators"
@ -167,8 +167,8 @@
</div>
</div>
</section>
<!-- How It Works Section -->
<!-- How It Works Section -->
<section
id="how-it-works"
aria-label="How TowerOps works"
@ -272,8 +272,8 @@
</div>
</div>
</section>
<!-- Social Proof / Use Cases -->
<!-- Social Proof / Use Cases -->
<section aria-label="Use cases" class="py-20 sm:py-24">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="mx-auto max-w-2xl md:text-center">
@ -312,8 +312,8 @@
</div>
</div>
</section>
<!-- Pricing Section -->
<!-- Pricing Section -->
<section id="pricing" aria-label="Pricing" class="bg-slate-50 dark:bg-slate-900 py-20 sm:py-32">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="mx-auto max-w-2xl text-center">
@ -410,8 +410,8 @@
</p>
</div>
</section>
<!-- Tech Details -->
<!-- Tech Details -->
<section aria-label="Technical details" class="py-20 sm:py-24">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="mx-auto max-w-2xl md:text-center">
@ -450,8 +450,8 @@
</div>
</div>
</section>
<!-- Final CTA -->
<!-- Final CTA -->
<section aria-label="Get started" class="relative overflow-hidden bg-blue-600 py-32">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 relative">
<div class="mx-auto max-w-lg text-center">

View file

@ -36,8 +36,8 @@
</div>
</div>
</div>
<!-- Right: Registration form -->
<!-- Right: Registration form -->
<div class="col-span-3 px-6 py-10 sm:px-12">
<!-- Mobile brand mark -->
<div class="mb-6 flex items-center justify-center gap-2 lg:hidden">
@ -63,8 +63,8 @@
</.link>
</p>
</div>
<!-- Mobile: value prop banner -->
<!-- Mobile: value prop banner -->
<%= unless @invitation do %>
<div class="mt-5 flex items-center gap-2 rounded-lg bg-green-50 px-4 py-2.5 text-sm text-green-800 dark:bg-green-900/20 dark:text-green-300 lg:hidden">
<.icon name="hero-gift" class="size-5 flex-shrink-0" />

View file

@ -23,8 +23,8 @@
</div>
</div>
</div>
<!-- Right: Login form -->
<!-- Right: Login form -->
<div class="col-span-3 px-6 py-10 sm:px-12">
<!-- Mobile brand mark -->
<div class="mb-6 flex items-center justify-center gap-2 lg:hidden">
@ -133,8 +133,8 @@
</span>
</div>
</div>
<!-- Magic Link -->
<!-- Magic Link -->
<.form :let={f} for={@form} as={:user} id="login_form_magic" action={~p"/users/log-in"}>
<.input
readonly={!!@current_scope}

View file

@ -149,8 +149,8 @@ defmodule ToweropsWeb.AccountLive.MyData do
This page shows all personal data we have stored about you in compliance with GDPR Article 15 (Right to Access).
</p>
</div>
<!-- Profile Information -->
<!-- Profile Information -->
<section class="bg-white dark:bg-gray-900 shadow rounded-lg overflow-hidden">
<div class="px-4 py-5 sm:px-6 border-b border-gray-200 dark:border-gray-700">
<h2 class="text-lg font-medium text-gray-900 dark:text-white">Profile Information</h2>
@ -206,8 +206,8 @@ defmodule ToweropsWeb.AccountLive.MyData do
</dl>
</div>
</section>
<!-- Consent Records -->
<!-- Consent Records -->
<section class="bg-white dark:bg-gray-900 shadow rounded-lg overflow-hidden">
<div class="px-4 py-5 sm:px-6 border-b border-gray-200 dark:border-gray-700">
<h2 class="text-lg font-medium text-gray-900 dark:text-white">
@ -340,8 +340,8 @@ defmodule ToweropsWeb.AccountLive.MyData do
<% end %>
</div>
</section>
<!-- Devices -->
<!-- Devices -->
<section class="bg-white dark:bg-gray-900 shadow rounded-lg overflow-hidden">
<div class="px-4 py-5 sm:px-6 border-b border-gray-200 dark:border-gray-700">
<h2 class="text-lg font-medium text-gray-900 dark:text-white">
@ -402,8 +402,8 @@ defmodule ToweropsWeb.AccountLive.MyData do
<% end %>
</div>
</section>
<!-- Alerts -->
<!-- Alerts -->
<section class="bg-white dark:bg-gray-900 shadow rounded-lg overflow-hidden">
<div class="px-4 py-5 sm:px-6 border-b border-gray-200 dark:border-gray-700">
<h2 class="text-lg font-medium text-gray-900 dark:text-white">
@ -471,8 +471,8 @@ defmodule ToweropsWeb.AccountLive.MyData do
</div>
</section>
<% end %>
<!-- Audit Logs -->
<!-- Audit Logs -->
<section class="bg-white dark:bg-gray-900 shadow rounded-lg overflow-hidden">
<div class="px-4 py-5 sm:px-6 border-b border-gray-200 dark:border-gray-700">
<h2 class="text-lg font-medium text-gray-900 dark:text-white">
@ -515,8 +515,8 @@ defmodule ToweropsWeb.AccountLive.MyData do
<% end %>
</div>
</section>
<!-- Export Data -->
<!-- Export Data -->
<section class="bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg p-6">
<div class="flex items-start gap-3">
<.icon
@ -539,8 +539,8 @@ defmodule ToweropsWeb.AccountLive.MyData do
</div>
</div>
</section>
<!-- Data Processing Information -->
<!-- Data Processing Information -->
<section class="bg-white dark:bg-gray-900 shadow rounded-lg overflow-hidden">
<div class="px-4 py-5 sm:px-6 border-b border-gray-200 dark:border-gray-700">
<h2 class="text-lg font-medium text-gray-900 dark:text-white">

View file

@ -212,16 +212,16 @@ defmodule ToweropsWeb.AccountLive.TotpEnrollment do
<.icon name="hero-arrow-down-tray" class="w-5 h-5 mr-2" /> Download
</a>
</div>
<!-- Hidden textarea for copy functionality -->
<!-- Hidden textarea for copy functionality -->
<textarea
id="recovery-codes-text"
class="sr-only"
readonly
>{Enum.join(@recovery_codes, "\n")}</textarea>
</div>
<!-- Continue Button -->
<!-- Continue Button -->
<div class="flex justify-center pt-4">
<button
type="button"
@ -280,8 +280,8 @@ defmodule ToweropsWeb.AccountLive.TotpEnrollment do
</li>
</ul>
</div>
<!-- Step 2: Scan QR Code -->
<!-- Step 2: Scan QR Code -->
<div class="border-t border-gray-200 dark:border-gray-700 pt-6">
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center">
<span class="flex items-center justify-center w-8 h-8 bg-blue-600 text-white rounded-full mr-3 text-sm">
@ -306,8 +306,8 @@ defmodule ToweropsWeb.AccountLive.TotpEnrollment do
</div>
<% end %>
</div>
<!-- Step 3: Enter Code -->
<!-- Step 3: Enter Code -->
<div class="border-t border-gray-200 dark:border-gray-700 pt-6">
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center">
<span class="flex items-center justify-center w-8 h-8 bg-blue-600 text-white rounded-full mr-3 text-sm">

View file

@ -7,8 +7,7 @@
<.header>
<div class="flex items-center gap-3">
<span class="relative flex h-3 w-3">
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75">
</span>
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
<span class="relative inline-flex rounded-full h-3 w-3 bg-green-500"></span>
</span>
{t("Activity Feed")}
@ -125,8 +124,7 @@
</span>
<span class="text-xs text-gray-400 dark:text-gray-500 flex items-center gap-1">
<span class="relative flex h-2 w-2">
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75">
</span>
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
<span class="relative inline-flex rounded-full h-2 w-2 bg-green-500"></span>
</span>
{t("Live")}

View file

@ -89,8 +89,8 @@ defmodule ToweropsWeb.Admin.AuditLive.Index do
View and search all system audit logs. Records are retained for 3 years.
</p>
</div>
<!-- Search Filters -->
<!-- Search Filters -->
<div class="mt-8 bg-white dark:bg-gray-900 shadow rounded-lg p-6">
<form id="audit-search-form" phx-change="search" phx-submit="search" class="space-y-4">
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
@ -181,8 +181,8 @@ defmodule ToweropsWeb.Admin.AuditLive.Index do
</div>
</form>
</div>
<!-- Results -->
<!-- Results -->
<div class="mt-8">
<%= if Enum.empty?(@audit_logs) do %>
<div class="text-center py-12 bg-white dark:bg-gray-900 rounded-lg shadow">
@ -279,8 +279,8 @@ defmodule ToweropsWeb.Admin.AuditLive.Index do
</tbody>
</table>
</div>
<!-- Pagination -->
<!-- Pagination -->
<div class="bg-gray-50 dark:bg-gray-800 px-6 py-4 flex items-center justify-between border-t border-gray-200 dark:border-gray-700">
<div class="text-sm text-gray-700 dark:text-gray-300">
Page {@page} Showing {length(@audit_logs)} records

View file

@ -8,8 +8,8 @@
{t("Real-time monitoring of polling and discovery jobs")}
</p>
</div>
<!-- Health Metrics Cards -->
<!-- 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>
@ -47,8 +47,8 @@
<p class="text-sm text-gray-500 dark:text-gray-500 mt-1">executing now</p>
</div>
</div>
<!-- Active Operations -->
<!-- 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)})
@ -85,8 +85,8 @@
</div>
<% end %>
</div>
<!-- Problems -->
<!-- Problems -->
<%= if length(@stuck_jobs) > 0 or length(@failed_jobs) > 0 do %>
<div class="bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-4">
<h2 class="text-lg font-semibold text-red-900 dark:text-red-100 mb-4">
@ -158,14 +158,14 @@
<% end %>
</div>
<% end %>
<!-- Health Metrics -->
<!-- Health Metrics -->
<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">
{t("Health Metrics")}
</h2>
<!-- Current Activity -->
<!-- Current Activity -->
<div class="mb-6">
<h3 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-3">
{t("Current Activity")}
@ -197,8 +197,8 @@
</div>
</div>
</div>
<!-- Success Rates -->
<!-- Success Rates -->
<div class="mb-6">
<h3 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-3">
{t("Success Rates")}
@ -237,8 +237,8 @@
</div>
</div>
</div>
<!-- Performance -->
<!-- Performance -->
<div class="mb-6">
<h3 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-3">
{t("Performance")}
@ -262,8 +262,8 @@
</div>
</dl>
</div>
<!-- Queue Depths -->
<!-- Queue Depths -->
<div>
<h3 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-3">
{t("Queue Depths")}
@ -290,8 +290,8 @@
</p>
</div>
</div>
<!-- Recent Activity -->
<!-- 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">
{t("Recent Activity")}

View file

@ -4,8 +4,8 @@
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">{t("All Organizations")}</h1>
<p class="text-gray-600 dark:text-gray-400">{t_admin("Manage organizations")}</p>
</div>
<!-- Global Billing Defaults Card -->
<!-- Global Billing Defaults Card -->
<div
class="rounded-lg border border-slate-200 bg-white p-6 dark:border-slate-700 dark:bg-slate-800"
data-test="global-defaults-card"

View file

@ -6,8 +6,8 @@
{t("Manage IP allowlist and view denied IPs")}
</p>
</div>
<!-- Tabs -->
<!-- Tabs -->
<div class="border-b border-gray-200 dark:border-white/10">
<nav class="-mb-px flex space-x-8">
<button
@ -43,8 +43,8 @@
</button>
</nav>
</div>
<!-- Whitelist Tab -->
<!-- Whitelist Tab -->
<%= if @current_tab == "whitelist" do %>
<div class="space-y-4">
<div class="flex justify-between items-center">

View file

@ -13,8 +13,8 @@
</.button>
</:actions>
</.header>
<!-- New Agent Form -->
<!-- New Agent Form -->
<div id="new-agent-form" class="hidden mt-6">
<div class="bg-white dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg p-6">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">
@ -388,8 +388,8 @@
</div>
</div>
<% end %>
<!-- Token Display Modal -->
<!-- Token Display Modal -->
<%= if @show_token_modal && @new_token do %>
<div
id="token-modal"

View file

@ -50,8 +50,8 @@
</.link>
</:actions>
</.header>
<!-- Tab Navigation (Superuser Only) -->
<!-- Tab Navigation (Superuser Only) -->
<div
:if={@current_scope.user.is_superuser}
class="mt-6 border-b border-gray-200 dark:border-white/10"
@ -89,8 +89,8 @@
</button>
</nav>
</div>
<!-- Debug Tab Content -->
<!-- Debug Tab Content -->
<div :if={@current_scope.user.is_superuser && @active_tab == "debug"} class="mt-6">
<div class={[
"rounded-md p-4 mb-4",
@ -153,11 +153,10 @@
</div>
</div>
</div>
<!-- Overview Tab Content -->
<!-- Overview Tab Content -->
<div :if={!@current_scope.user.is_superuser || @active_tab == "overview"}>
<!-- Agent Status Overview -->
<!-- Agent Status Overview -->
<div class="mt-6 grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-4">
<!-- Status Card -->
<div class="bg-white dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg p-6">
@ -175,8 +174,8 @@
<.icon name="hero-signal" class="h-8 w-8 text-gray-400 dark:text-gray-500" />
</div>
</div>
<!-- Device Count Card -->
<!-- Device Count Card -->
<div class="bg-white dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg p-6">
<div class="flex items-center justify-between">
<div>
@ -191,8 +190,8 @@
<.icon name="hero-server" class="h-8 w-8 text-gray-400 dark:text-gray-500" />
</div>
</div>
<!-- Last Seen Card -->
<!-- Last Seen Card -->
<div class="bg-white dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg p-6">
<div class="flex items-center justify-between">
<div class="min-w-0 flex-1">
@ -218,8 +217,8 @@
<.icon name="hero-clock" class="h-8 w-8 text-gray-400 dark:text-gray-500 flex-shrink-0" />
</div>
</div>
<!-- Uptime Card -->
<!-- Uptime Card -->
<div class="bg-white dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg p-6">
<div class="flex items-center justify-between">
<div>
@ -238,8 +237,8 @@
</div>
</div>
</div>
<!-- Agent Details -->
<!-- Agent Details -->
<%= if @agent_token.metadata && map_size(@agent_token.metadata) > 0 do %>
<div class="mt-6 bg-white dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg p-6">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">
@ -265,8 +264,8 @@
</dl>
</div>
<% end %>
<!-- Agent Timestamps -->
<!-- Agent Timestamps -->
<div class="mt-6 bg-white dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg p-6">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">
{t("Timestamps")}
@ -305,8 +304,8 @@
<% end %>
</dl>
</div>
<!-- Device List -->
<!-- Device List -->
<div class="mt-6 bg-white dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
<div class="p-6 border-b border-gray-200 dark:border-white/10">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">

View file

@ -402,8 +402,7 @@
</h4>
<div class="space-y-1.5">
<div class="flex items-center gap-2">
<span class="inline-block h-2 w-2 rounded-full bg-red-500 flex-shrink-0">
</span>
<span class="inline-block h-2 w-2 rounded-full bg-red-500 flex-shrink-0"></span>
<span class="text-gray-500 dark:text-gray-400 w-20 flex-shrink-0">
{t("Triggered")}
</span>
@ -416,8 +415,7 @@
</div>
<%= if alert.acknowledged_at do %>
<div class="flex items-center gap-2">
<span class="inline-block h-2 w-2 rounded-full bg-blue-500 flex-shrink-0">
</span>
<span class="inline-block h-2 w-2 rounded-full bg-blue-500 flex-shrink-0"></span>
<span class="text-gray-500 dark:text-gray-400 w-20 flex-shrink-0">
{t("Ack'd")}
</span>
@ -436,8 +434,7 @@
<% end %>
<%= if alert.resolved_at do %>
<div class="flex items-center gap-2">
<span class="inline-block h-2 w-2 rounded-full bg-green-500 flex-shrink-0">
</span>
<span class="inline-block h-2 w-2 rounded-full bg-green-500 flex-shrink-0"></span>
<span class="text-gray-500 dark:text-gray-400 w-20 flex-shrink-0">
{t("Resolved")}
</span>

View file

@ -57,8 +57,8 @@ defmodule ToweropsWeb.CheckLive.FormComponent do
disabled={@action == :edit}
/>
</div>
<!-- Check Name -->
<!-- Check Name -->
<div>
<.input
field={@form[:name]}
@ -67,8 +67,8 @@ defmodule ToweropsWeb.CheckLive.FormComponent do
placeholder="e.g., Web Server Check"
/>
</div>
<!-- Dynamic fields based on check type -->
<!-- Dynamic fields based on check type -->
<%= case @selected_type do %>
<% "http" -> %>
{render_http_fields(assigns)}
@ -83,8 +83,8 @@ defmodule ToweropsWeb.CheckLive.FormComponent do
Select a check type to configure
</div>
<% end %>
<!-- Common Settings -->
<!-- Common Settings -->
<div class="grid grid-cols-2 gap-4">
<div>
<.input

View file

@ -148,8 +148,7 @@
do: "bg-green-500",
else: "bg-gray-300 dark:bg-gray-600"
)
]}>
</span>
]}></span>
<span class="text-sm truncate flex-1">{c.name}</span>
<span class="text-[10px] text-gray-500 dark:text-gray-400 truncate">
{c.site && c.site.name}
@ -203,14 +202,11 @@
<div class="flex items-center gap-1 text-[10px] font-mono text-gray-700 dark:text-gray-300">
<span class="w-3 h-3 rounded inline-block" style="background:rgb(0,200,0)"></span>
<span>≥-50</span>
<span class="w-3 h-3 rounded inline-block ml-2" style="background:rgb(200,230,0)">
</span>
<span class="w-3 h-3 rounded inline-block ml-2" style="background:rgb(200,230,0)"></span>
<span>-65</span>
<span class="w-3 h-3 rounded inline-block ml-2" style="background:rgb(255,165,0)">
</span>
<span class="w-3 h-3 rounded inline-block ml-2" style="background:rgb(255,165,0)"></span>
<span>-75</span>
<span class="w-3 h-3 rounded inline-block ml-2" style="background:rgb(220,60,60)">
</span>
<span class="w-3 h-3 rounded inline-block ml-2" style="background:rgb(220,60,60)"></span>
<span>-85</span>
<span class="w-3 h-3 rounded inline-block ml-2" style="background:rgb(100,0,0)"></span>
<span>≤-95 dBm</span>

View file

@ -285,17 +285,13 @@
<div class="flex items-center gap-1 text-[10px] font-mono text-gray-700 dark:text-gray-300">
<span class="w-3 h-3 rounded inline-block" style="background:rgb(0,200,0)"></span>
<span>≥-50</span>
<span class="w-3 h-3 rounded inline-block ml-2" style="background:rgb(200,230,0)">
</span>
<span class="w-3 h-3 rounded inline-block ml-2" style="background:rgb(200,230,0)"></span>
<span>-65</span>
<span class="w-3 h-3 rounded inline-block ml-2" style="background:rgb(255,165,0)">
</span>
<span class="w-3 h-3 rounded inline-block ml-2" style="background:rgb(255,165,0)"></span>
<span>-75</span>
<span class="w-3 h-3 rounded inline-block ml-2" style="background:rgb(220,60,60)">
</span>
<span class="w-3 h-3 rounded inline-block ml-2" style="background:rgb(220,60,60)"></span>
<span>-85</span>
<span class="w-3 h-3 rounded inline-block ml-2" style="background:rgb(100,0,0)">
</span>
<span class="w-3 h-3 rounded inline-block ml-2" style="background:rgb(100,0,0)"></span>
<span>≤-95 dBm</span>
</div>
</div>

View file

@ -26,8 +26,7 @@
</div>
<div class="flex items-center gap-1.5 text-xs text-gray-400 dark:text-gray-500 font-mono">
<span class="relative flex h-2 w-2">
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75">
</span>
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
<span class="relative inline-flex rounded-full h-2 w-2 bg-green-500"></span>
</span>
<span>Live</span>
@ -597,8 +596,7 @@
<span class={[
"h-2 w-2 rounded-full flex-shrink-0",
site_health_dot(site.site_health)
]}>
</span>
]}></span>
{site.name}
</.link>
</td>

View file

@ -210,8 +210,8 @@
</div>
</div>
</div>
<!-- Monitoring Configuration -->
<!-- Monitoring Configuration -->
<div class="grid max-w-7xl grid-cols-1 gap-x-8 gap-y-6 px-4 py-8 sm:px-6 md:grid-cols-3 lg:px-8">
<div>
<h2 class="text-base/7 font-semibold text-gray-900 dark:text-white">
@ -319,8 +319,8 @@
</div>
</div>
</div>
<!-- SNMP Configuration -->
<!-- SNMP Configuration -->
<div class="grid max-w-7xl grid-cols-1 gap-x-8 gap-y-6 px-4 py-8 sm:px-6 md:grid-cols-3 lg:px-8">
<div>
<h2 class="text-base/7 font-semibold text-gray-900 dark:text-white">
@ -383,8 +383,8 @@
<% end %>
</div>
</div>
<!-- SNMP Fields -->
<!-- SNMP Fields -->
<div
:if={@monitoring_mode == "snmp_and_icmp"}
class="grid grid-cols-1 gap-x-6 gap-y-4 sm:max-w-xl sm:grid-cols-6"
@ -398,8 +398,8 @@
options={[{"v1", "1"}, {"v2c", "2c"}, {"v3", "3"}]}
/>
</div>
<!-- v1/v2c Community String -->
<!-- v1/v2c Community String -->
<div
:if={@form[:snmp_version].value in ["1", "2c"]}
class="col-span-full"
@ -451,8 +451,8 @@
<% end %>
<% end %>
</div>
<!-- v3 Credentials -->
<!-- v3 Credentials -->
<%= if @form[:snmp_version].value == "3" do %>
<div class="col-span-full">
<.input
@ -480,8 +480,8 @@
if Map.has_key?(@form.params, "snmpv3_security_level"),
do: @form.params["snmpv3_security_level"],
else: current_security_level %>
<!-- Auth Level Selector (ALWAYS VISIBLE) -->
<!-- Auth Level Selector (ALWAYS VISIBLE) -->
<div class="col-span-full">
<.input
field={@form[:snmpv3_security_level]}
@ -494,8 +494,8 @@
]}
/>
</div>
<!-- Auth fields (shown for authNoPriv and authPriv) -->
<!-- Auth fields (shown for authNoPriv and authPriv) -->
<%= if selected_security_level in ["authNoPriv", "authPriv"] do %>
<div class="col-span-full">
<.input
@ -523,8 +523,8 @@
/>
</div>
<% end %>
<!-- Privacy fields (shown for authPriv only) -->
<!-- Privacy fields (shown for authPriv only) -->
<%= if selected_security_level == "authPriv" do %>
<div class="col-span-full">
<.input
@ -748,8 +748,8 @@
</div>
<% end %>
</div>
<!-- Save/Cancel Footer -->
<!-- Save/Cancel Footer -->
<div class="flex items-center justify-between gap-x-6 border-t border-gray-200 px-4 py-4 sm:px-8 dark:border-white/10">
<.button navigate={~p"/devices"}>{t("Cancel")}</.button>
<.button
@ -761,8 +761,8 @@
</.button>
</div>
</.form>
<!-- Danger Zone -->
<!-- Danger Zone -->
<%= if @live_action == :edit do %>
<div class="grid max-w-7xl grid-cols-1 gap-x-8 gap-y-6 px-4 py-8 sm:px-6 md:grid-cols-3 lg:px-8 border-t border-gray-200 dark:border-white/10">
<div>

View file

@ -353,16 +353,14 @@
:if={row.stats.up > 0}
class="text-green-600 dark:text-green-400"
>
<span class="inline-block h-1.5 w-1.5 rounded-full bg-green-500">
</span>
<span class="inline-block h-1.5 w-1.5 rounded-full bg-green-500"></span>
{row.stats.up}
</span>
<span
:if={row.stats.down > 0}
class="text-red-600 dark:text-red-400 font-medium"
>
<span class="inline-block h-1.5 w-1.5 rounded-full bg-red-500">
</span>
<span class="inline-block h-1.5 w-1.5 rounded-full bg-red-500"></span>
{row.stats.down}
</span>
<%= if row.site && @site_subscribers[row.site.id] do %>
@ -663,8 +661,11 @@
</div>
<div class="hidden sm:flex sm:flex-1 sm:items-center sm:justify-between">
<p class="text-sm text-gray-700 dark:text-gray-400">
<span class="font-medium">{(@pagination.page - 1) * @pagination.per_page + 1}</span><span class="font-medium">{min(@pagination.page * @pagination.per_page, @pagination.total_count)}</span> of
<span class="font-medium">{@pagination.total_count}</span>
<span class="font-medium">{(@pagination.page - 1) * @pagination.per_page + 1}</span><span class="font-medium">{min(
@pagination.page * @pagination.per_page,
@pagination.total_count
)}</span>
of <span class="font-medium">{@pagination.total_count}</span>
</p>
<nav
class="isolate inline-flex -space-x-px rounded-md shadow-sm"

View file

@ -44,8 +44,7 @@
:down -> "bg-red-600 dark:bg-red-500"
:unknown -> "bg-gray-500 dark:bg-gray-400"
end
]}>
</span>
]}></span>
<span>
{case @device.status do
:up -> "Online"
@ -134,8 +133,8 @@
</div>
</div>
<% end %>
<!-- Tabs -->
<!-- Tabs -->
<div class="border-b border-gray-200 dark:border-white/10">
<nav class="-mb-px flex space-x-8 overflow-x-auto">
<.link

View file

@ -54,8 +54,7 @@
<%= if @is_live_mode do %>
<div class="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400 mb-4">
<span class="relative flex h-3 w-3">
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75">
</span>
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
<span class="relative inline-flex rounded-full h-3 w-3 bg-green-500"></span>
</span>
<span>Live polling (1 second interval, 5 minute window)</span>

View file

@ -513,8 +513,8 @@ defmodule ToweropsWeb.HelpLive.Index do
</p>
</div>
</div>
<!-- Step 2 -->
<!-- Step 2 -->
<div class="flex gap-4">
<div class="flex-shrink-0">
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
@ -537,8 +537,8 @@ defmodule ToweropsWeb.HelpLive.Index do
</p>
</div>
</div>
<!-- Step 3 -->
<!-- Step 3 -->
<div class="flex gap-4">
<div class="flex-shrink-0">
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
@ -741,8 +741,8 @@ defmodule ToweropsWeb.HelpLive.Index do
</p>
</div>
</div>
<!-- Step 2 -->
<!-- Step 2 -->
<div class="flex gap-4">
<div class="flex-shrink-0">
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
@ -758,8 +758,8 @@ defmodule ToweropsWeb.HelpLive.Index do
</p>
</div>
</div>
<!-- Step 3 -->
<!-- Step 3 -->
<div class="flex gap-4">
<div class="flex-shrink-0">
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
@ -779,8 +779,8 @@ defmodule ToweropsWeb.HelpLive.Index do
</p>
</div>
</div>
<!-- Step 4 -->
<!-- Step 4 -->
<div class="flex gap-4">
<div class="flex-shrink-0">
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
@ -954,8 +954,8 @@ defmodule ToweropsWeb.HelpLive.Index do
</p>
</div>
</div>
<!-- Step 2 -->
<!-- Step 2 -->
<div class="flex gap-4">
<div class="flex-shrink-0">
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
@ -1004,8 +1004,8 @@ defmodule ToweropsWeb.HelpLive.Index do
</p>
</div>
</div>
<!-- Step 3 -->
<!-- Step 3 -->
<div class="flex gap-4">
<div class="flex-shrink-0">
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
@ -1030,8 +1030,8 @@ defmodule ToweropsWeb.HelpLive.Index do
</p>
</div>
</div>
<!-- Step 4 -->
<!-- Step 4 -->
<div class="flex gap-4">
<div class="flex-shrink-0">
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">

View file

@ -41,8 +41,8 @@
</div>
</div>
</div>
<!-- Map Container -->
<!-- Map Container -->
<div
id="leaflet-map"
phx-hook="SitesMap"
@ -61,8 +61,8 @@
</div>
</div>
</div>
<!-- Stats and Site List -->
<!-- Stats and Site List -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Site Statistics -->
<div class="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-white/10 p-6">
@ -92,8 +92,8 @@
</div>
</div>
</div>
<!-- Sites with Coordinates -->
<!-- Sites with Coordinates -->
<div class="lg:col-span-2 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-white/10">
<div class="px-6 py-4 border-b border-gray-200 dark:border-white/10">
<h3 class="text-lg font-medium text-gray-900 dark:text-white">

View file

@ -15,16 +15,15 @@
<:actions>
<div class="flex items-center gap-1.5 text-xs text-gray-400 dark:text-gray-500 font-mono">
<span class="relative flex h-2 w-2">
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75">
</span>
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
<span class="relative inline-flex rounded-full h-2 w-2 bg-green-500"></span>
</span>
<span>Live</span>
</div>
</:actions>
</.header>
<!-- Tab Navigation -->
<!-- Tab Navigation -->
<div class="border-b border-gray-200 dark:border-white/10 mb-6">
<nav class="-mb-px flex space-x-8">
<.link
@ -150,8 +149,8 @@
</div>
</div>
</div>
<!-- Filter Bar -->
<!-- Filter Bar -->
<div class="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-white/10 mb-4 p-3">
<div class="flex items-center justify-between gap-4 flex-wrap">
<div class="flex items-center gap-2">
@ -256,8 +255,8 @@
</div>
</div>
</div>
<!-- Network Map Container -->
<!-- Network Map Container -->
<div class="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-white/10 overflow-hidden">
<div class="p-4 border-b border-gray-200 dark:border-white/10">
<div class="flex items-center justify-between">
@ -276,8 +275,8 @@
</div>
</div>
</div>
<!-- Cytoscape Container with Detail Panel -->
<!-- Cytoscape Container with Detail Panel -->
<div class="relative">
<div
id="cy-container"
@ -288,8 +287,8 @@
data-topology={Jason.encode!(@topology)}
>
</div>
<!-- Zoom Controls -->
<!-- Zoom Controls -->
<div class="absolute bottom-4 left-4 flex flex-col gap-1 z-10">
<button
id="cy-zoom-in"
@ -316,8 +315,8 @@
<.icon name="hero-arrows-pointing-out" class="h-4 w-4" />
</button>
</div>
<!-- Node Detail Panel (slide-out) -->
<!-- Node Detail Panel (slide-out) -->
<%= if @selected_node_detail do %>
<div
id="node-detail-panel"
@ -337,8 +336,8 @@
<.icon name="hero-x-mark" class="h-5 w-5" />
</button>
</div>
<!-- Device Info -->
<!-- Device Info -->
<div class="space-y-3">
<div>
<h4 class="text-base font-medium text-gray-900 dark:text-white">
@ -396,16 +395,15 @@
do: "bg-green-400",
else: "bg-red-400"
)
]}>
</span>
]}></span>
<span class="text-gray-700 dark:text-gray-300 capitalize">
{@selected_node_detail.status}
</span>
</div>
<% end %>
</div>
<!-- Wireless Stats (for APs, CPEs, backhaul radios) -->
<!-- Wireless Stats (for APs, CPEs, backhaul radios) -->
<%= if @selected_node_detail[:is_wireless] do %>
<div class="mt-4 pt-3 border-t border-gray-200 dark:border-white/10">
<h4 class="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-2">
@ -459,8 +457,8 @@
</div>
</div>
<% end %>
<!-- Connections -->
<!-- Connections -->
<%= if length(@selected_node_detail.connections) > 0 do %>
<div class="mt-5 pt-4 border-t border-gray-200 dark:border-white/10">
<h4 class="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-3">
@ -499,8 +497,8 @@
</div>
</div>
<% end %>
<!-- View Device Link (managed only) -->
<!-- View Device Link (managed only) -->
<%= if @selected_node_detail.type == :managed do %>
<div class="mt-4 space-y-2">
<.link
@ -527,8 +525,8 @@
</div>
<% end %>
</div>
<!-- Legend -->
<!-- Legend -->
<div class="p-4 border-t border-gray-200 dark:border-white/10 bg-gray-50 dark:bg-gray-900">
<div class="flex flex-col gap-3">
<%!-- Device roles --%>
@ -606,8 +604,8 @@
</div>
</div>
</div>
<!-- Empty State -->
<!-- Empty State -->
<%= if @topology.stats.total_devices == 0 do %>
<div class="text-center py-16">
<.icon name="hero-map" class="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500" />

View file

@ -173,8 +173,8 @@
</div>
</div>
<% end %>
<!-- Use Sites Section -->
<!-- Use Sites Section -->
<div class="grid max-w-7xl grid-cols-1 gap-x-8 gap-y-6 px-4 py-8 sm:px-6 md:grid-cols-3 lg:px-8">
<div>
<h2 class="text-base/7 font-semibold text-gray-900 dark:text-white">
@ -225,8 +225,8 @@
<% end %>
</div>
</div>
<!-- Alert Routing Section -->
<!-- Alert Routing Section -->
<div class="grid max-w-7xl grid-cols-1 gap-x-8 gap-y-6 px-4 py-8 sm:px-6 md:grid-cols-3 lg:px-8 border-t border-gray-200 dark:border-white/5">
<div>
<h2 class="text-base/7 font-semibold text-gray-900 dark:text-white">
@ -271,8 +271,8 @@
</span>
</div>
</label>
<!-- PagerDuty option -->
<!-- PagerDuty option -->
<label class={[
"relative flex cursor-pointer rounded-lg border p-4 transition-colors",
if(routing_value == "pagerduty",
@ -325,8 +325,8 @@
<% end %>
</div>
</label>
<!-- Both option -->
<!-- Both option -->
<label class={[
"relative flex cursor-pointer rounded-lg border p-4 transition-colors",
if(routing_value == "both",
@ -387,8 +387,8 @@
prompt="Select SNMP version"
options={[{"v1", "1"}, {"v2c", "2c"}, {"v3", "3"}]}
/>
<!-- v1/v2c Community String -->
<!-- v1/v2c Community String -->
<%= if @form[:snmp_version].value in ["1", "2c"] do %>
<.input
field={@form[:snmp_community]}
@ -397,8 +397,8 @@
placeholder="e.g., public"
/>
<% end %>
<!-- v3 Credentials -->
<!-- v3 Credentials -->
<%= if @form[:snmp_version].value == "3" do %>
<.input
field={@form[:snmpv3_security_level]}
@ -418,8 +418,8 @@
label={t("Username")}
placeholder="e.g., snmpuser"
/>
<!-- Auth fields (shown for authNoPriv and authPriv) -->
<!-- Auth fields (shown for authNoPriv and authPriv) -->
<%= if @form[:snmpv3_security_level].value in ["authNoPriv", "authPriv"] do %>
<.input
field={@form[:snmpv3_auth_protocol]}
@ -444,8 +444,8 @@
autocomplete="off"
/>
<% end %>
<!-- Priv fields (shown only for authPriv) -->
<!-- Priv fields (shown only for authPriv) -->
<%= if @form[:snmpv3_security_level].value == "authPriv" do %>
<.input
field={@form[:snmpv3_priv_protocol]}
@ -719,8 +719,8 @@
<% end %>
<% end %>
</div>
<!-- Save Button at Bottom (not shown on integrations tab) -->
<!-- Save Button at Bottom (not shown on integrations tab) -->
<div class="flex items-center justify-end gap-x-6 border-t border-gray-200 px-4 py-4 sm:px-6 lg:px-8 dark:border-white/10">
<.link
navigate={~p"/dashboard"}
@ -791,8 +791,8 @@
</div>
</div>
<% end %>
<!-- Pending invitations -->
<!-- Pending invitations -->
<%= if @pending_invitations != [] do %>
<div class="grid max-w-7xl grid-cols-1 gap-x-8 gap-y-6 px-4 py-8 sm:px-6 md:grid-cols-3 lg:px-8">
<div>
@ -872,8 +872,8 @@
</div>
</div>
<% end %>
<!-- Current members -->
<!-- Current members -->
<div class="grid max-w-7xl grid-cols-1 gap-x-8 gap-y-6 px-4 py-8 sm:px-6 md:grid-cols-3 lg:px-8">
<div>
<h2 class="text-base/7 font-semibold text-gray-900 dark:text-white">

View file

@ -199,8 +199,7 @@
<span class={[
"h-2 w-2 rounded-full",
schedule.current_on_call_color
]}>
</span>
]}></span>
<span class="text-sm font-medium text-gray-900 dark:text-white">
{schedule.current_on_call_name}
</span>

View file

@ -64,8 +64,8 @@
/>
</label>
</div>
<!-- Geographic Location Section -->
<!-- Geographic Location Section -->
<div class="mt-6 border-t pt-6">
<h3 class="text-base font-medium mb-4">
{t("Geographic Location")}
@ -151,8 +151,8 @@
</label>
</div>
</div>
<!-- Map Preview -->
<!-- Map Preview -->
<%= if @form[:latitude].value && @form[:longitude].value do %>
<div class="mt-4">
<span class="block text-sm font-medium text-gray-900 dark:text-white mb-2">
@ -270,8 +270,8 @@
prompt="Inherit from organization"
options={[{"v1", "1"}, {"v2c", "2c"}, {"v3", "3"}]}
/>
<!-- v1/v2c Community String -->
<!-- v1/v2c Community String -->
<%= if @form[:snmp_version].value in ["1", "2c"] do %>
<.input
field={@form[:snmp_community]}
@ -280,8 +280,8 @@
placeholder={t("Leave blank to inherit from organization")}
/>
<% end %>
<!-- v3 Credentials -->
<!-- v3 Credentials -->
<%= if @form[:snmp_version].value == "3" do %>
<.input
field={@form[:snmpv3_security_level]}
@ -301,8 +301,8 @@
label={t("Username")}
placeholder={t("Leave blank to inherit from organization")}
/>
<!-- Auth fields (shown for authNoPriv and authPriv) -->
<!-- Auth fields (shown for authNoPriv and authPriv) -->
<%= if @form[:snmpv3_security_level].value in ["authNoPriv", "authPriv"] do %>
<.input
field={@form[:snmpv3_auth_protocol]}
@ -327,8 +327,8 @@
autocomplete="off"
/>
<% end %>
<!-- Priv fields (shown only for authPriv) -->
<!-- Priv fields (shown only for authPriv) -->
<%= if @form[:snmpv3_security_level].value == "authPriv" do %>
<.input
field={@form[:snmpv3_priv_protocol]}

View file

@ -84,8 +84,7 @@
<span class={[
"h-3 w-3 rounded-full flex-shrink-0",
health_dot(@summary_map[site.id] && @summary_map[site.id].site_health)
]}>
</span>
]}></span>
{site.name}
</.link>
<p :if={site.parent_site} class="text-xs text-gray-500 dark:text-gray-400 ml-4">

View file

@ -21,8 +21,8 @@
<% end %>
</p>
</div>
<!-- Leaflet map if coordinates exist -->
<!-- Leaflet map if coordinates exist -->
<%= if @site.latitude && @site.longitude do %>
<div
id="site-map"

View file

@ -154,8 +154,7 @@
<td class="font-mono text-sm">{device.ip_address}</td>
<td>
<span class="flex items-center gap-1.5">
<span class={"h-2 w-2 rounded-full #{device_status_dot(device.status)}"}>
</span>
<span class={"h-2 w-2 rounded-full #{device_status_dot(device.status)}"}></span>
<span class={device_status_color(device.status)}>
{device.status || "unknown"}
</span>
@ -181,8 +180,7 @@
:for={alert <- @trace.alerts}
class="flex items-start gap-3 p-2 rounded-lg hover:bg-gray-100/50 dark:hover:bg-gray-800/50 dark:hover:bg-white/5"
>
<span class={"mt-1.5 h-2 w-2 rounded-full flex-shrink-0 #{alert_dot(alert)}"}>
</span>
<span class={"mt-1.5 h-2 w-2 rounded-full flex-shrink-0 #{alert_dot(alert)}"}></span>
<div class="flex-1 min-w-0">
<div class="flex items-center gap-2">
<span class="text-sm font-medium text-gray-900 dark:text-white">
@ -326,8 +324,7 @@
<span class={[
"inline-block h-2.5 w-2.5 rounded-full",
device_status_dot(@trace.device.status)
]}>
</span>
]}></span>
{String.capitalize(to_string(@trace.device.status))}
</span>
</div>
@ -542,8 +539,7 @@
<span class={[
"inline-block h-2.5 w-2.5 rounded-full flex-shrink-0",
alert_dot(alert)
]}>
</span>
]}></span>
<div class="flex-1 min-w-0">
<span class="text-sm font-medium text-gray-900 dark:text-white">
{format_alert_type(alert.alert_type)}
@ -626,8 +622,7 @@
<span class={[
"mt-0.5 inline-block h-2.5 w-2.5 rounded-full flex-shrink-0",
urgency_dot(insight.urgency)
]}>
</span>
]}></span>
<div class="min-w-0">
<div class="text-sm font-medium text-gray-900 dark:text-white">
{insight.title}

View file

@ -457,8 +457,8 @@
</div>
</div>
<% end %>
<!-- Account Tab -->
<!-- Account Tab -->
<%= if @active_tab == "account" do %>
<!-- Email Address Section -->
<div class="grid max-w-7xl grid-cols-1 gap-x-8 gap-y-10 px-4 py-16 sm:px-6 md:grid-cols-3 lg:px-8">
@ -509,8 +509,8 @@
</div>
</.form>
</div>
<!-- Password Section -->
<!-- Password Section -->
<div class="grid max-w-7xl grid-cols-1 gap-x-8 gap-y-10 px-4 py-16 sm:px-6 md:grid-cols-3 lg:px-8">
<div>
<h2 class="text-base/7 font-semibold text-gray-900 dark:text-white">
@ -603,8 +603,8 @@
</div>
</.form>
</div>
<!-- Delete Account Danger Zone -->
<!-- Delete Account Danger Zone -->
<div class="grid max-w-7xl grid-cols-1 gap-x-8 gap-y-10 px-4 py-16 sm:px-6 md:grid-cols-3 lg:px-8 border-t border-red-200 dark:border-red-900/50">
<div>
<h2 class="text-base/7 font-semibold text-red-600 dark:text-red-400">
@ -648,8 +648,8 @@
</div>
</div>
<% end %>
<!-- API Tab -->
<!-- API Tab -->
<%= if @active_tab == "api" do %>
<!-- API Tokens Section -->
<div class="grid max-w-7xl grid-cols-1 gap-x-8 gap-y-10 px-4 py-16 sm:px-6 md:grid-cols-3 lg:px-8">
@ -742,8 +742,8 @@
</div>
</div>
<% end %>
<!-- Notifications Tab -->
<!-- Notifications Tab -->
<%= if @active_tab == "notifications" do %>
<!-- Mobile Devices Section -->
<div class="grid max-w-7xl grid-cols-1 gap-x-8 gap-y-10 px-4 py-16 sm:px-6 md:grid-cols-3 lg:px-8">
@ -843,8 +843,8 @@
</div>
</div>
<% end %>
<!-- Sessions Tab -->
<!-- Sessions Tab -->
<%= if @active_tab == "sessions" do %>
<!-- Security Alert Banner -->
<%= if @show_security_alert do %>
@ -870,8 +870,8 @@
</div>
</div>
<% end %>
<!-- Active Sessions Section -->
<!-- Active Sessions Section -->
<div class="grid max-w-7xl grid-cols-1 gap-x-8 gap-y-10 px-4 py-16 sm:px-6 md:grid-cols-3 lg:px-8">
<div>
<h2 class="text-base/7 font-semibold text-gray-900 dark:text-white">
@ -971,8 +971,8 @@
<% end %>
</div>
</div>
<!-- Login History Section -->
<!-- Login History Section -->
<div class="max-w-7xl px-4 py-16 sm:px-6 lg:px-8 border-t border-gray-200 dark:border-white/10">
<div class="sm:flex sm:items-center">
<div class="sm:flex-auto">
@ -1097,8 +1097,8 @@
{t("Next")}
</.link>
</div>
<!-- Desktop: Full pagination with page numbers -->
<!-- Desktop: Full pagination with page numbers -->
<div class="hidden sm:flex sm:flex-1 sm:items-center sm:justify-between">
<div>
<p class="text-sm text-gray-700 dark:text-gray-400">
@ -1178,8 +1178,8 @@
</div>
</div>
<% end %>
<!-- Security Tab -->
<!-- Security Tab -->
<%= if @active_tab == "security" do %>
<!-- Authenticator Apps Section -->
<div class="grid max-w-7xl grid-cols-1 gap-x-8 gap-y-10 px-4 py-16 sm:px-6 md:grid-cols-3 lg:px-8">
@ -1279,8 +1279,8 @@
<% end %>
</div>
</div>
<!-- Recovery Codes Section -->
<!-- Recovery Codes Section -->
<div class="grid max-w-7xl grid-cols-1 gap-x-8 gap-y-10 px-4 py-16 sm:px-6 md:grid-cols-3 lg:px-8 border-t border-gray-200 dark:border-white/10">
<div>
<h2 class="text-base/7 font-semibold text-gray-900 dark:text-white">
@ -1353,8 +1353,8 @@
</div>
<% end %>
</div>
<!-- Revoke All Sessions Confirmation Modal -->
<!-- Revoke All Sessions Confirmation Modal -->
<%= if @show_revoke_all_modal do %>
<div
class="fixed inset-0 z-50 overflow-y-auto"
@ -1420,8 +1420,8 @@
</div>
</div>
<% end %>
<!-- API Token Creation Modal -->
<!-- API Token Creation Modal -->
<%= if @show_add_token_modal do %>
<div
class="fixed inset-0 z-50 overflow-y-auto"
@ -1519,8 +1519,8 @@
</div>
</div>
<% end %>
<!-- Token Created Success Modal -->
<!-- Token Created Success Modal -->
<%= if @show_token_modal && @created_token do %>
<div
id="token-success-modal"
@ -1601,8 +1601,8 @@
</div>
</div>
<% end %>
<!-- Add TOTP Device Modal -->
<!-- Add TOTP Device Modal -->
<%= if @show_add_device_modal do %>
<div
class="fixed inset-0 z-50 overflow-y-auto"
@ -1678,8 +1678,8 @@
</div>
</div>
<% end %>
<!-- Device QR Code Modal -->
<!-- Device QR Code Modal -->
<%= if @show_device_qr_modal && @new_device_qr_code do %>
<div
class="fixed inset-0 z-50 overflow-y-auto"
@ -1743,15 +1743,15 @@
</div>
</div>
</div>
<!-- QR Code -->
<!-- QR Code -->
<div class="mt-6 flex justify-center">
<div class="inline-block rounded-lg bg-white p-4">
<img src={@new_device_qr_code} alt="TOTP QR Code" class="h-48 w-48" />
</div>
</div>
<!-- Verification Code Input -->
<!-- Verification Code Input -->
<div class="mt-6">
<p class="mb-2 text-sm font-medium text-gray-900 dark:text-white">
{t("Enter the 6-digit code from your app to verify")}
@ -1794,8 +1794,8 @@
</div>
</div>
<% end %>
<!-- Recovery Codes Display Modal -->
<!-- Recovery Codes Display Modal -->
<%= if @show_recovery_codes_modal && @generated_recovery_codes do %>
<div
class="fixed inset-0 z-50 overflow-y-auto"
@ -1833,8 +1833,8 @@
{t("Save these codes in a secure location. Each code can only be used once.")}
</p>
</div>
<!-- Recovery Codes Grid -->
<!-- Recovery Codes Grid -->
<div class="mt-6">
<div class="rounded-lg bg-gray-50 p-6 dark:bg-gray-900/50">
<div class="grid grid-cols-2 gap-3 sm:grid-cols-3">
@ -1846,8 +1846,8 @@
</div>
</div>
</div>
<!-- Copy to Clipboard -->
<!-- Copy to Clipboard -->
<div class="mt-4 flex justify-center gap-3">
<button
type="button"
@ -1860,15 +1860,15 @@
<.icon name="hero-clipboard" class="-ml-0.5 h-5 w-5" /> Copy All
</button>
</div>
<!-- Hidden textarea for copy functionality -->
<!-- Hidden textarea for copy functionality -->
<textarea
id="recovery-codes-text"
class="sr-only"
readonly
>{Enum.join(@generated_recovery_codes, "\n")}</textarea>
<!-- Warning -->
<!-- Warning -->
<div class="mt-6 rounded-lg bg-amber-50 p-4 dark:bg-amber-900/20">
<div class="flex">
<div class="flex-shrink-0">
@ -1906,8 +1906,8 @@
</div>
</div>
<% end %>
<!-- Delete Account Confirmation Modal -->
<!-- Delete Account Confirmation Modal -->
<%= if @show_delete_modal do %>
<div
class="fixed inset-0 z-50 overflow-y-auto"

View file

@ -22,8 +22,7 @@
<div class="flex items-center gap-3">
<div class="flex items-center gap-1.5 text-xs text-gray-400 dark:text-gray-500 font-mono">
<span class="relative flex h-2 w-2">
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75">
</span>
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
<span class="relative inline-flex rounded-full h-2 w-2 bg-green-500"></span>
</span>
<span>60s refresh</span>
@ -52,8 +51,7 @@
<div class="flex items-center gap-3">
<div class="flex items-center gap-1.5 text-xs text-gray-400 dark:text-gray-500 font-mono">
<span class="relative flex h-2 w-2">
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75">
</span>
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
<span class="relative inline-flex rounded-full h-2 w-2 bg-green-500"></span>
</span>
<span>60s refresh</span>
@ -68,8 +66,8 @@
</div>
</div>
<% end %>
<!-- Tab Navigation -->
<!-- Tab Navigation -->
<div class="border-b border-gray-200 dark:border-white/10 px-4 bg-white dark:bg-gray-900">
<nav class="-mb-px flex space-x-8">
<.link
@ -235,8 +233,8 @@
</div>
</div>
</div>
<!-- Filter Bar -->
<!-- Filter Bar -->
<div class="bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-white/10 p-3">
<div class="flex items-center justify-between gap-4 flex-wrap">
<div class="flex items-center gap-2">
@ -342,8 +340,8 @@
</div>
</div>
</div>
<!-- Network Weathermap Container -->
<!-- Network Weathermap Container -->
<div class="flex-1 bg-white dark:bg-gray-800 relative overflow-hidden">
<div class="absolute inset-0 border-t border-gray-200 dark:border-white/10">
<div
@ -354,8 +352,8 @@
data-topology={Jason.encode!(@topology)}
>
</div>
<!-- Zoom Controls -->
<!-- Zoom Controls -->
<div class="absolute bottom-4 left-4 flex flex-col gap-1 z-10">
<button
id="cy-zoom-in"
@ -382,8 +380,8 @@
<.icon name="hero-arrows-pointing-out" class="h-4 w-4" />
</button>
</div>
<!-- Utilization Legend -->
<!-- Utilization Legend -->
<div class="absolute bottom-4 right-4 bg-white dark:bg-gray-800 border border-gray-200 dark:border-white/10 rounded-lg shadow-lg p-4 z-10">
<h4 class="text-sm font-medium text-gray-900 dark:text-white mb-3">Link Utilization</h4>
<div class="space-y-2 text-xs">
@ -412,8 +410,8 @@
Last updated: <.timestamp datetime={@topology.last_updated} timezone={@timezone} />
</div>
</div>
<!-- Node Detail Panel (slide-out) -->
<!-- Node Detail Panel (slide-out) -->
<%= if @selected_node_detail do %>
<div
id="node-detail-panel"
@ -432,8 +430,8 @@
<.icon name="hero-x-mark" class="h-5 w-5" />
</button>
</div>
<!-- Device Info -->
<!-- Device Info -->
<div class="space-y-3">
<div>
<h4 class="text-base font-medium text-gray-900 dark:text-white">
@ -491,16 +489,15 @@
do: "bg-green-400",
else: "bg-red-400"
)
]}>
</span>
]}></span>
<span class="text-gray-700 dark:text-gray-300 capitalize">
{@selected_node_detail.status}
</span>
</div>
<% end %>
</div>
<!-- Utilization Stats (for devices with bandwidth data) -->
<!-- Utilization Stats (for devices with bandwidth data) -->
<%= if @selected_node_detail[:utilization_stats] do %>
<div class="mt-4 pt-3 border-t border-gray-200 dark:border-white/10">
<h4 class="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-2">
@ -534,8 +531,8 @@
</div>
</div>
<% end %>
<!-- Connections -->
<!-- Connections -->
<%= if length(@selected_node_detail.connections) > 0 do %>
<div class="mt-5 pt-4 border-t border-gray-200 dark:border-white/10">
<h4 class="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-3">
@ -579,8 +576,8 @@
</div>
</div>
<% end %>
<!-- View Device Link (managed only) -->
<!-- View Device Link (managed only) -->
<%= if @selected_node_detail.type == :managed do %>
<div class="mt-4">
<.link
@ -597,8 +594,8 @@
<% end %>
</div>
</div>
<!-- Empty State -->
<!-- Empty State -->
<%= if @topology.stats.total_devices == 0 do %>
<div class="flex-1 flex items-center justify-center">
<div class="text-center py-16">

View file

@ -87,7 +87,7 @@ defmodule Towerops.MixProject do
{:postgrex, ">= 0.0.0"},
{:phoenix_html, "~> 4.1"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:phoenix_live_view, "~> 1.1.28"},
{:phoenix_live_view, "~> 1.2"},
{:lazy_html, ">= 0.1.0", only: :test},
{:phoenix_live_dashboard, "~> 0.8.3"},
{:esbuild, "~> 0.10", runtime: Mix.env() == :dev},

View file

@ -72,7 +72,7 @@
"phoenix_html": {:hex, :phoenix_html, "4.3.0", "d3577a5df4b6954cd7890c84d955c470b5310bb49647f0a114a6eeecc850f7ad", [:mix], [], "hexpm", "3eaa290a78bab0f075f791a46a981bbe769d94bc776869f4f3063a14f30497ad"},
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.7", "405880012cb4b706f26dd1c6349125bfc903fb9e44d1ea668adaf4e04d4884b7", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "3a8625cab39ec261d48a13b7468dc619c0ede099601b084e343968309bd4d7d7"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.6.2", "b18b0773a1ba77f28c52decbb0f10fd1ac4d3ae5b8632399bbf6986e3b665f62", [:mix], [{:file_system, "~> 0.2.10 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "d1f89c18114c50d394721365ffb428cce24f1c13de0467ffa773e2ff4a30d5b9"},
"phoenix_live_view": {:hex, :phoenix_live_view, "1.1.32", "4977ad4cfab7868f3d2ba390a2cd6c62412614d48f798e85785602281a0a3827", [:mix], [{:igniter, ">= 0.6.16 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:lazy_html, "~> 0.1.0", [hex: :lazy_html, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0 or ~> 1.8.0-rc", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c9d8e76373414259ec5699a809991d1324808bee1d297730599e273282cee34"},
"phoenix_live_view": {:hex, :phoenix_live_view, "1.2.6", "b2b50c51993b068fe2a29eda45ca4fe67bf74f146343468485686a253c65a8da", [:mix], [{:igniter, ">= 0.6.16 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:lazy_html, "~> 0.1.0", [hex: :lazy_html, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0 or ~> 1.8.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5dc549a78dab94e80a340c760090e9e7bab16ac47841e34f4fff5819e02cbf35"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.2.0", "ff3a5616e1bed6804de7773b92cbccfc0b0f473faf1f63d7daf1206c7aeaaa6f", [:mix], [], "hexpm", "adc313a5bf7136039f63cfd9668fde73bba0765e0614cba80c06ac9460ff3e96"},
"phoenix_pubsub_redis": {:hex, :phoenix_pubsub_redis, "3.1.1", "54919406b0b6401e0f643e26fd3b814bc3460f3fd3a32aa9c3a473db89e9dca7", [:mix], [{:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5.1 or ~> 1.6", [hex: :poolboy, repo: "hexpm", optional: false]}, {:redix, "~> 1.0", [hex: :redix, repo: "hexpm", optional: false]}], "hexpm", "e339963f649e7cf52bd352e55fab7bebb42b65b501e43499dd6eb56890703c32"},
"phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},