Browse Source

docs(28): create phase plan for Node Defaults UI

Phase 28: Node Defaults UI
- 1 plan created
- 3 tasks defined (2 auto, 1 checkpoint)
- Ready for execution
handoff-20260429-1057
shrimbly 6 months ago
parent
commit
59394f0a9c
  1. 270
      .planning/phases/28-node-defaults-ui/28-01-PLAN.md

270
.planning/phases/28-node-defaults-ui/28-01-PLAN.md

@ -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…
Cancel
Save