Refine quick tour copy and guide labels

This commit is contained in:
rcourtman
2026-04-21 22:35:58 +01:00
parent 3c93694c5f
commit 68c1e9564d
4 changed files with 27 additions and 24 deletions
@@ -1354,7 +1354,10 @@ of the product.
Secondary disclosures such as telemetry must stay subordinate to that
orientation job: keep them as footer-level links into the canonical
privacy/settings surfaces, and do not let them crowd out the migration
wayfinding copy.
wayfinding copy. The supporting docs CTA on that surface should likewise stay
route-oriented: use a neutral `Navigation guide` label and plain present-tense
copy that helps operators understand the current IA, rather than reviving
`Migration guide` branding that pulls the tour back into v5 historical framing.
That state owner now also owns public-demo suppression: the modal must stay
closed until `sessionPresentationPolicyResolved()` is true and must fail closed
when `presentationPolicyIsDemoMode()` resolves true, so the public demo does
@@ -71,10 +71,10 @@ describe('WhatsNewModal', () => {
const dialog = await screen.findByRole('dialog', { name: 'Welcome to Pulse v6' });
expect(dialog).toBeInTheDocument();
expect(within(dialog).getByText('Step 1 of 5')).toBeInTheDocument();
expect(within(dialog).getByText('V5 to V6')).toBeInTheDocument();
expect(within(dialog).getByText(/overview for health, alerts, capacity/i)).toBeInTheDocument();
expect(within(dialog).getByText('Quick Tour')).toBeInTheDocument();
expect(within(dialog).getByText(/Start here for health, alerts, capacity/i)).toBeInTheDocument();
expect(within(dialog).queryByText('Where Things Moved')).not.toBeInTheDocument();
expect(within(dialog).getByRole('link', { name: 'Migration guide' })).toBeInTheDocument();
expect(within(dialog).getByRole('link', { name: 'Navigation guide' })).toBeInTheDocument();
expect(within(dialog).getByRole('link', { name: 'Telemetry details' })).toBeInTheDocument();
});
@@ -128,33 +128,33 @@ describe('WhatsNewModal', () => {
it('advances through the guided tour and finishes on the last step', async () => {
render(() => <WhatsNewModal />);
expect(await screen.findByText(/overview for health, alerts, capacity/i)).toBeInTheDocument();
expect(await screen.findByText(/Start here for health, alerts, capacity/i)).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: 'Next' }));
expect(await screen.findByText(/Systems live here: nodes, hosts, clusters/i)).toBeInTheDocument();
expect(await screen.findByText(/Use this for nodes, hosts, clusters/i)).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: 'Next' }));
expect(await screen.findByText(/If you looked for guests in v5/i)).toBeInTheDocument();
expect(await screen.findByText(/Use this for VMs, containers, and pods/i)).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: 'Next' }));
expect(await screen.findByText(/Datastores, pools, disks, and capacity live here/i)).toBeInTheDocument();
expect(await screen.findByText(/Use this for datastores, pools, disks, and capacity/i)).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: 'Next' }));
expect(await screen.findByText(/Backups, snapshots, and replication live here/i)).toBeInTheDocument();
expect(await screen.findByText(/Use this for backups, snapshots, and replication/i)).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Done' })).toBeInTheDocument();
});
it('lets the user jump to a tour stop directly from the stop map', async () => {
render(() => <WhatsNewModal />);
expect(await screen.findByText(/overview for health, alerts, capacity/i)).toBeInTheDocument();
expect(await screen.findByText(/Start here for health, alerts, capacity/i)).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: /Workloads/i }));
expect(await screen.findByText(/If you looked for guests in v5/i)).toBeInTheDocument();
expect(await screen.findByText(/Use this for VMs, containers, and pods/i)).toBeInTheDocument();
expect(screen.getByText('Step 3 of 5')).toBeInTheDocument();
});
it('routes the docs CTA through the migration guide', async () => {
it('routes the docs CTA through the navigation guide', async () => {
render(() => <WhatsNewModal />);
const docsLink = await screen.findByRole('link', { name: 'Migration guide' });
const docsLink = await screen.findByRole('link', { name: 'Navigation guide' });
expect(docsLink).toHaveAttribute('href', '/docs/MIGRATION_UNIFIED_NAV.md');
});
});
@@ -14,47 +14,47 @@ export const WHATS_NEW_PRIVACY_URL = PRIVACY_DOC_URL;
export const WHATS_NEW_FEATURE_CARDS: WhatsNewFeatureCard[] = [
{
accent: 'border-indigo-200 bg-indigo-50 dark:border-indigo-800 dark:bg-indigo-900',
description: 'Your new overview for health, alerts, capacity, and recent activity.',
description: 'Start here for health, alerts, capacity, and recent activity.',
icon: 'dashboard',
target: 'dashboard',
title: 'Dashboard',
},
{
accent: 'border-blue-200 bg-blue-50 dark:border-blue-800 dark:bg-blue-900',
description: 'Systems live here: nodes, hosts, clusters, and other platform roots.',
description: 'Use this for nodes, hosts, clusters, and other platform roots.',
icon: 'infrastructure',
target: 'infrastructure',
title: 'Infrastructure',
},
{
accent: 'border-purple-200 bg-purple-50 dark:border-purple-800 dark:bg-purple-900',
description: 'VMs, containers, and pods live here. If you looked for guests in v5, start here.',
description: 'Use this for VMs, containers, and pods.',
icon: 'workloads',
target: 'workloads',
title: 'Workloads',
},
{
accent: 'border-emerald-200 bg-emerald-50 dark:border-emerald-800 dark:bg-emerald-900',
description: 'Datastores, pools, disks, and capacity live here across platforms.',
description: 'Use this for datastores, pools, disks, and capacity.',
icon: 'storage',
target: 'storage',
title: 'Storage',
},
{
accent: 'border-amber-200 bg-amber-50 dark:border-amber-800 dark:bg-amber-900',
description: 'Backups, snapshots, and replication live here.',
description: 'Use this for backups, snapshots, and replication.',
icon: 'recovery',
target: 'recovery',
title: 'Recovery',
},
];
export const WHATS_NEW_KICKER_LABEL = 'V5 to V6';
export const WHATS_NEW_KICKER_LABEL = 'Quick Tour';
export const WHATS_NEW_TITLE = 'Welcome to Pulse v6';
export const WHATS_NEW_PROGRESS_PREFIX = 'Step';
export const WHATS_NEW_BACK_LABEL = 'Back';
export const WHATS_NEW_CLOSE_LABEL = 'Close';
export const WHATS_NEW_DOCS_LABEL = 'Migration guide';
export const WHATS_NEW_DOCS_LABEL = 'Navigation guide';
export const WHATS_NEW_DO_NOT_SHOW_LABEL = "Don't show again";
export const WHATS_NEW_NEXT_LABEL = 'Next';
export const WHATS_NEW_PRIMARY_ACTION_LABEL = 'Done';
@@ -133,7 +133,7 @@ test.describe('Telemetry disclosure', () => {
.not.toBe(initialPreview.install_id);
});
test('whats-new tour opens shipped privacy and migration guide pages', async ({ page }, testInfo) => {
test('whats-new tour opens shipped privacy and navigation guide pages', async ({ page }, testInfo) => {
test.skip(testInfo.project.name.startsWith('mobile-'), 'Desktop-only telemetry disclosure coverage');
await page.addInitScript(() => {
@@ -153,12 +153,12 @@ test.describe('Telemetry disclosure', () => {
);
await expect(dialog).toHaveAttribute('aria-label', 'Welcome to Pulse v6');
await expect(dialog.getByText('Step 1 of 5')).toBeVisible();
await expect(dialog.getByText('V5 to V6')).toBeVisible();
await expect(dialog.getByText('Quick Tour')).toBeVisible();
await expect(assistantLauncher).toBeHidden();
await expect(spotlight).toHaveAttribute('data-tour-step', 'dashboard');
await expect(dialog).toHaveAttribute('data-tour-step', 'dashboard');
await expectSpotlightAround(spotlight, dashboardTab);
await expect(dialog.getByText(/overview for health, alerts, capacity/i)).toBeVisible();
await expect(dialog.getByText(/Start here for health, alerts, capacity/i)).toBeVisible();
await expect(dialog.getByRole('link', { name: 'Telemetry details' })).toBeVisible();
const privacyLink = dialog.getByRole('link', { name: 'Telemetry details' });
@@ -170,7 +170,7 @@ test.describe('Telemetry disclosure', () => {
'Pulse currently has two usage-data scopes',
);
const docsLink = dialog.getByRole('link', { name: 'Migration guide' });
const docsLink = dialog.getByRole('link', { name: 'Navigation guide' });
await expect(docsLink).toHaveAttribute('href', '/docs/MIGRATION_UNIFIED_NAV.md');
await expectPopupDoc(
page,