<.header> {@page_title} <:subtitle>{t("Manage remote agents for local SNMP polling")} <:actions> <.button phx-click={JS.show(to: "#new-agent-form")} variant="primary"> <.icon name="hero-plus" class="h-5 w-5" /> New Agent <%= if !@has_agents do %>
<.icon name="hero-server" class="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500" />

{t("No agents")}

{t("Get started by creating your first remote agent.")}

<.button phx-click={JS.show(to: "#new-agent-form")} variant="primary"> <.icon name="hero-plus" class="h-5 w-5" /> New Agent
<% else %>
<.table id="agents-table" rows={@streams.agent_tokens} row_link={fn {_id, agent} -> ~p"/agents/#{agent.id}" end} > <:col :let={{_id, agent}} label={t("Name")}>
{agent.name} <%= if agent.is_cloud_poller do %> <.icon name="hero-cloud" class="h-3 w-3" /> Cloud <% end %> <%= if agent.allow_remote_debug do %> <.icon name="hero-bug-ant" class="h-3 w-3" /> Debug <% end %>
<:col :let={{_id, agent}} label={t("Status")}> <% {status, label} = agent_status(agent) %> {label} <:col :let={{_id, agent}} label={t("Device")}> <% counts = Map.get(@device_counts, agent.id, %{direct: 0, total: 0}) %>
{counts.total} total
{counts.direct} direct <%= if counts.total > counts.direct do %> · {counts.total - counts.direct} inherited <% end %>
<:col :let={{_id, agent}} label={t("Last Seen")}>
<.timestamp datetime={agent.last_seen_at} timezone={@timezone} now={@now} />
<%= if agent.last_seen_at do %>
<.timestamp datetime={agent.last_seen_at} timezone={@timezone} format="absolute" />
<% end %> <%= if agent.last_ip do %>
{agent.last_ip}
<% end %> <:col :let={{_id, agent}} label={t("Version")}> <%= if agent.metadata["version"] do %>
{format_agent_version(agent.metadata["version"])}
<% end %> <:col :let={{_id, agent}} label={t("Created")}>
{ToweropsWeb.TimeHelpers.format_date(agent.inserted_at, @timezone)}
<:action :let={{_id, agent}}> <%= if agent.enabled do %>
<.button type="button" phx-click="show_setup" phx-value-id={agent.id} variant="secondary" > {t("View Setup")} <.button type="button" phx-click="delete_agent" phx-value-id={agent.id} data-confirm={ t( "Are you sure you want to delete this agent? All device assignments will be removed, and devices will fall back to site/organization defaults or cloud polling." ) } variant="danger" > {t("Delete")}
<% else %> Disabled <% end %>
<% end %> <%!-- Cloud Pollers Section (Superadmin Only) --%> <%= if @is_superuser && @has_cloud_pollers do %>

{t("Cloud Pollers")}

{t( "Application-wide agents that can poll devices for any organization. Only visible and manageable by superadmins." )}

