- 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
15 KiB
15 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 03-wizard-ui | 05 | execute | 4 |
|
|
false |
|
|
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.
<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>
@.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.mdFrom src/store/types.ts:
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:
export function useWizard(): { state: WizardState; dispatch: React.Dispatch<WizardAction> }
Step routing pattern (from RESEARCH.md):
// 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):
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 });
};
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
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
```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.
Dev server check:
npm run dev 2>&1 | head -5
Server starts without errors.
<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>