Use node.style.width (number or string), node.measured.width, or
default dimensions — in that priority order. Headers now match the
actual node width after user resize.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- FloatingNodeHeader: Controls (comment, expand, run) now sit flush-right
against the node edge with tighter spacing.
- ControlPanel: Remove "Model" label. Model name sits directly under the
settings title, separated by a horizontal divider.
- Add new-tab link icon next to provider name that opens model details page.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ControlPanel: Replace provider/model dropdowns with model name text +
Browse button. Fixed width, no horizontal scroll.
- GenerateImageNode: Carousel controls now overlay on image bottom with
semi-transparent dark background for legibility.
- BaseNode: Add fullBleed prop for borderless mode. Image IS the node -
no visible container, border, or padding.
- GenerateImageNode uses fullBleed mode. Empty state uses subtle fill
instead of dashed border.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove header props (title, customTitle, comment, etc.) from BaseNode calls
- Apply full-bleed content pattern with contentClassName
- Replace dashed border empty states with subtle fills (bg-neutral-900/40)
- Move floating UI elements to absolute positioning
Part of batch update for all 21 remaining node files.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Removed header props from encoder-not-supported BaseNode
- Added contentClassName for full-bleed pattern
- 2 more BaseNode instances in this file still need updating
- Note: Other node edits were reverted by linter/formatter
- Removed aspect ratio, resolution, and search toggles from node body
- Removed ModelParameters component from node body
- Parameters will be shown in ControlPanel (Plan 02 integration)
- Image preview now has room to fill node in full-bleed pattern
Task 1 partial progress: GenerateImageNode parameters removed, 24 more nodes need header props removed and full-bleed content applied
- ImageInputNode: remove header props, use contentClassName with overflow-clip, full-bleed image with object-cover
- OutputNode: same full-bleed pattern, floating download button overlays content
- nodeDimensions: add calculateNodeSizeForFullBleed for nodes without header chrome
- Empty states use subtle bg-neutral-900/40 fill with centered icons (no dashed borders)
Task 1 in progress - 23 more nodes need same pattern applied
- Created ControlPanel component rendering on right side of viewport
- Fixed position with pointer-events-none wrapper, auto scrolling
- Filters to single selected configurable node (7 types)
- Placeholder controls for each node type (Task 2 will implement)
- Integrated into WorkflowCanvas after ChatPanel
- Panel appears/disappears based on node selection
- Import ViewportPortal from @xyflow/react
- Add NODE_TITLES mapping for all node types
- Create getNodeTitle helper (checks selectedModel.displayName for generate nodes)
- Create getNodeTitlePrefix helper (returns ProviderBadge for nodes with provider)
- Wire up handleCustomTitleChange and handleCommentChange callbacks
- Render FloatingNodeHeader for each node inside ViewportPortal
- Headers positioned above nodes, width matches node width
- onExpand/onRun callbacks not wired yet (will be added in Plan 03)
- Comment editing and title editing fully functional
The server-reported availableProviders were only set on fresh API calls.
When models were served from localStorage cache, the provider filter
icons reverted to only showing Gemini/fal.ai. Now availableProviders
is stored in and restored from the model cache.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The ModelSearchDialog only checked client-side localStorage keys to
determine available providers, missing providers configured via .env
server-side vars. Now the /api/models endpoint returns an
availableProviders array and the dialog merges both sources.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create shared getModelPageUrl utility in src/utils/providerUrls.ts
- Add external-link icon to GenerateImageNode header (before Browse button)
- Add external-link icon to GenerateVideoNode header (before Browse button)
- Add external-link icon to Generate3DNode header (before Browse button)
- Icon only appears when model is selected and provider has a page URL
- Gemini models show no link (returns null); Replicate/fal/Kie/WaveSpeed show links
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Gemini and fal.ai always shown (always-available providers)
- Replicate, Kie.ai, WaveSpeed icons only shown when API key is configured
- Reset provider filter to "all" if selected provider becomes unavailable
- Fix WaveSpeed active color from orange to purple (matching its badge color)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove Annotate button assertion from basic rendering test
- Remove Annotate click test case
- Add All Nodes Menu test suite (4 tests: render, open, select, close)
- Update Browse Models tests for "All models" text label
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove Annotate shortcut button from action bar
- Add AllNodesMenu dropdown with all 22 node types in 6 categories
- Replace magnifying glass Browse models icon with "All models" text button
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ConnectionDropMenu tests expected stale last items and item counts after
Router, Switch, and Conditional Switch were added. WorkflowCanvas tests
were missing dimmedNodeIds from the mock store state.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of setting inputSchema via useEffect (which runs after render),
set it directly in handleModelChange and handleBrowseModelSelect. This
ensures dynamic handles (including image-0 for I2V models) are rendered
in the same update cycle as model selection, preventing connection issues
where the image handle wouldn't accept connections.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of an inline text field, negative prompt is now a proper text
handle on the node that can receive connections from prompt/LLM nodes.
Updates the API route to merge dynamicInputs.negative_prompt into the
Veo parameters, and aligns the model schema definition accordingly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Veo models (veo-3.1, veo-3.1-fast) showed no user-configurable
parameters in the UI. Follows the established pattern from
GenerateImageNode where Gemini model parameters are hardcoded in the
component rather than fetched via the schema API. Adds aspect ratio,
duration, resolution, negative prompt, and seed controls.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add early validation for image-to-video models when no image is provided
- Wrap Veo generation/polling in try/catch with specific error messages
- Add 60s AbortController timeout to video download fetch
- Fix SwitchNode toggle knob not sliding (peer-checked on non-sibling)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds an evaluationPaused flag that lets users reset evaluation state
and un-dim all downstream paths. The flag auto-resets on workflow
execution or manual rule edits.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The useMemo for incomingText depended on edges (from useEdges), which
doesn't change when upstream node data changes. On re-runs, the memo
returned stale text and the useEffect overwrote correct execution
results. Replace with a Zustand store selector using
getConnectedInputsPure that recomputes when upstream node data changes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The inline defaultDimensions record in the keyboard shortcut handler was
missing the conditionalSwitch entry, causing a TypeScript build error.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add guard in handleDelete and hide the delete button when only one
switch remains, matching ConditionalSwitchNode's existing behavior.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Identical rule evaluation logic existed in ConditionalSwitchNode.tsx and
workflowStore.ts. Extract to src/store/utils/ruleEvaluation.ts and
import from both locations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace static pixel math with useLayoutEffect + offsetTop measurement to
position output handles at the actual vertical center of their corresponding
rule/default rows. This is robust against header height, padding, and text
preview variations that caused the previous static offset to misalign.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolve three issues with the Conditional Switch node:
- Add fromHandleType resolution for conditionalSwitch in handleConnectEnd so
the connection drop menu appears when dragging from rule/default outputs
- Align output handles with visual rule rows by accounting for the text preview
height in baseOffset and using fixed h-8 rows matching handleSpacing=32
- Move "Add Rule" button after the Default row so the default handle aligns
with its visual row instead of being displaced
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add geminiApiKey to useProviderApiKeys hook. Update GenerateVideoNode to
include Gemini as a provider when API key is configured, and pass the
X-Gemini-API-Key header when fetching models.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Anthropic as a third LLM provider with Claude Opus 4.6, Sonnet 4.5,
and Haiku 4.5 models. Extend Google provider with Gemini 3.1 Pro.
Includes full API route support with multimodal content blocks,
provider settings UI, temperature clamping (Anthropic max 1.0),
header builder plumbing, and comprehensive test coverage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Nano Banana Pro supports 1K/2K/4K, while Nano Banana 2 also supports 512.
Split the shared RESOLUTIONS constant into RESOLUTIONS_PRO and RESOLUTIONS_NB2,
and use the correct list based on the selected model in both GenerateImageNode
and SplitGridSettingsModal. Also normalize aspect ratio and resolution to valid
defaults when switching models in the SplitGrid modal.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Nano Banana 2 (gemini-3.1-flash-image) supports a new searchTypes API
that allows enabling web search and image search independently. This adds
a useImageSearch toggle visible only for Nano Banana 2, while keeping the
existing Google Search toggle using the legacy format for Nano Banana Pro.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Make aspect ratio dropdowns model-aware: nano-banana-2 shows 14 ratios
while other models keep showing the base 10. Also add nano-banana-2 to
the SplitGrid settings model list.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove router/switch/conditionalSwitch entries from WorkflowCanvas
defaultDimensions and validation.ts (these types only exist on develop)
- Add ModelType import and cast in nodeDefaults.ts for type safety
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pre-existing type error — conditionalSwitch was added to NodeType but the
local defaultDimensions map in keyboard shortcut handler was not updated.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Nano Banana 2 entry to GEMINI_IMAGE_MODELS in model registry
- Add model to GenerateImageNode dropdown with 512px resolution option
- Extend resolution/Google Search gates to support nano-banana-2
- Replace hardcoded model name ternaries with MODEL_DISPLAY_NAMES lookup
in workflowStore, nodeDefaults, and GenerateImageNode migration code
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Conditional Switch was missing from the text target connection drop menu
and incorrectly present in the image source menu.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Import ConditionalSwitchNodeData type in dimmingUtils.ts
- Add conditionalSwitch block to collect potentially dimmed nodes
- Non-matching rules (isMatched=false) trigger downstream dimming
- Default output dims when ANY rule matches (inactive when no match)
- Extend smart cascade blockedTypes collection
- Check conditionalSwitch rules for match status
- Add inactive outputs to blockedTypes
- Extend hasReplacementInput check to skip non-matching outputs
- Guard conditionalSwitch nodes from dimming in WorkflowCanvas
- Updated guard: if (node.type === "switch" || node.type === "conditionalSwitch")
Phase 44's dimming system now handles both Switch and Conditional Switch.
- Import and add ConditionalSwitchNode to nodeTypes map
- Add getNodeHandles case with text input and dynamic outputs
- Add cyan-500 (#06b6d4) minimap color distinct from Router/Switch
- Add isValidConnection text-only validation
- Add handleMenuSelect with text handle and first rule/default source
- Add findCompatibleHandle for text input and rule outputs
- Add ConditionalSwitch to TEXT_TARGET_OPTIONS and TEXT_SOURCE_OPTIONS with filter icon
- Positioned after Switch entry in both menus
- Text input handle on left (blue, text type)
- Text preview section showing truncated incoming text (50 chars)
- Rule rows with:
- Match status indicator (green checkmark when matched, gray dot when not)
- Up/down arrow buttons for reordering rules
- Editable label (double-click to edit, inline editing pattern from SwitchNode)
- Mode dropdown (exact, contains, starts-with, ends-with)
- Value text field (comma-separated match values)
- Delete button (hidden if only one rule to prevent empty state)
- Add rule button (creates new rule with auto-generated label)
- Default output row (always at bottom, not editable/deletable)
- Active (green) when NO rules match, inactive (gray) otherwise
- Dynamic output handles per rule + default handle (all text type)
- Non-matching rule handles at 30% opacity (same as Switch disabled pattern)
- evaluateRule function: case-insensitive, multi-value OR logic, all 4 modes
- Match status updates reactively via useEffect watching incoming text
- Dynamic handle sync via useUpdateNodeInternals on rule count change
- Auto-resize height based on rule count
- Teal/cyan theme (bg-teal-950/50 border-teal-600) to differentiate from Router/Switch
- Add MatchMode type (exact, contains, starts-with, ends-with)
- Add ConditionalSwitchRule interface with id, value, mode, label, isMatched
- Add ConditionalSwitchNodeData interface with incomingText and rules array
- Add conditionalSwitch to NodeType union (after switch)
- Add ConditionalSwitchNodeData to WorkflowNodeData union
- Add default data with single rule (mode: contains, empty value)
- Add default dimensions (260x180, wider than Switch for mode dropdown)
- Add executeConditionalSwitch passthrough executor
- Add conditionalSwitch to VALID_NODE_TYPES in validation
- Export ConditionalSwitchNode from components index (component created in next task)
The menu path calls onConnect() directly, bypassing handleConnect's
resolveSwitchHandle. This left edges with targetHandle "generic-input"
instead of the actual type, causing inputType to be invalid, handles
to render without color, and downstream connections to fail validation.
- Set targetHandleId to actual type in handleMenuSelect Switch case
- Update Switch inputType immediately when created from menu
- Filter "generic-input" in derivedInputType as safety net
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>