diff --git a/docs/release-control/v6/internal/subsystems/agent-lifecycle.md b/docs/release-control/v6/internal/subsystems/agent-lifecycle.md index b60d7bdff5..08fdde73da 100644 --- a/docs/release-control/v6/internal/subsystems/agent-lifecycle.md +++ b/docs/release-control/v6/internal/subsystems/agent-lifecycle.md @@ -313,6 +313,16 @@ an add-only capacity posture. endpoints that own admission checks, and the `Disabled` flag on PVE/PBS/PMG surfaced by that ledger must remain a pause-only signal rather than an installer pre-flight gate. + The unified add surface is + `frontend-modern/src/components/Settings/ConnectionEditor/ConnectionEditor.tsx`, + mounted by `InfrastructureWorkspace.tsx` in place of the legacy + type-picker step tree. The editor's probe step calls the aggregator + probe endpoint and dispatches the detected or manually-selected type + into a credential slot that renders the existing per-type panel; it + must not bypass the probe endpoint or fabricate probe candidates, and + the agent credential slot must continue to reach + `InfrastructureInstallerSection.tsx` so install handoffs remain on the + canonical unified-agent install path. ## Forbidden Paths diff --git a/docs/release-control/v6/internal/subsystems/frontend-primitives.md b/docs/release-control/v6/internal/subsystems/frontend-primitives.md index 7a2cd885b0..919e452e86 100644 --- a/docs/release-control/v6/internal/subsystems/frontend-primitives.md +++ b/docs/release-control/v6/internal/subsystems/frontend-primitives.md @@ -230,6 +230,12 @@ work extends shared components instead of creating new local variants. default ledger plus route-backed `Connections` and `Install` workspaces inside that destination, while each secondary flow still stays single-purpose instead of stacking multiple workspace surfaces at once. + `InfrastructureWorkspace.tsx` must open a new connection through + `frontend-modern/src/components/Settings/ConnectionEditor/ConnectionEditor.tsx`, + not through a per-type picker or per-type step tree. The editor's probe + step is the canonical entry point; credential slots are dispatched by the + detected or manually-selected type and must reach the existing per-type + settings panel rather than diverging into a parallel add surface. 6. Keep Proxmox deep-link route selection on the shared settings-navigation boundary. `frontend-modern/src/components/Settings/settingsNavigationModel.ts` and `frontend-modern/src/components/Settings/useSettingsNavigation.ts` must treat the canonical PBS and PMG Proxmox deep links as agent-selection authority even though those URLs resolve to the shared `infrastructure-operations` tab. Reloading or remounting on a PBS or PMG deep link must not silently fall back to the PVE selector state. 7. Keep shared storage feature presenters on canonical platform truth. When reusable storage presenters under `frontend-modern/src/features/storageBackups/` classify canonical resources for the shared storage route, API-backed virtualization datastores such as VMware must stay inventory-only datastores instead of inheriting PBS-specific backup-repository or protected-target copy from older fallback branches. 8. Keep shared source/platform vocabulary on the governed manifest boundary. `frontend-modern/src/utils/platformSupportManifest.generated.ts` must be the tracked frontend projection of `docs/release-control/v6/internal/PLATFORM_SUPPORT_MANIFEST.json`, `frontend-modern/src/utils/platformSupportManifest.ts`, `frontend-modern/src/utils/sourcePlatforms.ts`, and `frontend-modern/src/utils/sourcePlatformOptions.ts` must consume that generated projection instead of embedding divergent future-label lists, setup/onboarding path allowlists, or presentation-only guesses, and `frontend-modern/scripts/canonical-platform-audit.mjs` must fail when the generated projection drifts from the governed manifest. diff --git a/frontend-modern/src/components/Settings/AddSystemPicker.tsx b/frontend-modern/src/components/Settings/AddSystemPicker.tsx deleted file mode 100644 index 4d8ad7624e..0000000000 --- a/frontend-modern/src/components/Settings/AddSystemPicker.tsx +++ /dev/null @@ -1,142 +0,0 @@ -import { Component, For } from 'solid-js'; -import { Dialog } from '@/components/shared/Dialog'; - -export type AddSystemChoiceKind = 'pve' | 'pbs' | 'pmg' | 'truenas' | 'vmware' | 'agent'; -export type AddSystemChoiceMethod = 'api' | 'agent'; - -export interface AddSystemChoice { - kind: AddSystemChoiceKind; - title: string; - description: string; - method: AddSystemChoiceMethod; - methodLabel: string; -} - -export const ADD_SYSTEM_CHOICES: readonly AddSystemChoice[] = [ - { - kind: 'agent', - title: 'Install on a host', - description: - 'Generate an install token and run the Pulse agent on the host itself. Best for the first monitored system or anything without a supported API.', - method: 'agent', - methodLabel: 'Agent install', - }, - { - kind: 'pve', - title: 'Proxmox VE', - description: 'Connect a Proxmox cluster or standalone node. Pulse polls the Proxmox API.', - method: 'api', - methodLabel: 'API connection', - }, - { - kind: 'pbs', - title: 'Proxmox Backup Server', - description: 'Connect a PBS instance so Pulse can track datastores, sync, and verify jobs.', - method: 'api', - methodLabel: 'API connection', - }, - { - kind: 'pmg', - title: 'Proxmox Mail Gateway', - description: 'Connect a PMG instance for queue, quarantine, and mail-stats reporting.', - method: 'api', - methodLabel: 'API connection', - }, - { - kind: 'truenas', - title: 'TrueNAS SCALE', - description: 'Connect a TrueNAS system so Pulse can report pools, datasets, and apps.', - method: 'api', - methodLabel: 'API connection', - }, - { - kind: 'vmware', - title: 'VMware vSphere or ESXi', - description: 'Connect a vCenter or ESXi host. Pulse polls the vSphere API.', - method: 'api', - methodLabel: 'API connection', - }, -]; - -interface AddSystemPickerProps { - isOpen: boolean; - onClose: () => void; - onSelect: (choice: AddSystemChoice) => void; - onManageProfiles?: () => void; -} - -export const AddSystemPicker: Component = (props) => { - return ( - -
-
-
-

- Add infrastructure -

-

- Choose the system or platform you want Pulse to start monitoring. -

-
- -
-
    - - {(choice) => ( -
  • - -
  • - )} -
    -
- - {(onManageProfiles) => ( -
-
- Agent profiles change install defaults for agent-based systems. -
- -
- )} -
-
-
- ); -}; diff --git a/frontend-modern/src/components/Settings/InfrastructureWorkspace.tsx b/frontend-modern/src/components/Settings/InfrastructureWorkspace.tsx index 281c9fb528..94423ed745 100644 --- a/frontend-modern/src/components/Settings/InfrastructureWorkspace.tsx +++ b/frontend-modern/src/components/Settings/InfrastructureWorkspace.tsx @@ -1,15 +1,16 @@ -import { Component, For, Show, createEffect, createMemo, createSignal } from 'solid-js'; +import { Component, Show, createEffect, createMemo, createSignal } from 'solid-js'; import { useLocation, useNavigate } from '@solidjs/router'; import { Dialog } from '@/components/shared/Dialog'; import { presentationPolicyIsReadOnly } from '@/stores/sessionPresentationPolicy'; import { AgentProfilesPanel } from './AgentProfilesPanel'; -import { ADD_SYSTEM_CHOICES, type AddSystemChoice } from './AddSystemPicker'; import { ConnectionsTable, type ConnectionsTableHeaderAction } from './ConnectionsTable'; import { buildInfrastructureSystemRows, type InfrastructureSystemRow, type SystemManageAction, } from './connectionsTableModel'; +import { ConnectionEditor } from './ConnectionEditor/ConnectionEditor'; +import type { ConnectionType } from '@/api/connections'; import { InfrastructureActiveRowDetails } from './InfrastructureActiveRowDetails'; import { InfrastructureInstallerSection } from './InfrastructureInstallerSection'; import { InfrastructureIgnoredRowDetails } from './InfrastructureIgnoredRowDetails'; @@ -21,7 +22,6 @@ import { buildInfrastructureWorkspacePath, deriveAddStepFromLegacyPath, type InfrastructureAddStep, - type InfrastructurePanelStep, } from './infrastructureWorkspaceModel'; import type { InfrastructurePlatformSettingsProps } from './proxmoxSettingsModel'; import type { NodeType } from './infrastructureSettingsModel'; @@ -32,13 +32,13 @@ import { export type InfrastructureWorkspaceProps = InfrastructurePlatformSettingsProps; -const STEP_TITLES: Record = { - agent: 'Install on a host', - pve: 'Proxmox VE', - pbs: 'Proxmox Backup Server', - pmg: 'Proxmox Mail Gateway', - truenas: 'TrueNAS SCALE', - vmware: 'VMware vSphere / ESXi', +const ADD_STEP_TO_TYPE: Record = { + agent: 'agent', + pve: 'pve', + pbs: 'pbs', + pmg: 'pmg', + truenas: 'truenas', + vmware: 'vmware', }; const InfrastructureWorkspaceContent: Component = (props) => { @@ -46,33 +46,40 @@ const InfrastructureWorkspaceContent: Component = const location = useLocation(); const state = useInfrastructureOperationsContext(); - const [panelStep, setPanelStep] = createSignal(null); + const [addDrawerOpen, setAddDrawerOpen] = createSignal(false); + const [initialAddType, setInitialAddType] = createSignal(null); const [showAgentProfiles, setShowAgentProfiles] = createSignal(false); const readOnly = createMemo(() => presentationPolicyIsReadOnly()); - // Redirect legacy deep links and open the appropriate panel. + // Redirect legacy deep links and pre-select the matching type in the editor. createEffect(() => { const path = location.pathname; if (path === '/settings/infrastructure') return; const step = deriveAddStepFromLegacyPath(path); navigate(buildInfrastructureWorkspacePath(), { replace: true }); - if (step && !readOnly()) { - setPanelStep(step); + if (!readOnly()) { + setAddDrawerOpen(true); + if (step && step !== 'pick') { + setInitialAddType(ADD_STEP_TO_TYPE[step]); + } else { + setInitialAddType(null); + } } }); // Auto-open the agent installer when a setup handoff is waiting. createEffect(() => { - if (state.setupHandoff?.() && panelStep() === null && !readOnly()) { - setPanelStep('agent'); + if (state.setupHandoff?.() && !addDrawerOpen() && !readOnly()) { + setAddDrawerOpen(true); + setInitialAddType('agent'); } }); // Close add panel in read-only mode. createEffect(() => { - if (readOnly() && panelStep() !== null) { - setPanelStep(null); + if (readOnly() && addDrawerOpen()) { + setAddDrawerOpen(false); } }); @@ -90,7 +97,8 @@ const InfrastructureWorkspaceContent: Component = { label: 'Add infrastructure', onSelect: () => { - setPanelStep('pick'); + setInitialAddType(null); + setAddDrawerOpen(true); setShowAgentProfiles(false); }, tone: 'primary' as const, @@ -113,42 +121,22 @@ const InfrastructureWorkspaceContent: Component = } }; - const handleAddSystem = (choice: AddSystemChoice) => { - setShowAgentProfiles(false); - setPanelStep(choice.kind as InfrastructureAddStep); - }; - - const closePanel = () => { - setPanelStep(null); + const closeAddDrawer = () => { + setAddDrawerOpen(false); + setInitialAddType(null); setShowAgentProfiles(false); }; - const goBackToPick = () => { - setShowAgentProfiles(false); - setPanelStep('pick'); - }; - - // For Proxmox: selectedAgent is derived from the active panel step. - const proxmoxAgent = createMemo(() => { - const step = panelStep(); - if (step === 'pbs') return 'pbs'; - if (step === 'pmg') return 'pmg'; - return 'pve'; - }); - - const onSelectProxmoxAgent = (agent: NodeType) => { - setPanelStep(agent as InfrastructureAddStep); - }; - - const isProxmoxStep = () => { - const step = panelStep(); - return step === 'pve' || step === 'pbs' || step === 'pmg'; - }; - - const stepTitle = () => { - const step = panelStep(); - if (!step || step === 'pick') return 'Add infrastructure'; - return STEP_TITLES[step]; + const renderProxmoxSlot = (type: NodeType) => { + const selectedAgent = () => type; + return ( + {}} + embedded + /> + ); }; return ( @@ -159,139 +147,87 @@ const InfrastructureWorkspaceContent: Component = onManageRow={(row) => handleManageAction(row.manage)} /> - {/* Add-infrastructure panel — right drawer */} + {/* Unified add-connection drawer */}
- {/* Drawer header */}
-
- - - - {stepTitle()} -
-
- - - - -
+ Add connection +
- {/* Drawer content */}
- {/* Step 1: picker */} - -
-

- Choose the system or platform you want Pulse to start monitoring. -

-
    - - {(choice) => ( -
  • -
- - {choice.methodLabel} - - - - )} - - -
- - - {/* Step 2a: agent installer */} - -
- -
-
-
Agent profiles
-
- Manage reusable install defaults for agent-based systems. -
-
- -
-
- -
-
- - {/* Step 2b: Proxmox (PVE / PBS / PMG) */} - -
- -
-
- - {/* Step 2c: TrueNAS */} - -
- -
-
- - {/* Step 2d: VMware */} - -
- -
+ +
+
+
+ Agent profiles +
+
+ Manage reusable install defaults for agent-based systems. +
+
+ +
+
+ +
+ ); + default: + return ( +
+ No credential form is wired up for the {type} type yet. +
+ ); + } + }} + /> diff --git a/frontend-modern/src/components/Settings/__tests__/AddSystemPicker.test.tsx b/frontend-modern/src/components/Settings/__tests__/AddSystemPicker.test.tsx deleted file mode 100644 index 3f315c9bed..0000000000 --- a/frontend-modern/src/components/Settings/__tests__/AddSystemPicker.test.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { cleanup, fireEvent, render, screen } from '@solidjs/testing-library'; -import { afterEach, describe, expect, it, vi } from 'vitest'; -import { ADD_SYSTEM_CHOICES, AddSystemPicker } from '../AddSystemPicker'; - -describe('AddSystemPicker', () => { - afterEach(() => cleanup()); - - it('does not render any dialog content when closed', () => { - render(() => ( - {}} onSelect={() => {}} /> - ) as any); - expect(screen.queryByRole('dialog')).toBeNull(); - }); - - it('lists one button per add-system choice including Proxmox VE, PBS, PMG, TrueNAS, VMware, and agent host', () => { - render(() => ( - {}} onSelect={() => {}} /> - ) as any); - - for (const choice of ADD_SYSTEM_CHOICES) { - expect(screen.getByText(choice.title)).toBeInTheDocument(); - } - expect(ADD_SYSTEM_CHOICES.map((c) => c.kind)).toEqual([ - 'agent', - 'pve', - 'pbs', - 'pmg', - 'truenas', - 'vmware', - ]); - }); - - it('invokes onSelect with the matching choice when a tile is clicked', () => { - const onSelect = vi.fn(); - render(() => ( - {}} onSelect={onSelect} /> - ) as any); - - fireEvent.click(screen.getByText('TrueNAS SCALE')); - expect(onSelect).toHaveBeenCalledTimes(1); - expect(onSelect.mock.calls[0][0].kind).toBe('truenas'); - expect(onSelect.mock.calls[0][0].method).toBe('api'); - }); - - it('invokes onClose when the close button is clicked', () => { - const onClose = vi.fn(); - render(() => ( - {}} /> - ) as any); - - fireEvent.click(screen.getByRole('button', { name: 'Close' })); - expect(onClose).toHaveBeenCalledTimes(1); - }); - - it('offers agent profile management as a secondary action when provided', () => { - const onManageProfiles = vi.fn(); - render(() => ( - {}} - onSelect={() => {}} - onManageProfiles={onManageProfiles} - /> - ) as any); - - fireEvent.click(screen.getByRole('button', { name: 'Manage agent profiles' })); - expect(onManageProfiles).toHaveBeenCalledTimes(1); - }); - - it('marks the agent-host choice as an agent install and everything else as an API connection', () => { - const agent = ADD_SYSTEM_CHOICES.find((c) => c.kind === 'agent'); - const apis = ADD_SYSTEM_CHOICES.filter((c) => c.kind !== 'agent'); - expect(agent?.method).toBe('agent'); - expect(apis.every((c) => c.method === 'api')).toBe(true); - }); -}); diff --git a/frontend-modern/src/components/Settings/__tests__/InfrastructureWorkspace.test.tsx b/frontend-modern/src/components/Settings/__tests__/InfrastructureWorkspace.test.tsx index 94e5b30ab1..2408cf1063 100644 --- a/frontend-modern/src/components/Settings/__tests__/InfrastructureWorkspace.test.tsx +++ b/frontend-modern/src/components/Settings/__tests__/InfrastructureWorkspace.test.tsx @@ -1,4 +1,4 @@ -import { cleanup, fireEvent, render, screen } from '@solidjs/testing-library'; +import { cleanup, fireEvent, render, screen, waitFor } from '@solidjs/testing-library'; import { createSignal } from 'solid-js'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import type { UnifiedAgentRow } from '../infrastructureOperationsModel'; @@ -82,6 +82,17 @@ vi.mock('../AgentProfilesPanel', () => ({ AgentProfilesPanel: () =>
profiles
, })); +vi.mock('@/api/connections', async () => { + const actual = await vi.importActual('@/api/connections'); + return { + ...actual, + ConnectionsAPI: { + list: vi.fn(), + probe: vi.fn().mockResolvedValue({ candidates: [], probedMs: 0 }), + }, + }; +}); + const reportingRow = (overrides: Partial = {}): UnifiedAgentRow => ({ rowKey: 'agent:tower', @@ -187,82 +198,85 @@ describe('InfrastructureWorkspace', () => { expect(screen.queryByText('lab-vcenter')).toBeNull(); }); - it('opens the type picker in the add panel when Add infrastructure is clicked', () => { + it('opens the unified add drawer with the probe step when Add infrastructure is clicked', () => { renderWorkspace(); fireEvent.click(screen.getByRole('button', { name: /Add infrastructure/i })); - expect(screen.getByText('Choose the system or platform you want Pulse to start monitoring.')).toBeInTheDocument(); - expect(screen.getByRole('button', { name: /Install on a host/i })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: /Probe address/i })).toBeInTheDocument(); + expect(screen.getByPlaceholderText(/pve01\.lan/)).toBeInTheDocument(); expect(navigateSpy).not.toHaveBeenCalled(); }); - it('shows the agent installer when Install on a host is chosen', () => { + it('routes to the agent credential slot when the user picks agent manually', () => { renderWorkspace(); fireEvent.click(screen.getByRole('button', { name: /Add infrastructure/i })); - fireEvent.click(screen.getByRole('button', { name: /Install on a host/i })); + fireEvent.click(screen.getByRole('button', { name: /Enter credentials manually/i })); + fireEvent.click(screen.getByRole('button', { name: /Agent \(install on host\)/i })); expect(screen.getByTestId('install-section')).toBeInTheDocument(); - expect(screen.queryByText('What do you want to connect?')).toBeNull(); }); - it('shows the TrueNAS panel when TrueNAS SCALE is chosen', () => { + it('routes to the TrueNAS credential slot when TrueNAS is picked manually', () => { renderWorkspace(); fireEvent.click(screen.getByRole('button', { name: /Add infrastructure/i })); + fireEvent.click(screen.getByRole('button', { name: /Enter credentials manually/i })); fireEvent.click(screen.getByRole('button', { name: /TrueNAS SCALE/i })); expect(screen.getByTestId('truenas-section')).toBeInTheDocument(); - expect(navigateSpy).not.toHaveBeenCalled(); }); - it('shows the VMware panel when VMware vSphere is chosen', () => { + it('routes to the VMware credential slot when VMware is picked manually', () => { renderWorkspace(); fireEvent.click(screen.getByRole('button', { name: /Add infrastructure/i })); - fireEvent.click(screen.getByRole('button', { name: /VMware vSphere or ESXi/i })); + fireEvent.click(screen.getByRole('button', { name: /Enter credentials manually/i })); + fireEvent.click(screen.getByRole('button', { name: /VMware vCenter/i })); expect(screen.getByTestId('vmware-section')).toBeInTheDocument(); - expect(navigateSpy).not.toHaveBeenCalled(); }); - it('shows the Proxmox panel when Proxmox VE is chosen', () => { + it('routes to the Proxmox credential slot when Proxmox VE is picked manually', () => { renderWorkspace(); fireEvent.click(screen.getByRole('button', { name: /Add infrastructure/i })); - fireEvent.click(screen.getByRole('button', { name: /Proxmox VE/i })); + fireEvent.click(screen.getByRole('button', { name: /Enter credentials manually/i })); + fireEvent.click(screen.getByRole('button', { name: /^Proxmox VE/i })); expect(screen.getByTestId('proxmox-section')).toBeInTheDocument(); - expect(navigateSpy).not.toHaveBeenCalled(); }); - it('returns to the picker via back button from a step-2 form', () => { + it('can return to the probe step from a credential slot via Back to probe', () => { renderWorkspace(); fireEvent.click(screen.getByRole('button', { name: /Add infrastructure/i })); - fireEvent.click(screen.getByRole('button', { name: /Install on a host/i })); - fireEvent.click(screen.getByRole('button', { name: /Choose different type/i })); + fireEvent.click(screen.getByRole('button', { name: /Enter credentials manually/i })); + fireEvent.click(screen.getByRole('button', { name: /Agent \(install on host\)/i })); + fireEvent.click(screen.getByRole('button', { name: /Back to probe/i })); - expect(screen.getByText('Choose the system or platform you want Pulse to start monitoring.')).toBeInTheDocument(); + expect(screen.getByRole('button', { name: /Probe address/i })).toBeInTheDocument(); expect(screen.queryByTestId('install-section')).toBeNull(); }); - it('toggles agent profiles in the agent install drawer', () => { + it('toggles agent profiles inside the agent credential slot', () => { renderWorkspace(); fireEvent.click(screen.getByRole('button', { name: /Add infrastructure/i })); - fireEvent.click(screen.getByRole('button', { name: /Install on a host/i })); + fireEvent.click(screen.getByRole('button', { name: /Enter credentials manually/i })); + fireEvent.click(screen.getByRole('button', { name: /Agent \(install on host\)/i })); fireEvent.click(screen.getByRole('button', { name: 'Manage agent profiles' })); expect(screen.getByTestId('agent-profiles')).toBeInTheDocument(); }); - it('does not use modals or child-node setup, only sets panel state on no-modal choices', () => { + it('does not mount node-modal legacy spies when a credential slot is rendered', () => { renderWorkspace(); fireEvent.click(screen.getByRole('button', { name: /Add infrastructure/i })); - fireEvent.click(screen.getByRole('button', { name: /Proxmox VE/i })); + fireEvent.click(screen.getByRole('button', { name: /Enter credentials manually/i })); + fireEvent.click(screen.getByRole('button', { name: /^Proxmox VE/i })); expect(setShowNodeModalSpy).not.toHaveBeenCalled(); expect(setEditingNodeSpy).not.toHaveBeenCalled(); @@ -279,28 +293,29 @@ describe('InfrastructureWorkspace', () => { expect(screen.getByTestId('active-details')).toBeInTheDocument(); }); - it('redirects legacy install deep link to the base route and opens the agent panel', () => { + it('redirects legacy install deep link and pre-selects the agent credential slot', async () => { mockPathname = '/settings/infrastructure/install'; renderWorkspace(); expect(navigateSpy).toHaveBeenCalledWith('/settings/infrastructure', { replace: true }); - expect(screen.getByTestId('install-section')).toBeInTheDocument(); + await waitFor(() => expect(screen.getByTestId('install-section')).toBeInTheDocument()); }); - it('redirects legacy platforms deep link to the base route and opens the picker', () => { + it('redirects legacy truenas deep link and pre-selects the TrueNAS credential slot', async () => { mockPathname = '/settings/infrastructure/platforms/truenas'; renderWorkspace(); expect(navigateSpy).toHaveBeenCalledWith('/settings/infrastructure', { replace: true }); - expect(screen.getByTestId('truenas-section')).toBeInTheDocument(); + await waitFor(() => expect(screen.getByTestId('truenas-section')).toBeInTheDocument()); }); - it('hides Add infrastructure and the add panel in read-only mode', () => { + it('hides Add infrastructure and the add drawer in read-only mode', () => { presentationPolicyIsReadOnlyMock.mockReturnValue(true); renderWorkspace(); expect(screen.queryByRole('button', { name: /Add infrastructure/i })).toBeNull(); expect(screen.queryByTestId('install-section')).toBeNull(); + expect(screen.queryByRole('button', { name: /Probe address/i })).toBeNull(); }); it('collapses read-only sessions back to the inventory and redirects', () => { diff --git a/frontend-modern/src/components/Settings/__tests__/settingsArchitecture.test.ts b/frontend-modern/src/components/Settings/__tests__/settingsArchitecture.test.ts index 0612ac2afa..96209a3186 100644 --- a/frontend-modern/src/components/Settings/__tests__/settingsArchitecture.test.ts +++ b/frontend-modern/src/components/Settings/__tests__/settingsArchitecture.test.ts @@ -896,8 +896,8 @@ describe('Settings architecture guardrails', () => { "import { Subtabs } from '@/components/shared/Subtabs'", ); expect(infrastructureWorkspaceSource).not.toContain('