<.table id="cloud-pollers-table" rows={@streams.cloud_pollers} row_link={fn {_id, agent} -> ~p"/agents/#{agent.id}" end} > <:col :let={{_id, agent}} label={t("Name")}>
{agent.name} <%= if agent.id == @global_default_cloud_poller_id do %> <.icon name="hero-check-circle" class="h-3 w-3" /> Default <% end %> <%= if agent.allow_remote_debug do %> <.icon name="hero-bug-ant" class="h-3 w-3" /> Debug <% end %>
<:col :let={{_id, agent}} label={t("Status")}> <% {status, label} = agent_status(agent) %> {label} <:col :let={{_id, agent}} label={t("Device")}> <% counts = Map.get(@cloud_poller_counts, agent.id, %{direct: 0, total: 0}) %>
{counts.total} total
{counts.direct} direct <%= if counts.total > counts.direct do %> · {counts.total - counts.direct} inherited <% end %>
<:col :let={{_id, agent}} label={t("Last Seen")}>
<.timestamp datetime={agent.last_seen_at} timezone={@timezone} now={@now} />
<%= if agent.last_seen_at do %>
<.timestamp datetime={agent.last_seen_at} timezone={@timezone} format="absolute" />
<% end %> <%= if agent.last_ip do %>
{agent.last_ip}
<% end %> <:col :let={{_id, agent}} label={t("Version")}> <%= if agent.metadata["version"] do %>
{format_agent_version(agent.metadata["version"])}
<% end %> <:col :let={{_id, agent}} label={t("Created")}>
{ToweropsWeb.TimeHelpers.format_date(agent.inserted_at, @timezone)}
<:action :let={{_id, agent}}> <%= if agent.enabled do %>
<.button type="button" phx-click="show_setup" phx-value-id={agent.id} variant="secondary" > {t("View Setup")} <.button type="button" phx-click="delete_agent" phx-value-id={agent.id} data-confirm={ t( "Are you sure you want to delete this cloud poller? This will affect all organizations using it." ) } variant="danger" > {t("Delete")}
<% else %> Disabled <% end %>
<% end %> <%!-- Global Default Cloud Poller (Superadmin Only) --%> <%= if @is_superuser do %>

{t("Global Default Cloud Poller")}

{t( "Fallback agent for organizations without a default agent configured. Devices with no assignment at any level will use this agent." )}

<.form for={%{}} phx-change="update_selected_global_default" class="max-w-md">
<%= if @global_default_cloud_poller_id do %> <% selected_poller = Enum.find(@cloud_pollers_list, &(&1.id == @global_default_cloud_poller_id)) %> <%= if selected_poller do %>

<.icon name="hero-check-circle" class="h-4 w-4 inline" /> Currently using: {selected_poller.name}

<% else %>

<.icon name="hero-exclamation-triangle" class="h-4 w-4 inline" /> {t("Warning: Selected agent no longer exists. Please choose a new agent.")}

<% end %> <% else %>

<.icon name="hero-information-circle" class="h-4 w-4 inline" /> {t( "No global default configured. Devices without assignments will use direct Phoenix cluster polling." )}

<% end %>
<.button type="button" phx-click="save_global_default" variant="primary" disabled={@selected_global_default == (@global_default_cloud_poller_id || "")} > <.icon name="hero-check" class="h-4 w-4" /> Save Changes <%= if @selected_global_default != (@global_default_cloud_poller_id || "") do %> <% end %>
<% end %> <%= if @show_token_modal && @new_token do %>

{t("Agent Setup Instructions")}

{t("Use the token and Docker Compose configuration below to deploy this agent.")}

{@new_token.agent_token.name}

{t("Click the token to select all, or use the Copy button")}

{t("Docker Compose Setup with Auto-Updates")}

{t( "This configuration includes Watchtower for automatic agent updates. The agent will automatically update to the latest version every 12 hours." )}

services:
  towerops-agent:
    image: {@agent_image}
    container_name: towerops-agent
    restart: unless-stopped
    environment:
      - TOWEROPS_API_URL={url(@socket, ~p"/")}
      - TOWEROPS_AGENT_TOKEN={@new_token.token}
    labels:
      - "com.centurylinklabs.watchtower.enable=true"
      - "com.centurylinklabs.watchtower.scope=towerops"

  watchtower:
    image: containrrr/watchtower:latest
    container_name: towerops-watchtower
    restart: unless-stopped
    environment:
      # Check for updates every 12 hours (43200 seconds)
      - WATCHTOWER_POLL_INTERVAL=43200
      - WATCHTOWER_LABEL_ENABLE=true
      - WATCHTOWER_SCOPE=towerops
      - WATCHTOWER_CLEANUP=true
      - WATCHTOWER_LOG_LEVEL=info
      # Use latest Docker API version
      - DOCKER_API_VERSION=1.44
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
<.button phx-click="close_token_modal" variant="primary"> {t("Close")}
<% end %>