mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-11 14:00:29 +00:00
feat(setup): add platform-connections handoff
This commit is contained in:
@@ -149,7 +149,8 @@ management, and fleet control surfaces.
|
||||
that route as the first-host install step, and present `Platform
|
||||
connections` as the named API-backed alternative for Proxmox, TrueNAS, and
|
||||
future provider integrations rather than leaving post-setup next actions
|
||||
implicit.
|
||||
implicit. That API-backed alternative must be a real first-run handoff
|
||||
control, not prose-only guidance.
|
||||
6. Keep `frontend-modern/src/components/Settings/InfrastructureInstallerSection.tsx`
|
||||
oriented around the first monitored host. Install-token generation,
|
||||
governed command copy, and install instructions belong to the canonical
|
||||
|
||||
@@ -85,6 +85,7 @@ interface ConnectedAgent {
|
||||
|
||||
const RELAY_SETTINGS_PATH = '/settings/system-relay';
|
||||
const INFRASTRUCTURE_INSTALL_PATH = '/settings/infrastructure/install';
|
||||
const INFRASTRUCTURE_PLATFORMS_PATH = '/settings/infrastructure/platforms';
|
||||
const SETUP_WIZARD_TELEMETRY_SURFACE = 'setup_wizard_complete';
|
||||
|
||||
const pd = (resource: Resource) =>
|
||||
@@ -254,6 +255,7 @@ export const SetupCompletionPanel: Component<CompleteStepProps> = (props) => {
|
||||
const downloadCredentials = () => {
|
||||
const baseUrl = getPulseBaseUrl();
|
||||
const installWorkspaceUrl = `${baseUrl.replace(/\/$/, '')}${INFRASTRUCTURE_INSTALL_PATH}`;
|
||||
const platformConnectionsUrl = `${baseUrl.replace(/\/$/, '')}${INFRASTRUCTURE_PLATFORMS_PATH}`;
|
||||
const content = `Pulse Credentials
|
||||
==================
|
||||
Generated: ${new Date().toISOString()}
|
||||
@@ -272,12 +274,20 @@ Infrastructure Install Workspace:
|
||||
---------------------------------
|
||||
${installWorkspaceUrl}
|
||||
|
||||
Platform Connections Workspace:
|
||||
-------------------------------
|
||||
${platformConnectionsUrl}
|
||||
|
||||
Use the Infrastructure Install workspace to:
|
||||
- continue with the first-host install token Pulse prepares from setup
|
||||
- choose the agent connection URL
|
||||
- configure TLS and custom CA options
|
||||
- copy Linux, macOS, Windows, and related install commands
|
||||
|
||||
Use the Platform connections workspace when:
|
||||
- the first system is API-backed, such as Proxmox or TrueNAS
|
||||
- Pulse should poll that platform directly instead of starting with a host install
|
||||
|
||||
Keep these credentials secure!
|
||||
`;
|
||||
|
||||
@@ -296,6 +306,10 @@ Keep these credentials secure!
|
||||
props.onComplete(INFRASTRUCTURE_INSTALL_PATH);
|
||||
};
|
||||
|
||||
const handleOpenPlatformConnections = () => {
|
||||
props.onComplete(INFRASTRUCTURE_PLATFORMS_PATH);
|
||||
};
|
||||
|
||||
const handleGoToDashboard = () => {
|
||||
props.onComplete('/');
|
||||
};
|
||||
@@ -664,7 +678,7 @@ Keep these credentials secure!
|
||||
<div class="mt-2 text-xs text-muted">
|
||||
{hasConnectedAgents()
|
||||
? 'Infrastructure Install stays available any time you want to add more systems later.'
|
||||
: 'Use that workspace any time you want to add more systems later.'}
|
||||
: 'If the first system is API-backed, use Platform connections instead of starting with host install.'}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 flex flex-col gap-3 sm:flex-row">
|
||||
@@ -676,6 +690,14 @@ Keep these credentials secure!
|
||||
>
|
||||
{hasConnectedAgents() ? 'Go to Dashboard' : 'Open Infrastructure Install'}
|
||||
</button>
|
||||
<Show when={!hasConnectedAgents()}>
|
||||
<button
|
||||
onClick={handleOpenPlatformConnections}
|
||||
class="inline-flex items-center justify-center gap-2 rounded-md border border-border px-4 py-3 text-sm font-medium text-base-content transition-colors hover:bg-surface-hover"
|
||||
>
|
||||
Open Platform connections
|
||||
</button>
|
||||
</Show>
|
||||
<Show when={hasConnectedAgents()}>
|
||||
<button
|
||||
onClick={handleOpenInstallWorkspace}
|
||||
|
||||
+11
@@ -6,15 +6,22 @@ describe('SetupCompletionPanel guardrails', () => {
|
||||
expect(setupCompletionPanelSource).toContain(
|
||||
"const INFRASTRUCTURE_INSTALL_PATH = '/settings/infrastructure/install';",
|
||||
);
|
||||
expect(setupCompletionPanelSource).toContain(
|
||||
"const INFRASTRUCTURE_PLATFORMS_PATH = '/settings/infrastructure/platforms';",
|
||||
);
|
||||
expect(setupCompletionPanelSource).toContain('Open Infrastructure Install');
|
||||
expect(setupCompletionPanelSource).toContain('Open Platform connections');
|
||||
expect(setupCompletionPanelSource).toContain('Infrastructure Install Workspace');
|
||||
expect(setupCompletionPanelSource).toContain('Platform Connections Workspace');
|
||||
expect(setupCompletionPanelSource).toContain('Credentials you must save now');
|
||||
expect(setupCompletionPanelSource).toContain('Shown during setup');
|
||||
expect(setupCompletionPanelSource).toContain('props.onComplete(INFRASTRUCTURE_INSTALL_PATH);');
|
||||
expect(setupCompletionPanelSource).toContain('props.onComplete(INFRASTRUCTURE_PLATFORMS_PATH);');
|
||||
expect(setupCompletionPanelSource).toContain('Use the Infrastructure Install workspace to:');
|
||||
expect(setupCompletionPanelSource).toContain(
|
||||
'continue with the first-host install token Pulse prepares from setup',
|
||||
);
|
||||
expect(setupCompletionPanelSource).toContain('Use the Platform connections workspace when:');
|
||||
expect(setupCompletionPanelSource).toContain('configure TLS and custom CA options');
|
||||
expect(setupCompletionPanelSource).toContain('runStartProTrialAction({');
|
||||
expect(setupCompletionPanelSource).not.toContain('getUpgradeActionUrlOrFallback');
|
||||
@@ -34,6 +41,9 @@ describe('SetupCompletionPanel guardrails', () => {
|
||||
expect(setupCompletionPanelSource).toContain(
|
||||
'API-backed platforms like Proxmox and TrueNAS use Platform connections instead of a dedicated install profile in Infrastructure Install.',
|
||||
);
|
||||
expect(setupCompletionPanelSource).toContain(
|
||||
'If the first system is API-backed, use Platform connections instead of starting with host install.',
|
||||
);
|
||||
expect(setupCompletionPanelSource).not.toContain('Smart Auto-Detection');
|
||||
expect(setupCompletionPanelSource).not.toContain('Agent Metrics');
|
||||
expect(setupCompletionPanelSource).not.toContain('ProxmoxIcon');
|
||||
@@ -70,6 +80,7 @@ describe('SetupCompletionPanel guardrails', () => {
|
||||
expect(setupCompletionPanelSource).toContain(
|
||||
"{hasConnectedAgents() ? 'Go to Dashboard' : 'Open Infrastructure Install'}",
|
||||
);
|
||||
expect(setupCompletionPanelSource).toContain('handleOpenPlatformConnections');
|
||||
expect(setupCompletionPanelSource).not.toContain(
|
||||
"connectedAgents().length > 0 ? 'Go to Dashboard' : 'Open Infrastructure Install'",
|
||||
);
|
||||
|
||||
@@ -110,6 +110,7 @@ describe('SetupCompletionPanel', () => {
|
||||
|
||||
expect(screen.getByText('What happens next')).toBeInTheDocument();
|
||||
expect(screen.getAllByText('Open Infrastructure Install').length).toBeGreaterThan(0);
|
||||
expect(screen.getByRole('button', { name: 'Open Platform connections' })).toBeInTheDocument();
|
||||
expect(screen.getByText('Credentials you must save now')).toBeInTheDocument();
|
||||
expect(screen.getByText('Shown during setup')).toBeInTheDocument();
|
||||
expect(screen.getByText('admin')).toBeInTheDocument();
|
||||
@@ -147,6 +148,16 @@ describe('SetupCompletionPanel', () => {
|
||||
expect(onComplete).toHaveBeenCalledWith('/settings/infrastructure/install');
|
||||
});
|
||||
|
||||
it('hands API-backed starts into the canonical platform connections workspace', async () => {
|
||||
const onComplete = vi.fn();
|
||||
|
||||
render(() => <SetupCompletionPanel state={baseState} onComplete={onComplete} />);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Open Platform connections' }));
|
||||
|
||||
expect(onComplete).toHaveBeenCalledWith('/settings/infrastructure/platforms');
|
||||
});
|
||||
|
||||
it('downloads credentials that point operators to the install workspace instead of inline commands', async () => {
|
||||
const anchorClickMock = vi.fn();
|
||||
const createElementSpy = vi.spyOn(document, 'createElement').mockImplementation((tagName) => {
|
||||
@@ -173,9 +184,14 @@ describe('SetupCompletionPanel', () => {
|
||||
expect(content).toContain('Admin API Token:');
|
||||
expect(content).toContain('Infrastructure Install Workspace:');
|
||||
expect(content).toContain('https://pulse.example.com/settings/infrastructure/install');
|
||||
expect(content).toContain('Platform Connections Workspace:');
|
||||
expect(content).toContain('https://pulse.example.com/settings/infrastructure/platforms');
|
||||
expect(content).toContain(
|
||||
'continue with the first-host install token Pulse prepares from setup',
|
||||
);
|
||||
expect(content).toContain(
|
||||
'the first system is API-backed, such as Proxmox or TrueNAS',
|
||||
);
|
||||
expect(content).not.toContain('Example Install Command');
|
||||
expect(content).not.toContain('Example Windows Install Command');
|
||||
|
||||
@@ -229,6 +245,7 @@ describe('SetupCompletionPanel', () => {
|
||||
expect(
|
||||
screen.getAllByRole('button', { name: 'Open Infrastructure Install' }).length,
|
||||
).toBeGreaterThan(0);
|
||||
expect(screen.queryByRole('button', { name: 'Open Platform connections' })).not.toBeInTheDocument();
|
||||
|
||||
const nextStepHeading = screen.getByRole('heading', { name: 'Open your first dashboard view' });
|
||||
const nextStepCard = nextStepHeading.closest('div.bg-surface.rounded-md.border.border-border.p-6.text-left.mb-6');
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('Setup completion platform connections handoff', () => {
|
||||
test('preview exposes Platform connections as the API-backed first-run alternative', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto('/preview/setup-complete', { waitUntil: 'domcontentloaded' });
|
||||
|
||||
await expect(page.getByText('What happens next')).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: 'Open Infrastructure Install' })).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: 'Open Platform connections' })).toBeVisible();
|
||||
await expect(
|
||||
page.getByText(
|
||||
'If the first system is API-backed, use Platform connections instead of starting with host install.',
|
||||
),
|
||||
).toBeVisible();
|
||||
|
||||
await page.getByRole('button', { name: 'Open Platform connections' }).click();
|
||||
await page.waitForURL(/\/settings\/infrastructure\/platforms$/, { timeout: 15_000 });
|
||||
await expect(
|
||||
page.getByRole('heading', { name: 'Infrastructure Operations', exact: true }),
|
||||
).toBeVisible();
|
||||
await expect(page.getByRole('tab', { name: 'Platform connections' })).toHaveAttribute(
|
||||
'aria-selected',
|
||||
'true',
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user