diff --git a/docs/release-control/v6/internal/subsystems/agent-lifecycle.md b/docs/release-control/v6/internal/subsystems/agent-lifecycle.md index 2c1759d49..79f2633c4 100644 --- a/docs/release-control/v6/internal/subsystems/agent-lifecycle.md +++ b/docs/release-control/v6/internal/subsystems/agent-lifecycle.md @@ -195,6 +195,17 @@ management, and fleet control surfaces. where the first-host scoped install token is prepared from setup handoff, not as a second manual token-generation task the operator still needs to figure out. +10. Keep API-backed platform onboarding explicit across + `frontend-modern/src/components/Settings/infrastructureOperationsModel.tsx`, + `frontend-modern/src/components/Settings/InfrastructureInstallerSection.tsx`, + `frontend-modern/src/components/Settings/useInfrastructureInstallState.tsx`, + `frontend-modern/src/components/Settings/InfrastructureWorkspace.tsx`, and + `frontend-modern/src/components/SetupWizard/SetupCompletionPanel.tsx`. + TrueNAS must be presented as a Platform connections workflow first, not as + a dedicated Unified Agent install profile. The install workspace may remain + available for optional later agent augmentation on TrueNAS, but first-run + copy, alternative CTAs, and install-profile lists must not imply that an + agent install is the required bootstrap for TrueNAS support in Pulse. ## Current State diff --git a/docs/release-control/v6/internal/subsystems/api-contracts.md b/docs/release-control/v6/internal/subsystems/api-contracts.md index d24b4ab43..1d014b1ef 100644 --- a/docs/release-control/v6/internal/subsystems/api-contracts.md +++ b/docs/release-control/v6/internal/subsystems/api-contracts.md @@ -228,17 +228,6 @@ Own canonical runtime payload shapes between backend and frontend. operators can receive the first success handoff without typing a hostname or agent ID. 20. Keep the shared first-run install-token transport explicit on -21. Keep connected-infrastructure surface vocabulary canonical across the - shared `/api/state` and reporting/install consumers: `frontend-modern/src/types/api.ts` - must treat `truenas` as a first-class connected-infrastructure surface kind, - and connected-infrastructure consumers such as - `frontend-modern/src/components/Settings/infrastructureOperationsModel.tsx` - and - `frontend-modern/src/components/Settings/useInfrastructureReportingState.tsx` - must preserve the transport distinction between machine-managed surfaces - (`agent`, `docker`, `kubernetes`) and platform-connections-managed - surfaces (`proxmox`, `pbs`, `pmg`, `truenas`) instead of collapsing them - into one uninstall/stop-monitoring model. `/api/security/tokens` as used by `frontend-modern/src/components/Settings/useInfrastructureInstallState.tsx`: once quick setup has produced the setup handoff credentials, the canonical @@ -249,7 +238,33 @@ Own canonical runtime payload shapes between backend and frontend. install-state surface must describe that prepared token path consistently with the live runtime behavior rather than directing the operator to create another install token manually. -21. Keep local trial-start transport explicit on the shared commercial API +21. Keep connected-infrastructure surface vocabulary canonical across the + shared `/api/state` and reporting/install consumers: + `frontend-modern/src/types/api.ts` must treat `truenas` as a first-class + connected-infrastructure surface kind, and connected-infrastructure + consumers such as + `frontend-modern/src/components/Settings/infrastructureOperationsModel.tsx` + and + `frontend-modern/src/components/Settings/useInfrastructureReportingState.tsx` + must preserve the transport distinction between machine-managed surfaces + (`agent`, `docker`, `kubernetes`) and platform-connections-managed + surfaces (`proxmox`, `pbs`, `pmg`, `truenas`) instead of collapsing them + into one uninstall/stop-monitoring model. +22. Keep API-backed first-target onboarding canonical on that same shared + infrastructure-settings boundary: + `frontend-modern/src/components/Settings/infrastructureOperationsModel.tsx`, + `frontend-modern/src/components/Settings/useInfrastructureInstallState.tsx`, + `frontend-modern/src/components/Settings/InfrastructureInstallerSection.tsx`, + `frontend-modern/src/components/Settings/InfrastructureWorkspace.tsx`, and + `frontend-modern/src/components/SetupWizard/SetupCompletionPanel.tsx` must + present TrueNAS and other API-backed platforms as Platform connections-first + onboarding rather than as dedicated unified-agent install profiles. The + shared host-install contract may guide operators through the first + agent-managed host, but alternate CTAs and setup-completion guidance must + route API-backed first systems to `/settings/infrastructure/platforms` + instead of implying that a host install command is required before those + platforms can report into Pulse. +23. Keep local trial-start transport explicit on the shared commercial API boundary: `/api/license/trial/start` must preserve the hosted-signup redirect contract during the allowed retry burst, then return the actual remaining backoff in both `Retry-After` and diff --git a/frontend-modern/src/components/Settings/InfrastructureInstallerSection.tsx b/frontend-modern/src/components/Settings/InfrastructureInstallerSection.tsx index c90be5f33..6a885c78b 100644 --- a/frontend-modern/src/components/Settings/InfrastructureInstallerSection.tsx +++ b/frontend-modern/src/components/Settings/InfrastructureInstallerSection.tsx @@ -1,7 +1,6 @@ import type { Component } from 'solid-js'; import { For, Show, createSignal } from 'solid-js'; import Server from 'lucide-solid/icons/server'; -import { ProxmoxIcon } from '@/components/icons/ProxmoxIcon'; import SettingsPanel from '@/components/shared/SettingsPanel'; import { copyToClipboard } from '@/utils/clipboard'; import { formatAbsoluteTime, formatRelativeTime } from '@/utils/format'; @@ -138,31 +137,29 @@ export const InfrastructureInstallerSection: Component = () => {
-

