Harden protected operator quick routes
This commit is contained in:
parent
23905d2a82
commit
3ff1ebf6dd
8 changed files with 144 additions and 6 deletions
|
|
@ -272,6 +272,36 @@ Current truthful reading after that follow-up:
|
|||
escalation and follow-through separation after sign-in instead of flattening
|
||||
access, package, runtime, and rollout questions together
|
||||
|
||||
Latest protected quick-routes follow-up on `2026-06-24`:
|
||||
|
||||
- the protected dashboard overview and protected download center now mirror the
|
||||
same three bounded public help lanes:
|
||||
- launch readiness
|
||||
- operator access
|
||||
- studio rollout
|
||||
- those same topics no longer bounce a signed-in operator back through generic
|
||||
auth entry points when the target is already known
|
||||
- instead, they now open direct protected follow-through routes such as:
|
||||
- `/app/downloads?platform=windows`
|
||||
- `/app/account`
|
||||
- `/app/browser-access`
|
||||
- `/app/notices`
|
||||
- `/pricing`
|
||||
- `/changelog`
|
||||
- the protected dashboard packaged-proof panel title was also normalized to
|
||||
`Current packaged desktop proof` so public and protected release evidence now
|
||||
read as one authority rather than two near-duplicate headings
|
||||
|
||||
That follow-up stayed green under:
|
||||
|
||||
- `npm --prefix website test -- --run src/__tests__/DashboardOverviewPage.test.tsx src/__tests__/protected-app-pages.test.tsx`
|
||||
- `2` test files passed
|
||||
- `10` tests passed
|
||||
- `./scripts/run-hypertwist-web-surface-validation.sh`
|
||||
- `./scripts/run-hypertwist-sentrux-source-only.sh`
|
||||
- `Quality: 6138`
|
||||
- `All rules pass`
|
||||
|
||||
Latest authority-sync follow-up later on `2026-06-23`:
|
||||
|
||||
- the public manual stayed aligned with the newer native
|
||||
|
|
|
|||
|
|
@ -429,6 +429,8 @@ For boundary-sensitive and restrictive rows:
|
|||
- progression persistence and analytics
|
||||
- browser-runtime and website/distribution posture where those lanes are in the
|
||||
current packet
|
||||
- public-versus-protected operator help-lane continuity, including
|
||||
auth-preserving next-target routing and signed-in release follow-through
|
||||
|
||||
## Unreal input and XR truthfulness rule
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -2,6 +2,8 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|||
import { cleanup, render, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { MemoryRouter } from 'react-router-dom'
|
||||
import { ROUTER_FUTURE_FLAGS } from '../router/router-future'
|
||||
|
||||
const mockUsePlatformAuth = vi.fn()
|
||||
const mockCreateDesktopLinkToken = vi.fn()
|
||||
|
|
@ -34,7 +36,9 @@ function renderPage() {
|
|||
|
||||
return render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<DashboardOverviewPage />
|
||||
<MemoryRouter initialEntries={['/app']} future={ROUTER_FUTURE_FLAGS}>
|
||||
<DashboardOverviewPage />
|
||||
</MemoryRouter>
|
||||
</QueryClientProvider>,
|
||||
)
|
||||
}
|
||||
|
|
@ -187,6 +191,12 @@ describe('DashboardOverviewPage', () => {
|
|||
expect(screen.getByText('Billing price-plan map: missing')).toBeTruthy()
|
||||
expect(screen.getByText('Paddle webhook secret: missing')).toBeTruthy()
|
||||
expect(screen.getByText('Public auth runtime posture: local-or-mixed')).toBeTruthy()
|
||||
expect(screen.getByText('Protected operator quick routes')).toBeTruthy()
|
||||
expect(screen.getByText('Signed-in help lanes')).toBeTruthy()
|
||||
expect(screen.getByRole('link', { name: 'Open account' }).getAttribute('href')).toBe('/app/account')
|
||||
expect(screen.getByRole('link', { name: 'Open browser access' }).getAttribute('href')).toBe('/app/browser-access')
|
||||
expect(screen.getAllByRole('link', { name: 'Open notices' }).length).toBeGreaterThan(0)
|
||||
expect(screen.getByText('Current packaged desktop proof')).toBeTruthy()
|
||||
expect(screen.getByText('Packaged validation passed')).toBeTruthy()
|
||||
expect(screen.getByText(/Magic120Cell dedicated-family training map: passed/i)).toBeTruthy()
|
||||
expect(screen.getByText('Native control and settings roster')).toBeTruthy()
|
||||
|
|
|
|||
|
|
@ -318,7 +318,7 @@ describe('DownloadCenterPage', () => {
|
|||
expect(screen.getByText(/your signed-in account still resolves to desktop access/i)).toBeTruthy()
|
||||
expect(screen.getAllByText('Live release authority temporarily unavailable').length).toBeGreaterThan(0)
|
||||
expect(screen.getByText('What stays intentionally withheld')).toBeTruthy()
|
||||
expect(screen.getByRole('link', { name: 'Open dashboard' }).getAttribute('href')).toBe('/app')
|
||||
expect(screen.getAllByRole('link', { name: 'Open dashboard' }).every((link) => link.getAttribute('href') === '/app')).toBe(true)
|
||||
expect(screen.queryByText(/account not entitled yet/i)).toBeNull()
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -213,6 +213,9 @@ describe('protected app pages', () => {
|
|||
expect(screen.getAllByText('Requested target').length).toBeGreaterThan(0)
|
||||
expect(screen.getByText('Current packaged desktop proof')).toBeTruthy()
|
||||
expect(screen.getAllByText('Packaged validation passed').length).toBeGreaterThan(0)
|
||||
expect(screen.getByText('Protected operator quick routes')).toBeTruthy()
|
||||
expect(screen.getByRole('link', { name: 'Open account' }).getAttribute('href')).toBe('/app/account')
|
||||
expect(screen.getByRole('link', { name: 'Open browser access' }).getAttribute('href')).toBe('/app/browser-access')
|
||||
expect(screen.getByText('Download and rollout escalation')).toBeTruthy()
|
||||
expect(screen.getByText('Current product-surface map')).toBeTruthy()
|
||||
expect(screen.getByText('Protected browser dashboard')).toBeTruthy()
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { ReleaseValidationSummary } from '../components/ui/ReleaseValidationSumm
|
|||
import { resolvePublicLaunchStatusSummary } from '../public-launch'
|
||||
import { downloadTargets, launchReadiness, mplSourceUrl, openSourceRepoUrl, publicDocsUrl, releaseNotesUrl } from '../site-config'
|
||||
import { buildReleaseMetadataItems, resolveReleaseManifestView, type ReleaseManifestView } from '../release-manifest'
|
||||
import { buildSupportPath, getDownloadPlatformLabel, normalizeDownloadPlatform } from '../site-routes'
|
||||
import { buildProtectedDownloadPath, buildSupportPath, getDownloadPlatformLabel, normalizeDownloadPlatform } from '../site-routes'
|
||||
import {
|
||||
controlProfileRosterCards,
|
||||
desktopDownloadSteps,
|
||||
|
|
@ -20,6 +20,7 @@ import {
|
|||
roadmapHonestyCards,
|
||||
supportEscalationCards,
|
||||
} from '../site-data'
|
||||
import { supportTopicDirectory } from './public-page-helpers'
|
||||
|
||||
function Panel({
|
||||
title,
|
||||
|
|
@ -208,6 +209,45 @@ function findWindowsManifestTarget(releaseManifest: ReleaseManifestView) {
|
|||
|
||||
const protectedPackagedDesktopProofTitle = 'Current packaged desktop proof'
|
||||
|
||||
type ProtectedSupportTopicRoute = {
|
||||
label: string
|
||||
to: string
|
||||
}
|
||||
|
||||
type ProtectedSupportTopicGuide = (typeof supportTopicDirectory)[number] & {
|
||||
actions: readonly ProtectedSupportTopicRoute[]
|
||||
}
|
||||
|
||||
function buildProtectedSupportTopicActions(topicKey: string): readonly ProtectedSupportTopicRoute[] {
|
||||
switch (topicKey) {
|
||||
case 'launch-readiness':
|
||||
return [
|
||||
{ label: 'Open downloads', to: buildProtectedDownloadPath('windows') },
|
||||
{ label: 'Open notices', to: '/app/notices' },
|
||||
{ label: 'Open pricing', to: '/pricing' },
|
||||
]
|
||||
case 'operator-access':
|
||||
return [
|
||||
{ label: 'Open downloads', to: buildProtectedDownloadPath('windows') },
|
||||
{ label: 'Open dashboard', to: '/app' },
|
||||
{ label: 'Open account', to: '/app/account' },
|
||||
]
|
||||
case 'studio-rollout':
|
||||
return [
|
||||
{ label: 'Open browser access', to: '/app/browser-access' },
|
||||
{ label: 'Open notices', to: '/app/notices' },
|
||||
{ label: 'Review release notes', to: '/changelog' },
|
||||
]
|
||||
default:
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
const protectedSupportTopicGuides: readonly ProtectedSupportTopicGuide[] = supportTopicDirectory.map((topic) => ({
|
||||
...topic,
|
||||
actions: buildProtectedSupportTopicActions(topic.topicKey),
|
||||
}))
|
||||
|
||||
function ProtectedReleaseAuthorityNotice({
|
||||
badge,
|
||||
title,
|
||||
|
|
@ -347,6 +387,42 @@ function SupportEscalationChecklist({
|
|||
)
|
||||
}
|
||||
|
||||
function ProtectedOperatorQuickRoutesPanel({
|
||||
title,
|
||||
kicker,
|
||||
description,
|
||||
}: {
|
||||
title: string
|
||||
kicker: string
|
||||
description: string
|
||||
}) {
|
||||
return (
|
||||
<Panel title={title} kicker={kicker}>
|
||||
<p>{description}</p>
|
||||
<div className="card-grid top-gap">
|
||||
{protectedSupportTopicGuides.map((topic) => (
|
||||
<article key={topic.topicKey} className="card card--compact">
|
||||
<h3>{topic.title}</h3>
|
||||
<p>{topic.description}</p>
|
||||
<ul className="list top-gap">
|
||||
{topic.steps.map((step) => (
|
||||
<li key={step}>{step}</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className="button-row top-gap">
|
||||
{topic.actions.map((action) => (
|
||||
<Link key={`${topic.topicKey}-${action.label}`} className="button button--ghost" to={action.to}>
|
||||
{action.label}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</Panel>
|
||||
)
|
||||
}
|
||||
|
||||
function ControlRosterManualPanel({
|
||||
title,
|
||||
kicker,
|
||||
|
|
@ -630,8 +706,14 @@ export function DashboardOverviewPage() {
|
|||
)}
|
||||
</Panel>
|
||||
|
||||
<ProtectedOperatorQuickRoutesPanel
|
||||
title="Protected operator quick routes"
|
||||
kicker="Signed-in help lanes"
|
||||
description="These signed-in quick routes mirror the same launch, access, and rollout lanes exposed on the public support surface, but they now open the direct protected destinations instead of sending the operator back through auth first."
|
||||
/>
|
||||
|
||||
<PackagedValidationPanel
|
||||
title="Package validation"
|
||||
title={protectedPackagedDesktopProofTitle}
|
||||
kicker="Desktop proof"
|
||||
description="This dashboard now surfaces the same server-backed Windows package proof that the public and protected release pages consume. That keeps higher-dimensional desktop validation truth separate from launch-tier checkout or download configuration."
|
||||
emptyMessage="The live release manifest did not return a Windows platform entry, so packaged desktop validation proof is unavailable here right now."
|
||||
|
|
@ -807,6 +889,12 @@ export function DownloadCenterPage() {
|
|||
/>
|
||||
</Panel>
|
||||
|
||||
<ProtectedOperatorQuickRoutesPanel
|
||||
title="Protected operator quick routes"
|
||||
kicker="Signed-in help lanes"
|
||||
description="These quick routes keep the entitled download surface aligned with the same launch, access, and rollout lanes used across the broader protected operator shell."
|
||||
/>
|
||||
|
||||
<PackagedValidationPanel
|
||||
title={protectedPackagedDesktopProofTitle}
|
||||
kicker="Protected release evidence"
|
||||
|
|
|
|||
|
|
@ -762,6 +762,11 @@ export const resourceCollections = [
|
|||
] as const
|
||||
|
||||
export const changelogEntries = [
|
||||
{
|
||||
date: 'June 24, 2026',
|
||||
title: 'Protected dashboard and downloads now keep the same help-lane split after sign-in',
|
||||
details: 'The signed-in dashboard and protected download center now mirror the same launch-readiness, operator-access, and studio-rollout guidance lanes used on the public support/manual surface, but they translate those actions into direct protected downloads, account, browser-access, notices, pricing, and release-note targets instead of sending operators back through anonymous auth hops.',
|
||||
},
|
||||
{
|
||||
date: 'June 24, 2026',
|
||||
title: 'Public and auth copy now reads as fully HyperTwist-owned',
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue