Canvas AI: Add AiWizardDev.tsx dev chat wizard gated by the aiDevMode flag
## Summary Clone the live `ui/src/components/aiExtension/AiWizard.tsx` into a new `AiWizardDev.tsx`, change its chat endpoint from `/admin/api/canvas/ai` to `/admin/api/canvas/ai-dev`, and render it instead of `AiWizard` only when the `aiDevMode` flag (set by `canvas_dev_ai`, #3591809) is active. The live `AiWizard.tsx` is not modified. End result: once `canvas_dev_ai` is installed, anyone opening the AI chat gets the dev wizard, which posts to `/ai-dev` and shows the mocked response from that controller. ## Why (this sprint) This is the frontend shell that pairs with `canvas_dev_ai`'s mock controller (#3591809): a wizard that talks to `/ai-dev` and only appears when the dev module is installed. It is intentionally a **clone of the current live wizard**, not the POC implementation. The POC's hop-loop logic and tools are migrated in gradually across later issues — that migration is the point of the whole sprint. Standing up the shell now lets that work land against a working dev chat. - Roadmap: https://git.drupalcode.org/project/canvas/-/work_items/3591777 - Depends on: https://git.drupalcode.org/project/canvas/-/work_items/3591809 (the `aiDevMode` flag + `/ai-dev` route + mock) ## Files ### Create `ui/src/components/aiExtension/AiWizardDev.tsx` Clone the live `AiWizard.tsx`, then make two minimal changes so it works against the dev controller: 1. **Endpoint.** The chat POST goes to `/admin/api/canvas/ai` (`AiWizard.tsx:1044`); change it to `/admin/api/canvas/ai-dev`. 2. **Drop the progress poll.** The live wizard also polls `/admin/api/canvas/ai-progress` (`AiWizard.tsx:416`). `canvas_dev_ai` has no progress endpoint, so remove that polling path; the dev flow is a single request → response, and the wizard renders the response `message` (already how it displays text, `AiWizard.tsx:894`/`:1058`). The CSRF token is still fetched on mount from `/admin/api/canvas/token` (`AiWizard.tsx:836`), which `canvas_dev_ai` reuses — no change. ### Gate on the flag (do NOT modify `AiWizard.tsx`) Both mount sites render `<AiWizard />` (default import). Render `AiWizardDev` when `aiDevMode` is set, `AiWizard` otherwise: - `ui/src/components/aiExtension/AiPanel.tsx:21` — `{isOpen && <AiWizard />}` - `ui/src/components/sidePanel/PrimaryPanel.tsx:117` — the `activePanel === 'aiWizard'` branch Use `getCanvasSettings()?.aiDevMode` (from `@/utils/drupal-globals`) — the same truthy accessor as the existing `getCanvasSettings()?.devMode`. A tiny shared selector avoids duplicating the check at both sites and makes graduation a one-file cleanup. No flag → the live `AiWizard` mounts, so production is unaffected. ## Explicitly NOT doing - **Not copying the POC hop-loop code or tools** — `AiWizardDev` is a clone of the live wizard for now; the POC logic migrates in gradually in later issues. - Not modifying the live `AiWizard.tsx`. - Not adding a dev progress/polling endpoint. --- _Issue generated with AI assistance._
issue