Start with the first host you want Pulse to monitor.

+

Use this workspace for the first agent-managed host.

- Install the Pulse agent on that system first. Once it connects, Pulse can keep using this - workspace to add more hosts and layered platform integrations. + Install the Pulse agent here only when the first system should run the unified agent + directly. If the first system is API-backed, such as TrueNAS or Proxmox, open Platform + connections instead.

-
- -
-

- Proxmox nodes can be added here with the unified agent for extra capabilities like - temperature monitoring and Pulse Patrol automation (auto-creates the required token - and links the node). -

- -
+
+

+ API-backed platforms such as Proxmox and TrueNAS belong in Platform connections. Use + this install workspace only for systems where Pulse should run the unified agent on + the machine itself. +

+
@@ -463,6 +460,10 @@ export const InfrastructureInstallerSection: Component = () => {

{state.getSelectedInstallProfile().description}

+

+ API-backed platforms such as TrueNAS connect through Platform connections + rather than a dedicated install profile here. +

0}>

Adds flags to shell-based install commands:{' '} diff --git a/frontend-modern/src/components/Settings/InfrastructureWorkspace.tsx b/frontend-modern/src/components/Settings/InfrastructureWorkspace.tsx index 6c8937b93..c98f1afbf 100644 --- a/frontend-modern/src/components/Settings/InfrastructureWorkspace.tsx +++ b/frontend-modern/src/components/Settings/InfrastructureWorkspace.tsx @@ -33,17 +33,17 @@ export const InfrastructureWorkspace: Component =

Connect your first system

- Start with Install on a host to connect the first machine you want Pulse to monitor. - If you already know you want an API-backed platform such as Proxmox or TrueNAS - instead, go straight to Platform connections. + Use Install on a host for the first machine that should run the unified agent. If the + first system is API-backed, such as Proxmox or TrueNAS, go straight to Platform + connections.

1. Choose path

- Install Pulse on a host first, or open Platform connections for Proxmox, TrueNAS, - and other systems Pulse should poll through their own APIs. + Choose Install on a host for agent-managed systems, or open Platform connections + for Proxmox, TrueNAS, and other systems Pulse should poll through their own APIs.

