Browse Source
Phase 28: Node Defaults UI - 1 plan created - 3 tasks defined (2 auto, 1 checkpoint) - Ready for executionhandoff-20260429-1057
1 changed files with 270 additions and 0 deletions
@ -0,0 +1,270 @@ |
|||||
|
--- |
||||
|
phase: 28-node-defaults-ui |
||||
|
plan: 01 |
||||
|
type: execute |
||||
|
--- |
||||
|
|
||||
|
<objective> |
||||
|
Create a settings panel for configuring default node preferences per node type. |
||||
|
|
||||
|
Purpose: Users can set their preferred default models for GenerateImage, GenerateVideo, and LLM nodes, so keyboard shortcuts (Shift+G, Shift+L) and quick-add create nodes with their preferred settings. |
||||
|
Output: New "Node Defaults" tab in ProjectSetupModal with model selection UI for each node type. |
||||
|
</objective> |
||||
|
|
||||
|
<execution_context> |
||||
|
~/.claude/get-shit-done/workflows/execute-phase.md |
||||
|
~/.claude/get-shit-done/templates/summary.md |
||||
|
</execution_context> |
||||
|
|
||||
|
<context> |
||||
|
@.planning/PROJECT.md |
||||
|
@.planning/ROADMAP.md |
||||
|
@.planning/STATE.md |
||||
|
@.planning/phases/27-node-defaults-infrastructure/27-01-SUMMARY.md |
||||
|
|
||||
|
**Key files:** |
||||
|
@src/components/ProjectSetupModal.tsx |
||||
|
@src/store/utils/localStorage.ts |
||||
|
@src/types/nodes.ts |
||||
|
@src/components/modals/ModelSearchDialog.tsx |
||||
|
@src/components/nodes/LLMGenerateNode.tsx |
||||
|
|
||||
|
**Infrastructure from Phase 27:** |
||||
|
- `NodeDefaultsConfig` type: `{ generateImage?: GenerateImageNodeDefaults, generateVideo?: GenerateVideoNodeDefaults, llm?: LLMNodeDefaults }` |
||||
|
- `GenerateImageNodeDefaults`: `{ selectedModel?: { provider, modelId, displayName } }` |
||||
|
- `GenerateVideoNodeDefaults`: `{ selectedModel?: { provider, modelId, displayName } }` |
||||
|
- `LLMNodeDefaults`: `{ provider?: LLMProvider, model?: LLMModelType, temperature?: number, maxTokens?: number }` |
||||
|
- `loadNodeDefaults()` / `saveNodeDefaults()` in localStorage.ts |
||||
|
- `createDefaultNodeData()` already applies these defaults when creating nodes |
||||
|
|
||||
|
**Established patterns:** |
||||
|
- Tab-based UI in ProjectSetupModal (project, providers tabs) |
||||
|
- Local state pattern: load from store on open, save on "Save" button |
||||
|
- Model selection: ModelSearchDialog opens in callback mode via `onModelSelected` |
||||
|
- LLM settings: dropdowns for provider/model, slider for temperature |
||||
|
</context> |
||||
|
|
||||
|
<tasks> |
||||
|
|
||||
|
<task type="auto"> |
||||
|
<name>Task 1: Add Node Defaults tab to ProjectSetupModal</name> |
||||
|
<files>src/components/ProjectSetupModal.tsx</files> |
||||
|
<action> |
||||
|
1. Add "Node Defaults" as a third tab after "Providers": |
||||
|
- Tab button: `setActiveTab("nodeDefaults")` |
||||
|
- activeTab state now `"project" | "providers" | "nodeDefaults"` |
||||
|
|
||||
|
2. Add local state for node defaults: |
||||
|
- `const [localNodeDefaults, setLocalNodeDefaults] = useState<NodeDefaultsConfig>({});` |
||||
|
- Import `NodeDefaultsConfig, loadNodeDefaults, saveNodeDefaults` from localStorage.ts |
||||
|
- On modal open (in useEffect): `setLocalNodeDefaults(loadNodeDefaults());` |
||||
|
|
||||
|
3. Add state for model selection dialogs: |
||||
|
- `const [showImageModelDialog, setShowImageModelDialog] = useState(false);` |
||||
|
- `const [showVideoModelDialog, setShowVideoModelDialog] = useState(false);` |
||||
|
|
||||
|
4. Add handler for saving node defaults: |
||||
|
```typescript |
||||
|
const handleSaveNodeDefaults = () => { |
||||
|
saveNodeDefaults(localNodeDefaults); |
||||
|
onClose(); |
||||
|
}; |
||||
|
``` |
||||
|
|
||||
|
5. Update handleSave to route to handleSaveNodeDefaults when activeTab === "nodeDefaults" |
||||
|
|
||||
|
6. Create Node Defaults tab content (render when activeTab === "nodeDefaults"): |
||||
|
- Three sections: GenerateImage, GenerateVideo, LLM |
||||
|
- Each in a styled container matching provider tab style (p-3 bg-neutral-900 rounded-lg border border-neutral-700) |
||||
|
|
||||
|
**GenerateImage section:** |
||||
|
- Label: "Default Image Model" |
||||
|
- Display current selection or "System default (Gemini nano-banana-pro)" if not set |
||||
|
- "Select Model" button that opens ModelSearchDialog with onModelSelected callback |
||||
|
- "Clear" button (only shown if selection exists) to reset to undefined |
||||
|
|
||||
|
**GenerateVideo section:** |
||||
|
- Label: "Default Video Model" |
||||
|
- Display current selection or "None set (select model on first use)" if not set |
||||
|
- "Select Model" button that opens ModelSearchDialog with initialCapabilityFilter="video" |
||||
|
- "Clear" button to reset |
||||
|
|
||||
|
**LLM section:** |
||||
|
- Label: "Default LLM Settings" |
||||
|
- Provider dropdown (Google, OpenAI) - use same PROVIDERS array as LLMGenerateNode |
||||
|
- Model dropdown (filtered by provider) - use same MODELS object as LLMGenerateNode |
||||
|
- Temperature slider (0-2, step 0.1) with label showing current value |
||||
|
- Display "Using system defaults" text if no overrides set |
||||
|
- "Clear" button to reset all LLM defaults |
||||
|
|
||||
|
7. Handle model selection callbacks: |
||||
|
```typescript |
||||
|
const handleImageModelSelected = (model: ProviderModel) => { |
||||
|
setLocalNodeDefaults(prev => ({ |
||||
|
...prev, |
||||
|
generateImage: { |
||||
|
...prev.generateImage, |
||||
|
selectedModel: { |
||||
|
provider: model.provider, |
||||
|
modelId: model.id, |
||||
|
displayName: model.name, |
||||
|
} |
||||
|
} |
||||
|
})); |
||||
|
setShowImageModelDialog(false); |
||||
|
}; |
||||
|
``` |
||||
|
Similar for video model. |
||||
|
|
||||
|
8. Import ProviderModel from @/lib/providers/types |
||||
|
|
||||
|
Do NOT add new imports for ModelSearchDialog - it's already used in FloatingActionBar, so check if we need portal or can render inline. Use portal pattern matching existing modal usage. |
||||
|
</action> |
||||
|
<verify>npm run build passes, modal opens with three tabs, Node Defaults tab shows three sections</verify> |
||||
|
<done>ProjectSetupModal has Node Defaults tab with sections for GenerateImage, GenerateVideo, and LLM defaults</done> |
||||
|
</task> |
||||
|
|
||||
|
<task type="auto"> |
||||
|
<name>Task 2: Wire up model selection dialogs and LLM controls</name> |
||||
|
<files>src/components/ProjectSetupModal.tsx</files> |
||||
|
<action> |
||||
|
1. Add ModelSearchDialog renders (conditionally when showImageModelDialog/showVideoModelDialog is true): |
||||
|
```tsx |
||||
|
{showImageModelDialog && ( |
||||
|
<ModelSearchDialog |
||||
|
isOpen={showImageModelDialog} |
||||
|
onClose={() => setShowImageModelDialog(false)} |
||||
|
onModelSelected={handleImageModelSelected} |
||||
|
initialCapabilityFilter="image" |
||||
|
/> |
||||
|
)} |
||||
|
{showVideoModelDialog && ( |
||||
|
<ModelSearchDialog |
||||
|
isOpen={showVideoModelDialog} |
||||
|
onClose={() => setShowVideoModelDialog(false)} |
||||
|
onModelSelected={handleVideoModelSelected} |
||||
|
initialCapabilityFilter="video" |
||||
|
/> |
||||
|
)} |
||||
|
``` |
||||
|
|
||||
|
2. Implement LLM settings handlers: |
||||
|
```typescript |
||||
|
const handleLLMProviderChange = (e: React.ChangeEvent<HTMLSelectElement>) => { |
||||
|
const newProvider = e.target.value as LLMProvider; |
||||
|
const firstModelForProvider = MODELS[newProvider][0].value; |
||||
|
setLocalNodeDefaults(prev => ({ |
||||
|
...prev, |
||||
|
llm: { |
||||
|
...prev.llm, |
||||
|
provider: newProvider, |
||||
|
model: firstModelForProvider, |
||||
|
} |
||||
|
})); |
||||
|
}; |
||||
|
|
||||
|
const handleLLMModelChange = (e: React.ChangeEvent<HTMLSelectElement>) => { |
||||
|
setLocalNodeDefaults(prev => ({ |
||||
|
...prev, |
||||
|
llm: { ...prev.llm, model: e.target.value as LLMModelType } |
||||
|
})); |
||||
|
}; |
||||
|
|
||||
|
const handleLLMTemperatureChange = (e: React.ChangeEvent<HTMLInputElement>) => { |
||||
|
setLocalNodeDefaults(prev => ({ |
||||
|
...prev, |
||||
|
llm: { ...prev.llm, temperature: parseFloat(e.target.value) } |
||||
|
})); |
||||
|
}; |
||||
|
``` |
||||
|
|
||||
|
3. Implement clear handlers: |
||||
|
```typescript |
||||
|
const handleClearImageDefaults = () => { |
||||
|
setLocalNodeDefaults(prev => { |
||||
|
const { generateImage, ...rest } = prev; |
||||
|
return rest; |
||||
|
}); |
||||
|
}; |
||||
|
// Similar for video and LLM |
||||
|
``` |
||||
|
|
||||
|
4. Import PROVIDERS and MODELS arrays - copy from LLMGenerateNode.tsx (they're not exported). Place at top of file: |
||||
|
```typescript |
||||
|
const LLM_PROVIDERS: { value: LLMProvider; label: string }[] = [ |
||||
|
{ value: "google", label: "Google" }, |
||||
|
{ value: "openai", label: "OpenAI" }, |
||||
|
]; |
||||
|
|
||||
|
const LLM_MODELS: Record<LLMProvider, { value: LLMModelType; label: string }[]> = { |
||||
|
google: [ |
||||
|
{ value: "gemini-3-flash-preview", label: "Gemini 3 Flash" }, |
||||
|
{ value: "gemini-2.5-flash", label: "Gemini 2.5 Flash" }, |
||||
|
{ value: "gemini-3-pro-preview", label: "Gemini 3.0 Pro" }, |
||||
|
], |
||||
|
openai: [ |
||||
|
{ value: "gpt-4.1-mini", label: "GPT-4.1 Mini" }, |
||||
|
{ value: "gpt-4.1-nano", label: "GPT-4.1 Nano" }, |
||||
|
], |
||||
|
}; |
||||
|
``` |
||||
|
|
||||
|
5. Import types: LLMProvider, LLMModelType, NodeDefaultsConfig from @/types |
||||
|
|
||||
|
6. Complete the UI for each section with proper styling: |
||||
|
- Use flex layout with justify-between for label and controls |
||||
|
- Model display shows provider icon + model name |
||||
|
- Buttons: "Select Model" (primary), "Clear" (text button, neutral-400) |
||||
|
</action> |
||||
|
<verify>npm run build passes, can select models from dialogs, LLM dropdowns work, clear buttons reset to defaults</verify> |
||||
|
<done>Model selection dialogs open and save selections, LLM controls update local state, clear buttons reset defaults</done> |
||||
|
</task> |
||||
|
|
||||
|
<task type="checkpoint:human-verify" gate="blocking"> |
||||
|
<what-built>Node Defaults tab in Project Settings with: |
||||
|
- GenerateImage section: shows selected model or "System default", Select Model and Clear buttons |
||||
|
- GenerateVideo section: shows selected model or "None set", Select Model and Clear buttons |
||||
|
- LLM section: provider dropdown, model dropdown, temperature slider, Clear button |
||||
|
- Changes persist to localStorage and affect new node creation via keyboard shortcuts</what-built> |
||||
|
<how-to-verify> |
||||
|
1. Run: npm run dev |
||||
|
2. Open Project Settings (gear icon in header) |
||||
|
3. Click "Node Defaults" tab (third tab) |
||||
|
4. Verify three sections appear: Image Model, Video Model, LLM Settings |
||||
|
5. Click "Select Model" for Image - verify ModelSearchDialog opens with image filter |
||||
|
6. Select a model (e.g., fal.ai flux) - verify it shows in the section |
||||
|
7. Click "Save" to close modal |
||||
|
8. Press Shift+G to create GenerateImage node - verify it has the selected model |
||||
|
9. Re-open settings, go to Node Defaults, click "Clear" on Image defaults |
||||
|
10. Click "Save", press Shift+G - verify node uses system default (Gemini) |
||||
|
11. Test LLM defaults: change provider to OpenAI, select GPT-4.1 Mini |
||||
|
12. Save and press Shift+L - verify LLM node uses OpenAI provider |
||||
|
</how-to-verify> |
||||
|
<resume-signal>Type "approved" to continue, or describe issues to fix</resume-signal> |
||||
|
</task> |
||||
|
|
||||
|
</tasks> |
||||
|
|
||||
|
<verification> |
||||
|
Before declaring plan complete: |
||||
|
- [ ] `npm run build` succeeds without TypeScript errors |
||||
|
- [ ] ProjectSetupModal has three tabs: Project, Providers, Node Defaults |
||||
|
- [ ] Can select default image model from ModelSearchDialog |
||||
|
- [ ] Can select default video model from ModelSearchDialog |
||||
|
- [ ] Can configure LLM provider, model, and temperature |
||||
|
- [ ] Clear buttons reset each section to undefined/system defaults |
||||
|
- [ ] Settings persist across modal close/reopen |
||||
|
- [ ] New nodes created via keyboard shortcuts use stored defaults |
||||
|
</verification> |
||||
|
|
||||
|
<success_criteria> |
||||
|
|
||||
|
- All tasks completed |
||||
|
- TypeScript builds without errors |
||||
|
- Node Defaults UI is functional and persists settings |
||||
|
- User verified functionality via checkpoint |
||||
|
</success_criteria> |
||||
|
|
||||
|
<output> |
||||
|
After completion, create `.planning/phases/28-node-defaults-ui/28-01-SUMMARY.md` |
||||
|
</output> |
||||
Loading…
Reference in new issue