Shift connected setup completion to dashboard

This commit is contained in:
rcourtman
2026-03-27 10:28:56 +00:00
parent 53154ccb8a
commit aa64753fbe
4 changed files with 64 additions and 22 deletions
@@ -165,7 +165,10 @@ management, and fleet control surfaces.
be saved now should be visible before the operator leaves the screen, and
the completion surface should present one canonical primary next-step path
into Infrastructure Install instead of repeating competing install or
dashboard CTAs across multiple sections.
dashboard CTAs across multiple sections. Once the first monitored host is
already connected, that same surface must pivot its primary CTA and headline
to `/` so the operator is sent to the dashboard rather than being told to
install the first host again.
## Current State
@@ -1,4 +1,12 @@
import { Component, createSignal, createEffect, onCleanup, Show, For } from 'solid-js';
import {
Component,
createSignal,
createEffect,
createMemo,
onCleanup,
Show,
For,
} from 'solid-js';
import { useNavigate } from '@solidjs/router';
import { unwrap } from 'solid-js/store';
import { copyToClipboard } from '@/utils/clipboard';
@@ -318,6 +326,8 @@ Keep these credentials secure!
navigate(RELAY_SETTINGS_PATH);
};
const hasConnectedAgents = createMemo(() => connectedAgents().length > 0);
return (
<div class="max-w-2xl mx-auto bg-surface border border-border overflow-hidden animate-fade-in relative rounded-md p-6 sm:p-8 text-center text-base-content">
<div class="relative z-10">
@@ -334,11 +344,12 @@ Keep these credentials secure!
</svg>
</div>
<h1 class="text-2xl sm:text-3xl font-bold tracking-tight text-base-content mb-2">
Install your first monitored host
{hasConnectedAgents() ? 'First monitored host connected' : 'Install your first monitored host'}
</h1>
<p class="text-slate-500 dark:text-emerald-300 font-light text-sm sm:text-base">
Your admin account is ready. Next, open Infrastructure Install and run the generated
command on the first system you want Pulse to monitor.
{hasConnectedAgents()
? 'Your admin account is ready and Pulse is already receiving telemetry. Open the dashboard to verify your first overview, or return to Infrastructure Install when you want to add more systems.'
: 'Your admin account is ready. Next, open Infrastructure Install and run the generated command on the first system you want Pulse to monitor.'}
</p>
</div>
@@ -408,8 +419,8 @@ Keep these credentials secure!
</span>
</span>
<p class="mt-1 text-xs text-muted max-w-xl">
Save the admin login and API token before leaving this screen, then continue into
Infrastructure Install for the first host.
Save the admin login and API token before leaving this screen, then continue into{' '}
{hasConnectedAgents() ? 'the dashboard or Infrastructure Install.' : 'Infrastructure Install for the first host.'}
</p>
</div>
</div>
@@ -629,13 +640,12 @@ Keep these credentials secure!
d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
/>
</svg>
Install your first host
{hasConnectedAgents() ? 'Open your first dashboard view' : 'Install your first host'}
</h3>
<p class="mt-2 text-xs text-muted max-w-xl">
The canonical install flow now lives in Infrastructure Operations. Open that
workspace to generate an install token, set the agent connection URL, configure TLS
or custom CA options, and copy the correct command for the first system you want
Pulse to monitor.
{hasConnectedAgents()
? 'Pulse already has a live monitored system. Open the dashboard to confirm the first overview, then return to Infrastructure Install any time you want to add more hosts or regenerate commands.'
: 'The canonical install flow now lives in Infrastructure Operations. Open that workspace to generate an install token, set the agent connection URL, configure TLS or custom CA options, and copy the correct command for the first system you want Pulse to monitor.'}
</p>
</div>
<div class="rounded-sm bg-blue-50 px-2 py-1 text-[10px] font-medium text-blue-700 dark:bg-blue-900 dark:text-blue-300">
@@ -647,31 +657,37 @@ Keep these credentials secure!
Next step
</div>
<div class="mt-2 text-sm text-base-content">
Open Infrastructure Install to bring your first monitored system into Pulse.
{hasConnectedAgents()
? 'Open the dashboard to review your first connected system.'
: 'Open Infrastructure Install to bring your first monitored system into Pulse.'}
</div>
<div class="mt-2 text-xs text-muted">
Use that workspace any time you want to add more systems later.
{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.'}
</div>
</div>
<div class="mt-4 flex flex-col gap-3 sm:flex-row">
<button
onClick={handleOpenInstallWorkspace}
onClick={() =>
hasConnectedAgents() ? handleGoToDashboard() : handleOpenInstallWorkspace()
}
class="inline-flex items-center justify-center gap-2 rounded-md bg-blue-600 px-4 py-3 text-sm font-semibold text-white transition-colors hover:bg-blue-700"
>
Open Infrastructure Install
{hasConnectedAgents() ? 'Go to Dashboard' : 'Open Infrastructure Install'}
</button>
<Show when={connectedAgents().length > 0}>
<Show when={hasConnectedAgents()}>
<button
onClick={handleGoToDashboard}
onClick={handleOpenInstallWorkspace}
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"
>
Go to Dashboard
Open Infrastructure Install
</button>
</Show>
</div>
</div>
<Show when={connectedAgents().length > 0}>
<Show when={hasConnectedAgents()}>
<div class="bg-indigo-50 dark:bg-indigo-900 rounded-md border border-indigo-100 dark:border-indigo-800 p-5 text-left mt-8 overflow-hidden relative">
<div class="flex items-start gap-4 relative z-10">
<div class="flex h-12 w-12 items-center justify-center rounded-md bg-indigo-600 text-white shrink-0 border border-indigo-500">
@@ -55,6 +55,13 @@ describe('SetupCompletionPanel guardrails', () => {
expect(setupCompletionPanelSource).toContain('Save the admin login and API token before leaving this screen');
expect(setupCompletionPanelSource).toContain('Recommended next step');
expect(setupCompletionPanelSource).toContain('Go to Dashboard');
expect(setupCompletionPanelSource).toContain('First monitored host connected');
expect(setupCompletionPanelSource).toContain(
'hasConnectedAgents() ? handleGoToDashboard() : handleOpenInstallWorkspace()',
);
expect(setupCompletionPanelSource).toContain(
"{hasConnectedAgents() ? 'Go to Dashboard' : 'Open Infrastructure Install'}",
);
expect(setupCompletionPanelSource).not.toContain(
"connectedAgents().length > 0 ? 'Go to Dashboard' : 'Open Infrastructure Install'",
);
@@ -1,5 +1,5 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { cleanup, fireEvent, render, screen, waitFor } from '@solidjs/testing-library';
import { cleanup, fireEvent, render, screen, waitFor, within } from '@solidjs/testing-library';
import { SetupCompletionPanel } from '../SetupCompletionPanel';
import type { WizardState } from '../SetupWizard';
@@ -203,9 +203,25 @@ describe('SetupCompletionPanel', () => {
});
expect(screen.getByText('Tower')).toBeInTheDocument();
expect(screen.getByText('First monitored host connected')).toBeInTheDocument();
expect(
screen.getByText(
'Your admin account is ready and Pulse is already receiving telemetry. Open the dashboard to verify your first overview, or return to Infrastructure Install when you want to add more systems.',
),
).toBeInTheDocument();
expect(
screen.getByText('Open the dashboard to review your first connected system.'),
).toBeInTheDocument();
expect(screen.getAllByRole('button', { name: 'Go to Dashboard' }).length).toBeGreaterThan(0);
expect(
screen.getAllByRole('button', { name: 'Open Infrastructure Install' }).length,
).toBeGreaterThan(0);
fireEvent.click(screen.getAllByRole('button', { name: 'Go to Dashboard' })[0]);
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');
expect(nextStepCard).not.toBeNull();
fireEvent.click(within(nextStepCard as HTMLElement).getByRole('button', { name: 'Go to Dashboard' }));
expect(onComplete).toHaveBeenCalledWith('/');
});