refactor(workshop): "meet your agent" framing for Phase 2
- Phase 1 proceed button → "Meet your agent". - Phase strip label + Phase 2 heading: "Meet your node" → "Meet your agent". - Phase 2 intro now describes the APESS agent (Claude on the edge, drives the board's devices, on-board fallback). - "Open your node" card → "Open your agent to explore" (same local ZeroClaw dashboard link); Pick-your-domain card kept below it. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
66723ebd35
commit
e0bcf51b08
@@ -24,7 +24,7 @@ describe('PhaseStrip', () => {
|
|||||||
expect(phases).toHaveLength(5)
|
expect(phases).toHaveLength(5)
|
||||||
expect(phases.map((p) => p.textContent)).toEqual([
|
expect(phases.map((p) => p.textContent)).toEqual([
|
||||||
expect.stringContaining('Team reg'),
|
expect.stringContaining('Team reg'),
|
||||||
expect.stringContaining('Meet your node'),
|
expect.stringContaining('Meet your agent'),
|
||||||
expect.stringContaining('Module 1'),
|
expect.stringContaining('Module 1'),
|
||||||
expect.stringContaining('Module 2'),
|
expect.stringContaining('Module 2'),
|
||||||
expect.stringContaining('Module 3'),
|
expect.stringContaining('Module 3'),
|
||||||
@@ -42,7 +42,7 @@ describe('PhaseStrip', () => {
|
|||||||
useSession.getState().completePhase('setup')
|
useSession.getState().completePhase('setup')
|
||||||
renderAt('/workshop/module1', 'm1')
|
renderAt('/workshop/module1', 'm1')
|
||||||
expect(screen.getByText('Team reg').closest('a')).toHaveAttribute('data-state', 'done')
|
expect(screen.getByText('Team reg').closest('a')).toHaveAttribute('data-state', 'done')
|
||||||
expect(screen.getByText('Meet your node').closest('a')).toHaveAttribute('data-state', 'done')
|
expect(screen.getByText('Meet your agent').closest('a')).toHaveAttribute('data-state', 'done')
|
||||||
expect(screen.getByText('Module 1').closest('a')).toHaveAttribute('data-state', 'active')
|
expect(screen.getByText('Module 1').closest('a')).toHaveAttribute('data-state', 'active')
|
||||||
expect(screen.getByText('Module 2').closest('a')).toHaveAttribute('data-state', 'pending')
|
expect(screen.getByText('Module 2').closest('a')).toHaveAttribute('data-state', 'pending')
|
||||||
})
|
})
|
||||||
@@ -54,13 +54,13 @@ describe('PhaseStrip', () => {
|
|||||||
useSession.getState().completePhase('setup')
|
useSession.getState().completePhase('setup')
|
||||||
renderAt('/workshop', 'reg')
|
renderAt('/workshop', 'reg')
|
||||||
expect(screen.getByText('Team reg').closest('a')).toHaveAttribute('data-state', 'active')
|
expect(screen.getByText('Team reg').closest('a')).toHaveAttribute('data-state', 'active')
|
||||||
expect(screen.getByText('Meet your node').closest('a')).toHaveAttribute('data-state', 'pending')
|
expect(screen.getByText('Meet your agent').closest('a')).toHaveAttribute('data-state', 'pending')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('links each phase to its workshop sub-route', () => {
|
it('links each phase to its workshop sub-route', () => {
|
||||||
renderAt('/workshop')
|
renderAt('/workshop')
|
||||||
expect(screen.getByText('Team reg').closest('a')).toHaveAttribute('href', '/workshop')
|
expect(screen.getByText('Team reg').closest('a')).toHaveAttribute('href', '/workshop')
|
||||||
expect(screen.getByText('Meet your node').closest('a')).toHaveAttribute('href', '/workshop/setup')
|
expect(screen.getByText('Meet your agent').closest('a')).toHaveAttribute('href', '/workshop/setup')
|
||||||
expect(screen.getByText('Module 1').closest('a')).toHaveAttribute('href', '/workshop/module1')
|
expect(screen.getByText('Module 1').closest('a')).toHaveAttribute('href', '/workshop/module1')
|
||||||
expect(screen.getByText('Module 2').closest('a')).toHaveAttribute('href', '/workshop/module2')
|
expect(screen.getByText('Module 2').closest('a')).toHaveAttribute('href', '/workshop/module2')
|
||||||
expect(screen.getByText('Module 3').closest('a')).toHaveAttribute('href', '/workshop/add')
|
expect(screen.getByText('Module 3').closest('a')).toHaveAttribute('href', '/workshop/add')
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ interface PhaseMeta {
|
|||||||
|
|
||||||
const PHASES: PhaseMeta[] = [
|
const PHASES: PhaseMeta[] = [
|
||||||
{ key: 'reg', name: 'Team reg', to: '/workshop' },
|
{ key: 'reg', name: 'Team reg', to: '/workshop' },
|
||||||
{ key: 'setup', name: 'Meet your node', to: '/workshop/setup' },
|
{ key: 'setup', name: 'Meet your agent', to: '/workshop/setup' },
|
||||||
{ key: 'm1', name: 'Module 1', to: '/workshop/module1' },
|
{ key: 'm1', name: 'Module 1', to: '/workshop/module1' },
|
||||||
{ key: 'm2', name: 'Module 2', to: '/workshop/module2' },
|
{ key: 'm2', name: 'Module 2', to: '/workshop/module2' },
|
||||||
{ key: 'add', name: 'Module 3', to: '/workshop/add' },
|
{ key: 'add', name: 'Module 3', to: '/workshop/add' },
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ function connect(nodeUrl: string | null = 'http://192.168.1.7:8080') {
|
|||||||
useSession.getState().setDevice({ connected: true, port: 'board · crimson-otter', uptimeS: 0, nodeUrl })
|
useSession.getState().setDevice({ connected: true, port: 'board · crimson-otter', uptimeS: 0, nodeUrl })
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('EnvSetup — Meet your node', () => {
|
describe('EnvSetup — Meet your agent', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
useSession.getState().reset()
|
useSession.getState().reset()
|
||||||
sessionStorage.clear()
|
sessionStorage.clear()
|
||||||
@@ -26,7 +26,7 @@ describe('EnvSetup — Meet your node', () => {
|
|||||||
it('renders the phase strip set to setup and the heading', () => {
|
it('renders the phase strip set to setup and the heading', () => {
|
||||||
renderPage()
|
renderPage()
|
||||||
expect(screen.getByTestId('phase-strip')).toBeInTheDocument()
|
expect(screen.getByTestId('phase-strip')).toBeInTheDocument()
|
||||||
expect(screen.getByRole('heading', { name: /meet your node/i })).toBeInTheDocument()
|
expect(screen.getByRole('heading', { name: /meet your agent/i })).toBeInTheDocument()
|
||||||
expect(
|
expect(
|
||||||
screen.getByTestId('phase-strip').querySelector('[data-phase="setup"]'),
|
screen.getByTestId('phase-strip').querySelector('[data-phase="setup"]'),
|
||||||
).toHaveAttribute('data-state', 'active')
|
).toHaveAttribute('data-state', 'active')
|
||||||
|
|||||||
@@ -39,17 +39,19 @@ export function EnvSetup() {
|
|||||||
<Badge variant="secondary" className="font-mono text-[10px] tracking-widest uppercase mb-2">
|
<Badge variant="secondary" className="font-mono text-[10px] tracking-widest uppercase mb-2">
|
||||||
Phase 2 of 5 · ~15 min
|
Phase 2 of 5 · ~15 min
|
||||||
</Badge>
|
</Badge>
|
||||||
<h1 className="text-3xl font-bold tracking-tight">Meet your node</h1>
|
<h1 className="text-3xl font-bold tracking-tight">Meet your agent</h1>
|
||||||
<p className="text-sm text-muted-foreground mt-2 max-w-xl">
|
<p className="text-sm text-muted-foreground mt-2 max-w-2xl leading-relaxed">
|
||||||
Open your node’s own dashboard and name the domain it’s for — then
|
Your board now runs the <span className="font-medium text-foreground">APESS agent</span> — a
|
||||||
you’re clear for Module 1.
|
Claude-powered agent living on the edge. It reasons about your domain, drives the board’s
|
||||||
|
own devices, and keeps working when the cloud drops by falling back to an on-board model.
|
||||||
|
Open it to explore, then name the domain it’s for.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 1 — Open your node (hero) */}
|
{/* 1 — Open your agent (hero) */}
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="text-base">Open your node</CardTitle>
|
<CardTitle className="text-base">Open your agent to explore</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<OpenYourNode variant="hero" />
|
<OpenYourNode variant="hero" />
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ describe('TeamRegistration', () => {
|
|||||||
it('gates the Proceed button until name + member + board are ready', async () => {
|
it('gates the Proceed button until name + member + board are ready', async () => {
|
||||||
const user = userEvent.setup()
|
const user = userEvent.setup()
|
||||||
renderPage()
|
renderPage()
|
||||||
const proceed = screen.getByRole('button', { name: /proceed/i })
|
const proceed = screen.getByRole('button', { name: /meet your agent/i })
|
||||||
expect(proceed).toBeDisabled()
|
expect(proceed).toBeDisabled()
|
||||||
|
|
||||||
await user.type(screen.getByLabelText(/team name/i), 'team_x')
|
await user.type(screen.getByLabelText(/team name/i), 'team_x')
|
||||||
@@ -94,7 +94,7 @@ describe('TeamRegistration', () => {
|
|||||||
await user.type(screen.getByLabelText(/team name/i), 'team_x')
|
await user.type(screen.getByLabelText(/team name/i), 'team_x')
|
||||||
await user.type(screen.getByLabelText('Member 1'), 'A. Rossi')
|
await user.type(screen.getByLabelText('Member 1'), 'A. Rossi')
|
||||||
act(() => useSession.getState().setDevice({ connected: true, port: 'board · KIT-01', uptimeS: 0 }))
|
act(() => useSession.getState().setDevice({ connected: true, port: 'board · KIT-01', uptimeS: 0 }))
|
||||||
await user.click(screen.getByRole('button', { name: /proceed/i }))
|
await user.click(screen.getByRole('button', { name: /meet your agent/i }))
|
||||||
expect(useSession.getState().phases.reg).toBe(true)
|
expect(useSession.getState().phases.reg).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ export function TeamRegistration() {
|
|||||||
|
|
||||||
<div className="flex justify-end pt-4">
|
<div className="flex justify-end pt-4">
|
||||||
<Button size="lg" disabled={!ready} onClick={onProceed}>
|
<Button size="lg" disabled={!ready} onClick={onProceed}>
|
||||||
Proceed to environment setup →
|
Meet your agent →
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
Reference in New Issue
Block a user