Add Initial State Presets with Seeding to visual canvas run drawer - #22
Conversation
- Implement modular loading, saving, and ID generation for State Presets - Scope state presets in localStorage under workflow IDs, defaulting to 'default' - Integrate presets selector dropdown, custom name save, and delete button directly inside the Initial State Editor portion of the Run Drawer UI - Automatically seed template-specific preset inputs (for ReAct, HTTP routing, and Human-in-the-Loop translations) on empty lists for highly polished UX - Author extensive unit tests verifying correct load, save, override, and deletion of state presets - Verify visually and functionally using a Playwright E2E script and screenshot
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
📝 WalkthroughWalkthroughAdds workflow-scoped state presets with localStorage persistence, default seeding, run-drawer controls, JSON validation behavior, and Vitest coverage. ChangesWorkflow State Presets
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
frontend/src/pages/Index.tsx (1)
229-249: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAdd coverage for the seeded template default presets.
template-react,template-http-router, andtemplate-translation-hitlare already declared inTEMPLATESand matched byIndex.tsx. Add test coverage that exercises each seededStatePresetso future ID changes do not silently stop seeding these templates.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/pages/Index.tsx` around lines 229 - 249, Add tests covering the seeded default presets selected by the template-matching logic in Index.tsx, exercising template-react, template-http-router, and template-translation-hitl. Assert each produces its expected StatePreset, including the stable seed ID, so changes to those IDs or mappings fail the tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@frontend/src/flow/statePresets.ts`:
- Around line 17-30: Update loadPresets to validate each parsed array element
before returning it as StatePreset[]. Filter out null, non-object, and records
missing the required StatePreset fields, while preserving valid presets and
returning an empty array when none remain.
In `@frontend/src/pages/Index.tsx`:
- Around line 225-263: Update the preset initialization in the useEffect around
loadPresets so default presets are created only when the workflow’s storage key
is absent, not when an existing key contains an empty array; preserve saved []
unchanged. Add a regression test covering deletion of the final preset followed
by workflow reload, asserting that no presets are recreated.
---
Nitpick comments:
In `@frontend/src/pages/Index.tsx`:
- Around line 229-249: Add tests covering the seeded default presets selected by
the template-matching logic in Index.tsx, exercising template-react,
template-http-router, and template-translation-hitl. Assert each produces its
expected StatePreset, including the stable seed ID, so changes to those IDs or
mappings fail the tests.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: b9d6ca26-617e-4a96-9fa6-c05c1d0aab7e
⛔ Files ignored due to path filters (1)
dev_server.logis excluded by!**/*.log
📒 Files selected for processing (3)
frontend/src/flow/statePresets.tsfrontend/src/pages/Index.tsxfrontend/src/test/statePresets.test.ts
| export function loadPresets(workflowId: string | null): StatePreset[] { | ||
| const id = workflowId || "default"; | ||
| try { | ||
| const raw = localStorage.getItem(`${STATE_PRESETS_PREFIX}.${id}`); | ||
| if (raw) { | ||
| const parsed = JSON.parse(raw); | ||
| if (Array.isArray(parsed)) { | ||
| return parsed; | ||
| } | ||
| } | ||
| } catch (e) { | ||
| console.error("Failed to load state presets:", e); | ||
| } | ||
| return []; |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Validate each persisted preset record.
Line 24 returns untyped localStorage values as StatePreset[]. A value such as [null] causes Index.tsx to access p.id during render and throws. Filter invalid records before returning them.
Proposed fix
+function isStatePreset(value: unknown): value is StatePreset {
+ if (typeof value !== "object" || value === null) return false;
+ const preset = value as Record<string, unknown>;
+ return (
+ typeof preset.id === "string" &&
+ typeof preset.name === "string" &&
+ typeof preset.stateStr === "string" &&
+ typeof preset.createdAt === "number" &&
+ Number.isFinite(preset.createdAt)
+ );
+}
+
export function loadPresets(workflowId: string | null): StatePreset[] {
const id = workflowId || "default";
try {
const raw = localStorage.getItem(`${STATE_PRESETS_PREFIX}.${id}`);
if (raw) {
const parsed = JSON.parse(raw);
if (Array.isArray(parsed)) {
- return parsed;
+ return parsed.filter(isStatePreset);
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export function loadPresets(workflowId: string | null): StatePreset[] { | |
| const id = workflowId || "default"; | |
| try { | |
| const raw = localStorage.getItem(`${STATE_PRESETS_PREFIX}.${id}`); | |
| if (raw) { | |
| const parsed = JSON.parse(raw); | |
| if (Array.isArray(parsed)) { | |
| return parsed; | |
| } | |
| } | |
| } catch (e) { | |
| console.error("Failed to load state presets:", e); | |
| } | |
| return []; | |
| function isStatePreset(value: unknown): value is StatePreset { | |
| if (typeof value !== "object" || value === null) return false; | |
| const preset = value as Record<string, unknown>; | |
| return ( | |
| typeof preset.id === "string" && | |
| typeof preset.name === "string" && | |
| typeof preset.stateStr === "string" && | |
| typeof preset.createdAt === "number" && | |
| Number.isFinite(preset.createdAt) | |
| ); | |
| } | |
| export function loadPresets(workflowId: string | null): StatePreset[] { | |
| const id = workflowId || "default"; | |
| try { | |
| const raw = localStorage.getItem(`${STATE_PRESETS_PREFIX}.${id}`); | |
| if (raw) { | |
| const parsed = JSON.parse(raw); | |
| if (Array.isArray(parsed)) { | |
| return parsed.filter(isStatePreset); | |
| } | |
| } | |
| } catch (e) { | |
| console.error("Failed to load state presets:", e); | |
| } | |
| return []; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@frontend/src/flow/statePresets.ts` around lines 17 - 30, Update loadPresets
to validate each parsed array element before returning it as StatePreset[].
Filter out null, non-object, and records missing the required StatePreset
fields, while preserving valid presets and returning an empty array when none
remain.
| useEffect(() => { | ||
| let loaded = loadPresets(activeWorkflowId); | ||
| if (loaded.length === 0) { | ||
| let defaultPreset: StatePreset | null = null; | ||
| if (activeWorkflowId === "template-react") { | ||
| defaultPreset = { | ||
| id: "seed-react", | ||
| name: "OpenAI Search Query", | ||
| stateStr: JSON.stringify({ query: "Should we search the web for OpenAI?" }, null, 2), | ||
| createdAt: Date.now(), | ||
| }; | ||
| } else if (activeWorkflowId === "template-http-router") { | ||
| defaultPreset = { | ||
| id: "seed-http", | ||
| name: "GitHub Octocat User", | ||
| stateStr: JSON.stringify({ username: "octocat" }, null, 2), | ||
| createdAt: Date.now(), | ||
| }; | ||
| } else if (activeWorkflowId === "template-translation-hitl") { | ||
| defaultPreset = { | ||
| id: "seed-translation", | ||
| name: "Lennon Quote Translation", | ||
| stateStr: JSON.stringify({ query: "Life is what happens when you're busy making other plans." }, null, 2), | ||
| createdAt: Date.now(), | ||
| }; | ||
| } else if (!activeWorkflowId) { | ||
| defaultPreset = { | ||
| id: "seed-default", | ||
| name: "Default Query", | ||
| stateStr: JSON.stringify({ query: "hello world" }, null, 2), | ||
| createdAt: Date.now(), | ||
| }; | ||
| } | ||
|
|
||
| if (defaultPreset) { | ||
| loaded = [defaultPreset]; | ||
| savePresets(activeWorkflowId, loaded); | ||
| } | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Do not seed when the user saved an empty preset list.
Deleting the final preset saves [] at lines 1894-1896. On the next reload or workflow switch, loaded.length === 0 seeds the template preset again. The delete operation therefore does not persist.
Seed only when the workflow storage key is absent. Keep an existing empty array unchanged. Add a regression test that deletes the final preset, reloads the workflow, and expects no presets.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@frontend/src/pages/Index.tsx` around lines 225 - 263, Update the preset
initialization in the useEffect around loadPresets so default presets are
created only when the workflow’s storage key is absent, not when an existing key
contains an empty array; preserve saved [] unchanged. Add a regression test
covering deletion of the final preset followed by workflow reload, asserting
that no presets are recreated.
There was a problem hiding this comment.
Pull request overview
Adds a “Initial State Presets” capability to the run drawer’s initial-state JSON editor, including template-specific seeding of a default preset and local persistence via localStorage.
Changes:
- Introduces a
statePresetslocalStorage library (loadPresets/savePresets/cryptoId) plus unit tests. - Extends
Canvas(run drawer) UI to select/create/overwrite/delete presets and auto-seed defaults for specific templates. - Updates
dev_server.logwith a new Vite host/port output.
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| frontend/src/flow/statePresets.ts | New localStorage-backed preset persistence utilities. |
| frontend/src/pages/Index.tsx | Adds preset seeding + run-drawer UI for selecting/saving/deleting initial-state presets. |
| frontend/src/test/statePresets.test.ts | Adds unit tests for preset persistence utilities and ID generation. |
| dev_server.log | Updates committed dev server output (likely an unintended artifact). |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| export function loadPresets(workflowId: string | null): StatePreset[] { | ||
| const id = workflowId || "default"; | ||
| try { | ||
| const raw = localStorage.getItem(`${STATE_PRESETS_PREFIX}.${id}`); | ||
| if (raw) { | ||
| const parsed = JSON.parse(raw); | ||
| if (Array.isArray(parsed)) { | ||
| return parsed; | ||
| } | ||
| } | ||
| } catch (e) { | ||
| console.error("Failed to load state presets:", e); | ||
| } | ||
| return []; | ||
| } |
| <span className="font-mono text-[9px] text-[hsl(var(--ink-faint))] uppercase tracking-wider"> | ||
| Preset: | ||
| </span> | ||
| <select | ||
| value={selectedPresetId} |
This submission implements the Initial State Presets feature, enabling users to name, save, overwrite, delete, and switch between multiple state inputs (JSON presets) within the browser execution run drawer. It also introduces automatic template-specific preset seeding, which populates realistic input states for ReAct, HTTP Routing, and HITL translation workflows. Full unit testing is provided and all tests pass with 100% success.
PR created automatically by Jules for task 17350595774032396327 started by @Jacobcdsmith
Summary by CodeRabbit
New Features
Tests