Browse Source
Phase 04: Model Search Dialog - 2 plans created - 5 total tasks defined - Ready for executionhandoff-20260429-1057
2 changed files with 297 additions and 0 deletions
@ -0,0 +1,119 @@ |
|||||
|
--- |
||||
|
phase: 04-model-search-dialog |
||||
|
plan: 01 |
||||
|
type: execute |
||||
|
--- |
||||
|
|
||||
|
<objective> |
||||
|
Add provider icon buttons to the floating action bar that show enabled providers. |
||||
|
|
||||
|
Purpose: Give users quick visual access to browse models from configured providers directly from the canvas. |
||||
|
Output: FloatingActionBar with provider icons (Replicate, fal.ai) that open a model search dialog. |
||||
|
</objective> |
||||
|
|
||||
|
<execution_context> |
||||
|
~/.claude/get-shit-done/workflows/execute-phase.md |
||||
|
./summary.md |
||||
|
</execution_context> |
||||
|
|
||||
|
<context> |
||||
|
@.planning/PROJECT.md |
||||
|
@.planning/ROADMAP.md |
||||
|
@.planning/STATE.md |
||||
|
@.planning/phases/03-generate-node-refactor/03-01-SUMMARY.md |
||||
|
@.planning/phases/03-generate-node-refactor/03-03-SUMMARY.md |
||||
|
|
||||
|
# Key source files: |
||||
|
@src/components/FloatingActionBar.tsx |
||||
|
@src/store/workflowStore.ts |
||||
|
@src/types/index.ts |
||||
|
|
||||
|
**Tech stack available:** React, Zustand, @xyflow/react |
||||
|
**Established patterns:** Provider detection via providerSettings state, modal count tracking in store |
||||
|
**Constraining decisions:** |
||||
|
- [Phase 3]: Provider dropdown shows Gemini always, others only if API key configured |
||||
|
- [Phase 3]: API keys stored in localStorage under node-banana-provider-settings key |
||||
|
</context> |
||||
|
|
||||
|
<tasks> |
||||
|
|
||||
|
<task type="auto"> |
||||
|
<name>Task 1: Add provider icon buttons to FloatingActionBar</name> |
||||
|
<files>src/components/FloatingActionBar.tsx, src/store/workflowStore.ts</files> |
||||
|
<action> |
||||
|
Add provider icon buttons after the Generate combo button, before the edge style toggle divider. |
||||
|
|
||||
|
1. In workflowStore.ts, add state for model search dialog: |
||||
|
- `modelSearchOpen: boolean` - whether dialog is open |
||||
|
- `setModelSearchOpen: (open: boolean) => void` - action to toggle |
||||
|
|
||||
|
2. In FloatingActionBar.tsx: |
||||
|
- Import providerSettings from workflowStore |
||||
|
- Create a ProviderIconButton component that renders: |
||||
|
- Replicate icon (show only if providerSettings.providers.replicate?.apiKey exists) |
||||
|
- fal.ai icon (always show - fal.ai works without key but is rate limited) |
||||
|
- Use simple SVG icons: |
||||
|
- Replicate: stylized "R" or cloud icon |
||||
|
- fal.ai: stylized "f" or lightning bolt icon |
||||
|
- On click, call setModelSearchOpen(true) and pass provider filter to state |
||||
|
- Add a divider before the provider icons section |
||||
|
|
||||
|
Button styling should match existing NodeButton: `px-2.5 py-1.5 text-[11px] font-medium text-neutral-400 hover:text-neutral-100 hover:bg-neutral-700 rounded transition-colors` |
||||
|
|
||||
|
Icons should be 14-16px (w-3.5 h-3.5 or w-4 h-4) to match existing icon sizes. |
||||
|
</action> |
||||
|
<verify>Dev server shows provider icons in floating action bar; Replicate icon only visible when API key is configured; fal.ai icon always visible</verify> |
||||
|
<done>Provider icons appear in FloatingActionBar, respecting API key configuration</done> |
||||
|
</task> |
||||
|
|
||||
|
<task type="auto"> |
||||
|
<name>Task 2: Add dialog state management and placeholder</name> |
||||
|
<files>src/store/workflowStore.ts, src/components/FloatingActionBar.tsx</files> |
||||
|
<action> |
||||
|
1. Add to workflowStore.ts state: |
||||
|
- `modelSearchProvider: ProviderType | null` - which provider to filter by (null = all) |
||||
|
- Update setModelSearchOpen to optionally accept provider filter |
||||
|
|
||||
|
2. In FloatingActionBar.tsx: |
||||
|
- Import modelSearchOpen and setModelSearchOpen from store |
||||
|
- When provider icon is clicked, call setModelSearchOpen(true) with provider type |
||||
|
- Add a placeholder div at the bottom of FloatingActionBar that renders conditionally: |
||||
|
```tsx |
||||
|
{modelSearchOpen && ( |
||||
|
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50"> |
||||
|
<div className="bg-neutral-800 p-4 rounded-lg"> |
||||
|
<p className="text-white">Model Search Dialog (Coming in 04-02)</p> |
||||
|
<button onClick={() => setModelSearchOpen(false)} className="mt-2 px-3 py-1 bg-neutral-700 text-white rounded">Close</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
)} |
||||
|
``` |
||||
|
|
||||
|
This placeholder confirms the state wiring works before 04-02 implements the full dialog. |
||||
|
</action> |
||||
|
<verify>Click provider icon opens placeholder dialog; clicking Close button closes it; state is properly managed via Zustand</verify> |
||||
|
<done>Dialog state management working, placeholder renders when provider icon clicked</done> |
||||
|
</task> |
||||
|
|
||||
|
</tasks> |
||||
|
|
||||
|
<verification> |
||||
|
Before declaring plan complete: |
||||
|
- [ ] `npm run build` succeeds without errors |
||||
|
- [ ] Provider icons visible in FloatingActionBar (Replicate if API key set, fal.ai always) |
||||
|
- [ ] Clicking icon opens placeholder dialog |
||||
|
- [ ] Closing dialog resets state properly |
||||
|
</verification> |
||||
|
|
||||
|
<success_criteria> |
||||
|
|
||||
|
- All tasks completed |
||||
|
- All verification checks pass |
||||
|
- No TypeScript errors |
||||
|
- FloatingActionBar shows provider icons for configured providers |
||||
|
- Dialog state management ready for 04-02 implementation |
||||
|
</success_criteria> |
||||
|
|
||||
|
<output> |
||||
|
After completion, create `.planning/phases/04-model-search-dialog/04-01-SUMMARY.md` |
||||
|
</output> |
||||
@ -0,0 +1,178 @@ |
|||||
|
--- |
||||
|
phase: 04-model-search-dialog |
||||
|
plan: 02 |
||||
|
type: execute |
||||
|
--- |
||||
|
|
||||
|
<objective> |
||||
|
Create a searchable model browser dialog with filtering and selection. |
||||
|
|
||||
|
Purpose: Let users browse and search models from Replicate and fal.ai, then add a GenerateImage node with the selected model. |
||||
|
Output: Functional ModelSearchDialog component that searches models, displays results, and creates nodes on selection. |
||||
|
</objective> |
||||
|
|
||||
|
<execution_context> |
||||
|
~/.claude/get-shit-done/workflows/execute-phase.md |
||||
|
./summary.md |
||||
|
~/.claude/get-shit-done/references/checkpoints.md |
||||
|
</execution_context> |
||||
|
|
||||
|
<context> |
||||
|
@.planning/PROJECT.md |
||||
|
@.planning/ROADMAP.md |
||||
|
@.planning/STATE.md |
||||
|
@.planning/phases/04-model-search-dialog/04-01-SUMMARY.md |
||||
|
|
||||
|
# Key source files: |
||||
|
@src/components/FloatingActionBar.tsx |
||||
|
@src/store/workflowStore.ts |
||||
|
@src/app/api/models/route.ts |
||||
|
@src/components/nodes/GenerateImageNode.tsx |
||||
|
@src/types/index.ts |
||||
|
@src/lib/providers/types.ts |
||||
|
|
||||
|
**Tech stack available:** React, Zustand, /api/models endpoint with search and capabilities filtering |
||||
|
**Established patterns:** Modal rendering via createPortal, model fetching with API key headers, SelectedModel type |
||||
|
**Constraining decisions:** |
||||
|
- [Phase 2]: /api/models endpoint accepts X-Replicate-Key and X-Fal-Key headers |
||||
|
- [Phase 2]: capabilities parameter filters models (text-to-image, image-to-image, text-to-video, image-to-video) |
||||
|
- [Phase 3]: SelectedModel type: { provider, modelId, displayName } |
||||
|
</context> |
||||
|
|
||||
|
<tasks> |
||||
|
|
||||
|
<task type="auto"> |
||||
|
<name>Task 1: Create ModelSearchDialog component</name> |
||||
|
<files>src/components/modals/ModelSearchDialog.tsx, src/components/FloatingActionBar.tsx</files> |
||||
|
<action> |
||||
|
Create ModelSearchDialog.tsx in src/components/modals/: |
||||
|
|
||||
|
1. Component structure: |
||||
|
- Use createPortal to render outside React Flow stacking context (like other modals) |
||||
|
- Increment/decrement modalCount in store on mount/unmount |
||||
|
- Full-screen overlay with centered dialog (max-w-2xl) |
||||
|
|
||||
|
2. Dialog layout: |
||||
|
- Header: "Browse Models" title + close button (X) |
||||
|
- Filter bar: |
||||
|
- Search input (debounced 300ms) |
||||
|
- Provider filter dropdown (All / Replicate / fal.ai) |
||||
|
- Capability filter (All / Image / Video) |
||||
|
- Model grid/list: |
||||
|
- Show cover image thumbnail (if available), model name, provider badge, description (truncated) |
||||
|
- Loading state while fetching |
||||
|
- Empty state for no results |
||||
|
|
||||
|
3. Data fetching: |
||||
|
- Fetch from /api/models with query params: |
||||
|
- search: search query (if not empty) |
||||
|
- provider: provider filter (if not "all") |
||||
|
- capabilities: "text-to-image,image-to-image" for Image, "text-to-video,image-to-video" for Video |
||||
|
- Pass API keys via headers: |
||||
|
- Get from providerSettings in store |
||||
|
- X-Replicate-Key: providerSettings.providers.replicate?.apiKey |
||||
|
- X-Fal-Key: providerSettings.providers.fal?.apiKey |
||||
|
- Show loading spinner while fetching |
||||
|
- Handle errors gracefully (show error message, allow retry) |
||||
|
|
||||
|
4. Styling (match existing dark theme): |
||||
|
- Background: bg-neutral-800 |
||||
|
- Borders: border-neutral-700 |
||||
|
- Text: text-neutral-100 for headers, text-neutral-300 for body |
||||
|
- Inputs: bg-neutral-700 border-neutral-600 |
||||
|
- Cards: bg-neutral-700/50 hover:bg-neutral-700 |
||||
|
|
||||
|
5. Update FloatingActionBar.tsx: |
||||
|
- Replace placeholder with actual ModelSearchDialog import and render |
||||
|
- Pass modelSearchProvider as initial provider filter |
||||
|
</action> |
||||
|
<verify>Open dialog via provider icon; search input filters results; provider dropdown changes results; models display with thumbnails</verify> |
||||
|
<done>ModelSearchDialog renders with search, filtering, and model display working</done> |
||||
|
</task> |
||||
|
|
||||
|
<task type="auto"> |
||||
|
<name>Task 2: Add model selection behavior</name> |
||||
|
<files>src/components/modals/ModelSearchDialog.tsx, src/store/workflowStore.ts</files> |
||||
|
<action> |
||||
|
1. Add click handler to model cards: |
||||
|
- When model clicked, create a new GenerateImage node at canvas center |
||||
|
- Set the node's selectedModel to: { provider: model.provider, modelId: model.id, displayName: model.name } |
||||
|
- Close the dialog after creating node |
||||
|
|
||||
|
2. In workflowStore.ts, modify addNode to optionally accept initial data: |
||||
|
- Add optional second parameter: `initialData?: Partial<WorkflowNodeData>` |
||||
|
- Merge initialData into default node data when creating node |
||||
|
- This allows setting selectedModel when adding from model browser |
||||
|
|
||||
|
3. Update ModelSearchDialog to call addNode with selectedModel: |
||||
|
```typescript |
||||
|
const handleSelectModel = (model: ProviderModel) => { |
||||
|
const center = getPaneCenter(); // reuse from FloatingActionBar |
||||
|
const position = screenToFlowPosition({ |
||||
|
x: center.x + Math.random() * 100 - 50, |
||||
|
y: center.y + Math.random() * 100 - 50, |
||||
|
}); |
||||
|
|
||||
|
addNode("nanoBanana", position, { |
||||
|
selectedModel: { |
||||
|
provider: model.provider, |
||||
|
modelId: model.id, |
||||
|
displayName: model.name, |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
setModelSearchOpen(false); |
||||
|
}; |
||||
|
``` |
||||
|
|
||||
|
4. Add visual feedback: |
||||
|
- Cursor pointer on model cards |
||||
|
- Hover state on cards (slight brightness increase) |
||||
|
- Optional: toast/notification when node created |
||||
|
</action> |
||||
|
<verify>Click model in dialog; GenerateImage node created at canvas center with selectedModel set; dialog closes automatically</verify> |
||||
|
<done>Model selection creates configured GenerateImage node and closes dialog</done> |
||||
|
</task> |
||||
|
|
||||
|
<task type="checkpoint:human-verify" gate="blocking"> |
||||
|
<what-built>Model search dialog with search, filtering, and node creation</what-built> |
||||
|
<how-to-verify> |
||||
|
1. Run: npm run dev |
||||
|
2. Configure a Replicate API key in settings (if not already) |
||||
|
3. Look at floating action bar - should see provider icon(s) |
||||
|
4. Click a provider icon - dialog should open |
||||
|
5. Test search: type "flux" or "stable diffusion" - results should filter |
||||
|
6. Test provider filter: switch between All/Replicate/fal.ai |
||||
|
7. Test capability filter: switch between All/Image/Video |
||||
|
8. Click a model - should create a GenerateImage node on canvas |
||||
|
9. Check the new node - should have correct provider/model selected |
||||
|
</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 errors |
||||
|
- [ ] Model search dialog opens and closes correctly |
||||
|
- [ ] Search filters results (debounced) |
||||
|
- [ ] Provider filter works |
||||
|
- [ ] Capability filter works |
||||
|
- [ ] Clicking model creates GenerateImage node with correct selectedModel |
||||
|
- [ ] No console errors during normal operation |
||||
|
</verification> |
||||
|
|
||||
|
<success_criteria> |
||||
|
|
||||
|
- All tasks completed |
||||
|
- All verification checks pass |
||||
|
- Human verification approved |
||||
|
- No TypeScript errors |
||||
|
- Users can browse, search, filter, and select models from the dialog |
||||
|
- Phase 4 complete |
||||
|
</success_criteria> |
||||
|
|
||||
|
<output> |
||||
|
After completion, create `.planning/phases/04-model-search-dialog/04-02-SUMMARY.md` |
||||
|
</output> |
||||
Loading…
Reference in new issue