docs(05-03): complete act()-warning elimination plan

- SUMMARY.md: userEvent v14 migration + vi.useFakeTimers() for ReviewStep
- STATE.md: advanced to completed 05-03, added patterns as decisions
- ROADMAP.md: phase 5 now 4/4 plans complete (Complete status)
- REQUIREMENTS.md: TECH-05 marked complete
This commit is contained in:
2026-03-30 11:44:59 +02:00
parent 913cbe836e
commit 53bbd00533
10 changed files with 1750 additions and 12 deletions
+321
View File
@@ -0,0 +1,321 @@
---
phase: 03-wizard-ui
plan: "05"
type: execute
wave: 4
depends_on:
- "03-03"
- "03-04"
files_modified:
- src/components/wizard/DeploymentStep.tsx
- src/components/wizard/StepIndicator.tsx
- src/App.tsx
autonomous: false
requirements:
- WIZD-02
- WIZD-03
must_haves:
truths:
- "App.tsx renders BackendSelectionStep for currentStep 0, RemoteConfigStep for step 1, DeploymentStep for step 2"
- "StepIndicator shows 3 labeled steps with checkmarks on completed steps"
- "Clicking a completed step in StepIndicator dispatches SET_STEP — clicking step 0 also dispatches SET_REMOTE_PARAMS({})"
- "DeploymentStep renders includeInstall toggle, configPath radio group, and scriptTargets checkboxes"
- "DeploymentStep dispatches SET_DEPLOYMENT on each change, keeping deployment state in sync"
- "Full forward + backward wizard navigation works without losing entered data in any step"
artifacts:
- path: "src/components/wizard/DeploymentStep.tsx"
provides: "Step 2 — deployment options (includeInstall, configPath, scriptTargets)"
exports: ["DeploymentStep"]
- path: "src/components/wizard/StepIndicator.tsx"
provides: "Breadcrumb navigation — 1.Backend > 2.Remote Config > 3.Deployment"
exports: ["StepIndicator"]
- path: "src/App.tsx"
provides: "Step router — renders correct step component by currentStep"
key_links:
- from: "src/App.tsx"
to: "src/components/wizard/BackendSelectionStep.tsx"
via: "STEPS[0] — renders when currentStep === 0"
pattern: "BackendSelectionStep"
- from: "src/App.tsx"
to: "src/components/wizard/RemoteConfigStep.tsx"
via: "STEPS[1] — renders when currentStep === 1, keyed on backendType"
pattern: "RemoteConfigStep"
- from: "src/components/wizard/StepIndicator.tsx"
to: "src/store/context.tsx"
via: "dispatches SET_STEP and conditionally SET_REMOTE_PARAMS on back-nav to step 0"
pattern: "dispatch.*SET_STEP|SET_REMOTE_PARAMS"
- from: "src/components/wizard/DeploymentStep.tsx"
to: "src/store/context.tsx"
via: "dispatches SET_DEPLOYMENT on every control change"
pattern: "dispatch.*SET_DEPLOYMENT"
---
<objective>
Wire the complete wizard: implement DeploymentStep and StepIndicator, then update App.tsx to route between all three steps and render the breadcrumb navigation.
Purpose: Satisfies WIZD-02 (multi-step navigation shell) and WIZD-03 (back navigation without data loss). Closes the full wizard loop.
Output: DeploymentStep, StepIndicator, App.tsx wired — all tests GREEN.
</objective>
<execution_context>
@C:/Users/SebastienQUEROL/.claude/get-shit-done/workflows/execute-plan.md
@C:/Users/SebastienQUEROL/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/phases/03-wizard-ui/03-CONTEXT.md
@.planning/phases/03-wizard-ui/03-RESEARCH.md
@.planning/phases/03-wizard-ui/03-03-SUMMARY.md
@.planning/phases/03-wizard-ui/03-04-SUMMARY.md
<interfaces>
<!-- Key types and contracts the executor needs. -->
From src/store/types.ts:
```typescript
export interface WizardState {
currentStep: number; // 0=Backend, 1=RemoteConfig, 2=Deployment
remote: {
name: string;
backendType: BackendType | null;
params: Record<string, string>;
};
deployment: {
includeInstall: boolean; // toggle — default: false
configPath: 'machine-wide' | 'user-profile'; // radio — default: 'machine-wide'
scriptTargets: ('intune' | 'rmm')[]; // checkboxes — default: both selected
};
}
// Deploy step actions:
dispatch({ type: 'SET_DEPLOYMENT', payload: { includeInstall: true } });
dispatch({ type: 'SET_DEPLOYMENT', payload: { configPath: 'user-profile' } });
dispatch({ type: 'SET_DEPLOYMENT', payload: { scriptTargets: ['intune'] } });
// Back-nav to step 0 (CRITICAL: clears params but NOT deployment):
dispatch({ type: 'SET_REMOTE_PARAMS', payload: {} });
dispatch({ type: 'SET_STEP', payload: 0 });
```
From src/store/context.tsx:
```typescript
export function useWizard(): { state: WizardState; dispatch: React.Dispatch<WizardAction> }
```
Step routing pattern (from RESEARCH.md):
```tsx
// App.tsx step routing
import { BackendSelectionStep } from './components/wizard/BackendSelectionStep';
import { RemoteConfigStep } from './components/wizard/RemoteConfigStep';
import { DeploymentStep } from './components/wizard/DeploymentStep';
import { StepIndicator } from './components/wizard/StepIndicator';
// Key RemoteConfigStep on backendType to force remount on backend change (Pitfall 1 fix)
const STEPS = [
() => <BackendSelectionStep />,
() => <RemoteConfigStep key={state.remote.backendType} />,
() => <DeploymentStep />,
];
```
StepIndicator back-nav pattern (from RESEARCH.md):
```tsx
const handleStepClick = (targetStep: number) => {
if (targetStep === 0 && state.currentStep > 0) {
dispatch({ type: 'SET_REMOTE_PARAMS', payload: {} }); // clear params (backend may change)
// Do NOT dispatch RESET — deployment options must be preserved
}
dispatch({ type: 'SET_STEP', payload: targetStep });
};
```
</interfaces>
</context>
<tasks>
<task type="auto" tdd="true">
<name>Task 1: Implement DeploymentStep and StepIndicator</name>
<files>src/components/wizard/DeploymentStep.tsx, src/components/wizard/StepIndicator.tsx</files>
<behavior>
DeploymentStep:
- Renders an "Include rclone installation" toggle (checkbox or switch); state.deployment.includeInstall default false
- Renders a "Config deployment path" radio group: 'machine-wide' (C:\ProgramData\rclone\) and 'user-profile' (%APPDATA%\rclone\); default machine-wide
- Renders a "Script targets" checkbox group: 'intune' and 'rmm' checkboxes; both checked by default
- Each control dispatches SET_DEPLOYMENT immediately on change (live sync, no Next button needed for deployment options)
- Renders a "Back" button that dispatches SET_STEP(1) and a "Next / Review" button that dispatches SET_STEP(3) to advance to Phase 4's review step
StepIndicator:
- Renders three labeled steps: "1. Backend", "2. Remote Config", "3. Deployment"
- Current step is bold/active
- Completed steps (step index < currentStep) show a checkmark prefix and are clickable buttons
- Future steps are not clickable (non-interactive)
- Clicking a completed step that is NOT step 0 dispatches only SET_STEP(targetStep)
- Clicking step 0 dispatches SET_REMOTE_PARAMS({}) THEN SET_STEP(0) — clears params for potential backend change
- Does NOT dispatch RESET on any click
</behavior>
<action>
Create `src/components/wizard/DeploymentStep.tsx`:
- Uses `useWizard()` to read `state.deployment` and `dispatch`
- Does NOT use react-hook-form — deployment fields dispatch directly via onChange handlers
- `includeInstall` toggle: `<input type="checkbox" checked={state.deployment.includeInstall} onChange={e => dispatch({ type: 'SET_DEPLOYMENT', payload: { includeInstall: e.target.checked } })} />`
- `configPath` radios: two `<input type="radio">` elements for 'machine-wide' and 'user-profile'
- `scriptTargets` checkboxes: two `<input type="checkbox">` for 'intune' and 'rmm' — on change, compute new array and dispatch SET_DEPLOYMENT
- Back button: `dispatch({ type: 'SET_STEP', payload: 1 })`
- Next button: `dispatch({ type: 'SET_STEP', payload: 3 })` — step 3 is Phase 4's review/download (placeholder for now)
Create `src/components/wizard/StepIndicator.tsx`:
- Uses `useWizard()` to read `state.currentStep`
- Renders a horizontal breadcrumb with separators ()
- Step labels: `['Backend', 'Remote Config', 'Deployment']`
- For each step index i:
- If i < currentStep: completed — render as `<button>` with "checkmark {label}"
- If i === currentStep: active — render as `<span>` bold with "{i+1}. {label}"
- If i > currentStep: future — render as `<span>` muted with "{i+1}. {label}"
- `handleStepClick(i)`: if i === 0 and currentStep > 0, dispatch SET_REMOTE_PARAMS({}) first, then dispatch SET_STEP(i)
Update `src/components/wizard/StepIndicator.test.tsx` to make all WIZD-03 tests GREEN:
- "clicking a completed step dispatches SET_STEP" — render with currentStep=2, click "Backend" step, verify SET_STEP(0) was dispatched (use spy or observe re-render)
- "clicking back to step 0 dispatches SET_REMOTE_PARAMS({})" — same scenario, verify params are cleared
- "clicking back to step 0 does NOT dispatch RESET" — verify no full RESET
- "step 0 shows as active when currentStep is 0" — render with step 0
- "completed steps are clickable" — render with step 2, verify step 0 and 1 have button role
</action>
<verify>
<automated>npx vitest run src/components/wizard/StepIndicator.test.tsx --reporter=verbose 2>&1</automated>
</verify>
<done>
DeploymentStep.tsx and StepIndicator.tsx exist with named exports. All StepIndicator WIZD-03 tests GREEN.
</done>
</task>
<task type="auto" tdd="true">
<name>Task 2: Wire App.tsx step router and make App.test GREEN</name>
<files>src/App.tsx</files>
<behavior>
- App renders BackendSelectionStep when state.currentStep === 0
- App renders RemoteConfigStep when state.currentStep === 1
- App renders DeploymentStep when state.currentStep === 2
- App always renders StepIndicator above the current step component
- RemoteConfigStep is keyed on state.remote.backendType to force remount on backend change
</behavior>
<action>
Replace the placeholder `src/App.tsx` with the step router.
```tsx
import { useWizard } from './store/context';
import { WizardProvider } from './store/context';
import { StepIndicator } from './components/wizard/StepIndicator';
import { BackendSelectionStep } from './components/wizard/BackendSelectionStep';
import { RemoteConfigStep } from './components/wizard/RemoteConfigStep';
import { DeploymentStep } from './components/wizard/DeploymentStep';
function WizardShell() {
const { state } = useWizard();
const steps = [
<BackendSelectionStep />,
<RemoteConfigStep key={state.remote.backendType ?? 'none'} />,
<DeploymentStep />,
];
// Guard: clamp to valid range (phase 4 adds step 3 later)
const stepIndex = Math.min(state.currentStep, steps.length - 1);
const CurrentStep = steps[stepIndex];
return (
<div className="min-h-screen bg-gray-50 flex flex-col items-center py-12 px-4">
<div className="w-full max-w-2xl">
<h1 className="text-3xl font-bold text-gray-900 mb-8 text-center">Ready2Blob</h1>
<StepIndicator />
<div className="mt-8">
{CurrentStep}
</div>
</div>
</div>
);
}
export default function App() {
return (
<WizardProvider>
<WizardShell />
</WizardProvider>
);
}
```
Then update `src/App.test.tsx` to make all WIZD-02 tests GREEN:
- "renders BackendSelectionStep when currentStep is 0" — render App, expect to find backend card grid (e.g., text "Azure Blob Storage")
- "renders RemoteConfigStep when currentStep is 1" — render App, dispatch SET_BACKEND_TYPE + SET_STEP(1), expect backend config form to appear
- "renders DeploymentStep when currentStep is 2" — render App, navigate to step 2, expect deployment options to appear
Testing approach: `render(<App />)`, then use a dispatch helper or find elements that are only present on the target step.
</action>
<verify>
<automated>npx vitest run src/App.test.tsx --reporter=verbose 2>&1</automated>
</verify>
<done>
All App.test.tsx WIZD-02 tests GREEN. App.tsx wires all three steps. StepIndicator renders above each step.
</done>
</task>
<task type="checkpoint:human-verify" gate="blocking">
<name>Task 3: Human verification of complete wizard flow end-to-end</name>
<action>Human runs `npm run dev` and manually verifies the complete wizard flow in the browser. No code changes required — this task only requires visual inspection and interaction testing.</action>
<what-built>Complete wizard navigation: BackendSelectionStep to RemoteConfigStep to DeploymentStep, with StepIndicator breadcrumb and full back-navigation support.</what-built>
<how-to-verify>
1. Run `npm run dev` and open http://localhost:5173
2. Verify the breadcrumb shows "1. Backend 2. Remote Config 3. Deployment"
3. Step 1 (Backend Selection):
- Remote name field is at the top
- Try clicking a card without a name — inline error should appear below the name field
- Enter "my-remote" in the name field, click "Azure Blob Storage" — should advance to step 2
4. Step 2 (Remote Config) with Azure:
- Storage Account Name field visible
- "SAS URL" is the default active auth method
- Enter a SAS URL, toggle to "Access Key", enter a key — both values should be in the form
- Click "Back" — should return to step 1 with "my-remote" still in the name field
5. Navigate back to step 1, click "Amazon S3" — should advance to step 2 with S3 fields
6. Verify S3 form: access key ID, secret access key, region fields (no provider dropdown visible)
7. Fill S3 form and click "Next" — should advance to step 3
8. Step 3 (Deployment): verify include-install toggle, config path radios, script targets checkboxes
9. Click step "1. Backend" in breadcrumb from step 3 — should navigate back to step 1 without losing deployment options
10. Select a different backend — step 2 form should be blank (not showing old S3 values)
</how-to-verify>
<verify>
<automated>npm run dev 2>&1 | head -5</automated>
</verify>
<done>User confirms the full wizard flow works end-to-end with correct navigation, validation, and data preservation.</done>
<resume-signal>Type "approved" if navigation works correctly end-to-end, or describe any issues found.</resume-signal>
</task>
</tasks>
<verification>
Full automated suite:
```bash
npx vitest run --reporter=verbose 2>&1
```
All tests GREEN: App.test.tsx (WIZD-02), BackendSelectionStep.test.tsx (WIZD-01, WIZD-04), RemoteConfigStep.test.tsx (BACK-01, BACK-02, BACK-03), StepIndicator.test.tsx (WIZD-03).
Dev server check:
```bash
npm run dev 2>&1 | head -5
```
Server starts without errors.
</verification>
<success_criteria>
- All 7 requirement test suites GREEN (WIZD-01, WIZD-02, WIZD-03, WIZD-04, BACK-01, BACK-02, BACK-03)
- App.tsx routes to correct step component by currentStep
- RemoteConfigStep keyed on backendType (prevents stale form values on backend change)
- StepIndicator dispatches SET_REMOTE_PARAMS({}) when navigating back to step 0 (preserves deployment)
- DeploymentStep dispatches SET_DEPLOYMENT live on every control change
- Human verifies full wizard flow end-to-end: forward navigation, back navigation, data preservation
</success_criteria>
<output>
After completion, create `.planning/phases/03-wizard-ui/03-05-SUMMARY.md`
</output>