Format traffic values in Mbps/Gbps and fix column layout

This commit is contained in:
Graham McIntire 2026-01-05 13:38:07 -06:00
parent a57dfd2e26
commit b6abe23493
No known key found for this signature in database
2 changed files with 150 additions and 123 deletions

View file

@ -76,11 +76,27 @@ const SensorChart = {
pointHoverRadius: 4,
}))
// Format bits per second into human-readable units
const formatBps = (bps) => {
if (bps >= 1_000_000_000) {
return (bps / 1_000_000_000).toFixed(2) + ' Gbps'
} else if (bps >= 1_000_000) {
return (bps / 1_000_000).toFixed(2) + ' Mbps'
} else if (bps >= 1_000) {
return (bps / 1_000).toFixed(2) + ' Kbps'
} else {
return bps.toFixed(2) + ' bps'
}
}
// Y-axis configuration
const yAxisConfig = autoScale ? {
beginAtZero: showZeroLine,
ticks: {
callback: function(value) {
if (unit === 'bps') {
return formatBps(value)
}
return value + unit
}
},
@ -105,6 +121,9 @@ const SensorChart = {
max: 100,
ticks: {
callback: function(value) {
if (unit === 'bps') {
return formatBps(value)
}
return value + unit
}
},
@ -145,6 +164,9 @@ const SensorChart = {
})
},
label: function(context) {
if (unit === 'bps') {
return context.dataset.label + ': ' + formatBps(context.parsed.y)
}
return context.dataset.label + ': ' + context.parsed.y.toFixed(1) + unit
}
}

View file

@ -71,141 +71,146 @@
<%= case @active_tab do %>
<% "overview" -> %>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 items-start">
<!-- 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">
Device Information
</h3>
</div>
<div class="p-4">
<dl class="space-y-3">
<%= if @snmp_device do %>
<!-- 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">
Device Information
</h3>
</div>
<div class="p-4">
<dl class="space-y-3">
<%= if @snmp_device do %>
<div class="flex justify-between py-2 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">
{@snmp_device.sys_name || @equipment.name}
</dd>
</div>
<div class="flex justify-between py-2 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">
{@equipment.ip_address}
</dd>
</div>
<div class="flex justify-between py-2 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">
{@snmp_device.model || "N/A"}
</dd>
</div>
<div class="flex justify-between py-2 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">
{if @snmp_device.manufacturer && @snmp_device.firmware_version do
"#{@snmp_device.manufacturer} #{@snmp_device.firmware_version}"
else
@snmp_device.sys_descr || "N/A"
end}
</dd>
</div>
<div class="flex justify-between py-2 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">
{@snmp_device.sys_object_id || "N/A"}
</dd>
</div>
<div class="flex justify-between py-2 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">
{@snmp_device.sys_contact || "N/A"}
</dd>
</div>
<div class="flex justify-between py-2 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">
{@snmp_device.sys_location || "N/A"}
</dd>
</div>
<div class="flex justify-between py-2 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">
{format_uptime(@snmp_device.sys_uptime)}
</dd>
</div>
<% else %>
<div class="flex justify-between py-2 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">
{@equipment.name}
</dd>
</div>
<div class="flex justify-between py-2 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">
{@equipment.ip_address}
</dd>
</div>
<% end %>
<div class="flex justify-between py-2 border-b border-zinc-100 dark:border-zinc-800">
<dt class="text-sm text-zinc-600 dark:text-zinc-400">System Name</dt>
<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">
{@snmp_device.sys_name || @equipment.name}
{format_device_age(@equipment.inserted_at)}
</dd>
</div>
<div class="flex justify-between py-2 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">
{@equipment.ip_address}
</dd>
</div>
<div class="flex justify-between py-2 border-b border-zinc-100 dark:border-zinc-800">
<dt class="text-sm text-zinc-600 dark:text-zinc-400">Hardware</dt>
<div class="flex justify-between py-2">
<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">
{@snmp_device.model || "N/A"}
</dd>
</div>
<div class="flex justify-between py-2 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">
{if @snmp_device.manufacturer && @snmp_device.firmware_version do
"#{@snmp_device.manufacturer} #{@snmp_device.firmware_version}"
{if @equipment.last_discovery_at do
format_device_age(@equipment.last_discovery_at)
else
@snmp_device.sys_descr || "N/A"
"Never"
end}
</dd>
</div>
<div class="flex justify-between py-2 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">
{@snmp_device.sys_object_id || "N/A"}
</dd>
</div>
<div class="flex justify-between py-2 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">
{@snmp_device.sys_contact || "N/A"}
</dd>
</div>
<div class="flex justify-between py-2 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">
{@snmp_device.sys_location || "N/A"}
</dd>
</div>
<div class="flex justify-between py-2 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">
{format_uptime(@snmp_device.sys_uptime)}
</dd>
</div>
<% else %>
<div class="flex justify-between py-2 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">
{@equipment.name}
</dd>
</div>
<div class="flex justify-between py-2 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">
{@equipment.ip_address}
</dd>
</div>
<% end %>
<div class="flex justify-between py-2 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">
{format_device_age(@equipment.inserted_at)}
</dd>
</div>
<div class="flex justify-between py-2">
<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">
{if @equipment.last_discovery_at do
format_device_age(@equipment.last_discovery_at)
else
"Never"
end}
</dd>
</div>
</dl>
</div>
</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">
<.link
navigate={
~p"/orgs/#{@current_organization.slug}/equipment/#{@equipment.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"
>
<div class="flex items-center justify-between">
<h3 class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">
Overall Traffic (24 Hours)
</h3>
<.icon name="hero-arrow-right" class="h-4 w-4 text-zinc-400" />
</div>
</.link>
<div class="p-4">
<div
id="traffic-chart"
phx-hook="SensorChart"
data-chart={@traffic_chart_data}
data-show-zero-line="true"
style="height: 300px;"
>
<canvas></canvas>
</div>
</dl>
</div>
</div>
<% end %>
<!-- Graphs and Metrics -->
<!-- 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">
<.link
navigate={
~p"/orgs/#{@current_organization.slug}/equipment/#{@equipment.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"
>
<div class="flex items-center justify-between">
<h3 class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">
Overall Traffic (24 Hours)
</h3>
<.icon name="hero-arrow-right" class="h-4 w-4 text-zinc-400" />
</div>
</.link>
<div class="p-4">
<div
id="traffic-chart"
phx-hook="SensorChart"
data-chart={@traffic_chart_data}
data-unit="bps"
data-auto-scale="true"
data-show-zero-line="true"
style="height: 300px;"
>
<canvas></canvas>
</div>
</div>
</div>
<% end %>
</div>
<!-- Right Column: Graphs and Metrics -->
<div class="space-y-6">
<!-- CPU Usage Chart -->
<%= if @cpu_chart_data do %>