<.breadcrumb items={[ %{label: "Dashboard", navigate: ~p"/dashboard"}, %{label: "Settings", navigate: ~p"/orgs/#{@organization.slug}/settings"}, %{label: "Integrations", navigate: ~p"/orgs/#{@organization.slug}/settings/integrations"}, %{label: "Gaiia"} ]} /> <.header> {t("Gaiia Inventory Reconciliation")} <:subtitle> {t( "Compare Gaiia inventory against Towerops device discovery. Reconciliation runs nightly." )} <%!-- Sub-navigation tabs --%>
{@report.summary.total_mapped}
Mapped
{@report.summary.missing_mapping_count}
Unmapped Items
{@report.summary.untracked_count}
Untracked Devices
{@report.summary.mismatch_count}
Data Mismatches
{@report.summary.ghost_count}
Ghosts
<.link patch={ ~p"/orgs/#{@organization.slug}/settings/integrations/gaiia/reconciliation?tab=summary" } class={[ "px-4 py-2 text-sm font-medium rounded-l-lg", @active_tab == "summary" && "bg-blue-600 text-white dark:bg-blue-500", @active_tab != "summary" && "bg-white text-gray-700 hover:bg-gray-50 dark:bg-gray-800/50 dark:text-gray-300 dark:hover:bg-gray-800" ]} > {t("Summary")} <.link patch={ ~p"/orgs/#{@organization.slug}/settings/integrations/gaiia/reconciliation?tab=untracked" } class={[ "px-4 py-2 text-sm font-medium border-l border-gray-200 dark:border-white/10", @active_tab == "untracked" && "bg-blue-600 text-white dark:bg-blue-500", @active_tab != "untracked" && "bg-white text-gray-700 hover:bg-gray-50 dark:bg-gray-800/50 dark:text-gray-300 dark:hover:bg-gray-800" ]} > Untracked ({@report.summary.untracked_count}) <.link patch={ ~p"/orgs/#{@organization.slug}/settings/integrations/gaiia/reconciliation?tab=mismatches" } class={[ "px-4 py-2 text-sm font-medium border-l border-gray-200 dark:border-white/10", @active_tab == "mismatches" && "bg-blue-600 text-white dark:bg-blue-500", @active_tab != "mismatches" && "bg-white text-gray-700 hover:bg-gray-50 dark:bg-gray-800/50 dark:text-gray-300 dark:hover:bg-gray-800" ]} > Mismatches ({@report.summary.mismatch_count}) <.link patch={ ~p"/orgs/#{@organization.slug}/settings/integrations/gaiia/reconciliation?tab=unmapped" } class={[ "px-4 py-2 text-sm font-medium border-l border-gray-200 dark:border-white/10", @active_tab == "unmapped" && "bg-blue-600 text-white dark:bg-blue-500", @active_tab != "unmapped" && "bg-white text-gray-700 hover:bg-gray-50 dark:bg-gray-800/50 dark:text-gray-300 dark:hover:bg-gray-800" ]} > Unmapped ({@report.summary.missing_mapping_count}) <.link patch={ ~p"/orgs/#{@organization.slug}/settings/integrations/gaiia/reconciliation?tab=ghosts" } class={[ "px-4 py-2 text-sm font-medium rounded-r-lg border-l border-gray-200 dark:border-white/10", @active_tab == "ghosts" && "bg-blue-600 text-white dark:bg-blue-500", @active_tab != "ghosts" && "bg-white text-gray-700 hover:bg-gray-50 dark:bg-gray-800/50 dark:text-gray-300 dark:hover:bg-gray-800" ]} > Ghosts ({@report.summary.ghost_count})
<%= case @active_tab do %> <% "untracked" -> %>
<%= if @report.untracked_devices == [] do %>

{t("All Towerops devices have matching Gaiia inventory items.")}

<% else %>
{t("Links by MAC, IP, or site assignment.")}
<%= for entry <- @report.untracked_devices do %> <%!-- Search results row for link search --%> <%= if @open_link_for == entry.device.id and @link_search_results != [] do %> <% end %> <% end %>
{t("Device")} {t("IP Address")} {t("Site")} {t("Actions")}
<.link navigate={~p"/devices/#{entry.device.id}"} class="text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300" > {entry.device.name} {entry.device.ip_address} <%= if entry.device.site do %> {entry.device.site.name} <% end %> <%= cond do %> <% @open_create_for == entry.device.id -> %>
<%= if @selected_manufacturer do %>
<% end %>
<% @open_link_for == entry.device.id -> %>
<% true -> %>
<% end %>
<%= for item <- @link_search_results do %>
{item.name} {item.ip_address || "—"}
<% end %>
<% end %>
<% "mismatches" -> %>
<%= if @report.data_mismatches == [] do %>

{t("No data mismatches found between mapped devices.")}

<% else %>
<%= for mismatch <- @report.data_mismatches do %> <% end %>
{t("Device")} {t("Field")} {t("Towerops")} {t("Gaiia")}
<.link navigate={~p"/devices/#{mismatch.device.id}"} class="text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300" > {mismatch.device.name} {mismatch.field} {mismatch.towerops_value} {mismatch.gaiia_value}
<% end %>
<% "unmapped" -> %>
<%= if @report.missing_mappings == [] do %>

{t("All Gaiia inventory items are mapped to Towerops devices.")}

<% else %>
<%= for entry <- @report.missing_mappings do %> <% end %>
{t("Gaiia Item")} {t("IP Address")} {t("Category")} {t("Status")}
{entry.inventory_item.name} {entry.inventory_item.ip_address || "—"} {entry.inventory_item.category || "—"} {entry.inventory_item.status || "—"}
<% end %>
<% "ghosts" -> %>
<%= if @report.ghost_devices == [] do %>

{t("No stale mappings — all linked Gaiia items reference existing Towerops devices.")}

<% else %>

{t( "These Gaiia inventory items are linked to Towerops devices that no longer exist. Unlink them to restore them to the unmapped pool." )}

<%= for entry <- @report.ghost_devices do %> <% end %>
{t("Gaiia Item")} {t("IP Address")} {t("Status")} {t("Actions")}
{entry.inventory_item.name} {entry.inventory_item.ip_address || "—"} {entry.inventory_item.status || "—"}
<% end %>
<% _ -> %>

Last reconciled: {ToweropsWeb.TimeHelpers.format_datetime( @report.reconciled_at, @current_scope.timezone, @current_scope.time_format )}

<%= if @report.summary.total_mapped == 0 && @report.summary.missing_mapping_count == 0 && @report.summary.untracked_count == 0 do %>
<.icon name="hero-check-circle" class="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500" />

{t("No inventory data")}

{t("Sync Gaiia data and map inventory items to see reconciliation results.")}

<.link navigate={~p"/orgs/#{@organization.slug}/settings/integrations/gaiia/mapping"} class="mt-4 inline-flex items-center gap-1 text-sm font-medium text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300" > Go to Entity Mapping <.icon name="hero-arrow-right" class="h-4 w-4" />
<% else %>

{t("Overview")}

Mapped devices (Gaiia ↔ Towerops)
{@report.summary.total_mapped}
{t("Unmapped Gaiia items (no Towerops link)")}
{@report.summary.missing_mapping_count}
{t("Untracked Towerops devices (not in Gaiia)")}
{@report.summary.untracked_count}
{t("Data mismatches (IP, serial, etc.)")}
{@report.summary.mismatch_count}
{t("Ghost mappings (stale device links)")}
{@report.summary.ghost_count}
<% end %>
<% end %>