260 lines
10 KiB
Text
260 lines
10 KiB
Text
<Layouts.authenticated
|
|
flash={@flash}
|
|
current_scope={@current_scope}
|
|
current_organization={@current_organization}
|
|
active_page="network-map"
|
|
timezone={@timezone}
|
|
>
|
|
<.header>
|
|
<span class="flex items-center gap-2">
|
|
Network Map
|
|
<span class="inline-flex items-center rounded-full bg-blue-50 px-2 py-0.5 text-xs font-medium text-blue-700 ring-1 ring-inset ring-blue-700/10 dark:bg-blue-400/10 dark:text-blue-400 dark:ring-blue-400/30">
|
|
Experimental
|
|
</span>
|
|
</span>
|
|
<:subtitle>Visual topology of your network infrastructure</:subtitle>
|
|
<:actions>
|
|
<.button phx-click="refresh_topology" disabled={@loading}>
|
|
<.icon name="hero-arrow-path" class="h-5 w-5" /> Refresh
|
|
</.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"/network-map?tab=added"}
|
|
class={[
|
|
"whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm",
|
|
if @active_tab == "added" 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
|
|
]}
|
|
>
|
|
Added Devices
|
|
</.link>
|
|
|
|
<.link
|
|
patch={~p"/network-map?tab=all"}
|
|
class={[
|
|
"whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm",
|
|
if @active_tab == "all" 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
|
|
]}
|
|
>
|
|
All Devices
|
|
<span class="ml-2 inline-flex items-center rounded-full bg-gray-100 px-2 py-0.5 text-xs font-medium text-gray-700 dark:bg-gray-700 dark:text-gray-300">
|
|
{@topology.stats.discovered_devices}
|
|
</span>
|
|
</.link>
|
|
</nav>
|
|
</div>
|
|
|
|
<%= if @loading do %>
|
|
<div class="flex items-center justify-center h-96">
|
|
<div class="text-center">
|
|
<.icon name="hero-arrow-path" class="h-12 w-12 text-gray-400 animate-spin mx-auto" />
|
|
<p class="mt-4 text-sm text-gray-600 dark:text-gray-400">Loading network topology...</p>
|
|
</div>
|
|
</div>
|
|
<% else %>
|
|
<!-- Stats Bar -->
|
|
<div class="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-5 mb-6">
|
|
<div class="bg-white dark:bg-gray-800 overflow-hidden rounded-lg border border-gray-200 dark:border-white/10">
|
|
<div class="p-5">
|
|
<div class="flex items-center">
|
|
<div class="flex-shrink-0">
|
|
<.icon name="hero-server" class="h-6 w-6 text-gray-400" />
|
|
</div>
|
|
<div class="ml-5 w-0 flex-1">
|
|
<dl>
|
|
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400 truncate">
|
|
Total Devices
|
|
</dt>
|
|
<dd class="text-lg font-medium text-gray-900 dark:text-white">
|
|
{@topology.stats.total_devices}
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-white dark:bg-gray-800 overflow-hidden rounded-lg border border-gray-200 dark:border-white/10">
|
|
<div class="p-5">
|
|
<div class="flex items-center">
|
|
<div class="flex-shrink-0">
|
|
<.icon name="hero-check-circle" class="h-6 w-6 text-green-400" />
|
|
</div>
|
|
<div class="ml-5 w-0 flex-1">
|
|
<dl>
|
|
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400 truncate">
|
|
Added Devices
|
|
</dt>
|
|
<dd class="text-lg font-medium text-gray-900 dark:text-white">
|
|
{@topology.stats.added_devices}
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-white dark:bg-gray-800 overflow-hidden rounded-lg border border-gray-200 dark:border-white/10">
|
|
<div class="p-5">
|
|
<div class="flex items-center">
|
|
<div class="flex-shrink-0">
|
|
<.icon name="hero-magnifying-glass" class="h-6 w-6 text-blue-400" />
|
|
</div>
|
|
<div class="ml-5 w-0 flex-1">
|
|
<dl>
|
|
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400 truncate">
|
|
Discovered
|
|
</dt>
|
|
<dd class="text-lg font-medium text-gray-900 dark:text-white">
|
|
{@topology.stats.discovered_devices}
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-white dark:bg-gray-800 overflow-hidden rounded-lg border border-gray-200 dark:border-white/10">
|
|
<div class="p-5">
|
|
<div class="flex items-center">
|
|
<div class="flex-shrink-0">
|
|
<.icon name="hero-link" class="h-6 w-6 text-purple-400" />
|
|
</div>
|
|
<div class="ml-5 w-0 flex-1">
|
|
<dl>
|
|
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400 truncate">
|
|
Connections
|
|
</dt>
|
|
<dd class="text-lg font-medium text-gray-900 dark:text-white">
|
|
{@topology.stats.total_links}
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-white dark:bg-gray-800 overflow-hidden rounded-lg border border-gray-200 dark:border-white/10">
|
|
<div class="p-5">
|
|
<div class="flex items-center">
|
|
<div class="flex-shrink-0">
|
|
<.icon name="hero-squares-2x2" class="h-6 w-6 text-orange-400" />
|
|
</div>
|
|
<div class="ml-5 w-0 flex-1">
|
|
<dl>
|
|
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400 truncate">
|
|
Subnets
|
|
</dt>
|
|
<dd class="text-lg font-medium text-gray-900 dark:text-white">
|
|
{@topology.stats.total_subnets}
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Network Map Container -->
|
|
<div class="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-white/10 overflow-hidden">
|
|
<div class="p-4 border-b border-gray-200 dark:border-white/10">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<h3 class="text-sm font-medium text-gray-900 dark:text-white">
|
|
Topology Visualization
|
|
</h3>
|
|
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
|
Click and drag to pan, scroll to zoom, click nodes for details
|
|
</p>
|
|
</div>
|
|
<div class="flex items-center space-x-2">
|
|
<span class="text-xs text-gray-500 dark:text-gray-400">
|
|
Last updated: <.timestamp datetime={@topology.last_updated} timezone={@timezone} />
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Cytoscape Container -->
|
|
<div
|
|
id="cy-container"
|
|
phx-hook="NetworkMap"
|
|
class="w-full"
|
|
style="height: 600px;"
|
|
data-topology={Jason.encode!(@topology)}
|
|
>
|
|
</div>
|
|
|
|
<!-- Legend -->
|
|
<div class="p-4 border-t border-gray-200 dark:border-white/10 bg-gray-50 dark:bg-gray-900">
|
|
<div class="flex items-center justify-between">
|
|
<div class="flex items-center space-x-6 text-xs">
|
|
<div class="flex items-center space-x-2">
|
|
<div class="w-3 h-3 rounded-full bg-blue-500"></div>
|
|
<span class="text-gray-700 dark:text-gray-300">Router</span>
|
|
</div>
|
|
<div class="flex items-center space-x-2">
|
|
<div class="w-3 h-3 rounded-full bg-purple-500"></div>
|
|
<span class="text-gray-700 dark:text-gray-300">Switch</span>
|
|
</div>
|
|
<div class="flex items-center space-x-2">
|
|
<div class="w-3 h-3 rounded-full bg-green-500"></div>
|
|
<span class="text-gray-700 dark:text-gray-300">Wireless</span>
|
|
</div>
|
|
<div class="flex items-center space-x-2">
|
|
<div class="w-3 h-3 rounded-full bg-orange-500"></div>
|
|
<span class="text-gray-700 dark:text-gray-300">Server</span>
|
|
</div>
|
|
<div class="flex items-center space-x-2">
|
|
<div class="w-3 h-3 rounded-full bg-gray-500"></div>
|
|
<span class="text-gray-700 dark:text-gray-300">Unknown</span>
|
|
</div>
|
|
<div class="flex items-center space-x-2">
|
|
<div class="w-3 h-3 rounded-full border-2 border-dashed border-gray-400"></div>
|
|
<span class="text-gray-700 dark:text-gray-300">Discovered (Not Added)</span>
|
|
</div>
|
|
</div>
|
|
<div class="flex items-center space-x-4 text-xs">
|
|
<div class="flex items-center space-x-2">
|
|
<div class="w-8 h-0.5 bg-green-600"></div>
|
|
<span class="text-gray-700 dark:text-gray-300">Active Link</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Empty State -->
|
|
<%= if @topology.stats.total_devices == 0 do %>
|
|
<div class="text-center py-16">
|
|
<.icon name="hero-map" class="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500" />
|
|
<h3 class="mt-4 text-lg font-semibold text-gray-900 dark:text-white">
|
|
No network topology available
|
|
</h3>
|
|
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
|
|
Add devices with SNMP enabled to start building your network map.
|
|
</p>
|
|
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
|
|
The topology is automatically discovered via LLDP and CDP protocols.
|
|
</p>
|
|
<div class="mt-6">
|
|
<.button navigate={~p"/devices/new"} variant="primary">
|
|
<.icon name="hero-plus" class="h-5 w-5" /> Add Your First Device
|
|
</.button>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
<% end %>
|
|
</Layouts.authenticated>
|