towerops/lib/towerops_web/live/device_live/index.html.heex

273 lines
10 KiB
Text

<Layouts.authenticated
flash={@flash}
current_scope={@current_scope}
current_organization={@current_organization}
active_page="devices"
timezone={@timezone}
>
<.header>
{@page_title}
<:subtitle>Monitor and manage all your network devices</:subtitle>
<:actions>
<%= if @device != [] do %>
<.button
type="button"
phx-click="force_rediscover_all"
data-confirm="This will trigger SNMP discovery for all SNMP-enabled devices. Continue?"
>
<.icon name="hero-magnifying-glass" class="h-4 w-4" /> Force Rediscover All
</.button>
<% end %>
<.button
:if={@has_sites}
navigate={~p"/devices/new"}
variant="primary"
>
<.icon name="hero-plus" class="h-5 w-5" /> New Device
</.button>
</:actions>
</.header>
<!-- Tab Navigation -->
<div class="border-b border-gray-200 dark:border-white/10 mb-6">
<nav class="-mb-px flex space-x-8">
<.link
patch={~p"/devices?tab=existing"}
class={[
"whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm",
if @active_tab == "existing" do
"border-blue-500 text-blue-600 dark:text-blue-400"
else
"border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300"
end
]}
>
Existing Devices
</.link>
<.link
patch={~p"/devices?tab=discovered"}
class={[
"whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm",
if @active_tab == "discovered" do
"border-blue-500 text-blue-600 dark:text-blue-400"
else
"border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300"
end
]}
>
Discovered Devices
<%= if @discovered_devices != [] do %>
<span class="ml-2 inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200">
{length(@discovered_devices)}
</span>
<% end %>
</.link>
</nav>
</div>
<%= case @active_tab do %>
<% "existing" -> %>
<%= if !@has_sites do %>
<div class="text-center py-16">
<.icon
name="hero-building-office"
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">
Create a site first
</h3>
<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-gray-600 dark:text-gray-400">
Sites help you organize your devices by physical location.
</p>
<div class="mt-6">
<.button navigate={~p"/sites/new"} variant="primary">
<.icon name="hero-plus" class="h-5 w-5" /> Create Your First Site
</.button>
</div>
</div>
<% else %>
<%= if @device == [] do %>
<div class="text-center py-16">
<.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">
<.button
navigate={~p"/devices/new"}
variant="primary"
>
<.icon name="hero-plus" class="h-5 w-5" /> New Device
</.button>
</div>
</div>
<% else %>
<.table
id="devices"
rows={@device}
row_click={
fn eq ->
JS.navigate(~p"/devices/#{eq.id}")
end
}
>
<:col :let={eq} label="Name">
<span class="font-medium">{eq.name}</span>
</:col>
<:col :let={eq} label="IP Address">
<span class="font-mono text-sm">{eq.ip_address}</span>
</:col>
<:col :let={eq} label="Site">
<.link
navigate={~p"/sites/#{eq.site.id}"}
class="text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300"
>
{eq.site.name}
</.link>
</:col>
<:col :let={eq} label="Status">
<span class={[
"inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium",
eq.status == :up &&
"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-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">
<.timestamp
datetime={eq.last_checked_at}
timezone={@timezone}
class="text-sm text-gray-600 dark:text-gray-400"
/>
</:col>
</.table>
<% end %>
<% end %>
<% "discovered" -> %>
<%= if @discovered_devices == [] do %>
<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-magnifying-glass" 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 undiscovered devices
</h3>
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
All discovered devices have been added, or no devices have been discovered yet via LLDP, CDP, or ARP.
</p>
</div>
</div>
<% else %>
<.table id="discovered-devices" rows={@discovered_devices}>
<:col :let={discovered} label="Identifier">
<%= case discovered.identifier.type do %>
<% :mac -> %>
<div>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200">
MAC
</span>
<span class="ml-2 font-mono text-sm text-gray-900 dark:text-white">
{discovered.identifier.value}
</span>
</div>
<% :ip -> %>
<div>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200">
IP
</span>
<span class="ml-2 font-mono text-sm text-gray-900 dark:text-white">
{discovered.identifier.value}
</span>
</div>
<% :hostname -> %>
<div>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200">
HOST
</span>
<span class="ml-2 text-sm text-gray-900 dark:text-white">
{discovered.identifier.value}
</span>
</div>
<% _ -> %>
<span class="text-sm text-gray-500">Unknown</span>
<% end %>
</:col>
<:col :let={discovered} label="Hostname">
<%= if discovered.hostname do %>
<span class="text-sm font-medium text-gray-900 dark:text-white">
{discovered.hostname}
</span>
<% else %>
<span class="text-sm text-gray-400">-</span>
<% end %>
</:col>
<:col :let={discovered} label="Type">
<div class="flex items-center gap-2">
<.icon
name={device_type_icon(discovered.device_type)}
class="h-4 w-4 text-gray-500"
/>
<span class="text-sm text-gray-900 dark:text-white">
{device_type_label(discovered.device_type)}
</span>
</div>
</:col>
<:col :let={discovered} label="Manufacturer">
<%= if discovered.manufacturer do %>
<span class="text-sm text-gray-900 dark:text-white">
{discovered.manufacturer}
</span>
<% else %>
<span class="text-sm text-gray-400">-</span>
<% end %>
</:col>
<:col :let={discovered} label="Discovered By">
<div class="text-sm text-gray-600 dark:text-gray-400">
<%= if length(discovered.discovered_by) == 1 do %>
<% [first] = discovered.discovered_by %>
<.link
navigate={~p"/devices/#{first.device_id}"}
class="text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300"
>
{first.device_name}
</.link>
<span class="text-xs text-gray-500"> ({first.interface})</span>
<% else %>
<span>{length(discovered.discovered_by)} devices</span>
<% end %>
</div>
</:col>
<:col :let={discovered} label="Last Seen">
<.timestamp
datetime={discovered.last_seen}
timezone={@timezone}
class="text-sm text-gray-600 dark:text-gray-400"
/>
</:col>
<:col :let={discovered} label="Actions">
<.button
phx-click="add_discovered_device"
phx-value-identifier={Jason.encode!(discovered.identifier)}
variant="primary"
>
<.icon name="hero-plus" class="h-3 w-3" /> Add Device
</.button>
</:col>
</.table>
<% end %>
<% end %>
</Layouts.authenticated>