towerops/lib/towerops_web/live/device_live/form.html.heex
Graham McIntire 841cf67e8b
Move SNMP device name help text to placeholder
Changed the help text below the device name field to appear as placeholder
text inside the input field when in SNMP mode
2026-01-17 17:08:47 -06:00

262 lines
10 KiB
Text

<Layouts.authenticated
flash={@flash}
current_scope={@current_scope}
current_organization={@organization}
>
<div class="mb-4">
<.link
navigate={
if @live_action == :edit,
do: ~p"/orgs/#{@organization.slug}/devices/#{@device.id}",
else: ~p"/orgs/#{@organization.slug}/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"
>
<.icon name="hero-arrow-left" class="h-4 w-4" />
{if @live_action == :edit, do: "Back to Device", else: "Back to Device List"}
</.link>
</div>
<.header>
{@page_title}
<:subtitle>
{if @live_action == :new,
do: "Add new device to monitor",
else: "Update device details"}
</:subtitle>
</.header>
<div class="max-w-2xl">
<.form for={@form} id="device-form" phx-change="validate" phx-submit="save">
<.input
field={@form[:name]}
type="text"
label="Device Name"
placeholder={
if @monitoring_mode == "snmp_and_icmp",
do: "Leave blank to automatically populate from SNMP device name (sysName)",
else: nil
}
required={@monitoring_mode == "icmp_only"}
/>
<.input field={@form[:ip_address]} type="text" label="IP Address" required />
<.input
field={@form[:site_id]}
type="select"
label="Site"
required
prompt="Select a site"
options={Enum.map(@available_sites, &{&1.name, &1.id})}
/>
<.input field={@form[:description]} type="textarea" label="Description" />
<.input
field={@form[:check_interval_seconds]}
type="number"
label="Check Interval (seconds)"
min="30"
max="3600"
/>
<.input field={@form[:monitoring_enabled]} type="checkbox" label="Enable Monitoring" />
<%= if @available_agents != [] do %>
<.input
field={@form[:agent_token_id]}
type="select"
label="Remote Agent"
prompt="Inherit from site/organization"
options={Enum.map(@available_agents, &{&1.name, &1.id})}
/>
<%= if @live_action == :edit and Map.has_key?(assigns, :agent_source) do %>
<%= case @agent_source do %>
<% :device -> %>
<p class="mt-1 text-sm text-amber-600 dark:text-amber-400 flex items-center gap-1">
<.icon name="hero-exclamation-triangle" class="h-4 w-4" />
<strong>Overriding</strong> site/organization defaults -
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">
<.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">
<.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">
<.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">
Assign this device to a remote agent for local SNMP polling. Leave empty to inherit from site or organization defaults.
</p>
<% end %>
<% end %>
<div class="mt-8 border-t pt-6">
<h3 class="text-lg font-medium mb-4">Monitoring Configuration</h3>
<!-- Monitoring Mode Tabs -->
<div class="mb-6">
<div class="border-b border-zinc-200 dark:border-zinc-700">
<nav class="-mb-px flex space-x-8" aria-label="Monitoring mode">
<button
type="button"
phx-click="switch_monitoring_mode"
phx-value-mode="snmp_and_icmp"
class={[
"whitespace-nowrap border-b-2 px-1 py-4 text-sm font-medium",
@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"
]}
>
SNMP & ICMP
</button>
<button
type="button"
phx-click="switch_monitoring_mode"
phx-value-mode="icmp_only"
class={[
"whitespace-nowrap border-b-2 px-1 py-4 text-sm font-medium",
@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"
]}
>
ICMP Only
</button>
</nav>
</div>
<div class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
<%= if @monitoring_mode == "snmp_and_icmp" do %>
<p>
Monitor device availability with ICMP pings and collect detailed information via SNMP
(interfaces, sensors, system info).
</p>
<% else %>
<p>Monitor device availability with ICMP pings only (no SNMP discovery).</p>
<% end %>
</div>
</div>
<div
:if={@monitoring_mode == "snmp_and_icmp"}
class="mt-4 space-y-4 pl-6 border-l-2 border-blue-200"
>
<.input
field={@form[:snmp_version]}
type="select"
label="SNMP Version"
prompt="Inherit from site/organization"
options={[{"SNMPv1", "1"}, {"SNMPv2c", "2c"}]}
/>
<.input
field={@form[:snmp_community]}
type="text"
label="Community String"
placeholder="Leave blank to inherit from site/organization"
autocomplete="off"
/>
<%= if @live_action == :edit and Map.has_key?(assigns, :snmp_config_source) do %>
<%= case @snmp_config_source do %>
<% :device -> %>
<p class="text-sm text-amber-600 dark:text-amber-400 flex items-center gap-1">
<.icon name="hero-exclamation-triangle" class="h-4 w-4" />
<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">
<.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">
<.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">
<.icon name="hero-information-circle" class="h-4 w-4" />
Using default (v2c, no community set - configure at organization or site level)
</p>
<% end %>
<% end %>
<.input
field={@form[:snmp_port]}
type="number"
label="SNMP Port"
min="1"
max="65535"
value={@form[:snmp_port].value || 161}
/>
<div
:if={@snmp_test_result}
class="rounded-md p-3"
class={[
@snmp_test_result.success && "bg-green-50 text-green-800",
!@snmp_test_result.success && "bg-red-50 text-red-800"
]}
>
<div class="flex items-center gap-2">
<.icon :if={@snmp_test_result.success} name="hero-check-circle" class="w-5 h-5" />
<.icon :if={!@snmp_test_result.success} name="hero-x-circle" class="w-5 h-5" />
<span class="text-sm font-medium">{@snmp_test_result.message}</span>
</div>
</div>
<div class="flex gap-3">
<.button type="button" phx-click="test_snmp" phx-disable-with="Testing...">
Test SNMP Connection
</.button>
<%= if @live_action == :edit do %>
<.button
type="button"
phx-click="trigger_discovery"
phx-disable-with="Discovering..."
>
<.icon name="hero-magnifying-glass" class="h-4 w-4" /> Rediscover Device
</.button>
<% end %>
</div>
</div>
</div>
<div class="flex gap-3 mt-6">
<.button phx-disable-with="Saving..." variant="primary">Save Device</.button>
<.button navigate={~p"/orgs/#{@organization.slug}/devices"}>Cancel</.button>
</div>
</.form>
<%= if @live_action == :edit do %>
<div class="mt-12 pt-8 border-t border-zinc-200 dark:border-zinc-800">
<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">
Once you delete this device, there is no going back. All monitoring history and alerts will be permanently deleted.
</p>
<.button
phx-click="delete"
data-confirm="Are you sure you want to delete this device? All monitoring history and alerts will be permanently deleted."
variant="danger"
>
<.icon name="hero-trash" class="h-4 w-4" /> Delete Device
</.button>
</div>
<% end %>
</div>
</Layouts.authenticated>