diff --git a/frontend-modern/src/components/Settings/__tests__/InfrastructureOperationsController.test.tsx b/frontend-modern/src/components/Settings/__tests__/InfrastructureOperationsController.test.tsx index 5c908d8f0..1263761ba 100644 --- a/frontend-modern/src/components/Settings/__tests__/InfrastructureOperationsController.test.tsx +++ b/frontend-modern/src/components/Settings/__tests__/InfrastructureOperationsController.test.tsx @@ -120,9 +120,9 @@ describe('InfrastructureOperationsController ownership guardrails', () => { expect(infrastructureOperationsStateSource).not.toContain('renderStopMonitoringDialog'); expect(infrastructureInstallStateSource).toContain('export const useInfrastructureInstallState'); expect(infrastructureInstallStateSource).toContain('MonitoringAPI.getState()'); - expect(infrastructureInstallStateSource).toContain('./platformConnectionsModel'); + expect(infrastructureInstallStateSource).toContain('./infrastructureWorkspaceModel'); expect(infrastructureInstallStateSource).toContain( - "navigate(buildPlatformConnectionsPath('proxmox'))", + "navigate(buildInfrastructureWorkspacePath('platforms'))", ); expect(infrastructureInstallStateSource).not.toContain( "navigate('/settings/infrastructure/proxmox')", @@ -2722,6 +2722,34 @@ describe('InfrastructureOperationsController platform commands', () => { }); }); + it('keeps TrueNAS out of host install profiles and routes the alternative CTA to platform connections', async () => { + createTokenMock.mockResolvedValue({ + token: 'test-token', + record: { + id: 'token-record', + name: 'Test Token', + prefix: 'abc', + suffix: '123', + createdAt: new Date().toISOString(), + }, + }); + + setupComponent(); + + fireEvent.click(screen.getByRole('button', { name: /Generate token/i })); + + await waitFor(() => expect(createTokenMock).toHaveBeenCalled(), { interval: 0 }); + await waitFor(() => { + expect(getTargetProfileSelect()).toBeInTheDocument(); + }); + + expect(screen.queryByRole('option', { name: 'TrueNAS SCALE agent' })).toBeNull(); + + fireEvent.click(screen.getByRole('button', { name: /Open Platform connections/i })); + + expect(navigateMock).toHaveBeenCalledWith('/settings/infrastructure/platforms'); + }); + it('tracks install command copies', async () => { createTokenMock.mockResolvedValue({ token: 'test-token', diff --git a/frontend-modern/src/components/Settings/__tests__/InfrastructureOperationsModel.test.tsx b/frontend-modern/src/components/Settings/__tests__/InfrastructureOperationsModel.test.tsx index ff8ed5079..45c184705 100644 --- a/frontend-modern/src/components/Settings/__tests__/InfrastructureOperationsModel.test.tsx +++ b/frontend-modern/src/components/Settings/__tests__/InfrastructureOperationsModel.test.tsx @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; import type { ConnectedInfrastructureItem } from '@/types/api'; import { + INSTALL_PROFILE_OPTIONS, getPlatformConnectionsPathForCapability, hasMachineInstallActions, getPowerShellInstallProfileEnvFromFlags, @@ -146,4 +147,8 @@ describe('infrastructure operations model', () => { '$env:PULSE_PROXMOX_TYPE="pbs"', ]); }); + + it('keeps api-backed TrueNAS out of the host install profile list', () => { + expect(INSTALL_PROFILE_OPTIONS.map((option) => option.value)).not.toContain('truenas'); + }); }); diff --git a/frontend-modern/src/components/Settings/__tests__/InfrastructureWorkspace.test.tsx b/frontend-modern/src/components/Settings/__tests__/InfrastructureWorkspace.test.tsx index da8901e52..eac23b6cb 100644 --- a/frontend-modern/src/components/Settings/__tests__/InfrastructureWorkspace.test.tsx +++ b/frontend-modern/src/components/Settings/__tests__/InfrastructureWorkspace.test.tsx @@ -59,7 +59,7 @@ describe('InfrastructureWorkspace', () => { expect(screen.getByText('Connect your first system')).toBeInTheDocument(); expect( screen.getByText( - 'Start with Install on a host to connect the first machine you want Pulse to monitor. If you already know you want an API-backed platform such as Proxmox or TrueNAS instead, go straight to Platform connections.', + 'Use Install on a host for the first machine that should run the unified agent. If the first system is API-backed, such as Proxmox or TrueNAS, go straight to Platform connections.', ), ).toBeInTheDocument(); expect(screen.getByText('1. Choose path')).toBeInTheDocument(); diff --git a/frontend-modern/src/components/Settings/infrastructureOperationsModel.tsx b/frontend-modern/src/components/Settings/infrastructureOperationsModel.tsx index 6d048f01c..d3fe6ce93 100644 --- a/frontend-modern/src/components/Settings/infrastructureOperationsModel.tsx +++ b/frontend-modern/src/components/Settings/infrastructureOperationsModel.tsx @@ -23,8 +23,7 @@ export type InstallProfile = | 'docker' | 'kubernetes' | 'proxmox-pve' - | 'proxmox-pbs' - | 'truenas'; + | 'proxmox-pbs'; export type SetupHandoffState = { username: string; @@ -337,13 +336,6 @@ export const INSTALL_PROFILE_OPTIONS: InstallProfileOption[] = [ description: 'Force Proxmox integration and register as a PBS node.', flags: ['--enable-proxmox', '--proxmox-type pbs'], }, - { - value: 'truenas', - label: 'TrueNAS SCALE agent', - description: - 'Use default auto-detection; installer applies TrueNAS-safe service handling automatically.', - flags: [], - }, ]; export const buildCommandsByPlatform = ( diff --git a/frontend-modern/src/components/Settings/useInfrastructureInstallState.tsx b/frontend-modern/src/components/Settings/useInfrastructureInstallState.tsx index 841e82c6b..b11a2326b 100644 --- a/frontend-modern/src/components/Settings/useInfrastructureInstallState.tsx +++ b/frontend-modern/src/components/Settings/useInfrastructureInstallState.tsx @@ -17,7 +17,6 @@ import { getPulseBaseUrl } from '@/utils/url'; import { logger } from '@/utils/logger'; import { STORAGE_KEYS } from '@/utils/localStorage'; import { buildInfrastructureWorkspacePath } from './infrastructureWorkspaceModel'; -import { buildPlatformConnectionsPath } from './platformConnectionsModel'; import { buildUnixAgentInstallCommand, buildWindowsAgentInstallCommand, @@ -471,8 +470,8 @@ Pulse prepares the first-host install token from setup so you can move straight })); }); - const openDirectProxmoxSetup = () => { - navigate(buildPlatformConnectionsPath('proxmox')); + const openPlatformConnections = () => { + navigate(buildInfrastructureWorkspacePath('platforms')); }; const openDashboard = () => { @@ -518,7 +517,7 @@ Pulse prepares the first-host install token from setup so you can move straight lookupValue, lookupWasAutoDetected, openDashboard, - openDirectProxmoxSetup, + openPlatformConnections, openInfrastructureInventory, requiresToken, selectedAgentUrl, diff --git a/frontend-modern/src/components/SetupWizard/SetupCompletionPanel.tsx b/frontend-modern/src/components/SetupWizard/SetupCompletionPanel.tsx index 1f49f73ae..4112f06fa 100644 --- a/frontend-modern/src/components/SetupWizard/SetupCompletionPanel.tsx +++ b/frontend-modern/src/components/SetupWizard/SetupCompletionPanel.tsx @@ -50,28 +50,28 @@ interface CompleteStepProps { const UNIFIED_RESOURCE_GUIDANCE = { title: 'What happens next', description: - 'Pulse is now secured. Your next step is to install the Pulse agent on the first system you want to monitor, then let Pulse discover and enrich that system over time.', + 'Pulse is now secured. Next, choose the first infrastructure path: use Infrastructure Install for a host that should run the unified agent, or use Platform connections for API-backed platforms like Proxmox and TrueNAS.', steps: [ { title: 'Open Infrastructure Install', description: - 'Use the canonical install workspace where Pulse prepares the first-host install token from setup and keeps the connection settings together.', + 'Use the canonical install workspace where Pulse prepares the first-host install token from setup and keeps Platform connections beside it when the first target is API-backed.', }, { title: 'Copy the command for your target system', description: - 'Choose Linux, macOS, Windows, or another supported target and copy the matching command.', + 'Choose Linux, macOS, Windows, or another supported target only when the first system should run the unified agent directly.', }, { title: 'Run it on the first host you want to monitor', description: - 'When the agent connects, Pulse creates your first monitored system and you can add more infrastructure from there.', + 'When that agent-managed host connects, Pulse creates your first monitored system and you can add more infrastructure from there.', }, ], inventoryFacts: [ 'Start with one host, then add more systems later from the same install workspace.', 'Infrastructure Install owns the token, connection URL, TLS/CA settings, and platform-specific commands.', - 'Platform connections remains available for API-backed platforms like Proxmox and TrueNAS when you need it.', + 'API-backed platforms like Proxmox and TrueNAS use Platform connections instead of a dedicated install profile in Infrastructure Install.', ], } as const; diff --git a/frontend-modern/src/components/SetupWizard/__tests__/SetupCompletionPanel.guardrails.test.ts b/frontend-modern/src/components/SetupWizard/__tests__/SetupCompletionPanel.guardrails.test.ts index 4b7c9b2c8..055c4804c 100644 --- a/frontend-modern/src/components/SetupWizard/__tests__/SetupCompletionPanel.guardrails.test.ts +++ b/frontend-modern/src/components/SetupWizard/__tests__/SetupCompletionPanel.guardrails.test.ts @@ -32,7 +32,7 @@ describe('SetupCompletionPanel guardrails', () => { expect(setupCompletionPanelSource).toContain('First host first'); expect(setupCompletionPanelSource).toContain('Start with one host, then add more systems later from the same install workspace.'); expect(setupCompletionPanelSource).toContain( - 'Platform connections remains available for API-backed platforms like Proxmox and TrueNAS when you need it.', + 'API-backed platforms like Proxmox and TrueNAS use Platform connections instead of a dedicated install profile in Infrastructure Install.', ); expect(setupCompletionPanelSource).not.toContain('Smart Auto-Detection'); expect(setupCompletionPanelSource).not.toContain('Agent Metrics'); diff --git a/frontend-modern/src/components/SetupWizard/__tests__/SetupCompletionPanel.test.tsx b/frontend-modern/src/components/SetupWizard/__tests__/SetupCompletionPanel.test.tsx index 6e94f4409..c23a26655 100644 --- a/frontend-modern/src/components/SetupWizard/__tests__/SetupCompletionPanel.test.tsx +++ b/frontend-modern/src/components/SetupWizard/__tests__/SetupCompletionPanel.test.tsx @@ -123,7 +123,12 @@ describe('SetupCompletionPanel', () => { ).toBeInTheDocument(); expect( screen.getByText( - 'Use the canonical install workspace where Pulse prepares the first-host install token from setup and keeps the connection settings together.', + 'Use the canonical install workspace where Pulse prepares the first-host install token from setup and keeps Platform connections beside it when the first target is API-backed.', + ), + ).toBeInTheDocument(); + expect( + screen.getByText( + 'API-backed platforms like Proxmox and TrueNAS use Platform connections instead of a dedicated install profile in Infrastructure Install.', ), ).toBeInTheDocument();