more dark mode

This commit is contained in:
Graham McIntire 2026-01-20 17:23:11 -06:00
parent fbad8c64b2
commit c54b5d81bb
No known key found for this signature in database
27 changed files with 673 additions and 1742 deletions

View file

@ -124,7 +124,7 @@ defmodule ToweropsWeb.CoreComponents do
"primary" => "bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500 dark:bg-blue-500 dark:hover:bg-blue-600",
"danger" => "bg-red-600 text-white hover:bg-red-700 focus:ring-red-500 dark:bg-red-500 dark:hover:bg-red-600",
nil =>
"bg-white text-zinc-900 ring-1 ring-inset ring-zinc-300 hover:bg-zinc-50 focus:ring-blue-500 dark:bg-zinc-800 dark:text-zinc-100 dark:ring-zinc-700 dark:hover:bg-zinc-700"
"bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:ring-blue-500 dark:bg-gray-800 dark:text-white dark:ring-gray-700 dark:hover:bg-gray-700"
}
assigns =
@ -254,11 +254,11 @@ defmodule ToweropsWeb.CoreComponents do
checked={@checked}
class={
@class ||
"h-4 w-4 rounded border-zinc-300 text-blue-600 focus:ring-blue-500 dark:border-zinc-600 dark:bg-zinc-800"
"h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-800"
}
{@rest}
/>
<span class="text-sm font-medium text-zinc-900 dark:text-zinc-100">{@label}</span>
<span class="text-sm font-medium text-gray-900 dark:text-white">{@label}</span>
</label>
<.error :for={msg <- @errors}>{msg}</.error>
</div>
@ -313,7 +313,7 @@ defmodule ToweropsWeb.CoreComponents do
~H"""
<div class="mb-4">
<label>
<span :if={@label} class="block text-sm font-medium text-zinc-900 dark:text-zinc-100 mb-2">
<span :if={@label} class="block text-sm font-medium text-gray-900 dark:text-white mb-2">
{@label}
</span>
<textarea
@ -321,9 +321,9 @@ defmodule ToweropsWeb.CoreComponents do
name={@name}
class={[
@class ||
"block w-full rounded-lg border-0 py-2 px-3 text-zinc-900 shadow-sm ring-1 ring-inset focus:ring-2 focus:ring-inset sm:text-sm sm:leading-6 dark:bg-zinc-800 dark:text-zinc-100",
"block w-full rounded-lg border-0 py-2 px-3 text-gray-900 shadow-sm ring-1 ring-inset focus:ring-2 focus:ring-inset sm:text-sm sm:leading-6 dark:bg-gray-800 dark:text-white",
@errors == [] &&
"ring-zinc-300 focus:ring-blue-600 dark:ring-zinc-700 dark:focus:ring-blue-500",
"ring-gray-300 focus:ring-blue-600 dark:ring-gray-700 dark:focus:ring-blue-500",
@errors != [] &&
(@error_class ||
"ring-red-300 focus:ring-red-500 dark:ring-red-700 dark:focus:ring-red-500")
@ -341,7 +341,7 @@ defmodule ToweropsWeb.CoreComponents do
~H"""
<div class="mb-4">
<label>
<span :if={@label} class="block text-sm font-medium text-zinc-900 dark:text-zinc-100 mb-2">
<span :if={@label} class="block text-sm font-medium text-gray-900 dark:text-white mb-2">
{@label}
</span>
<input
@ -351,9 +351,9 @@ defmodule ToweropsWeb.CoreComponents do
value={Phoenix.HTML.Form.normalize_value(@type, @value)}
class={[
@class ||
"block w-full rounded-lg border-0 py-2 px-3 text-zinc-900 shadow-sm ring-1 ring-inset focus:ring-2 focus:ring-inset sm:text-sm sm:leading-6 dark:bg-zinc-800 dark:text-zinc-100",
"block w-full rounded-lg border-0 py-2 px-3 text-gray-900 shadow-sm ring-1 ring-inset focus:ring-2 focus:ring-inset sm:text-sm sm:leading-6 dark:bg-gray-800 dark:text-white",
@errors == [] &&
"ring-zinc-300 focus:ring-blue-600 dark:ring-zinc-700 dark:focus:ring-blue-500",
"ring-gray-300 focus:ring-blue-600 dark:ring-gray-700 dark:focus:ring-blue-500",
@errors != [] &&
(@error_class ||
"ring-red-300 focus:ring-red-500 dark:ring-red-700 dark:focus:ring-red-500")
@ -387,10 +387,10 @@ defmodule ToweropsWeb.CoreComponents do
~H"""
<header class={[@actions != [] && "flex items-center justify-between gap-6", "mb-8"]}>
<div>
<h1 class="text-3xl font-bold text-zinc-900 dark:text-zinc-100">
<h1 class="text-3xl font-bold text-gray-900 dark:text-white">
{render_slot(@inner_block)}
</h1>
<p :if={@subtitle != []} class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
<p :if={@subtitle != []} class="mt-2 text-sm text-gray-600 dark:text-gray-400">
{render_slot(@subtitle)}
</p>
</div>
@ -497,10 +497,10 @@ defmodule ToweropsWeb.CoreComponents do
def list(assigns) do
~H"""
<div class="overflow-hidden bg-white shadow rounded-lg divide-y divide-zinc-200 dark:bg-zinc-900 dark:divide-zinc-800">
<div class="overflow-hidden bg-white shadow rounded-lg divide-y divide-gray-200 dark:bg-gray-800/50 dark:divide-white/10">
<div :for={item <- @item} class="px-6 py-4">
<dt class="text-sm font-medium text-zinc-900 dark:text-zinc-100">{item.title}</dt>
<dd class="mt-1 text-sm text-zinc-700 dark:text-zinc-300">{render_slot(item)}</dd>
<dt class="text-sm font-medium text-gray-900 dark:text-white">{item.title}</dt>
<dd class="mt-1 text-sm text-gray-700 dark:text-gray-300">{render_slot(item)}</dd>
</div>
</div>
"""

View file

@ -37,19 +37,19 @@ defmodule ToweropsWeb.Layouts do
def app(assigns) do
~H"""
<div class="flex min-h-screen flex-col bg-zinc-50 dark:bg-zinc-950">
<header class="border-b border-zinc-200 bg-white dark:border-zinc-800 dark:bg-zinc-900">
<div class="flex min-h-screen flex-col bg-gray-50 dark:bg-gray-950">
<header class="border-b border-gray-200 bg-white dark:border-white/10 dark:bg-gray-900">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<nav class="flex h-16 items-center justify-between">
<div class="flex items-center">
<.link navigate={~p"/"} class="text-xl font-bold text-zinc-900 dark:text-zinc-100">
<.link navigate={~p"/"} class="text-xl font-bold text-gray-900 dark:text-white">
Towerops
</.link>
</div>
<div class="flex items-center gap-x-4">
<.link
navigate={~p"/users/log-in"}
class="text-sm font-medium text-zinc-700 hover:text-zinc-900 dark:text-zinc-300 dark:hover:text-zinc-100"
class="text-sm font-medium text-gray-700 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white"
>
Log in
</.link>
@ -109,7 +109,7 @@ defmodule ToweropsWeb.Layouts do
def authenticated(assigns) do
~H"""
<div class="flex min-h-screen flex-col bg-zinc-50 dark:bg-zinc-950">
<div class="flex min-h-screen flex-col bg-gray-50 dark:bg-gray-950">
<!-- Impersonation Banner -->
<%= if @current_scope && @current_scope.impersonating? do %>
<div class="bg-yellow-400 border-b-2 border-yellow-600">
@ -133,12 +133,12 @@ defmodule ToweropsWeb.Layouts do
</div>
<% end %>
<nav class="border-b border-zinc-200 bg-white dark:border-zinc-800 dark:bg-zinc-900">
<nav class="border-b border-gray-200 bg-white dark:border-white/10 dark:bg-gray-900">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="flex h-16 justify-between">
<div class="flex">
<div class="flex flex-shrink-0 items-center">
<.link navigate={~p"/orgs"} class="text-xl font-bold text-zinc-900 dark:text-zinc-100">
<.link navigate={~p"/orgs"} class="text-xl font-bold text-gray-900 dark:text-white">
Towerops
</.link>
</div>
@ -275,9 +275,9 @@ defmodule ToweropsWeb.Layouts do
class={[
"inline-flex items-center border-b-2 px-1 pt-1 text-sm font-medium",
if(@active,
do: "border-zinc-900 text-zinc-900 dark:border-zinc-100 dark:text-zinc-100",
do: "border-gray-900 text-gray-900 dark:border-white dark:text-white",
else:
"border-transparent text-zinc-700 hover:border-zinc-300 hover:text-zinc-900 dark:text-zinc-300 dark:hover:border-zinc-700 dark:hover:text-zinc-100"
"border-transparent text-gray-700 hover:border-gray-300 hover:text-gray-900 dark:text-gray-300 dark:hover:border-gray-600 dark:hover:text-white"
)
]}
>
@ -341,7 +341,7 @@ defmodule ToweropsWeb.Layouts do
type="button"
id="theme-menu-button"
phx-click={JS.toggle(to: "#theme-menu")}
class="flex items-center justify-center p-2 rounded-md text-zinc-500 hover:text-zinc-700 hover:bg-zinc-100 dark:text-zinc-400 dark:hover:text-zinc-200 dark:hover:bg-zinc-800"
class="flex items-center justify-center 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"
aria-label="Toggle theme"
>
<.icon name="hero-sun" class="size-5 block dark:hidden" />
@ -350,13 +350,13 @@ defmodule ToweropsWeb.Layouts do
<div
id="theme-menu"
class="hidden absolute top-full right-0 mt-2 w-36 origin-top-right rounded-md bg-white shadow-lg ring-1 ring-black/5 z-50 dark:bg-zinc-800 dark:ring-white/10"
class="hidden absolute top-full right-0 mt-2 w-36 origin-top-right rounded-md bg-white shadow-lg ring-1 ring-black/5 z-50 dark:bg-gray-800 dark:ring-white/10"
phx-click-away={JS.hide(to: "#theme-menu")}
>
<div class="py-1">
<button
type="button"
class="flex w-full items-center gap-2 px-4 py-2 text-sm text-zinc-700 hover:bg-zinc-100 dark:text-zinc-300 dark:hover:bg-zinc-700"
class="flex w-full items-center gap-2 px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700"
phx-click={JS.dispatch("phx:set-theme") |> JS.hide(to: "#theme-menu")}
data-phx-theme="system"
>
@ -364,7 +364,7 @@ defmodule ToweropsWeb.Layouts do
</button>
<button
type="button"
class="flex w-full items-center gap-2 px-4 py-2 text-sm text-zinc-700 hover:bg-zinc-100 dark:text-zinc-300 dark:hover:bg-zinc-700"
class="flex w-full items-center gap-2 px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700"
phx-click={JS.dispatch("phx:set-theme") |> JS.hide(to: "#theme-menu")}
data-phx-theme="light"
>
@ -372,7 +372,7 @@ defmodule ToweropsWeb.Layouts do
</button>
<button
type="button"
class="flex w-full items-center gap-2 px-4 py-2 text-sm text-zinc-700 hover:bg-zinc-100 dark:text-zinc-300 dark:hover:bg-zinc-700"
class="flex w-full items-center gap-2 px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700"
phx-click={JS.dispatch("phx:set-theme") |> JS.hide(to: "#theme-menu")}
data-phx-theme="dark"
>
@ -404,27 +404,27 @@ defmodule ToweropsWeb.Layouts do
def admin(assigns) do
~H"""
<div class="flex min-h-screen flex-col bg-zinc-50 dark:bg-zinc-950">
<nav class="bg-white border-b border-zinc-200 dark:border-zinc-800 dark:bg-zinc-900">
<div class="flex min-h-screen flex-col bg-gray-50 dark:bg-gray-950">
<nav class="bg-white border-b border-gray-200 dark:border-white/10 dark:bg-gray-900">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex">
<.link
navigate={~p"/admin"}
class="flex items-center text-xl font-bold text-zinc-900 dark:text-zinc-100"
class="flex items-center text-xl font-bold text-gray-900 dark:text-white"
>
Towerops Admin
</.link>
<div class="hidden sm:ml-6 sm:flex sm:space-x-8">
<.link
navigate={~p"/admin/users"}
class="inline-flex items-center px-1 pt-1 text-sm font-medium text-zinc-700 hover:text-zinc-900 dark:text-zinc-300 dark:hover:text-zinc-100"
class="inline-flex items-center px-1 pt-1 text-sm font-medium text-gray-700 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white"
>
Users
</.link>
<.link
navigate={~p"/admin/organizations"}
class="inline-flex items-center px-1 pt-1 text-sm font-medium text-zinc-700 hover:text-zinc-900 dark:text-zinc-300 dark:hover:text-zinc-100"
class="inline-flex items-center px-1 pt-1 text-sm font-medium text-gray-700 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white"
>
Organizations
</.link>
@ -434,7 +434,7 @@ defmodule ToweropsWeb.Layouts do
<.theme_toggle />
<.link
navigate={~p"/orgs"}
class="text-sm text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100"
class="text-sm text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
Back to App
</.link>
@ -474,9 +474,9 @@ defmodule ToweropsWeb.Layouts do
|> assign(:formatted_time, TimeHelpers.format_iso8601(build_time, timezone))
~H"""
<footer class="border-t border-zinc-200 bg-white dark:border-zinc-800 dark:bg-zinc-900">
<footer class="border-t border-gray-200 bg-white dark:border-white/10 dark:bg-gray-900">
<div class="mx-auto max-w-7xl px-4 py-6 sm:px-6 lg:px-8">
<div class="flex flex-col items-center gap-2 text-sm text-zinc-600 dark:text-zinc-400">
<div class="flex flex-col items-center gap-2 text-sm text-gray-600 dark:text-gray-400">
<p>Copyright © {Date.utc_today().year} Towerops</p>
<p class="text-xs">
Last deploy <span title={@formatted_time}>{@time_ago}</span> · {@formatted_time}

View file

@ -18,7 +18,7 @@
<li>
<a
href="#introduction"
class="block py-1 pl-4 pr-3 text-sm text-zinc-600 transition hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white"
class="block py-1 pl-4 pr-3 text-sm text-gray-600 transition hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
Introduction
</a>
@ -26,7 +26,7 @@
<li>
<a
href="#authentication"
class="block py-1 pl-4 pr-3 text-sm text-zinc-600 transition hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white"
class="block py-1 pl-4 pr-3 text-sm text-gray-600 transition hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
Authentication
</a>
@ -34,7 +34,7 @@
<li>
<a
href="#errors"
class="block py-1 pl-4 pr-3 text-sm text-zinc-600 transition hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white"
class="block py-1 pl-4 pr-3 text-sm text-gray-600 transition hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
Errors
</a>
@ -57,7 +57,7 @@
<li>
<a
href="#devices"
class="block py-1 pl-4 pr-3 text-sm text-zinc-600 transition hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white"
class="block py-1 pl-4 pr-3 text-sm text-gray-600 transition hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
Devices
</a>
@ -78,7 +78,7 @@
<h1 class="text-4xl font-bold tracking-tight text-zinc-900 dark:text-white sm:text-5xl">
Towerops API Reference
</h1>
<p class="mt-4 text-lg text-zinc-600 dark:text-zinc-400">
<p class="mt-4 text-lg text-gray-600 dark:text-gray-400">
Use the Towerops API to manage your network monitoring infrastructure programmatically. Create and monitor sites, devices, and alerts.
</p>
</section>
@ -88,16 +88,16 @@
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
Authentication
</h2>
<p class="mt-4 text-base text-zinc-600 dark:text-zinc-400">
<p class="mt-4 text-base text-gray-600 dark:text-gray-400">
All API requests require authentication using an API token. Include your token in the Authorization header:
</p>
<div class="mt-6 overflow-hidden rounded-lg bg-zinc-900 dark:bg-zinc-950">
<div class="mt-6 overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<pre class="p-4 text-sm text-zinc-100 overflow-x-auto"><code><%= raw("""
curl https://towerops.net/api/v1/sites \\
-H "Authorization: Bearer #{@sample_token}"
""") %></code></pre>
</div>
<p class="mt-4 text-base text-zinc-600 dark:text-zinc-400">
<p class="mt-4 text-base text-gray-600 dark:text-gray-400">
API tokens are created and managed in your organization settings. Each token is scoped to a single organization.
</p>
</section>
@ -107,11 +107,11 @@ curl https://towerops.net/api/v1/sites \\
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
Errors
</h2>
<p class="mt-4 text-base text-zinc-600 dark:text-zinc-400">
<p class="mt-4 text-base text-gray-600 dark:text-gray-400">
The API uses conventional HTTP response codes to indicate success or failure:
</p>
<div class="mt-6">
<table class="min-w-full divide-y divide-zinc-200 dark:divide-zinc-800">
<table class="min-w-full divide-y divide-gray-200 dark:divide-white/10">
<thead>
<tr>
<th class="py-3 text-left text-sm font-semibold text-zinc-900 dark:text-white">
@ -122,44 +122,44 @@ curl https://towerops.net/api/v1/sites \\
</th>
</tr>
</thead>
<tbody class="divide-y divide-zinc-200 dark:divide-zinc-800">
<tbody class="divide-y divide-gray-200 dark:divide-white/10">
<tr>
<td class="py-3 text-sm font-mono text-emerald-600 dark:text-emerald-400">200</td>
<td class="py-3 text-sm text-zinc-600 dark:text-zinc-400">Success</td>
<td class="py-3 text-sm text-gray-600 dark:text-gray-400">Success</td>
</tr>
<tr>
<td class="py-3 text-sm font-mono text-emerald-600 dark:text-emerald-400">201</td>
<td class="py-3 text-sm text-zinc-600 dark:text-zinc-400">
<td class="py-3 text-sm text-gray-600 dark:text-gray-400">
Created successfully
</td>
</tr>
<tr>
<td class="py-3 text-sm font-mono text-red-600 dark:text-red-400">400</td>
<td class="py-3 text-sm text-zinc-600 dark:text-zinc-400">
<td class="py-3 text-sm text-gray-600 dark:text-gray-400">
Bad request - missing or invalid parameters
</td>
</tr>
<tr>
<td class="py-3 text-sm font-mono text-red-600 dark:text-red-400">401</td>
<td class="py-3 text-sm text-zinc-600 dark:text-zinc-400">
<td class="py-3 text-sm text-gray-600 dark:text-gray-400">
Unauthorized - invalid or missing API token
</td>
</tr>
<tr>
<td class="py-3 text-sm font-mono text-red-600 dark:text-red-400">403</td>
<td class="py-3 text-sm text-zinc-600 dark:text-zinc-400">
<td class="py-3 text-sm text-gray-600 dark:text-gray-400">
Forbidden - you don't have access to this resource
</td>
</tr>
<tr>
<td class="py-3 text-sm font-mono text-red-600 dark:text-red-400">404</td>
<td class="py-3 text-sm text-zinc-600 dark:text-zinc-400">
<td class="py-3 text-sm text-gray-600 dark:text-gray-400">
Not found - resource doesn't exist
</td>
</tr>
<tr>
<td class="py-3 text-sm font-mono text-red-600 dark:text-red-400">422</td>
<td class="py-3 text-sm text-zinc-600 dark:text-zinc-400">
<td class="py-3 text-sm text-gray-600 dark:text-gray-400">
Unprocessable entity - validation errors
</td>
</tr>
@ -168,14 +168,14 @@ curl https://towerops.net/api/v1/sites \\
</div>
</section>
<hr class="my-16 border-zinc-200 dark:border-zinc-800" />
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- 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
</h2>
<p class="mt-4 text-base text-zinc-600 dark:text-zinc-400">
<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>
@ -183,59 +183,59 @@ curl https://towerops.net/api/v1/sites \\
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">The site model</h3>
<div class="mt-6">
<dl class="divide-y divide-zinc-200 dark:divide-zinc-800">
<dl class="divide-y divide-gray-200 dark:divide-white/10">
<div class="py-4">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
id
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
string
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Unique identifier for the site (UUID).
</dd>
</div>
<div class="py-4">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
name
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
string
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
The name of the site.
</dd>
</div>
<div class="py-4">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
location
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
string
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Physical location or address of the site.
</dd>
</div>
<div class="py-4">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
snmp_community
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
string
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Default SNMP community string for devices at this site (optional).
</dd>
</div>
<div class="py-4">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
inserted_at
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
timestamp
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Timestamp when the site was created.
</dd>
</div>
@ -243,7 +243,7 @@ curl https://towerops.net/api/v1/sites \\
</div>
</div>
<hr class="my-12 border-zinc-200 dark:border-zinc-800" />
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- List all sites -->
<div class="mt-12">
@ -252,20 +252,20 @@ curl https://towerops.net/api/v1/sites \\
<span class="inline-flex items-center rounded-md bg-emerald-50 px-2 py-1 text-xs font-medium text-emerald-700 ring-1 ring-inset ring-emerald-600/20 dark:bg-emerald-400/10 dark:text-emerald-400 dark:ring-emerald-400/30">
GET
</span>
<span class="text-sm font-mono text-zinc-600 dark:text-zinc-400">/api/v1/sites</span>
<span class="text-sm font-mono text-gray-600 dark:text-gray-400">/api/v1/sites</span>
</div>
<div class="mt-6 grid grid-cols-1 gap-x-12 gap-y-8 lg:grid-cols-2">
<!-- Left column - description -->
<div>
<p class="text-sm text-zinc-600 dark:text-zinc-400">
<p class="text-sm text-gray-600 dark:text-gray-400">
Lists all sites for the authenticated organization.
</p>
</div>
<!-- Right column - code example -->
<div>
<div class="overflow-hidden rounded-lg bg-zinc-900 dark:bg-zinc-950">
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
<p class="text-xs font-medium text-zinc-400">Request</p>
</div>
@ -275,7 +275,7 @@ curl -G https://towerops.net/api/v1/sites \\
""") %></code></pre>
</div>
<div class="mt-4 overflow-hidden rounded-lg bg-zinc-900 dark:bg-zinc-950">
<div class="mt-4 overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
<p class="text-xs font-medium text-zinc-400">Response</p>
</div>
@ -297,7 +297,7 @@ curl -G https://towerops.net/api/v1/sites \\
</div>
</div>
<hr class="my-12 border-zinc-200 dark:border-zinc-800" />
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Create a site -->
<div class="mt-12">
@ -306,39 +306,39 @@ curl -G https://towerops.net/api/v1/sites \\
<span class="inline-flex items-center rounded-md bg-blue-50 px-2 py-1 text-xs font-medium text-blue-700 ring-1 ring-inset ring-blue-600/20 dark:bg-blue-400/10 dark:text-blue-400 dark:ring-blue-400/30">
POST
</span>
<span class="text-sm font-mono text-zinc-600 dark:text-zinc-400">/api/v1/sites</span>
<span class="text-sm font-mono text-gray-600 dark:text-gray-400">/api/v1/sites</span>
</div>
<div class="mt-6 grid grid-cols-1 gap-x-12 gap-y-8 lg:grid-cols-2">
<!-- Left column -->
<div>
<p class="text-sm text-zinc-600 dark:text-zinc-400">
<p class="text-sm text-gray-600 dark:text-gray-400">
Creates a new site for the authenticated organization.
</p>
<h4 class="mt-6 text-sm font-semibold text-zinc-900 dark:text-white">
Required parameters
</h4>
<dl class="mt-3 divide-y divide-zinc-200 dark:divide-zinc-800">
<dl class="mt-3 divide-y divide-gray-200 dark:divide-white/10">
<div class="py-3">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
name
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
string
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
The name of the site.
</dd>
</div>
<div class="py-3">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
location
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
string
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Physical location of the site.
</dd>
</div>
@ -347,15 +347,15 @@ curl -G https://towerops.net/api/v1/sites \\
<h4 class="mt-6 text-sm font-semibold text-zinc-900 dark:text-white">
Optional parameters
</h4>
<dl class="mt-3 divide-y divide-zinc-200 dark:divide-zinc-800">
<dl class="mt-3 divide-y divide-gray-200 dark:divide-white/10">
<div class="py-3">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
snmp_community
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
string
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Default SNMP community string for devices at this site.
</dd>
</div>
@ -364,7 +364,7 @@ curl -G https://towerops.net/api/v1/sites \\
<!-- Right column -->
<div>
<div class="overflow-hidden rounded-lg bg-zinc-900 dark:bg-zinc-950">
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
<p class="text-xs font-medium text-zinc-400">Request</p>
</div>
@ -382,7 +382,7 @@ curl https://towerops.net/api/v1/sites \
""") %></code></pre>
</div>
<div class="mt-4 overflow-hidden rounded-lg bg-zinc-900 dark:bg-zinc-950">
<div class="mt-4 overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
<p class="text-xs font-medium text-zinc-400">Response</p>
</div>
@ -400,7 +400,7 @@ curl https://towerops.net/api/v1/sites \
</div>
</div>
<hr class="my-12 border-zinc-200 dark:border-zinc-800" />
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Get a site -->
<div class="mt-12">
@ -409,20 +409,20 @@ curl https://towerops.net/api/v1/sites \
<span class="inline-flex items-center rounded-md bg-emerald-50 px-2 py-1 text-xs font-medium text-emerald-700 ring-1 ring-inset ring-emerald-600/20 dark:bg-emerald-400/10 dark:text-emerald-400 dark:ring-emerald-400/30">
GET
</span>
<span class="text-sm font-mono text-zinc-600 dark:text-zinc-400">
<span class="text-sm font-mono text-gray-600 dark:text-gray-400">
/api/v1/sites/:id
</span>
</div>
<div class="mt-6 grid grid-cols-1 gap-x-12 gap-y-8 lg:grid-cols-2">
<div>
<p class="text-sm text-zinc-600 dark:text-zinc-400">
<p class="text-sm text-gray-600 dark:text-gray-400">
Retrieves a single site by ID.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-zinc-900 dark:bg-zinc-950">
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
<p class="text-xs font-medium text-zinc-400">Request</p>
</div>
@ -432,7 +432,7 @@ curl https://towerops.net/api/v1/sites/550e8400-e29b-41d4-a716-446655440000 \
""") %></code></pre>
</div>
<div class="mt-4 overflow-hidden rounded-lg bg-zinc-900 dark:bg-zinc-950">
<div class="mt-4 overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
<p class="text-xs font-medium text-zinc-400">Response</p>
</div>
@ -450,7 +450,7 @@ curl https://towerops.net/api/v1/sites/550e8400-e29b-41d4-a716-446655440000 \
</div>
</div>
<hr class="my-12 border-zinc-200 dark:border-zinc-800" />
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Update a site -->
<div class="mt-12">
@ -459,20 +459,20 @@ curl https://towerops.net/api/v1/sites/550e8400-e29b-41d4-a716-446655440000 \
<span class="inline-flex items-center rounded-md bg-amber-50 px-2 py-1 text-xs font-medium text-amber-700 ring-1 ring-inset ring-amber-600/20 dark:bg-amber-400/10 dark:text-amber-400 dark:ring-amber-400/30">
PATCH
</span>
<span class="text-sm font-mono text-zinc-600 dark:text-zinc-400">
<span class="text-sm font-mono text-gray-600 dark:text-gray-400">
/api/v1/sites/:id
</span>
</div>
<div class="mt-6 grid grid-cols-1 gap-x-12 gap-y-8 lg:grid-cols-2">
<div>
<p class="text-sm text-zinc-600 dark:text-zinc-400">
<p class="text-sm text-gray-600 dark:text-gray-400">
Updates an existing site. Only provided fields will be updated.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-zinc-900 dark:bg-zinc-950">
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
<p class="text-xs font-medium text-zinc-400">Request</p>
</div>
@ -488,7 +488,7 @@ curl -X PATCH https://towerops.net/api/v1/sites/550e8400-e29b-41d4-a716-44665544
""") %></code></pre>
</div>
<div class="mt-4 overflow-hidden rounded-lg bg-zinc-900 dark:bg-zinc-950">
<div class="mt-4 overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
<p class="text-xs font-medium text-zinc-400">Response</p>
</div>
@ -506,7 +506,7 @@ curl -X PATCH https://towerops.net/api/v1/sites/550e8400-e29b-41d4-a716-44665544
</div>
</div>
<hr class="my-12 border-zinc-200 dark:border-zinc-800" />
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Delete a site -->
<div class="mt-12">
@ -515,20 +515,20 @@ curl -X PATCH https://towerops.net/api/v1/sites/550e8400-e29b-41d4-a716-44665544
<span class="inline-flex items-center rounded-md bg-red-50 px-2 py-1 text-xs font-medium text-red-700 ring-1 ring-inset ring-red-600/20 dark:bg-red-400/10 dark:text-red-400 dark:ring-red-400/30">
DELETE
</span>
<span class="text-sm font-mono text-zinc-600 dark:text-zinc-400">
<span class="text-sm font-mono text-gray-600 dark:text-gray-400">
/api/v1/sites/:id
</span>
</div>
<div class="mt-6 grid grid-cols-1 gap-x-12 gap-y-8 lg:grid-cols-2">
<div>
<p class="text-sm text-zinc-600 dark:text-zinc-400">
<p class="text-sm text-gray-600 dark:text-gray-400">
Deletes a site. Note: This will also delete all devices associated with the site.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-zinc-900 dark:bg-zinc-950">
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
<p class="text-xs font-medium text-zinc-400">Request</p>
</div>
@ -538,7 +538,7 @@ curl -X DELETE https://towerops.net/api/v1/sites/550e8400-e29b-41d4-a716-4466554
""") %></code></pre>
</div>
<div class="mt-4 overflow-hidden rounded-lg bg-zinc-900 dark:bg-zinc-950">
<div class="mt-4 overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
<p class="text-xs font-medium text-zinc-400">Response</p>
</div>
@ -553,14 +553,14 @@ curl -X DELETE https://towerops.net/api/v1/sites/550e8400-e29b-41d4-a716-4466554
</div>
</section>
<hr class="my-16 border-zinc-200 dark:border-zinc-800" />
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- 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
</h2>
<p class="mt-4 text-base text-zinc-600 dark:text-zinc-400">
<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>
@ -568,125 +568,125 @@ curl -X DELETE https://towerops.net/api/v1/sites/550e8400-e29b-41d4-a716-4466554
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">The device model</h3>
<div class="mt-6">
<dl class="divide-y divide-zinc-200 dark:divide-zinc-800">
<dl class="divide-y divide-gray-200 dark:divide-white/10">
<div class="py-4">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
id
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
string
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Unique identifier for the device (UUID).
</dd>
</div>
<div class="py-4">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
name
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
string
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
The name of the device.
</dd>
</div>
<div class="py-4">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
ip_address
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
string
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
IP address of the device.
</dd>
</div>
<div class="py-4">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
site_id
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
string
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
ID of the site this device belongs to.
</dd>
</div>
<div class="py-4">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
description
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
string
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Optional description of the device.
</dd>
</div>
<div class="py-4">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
monitoring_enabled
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
boolean
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Whether monitoring is enabled for this device.
</dd>
</div>
<div class="py-4">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
check_interval_seconds
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
integer
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
How often to poll this device (in seconds).
</dd>
</div>
<div class="py-4">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
snmp_enabled
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
boolean
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Whether SNMP monitoring is enabled.
</dd>
</div>
<div class="py-4">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
snmp_version
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
string
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
SNMP version to use (e.g., "2c").
</dd>
</div>
<div class="py-4">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
snmp_port
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
integer
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
SNMP port (default: 161).
</dd>
</div>
<div class="py-4">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
inserted_at
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
timestamp
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Timestamp when the device was created.
</dd>
</div>
@ -694,7 +694,7 @@ curl -X DELETE https://towerops.net/api/v1/sites/550e8400-e29b-41d4-a716-4466554
</div>
</div>
<hr class="my-12 border-zinc-200 dark:border-zinc-800" />
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- List all devices -->
<div class="mt-12">
@ -703,29 +703,29 @@ curl -X DELETE https://towerops.net/api/v1/sites/550e8400-e29b-41d4-a716-4466554
<span class="inline-flex items-center rounded-md bg-emerald-50 px-2 py-1 text-xs font-medium text-emerald-700 ring-1 ring-inset ring-emerald-600/20 dark:bg-emerald-400/10 dark:text-emerald-400 dark:ring-emerald-400/30">
GET
</span>
<span class="text-sm font-mono text-zinc-600 dark:text-zinc-400">
<span class="text-sm font-mono text-gray-600 dark:text-gray-400">
/api/v1/devices
</span>
</div>
<div class="mt-6 grid grid-cols-1 gap-x-12 gap-y-8 lg:grid-cols-2">
<div>
<p class="text-sm text-zinc-600 dark:text-zinc-400">
<p class="text-sm text-gray-600 dark:text-gray-400">
Lists all devices for the authenticated organization.
</p>
<h4 class="mt-6 text-sm font-semibold text-zinc-900 dark:text-white">
Optional parameters
</h4>
<dl class="mt-3 divide-y divide-zinc-200 dark:divide-zinc-800">
<dl class="mt-3 divide-y divide-gray-200 dark:divide-white/10">
<div class="py-3">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
site_id
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
string
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Filter devices by site ID.
</dd>
</div>
@ -733,7 +733,7 @@ curl -X DELETE https://towerops.net/api/v1/sites/550e8400-e29b-41d4-a716-4466554
</div>
<div>
<div class="overflow-hidden rounded-lg bg-zinc-900 dark:bg-zinc-950">
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
<p class="text-xs font-medium text-zinc-400">Request</p>
</div>
@ -743,7 +743,7 @@ curl -G https://towerops.net/api/v1/devices \
""") %></code></pre>
</div>
<div class="mt-4 overflow-hidden rounded-lg bg-zinc-900 dark:bg-zinc-950">
<div class="mt-4 overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
<p class="text-xs font-medium text-zinc-400">Response</p>
</div>
@ -767,7 +767,7 @@ curl -G https://towerops.net/api/v1/devices \
</div>
</div>
<hr class="my-12 border-zinc-200 dark:border-zinc-800" />
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Create a device -->
<div class="mt-12">
@ -776,51 +776,51 @@ curl -G https://towerops.net/api/v1/devices \
<span class="inline-flex items-center rounded-md bg-blue-50 px-2 py-1 text-xs font-medium text-blue-700 ring-1 ring-inset ring-blue-600/20 dark:bg-blue-400/10 dark:text-blue-400 dark:ring-blue-400/30">
POST
</span>
<span class="text-sm font-mono text-zinc-600 dark:text-zinc-400">
<span class="text-sm font-mono text-gray-600 dark:text-gray-400">
/api/v1/devices
</span>
</div>
<div class="mt-6 grid grid-cols-1 gap-x-12 gap-y-8 lg:grid-cols-2">
<div>
<p class="text-sm text-zinc-600 dark:text-zinc-400">
<p class="text-sm text-gray-600 dark:text-gray-400">
Creates a new device.
</p>
<h4 class="mt-6 text-sm font-semibold text-zinc-900 dark:text-white">
Required parameters
</h4>
<dl class="mt-3 divide-y divide-zinc-200 dark:divide-zinc-800">
<dl class="mt-3 divide-y divide-gray-200 dark:divide-white/10">
<div class="py-3">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
site_id
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
string
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
ID of the site this device belongs to.
</dd>
</div>
<div class="py-3">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
name
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
string
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
The name of the device.
</dd>
</div>
<div class="py-3">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
ip_address
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
string
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
IP address of the device.
</dd>
</div>
@ -829,70 +829,70 @@ curl -G https://towerops.net/api/v1/devices \
<h4 class="mt-6 text-sm font-semibold text-zinc-900 dark:text-white">
Optional parameters
</h4>
<dl class="mt-3 divide-y divide-zinc-200 dark:divide-zinc-800">
<dl class="mt-3 divide-y divide-gray-200 dark:divide-white/10">
<div class="py-3">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
description
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
string
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Description of the device.
</dd>
</div>
<div class="py-3">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
monitoring_enabled
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
boolean
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Enable monitoring (default: true).
</dd>
</div>
<div class="py-3">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
snmp_enabled
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
boolean
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Enable SNMP monitoring (default: true).
</dd>
</div>
<div class="py-3">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
snmp_version
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
string
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
SNMP version (default: "2c").
</dd>
</div>
<div class="py-3">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
snmp_community
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
string
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
SNMP community string (inherits from site/org if not set).
</dd>
</div>
<div class="py-3">
<dt class="text-sm font-mono font-medium text-zinc-900 dark:text-white">
snmp_port
<span class="ml-2 font-sans text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 font-sans text-xs font-normal text-gray-500 dark:text-gray-400">
integer
</span>
</dt>
<dd class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<dd class="mt-1 text-sm text-gray-600 dark:text-gray-400">
SNMP port (default: 161).
</dd>
</div>
@ -900,7 +900,7 @@ curl -G https://towerops.net/api/v1/devices \
</div>
<div>
<div class="overflow-hidden rounded-lg bg-zinc-900 dark:bg-zinc-950">
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
<p class="text-xs font-medium text-zinc-400">Request</p>
</div>
@ -920,7 +920,7 @@ curl https://towerops.net/api/v1/devices \
""") %></code></pre>
</div>
<div class="mt-4 overflow-hidden rounded-lg bg-zinc-900 dark:bg-zinc-950">
<div class="mt-4 overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
<p class="text-xs font-medium text-zinc-400">Response</p>
</div>
@ -940,7 +940,7 @@ curl https://towerops.net/api/v1/devices \
</div>
</div>
<hr class="my-12 border-zinc-200 dark:border-zinc-800" />
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Get a device -->
<div class="mt-12">
@ -949,20 +949,20 @@ curl https://towerops.net/api/v1/devices \
<span class="inline-flex items-center rounded-md bg-emerald-50 px-2 py-1 text-xs font-medium text-emerald-700 ring-1 ring-inset ring-emerald-600/20 dark:bg-emerald-400/10 dark:text-emerald-400 dark:ring-emerald-400/30">
GET
</span>
<span class="text-sm font-mono text-zinc-600 dark:text-zinc-400">
<span class="text-sm font-mono text-gray-600 dark:text-gray-400">
/api/v1/devices/:id
</span>
</div>
<div class="mt-6 grid grid-cols-1 gap-x-12 gap-y-8 lg:grid-cols-2">
<div>
<p class="text-sm text-zinc-600 dark:text-zinc-400">
<p class="text-sm text-gray-600 dark:text-gray-400">
Retrieves a single device by ID, including all configuration details.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-zinc-900 dark:bg-zinc-950">
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
<p class="text-xs font-medium text-zinc-400">Request</p>
</div>
@ -972,7 +972,7 @@ curl https://towerops.net/api/v1/devices/650e8400-e29b-41d4-a716-446655440001 \
""") %></code></pre>
</div>
<div class="mt-4 overflow-hidden rounded-lg bg-zinc-900 dark:bg-zinc-950">
<div class="mt-4 overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
<p class="text-xs font-medium text-zinc-400">Response</p>
</div>
@ -996,7 +996,7 @@ curl https://towerops.net/api/v1/devices/650e8400-e29b-41d4-a716-446655440001 \
</div>
</div>
<hr class="my-12 border-zinc-200 dark:border-zinc-800" />
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Update a device -->
<div class="mt-12">
@ -1005,20 +1005,20 @@ curl https://towerops.net/api/v1/devices/650e8400-e29b-41d4-a716-446655440001 \
<span class="inline-flex items-center rounded-md bg-amber-50 px-2 py-1 text-xs font-medium text-amber-700 ring-1 ring-inset ring-amber-600/20 dark:bg-amber-400/10 dark:text-amber-400 dark:ring-amber-400/30">
PATCH
</span>
<span class="text-sm font-mono text-zinc-600 dark:text-zinc-400">
<span class="text-sm font-mono text-gray-600 dark:text-gray-400">
/api/v1/devices/:id
</span>
</div>
<div class="mt-6 grid grid-cols-1 gap-x-12 gap-y-8 lg:grid-cols-2">
<div>
<p class="text-sm text-zinc-600 dark:text-zinc-400">
<p class="text-sm text-gray-600 dark:text-gray-400">
Updates an existing device. Only provided fields will be updated.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-zinc-900 dark:bg-zinc-950">
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
<p class="text-xs font-medium text-zinc-400">Request</p>
</div>
@ -1035,7 +1035,7 @@ curl -X PATCH https://towerops.net/api/v1/devices/650e8400-e29b-41d4-a716-446655
""") %></code></pre>
</div>
<div class="mt-4 overflow-hidden rounded-lg bg-zinc-900 dark:bg-zinc-950">
<div class="mt-4 overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
<p class="text-xs font-medium text-zinc-400">Response</p>
</div>
@ -1059,7 +1059,7 @@ curl -X PATCH https://towerops.net/api/v1/devices/650e8400-e29b-41d4-a716-446655
</div>
</div>
<hr class="my-12 border-zinc-200 dark:border-zinc-800" />
<hr class="my-12 border-gray-200 dark:border-white/10" />
<!-- Delete a device -->
<div class="mt-12">
@ -1068,20 +1068,20 @@ curl -X PATCH https://towerops.net/api/v1/devices/650e8400-e29b-41d4-a716-446655
<span class="inline-flex items-center rounded-md bg-red-50 px-2 py-1 text-xs font-medium text-red-700 ring-1 ring-inset ring-red-600/20 dark:bg-red-400/10 dark:text-red-400 dark:ring-red-400/30">
DELETE
</span>
<span class="text-sm font-mono text-zinc-600 dark:text-zinc-400">
<span class="text-sm font-mono text-gray-600 dark:text-gray-400">
/api/v1/devices/:id
</span>
</div>
<div class="mt-6 grid grid-cols-1 gap-x-12 gap-y-8 lg:grid-cols-2">
<div>
<p class="text-sm text-zinc-600 dark:text-zinc-400">
<p class="text-sm text-gray-600 dark:text-gray-400">
Deletes a device. Note: This will also delete all monitoring data associated with the device.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-zinc-900 dark:bg-zinc-950">
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
<p class="text-xs font-medium text-zinc-400">Request</p>
</div>
@ -1091,7 +1091,7 @@ curl -X DELETE https://towerops.net/api/v1/devices/650e8400-e29b-41d4-a716-44665
""") %></code></pre>
</div>
<div class="mt-4 overflow-hidden rounded-lg bg-zinc-900 dark:bg-zinc-950">
<div class="mt-4 overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<div class="border-b border-zinc-800 px-4 py-2">
<p class="text-xs font-medium text-zinc-400">Response</p>
</div>
@ -1107,8 +1107,8 @@ curl -X DELETE https://towerops.net/api/v1/devices/650e8400-e29b-41d4-a716-44665
</section>
<!-- Footer -->
<footer class="mt-24 border-t border-zinc-200 dark:border-zinc-800 pt-8 pb-16">
<p class="text-sm text-zinc-600 dark:text-zinc-400">
<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.
</p>
</footer>

File diff suppressed because it is too large Load diff

View file

@ -60,10 +60,10 @@
<div class="relative">
<div class="absolute inset-0 flex items-center">
<div class="w-full border-t border-zinc-300 dark:border-zinc-700"></div>
<div class="w-full border-t border-gray-300 dark:border-white/10"></div>
</div>
<div class="relative flex justify-center text-sm">
<span class="bg-zinc-50 px-2 text-zinc-600 dark:bg-zinc-950 dark:text-zinc-400">
<span class="bg-gray-50 px-2 text-gray-600 dark:bg-gray-950 dark:text-gray-400">
or use email
</span>
</div>
@ -85,10 +85,10 @@
<div class="relative">
<div class="absolute inset-0 flex items-center">
<div class="w-full border-t border-zinc-300 dark:border-zinc-700"></div>
<div class="w-full border-t border-gray-300 dark:border-white/10"></div>
</div>
<div class="relative flex justify-center text-sm">
<span class="bg-zinc-50 px-2 text-zinc-600 dark:bg-zinc-950 dark:text-zinc-400">
<span class="bg-gray-50 px-2 text-gray-600 dark:bg-gray-950 dark:text-gray-400">
or use password
</span>
</div>

View file

@ -41,38 +41,38 @@
<div class="divider" />
<div>
<h3 class="text-lg font-semibold leading-6 text-zinc-900 dark:text-zinc-100">
<h3 class="text-lg font-semibold leading-6 text-gray-900 dark:text-white">
Alert Notification Devices
</h3>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Manage mobile devices that receive push notifications for alerts
</p>
<div class="mt-6 space-y-4">
<%= if Enum.empty?(@mobile_sessions) do %>
<div class="rounded-lg border border-dashed border-zinc-300 p-8 text-center dark:border-zinc-700">
<.icon name="hero-device-phone-mobile" class="mx-auto h-12 w-12 text-zinc-400" />
<h3 class="mt-2 text-sm font-semibold text-zinc-900 dark:text-zinc-100">
<div class="rounded-lg border border-dashed border-gray-300 p-8 text-center dark:border-white/10">
<.icon name="hero-device-phone-mobile" class="mx-auto h-12 w-12 text-gray-400" />
<h3 class="mt-2 text-sm font-semibold text-gray-900 dark:text-white">
No mobile devices registered
</h3>
<p class="mt-1 text-sm text-zinc-500 dark:text-zinc-400">
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
Add a mobile device to receive push notifications for alerts
</p>
</div>
<% else %>
<div class="space-y-3">
<%= for session <- @mobile_sessions do %>
<div class="flex items-center justify-between rounded-lg border border-zinc-200 p-4 dark:border-zinc-800">
<div class="flex items-center justify-between rounded-lg border border-gray-200 p-4 dark:border-white/10">
<div class="flex items-center gap-3">
<.icon name="hero-device-phone-mobile" class="h-5 w-5 text-zinc-400" />
<.icon name="hero-device-phone-mobile" class="h-5 w-5 text-gray-400" />
<div>
<p class="font-medium text-zinc-900 dark:text-zinc-100">
<p class="font-medium text-gray-900 dark:text-white">
{session.device_name || "Unknown Device"}
</p>
<p class="text-sm text-zinc-500 dark:text-zinc-400">
<p class="text-sm text-gray-500 dark:text-gray-400">
{session.device_os} • {session.app_version}
</p>
<p class="text-sm text-zinc-500 dark:text-zinc-400">
<p class="text-sm text-gray-500 dark:text-gray-400">
Last used {Calendar.strftime(session.last_used_at, "%B %d, %Y")}
</p>
</div>
@ -100,7 +100,7 @@
do:
"bg-green-100 text-green-700 hover:bg-green-200 dark:bg-green-900/20 dark:text-green-400 dark:hover:bg-green-900/30",
else:
"bg-zinc-100 text-zinc-700 hover:bg-zinc-200 dark:bg-zinc-800 dark:text-zinc-400 dark:hover:bg-zinc-700"
"bg-gray-100 text-gray-700 hover:bg-gray-200 dark:bg-gray-800/50 dark:text-gray-400 dark:hover:bg-gray-800"
)
]}
>
@ -136,7 +136,7 @@
<.link
navigate={~p"/mobile/qr-login"}
class="inline-flex items-center gap-2 rounded-lg bg-zinc-900 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-zinc-700 dark:bg-zinc-50 dark:text-zinc-900 dark:hover:bg-zinc-300"
class="inline-flex items-center gap-2 rounded-lg bg-gray-900 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-gray-700 dark:bg-gray-50 dark:text-gray-900 dark:hover:bg-gray-300"
>
<.icon name="hero-qr-code" class="h-4 w-4" /> Add Mobile Device
</.link>
@ -146,10 +146,10 @@
<div class="divider" />
<div>
<h3 class="text-lg font-semibold leading-6 text-zinc-900 dark:text-zinc-100">
<h3 class="text-lg font-semibold leading-6 text-gray-900 dark:text-white">
Passkeys
</h3>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Use your device's biometrics (Face ID, Touch ID, Windows Hello) or security keys to sign in
</p>
@ -163,31 +163,31 @@
<div class="mt-6 space-y-4">
<%= if Enum.empty?(@credentials) do %>
<div class="rounded-lg border border-dashed border-zinc-300 p-8 text-center dark:border-zinc-700">
<.icon name="hero-key" class="mx-auto h-12 w-12 text-zinc-400" />
<h3 class="mt-2 text-sm font-semibold text-zinc-900 dark:text-zinc-100">
<div class="rounded-lg border border-dashed border-gray-300 p-8 text-center dark:border-white/10">
<.icon name="hero-key" class="mx-auto h-12 w-12 text-gray-400" />
<h3 class="mt-2 text-sm font-semibold text-gray-900 dark:text-white">
No passkeys registered
</h3>
<p class="mt-1 text-sm text-zinc-500 dark:text-zinc-400">
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
Add a passkey to enable quick, secure sign-in with biometrics
</p>
</div>
<% else %>
<div class="space-y-3">
<%= for credential <- @credentials do %>
<div class="flex items-center justify-between rounded-lg border border-zinc-200 p-4 dark:border-zinc-800">
<div class="flex items-center justify-between rounded-lg border border-gray-200 p-4 dark:border-white/10">
<div class="flex items-center gap-3">
<.icon name="hero-key" class="h-5 w-5 text-zinc-400" />
<.icon name="hero-key" class="h-5 w-5 text-gray-400" />
<div>
<p class="font-medium text-zinc-900 dark:text-zinc-100">
<p class="font-medium text-gray-900 dark:text-white">
{credential.name}
</p>
<%= if credential.last_used_at do %>
<p class="text-sm text-zinc-500 dark:text-zinc-400">
<p class="text-sm text-gray-500 dark:text-gray-400">
Last used {Calendar.strftime(credential.last_used_at, "%B %d, %Y")}
</p>
<% else %>
<p class="text-sm text-zinc-500 dark:text-zinc-400">Never used</p>
<p class="text-sm text-gray-500 dark:text-gray-400">Never used</p>
<% end %>
</div>
</div>
@ -208,7 +208,7 @@
<button
type="button"
id="add-passkey-btn"
class="inline-flex items-center gap-2 rounded-lg bg-zinc-900 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-zinc-700 dark:bg-zinc-50 dark:text-zinc-900 dark:hover:bg-zinc-300"
class="inline-flex items-center gap-2 rounded-lg bg-gray-900 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-gray-700 dark:bg-gray-50 dark:text-gray-900 dark:hover:bg-gray-300"
>
<.icon name="hero-plus" class="h-4 w-4" /> Add Passkey
</button>
@ -224,7 +224,7 @@
<div class="flex min-h-screen items-end justify-center px-4 pb-20 pt-4 text-center sm:block sm:p-0">
<!-- Background overlay -->
<div
class="fixed inset-0 z-0 bg-zinc-500 bg-opacity-75 transition-opacity dark:bg-zinc-950 dark:bg-opacity-75"
class="fixed inset-0 z-0 bg-gray-500 bg-opacity-75 transition-opacity dark:bg-gray-950 dark:bg-opacity-75"
aria-hidden="true"
>
</div>
@ -237,20 +237,20 @@
&#8203;
</span>
<div class="relative z-10 inline-block transform overflow-hidden rounded-lg bg-white px-4 pb-4 pt-5 text-left align-bottom shadow-xl transition-all dark:bg-zinc-900 sm:my-8 sm:w-full sm:max-w-lg sm:p-6 sm:align-middle">
<div class="relative z-10 inline-block transform overflow-hidden rounded-lg bg-white px-4 pb-4 pt-5 text-left align-bottom shadow-xl transition-all dark:bg-gray-800/95 sm:my-8 sm:w-full sm:max-w-lg sm:p-6 sm:align-middle">
<div>
<div class="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-blue-100 dark:bg-blue-900">
<.icon name="hero-key" class="h-6 w-6 text-blue-600 dark:text-blue-400" />
</div>
<div class="mt-3 text-center sm:mt-5">
<h3
class="text-lg font-semibold leading-6 text-zinc-900 dark:text-zinc-100"
class="text-lg font-semibold leading-6 text-gray-900 dark:text-white"
id="modal-title"
>
Add Passkey
</h3>
<div class="mt-2">
<p class="text-sm text-zinc-500 dark:text-zinc-400">
<p class="text-sm text-gray-500 dark:text-gray-400">
Give this passkey a name to help you identify it later (e.g., "MacBook Touch ID", "iPhone").
</p>
</div>
@ -259,7 +259,7 @@
type="text"
id="passkey-name-input"
placeholder="e.g., MacBook Touch ID"
class="block w-full rounded-lg border-zinc-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-100 sm:text-sm"
class="block w-full rounded-lg border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-white/10 dark:bg-gray-800/50 dark:text-white sm:text-sm"
/>
</div>
<div
@ -281,7 +281,7 @@
<button
type="button"
id="cancel-add-passkey"
class="mt-3 inline-flex w-full justify-center rounded-lg bg-white px-3 py-2 text-sm font-semibold text-zinc-900 shadow-sm ring-1 ring-inset ring-zinc-300 hover:bg-zinc-50 dark:bg-zinc-800 dark:text-zinc-100 dark:ring-zinc-700 dark:hover:bg-zinc-700 sm:col-start-1 sm:mt-0"
class="mt-3 inline-flex w-full justify-center rounded-lg bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 dark:bg-gray-800/50 dark:text-white dark:ring-white/10 dark:hover:bg-gray-800 sm:col-start-1 sm:mt-0"
>
Cancel
</button>

View file

@ -1,31 +1,37 @@
<Layouts.admin flash={@flash} timezone={@timezone}>
<div class="space-y-6">
<div>
<h1 class="text-2xl font-bold text-zinc-900">Admin Dashboard</h1>
<p class="text-zinc-600">System overview and recent activity</p>
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">Admin Dashboard</h1>
<p class="text-gray-600 dark:text-gray-400">System overview and recent activity</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="bg-white rounded-lg border border-zinc-200 p-6">
<h2 class="text-lg font-semibold text-zinc-900 mb-2">Users</h2>
<p class="text-3xl font-bold text-zinc-900">{@user_count}</p>
<.link navigate={~p"/admin/users"} class="text-blue-600 hover:underline text-sm">
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10 p-6">
<h2 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">Users</h2>
<p class="text-3xl font-bold text-gray-900 dark:text-white">{@user_count}</p>
<.link
navigate={~p"/admin/users"}
class="text-blue-600 dark:text-blue-400 hover:underline text-sm"
>
View all users →
</.link>
</div>
<div class="bg-white rounded-lg border border-zinc-200 p-6">
<h2 class="text-lg font-semibold text-zinc-900 mb-2">Organizations</h2>
<p class="text-3xl font-bold text-zinc-900">{@org_count}</p>
<.link navigate={~p"/admin/organizations"} class="text-blue-600 hover:underline text-sm">
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10 p-6">
<h2 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">Organizations</h2>
<p class="text-3xl font-bold text-gray-900 dark:text-white">{@org_count}</p>
<.link
navigate={~p"/admin/organizations"}
class="text-blue-600 dark:text-blue-400 hover:underline text-sm"
>
View all organizations →
</.link>
</div>
</div>
<div class="bg-white rounded-lg border border-zinc-200">
<div class="px-4 py-3 border-b border-zinc-200">
<h2 class="text-lg font-semibold text-zinc-900">Recent Audit Logs</h2>
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10">
<div class="px-4 py-3 border-b border-gray-200 dark:border-white/10">
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">Recent Audit Logs</h2>
</div>
<.table id="audit-logs" rows={@recent_logs}>
<:col :let={log} label="Action">{log.action}</:col>

View file

@ -1,11 +1,11 @@
<Layouts.admin flash={@flash} timezone={@timezone}>
<div class="space-y-6">
<div>
<h1 class="text-2xl font-bold text-zinc-900">All Organizations</h1>
<p class="text-zinc-600">Manage organizations</p>
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">All Organizations</h1>
<p class="text-gray-600 dark:text-gray-400">Manage organizations</p>
</div>
<div class="bg-white rounded-lg border border-zinc-200">
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10">
<.table id="organizations" rows={@organizations}>
<:col :let={org} label="Name">{org.name}</:col>
<:col :let={org} label="Slug">{org.slug}</:col>
@ -18,7 +18,7 @@
phx-click="delete_org"
phx-value-id={org.id}
data-confirm="Are you sure? This will delete all sites, device, and data for this organization."
class="text-sm text-red-600 hover:text-red-800"
class="text-sm text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300"
>
Delete
</button>

View file

@ -1,11 +1,11 @@
<Layouts.admin flash={@flash} timezone={@timezone}>
<div class="space-y-6">
<div>
<h1 class="text-2xl font-bold text-zinc-900">All Users</h1>
<p class="text-zinc-600">Manage system users</p>
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">All Users</h1>
<p class="text-gray-600 dark:text-gray-400">Manage system users</p>
</div>
<div class="bg-white rounded-lg border border-zinc-200">
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10">
<.table id="users" rows={@users}>
<:col :let={user} label="Email">{user.email}</:col>
<:col :let={user} label="Superuser">{if user.is_superuser, do: "Yes", else: "No"}</:col>
@ -20,7 +20,7 @@
<button
type="submit"
disabled={user.is_superuser}
class="text-sm text-blue-600 hover:text-blue-800 disabled:text-zinc-400 disabled:cursor-not-allowed"
class="text-sm text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 disabled:text-gray-400 disabled:cursor-not-allowed"
>
Impersonate
</button>
@ -30,7 +30,7 @@
phx-value-id={user.id}
data-confirm="Are you sure you want to delete this user?"
disabled={user.is_superuser}
class="text-sm text-red-600 hover:text-red-800 disabled:text-zinc-400 disabled:cursor-not-allowed"
class="text-sm text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300 disabled:text-gray-400 disabled:cursor-not-allowed"
>
Delete
</button>

View file

@ -9,12 +9,12 @@
</.link>
</div>
<div class="bg-white dark:bg-zinc-900 shadow rounded-lg">
<div class="px-6 py-5 border-b border-zinc-200 dark:border-zinc-800">
<h3 class="text-lg font-medium text-zinc-900 dark:text-zinc-100">
<div class="bg-white dark:bg-gray-800/50 shadow rounded-lg">
<div class="px-6 py-5 border-b border-gray-200 dark:border-white/10">
<h3 class="text-lg font-medium text-gray-900 dark:text-white">
Edit Agent
</h3>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Update the agent name. The authentication token cannot be changed.
</p>
</div>
@ -35,7 +35,7 @@
placeholder="e.g., Datacenter Agent"
required
/>
<p class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
A descriptive name to identify this agent in your organization.
</p>
</div>
@ -44,7 +44,7 @@
<div class="mt-6 flex items-center justify-end gap-x-4">
<.link
navigate={~p"/orgs/#{@current_organization.slug}/agents/#{@agent_token.id}"}
class="text-sm font-semibold text-zinc-700 dark:text-zinc-300 hover:text-zinc-900 dark:hover:text-zinc-100"
class="text-sm font-semibold text-gray-700 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white"
>
Cancel
</.link>

View file

@ -36,7 +36,7 @@ defmodule ToweropsWeb.AgentLive.Helpers do
:online -> "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300"
:warning -> "bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300"
:offline -> "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300"
:never -> "bg-zinc-100 text-zinc-800 dark:bg-zinc-800 dark:text-zinc-300"
:never -> "bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-300"
end
end
@ -49,7 +49,7 @@ defmodule ToweropsWeb.AgentLive.Helpers do
:online -> "bg-green-600 dark:bg-green-400 animate-pulse"
:warning -> "bg-yellow-600 dark:bg-yellow-400"
:offline -> "bg-red-600 dark:bg-red-400"
:never -> "bg-zinc-400 dark:bg-zinc-600"
:never -> "bg-gray-400 dark:bg-gray-600"
end
end

View file

@ -17,8 +17,8 @@
<!-- New Agent Form -->
<div id="new-agent-form" class="hidden mt-6">
<div class="bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-lg p-6">
<h3 class="text-lg font-semibold text-zinc-900 dark:text-zinc-100 mb-4">
<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">
Create New Agent
</h3>
<.form for={@agent_form} phx-submit="create_agent">
@ -37,7 +37,7 @@
<button
type="button"
phx-click={JS.hide(to: "#new-agent-form")}
class="px-3 py-2 text-sm font-semibold text-zinc-700 dark:text-zinc-300 hover:text-zinc-900 dark:hover:text-zinc-100"
class="px-3 py-2 text-sm font-semibold text-gray-700 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white"
>
Cancel
</button>
@ -49,9 +49,9 @@
<%= if @agent_tokens == [] do %>
<div class="text-center py-16">
<.icon name="hero-server" class="mx-auto h-12 w-12 text-zinc-400 dark:text-zinc-600" />
<h3 class="mt-4 text-lg font-semibold text-zinc-900 dark:text-zinc-100">No agents</h3>
<p class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
<.icon name="hero-server" class="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500" />
<h3 class="mt-4 text-lg font-semibold text-gray-900 dark:text-white">No agents</h3>
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
Get started by creating your first remote agent.
</p>
<div class="mt-6">
@ -71,7 +71,7 @@
{agent.name}
</.link>
<%= if agent.metadata["version"] do %>
<div class="text-xs text-zinc-500 dark:text-zinc-400 mt-0.5">
<div class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
v{agent.metadata["version"]}
</div>
<% end %>
@ -87,10 +87,10 @@
<:col :let={agent} label="Device">
<% counts = Map.get(@device_counts, agent.id, %{direct: 0, total: 0}) %>
<div class="text-sm text-zinc-900 dark:text-zinc-100">
<div class="text-sm text-gray-900 dark:text-white">
{counts.total} total
</div>
<div class="text-xs text-zinc-500 dark:text-zinc-400 mt-0.5">
<div class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
{counts.direct} direct
<%= if counts.total > counts.direct do %>
· {counts.total - counts.direct} inherited
@ -99,16 +99,16 @@
</:col>
<:col :let={agent} label="Last Seen">
<div class="text-sm text-zinc-900 dark:text-zinc-100">
<div class="text-sm text-gray-900 dark:text-white">
<.timestamp datetime={agent.last_seen_at} timezone={@timezone} />
</div>
<%= if agent.last_seen_at do %>
<div class="text-xs text-zinc-500 dark:text-zinc-400 mt-0.5">
<div class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
{format_datetime(agent.last_seen_at, @timezone)}
</div>
<% end %>
<%= if agent.last_ip do %>
<div class="text-xs text-zinc-500 dark:text-zinc-400 mt-0.5 font-mono">
<div class="text-xs text-gray-500 dark:text-gray-400 mt-0.5 font-mono">
{agent.last_ip}
</div>
<% end %>
@ -116,7 +116,7 @@
<:col :let={agent} label="Metadata">
<%= if agent.metadata["hostname"] do %>
<div class="text-sm text-zinc-600 dark:text-zinc-400">
<div class="text-sm text-gray-600 dark:text-gray-400">
<.icon name="hero-computer-desktop" class="h-4 w-4 inline" />
{agent.metadata["hostname"]}
</div>
@ -124,7 +124,7 @@
</:col>
<:col :let={agent} label="Created">
<div class="text-sm text-zinc-600 dark:text-zinc-400">
<div class="text-sm text-gray-600 dark:text-gray-400">
{ToweropsWeb.TimeHelpers.format_date(agent.inserted_at, @timezone)}
</div>
</:col>
@ -151,7 +151,7 @@
</button>
</div>
<% else %>
<span class="text-xs text-zinc-500 dark:text-zinc-400">Disabled</span>
<span class="text-xs text-gray-500 dark:text-gray-400">Disabled</span>
<% end %>
</:action>
</.table>
@ -167,26 +167,26 @@
>
<div class="flex min-h-screen items-center justify-center p-4">
<div
class="fixed inset-0 bg-zinc-500/75 dark:bg-zinc-950/75 transition-opacity"
class="fixed inset-0 bg-gray-500/75 dark:bg-gray-950/75 transition-opacity"
phx-click="close_token_modal"
>
</div>
<div class="relative bg-white dark:bg-zinc-900 rounded-lg shadow-xl max-w-2xl w-full">
<div class="relative bg-white dark:bg-gray-900 rounded-lg shadow-xl max-w-2xl w-full">
<div class="p-6">
<div class="flex items-start justify-between mb-4">
<div>
<h3 class="text-lg font-semibold text-zinc-900 dark:text-zinc-100">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">
Agent Setup Instructions
</h3>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Use the token and Docker Compose configuration below to deploy this agent.
</p>
</div>
<button
type="button"
phx-click="close_token_modal"
class="text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-300"
class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
>
<.icon name="hero-x-mark" class="h-6 w-6" />
</button>
@ -194,16 +194,16 @@
<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-2">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Agent Name
</label>
<div class="text-base font-mono text-zinc-900 dark:text-zinc-100">
<div class="text-base font-mono text-gray-900 dark:text-white">
{@new_token.agent_token.name}
</div>
</div>
<div>
<label class="block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-2">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Authentication Token
</label>
<div class="relative">
@ -211,7 +211,7 @@
type="text"
readonly
value={@new_token.token}
class="w-full font-mono text-sm bg-zinc-50 dark:bg-zinc-800 border border-zinc-300 dark:border-zinc-700 rounded px-3 py-2 pr-24 text-zinc-900 dark:text-zinc-100"
class="w-full font-mono text-sm bg-gray-50 dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded px-3 py-2 pr-24 text-gray-900 dark:text-white"
id="agent-token-input"
/>
<button
@ -219,21 +219,21 @@
phx-hook="CopyToClipboard"
data-target="#agent-token-input"
id={"copy-token-#{@new_token.agent_token.id}"}
class="absolute right-2 top-1/2 -translate-y-1/2 px-3 py-1 text-xs font-medium text-zinc-700 dark:text-zinc-300 bg-zinc-100 dark:bg-zinc-800 border border-zinc-300 dark:border-zinc-700 rounded hover:bg-zinc-200 dark:hover:bg-zinc-700"
class="absolute right-2 top-1/2 -translate-y-1/2 px-3 py-1 text-xs font-medium text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded hover:bg-gray-200 dark:hover:bg-gray-700"
>
<.icon name="hero-clipboard" class="h-4 w-4" />
</button>
</div>
</div>
<div class="bg-zinc-50 dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 rounded-lg p-4">
<h4 class="text-sm font-medium text-zinc-900 dark:text-zinc-100 mb-2">
<div class="bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg p-4">
<h4 class="text-sm font-medium text-gray-900 dark:text-white mb-2">
Docker Compose Setup with Auto-Updates
</h4>
<p class="text-xs text-zinc-600 dark:text-zinc-400 mb-3">
<p class="text-xs text-gray-600 dark:text-gray-400 mb-3">
This configuration includes Watchtower for automatic agent updates. The agent will automatically update to the latest version every 15 minutes during development.
</p>
<pre class="text-xs font-mono text-zinc-600 dark:text-zinc-400 overflow-x-auto"><code>services:
<pre class="text-xs font-mono text-gray-600 dark:text-gray-400 overflow-x-auto"><code>services:
towerops-agent:
image: {@agent_image}
container_name: towerops-agent

View file

@ -62,7 +62,7 @@ defmodule ToweropsWeb.AgentLive.Show do
:direct -> "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300"
:site -> "bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300"
:organization -> "bg-amber-100 text-amber-800 dark:bg-amber-900 dark:text-amber-300"
:unknown -> "bg-zinc-100 text-zinc-800 dark:bg-zinc-800 dark:text-zinc-300"
:unknown -> "bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-300"
end
end
end

View file

@ -17,7 +17,7 @@
</.link>
<.link
navigate={~p"/orgs/#{@current_organization.slug}/agents"}
class="text-sm font-semibold text-zinc-700 dark:text-zinc-300 hover:text-zinc-900 dark:hover:text-zinc-100"
class="text-sm font-semibold text-gray-700 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white"
>
<.icon name="hero-arrow-left" class="h-5 w-5" /> Back to Agents
</.link>
@ -27,10 +27,10 @@
<!-- 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-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-lg p-6">
<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>
<p class="text-sm font-medium text-zinc-600 dark:text-zinc-400">Status</p>
<p class="text-sm font-medium text-gray-600 dark:text-gray-400">Status</p>
<% {status, label} = agent_status(@agent_token) %>
<div class="mt-2">
<span class={"inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium #{status_badge_class(status)}"}>
@ -39,104 +39,104 @@
</span>
</div>
</div>
<.icon name="hero-signal" class="h-8 w-8 text-zinc-400 dark:text-zinc-600" />
<.icon name="hero-signal" class="h-8 w-8 text-gray-400 dark:text-gray-500" />
</div>
</div>
<!-- Device Count Card -->
<div class="bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-lg p-6">
<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>
<p class="text-sm font-medium text-zinc-600 dark:text-zinc-400">Device</p>
<p class="mt-2 text-3xl font-semibold text-zinc-900 dark:text-zinc-100">
<p class="text-sm font-medium text-gray-600 dark:text-gray-400">Device</p>
<p class="mt-2 text-3xl font-semibold text-gray-900 dark:text-white">
{length(@polling_targets)}
</p>
<p class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
{@direct_assignments} direct
</p>
</div>
<.icon name="hero-server" class="h-8 w-8 text-zinc-400 dark:text-zinc-600" />
<.icon name="hero-server" class="h-8 w-8 text-gray-400 dark:text-gray-500" />
</div>
</div>
<!-- Last Seen Card -->
<div class="bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-lg p-6">
<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">
<p class="text-sm font-medium text-zinc-600 dark:text-zinc-400">Last Seen</p>
<p class="mt-2 text-lg font-semibold text-zinc-900 dark:text-zinc-100">
<p class="text-sm font-medium text-gray-600 dark:text-gray-400">Last Seen</p>
<p class="mt-2 text-lg font-semibold text-gray-900 dark:text-white">
<.timestamp
datetime={@agent_token.last_seen_at}
timezone={@timezone}
/>
</p>
<%= if @agent_token.last_seen_at do %>
<p class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
{format_datetime(@agent_token.last_seen_at, @timezone)}
</p>
<% end %>
<%= if @agent_token.last_ip do %>
<p class="mt-1 text-xs text-zinc-500 dark:text-zinc-400 font-mono">
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400 font-mono">
{@agent_token.last_ip}
</p>
<% end %>
</div>
<.icon name="hero-clock" class="h-8 w-8 text-zinc-400 dark:text-zinc-600 flex-shrink-0" />
<.icon name="hero-clock" class="h-8 w-8 text-gray-400 dark:text-gray-500 flex-shrink-0" />
</div>
</div>
<!-- Version/Uptime Card -->
<div class="bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-lg p-6">
<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>
<p class="text-sm font-medium text-zinc-600 dark:text-zinc-400">Agent Info</p>
<p class="text-sm font-medium text-gray-600 dark:text-gray-400">Agent Info</p>
<%= if @agent_token.metadata["version"] do %>
<p class="mt-2 text-lg font-semibold text-zinc-900 dark:text-zinc-100">
<p class="mt-2 text-lg font-semibold text-gray-900 dark:text-white">
v{@agent_token.metadata["version"]}
</p>
<% else %>
<p class="mt-2 text-lg font-semibold text-zinc-500 dark:text-zinc-400">
<p class="mt-2 text-lg font-semibold text-gray-500 dark:text-gray-400">
Unknown
</p>
<% end %>
<%= if @agent_token.metadata["uptime_seconds"] do %>
<p class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
Uptime: {format_uptime(@agent_token.metadata["uptime_seconds"])}
</p>
<% end %>
</div>
<.icon name="hero-information-circle" class="h-8 w-8 text-zinc-400 dark:text-zinc-600" />
<.icon name="hero-information-circle" class="h-8 w-8 text-gray-400 dark:text-gray-500" />
</div>
</div>
</div>
<!-- Agent Metadata -->
<%= if @agent_token.metadata && map_size(@agent_token.metadata) > 0 do %>
<div class="mt-6 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-lg p-6">
<h3 class="text-lg font-semibold text-zinc-900 dark:text-zinc-100 mb-4">
<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">
Agent Metadata
</h3>
<dl class="grid grid-cols-1 gap-4 sm:grid-cols-2">
<%= if @agent_token.metadata["hostname"] do %>
<div>
<dt class="text-sm font-medium text-zinc-600 dark:text-zinc-400">Hostname</dt>
<dd class="mt-1 text-sm text-zinc-900 dark:text-zinc-100 font-mono">
<dt class="text-sm font-medium text-gray-600 dark:text-gray-400">Hostname</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white font-mono">
{@agent_token.metadata["hostname"]}
</dd>
</div>
<% end %>
<%= if @agent_token.metadata["version"] do %>
<div>
<dt class="text-sm font-medium text-zinc-600 dark:text-zinc-400">Version</dt>
<dd class="mt-1 text-sm text-zinc-900 dark:text-zinc-100">
<dt class="text-sm font-medium text-gray-600 dark:text-gray-400">Version</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">
{@agent_token.metadata["version"]}
</dd>
</div>
<% end %>
<%= if @agent_token.metadata["uptime_seconds"] do %>
<div>
<dt class="text-sm font-medium text-zinc-600 dark:text-zinc-400">Uptime</dt>
<dd class="mt-1 text-sm text-zinc-900 dark:text-zinc-100">
<dt class="text-sm font-medium text-gray-600 dark:text-gray-400">Uptime</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">
{format_uptime(@agent_token.metadata["uptime_seconds"])}
</dd>
</div>
@ -146,40 +146,40 @@
<% end %>
<!-- Agent Timestamps -->
<div class="mt-6 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-lg p-6">
<h3 class="text-lg font-semibold text-zinc-900 dark:text-zinc-100 mb-4">
<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">
Timestamps
</h3>
<dl class="grid grid-cols-1 gap-4 sm:grid-cols-2">
<div>
<dt class="text-sm font-medium text-zinc-600 dark:text-zinc-400">Created</dt>
<dd class="mt-1 text-sm text-zinc-900 dark:text-zinc-100">
<dt class="text-sm font-medium text-gray-600 dark:text-gray-400">Created</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">
{format_datetime(@agent_token.inserted_at, @timezone)}
</dd>
<dd class="mt-0.5 text-xs text-zinc-500 dark:text-zinc-400">
<dd class="mt-0.5 text-xs text-gray-500 dark:text-gray-400">
<.timestamp datetime={@agent_token.inserted_at} timezone={@timezone} /> (created)
</dd>
</div>
<div>
<dt class="text-sm font-medium text-zinc-600 dark:text-zinc-400">Last Updated</dt>
<dd class="mt-1 text-sm text-zinc-900 dark:text-zinc-100">
<dt class="text-sm font-medium text-gray-600 dark:text-gray-400">Last Updated</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white">
{format_datetime(@agent_token.updated_at, @timezone)}
</dd>
<dd class="mt-0.5 text-xs text-zinc-500 dark:text-zinc-400">
<dd class="mt-0.5 text-xs text-gray-500 dark:text-gray-400">
<.timestamp datetime={@agent_token.updated_at} timezone={@timezone} />
</dd>
</div>
<div>
<dt class="text-sm font-medium text-zinc-600 dark:text-zinc-400">
<dt class="text-sm font-medium text-gray-600 dark:text-gray-400">
Last Seen (Heartbeat)
</dt>
<dd class="mt-1 text-sm text-zinc-900 dark:text-zinc-100">
<dd class="mt-1 text-sm text-gray-900 dark:text-white">
{format_datetime(@agent_token.last_seen_at, @timezone)}
</dd>
<%= if @agent_token.last_seen_at do %>
<dd class="mt-0.5 text-xs text-zinc-500 dark:text-zinc-400">
<dd class="mt-0.5 text-xs text-gray-500 dark:text-gray-400">
<.timestamp datetime={@agent_token.last_seen_at} timezone={@timezone} />
</dd>
<% end %>
@ -187,8 +187,8 @@
<%= if @agent_token.last_ip do %>
<div>
<dt class="text-sm font-medium text-zinc-600 dark:text-zinc-400">Last IP Address</dt>
<dd class="mt-1 text-sm text-zinc-900 dark:text-zinc-100 font-mono">
<dt class="text-sm font-medium text-gray-600 dark:text-gray-400">Last IP Address</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-white font-mono">
{@agent_token.last_ip}
</dd>
</div>
@ -197,38 +197,38 @@
</div>
<!-- Device List -->
<div class="mt-6 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-lg">
<div class="p-6 border-b border-zinc-200 dark:border-zinc-800">
<h3 class="text-lg font-semibold text-zinc-900 dark:text-zinc-100">
<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">
Polling Targets
</h3>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Device that this agent is responsible for polling
</p>
</div>
<%= if @polling_targets == [] do %>
<div class="p-12 text-center">
<.icon name="hero-server" class="mx-auto h-12 w-12 text-zinc-400 dark:text-zinc-600" />
<h3 class="mt-4 text-sm font-semibold text-zinc-900 dark:text-zinc-100">
<.icon name="hero-server" class="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500" />
<h3 class="mt-4 text-sm font-semibold text-gray-900 dark:text-white">
No devices assigned
</h3>
<p class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
This agent is not currently polling any device.
</p>
</div>
<% else %>
<div class="divide-y divide-zinc-200 dark:divide-zinc-800">
<div class="divide-y divide-gray-200 dark:divide-white/10">
<%= for device <- @polling_targets do %>
<.link
navigate={~p"/devices/#{device.id}"}
class="block hover:bg-zinc-50 dark:hover:bg-zinc-800 transition-colors"
class="block hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
>
<div class="p-6">
<div class="flex items-center justify-between">
<div class="flex-1 min-w-0">
<div class="flex items-center gap-3">
<p class="text-sm font-medium text-zinc-900 dark:text-zinc-100 truncate">
<p class="text-sm font-medium text-gray-900 dark:text-white truncate">
{device.name}
</p>
<% {source, source_label} = assignment_source(device, @agent_token.id) %>
@ -236,7 +236,7 @@
{source_label}
</span>
</div>
<div class="mt-1 flex items-center gap-4 text-sm text-zinc-600 dark:text-zinc-400">
<div class="mt-1 flex items-center gap-4 text-sm text-gray-600 dark:text-gray-400">
<span class="flex items-center gap-1">
<.icon name="hero-globe-alt" class="h-4 w-4" />
{device.ip_address}
@ -249,7 +249,7 @@
<% end %>
</div>
</div>
<.icon name="hero-chevron-right" class="h-5 w-5 text-zinc-400 dark:text-zinc-600" />
<.icon name="hero-chevron-right" class="h-5 w-5 text-gray-400 dark:text-gray-500" />
</div>
</div>
</.link>

View file

@ -11,7 +11,7 @@
</.header>
<div class="mb-6">
<div class="inline-flex rounded-lg border border-zinc-200 dark:border-zinc-800">
<div class="inline-flex rounded-lg border border-gray-200 dark:border-white/10">
<.link
patch={~p"/orgs/#{@current_organization.slug}/alerts"}
class={[
@ -19,7 +19,7 @@
@filter == "active" &&
"bg-blue-600 text-white dark:bg-blue-500",
@filter != "active" &&
"bg-white text-zinc-700 hover:bg-zinc-50 dark:bg-zinc-900 dark:text-zinc-300 dark:hover:bg-zinc-800"
"bg-white text-gray-700 hover:bg-gray-50 dark:bg-gray-800/50 dark:text-gray-300 dark:hover:bg-gray-800"
]}
>
Active Alerts
@ -27,11 +27,11 @@
<.link
patch={~p"/orgs/#{@current_organization.slug}/alerts?filter=all"}
class={[
"px-4 py-2 text-sm font-medium rounded-r-lg border-l border-zinc-200 dark:border-zinc-800",
"px-4 py-2 text-sm font-medium rounded-r-lg border-l border-gray-200 dark:border-white/10",
@filter == "all" &&
"bg-blue-600 text-white dark:bg-blue-500",
@filter != "all" &&
"bg-white text-zinc-700 hover:bg-zinc-50 dark:bg-zinc-900 dark:text-zinc-300 dark:hover:bg-zinc-800"
"bg-white text-gray-700 hover:bg-gray-50 dark:bg-gray-800/50 dark:text-gray-300 dark:hover:bg-gray-800"
]}
>
All Alerts
@ -41,9 +41,9 @@
<%= if Enum.empty?(@alerts) do %>
<div class="text-center py-16">
<.icon name="hero-bell-slash" class="mx-auto h-12 w-12 text-zinc-400 dark:text-zinc-600" />
<h3 class="mt-4 text-lg font-semibold text-zinc-900 dark:text-zinc-100">No alerts</h3>
<p class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
<.icon name="hero-bell-slash" class="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500" />
<h3 class="mt-4 text-lg font-semibold text-gray-900 dark:text-white">No alerts</h3>
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
<%= if @filter == "active" do %>
There are no active alerts for this organization.
<% else %>
@ -60,7 +60,7 @@
alert.alert_type == :device_down && is_nil(alert.resolved_at) &&
"border-l-4 border-red-500 bg-red-50 dark:bg-red-950 dark:border-red-700",
(alert.alert_type != :device_down || alert.resolved_at) &&
"border-zinc-200 bg-white dark:border-zinc-800 dark:bg-zinc-900"
"border-gray-200 bg-white dark:border-white/10 dark:bg-gray-800/50"
]}>
<div class="flex items-start justify-between">
<div class="flex-1">
@ -81,7 +81,7 @@
</span>
<%= if alert.resolved_at do %>
<span class="inline-flex items-center rounded-full bg-zinc-100 px-2.5 py-0.5 text-xs font-medium text-zinc-800 dark:bg-zinc-800 dark:text-zinc-200">
<span class="inline-flex items-center rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium text-gray-800 dark:bg-gray-800 dark:text-gray-200">
Resolved
</span>
<% end %>
@ -93,7 +93,7 @@
<% end %>
</div>
<h3 class="mt-3 font-semibold text-zinc-900 dark:text-zinc-100">
<h3 class="mt-3 font-semibold text-gray-900 dark:text-white">
<.link
navigate={~p"/devices/#{alert.device.id}"}
class="text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300"
@ -102,9 +102,9 @@
</.link>
</h3>
<p class="mt-1 text-sm text-zinc-700 dark:text-zinc-300">{alert.message}</p>
<p class="mt-1 text-sm text-gray-700 dark:text-gray-300">{alert.message}</p>
<div class="mt-3 space-y-1 text-xs text-zinc-600 dark:text-zinc-400">
<div class="mt-3 space-y-1 text-xs text-gray-600 dark:text-gray-400">
<div>
<strong class="font-medium">Triggered:</strong>
{ToweropsWeb.TimeHelpers.format_iso8601(alert.triggered_at, @timezone)}

View file

@ -11,15 +11,15 @@
</.header>
<%= if @sites_count == 0 do %>
<div class="mt-8 rounded-lg border-2 border-dashed border-zinc-300 bg-zinc-50 p-12 text-center dark:border-zinc-700 dark:bg-zinc-900">
<div class="mt-8 rounded-lg border-2 border-dashed border-gray-300 bg-gray-50 p-12 text-center dark:border-white/20 dark:bg-gray-800/50">
<.icon
name="hero-light-bulb"
class="mx-auto h-16 w-16 text-blue-500 dark:text-blue-400"
/>
<h3 class="mt-6 text-xl font-semibold text-zinc-900 dark:text-zinc-100">
<h3 class="mt-6 text-xl font-semibold text-gray-900 dark:text-white">
Let's get started!
</h3>
<p class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
Follow these steps to set up your network monitoring:
</p>
<div class="mt-8 max-w-2xl mx-auto">
@ -29,32 +29,32 @@
1
</div>
<div>
<h4 class="font-medium text-zinc-900 dark:text-zinc-100">Create a Site</h4>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<h4 class="font-medium text-gray-900 dark:text-white">Create a Site</h4>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Sites represent your physical locations (offices, data centers, towers, etc.)
</p>
</div>
</div>
<div class="flex gap-4 items-start">
<div class="flex-shrink-0 flex items-center justify-center w-8 h-8 rounded-full bg-zinc-200 text-zinc-600 font-semibold dark:bg-zinc-700 dark:text-zinc-400">
<div class="flex-shrink-0 flex items-center justify-center w-8 h-8 rounded-full bg-gray-200 text-gray-600 font-semibold dark:bg-gray-700 dark:text-gray-400">
2
</div>
<div>
<h4 class="font-medium text-zinc-900 dark:text-zinc-100">Add Device</h4>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<h4 class="font-medium text-gray-900 dark:text-white">Add Device</h4>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Add network devices (routers, switches, servers) to your sites
</p>
</div>
</div>
<div class="flex gap-4 items-start">
<div class="flex-shrink-0 flex items-center justify-center w-8 h-8 rounded-full bg-zinc-200 text-zinc-600 font-semibold dark:bg-zinc-700 dark:text-zinc-400">
<div class="flex-shrink-0 flex items-center justify-center w-8 h-8 rounded-full bg-gray-200 text-gray-600 font-semibold dark:bg-gray-700 dark:text-gray-400">
3
</div>
<div>
<h4 class="font-medium text-zinc-900 dark:text-zinc-100">
<h4 class="font-medium text-gray-900 dark:text-white">
Monitor & Receive Alerts
</h4>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Towerops will automatically monitor your devices and alert you of issues
</p>
</div>
@ -71,30 +71,30 @@
<div class="mt-8 grid gap-6 md:grid-cols-2 lg:grid-cols-4">
<.link
navigate={~p"/sites"}
class="rounded-lg border border-zinc-200 bg-white p-6 shadow-sm transition-shadow hover:shadow-md dark:border-zinc-800 dark:bg-zinc-900"
class="rounded-lg border border-gray-200 bg-white p-6 shadow-sm transition-shadow hover:shadow-md dark:border-white/10 dark:bg-gray-800/50"
>
<h3 class="text-sm font-medium text-zinc-500 dark:text-zinc-400">Sites</h3>
<p class="mt-2 text-3xl font-bold text-zinc-900 dark:text-zinc-100">{@sites_count}</p>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">Total sites</p>
<h3 class="text-sm font-medium text-gray-500 dark:text-gray-400">Sites</h3>
<p class="mt-2 text-3xl font-bold text-gray-900 dark:text-white">{@sites_count}</p>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">Total sites</p>
</.link>
<.link
navigate={~p"/devices"}
class="rounded-lg border border-zinc-200 bg-white p-6 shadow-sm transition-shadow hover:shadow-md dark:border-zinc-800 dark:bg-zinc-900"
class="rounded-lg border border-gray-200 bg-white p-6 shadow-sm transition-shadow hover:shadow-md dark:border-white/10 dark:bg-gray-800/50"
>
<h3 class="text-sm font-medium text-zinc-500 dark:text-zinc-400">Device</h3>
<p class="mt-2 text-3xl font-bold text-zinc-900 dark:text-zinc-100">{@device_count}</p>
<h3 class="text-sm font-medium text-gray-500 dark:text-gray-400">Device</h3>
<p class="mt-2 text-3xl font-bold text-gray-900 dark:text-white">{@device_count}</p>
<div class="mt-3 space-y-1.5 text-sm">
<div class="flex items-center gap-2 text-zinc-700 dark:text-zinc-300">
<div class="flex items-center gap-2 text-gray-700 dark:text-gray-300">
<span class="h-2 w-2 rounded-full bg-green-500"></span>
{@device_up} Up
</div>
<div class="flex items-center gap-2 text-zinc-700 dark:text-zinc-300">
<div class="flex items-center gap-2 text-gray-700 dark:text-gray-300">
<span class="h-2 w-2 rounded-full bg-red-500"></span>
{@device_down} Down
</div>
<div class="flex items-center gap-2 text-zinc-700 dark:text-zinc-300">
<span class="h-2 w-2 rounded-full bg-zinc-400"></span>
<div class="flex items-center gap-2 text-gray-700 dark:text-gray-300">
<span class="h-2 w-2 rounded-full bg-gray-400"></span>
{@device_unknown} Unknown
</div>
</div>
@ -102,21 +102,21 @@
<.link
navigate={~p"/orgs/#{@current_organization.slug}/alerts"}
class="rounded-lg border border-zinc-200 bg-white p-6 shadow-sm transition-shadow hover:shadow-md dark:border-zinc-800 dark:bg-zinc-900"
class="rounded-lg border border-gray-200 bg-white p-6 shadow-sm transition-shadow hover:shadow-md dark:border-white/10 dark:bg-gray-800/50"
>
<h3 class="text-sm font-medium text-zinc-500 dark:text-zinc-400">Active Alerts</h3>
<h3 class="text-sm font-medium text-gray-500 dark:text-gray-400">Active Alerts</h3>
<p class={[
"mt-2 text-3xl font-bold",
(length(@active_alerts) > 0 && "text-red-600 dark:text-red-500") ||
"text-zinc-900 dark:text-zinc-100"
"text-gray-900 dark:text-white"
]}>
{length(@active_alerts)}
</p>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">Requires attention</p>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">Requires attention</p>
</.link>
<div class="rounded-lg border border-zinc-200 bg-white p-6 shadow-sm dark:border-zinc-800 dark:bg-zinc-900">
<h3 class="text-sm font-medium text-zinc-500 dark:text-zinc-400">System Status</h3>
<div class="rounded-lg border border-gray-200 bg-white p-6 shadow-sm dark:border-white/10 dark:bg-gray-800/50">
<h3 class="text-sm font-medium text-gray-500 dark:text-gray-400">System Status</h3>
<div class={[
"mt-3 flex items-center gap-2 text-sm font-semibold",
(@device_down == 0 && "text-green-600 dark:text-green-500") ||
@ -136,7 +136,7 @@
<%= if length(@active_alerts) > 0 do %>
<div class="mt-8">
<div class="flex items-center justify-between mb-4">
<h2 class="text-xl font-semibold text-zinc-900 dark:text-zinc-100">Active Alerts</h2>
<h2 class="text-xl font-semibold text-gray-900 dark:text-white">Active Alerts</h2>
<.link
navigate={~p"/orgs/#{@current_organization.slug}/alerts"}
class="text-sm font-medium text-blue-600 hover:text-blue-700 dark:text-blue-500 dark:hover:text-blue-400"
@ -153,7 +153,7 @@
class="h-5 w-5 flex-shrink-0 text-red-600 dark:text-red-500"
/>
<div class="flex-1 min-w-0">
<h3 class="font-semibold text-zinc-900 dark:text-zinc-100">
<h3 class="font-semibold text-gray-900 dark:text-white">
<.link
navigate={~p"/devices/#{alert.device.id}"}
class="hover:text-blue-600 hover:underline dark:hover:text-blue-400"
@ -161,16 +161,16 @@
{alert.device.name}
</.link>
</h3>
<p class="mt-0.5 text-sm text-zinc-700 dark:text-zinc-300">{alert.message}</p>
<p class="mt-0.5 text-sm text-gray-700 dark:text-gray-300">{alert.message}</p>
</div>
<span class="text-xs text-zinc-500 dark:text-zinc-400 whitespace-nowrap">
<span class="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap">
{ToweropsWeb.TimeHelpers.format_datetime(alert.triggered_at, @timezone)}
</span>
</div>
<% end %>
<%= if length(@active_alerts) > 5 do %>
<div class="text-center text-sm text-zinc-500 dark:text-zinc-400">
<div class="text-center text-sm text-gray-500 dark:text-gray-400">
+ {length(@active_alerts) - 5} more alerts
</div>
<% end %>
@ -179,7 +179,7 @@
<% end %>
<div class="mt-8">
<h2 class="text-xl font-semibold mb-4 text-zinc-900 dark:text-zinc-100">Quick Actions</h2>
<h2 class="text-xl font-semibold mb-4 text-gray-900 dark:text-white">Quick Actions</h2>
<div class="flex flex-wrap gap-4">
<.link
navigate={~p"/sites"}
@ -197,7 +197,7 @@
</.link>
<.link
navigate={~p"/orgs/#{@current_organization.slug}/alerts"}
class="inline-flex items-center gap-2 rounded-lg border border-zinc-300 bg-white px-4 py-2.5 text-sm font-semibold text-zinc-700 shadow-sm hover:bg-zinc-50 focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-200 dark:hover:bg-zinc-700"
class="inline-flex items-center gap-2 rounded-lg border border-gray-300 bg-white px-4 py-2.5 text-sm font-semibold text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2 dark:border-white/10 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700"
>
<.icon name="hero-bell" class="h-5 w-5" />
<span>View Alerts</span>

View file

@ -12,7 +12,7 @@
do: ~p"/devices/#{@device.id}",
else: ~p"/devices"
}
class="inline-flex items-center gap-1 text-sm text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100"
class="inline-flex items-center gap-1 text-sm text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
<.icon name="hero-arrow-left" class="h-4 w-4" />
{if @live_action == :edit, do: "Back to Device", else: "Back to Device List"}
@ -82,22 +82,22 @@
this device is explicitly assigned
</p>
<% :site -> %>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400 flex items-center gap-1">
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1">
<.icon name="hero-building-office" class="h-4 w-4" /> Inherited from site:
<strong>{@effective_agent_name}</strong>
</p>
<% :organization -> %>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400 flex items-center gap-1">
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1">
<.icon name="hero-building-office-2" class="h-4 w-4" />
Inherited from organization: <strong>{@effective_agent_name}</strong>
</p>
<% :none -> %>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400 flex items-center gap-1">
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1">
<.icon name="hero-cloud" class="h-4 w-4" /> No agent assigned - cloud polling
</p>
<% end %>
<% else %>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Assign this device to a remote agent for local SNMP polling. Leave empty to inherit from site or organization defaults.
</p>
<% end %>
@ -108,7 +108,7 @@
<!-- Monitoring Mode Tabs -->
<div class="mb-6">
<div class="border-b border-zinc-200 dark:border-zinc-700">
<div class="border-b border-gray-200 dark:border-white/10">
<nav class="-mb-px flex space-x-8" aria-label="Monitoring mode">
<button
type="button"
@ -119,7 +119,7 @@
@monitoring_mode == "snmp_and_icmp" &&
"border-blue-500 text-blue-600 dark:border-blue-400 dark:text-blue-400",
@monitoring_mode != "snmp_and_icmp" &&
"border-transparent text-zinc-500 hover:border-zinc-300 hover:text-zinc-700 dark:text-zinc-400 dark:hover:border-zinc-600 dark:hover:text-zinc-300"
"border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 dark:text-gray-400 dark:hover:border-gray-600 dark:hover:text-gray-300"
]}
>
SNMP & ICMP
@ -133,14 +133,14 @@
@monitoring_mode == "icmp_only" &&
"border-blue-500 text-blue-600 dark:border-blue-400 dark:text-blue-400",
@monitoring_mode != "icmp_only" &&
"border-transparent text-zinc-500 hover:border-zinc-300 hover:text-zinc-700 dark:text-zinc-400 dark:hover:border-zinc-600 dark:hover:text-zinc-300"
"border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 dark:text-gray-400 dark:hover:border-gray-600 dark:hover:text-gray-300"
]}
>
ICMP Only
</button>
</nav>
</div>
<div class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
<div class="mt-2 text-sm text-gray-600 dark:text-gray-400">
<%= if @monitoring_mode == "snmp_and_icmp" do %>
<p>
Monitor device availability with ICMP pings and collect detailed information via SNMP
@ -180,17 +180,17 @@
<strong>Overriding</strong> site/organization SNMP defaults
</p>
<% :site -> %>
<p class="text-sm text-zinc-600 dark:text-zinc-400 flex items-center gap-1">
<p class="text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1">
<.icon name="hero-building-office" class="h-4 w-4" />
Inherited from site (v{@effective_snmp_version}, community: {@effective_snmp_community})
</p>
<% :organization -> %>
<p class="text-sm text-zinc-600 dark:text-zinc-400 flex items-center gap-1">
<p class="text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1">
<.icon name="hero-building-office-2" class="h-4 w-4" />
Inherited from organization (v{@effective_snmp_version}, community: {@effective_snmp_community})
</p>
<% :default -> %>
<p class="text-sm text-zinc-600 dark:text-zinc-400 flex items-center gap-1">
<p class="text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1">
<.icon name="hero-information-circle" class="h-4 w-4" />
Using default (v2c, no community set - configure at organization or site level)
</p>
@ -246,9 +246,9 @@
</.form>
<%= if @live_action == :edit do %>
<div class="mt-12 pt-8 border-t border-zinc-200 dark:border-zinc-800">
<div class="mt-12 pt-8 border-t border-gray-200 dark:border-white/10">
<h3 class="text-lg font-semibold text-red-600 dark:text-red-500 mb-4">Danger Zone</h3>
<p class="text-sm text-zinc-600 dark:text-zinc-400 mb-4">
<p class="text-sm text-gray-600 dark:text-gray-400 mb-4">
Once you delete this device, there is no going back. All monitoring history and alerts will be permanently deleted.
</p>
<.button

View file

@ -32,15 +32,15 @@
<div class="text-center py-16">
<.icon
name="hero-building-office"
class="mx-auto h-12 w-12 text-zinc-400 dark:text-zinc-600"
class="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500"
/>
<h3 class="mt-4 text-lg font-semibold text-zinc-900 dark:text-zinc-100">
<h3 class="mt-4 text-lg font-semibold text-gray-900 dark:text-white">
Create a site first
</h3>
<p class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
Before adding device, you need to create at least one site location.
</p>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Sites help you organize your devices by physical location.
</p>
<div class="mt-6">
@ -52,9 +52,9 @@
<% else %>
<%= if @device == [] do %>
<div class="text-center py-16">
<.icon name="hero-server" class="mx-auto h-12 w-12 text-zinc-400 dark:text-zinc-600" />
<h3 class="mt-4 text-lg font-semibold text-zinc-900 dark:text-zinc-100">No devices</h3>
<p class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
<.icon name="hero-server" class="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500" />
<h3 class="mt-4 text-lg font-semibold text-gray-900 dark:text-white">No devices</h3>
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
Get started by adding your first device.
</p>
<div class="mt-6">
@ -97,13 +97,13 @@
"bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200",
eq.status == :down && "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200",
eq.status == :unknown &&
"bg-zinc-100 text-zinc-800 dark:bg-zinc-800 dark:text-zinc-200"
"bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-200"
]}>
{eq.status |> to_string() |> String.upcase()}
</span>
</:col>
<:col :let={eq} label="Last Checked">
<span class="text-sm text-zinc-600 dark:text-zinc-400">
<span class="text-sm text-gray-600 dark:text-gray-400">
{ToweropsWeb.TimeHelpers.format_datetime(eq.last_checked_at, @timezone)}
</span>
</:col>

View file

@ -8,11 +8,11 @@
<div class="mb-6">
<!-- Breadcrumbs -->
<nav class="flex mb-4" aria-label="Breadcrumb">
<ol class="inline-flex items-center space-x-1 text-sm text-zinc-600 dark:text-zinc-400">
<ol class="inline-flex items-center space-x-1 text-sm text-gray-600 dark:text-gray-400">
<li class="inline-flex items-center">
<.link
navigate={~p"/sites/#{@device.site.id}"}
class="hover:text-zinc-900 dark:hover:text-zinc-200"
class="hover:text-gray-900 dark:hover:text-white"
>
{@device.site.name}
</.link>
@ -20,7 +20,7 @@
<li aria-current="page">
<div class="flex items-center">
<.icon name="hero-chevron-right" class="h-4 w-4 mx-1" />
<span class="text-zinc-900 dark:text-zinc-100 font-medium">{@device.name}</span>
<span class="text-gray-900 dark:text-white font-medium">{@device.name}</span>
</div>
</li>
</ol>
@ -28,8 +28,8 @@
<div class="flex items-center justify-between mb-4">
<div>
<h1 class="text-2xl font-bold text-zinc-900 dark:text-zinc-100">{@device.name}</h1>
<p class="text-sm text-zinc-600 dark:text-zinc-400 font-mono">{@device.ip_address}</p>
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">{@device.name}</h1>
<p class="text-sm text-gray-600 dark:text-gray-400 font-mono">{@device.ip_address}</p>
</div>
<div class="flex gap-2">
<.button navigate={~p"/devices/#{@device.id}/edit"}>
@ -38,7 +38,7 @@
</div>
</div>
<!-- Tabs -->
<div class="border-b border-zinc-200 dark:border-zinc-700">
<div class="border-b border-gray-200 dark:border-white/10">
<nav class="-mb-px flex space-x-8">
<.link
patch={~p"/devices/#{@device.id}?tab=overview"}
@ -47,7 +47,7 @@
if @active_tab == "overview" do
"border-blue-500 text-blue-600 dark:text-blue-400"
else
"border-transparent text-zinc-500 hover:text-zinc-700 hover:border-zinc-300 dark:text-zinc-400 dark:hover:text-zinc-300"
"border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300"
end
]}
>
@ -62,7 +62,7 @@
if @active_tab == "ports" do
"border-blue-500 text-blue-600 dark:text-blue-400"
else
"border-transparent text-zinc-500 hover:text-zinc-700 hover:border-zinc-300 dark:text-zinc-400 dark:hover:text-zinc-300"
"border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300"
end
]}
>
@ -77,7 +77,7 @@
if @active_tab == "neighbors" do
"border-blue-500 text-blue-600 dark:text-blue-400"
else
"border-transparent text-zinc-500 hover:text-zinc-700 hover:border-zinc-300 dark:text-zinc-400 dark:hover:text-zinc-300"
"border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300"
end
]}
>
@ -91,7 +91,7 @@
if @active_tab == "logs" do
"border-blue-500 text-blue-600 dark:text-blue-400"
else
"border-transparent text-zinc-500 hover:text-zinc-700 hover:border-zinc-300 dark:text-zinc-400 dark:hover:text-zinc-300"
"border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300"
end
]}
>
@ -106,7 +106,7 @@
if @active_tab == "debug" do
"border-blue-500 text-blue-600 dark:text-blue-400"
else
"border-transparent text-zinc-500 hover:text-zinc-700 hover:border-zinc-300 dark:text-zinc-400 dark:hover:text-zinc-300"
"border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300"
end
]}
>
@ -124,39 +124,39 @@
<!-- Left Column: Device Information & Traffic -->
<div class="space-y-6">
<!-- Device Information -->
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700">
<div class="px-4 py-3 border-b border-zinc-200 dark:border-zinc-700">
<h3 class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10">
<div class="px-4 py-3 border-b border-gray-200 dark:border-white/10">
<h3 class="text-sm font-semibold text-gray-900 dark:text-white">
Device Information
</h3>
</div>
<div class="p-4">
<dl class="space-y-1">
<%= if @snmp_device do %>
<div class="flex justify-between py-1.5 border-b border-zinc-100 dark:border-zinc-800">
<dt class="text-sm text-zinc-600 dark:text-zinc-400">System Name</dt>
<dd class="text-sm font-medium text-zinc-900 dark:text-zinc-100">
<div class="flex justify-between py-1.5 border-b border-gray-100 dark:border-white/5">
<dt class="text-sm text-gray-600 dark:text-gray-400">System Name</dt>
<dd class="text-sm font-medium text-gray-900 dark:text-white">
{@snmp_device.sys_name || @device.name}
</dd>
</div>
<div class="flex justify-between py-1.5 border-b border-zinc-100 dark:border-zinc-800">
<dt class="text-sm text-zinc-600 dark:text-zinc-400">Resolved IP</dt>
<dd class="text-sm font-medium text-zinc-900 dark:text-zinc-100 font-mono">
<div class="flex justify-between py-1.5 border-b border-gray-100 dark:border-white/5">
<dt class="text-sm text-gray-600 dark:text-gray-400">Resolved IP</dt>
<dd class="text-sm font-medium text-gray-900 dark:text-white font-mono">
{@device.ip_address}
</dd>
</div>
<div class="flex justify-between py-1.5 border-b border-zinc-100 dark:border-zinc-800">
<dt class="text-sm text-zinc-600 dark:text-zinc-400">Hardware</dt>
<dd class="text-sm font-medium text-zinc-900 dark:text-zinc-100">
<div class="flex justify-between py-1.5 border-b border-gray-100 dark:border-white/5">
<dt class="text-sm text-gray-600 dark:text-gray-400">Hardware</dt>
<dd class="text-sm font-medium text-gray-900 dark:text-white">
{@snmp_device.model || "N/A"}
</dd>
</div>
<div class="flex justify-between py-1.5 border-b border-zinc-100 dark:border-zinc-800">
<dt class="text-sm text-zinc-600 dark:text-zinc-400">Operating System</dt>
<dd class="text-sm font-medium text-zinc-900 dark:text-zinc-100">
<div class="flex justify-between py-1.5 border-b border-gray-100 dark:border-white/5">
<dt class="text-sm text-gray-600 dark:text-gray-400">Operating System</dt>
<dd class="text-sm font-medium text-gray-900 dark:text-white">
{if @snmp_device.manufacturer && @snmp_device.firmware_version do
"#{@snmp_device.manufacturer} #{@snmp_device.firmware_version}"
else
@ -165,59 +165,59 @@
</dd>
</div>
<div class="flex justify-between py-1.5 border-b border-zinc-100 dark:border-zinc-800">
<dt class="text-sm text-zinc-600 dark:text-zinc-400">Object ID</dt>
<dd class="text-sm font-medium text-zinc-900 dark:text-zinc-100 font-mono">
<div class="flex justify-between py-1.5 border-b border-gray-100 dark:border-white/5">
<dt class="text-sm text-gray-600 dark:text-gray-400">Object ID</dt>
<dd class="text-sm font-medium text-gray-900 dark:text-white font-mono">
{@snmp_device.sys_object_id || "N/A"}
</dd>
</div>
<div class="flex justify-between py-1.5 border-b border-zinc-100 dark:border-zinc-800">
<dt class="text-sm text-zinc-600 dark:text-zinc-400">Contact</dt>
<dd class="text-sm font-medium text-zinc-900 dark:text-zinc-100">
<div class="flex justify-between py-1.5 border-b border-gray-100 dark:border-white/5">
<dt class="text-sm text-gray-600 dark:text-gray-400">Contact</dt>
<dd class="text-sm font-medium text-gray-900 dark:text-white">
{@snmp_device.sys_contact || "N/A"}
</dd>
</div>
<div class="flex justify-between py-1.5 border-b border-zinc-100 dark:border-zinc-800">
<dt class="text-sm text-zinc-600 dark:text-zinc-400">Location</dt>
<dd class="text-sm font-medium text-zinc-900 dark:text-zinc-100">
<div class="flex justify-between py-1.5 border-b border-gray-100 dark:border-white/5">
<dt class="text-sm text-gray-600 dark:text-gray-400">Location</dt>
<dd class="text-sm font-medium text-gray-900 dark:text-white">
{@snmp_device.sys_location || "N/A"}
</dd>
</div>
<div class="flex justify-between py-1.5 border-b border-zinc-100 dark:border-zinc-800">
<dt class="text-sm text-zinc-600 dark:text-zinc-400">Uptime</dt>
<dd class="text-sm font-medium text-zinc-900 dark:text-zinc-100">
<div class="flex justify-between py-1.5 border-b border-gray-100 dark:border-white/5">
<dt class="text-sm text-gray-600 dark:text-gray-400">Uptime</dt>
<dd class="text-sm font-medium text-gray-900 dark:text-white">
{format_uptime(@snmp_device.sys_uptime)}
</dd>
</div>
<% else %>
<div class="flex justify-between py-1.5 border-b border-zinc-100 dark:border-zinc-800">
<dt class="text-sm text-zinc-600 dark:text-zinc-400">Name</dt>
<dd class="text-sm font-medium text-zinc-900 dark:text-zinc-100">
<div class="flex justify-between py-1.5 border-b border-gray-100 dark:border-white/5">
<dt class="text-sm text-gray-600 dark:text-gray-400">Name</dt>
<dd class="text-sm font-medium text-gray-900 dark:text-white">
{@device.name}
</dd>
</div>
<div class="flex justify-between py-1.5 border-b border-zinc-100 dark:border-zinc-800">
<dt class="text-sm text-zinc-600 dark:text-zinc-400">IP Address</dt>
<dd class="text-sm font-medium text-zinc-900 dark:text-zinc-100 font-mono">
<div class="flex justify-between py-1.5 border-b border-gray-100 dark:border-white/5">
<dt class="text-sm text-gray-600 dark:text-gray-400">IP Address</dt>
<dd class="text-sm font-medium text-gray-900 dark:text-white font-mono">
{@device.ip_address}
</dd>
</div>
<% end %>
<div class="flex justify-between py-1.5 border-b border-zinc-100 dark:border-zinc-800">
<dt class="text-sm text-zinc-600 dark:text-zinc-400">Device Added</dt>
<dd class="text-sm font-medium text-zinc-900 dark:text-zinc-100">
<div class="flex justify-between py-1.5 border-b border-gray-100 dark:border-white/5">
<dt class="text-sm text-gray-600 dark:text-gray-400">Device Added</dt>
<dd class="text-sm font-medium text-gray-900 dark:text-white">
{format_device_age(@device.inserted_at)}
</dd>
</div>
<div class="flex justify-between py-1.5">
<dt class="text-sm text-zinc-600 dark:text-zinc-400">Last Discovered</dt>
<dd class="text-sm font-medium text-zinc-900 dark:text-zinc-100">
<dt class="text-sm text-gray-600 dark:text-gray-400">Last Discovered</dt>
<dd class="text-sm font-medium text-gray-900 dark:text-white">
{if @device.last_discovery_at do
format_device_age(@device.last_discovery_at)
else
@ -230,16 +230,16 @@
</div>
<!-- Overall Traffic Chart -->
<%= if @traffic_chart_data do %>
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700">
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10">
<.link
navigate={~p"/devices/#{@device.id}/graph/traffic"}
class="block px-4 py-3 border-b border-zinc-200 dark:border-zinc-700 hover:bg-zinc-50 dark:hover:bg-zinc-750 transition-colors"
class="block px-4 py-3 border-b border-gray-200 dark:border-white/10 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
>
<div class="flex items-center justify-between">
<h3 class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">
<h3 class="text-sm font-semibold text-gray-900 dark:text-white">
Overall Traffic
</h3>
<.icon name="hero-arrow-right" class="h-4 w-4 text-zinc-400" />
<.icon name="hero-arrow-right" class="h-4 w-4 text-gray-400" />
</div>
</.link>
<div class="p-4">
@ -259,16 +259,16 @@
<% end %>
<!-- ICMP Latency Chart -->
<%= if @latency_chart_data do %>
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700">
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10">
<.link
navigate={~p"/devices/#{@device.id}/graph/latency"}
class="block px-4 py-3 border-b border-zinc-200 dark:border-zinc-700 hover:bg-zinc-50 dark:hover:bg-zinc-750 transition-colors"
class="block px-4 py-3 border-b border-gray-200 dark:border-white/10 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
>
<div class="flex items-center justify-between">
<h3 class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">
<h3 class="text-sm font-semibold text-gray-900 dark:text-white">
ICMP Latency
</h3>
<.icon name="hero-arrow-right" class="h-4 w-4 text-zinc-400" />
<.icon name="hero-arrow-right" class="h-4 w-4 text-gray-400" />
</div>
</.link>
<div class="p-4">
@ -290,16 +290,16 @@
<div class="space-y-6">
<!-- CPU Usage Chart -->
<%= if @cpu_chart_data do %>
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700">
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10">
<.link
navigate={~p"/devices/#{@device.id}/graph/processors"}
class="block px-4 py-3 border-b border-zinc-200 dark:border-zinc-700 hover:bg-zinc-50 dark:hover:bg-zinc-750 transition-colors"
class="block px-4 py-3 border-b border-gray-200 dark:border-white/10 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
>
<div class="flex items-center justify-between">
<h3 class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">
<h3 class="text-sm font-semibold text-gray-900 dark:text-white">
Processors
</h3>
<.icon name="hero-arrow-right" class="h-4 w-4 text-zinc-400" />
<.icon name="hero-arrow-right" class="h-4 w-4 text-gray-400" />
</div>
</.link>
<div class="p-4">
@ -316,16 +316,16 @@
<% end %>
<!-- Memory Usage Chart -->
<%= if @memory_chart_data do %>
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700">
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10">
<.link
navigate={~p"/devices/#{@device.id}/graph/memory"}
class="block px-4 py-3 border-b border-zinc-200 dark:border-zinc-700 hover:bg-zinc-50 dark:hover:bg-zinc-750 transition-colors"
class="block px-4 py-3 border-b border-gray-200 dark:border-white/10 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
>
<div class="flex items-center justify-between">
<h3 class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">
<h3 class="text-sm font-semibold text-gray-900 dark:text-white">
Memory Usage
</h3>
<.icon name="hero-arrow-right" class="h-4 w-4 text-zinc-400" />
<.icon name="hero-arrow-right" class="h-4 w-4 text-gray-400" />
</div>
</.link>
<div class="p-4">
@ -342,17 +342,17 @@
<% end %>
<!-- Storage Usage -->
<%= if @storage_sensors && length(@storage_sensors) > 0 do %>
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700">
<div class="px-4 py-3 border-b border-zinc-200 dark:border-zinc-700">
<h3 class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10">
<div class="px-4 py-3 border-b border-gray-200 dark:border-white/10">
<h3 class="text-sm font-semibold text-gray-900 dark:text-white">
Storage Usage
</h3>
</div>
<div class="p-4">
<dl class="space-y-1">
<%= for sensor <- @storage_sensors do %>
<div class="flex justify-between py-1.5 border-b border-zinc-100 dark:border-zinc-800">
<dt class="text-sm text-zinc-600 dark:text-zinc-400">
<div class="flex justify-between py-1.5 border-b border-gray-100 dark:border-white/5">
<dt class="text-sm text-gray-600 dark:text-gray-400">
<.link
navigate={~p"/devices/#{@device.id}/graph/storage"}
class="hover:text-blue-600 dark:hover:text-blue-400 hover:underline"
@ -360,7 +360,7 @@
{sensor.sensor_descr}
</.link>
</dt>
<dd class="text-sm font-medium text-zinc-900 dark:text-zinc-100">
<dd class="text-sm font-medium text-gray-900 dark:text-white">
<%= if sensor.latest_reading do %>
{format_sensor_value(
sensor.latest_reading.value,
@ -379,17 +379,17 @@
<% end %>
<!-- Temperature Sensors -->
<%= if @temperature_sensors && length(@temperature_sensors) > 0 do %>
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700">
<div class="px-4 py-3 border-b border-zinc-200 dark:border-zinc-700">
<h3 class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10">
<div class="px-4 py-3 border-b border-gray-200 dark:border-white/10">
<h3 class="text-sm font-semibold text-gray-900 dark:text-white">
Temperature
</h3>
</div>
<div class="p-4">
<dl class="space-y-1">
<%= for sensor <- @temperature_sensors do %>
<div class="flex justify-between py-1.5 border-b border-zinc-100 dark:border-zinc-800">
<dt class="text-sm text-zinc-600 dark:text-zinc-400">
<div class="flex justify-between py-1.5 border-b border-gray-100 dark:border-white/5">
<dt class="text-sm text-gray-600 dark:text-gray-400">
<.link
navigate={~p"/devices/#{@device.id}/graph/temperature"}
class="hover:text-blue-600 dark:hover:text-blue-400 hover:underline"
@ -397,7 +397,7 @@
{sensor.sensor_descr}
</.link>
</dt>
<dd class="text-sm font-medium text-zinc-900 dark:text-zinc-100">
<dd class="text-sm font-medium text-gray-900 dark:text-white">
<%= if sensor.latest_reading do %>
{format_sensor_value(
sensor.latest_reading.value,
@ -416,15 +416,15 @@
<% end %>
<!-- Voltage Sensors -->
<%= if @voltage_sensors && length(@voltage_sensors) > 0 do %>
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700">
<div class="px-4 py-3 border-b border-zinc-200 dark:border-zinc-700">
<h3 class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">Voltage</h3>
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10">
<div class="px-4 py-3 border-b border-gray-200 dark:border-white/10">
<h3 class="text-sm font-semibold text-gray-900 dark:text-white">Voltage</h3>
</div>
<div class="p-4">
<dl class="space-y-1">
<%= for sensor <- @voltage_sensors do %>
<div class="flex justify-between py-1.5 border-b border-zinc-100 dark:border-zinc-800">
<dt class="text-sm text-zinc-600 dark:text-zinc-400">
<div class="flex justify-between py-1.5 border-b border-gray-100 dark:border-white/5">
<dt class="text-sm text-gray-600 dark:text-gray-400">
<.link
navigate={~p"/devices/#{@device.id}/graph/voltage"}
class="hover:text-blue-600 dark:hover:text-blue-400 hover:underline"
@ -432,7 +432,7 @@
{sensor.sensor_descr}
</.link>
</dt>
<dd class="text-sm font-medium text-zinc-900 dark:text-zinc-100">
<dd class="text-sm font-medium text-gray-900 dark:text-white">
<%= if sensor.latest_reading do %>
{format_sensor_value(
sensor.latest_reading.value,
@ -451,9 +451,9 @@
<% end %>
<!-- SFP Transceivers -->
<%= if @grouped_transceivers && length(@grouped_transceivers) > 0 do %>
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700">
<div class="px-4 py-3 border-b border-zinc-200 dark:border-zinc-700">
<h3 class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10">
<div class="px-4 py-3 border-b border-gray-200 dark:border-white/10">
<h3 class="text-sm font-semibold text-gray-900 dark:text-white">
Transceivers
</h3>
</div>
@ -461,8 +461,8 @@
<dl class="space-y-1">
<%= for {_transceiver_name, sensors} <- @grouped_transceivers do %>
<%= for sensor <- sensors do %>
<div class="flex justify-between py-1.5 border-b border-zinc-100 dark:border-zinc-800">
<dt class="text-sm text-zinc-600 dark:text-zinc-400">
<div class="flex justify-between py-1.5 border-b border-gray-100 dark:border-white/5">
<dt class="text-sm text-gray-600 dark:text-gray-400">
<.link
navigate={~p"/devices/#{@device.id}/graph/dbm"}
class="hover:text-blue-600 dark:hover:text-blue-400 hover:underline"
@ -470,7 +470,7 @@
{sensor.sensor_descr}
</.link>
</dt>
<dd class="text-sm font-medium text-zinc-900 dark:text-zinc-100 font-mono">
<dd class="text-sm font-medium text-gray-900 dark:text-white font-mono">
<%= if sensor.latest_reading do %>
{format_sensor_value(
sensor.latest_reading.value,
@ -490,15 +490,15 @@
<% end %>
<!-- Count Sensors (DHCP Leases, Connections, etc.) -->
<%= if @count_sensors && length(@count_sensors) > 0 do %>
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700">
<div class="px-4 py-3 border-b border-zinc-200 dark:border-zinc-700">
<h3 class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">Counters</h3>
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10">
<div class="px-4 py-3 border-b border-gray-200 dark:border-white/10">
<h3 class="text-sm font-semibold text-gray-900 dark:text-white">Counters</h3>
</div>
<div class="p-4">
<dl class="space-y-1">
<%= for sensor <- @count_sensors do %>
<div class="flex justify-between py-1.5 border-b border-zinc-100 dark:border-zinc-800">
<dt class="text-sm text-zinc-600 dark:text-zinc-400">
<div class="flex justify-between py-1.5 border-b border-gray-100 dark:border-white/5">
<dt class="text-sm text-gray-600 dark:text-gray-400">
<.link
navigate={~p"/devices/#{@device.id}/graph/count"}
class="hover:text-blue-600 dark:hover:text-blue-400 hover:underline"
@ -506,7 +506,7 @@
{sensor.sensor_descr}
</.link>
</dt>
<dd class="text-sm font-medium text-zinc-900 dark:text-zinc-100">
<dd class="text-sm font-medium text-gray-900 dark:text-white">
<%= if sensor.latest_reading do %>
{trunc(sensor.latest_reading.value)}
<% else %>
@ -525,19 +525,19 @@
<%= if @snmp_interfaces && length(@snmp_interfaces) > 0 do %>
<div class="space-y-6">
<%= for {category, interfaces} <- @interfaces_by_type do %>
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700">
<div class="px-4 py-3 border-b border-zinc-200 dark:border-zinc-700">
<h3 class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10">
<div class="px-4 py-3 border-b border-gray-200 dark:border-white/10">
<h3 class="text-sm font-semibold text-gray-900 dark:text-white">
{category} Interfaces
<span class="ml-2 text-xs font-normal text-zinc-500 dark:text-zinc-400">
<span class="ml-2 text-xs font-normal text-gray-500 dark:text-gray-400">
({length(interfaces)})
</span>
</h3>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-zinc-200 dark:divide-zinc-700">
<thead class="bg-zinc-50 dark:bg-zinc-900">
<tr class="text-xs text-zinc-600 dark:text-zinc-400">
<table class="min-w-full divide-y divide-gray-200 dark:divide-white/10">
<thead class="bg-gray-50 dark:bg-gray-800/75">
<tr class="text-xs text-gray-600 dark:text-gray-400">
<th class="px-4 py-3 text-left font-medium">#</th>
<th class="px-4 py-3 text-left font-medium">Name</th>
<th class="px-4 py-3 text-left font-medium">Status</th>
@ -545,10 +545,10 @@
<th class="px-4 py-3 text-left font-medium">MAC</th>
</tr>
</thead>
<tbody class="divide-y divide-zinc-200 dark:divide-zinc-700">
<tbody class="divide-y divide-gray-200 dark:divide-white/10">
<%= for interface <- interfaces do %>
<tr class="text-sm hover:bg-zinc-50 dark:hover:bg-zinc-900">
<td class="px-4 py-3 text-zinc-900 dark:text-zinc-100">
<tr class="text-sm hover:bg-gray-50 dark:hover:bg-gray-800">
<td class="px-4 py-3 text-gray-900 dark:text-white">
{interface.if_index}
</td>
<td class="px-4 py-3">
@ -558,11 +558,11 @@
}
class="hover:text-blue-600 dark:hover:text-blue-400"
>
<div class="font-medium text-zinc-900 dark:text-zinc-100 hover:underline">
<div class="font-medium text-gray-900 dark:text-white hover:underline">
{interface.if_name || interface.if_descr}
</div>
<%= if interface.if_alias do %>
<div class="text-xs text-zinc-500 dark:text-zinc-400">
<div class="text-xs text-gray-500 dark:text-gray-400">
{interface.if_alias}
</div>
<% end %>
@ -576,15 +576,15 @@
interface.if_oper_status == "down" &&
"bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200",
interface.if_oper_status not in ["up", "down"] &&
"bg-zinc-100 text-zinc-800 dark:bg-zinc-800 dark:text-zinc-200"
"bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-200"
]}>
{String.upcase(interface.if_oper_status || "unknown")}
</span>
</td>
<td class="px-4 py-3 text-zinc-900 dark:text-zinc-100">
<td class="px-4 py-3 text-gray-900 dark:text-white">
{format_speed(interface.if_speed)}
</td>
<td class="px-4 py-3 font-mono text-xs text-zinc-600 dark:text-zinc-400">
<td class="px-4 py-3 font-mono text-xs text-gray-600 dark:text-gray-400">
{interface.if_phys_address || "-"}
</td>
</tr>
@ -597,21 +597,21 @@
</div>
<% else %>
<div class="text-center py-12">
<p class="text-zinc-500 dark:text-zinc-400">No interfaces discovered</p>
<p class="text-gray-500 dark:text-gray-400">No interfaces discovered</p>
</div>
<% end %>
<% "neighbors" -> %>
<%= if @neighbors && length(@neighbors) > 0 do %>
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700">
<div class="px-4 py-3 border-b border-zinc-200 dark:border-zinc-700">
<h3 class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10">
<div class="px-4 py-3 border-b border-gray-200 dark:border-white/10">
<h3 class="text-sm font-semibold text-gray-900 dark:text-white">
Discovered Neighbors
</h3>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-zinc-200 dark:divide-zinc-700">
<thead class="bg-zinc-50 dark:bg-zinc-900">
<tr class="text-xs text-zinc-600 dark:text-zinc-400">
<table class="min-w-full divide-y divide-gray-200 dark:divide-white/10">
<thead class="bg-gray-50 dark:bg-gray-800/75">
<tr class="text-xs text-gray-600 dark:text-gray-400">
<th class="px-4 py-3 text-left font-medium">Protocol</th>
<th class="px-4 py-3 text-left font-medium">Local Port</th>
<th class="px-4 py-3 text-left font-medium">Remote Device</th>
@ -621,9 +621,9 @@
<th class="px-4 py-3 text-left font-medium">Last Seen</th>
</tr>
</thead>
<tbody class="divide-y divide-zinc-200 dark:divide-zinc-700">
<tbody class="divide-y divide-gray-200 dark:divide-white/10">
<%= for neighbor <- @neighbors do %>
<tr class="text-sm hover:bg-zinc-50 dark:hover:bg-zinc-900">
<tr class="text-sm hover:bg-gray-50 dark:hover:bg-gray-800">
<td class="px-4 py-3">
<span class={[
"inline-flex items-center px-2 py-0.5 rounded text-xs font-medium uppercase",
@ -635,7 +635,7 @@
{neighbor.protocol}
</span>
</td>
<td class="px-4 py-3 text-zinc-900 dark:text-zinc-100">
<td class="px-4 py-3 text-gray-900 dark:text-white">
{neighbor.interface.if_name || neighbor.interface.if_descr}
</td>
<td class="px-4 py-3">
@ -647,7 +647,7 @@
{neighbor.matched_device.name}
</.link>
<% else %>
<div class="text-zinc-900 dark:text-zinc-100">
<div class="text-gray-900 dark:text-white">
<%= if neighbor.remote_system_name do %>
{neighbor.remote_system_name |> String.split("/") |> List.first()}
<% else %>
@ -657,26 +657,26 @@
<% end %>
</td>
<td class="px-4 py-3">
<div class="text-zinc-900 dark:text-zinc-100">
<div class="text-gray-900 dark:text-white">
{neighbor.remote_port_id || "-"}
</div>
<%= if !neighbor.matched_device && neighbor.remote_chassis_id do %>
<div class="text-xs font-mono text-zinc-500 dark:text-zinc-400">
<div class="text-xs font-mono text-gray-500 dark:text-gray-400">
{neighbor.remote_chassis_id}
</div>
<% end %>
</td>
<td class="px-4 py-3 text-xs text-zinc-600 dark:text-zinc-400">
<td class="px-4 py-3 text-xs text-gray-600 dark:text-gray-400">
{neighbor.remote_platform || "-"}
</td>
<td class="px-4 py-3 text-xs text-zinc-600 dark:text-zinc-400">
<td class="px-4 py-3 text-xs text-gray-600 dark:text-gray-400">
<%= if neighbor.remote_capabilities && length(neighbor.remote_capabilities) > 0 do %>
{Enum.join(neighbor.remote_capabilities, ", ")}
<% else %>
-
<% end %>
</td>
<td class="px-4 py-3 text-xs text-zinc-500 dark:text-zinc-400">
<td class="px-4 py-3 text-xs text-gray-500 dark:text-gray-400">
{time_ago(neighbor.last_discovered_at)}
</td>
</tr>
@ -686,30 +686,30 @@
</div>
</div>
<% else %>
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700 p-12">
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10 p-12">
<div class="text-center">
<.icon name="hero-server-stack" class="mx-auto h-12 w-12 text-zinc-400" />
<h3 class="mt-2 text-sm font-semibold text-zinc-900 dark:text-zinc-100">
<.icon name="hero-server-stack" class="mx-auto h-12 w-12 text-gray-400" />
<h3 class="mt-2 text-sm font-semibold text-gray-900 dark:text-white">
No neighbors discovered
</h3>
<p class="mt-1 text-sm text-zinc-500 dark:text-zinc-400">
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
This device doesn't have any LLDP or CDP neighbors, or neighbor discovery hasn't run yet.
</p>
</div>
</div>
<% end %>
<% "logs" -> %>
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700">
<div class="px-4 py-3 border-b border-zinc-200 dark:border-zinc-700">
<h3 class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">Event Logs</h3>
<p class="text-xs text-zinc-600 dark:text-zinc-400 mt-1">
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10">
<div class="px-4 py-3 border-b border-gray-200 dark:border-white/10">
<h3 class="text-sm font-semibold text-gray-900 dark:text-white">Event Logs</h3>
<p class="text-xs text-gray-600 dark:text-gray-400 mt-1">
Showing the most recent 100 events
</p>
</div>
<%= if Enum.any?(@events) do %>
<div class="divide-y divide-zinc-200 dark:divide-zinc-700">
<div class="divide-y divide-gray-200 dark:divide-white/10">
<%= for event <- @events do %>
<div class="px-4 py-3 hover:bg-zinc-50 dark:hover:bg-zinc-750">
<div class="px-4 py-3 hover:bg-gray-50 dark:hover:bg-gray-800">
<div class="flex items-start gap-3">
<!-- Severity Icon -->
<div class={[
@ -732,16 +732,16 @@
<div class="flex-1 min-w-0">
<div class="flex items-start justify-between gap-2">
<div class="flex-1">
<p class="text-sm font-medium text-zinc-900 dark:text-zinc-100">
<p class="text-sm font-medium text-gray-900 dark:text-white">
{event.message}
</p>
<div class="mt-1 flex items-center gap-3 text-xs text-zinc-500 dark:text-zinc-400">
<div class="mt-1 flex items-center gap-3 text-xs text-gray-500 dark:text-gray-400">
<span>{format_event_type(event.event_type)}</span>
<span>•</span>
<span class="capitalize">{event.severity}</span>
</div>
</div>
<time class="flex-shrink-0 text-xs text-zinc-500 dark:text-zinc-400">
<time class="flex-shrink-0 text-xs text-gray-500 dark:text-gray-400">
{time_ago(event.occurred_at)}
</time>
</div>
@ -752,23 +752,23 @@
</div>
<% else %>
<div class="p-8 text-center">
<.icon name="hero-document-text" class="mx-auto h-12 w-12 text-zinc-400" />
<h3 class="mt-2 text-sm font-semibold text-zinc-900 dark:text-zinc-100">
<.icon name="hero-document-text" class="mx-auto h-12 w-12 text-gray-400" />
<h3 class="mt-2 text-sm font-semibold text-gray-900 dark:text-white">
No events yet
</h3>
<p class="mt-1 text-sm text-zinc-500 dark:text-zinc-400">
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
Events will appear here as interface states change, speeds change, or other monitored changes occur.
</p>
</div>
<% end %>
</div>
<% "debug" -> %>
<div class="bg-white dark:bg-zinc-800 shadow sm:rounded-lg">
<div class="bg-white dark:bg-gray-800/50 shadow sm:rounded-lg">
<div class="px-4 py-5 sm:p-6">
<h3 class="text-lg font-medium leading-6 text-zinc-900 dark:text-zinc-100">
<h3 class="text-lg font-medium leading-6 text-gray-900 dark:text-white">
Raw Discovery Data
</h3>
<div class="mt-2 max-w-xl text-sm text-zinc-500 dark:text-zinc-400">
<div class="mt-2 max-w-xl text-sm text-gray-500 dark:text-gray-400">
<p>
Raw SNMP OID values collected during the last discovery run at
<%= if @snmp_device.last_discovery_at do %>
@ -780,34 +780,34 @@
</div>
<%= if @snmp_device.raw_discovery_data do %>
<div class="mt-5">
<h4 class="text-sm font-medium text-zinc-900 dark:text-zinc-100 mb-3">
<h4 class="text-sm font-medium text-gray-900 dark:text-white mb-3">
System OIDs
</h4>
<div class="overflow-hidden rounded-lg border border-zinc-200 dark:border-zinc-700">
<table class="min-w-full divide-y divide-zinc-200 dark:divide-zinc-700">
<thead class="bg-zinc-50 dark:bg-zinc-900">
<div class="overflow-hidden rounded-lg border border-gray-200 dark:border-white/10">
<table class="min-w-full divide-y divide-gray-200 dark:divide-white/10">
<thead class="bg-gray-50 dark:bg-gray-800/75">
<tr>
<th class="px-3 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider">
<th class="px-3 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Field
</th>
<th class="px-3 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider">
<th class="px-3 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
OID
</th>
<th class="px-3 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider">
<th class="px-3 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Value
</th>
</tr>
</thead>
<tbody class="bg-white dark:bg-zinc-800 divide-y divide-zinc-200 dark:divide-zinc-700">
<tbody class="bg-white dark:bg-gray-800/50 divide-y divide-gray-200 dark:divide-white/10">
<%= for {key, data} <- Map.get(@snmp_device.raw_discovery_data, "system_oids", %{}) do %>
<tr>
<td class="px-3 py-4 whitespace-nowrap text-sm font-medium text-zinc-900 dark:text-zinc-100">
<td class="px-3 py-4 whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">
{key}
</td>
<td class="px-3 py-4 whitespace-nowrap text-sm text-zinc-500 dark:text-zinc-400 font-mono">
<td class="px-3 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400 font-mono">
{data["oid"]}
</td>
<td class="px-3 py-4 text-sm text-zinc-900 dark:text-zinc-100">
<td class="px-3 py-4 text-sm text-gray-900 dark:text-white">
<code class="text-xs">{inspect(data["value"])}</code>
</td>
</tr>
@ -817,28 +817,28 @@
</div>
<%= if Map.get(@snmp_device.raw_discovery_data, "health_sensor_table") do %>
<h4 class="text-sm font-medium text-zinc-900 dark:text-zinc-100 mt-6 mb-3">
<h4 class="text-sm font-medium text-gray-900 dark:text-white mt-6 mb-3">
Health Sensor Table Walk
</h4>
<div class="overflow-hidden rounded-lg border border-zinc-200 dark:border-zinc-700">
<table class="min-w-full divide-y divide-zinc-200 dark:divide-zinc-700">
<thead class="bg-zinc-50 dark:bg-zinc-900">
<div class="overflow-hidden rounded-lg border border-gray-200 dark:border-white/10">
<table class="min-w-full divide-y divide-gray-200 dark:divide-white/10">
<thead class="bg-gray-50 dark:bg-gray-800/75">
<tr>
<th class="px-3 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider">
<th class="px-3 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
OID
</th>
<th class="px-3 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider">
<th class="px-3 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Value
</th>
</tr>
</thead>
<tbody class="bg-white dark:bg-zinc-800 divide-y divide-zinc-200 dark:divide-zinc-700">
<tbody class="bg-white dark:bg-gray-800/50 divide-y divide-gray-200 dark:divide-white/10">
<%= for {oid, value} <- Map.get(@snmp_device.raw_discovery_data, "health_sensor_table", %{}) do %>
<tr>
<td class="px-3 py-4 whitespace-nowrap text-sm font-mono text-zinc-500 dark:text-zinc-400">
<td class="px-3 py-4 whitespace-nowrap text-sm font-mono text-gray-500 dark:text-gray-400">
{oid}
</td>
<td class="px-3 py-4 text-sm text-zinc-900 dark:text-zinc-100">
<td class="px-3 py-4 text-sm text-gray-900 dark:text-white">
<code class="text-xs">{inspect(value)}</code>
</td>
</tr>
@ -848,24 +848,24 @@
</div>
<% end %>
<h4 class="text-sm font-medium text-zinc-900 dark:text-zinc-100 mt-6 mb-3">
<h4 class="text-sm font-medium text-gray-900 dark:text-white mt-6 mb-3">
Copyable Debug Data
</h4>
<div class="rounded-lg border border-zinc-200 dark:border-zinc-700">
<div class="rounded-lg border border-gray-200 dark:border-white/10">
<textarea
readonly
rows="10"
class="w-full p-3 font-mono text-xs bg-zinc-50 dark:bg-zinc-900 text-zinc-900 dark:text-zinc-100 border-0 rounded-lg focus:ring-2 focus:ring-blue-500"
class="w-full p-3 font-mono text-xs bg-gray-50 dark:bg-gray-900 text-gray-900 dark:text-white border-0 rounded-lg focus:ring-2 focus:ring-blue-500"
onclick="this.select()"
><%= Jason.encode!(@snmp_device.raw_discovery_data, pretty: true) %></textarea>
</div>
<p class="mt-2 text-xs text-zinc-500 dark:text-zinc-400">
<p class="mt-2 text-xs text-gray-500 dark:text-gray-400">
Click the text box to select all data, then copy with Cmd+C or Ctrl+C
</p>
</div>
<% else %>
<div class="mt-5 p-4 bg-zinc-50 dark:bg-zinc-900 rounded-md">
<p class="text-sm text-zinc-500 dark:text-zinc-400">
<div class="mt-5 p-4 bg-gray-50 dark:bg-gray-900 rounded-md">
<p class="text-sm text-gray-500 dark:text-gray-400">
No raw discovery data available. Run discovery again to collect debug data.
</p>
</div>
@ -874,7 +874,7 @@
</div>
<% _ -> %>
<div class="text-center py-12">
<p class="text-zinc-500 dark:text-zinc-400">Tab not found</p>
<p class="text-gray-500 dark:text-gray-400">Tab not found</p>
</div>
<% end %>
</div>

View file

@ -11,19 +11,19 @@
<div class="flex items-center gap-4">
<.link
navigate={~p"/devices/#{@device_id}"}
class="text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100"
class="text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
<.icon name="hero-arrow-left" class="h-5 w-5" />
</.link>
<div>
<h1 class="text-2xl font-bold text-zinc-900 dark:text-zinc-100">{@chart_title}</h1>
<p class="text-sm text-zinc-600 dark:text-zinc-400">{@device.name}</p>
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">{@chart_title}</h1>
<p class="text-sm text-gray-600 dark:text-gray-400">{@device.name}</p>
</div>
</div>
</div>
<!-- Date Range Selector -->
<div class="flex items-center gap-2 mb-6">
<span class="text-sm font-medium text-zinc-700 dark:text-zinc-300">Time Range:</span>
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">Time Range:</span>
<div class="flex gap-1">
<%= for {label, value} <- [{"1 Hour", "1h"}, {"6 Hours", "6h"}, {"12 Hours", "12h"}, {"24 Hours", "24h"}, {"7 Days", "7d"}, {"30 Days", "30d"}] do %>
<button
@ -34,7 +34,7 @@
if @range == value do
"bg-blue-500 text-white border-blue-500"
else
"bg-white dark:bg-zinc-800 text-zinc-700 dark:text-zinc-300 border-zinc-300 dark:border-zinc-600 hover:bg-zinc-50 dark:hover:bg-zinc-700"
"bg-white dark:bg-gray-800/50 text-gray-700 dark:text-gray-300 border-gray-300 dark:border-white/10 hover:bg-gray-50 dark:hover:bg-gray-800"
end
]}
>
@ -45,7 +45,7 @@
</div>
<!-- Large Chart -->
<%= if @chart_data do %>
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700">
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10">
<div class="p-6">
<div
id="detail-chart"
@ -62,13 +62,13 @@
</div>
</div>
<% else %>
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700 p-12">
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10 p-12">
<div class="text-center">
<.icon name="hero-chart-bar" class="mx-auto h-12 w-12 text-zinc-400" />
<h3 class="mt-2 text-sm font-semibold text-zinc-900 dark:text-zinc-100">
<.icon name="hero-chart-bar" class="mx-auto h-12 w-12 text-gray-400" />
<h3 class="mt-2 text-sm font-semibold text-gray-900 dark:text-white">
No sensor data available
</h3>
<p class="mt-1 text-sm text-zinc-500 dark:text-zinc-400">
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
This device doesn't have any sensors of this type.
</p>
</div>

View file

@ -92,13 +92,13 @@ defmodule ToweropsWeb.MobileQRLive do
</.header>
<div :if={!@completed} class="mt-8">
<div class="rounded-lg bg-white p-8 shadow-sm ring-1 ring-zinc-200 dark:bg-zinc-900 dark:ring-zinc-700">
<div class="rounded-lg bg-white p-8 shadow-sm ring-1 ring-gray-200 dark:bg-gray-800/50 dark:ring-white/10">
<div class="flex flex-col items-center space-y-6">
<div class="text-center">
<h3 class="text-lg font-semibold text-zinc-900 dark:text-zinc-100">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">
Scan with Mobile App
</h3>
<p class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
Open the Towerops mobile app and scan this QR code to log in
</p>
</div>
@ -112,17 +112,17 @@ defmodule ToweropsWeb.MobileQRLive do
</div>
<div class="text-center">
<p class="text-xs text-zinc-500 dark:text-zinc-400">
<p class="text-xs text-gray-500 dark:text-gray-400">
This QR code expires in 5 minutes
</p>
<p class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
Waiting for mobile app to scan...
</p>
</div>
<div class="flex items-center space-x-2">
<div class="h-2 w-2 animate-pulse rounded-full bg-blue-500"></div>
<span class="text-sm text-zinc-600 dark:text-zinc-400">Checking...</span>
<span class="text-sm text-gray-600 dark:text-gray-400">Checking...</span>
</div>
</div>
</div>
@ -164,23 +164,23 @@ defmodule ToweropsWeb.MobileQRLive do
</p>
</div>
<div class="mt-4 rounded-lg bg-white p-4 dark:bg-zinc-800">
<div class="mt-4 rounded-lg bg-white p-4 dark:bg-gray-800/50">
<dl class="space-y-2 text-sm">
<div>
<dt class="font-medium text-zinc-700 dark:text-zinc-300">Device Name</dt>
<dd class="mt-1 text-zinc-900 dark:text-zinc-100">
<dt class="font-medium text-gray-700 dark:text-gray-300">Device Name</dt>
<dd class="mt-1 text-gray-900 dark:text-white">
{@mobile_session.device_name || "Unknown"}
</dd>
</div>
<div>
<dt class="font-medium text-zinc-700 dark:text-zinc-300">Device OS</dt>
<dd class="mt-1 text-zinc-900 dark:text-zinc-100">
<dt class="font-medium text-gray-700 dark:text-gray-300">Device OS</dt>
<dd class="mt-1 text-gray-900 dark:text-white">
{@mobile_session.device_os || "Unknown"}
</dd>
</div>
<div>
<dt class="font-medium text-zinc-700 dark:text-zinc-300">App Version</dt>
<dd class="mt-1 text-zinc-900 dark:text-zinc-100">
<dt class="font-medium text-gray-700 dark:text-gray-300">App Version</dt>
<dd class="mt-1 text-gray-900 dark:text-white">
{@mobile_session.app_version || "Unknown"}
</dd>
</div>
@ -200,7 +200,7 @@ defmodule ToweropsWeb.MobileQRLive do
<div class="mt-6">
<.link
navigate={~p"/orgs"}
class="text-sm font-medium text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100"
class="text-sm font-medium text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
Back to Organizations
</.link>

View file

@ -6,7 +6,7 @@
<div class="mb-4">
<.link
navigate={~p"/orgs/#{@organization.slug}"}
class="inline-flex items-center gap-1 text-sm text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100"
class="inline-flex items-center gap-1 text-sm text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
<.icon name="hero-arrow-left" class="h-4 w-4" /> Back to Dashboard
</.link>
@ -25,7 +25,7 @@
<div class="mt-6 border-t pt-6">
<h3 class="text-lg font-medium mb-4">SNMP Configuration</h3>
<p class="text-sm text-zinc-600 dark:text-zinc-400 mb-4">
<p class="text-sm text-gray-600 dark:text-gray-400 mb-4">
Set default SNMP settings for all devices in this organization. These can be overridden at the site or device level.
</p>
@ -44,7 +44,7 @@
placeholder="e.g., public"
/>
<p class="mt-3 text-sm text-zinc-500 dark:text-zinc-400 italic">
<p class="mt-3 text-sm text-gray-500 dark:text-gray-400 italic">
<.icon name="hero-information-circle" class="h-4 w-4 inline" />
SNMP configuration hierarchy: Device > Site > Organization
</p>
@ -72,7 +72,7 @@
<%= if @available_agents != [] do %>
<div class="mt-6 border-t pt-6">
<h3 class="text-lg font-medium mb-4">Default Agent</h3>
<p class="text-sm text-zinc-600 dark:text-zinc-400 mb-4">
<p class="text-sm text-gray-600 dark:text-gray-400 mb-4">
Select a default agent for SNMP polling. This will be used for all devices in this organization unless overridden at the site or device level.
</p>
@ -84,11 +84,11 @@
options={Enum.map(@available_agents, &{&1.name, &1.id})}
/>
<div class="mt-3 p-3 bg-zinc-50 dark:bg-zinc-800 rounded-lg text-sm">
<p class="font-medium text-zinc-700 dark:text-zinc-300 mb-2">
<div class="mt-3 p-3 bg-gray-50 dark:bg-gray-800/50 rounded-lg text-sm">
<p class="font-medium text-gray-700 dark:text-gray-300 mb-2">
Current Device Assignment:
</p>
<div class="space-y-1 text-zinc-600 dark:text-zinc-400">
<div class="space-y-1 text-gray-600 dark:text-gray-400">
<div class="flex items-center gap-2">
<.icon name="hero-server" class="h-4 w-4" />
<span>
@ -115,7 +115,7 @@
</div>
</div>
<p class="mt-3 text-sm text-zinc-500 dark:text-zinc-400 italic">
<p class="mt-3 text-sm text-gray-500 dark:text-gray-400 italic">
<.icon name="hero-information-circle" class="h-4 w-4 inline" />
Agent assignment hierarchy: Device > Site > Organization
</p>
@ -142,7 +142,7 @@
<% else %>
<div class="mt-6 border-t pt-6">
<h3 class="text-lg font-medium mb-2">Default Agent</h3>
<p class="text-sm text-zinc-600 dark:text-zinc-400 mb-4">
<p class="text-sm text-gray-600 dark:text-gray-400 mb-4">
No agents configured yet.
<.link
navigate={~p"/orgs/#{@organization.slug}/agents"}

View file

@ -17,10 +17,10 @@
<.link
:for={org <- @organizations}
navigate={~p"/orgs/#{org.slug}"}
class="relative overflow-hidden rounded-lg border border-zinc-200 bg-white p-6 shadow-sm hover:shadow-md transition-shadow dark:border-zinc-800 dark:bg-zinc-900 cursor-pointer"
class="relative overflow-hidden rounded-lg border border-gray-200 bg-white p-6 shadow-sm hover:shadow-md transition-shadow dark:border-white/10 dark:bg-gray-800/50 cursor-pointer"
>
<h2 class="text-xl font-semibold text-zinc-900 dark:text-zinc-100">{org.name}</h2>
<p class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
<h2 class="text-xl font-semibold text-gray-900 dark:text-white">{org.name}</h2>
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
{Enum.find(org.memberships, &(&1.user_id == @current_scope.user.id)).role
|> to_string()
|> String.capitalize()}
@ -29,9 +29,9 @@
</div>
<div :if={@organizations == []} class="text-center py-16">
<.icon name="hero-building-office" class="mx-auto h-12 w-12 text-zinc-400 dark:text-zinc-600" />
<h3 class="mt-4 text-lg font-semibold text-zinc-900 dark:text-zinc-100">No organizations</h3>
<p class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
<.icon name="hero-building-office" class="mx-auto h-12 w-12 text-gray-400 dark:text-gray-600" />
<h3 class="mt-4 text-lg font-semibold text-gray-900 dark:text-white">No organizations</h3>
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
Get started by creating a new organization.
</p>
<div class="mt-6">

View file

@ -11,7 +11,7 @@
do: ~p"/sites/#{@site.id}",
else: ~p"/sites"
}
class="inline-flex items-center gap-1 text-sm text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100"
class="inline-flex items-center gap-1 text-sm text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
<.icon name="hero-arrow-left" class="h-4 w-4" />
{if @live_action == :edit, do: "Back to Site", else: "Back to Sites"}
@ -33,14 +33,14 @@
<div class="mb-4">
<label>
<span class="block text-sm font-medium text-zinc-900 dark:text-zinc-100 mb-2">
<span class="block text-sm font-medium text-gray-900 dark:text-white mb-2">
Parent Site
<span class="text-zinc-400 dark:text-zinc-500 font-normal">(optional)</span>
<span class="text-gray-400 dark:text-gray-500 font-normal">(optional)</span>
</span>
<select
id={@form[:parent_site_id].id}
name={@form[:parent_site_id].name}
class="block w-full rounded-lg border-0 py-2 px-3 text-zinc-900 shadow-sm ring-1 ring-inset ring-zinc-300 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6 dark:bg-zinc-800 dark:text-zinc-100 dark:ring-zinc-700 dark:focus:ring-blue-500"
class="block w-full rounded-lg border-0 py-2 px-3 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6 dark:bg-gray-800/50 dark:text-white dark:ring-white/10 dark:focus:ring-blue-500"
>
<option value="">No parent site</option>
{Phoenix.HTML.Form.options_for_select(
@ -53,29 +53,29 @@
<div class="mb-4">
<label>
<span class="block text-sm font-medium text-zinc-900 dark:text-zinc-100 mb-2">
Location <span class="text-zinc-400 dark:text-zinc-500 font-normal">(optional)</span>
<span class="block text-sm font-medium text-gray-900 dark:text-white mb-2">
Location <span class="text-gray-400 dark:text-gray-500 font-normal">(optional)</span>
</span>
<input
type="text"
id={@form[:location].id}
name={@form[:location].name}
value={@form[:location].value}
class="block w-full rounded-lg border-0 py-2 px-3 text-zinc-900 shadow-sm ring-1 ring-inset ring-zinc-300 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6 dark:bg-zinc-800 dark:text-zinc-100 dark:ring-zinc-700 dark:focus:ring-blue-500"
class="block w-full rounded-lg border-0 py-2 px-3 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6 dark:bg-gray-800/50 dark:text-white dark:ring-white/10 dark:focus:ring-blue-500"
/>
</label>
</div>
<div class="mb-4">
<label>
<span class="block text-sm font-medium text-zinc-900 dark:text-zinc-100 mb-2">
<span class="block text-sm font-medium text-gray-900 dark:text-white mb-2">
Description
<span class="text-zinc-400 dark:text-zinc-500 font-normal">(optional)</span>
<span class="text-gray-400 dark:text-gray-500 font-normal">(optional)</span>
</span>
<textarea
id={@form[:description].id}
name={@form[:description].name}
class="block w-full rounded-lg border-0 py-2 px-3 text-zinc-900 shadow-sm ring-1 ring-inset ring-zinc-300 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6 dark:bg-zinc-800 dark:text-zinc-100 dark:ring-zinc-700 dark:focus:ring-blue-500"
class="block w-full rounded-lg border-0 py-2 px-3 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6 dark:bg-gray-800/50 dark:text-white dark:ring-white/10 dark:focus:ring-blue-500"
>{Phoenix.HTML.Form.normalize_value("textarea", @form[:description].value)}</textarea>
</label>
</div>
@ -84,9 +84,9 @@
<div class="mt-6 border-t pt-6">
<h3 class="text-base font-medium mb-4">
Agent Configuration
<span class="text-zinc-400 dark:text-zinc-500 font-normal">(optional)</span>
<span class="text-gray-400 dark:text-gray-500 font-normal">(optional)</span>
</h3>
<p class="text-sm text-zinc-600 dark:text-zinc-400 mb-4">
<p class="text-sm text-gray-600 dark:text-gray-400 mb-4">
Set a default agent for SNMP polling at this site. This will override the organization default for all devices at this site. Leave blank to inherit from organization.
</p>
@ -123,12 +123,12 @@
</div>
<% else %>
<%= if Map.get(assigns, :org_agent) do %>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400 flex items-center gap-1">
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1">
<.icon name="hero-building-office-2" class="h-4 w-4" />
Currently inheriting organization default: <strong>{@org_agent.name}</strong>
</p>
<% else %>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Set a default agent for all devices at this site. Device can override this setting individually.
</p>
<% end %>
@ -139,9 +139,9 @@
<div class="mt-6 border-t pt-6">
<h3 class="text-base font-medium mb-4">
SNMP Configuration
<span class="text-zinc-400 dark:text-zinc-500 font-normal">(optional)</span>
<span class="text-gray-400 dark:text-gray-500 font-normal">(optional)</span>
</h3>
<p class="text-sm text-zinc-600 dark:text-zinc-400 mb-4">
<p class="text-sm text-gray-600 dark:text-gray-400 mb-4">
Override organization SNMP defaults for all devices at this site. Leave blank to inherit from organization.
</p>
@ -187,9 +187,9 @@
</.form>
<%= if @live_action == :edit do %>
<div class="mt-12 pt-8 border-t border-zinc-200 dark:border-zinc-800">
<div class="mt-12 pt-8 border-t border-gray-200 dark:border-white/10">
<h3 class="text-lg font-semibold text-red-600 dark:text-red-500 mb-4">Danger Zone</h3>
<p class="text-sm text-zinc-600 dark:text-zinc-400 mb-4">
<p class="text-sm text-gray-600 dark:text-gray-400 mb-4">
Once you delete a site, there is no going back. This will also delete all devices at this site.
</p>
<.button

View file

@ -19,10 +19,10 @@
<div class="text-center py-16">
<.icon
name="hero-building-office"
class="mx-auto h-12 w-12 text-zinc-400 dark:text-zinc-600"
class="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500"
/>
<h3 class="mt-4 text-lg font-semibold text-zinc-900 dark:text-zinc-100">No sites</h3>
<p class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
<h3 class="mt-4 text-lg font-semibold text-gray-900 dark:text-white">No sites</h3>
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
Get started by creating your first site.
</p>
<div class="mt-6">
@ -36,16 +36,16 @@
<.link
:for={site <- @sites}
navigate={~p"/sites/#{site.id}"}
class="relative overflow-hidden rounded-lg border border-zinc-200 bg-white p-6 shadow-sm hover:shadow-md transition-shadow dark:border-zinc-800 dark:bg-zinc-900 cursor-pointer"
class="relative overflow-hidden rounded-lg border border-gray-200 bg-white p-6 shadow-sm hover:shadow-md transition-shadow dark:border-white/10 dark:bg-gray-800/50 cursor-pointer"
>
<h3 class="text-xl font-semibold text-zinc-900 dark:text-zinc-100">{site.name}</h3>
<h3 class="text-xl font-semibold text-gray-900 dark:text-white">{site.name}</h3>
<%= if site.location do %>
<p class="mt-2 flex items-center gap-1.5 text-sm text-zinc-600 dark:text-zinc-400">
<p class="mt-2 flex items-center gap-1.5 text-sm text-gray-600 dark:text-gray-400">
<.icon name="hero-map-pin" class="h-4 w-4" /> {site.location}
</p>
<% end %>
<%= if site.parent_site do %>
<p class="mt-2 text-xs text-zinc-500 dark:text-zinc-500">
<p class="mt-2 text-xs text-gray-500 dark:text-gray-500">
Parent: {site.parent_site.name}
</p>
<% end %>

View file

@ -26,11 +26,11 @@
<div class="mt-8 grid gap-6 md:grid-cols-2">
<div>
<h3 class="text-lg font-semibold mb-4 text-zinc-900 dark:text-zinc-100">Site Details</h3>
<h3 class="text-lg font-semibold mb-4 text-gray-900 dark:text-white">Site Details</h3>
<dl class="space-y-4">
<%= if @site.parent_site do %>
<div>
<dt class="text-sm font-medium text-zinc-600 dark:text-zinc-400">Parent Site</dt>
<dt class="text-sm font-medium text-gray-600 dark:text-gray-400">Parent Site</dt>
<dd class="mt-1">
<.link
navigate={~p"/sites/#{@site.parent_site.id}"}
@ -43,21 +43,21 @@
<% end %>
<%= if @site.location do %>
<div>
<dt class="text-sm font-medium text-zinc-600 dark:text-zinc-400">Location</dt>
<dd class="mt-1 text-zinc-900 dark:text-zinc-100">{@site.location}</dd>
<dt class="text-sm font-medium text-gray-600 dark:text-gray-400">Location</dt>
<dd class="mt-1 text-gray-900 dark:text-white">{@site.location}</dd>
</div>
<% end %>
<%= if @site.description do %>
<div>
<dt class="text-sm font-medium text-zinc-600 dark:text-zinc-400">Description</dt>
<dd class="mt-1 text-zinc-900 dark:text-zinc-100">{@site.description}</dd>
<dt class="text-sm font-medium text-gray-600 dark:text-gray-400">Description</dt>
<dd class="mt-1 text-gray-900 dark:text-white">{@site.description}</dd>
</div>
<% end %>
</dl>
<%= if @site.child_sites != [] do %>
<div class="mt-6">
<h4 class="text-sm font-semibold mb-3 text-zinc-900 dark:text-zinc-100">Child Sites</h4>
<h4 class="text-sm font-semibold mb-3 text-gray-900 dark:text-white">Child Sites</h4>
<ul class="space-y-2">
<li :for={child <- @site.child_sites}>
<.link
@ -74,7 +74,7 @@
<div>
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-semibold text-zinc-900 dark:text-zinc-100">Device</h3>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">Device</h3>
<.button
navigate={~p"/devices/new?site_id=#{@site.id}"}
variant="primary"
@ -84,15 +84,15 @@
</div>
<%= if @device == [] do %>
<div class="rounded-lg border-2 border-dashed border-zinc-300 bg-zinc-50 p-8 text-center dark:border-zinc-700 dark:bg-zinc-900">
<.icon name="hero-server" class="mx-auto h-12 w-12 text-zinc-400 dark:text-zinc-600" />
<h4 class="mt-4 text-base font-semibold text-zinc-900 dark:text-zinc-100">
<div class="rounded-lg border-2 border-dashed border-gray-300 bg-gray-50 p-8 text-center dark:border-white/20 dark:bg-gray-800/50">
<.icon name="hero-server" class="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500" />
<h4 class="mt-4 text-base font-semibold text-gray-900 dark:text-white">
Add your first device
</h4>
<p class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
Start monitoring by adding network devices to this site.
</p>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
You can add routers, switches, servers, or any device with an IP address.
</p>
<div class="mt-6">
@ -109,11 +109,11 @@
<.link
:for={eq <- @device}
navigate={~p"/devices/#{eq.id}"}
class="flex items-center justify-between rounded-lg border border-zinc-200 bg-white p-4 dark:border-zinc-800 dark:bg-zinc-900 hover:border-zinc-300 dark:hover:border-zinc-700 hover:bg-zinc-50 dark:hover:bg-zinc-800 transition-colors cursor-pointer"
class="flex items-center justify-between rounded-lg border border-gray-200 bg-white p-4 dark:border-white/10 dark:bg-gray-800/50 hover:border-gray-300 dark:hover:border-white/20 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors cursor-pointer"
>
<div>
<p class="font-medium text-zinc-900 dark:text-zinc-100">{eq.name}</p>
<p class="text-sm text-zinc-600 dark:text-zinc-400">{eq.ip_address}</p>
<p class="font-medium text-gray-900 dark:text-white">{eq.name}</p>
<p class="text-sm text-gray-600 dark:text-gray-400">{eq.ip_address}</p>
</div>
<span class={[
"inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium",
@ -121,7 +121,7 @@
"bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200",
eq.status == :down && "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200",
eq.status == :unknown &&
"bg-zinc-100 text-zinc-800 dark:bg-zinc-800 dark:text-zinc-200"
"bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-200"
]}>
{eq.status |> to_string() |> String.upcase()}
</span>
@ -133,9 +133,9 @@
<!-- Latency Chart -->
<%= if @latency_chart_data do %>
<div class="mt-8">
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700">
<div class="px-4 py-3 border-b border-zinc-200 dark:border-zinc-700">
<h3 class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10">
<div class="px-4 py-3 border-b border-gray-200 dark:border-white/10">
<h3 class="text-sm font-semibold text-gray-900 dark:text-white">
Site Latency - Last 24 Hours
</h3>
</div>

View file

@ -916,7 +916,7 @@ defmodule ToweropsWeb.UserSettingsLive do
<div class="flex min-h-screen items-end justify-center px-4 pb-20 pt-4 text-center sm:block sm:p-0">
<div
phx-click="cancel_add_token"
class="fixed inset-0 z-0 bg-zinc-500 bg-opacity-75 transition-opacity dark:bg-zinc-950 dark:bg-opacity-75"
class="fixed inset-0 z-0 bg-gray-500 bg-opacity-75 transition-opacity dark:bg-gray-950 dark:bg-opacity-75"
aria-hidden="true"
>
</div>
@ -927,7 +927,7 @@ defmodule ToweropsWeb.UserSettingsLive do
&#8203;
</span>
<div class="relative z-10 inline-block transform overflow-hidden rounded-lg bg-white px-4 pb-4 pt-5 text-left align-bottom shadow-xl transition-all dark:bg-zinc-900 sm:my-8 sm:w-full sm:max-w-lg sm:p-6 sm:align-middle">
<div class="relative z-10 inline-block transform overflow-hidden rounded-lg bg-white px-4 pb-4 pt-5 text-left align-bottom shadow-xl transition-all dark:bg-gray-800/95 sm:my-8 sm:w-full sm:max-w-lg sm:p-6 sm:align-middle">
<.form for={%{}} as={:token} phx-submit="create_api_token">
<div>
<div class="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-blue-100 dark:bg-blue-900">
@ -935,13 +935,13 @@ defmodule ToweropsWeb.UserSettingsLive do
</div>
<div class="mt-3 text-center sm:mt-5">
<h3
class="text-lg font-semibold leading-6 text-zinc-900 dark:text-zinc-100"
class="text-lg font-semibold leading-6 text-gray-900 dark:text-white"
id="create-api-token-modal-title"
>
Create API Token
</h3>
<div class="mt-2">
<p class="text-sm text-zinc-500 dark:text-zinc-400">
<p class="text-sm text-gray-500 dark:text-gray-400">
Give this token a name and select the organization it will have access to.
</p>
</div>
@ -990,7 +990,7 @@ defmodule ToweropsWeb.UserSettingsLive do
<button
type="button"
phx-click="cancel_add_token"
class="mt-3 inline-flex w-full justify-center rounded-lg bg-white px-3 py-2 text-sm font-semibold text-zinc-900 shadow-sm ring-1 ring-inset ring-zinc-300 hover:bg-zinc-50 dark:bg-zinc-800 dark:text-zinc-100 dark:ring-zinc-700 dark:hover:bg-zinc-700 sm:col-start-1 sm:mt-0"
class="mt-3 inline-flex w-full justify-center rounded-lg bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 dark:bg-gray-800/50 dark:text-white dark:ring-white/10 dark:hover:bg-gray-800 sm:col-start-1 sm:mt-0"
>
Cancel
</button>
@ -1013,7 +1013,7 @@ defmodule ToweropsWeb.UserSettingsLive do
<div class="flex min-h-screen items-end justify-center px-4 pb-20 pt-4 text-center sm:block sm:p-0">
<div
phx-click="close_token_modal"
class="fixed inset-0 z-0 bg-zinc-500 bg-opacity-75 transition-opacity dark:bg-zinc-950 dark:bg-opacity-75"
class="fixed inset-0 z-0 bg-gray-500 bg-opacity-75 transition-opacity dark:bg-gray-950 dark:bg-opacity-75"
aria-hidden="true"
>
</div>
@ -1024,7 +1024,7 @@ defmodule ToweropsWeb.UserSettingsLive do
&#8203;
</span>
<div class="relative z-10 inline-block transform overflow-hidden rounded-lg bg-white px-4 pb-4 pt-5 text-left align-bottom shadow-xl transition-all dark:bg-zinc-900 sm:my-8 sm:w-full sm:max-w-lg sm:p-6 sm:align-middle">
<div class="relative z-10 inline-block transform overflow-hidden rounded-lg bg-white px-4 pb-4 pt-5 text-left align-bottom shadow-xl transition-all dark:bg-gray-800/95 sm:my-8 sm:w-full sm:max-w-lg sm:p-6 sm:align-middle">
<div>
<div class="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-green-100 dark:bg-green-900">
<.icon name="hero-check" class="h-6 w-6 text-green-600 dark:text-green-400" />
@ -1032,18 +1032,18 @@ defmodule ToweropsWeb.UserSettingsLive do
<div class="mt-3 text-center sm:mt-5">
<h3
id="token-success-modal-title"
class="text-lg font-semibold leading-6 text-zinc-900 dark:text-zinc-100"
class="text-lg font-semibold leading-6 text-gray-900 dark:text-white"
>
API Token Created
</h3>
<div class="mt-2">
<p class="text-sm text-zinc-500 dark:text-zinc-400">
<p class="text-sm text-gray-500 dark:text-gray-400">
Copy this token now. You won't be able to see it again.
</p>
</div>
<div class="mt-4">
<div class="rounded-lg bg-zinc-50 p-3 dark:bg-zinc-800">
<code class="text-sm text-zinc-900 dark:text-zinc-100 break-all">
<div class="rounded-lg bg-gray-50 p-3 dark:bg-gray-800/50">
<code class="text-sm text-gray-900 dark:text-white break-all">
{@created_token}
</code>
</div>
@ -1074,7 +1074,7 @@ defmodule ToweropsWeb.UserSettingsLive do
>
<div class="flex min-h-screen items-end justify-center px-4 pb-20 pt-4 text-center sm:block sm:p-0">
<div
class="fixed inset-0 z-0 bg-zinc-500 bg-opacity-75 transition-opacity dark:bg-zinc-950 dark:bg-opacity-75"
class="fixed inset-0 z-0 bg-gray-500 bg-opacity-75 transition-opacity dark:bg-gray-950 dark:bg-opacity-75"
aria-hidden="true"
>
</div>
@ -1085,20 +1085,20 @@ defmodule ToweropsWeb.UserSettingsLive do
&#8203;
</span>
<div class="relative z-10 inline-block transform overflow-hidden rounded-lg bg-white px-4 pb-4 pt-5 text-left align-bottom shadow-xl transition-all dark:bg-zinc-900 sm:my-8 sm:w-full sm:max-w-lg sm:p-6 sm:align-middle">
<div class="relative z-10 inline-block transform overflow-hidden rounded-lg bg-white px-4 pb-4 pt-5 text-left align-bottom shadow-xl transition-all dark:bg-gray-800/95 sm:my-8 sm:w-full sm:max-w-lg sm:p-6 sm:align-middle">
<div>
<div class="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-blue-100 dark:bg-blue-900">
<.icon name="hero-key" class="h-6 w-6 text-blue-600 dark:text-blue-400" />
</div>
<div class="mt-3 text-center sm:mt-5">
<h3
class="text-lg font-semibold leading-6 text-zinc-900 dark:text-zinc-100"
class="text-lg font-semibold leading-6 text-gray-900 dark:text-white"
id="add-passkey-modal-title"
>
Add Passkey
</h3>
<div class="mt-2">
<p class="text-sm text-zinc-500 dark:text-zinc-400">
<p class="text-sm text-gray-500 dark:text-gray-400">
Give this passkey a name to help you identify it later (e.g., "MacBook Touch ID", "iPhone").
</p>
</div>
@ -1107,7 +1107,7 @@ defmodule ToweropsWeb.UserSettingsLive do
type="text"
id="passkey-name-input"
placeholder="e.g., MacBook Touch ID"
class="block w-full rounded-lg border-zinc-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-100 sm:text-sm"
class="block w-full rounded-lg border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-white/10 dark:bg-gray-800/50 dark:text-white sm:text-sm"
/>
</div>
<div
@ -1129,7 +1129,7 @@ defmodule ToweropsWeb.UserSettingsLive do
<button
type="button"
id="cancel-add-passkey"
class="mt-3 inline-flex w-full justify-center rounded-lg bg-white px-3 py-2 text-sm font-semibold text-zinc-900 shadow-sm ring-1 ring-inset ring-zinc-300 hover:bg-zinc-50 dark:bg-zinc-800 dark:text-zinc-100 dark:ring-zinc-700 dark:hover:bg-zinc-700 sm:col-start-1 sm:mt-0"
class="mt-3 inline-flex w-full justify-center rounded-lg bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 dark:bg-gray-800/50 dark:text-white dark:ring-white/10 dark:hover:bg-gray-800 sm:col-start-1 sm:mt-0"
>
Cancel
</button>