You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

10 KiB

phase plan type
28-node-defaults-ui 1 execute
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.

<execution_context> ~/.claude/get-shit-done/workflows/execute-phase.md ~/.claude/get-shit-done/templates/summary.md </execution_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
Task 1: Add Node Defaults tab to ProjectSetupModal src/components/ProjectSetupModal.tsx 1. Add "Node Defaults" as a third tab after "Providers": - Tab button: `setActiveTab("nodeDefaults")` - activeTab state now `"project" | "providers" | "nodeDefaults"`
  1. 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());
  2. Add state for model selection dialogs:

    • const [showImageModelDialog, setShowImageModelDialog] = useState(false);
    • const [showVideoModelDialog, setShowVideoModelDialog] = useState(false);
  3. Add handler for saving node defaults:

    const handleSaveNodeDefaults = () => {
      saveNodeDefaults(localNodeDefaults);
      onClose();
    };
    
  4. Update handleSave to route to handleSaveNodeDefaults when activeTab === "nodeDefaults"

  5. 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
  1. Handle model selection callbacks:

    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.

  2. 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. npm run build passes, modal opens with three tabs, Node Defaults tab shows three sections ProjectSetupModal has Node Defaults tab with sections for GenerateImage, GenerateVideo, and LLM defaults

Task 2: Wire up model selection dialogs and LLM controls src/components/ProjectSetupModal.tsx 1. Add ModelSearchDialog renders (conditionally when showImageModelDialog/showVideoModelDialog is true): ```tsx {showImageModelDialog && ( setShowImageModelDialog(false)} onModelSelected={handleImageModelSelected} initialCapabilityFilter="image" /> )} {showVideoModelDialog && ( setShowVideoModelDialog(false)} onModelSelected={handleVideoModelSelected} initialCapabilityFilter="video" /> )} ```
  1. Implement LLM settings handlers:

    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) }
      }));
    };
    
  2. Implement clear handlers:

    const handleClearImageDefaults = () => {
      setLocalNodeDefaults(prev => {
        const { generateImage, ...rest } = prev;
        return rest;
      });
    };
    // Similar for video and LLM
    
  3. Import PROVIDERS and MODELS arrays - copy from LLMGenerateNode.tsx (they're not exported). Place at top of file:

    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" },
      ],
    };
    
  4. Import types: LLMProvider, LLMModelType, NodeDefaultsConfig from @/types

  5. 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) npm run build passes, can select models from dialogs, LLM dropdowns work, clear buttons reset to defaults Model selection dialogs open and save selections, LLM controls update local state, clear buttons reset defaults
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 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 Type "approved" to continue, or describe issues to fix 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

<success_criteria>

  • All tasks completed
  • TypeScript builds without errors
  • Node Defaults UI is functional and persists settings
  • User verified functionality via checkpoint </success_criteria>
After completion, create `.planning/phases/28-node-defaults-ui/28-01-SUMMARY.md`