<.link navigate={ if @live_action == :edit, do: ~p"/devices/#{@device.id}", else: ~p"/devices" } 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"}
<.header> {@page_title} <:subtitle> {if @live_action == :new, do: "Add new device to monitor", else: "Update device details"}
<%= if @live_action == :new do %> <% percent = if @device_quota.limit != :unlimited and @device_quota.limit > 0 do (@device_quota.current / @device_quota.limit * 100) |> trunc() else 0 end %> <% badge_class = cond do @current_scope.user.is_superuser -> "bg-blue-50 text-blue-800 dark:bg-blue-900/20 dark:text-blue-400" @device_quota.at_limit -> "bg-red-50 text-red-800 border-red-200 dark:bg-red-900/20 dark:text-red-400 dark:border-red-800" percent >= 90 -> "bg-orange-50 text-orange-800 border-orange-200 dark:bg-orange-900/20 dark:text-orange-400 dark:border-orange-800" percent >= 75 -> "bg-yellow-50 text-yellow-800 border-yellow-200 dark:bg-yellow-900/20 dark:text-yellow-400 dark:border-yellow-800" @device_quota.limit == :unlimited -> "bg-blue-50 text-blue-800 dark:bg-blue-900/20 dark:text-blue-400" true -> "bg-green-50 text-green-800 border-green-200 dark:bg-green-900/20 dark:text-green-400 dark:border-green-800" end %>
<%= cond do %> <% @current_scope.user.is_superuser -> %> {@device_quota.current} devices <% @device_quota.limit == :unlimited -> %> {@device_quota.current} devices <% true -> %> {@device_quota.current}/{@device_quota.limit} devices <% end %>
<% end %>
<%= if @live_action == :new and not @device_quota.at_limit and @device_quota.limit != :unlimited and not @current_scope.user.is_superuser do %> <% remaining = @device_quota.limit - @device_quota.current %> <%= if remaining <= 3 do %>
<.icon name="hero-exclamation-triangle" class="h-5 w-5 text-orange-400" />

Approaching device limit

You have {remaining} {if remaining == 1, do: "slot", else: "slots"} remaining.

<% end %> <% end %>
<.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 />
<.icon name="hero-exclamation-triangle" class="h-5 w-5 flex-shrink-0" />

A device with this IP address already exists: <.link navigate={~p"/devices/#{@duplicate_device.id}"} class="font-medium underline hover:text-amber-900 dark:hover:text-amber-100" > {@duplicate_device.name || @duplicate_device.ip_address}

<.icon name="hero-exclamation-circle" class="h-5 w-5 flex-shrink-0 mt-0.5" />

Non-routable IP address detected

This IP address (private network or CGNAT range) cannot be reached from the cloud. To monitor this device, assign it to a <.link navigate={~p"/agents"} class="font-medium underline" > remote agent deployed on the same network.

<.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, fn agent -> label = if agent.is_cloud_poller, do: "#{agent.name} (Cloud Poller)", else: agent.name {label, agent.id} end) } /> <%= if @live_action == :edit and Map.has_key?(assigns, :agent_source) do %> <%= case @agent_source do %> <% :device -> %>

<.icon name="hero-exclamation-triangle" class="h-4 w-4" /> Overriding site/organization defaults - this device is explicitly assigned

<% :site -> %>

<.icon name="hero-building-office" class="h-4 w-4" /> Inherited from site: {@effective_agent_name}

<% :organization -> %>

<.icon name="hero-building-office-2" class="h-4 w-4" /> Inherited from organization: {@effective_agent_name}

<% :global -> %>

<.icon name="hero-globe-alt" class="h-4 w-4" /> Using global default cloud poller: {@effective_agent_name}

<% :none -> %>

<.icon name="hero-cloud" class="h-4 w-4" /> No agent assigned - cloud polling

<% end %> <% else %>

Assign this device to a remote agent for local SNMP polling. Leave empty to inherit from site or organization defaults.

<% end %> <% end %>

Monitoring Configuration

<%= if @monitoring_mode == "snmp_and_icmp" do %>

Monitor device availability with ICMP pings and collect detailed information via SNMP (interfaces, sensors, system info).

<% else %>

Monitor device availability with ICMP pings only (no SNMP discovery).

<% end %>
<.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 -> %>

<.icon name="hero-exclamation-triangle" class="h-4 w-4" /> Overriding site/organization SNMP defaults

<% :site -> %>

<.icon name="hero-building-office" class="h-4 w-4" /> Inherited from site (v{@effective_snmp_version}, community: {@effective_snmp_community})

<% :organization -> %>

<.icon name="hero-building-office-2" class="h-4 w-4" /> Inherited from organization (v{@effective_snmp_version}, community: {@effective_snmp_community})

<% :default -> %>

<.icon name="hero-information-circle" class="h-4 w-4" /> Using default (v2c, no community set - configure at organization or site level)

<% end %> <% end %> <.input field={@form[:snmp_port]} type="number" label="SNMP Port" min="1" max="65535" value={@form[:snmp_port].value || 161} />
<.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" /> {@snmp_test_result.message}
<.button type="button" phx-click="test_snmp" phx-disable-with="Testing..."> Test SNMP Connection <%= 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 <% end %>
<.button phx-disable-with="Saving..." variant="primary" disabled={@duplicate_device != nil or @non_routable_ip_error} > Save Device <.button navigate={~p"/devices"}>Cancel
<%= if @live_action == :edit do %>

Danger Zone

Once you delete this device, there is no going back. All monitoring history and alerts will be permanently deleted.

<.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
<% end %>