diff --git a/lib/towerops_web/live/org/settings_live.ex b/lib/towerops_web/live/org/settings_live.ex
index 0ce813e9..e427822b 100644
--- a/lib/towerops_web/live/org/settings_live.ex
+++ b/lib/towerops_web/live/org/settings_live.ex
@@ -20,123 +20,6 @@ defmodule ToweropsWeb.Org.SettingsLive do
@billing_provider_ids ~w(gaiia sonar splynx visp)
- @providers [
- # Billing providers (mutually exclusive — grouped first)
- %{
- id: "gaiia",
- name: "Gaiia",
- description:
- "Billing and subscriber management. Enables outage impact analysis, inventory reconciliation, and subscriber-aware monitoring.",
- icon: "hero-user-group",
- setup_help: %{
- url_pattern: "https://app.gaiia.com/{your-org}/admin/apiKeys",
- steps: [
- "Log into Gaiia and go to **Admin** → **API Keys**",
- "Click **Create API Key**",
- "Give it a descriptive name (e.g. \"TowerOps\")",
- "Copy the generated API key and paste it below"
- ],
- permissions:
- "Read-only access. The key only needs permission to read accounts, subscriptions, and inventory data."
- }
- },
- %{
- id: "sonar",
- name: "Sonar",
- description:
- "Billing and subscriber management. Sync accounts, network sites, and inventory from your Sonar instance.",
- icon: "hero-currency-dollar",
- setup_help: %{
- url_pattern: "https://{your-instance}.sonar.software/admin/users/{your-user-id}",
- steps: [
- "Log into Sonar and go to **Settings** → **Security** → **API Tokens** (or your user profile → API Tokens)",
- "Click **Create Token**",
- "Name it (e.g. \"TowerOps\") and copy the generated token"
- ],
- permissions:
- "Requires a **read-only** personal access token. The token needs access to: Accounts, Network Sites, Inventory Items, and Address data."
- }
- },
- %{
- id: "splynx",
- name: "Splynx",
- description:
- "ISP billing and management platform. Sync customers, internet services, and network routers from Splynx.",
- icon: "hero-banknotes",
- setup_help: %{
- url_pattern: "https://{your-instance}.splynx.app/admin/administration/api-keys",
- steps: [
- "Log into Splynx and go to **Administration** → **API Keys**",
- "Click **Add** to create a new API key",
- "Copy both the **API Key** and **API Secret**"
- ],
- permissions:
- "Requires read access to **Customers**, **Internet Services**, and **Routers**. No write permissions needed."
- }
- },
- %{
- id: "visp",
- name: "VISP",
- description: "Cloud-based ISP management. Sync subscribers, sites, equipment, and MRR data from VISP.",
- icon: "hero-cloud",
- setup_help: %{
- url_pattern: "https://app.visp.net/settings/api",
- steps: [
- "Log into VISP and go to **Settings** → **API**",
- "Click **Generate New Key**",
- "Name it (e.g. \"TowerOps\") and copy the generated API key"
- ],
- permissions: "Requires read-only API access to **Subscribers**, **Sites**, **Equipment**, and **Billing** data."
- }
- },
- # Quality of Experience
- %{
- id: "preseem",
- name: "Preseem",
- description: "QoE monitoring and subscriber experience analytics for wireless ISPs.",
- icon: "hero-signal",
- category: "Quality of Experience",
- setup_help: %{
- url_pattern: "https://app.preseem.com/settings/api",
- steps: [
- "Log into Preseem and go to **Settings** → **API**",
- "Click **Generate API Key**",
- "Copy the generated key and paste it below"
- ],
- permissions: "Read-only access. The key needs permission to read subscriber QoE metrics and access point data."
- }
- },
- # Incident Management
- %{
- id: "pagerduty",
- name: "PagerDuty",
- description:
- "Incident management and on-call alerting. Automatically triggers, acknowledges, and resolves PagerDuty incidents from TowerOps alerts.",
- icon: "hero-bell-alert",
- category: "Incident Management"
- },
- # Infrastructure & IPAM
- %{
- id: "netbox",
- name: "NetBox",
- description:
- "Infrastructure source of truth. Sync devices, sites, IP addresses, and interfaces between TowerOps and your NetBox instance.",
- icon: "hero-server-stack",
- category: "Infrastructure & IPAM",
- setup_help: %{
- url_pattern: "https://{your-netbox-instance}/user/api-tokens/",
- steps: [
- "Log into NetBox and go to your **profile** (top right) → **API Tokens**",
- "Click **Add a token**",
- "Optionally set an expiry date and description (e.g. \"TowerOps\")",
- "Copy the generated token"
- ],
- permissions:
- "Requires **read** permission at minimum. If you want to push data to NetBox (bidirectional sync), the token also needs **write** permission."
- }
- }
- ]
-
@impl true
def mount(_params, _session, socket) do
organization = socket.assigns.current_scope.organization
@@ -173,15 +56,7 @@ defmodule ToweropsWeb.Org.SettingsLive do
|> assign(:pending_invitations, [])
|> assign(:invite_form, to_form(%{"email" => "", "role" => "technician"}))
# Integration assigns - loaded lazily when tab is selected
- |> assign(:providers, @providers)
- |> assign(:billing_provider_ids, @billing_provider_ids)
|> assign(:integrations, %{})
- |> assign(:active_billing_provider, nil)
- |> assign(:configuring, nil)
- |> assign(:integration_form, nil)
- |> assign(:test_result, nil)
- |> assign(:netbox_config, default_netbox_config())
- |> assign(:integration_credentials, %{})
|> assign(:timezone, socket.assigns.current_scope.timezone)}
end
@@ -210,14 +85,6 @@ defmodule ToweropsWeb.Org.SettingsLive do
|> assign(:pending_invitations, Organizations.list_pending_invitations(org_id))
end
- defp maybe_load_integrations(socket, "integrations") do
- integrations = load_integrations(socket.assigns.organization.id)
-
- socket
- |> assign(:integrations, integrations)
- |> assign(:active_billing_provider, active_billing_provider(integrations))
- end
-
defp maybe_load_integrations(socket, _tab), do: socket
# === Org settings events ===
diff --git a/lib/towerops_web/live/org/settings_live.html.heex b/lib/towerops_web/live/org/settings_live.html.heex
index 6ff76986..78169e2e 100644
--- a/lib/towerops_web/live/org/settings_live.html.heex
+++ b/lib/towerops_web/live/org/settings_live.html.heex
@@ -77,12 +77,8 @@
<.link
- patch={~p"/orgs/#{@organization.slug}/settings?tab=integrations"}
- class={
- if @active_tab == "integrations",
- do: "text-indigo-600 dark:text-indigo-400",
- else: ""
- }
+ navigate={~p"/orgs/#{@organization.slug}/settings/integrations"}
+ class=""
>
{t("Integrations")}
@@ -993,1396 +989,24 @@
<% end %>
<%= if @active_tab == "integrations" do %>
-
- <%= for {provider, idx} <- Enum.with_index(@providers) do %>
- <% billing_locked? =
- @active_billing_provider != nil and provider.id in @billing_provider_ids and
- provider.id != @active_billing_provider %>
- <%!-- Skip locked billing providers — they're shown in the collapsed group below --%>
- <%= unless billing_locked? do %>
- <%!-- Section headers --%>
- <%= if idx == 0 do %>
-
-
- Billing & Subscriber Management
-
- <%= if @active_billing_provider == nil do %>
-
- <.icon name="hero-arrow-path" class="h-3 w-3" /> Choose one
-
-
- — only one billing platform can be active at a time
-
- <% end %>
-
- <% end %>
- <%= if Map.has_key?(provider, :category) and (idx == 0 or Enum.at(@providers, idx - 1) |> Map.get(:category) != provider.category) do %>
-
-
- {provider.category}
-
-
- <% end %>
-
- "border-red-200 dark:border-red-500/30"
-
- @integrations[provider.id] && @integrations[provider.id].enabled ->
- "border-green-200 dark:border-green-500/20"
-
- true ->
- "border-gray-200 dark:border-white/10"
- end
- ]}>
- <%!-- Left status accent bar --%>
-
- {t(
- "When someone resolves or acknowledges an incident directly in PagerDuty,"
- )}
- {t("TowerOps will automatically update the corresponding alert.")}
-