The detail panel never earned its keep — it showed the same status, host,
and last-seen already on the row, and gated Edit / Pause / Remove behind
a navigation hop. Collapse it into row-level actions so the ledger is the
single surface for managing a monitored system:
- New useConnectionRowActions hook: per-id pending / error / confirming
state so pause + two-click remove coexist across rows without
component-per-row signal proliferation. Confirm window bumped to 6s.
- ConnectionsTable: inline Edit / Pause / Remove cluster per row, red
alert row for action errors, expansion row with agent uninstall
commands (Linux + Windows, copy-to-clipboard) during remove-confirm.
- InfrastructureWorkspace: 3-mode shape (ledger / add / edit), no
detail selection state, pulls uninstall commands from the operations
context and wires clipboard + notifications.
- Deleted ConnectionDetailPanel + its test; subsystem contracts
(agent-lifecycle, frontend-primitives, api-contracts, registry)
updated to point at useConnectionRowActions and ConnectionsTable
as the canonical drill-in surface.
All 30 Settings tests pass; type-check clean.
Row click on the ConnectionsTable was still popping a right-side Dialog
drawer. That re-wrapped the per-type panels rather than replacing them —
"consolidation means shared fabric, not shared container."
Swap ConnectionDetailDrawer for ConnectionDetailPanel: same props, same
pause/remove handlers, but rendered as an inline bordered card instead
of a Dialog. The workspace Switch/Match gains a 'detail' mode that
shows the panel with a "Back to systems" header. Removing a connection
exits detail mode via onRemoved; editing routes through the existing
handleEditConnection.
Subsystem contracts updated to match: agent-lifecycle, frontend-primitives,
and api-contracts now name ConnectionDetailPanel.tsx (with a note that
it must not be re-wrapped as a floating Dialog); registry owned_files
and platform-connections-workspace-lifecycle-proof match_files renamed
to match the new filename.
Delete the stop-monitoring dialog plus the retired per-type settings
shells now that the unified ConnectionEditor replaces them: remove
PlatformConnectionsWorkspace / ProxmoxSettingsPanel /
ProxmoxDirectWorkspace / NodeModal et al and the accompanying tests.
Strip the lingering reporting-state hook from
useInfrastructureOperationsState and the guardrail test reinforces the
removal. Reconcile registry.json, frontend-primitives.md,
api-contracts.md, agent-lifecycle.md, status.json, and the
release-control guard/test fixtures so governance audits stay clean.
Adds positive MonitorDatasets/Pools/Replication booleans to TrueNASInstance
and MonitorVMs/Hosts/Datastores to VMwareVCenterInstance, matching the
PVE/PBS/PMG scope pattern. NewInstance defaults all surfaces to true;
ApplyDefaults migrates legacy all-false records to all-true so existing
truenas.json / vmware.json on disk continue monitoring after upgrade.
The unified connections aggregator now reads those booleans into the
Scope map and flips SupportsScope to true for both types, so the Scope
UI in the ConnectionEditor is a straight wire-through to the native
config fields — no new storage or adapter layer. Per-type API clients,
form state, and the TrueNAS and VMware credential slots render the same
three-checkbox "Collection scope" panel used by PVE/PBS/PMG, replacing
the old per-type Stop-this-surface dialog end-to-end from the editor's
side.
Contracts updated: agent-lifecycle, api-contracts, storage-recovery.
Tests: truenas.test.ts and vmware.test.ts round-trip the new monitor*
flags through list + update payloads; config tests cover the legacy
all-false ApplyDefaults migration; aggregator test asserts the scope map
and SupportsScope: true for both types.
Provider Refresh paths still fetch everything in one trip; honoring
Monitor* inside VMware and TrueNAS pollers is deferred to a follow-up.
Switches the configured-connections ledger in the infrastructure workspace
from the legacy `useInfrastructureReportingState`-derived rows to
`GET /api/connections`, so the table now reflects aggregator-derived state
(active/paused/unauthorized/unreachable/stale/pending) and per-connection
scope directly from the per-type config stores plus scheduler health.
New frontend surfaces:
- `useConnectionsLedger.ts` polls the unified aggregator every 15s and
maps each `Connection` into an `InfrastructureSystemRow` with state
badges, collection label, active-scope coverage labels, and a
`connection` manage action.
- `ConnectionDetailDrawer.tsx` renders the aggregator fields (type,
address, state, stateReason, enabled, surfaces with active scope,
last seen, last error, source) when a unified row is clicked,
replacing `InfrastructureActiveRowDetails` for configured connections.
`InfrastructureWorkspace` now composes its row list from the ledger plus
the legacy monitoring-stopped rows (still driven by
`useInfrastructureReportingState`) and no longer mounts the legacy
active-row drawer. Ignored-inventory drill-in continues to use
`InfrastructureIgnoredRowDetails` pending the phase 9 cleanup.
`SystemManageAction` gains a `connection` variant so the workspace can
differentiate unified-row clicks from monitoring-stopped rows without
conflating them through the legacy `rowKey` path.
Contracts updated: agent-lifecycle, frontend-primitives.
Tests: `InfrastructureWorkspace.test.tsx` extended with a
`connectionFixture`, asserts unified rows render with the new state
badges, and the View-details click opens the new connection-detail
drawer instead of calling `setExpandedRowKey`.
Extracts the inner form bodies from TrueNASSettingsPanel and
VMwareSettingsPanel into dedicated credential slot components mounted
inline under ConnectionEditor. When the user adds a TrueNAS or VMware
connection, the editor now shows a clean form instead of re-rendering
the full platform panel (which listed every other saved connection
before exposing the add dialog).
State still lives on TrueNASSettingsPanelState and
VMwareSettingsPanelState, so save, test, preview, and admission-preview
behavior remain identical. The slots prime the existing create-dialog
state on mount and close it on cancel; save completion is detected via
the state's dialogOpen transition.
Replaces the ProxmoxSettingsPanel stopgap that rendered an entire
Proxmox workspace (discovery card, configured nodes table, node modal
stack) inside the add-connection credential slot. The add flow now
mounts NodeCredentialSlot, which drops the Dialog chrome and reuses the
NodeModalBasicInfoSection / AuthenticationSection / MonitoringSection /
StatusFooter primitives directly so the user sees a fresh credentials
form — not the configured-nodes table they just came from.
Save dispatch still routes through the existing per-type saveNode
plumbing; the unified form is additive and does not change backend
contracts.
Replaces the right-side drawer wrapper around ConnectionEditor with an
inline content swap inside InfrastructureWorkspace. When add mode is
active, the inventory table is replaced in place by the editor with a
back-to-systems affordance, instead of floating over a preserved list
behind modal chrome. Putting per-type panels behind a common drawer was
re-wrapping, not consolidating; the unified add surface must take over
the workspace.
Updates subsystem contracts for agent-lifecycle and frontend-primitives
to forbid the drawer/modal overlay for the add flow, so the pattern
cannot silently return.
The Add infrastructure drawer now opens ConnectionEditor instead of the
legacy type picker + per-type step branches. Paste an address, Pulse
probes, detected type dispatches into a credential slot. The slot still
mounts the existing per-type panels (ProxmoxSettingsPanel,
TrueNASSettingsPanel, VMwareSettingsPanel, InfrastructureInstallerSection)
so mature credential flows keep working end-to-end; slot components are
a later phase.
- InfrastructureWorkspace: panelStep state machine replaced with
addDrawerOpen + initialAddType. Legacy deep links still redirect and
pre-select the matching type. Agent setup handoff still auto-opens
into the agent slot. Read-only mode still suppresses the drawer.
- AddSystemPicker + its test deleted (dead code, the picker UI is gone).
- InfrastructureWorkspace.test.tsx rewritten for the probe-first flow
(probe button, manual-type escape hatch, back-to-probe, per-type
credential slot routing, legacy redirects, read-only).
- settingsArchitecture guardrail swapped from panelStep string
assertions to ConnectionEditor + renderCredentialSlot assertions.
- agent-lifecycle + frontend-primitives contracts extended to require
the unified add surface run through ConnectionEditor.
Introduces GET /api/connections and POST /api/connections/probe as the
backend half of the one-ledger / one-editor connection redesign.
- GET /api/connections aggregates PVE/PBS/PMG/VMware/TrueNAS/agent rows
into a unified Connection shape with derived state (active, paused,
unauthorized, unreachable, stale, pending) computed from in-memory
scheduler health plus agent Host.LastSeen. No new persisted state.
- POST /api/connections/probe fingerprints a host across the five
supported products in parallel (2s dial + 1s read, 3s total, max 5
concurrent). Admin-gated (RequireAdmin + ScopeSettingsWrite) to block
unauthenticated SSRF against internal hosts.
- Disabled bool on PVEInstance/PBSInstance/PMGInstance (zero-value =
enabled, preserves existing nodes.json); pollers skip disabled
instances at client init, reconnect, and per-node iteration.
- NodeConfigRequest/Response gain Enabled; write path translates
*bool -> Disabled so omitted field leaves state untouched.
- ConnectionsAPI frontend client (list/probe) typed off the Go shape.
Contracts updated: api-contracts, monitoring, agent-lifecycle,
performance-and-scalability, storage-recovery. Proofs added:
contract_test.go JSON snapshot for Connection and ProbeResponse,
monitoring guardrails for the Disabled-skip behavior, and a vitest
mock-client test for ConnectionsAPI.
Frontend editor / drawer / table rewrite lands in a separate block.
Summary cards now show degraded/alerting/failing counts rather than raw
online/offline splits, giving operators an at-a-glance health posture without
drilling into the full resource list.
- InfrastructureSummary/infrastructureSummaryModel: adds degraded and alerting
counts derived from resource statuses and active alerts
- StorageSummary/StoragePageSummary/useStoragePageSummary: adds poolsDegraded
and disksFailing indicators, shows "all healthy" when zero degradation
- WorkloadsSummary/useDashboardWorkloadDerivedState: adds alerting guest count
from activeAlerts accessor, included in summary header counts
- RecoverySummary: adds aggregate health-state summary row
- useDashboardState: threads alertsEnabled through workload derived state
- Fix monitored-system cap test helper to use TierEnterprise so limits are
honored (self-hosted tiers are now uncapped per the v6 product model)
- Update registry and governance test snapshots to include
useStoragePageSummary.test.ts in the storage-product-surface proof set
The purchase-start handoff (/auth/license-purchase-start) requires a configured
PublicURL and fails silently on local self-hosted instances without one. Routes
ai_alerts, ai_autofix, relay, rbac, audit_logging, advanced_sso,
agent_profiles, long_term_metrics, and trial_expired to the self-hosted billing
plan page so upgrade CTAs remain functional on local instances.
These props were passed through the entire alerts component tree but are no
longer needed — AI alert gating is handled by the shared license/entitlements
layer without each surface needing its own capabilities fetch. Removes the
onMount capabilities load, the paywall-viewed tracking effect, and the
dependent prop chain through OverviewTab, HistoryTab, and all alert card
surfaces.
Updates all test files broken by the collapse of infrastructure sub-routes
(/install, /platforms, /connections) into one /settings/infrastructure entry.
Key contract deltas:
- settingsNavCatalog/Model: infrastructure-connections and infrastructure-install
tabs removed; infrastructure-systems is the single sidebar entry
- infrastructureWorkspaceModel: getInfrastructureWorkspaceViewFromPath renamed
to deriveAddStepFromLegacyPath; buildInfrastructureWorkspacePath now always
returns /settings/infrastructure regardless of argument
- settingsNavigationModel: deriveAgentFromPath and isProxmoxSettingsPath use
normalised (not canonical) path so Proxmox deep links still resolve to the
correct agent before the canonical-path redirect fires
- useSettingsNavigation: Proxmox agent sync moved before the redirect early-
return so deep links seed the correct selectedAgent
- InfrastructureInstallerSection: "Open Platform connections" button replaced
with informational text; navigate target updated to flat workspace path
- useInfrastructureDiscoveryRuntimeState: currentTab parameter removed (tab
collapse means discovery is always active when the workspace is mounted)
- SetupCompletionPanel: unified INFRASTRUCTURE_PATH constant replaces the two
distinct INFRASTRUCTURE_INSTALL_PATH / INFRASTRUCTURE_PLATFORMS_PATH
- All navigation call sites (Dashboard, DashboardStateCards, Infrastructure
empty-state) updated to /settings/infrastructure
- Contract updates: agent-lifecycle, api-contracts, frontend-primitives