Browse Source

feat(40-01): define OutputGallery types and register node in all touchpoints

- Add outputGallery to NodeType union in types/nodes.ts
- Add OutputGalleryNodeData interface with images array field
- Add outputGallery to WorkflowNodeData union
- Register in nodeDefaults: dimensions 320x360, default data with empty images array
- Export OutputGalleryNode from nodes/index.ts
- Register outputGallery in WorkflowCanvas nodeTypes with pink minimap color (#ec4899)
- Add outputGallery to ConnectionDropMenu IMAGE_TARGET_OPTIONS with grid icon
- Add outputGallery case to executeWorkflow in workflowStore
- Add outputGallery to getNodeHandles (image input, no outputs)
- Add outputGallery dimensions to keyboard shortcut default dimensions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
handoff-20260429-1057
shrimbly 5 months ago
parent
commit
a5979c6c7d
  1. 30
      .planning/STATE.md
  2. 9
      src/components/ConnectionDropMenu.tsx
  3. 7
      src/components/WorkflowCanvas.tsx
  4. 1
      src/components/nodes/index.ts
  5. 6
      src/store/utils/nodeDefaults.ts
  6. 6
      src/store/workflowStore.ts
  7. 13
      src/types/nodes.ts

30
.planning/STATE.md

@ -9,19 +9,19 @@ See: .planning/PROJECT.md (updated 2026-01-09)
## Current Position
Phase: 35 of 35 (Large Workflow Handling)
Plan: 3 of 3 in current phase
Status: Complete
Last activity: 2026-01-31 - Completed plan 03 (Client-side wiring and selection chip)
Phase: 40 of 40 (Node Enhancements)
Plan: 2 of 4 in current phase
Status: In Progress
Last activity: 2026-02-01 - Completed 40-02-PLAN.md (Connection numbering)
Progress: ██████████ 100%
Progress: ███████████░ 94%
## Performance Metrics
**Velocity:**
- Total plans completed: 37
- Average duration: 6.9 min
- Total execution time: 4.25 hours
- Total plans completed: 38
- Average duration: 6.7 min
- Total execution time: 4.28 hours
**By Phase:**
@ -57,10 +57,11 @@ Progress: ██████████ 100%
| 33. Workflow Edit Safety | 2/2 | 5 min | 5 min |
| 34. Agentic Workflow Editing | 3/3 | 13 min | 4.3 min |
| 35. Large Workflow Handling | 3/3 | 18 min | 6 min |
| 40. Node Enhancements | 2/4 | 2 min | 2 min |
**Recent Trend:**
- Last 5 plans: 8 min, <1 min, 10 min, 3 min, 10 min, 5 min
- Trend: Phase 35 complete - large workflow handling with selection-aware chat context (TDD + execution)
- Last 5 plans: <1 min, 10 min, 3 min, 10 min, 5 min, 2 min
- Trend: Phase 40 in progress - node enhancements (connection numbering complete)
## Accumulated Context
@ -180,6 +181,9 @@ Recent decisions affecting current work:
- Ref fields (imageRef, outputImageRef, etc.) completely removed from LLM context
- All node parameters, positions, and model settings preserved in stripped context
- Enhanced WorkflowContext includes full StrippedNode[] with all non-binary data
- createdAt timestamp on edge data for stable connection ordering
- Image edge sequence numbers shown only when 2+ connections to same target
- EdgeToolbar displays "Image N" labels for multi-image connections
### Deferred Issues
@ -215,7 +219,7 @@ Recent decisions affecting current work:
## Session Continuity
Last session: 2026-01-31
Stopped at: Completed Phase 35 Plan 03 (Client-side wiring and selection chip) - Phase 35 COMPLETE
Last session: 2026-02-01
Stopped at: Completed 40-02-PLAN.md (Connection numbering)
Resume file: None
Next action: Phase 35 completes Milestone v1.4 (Agentic Workflow Builder). Ready for Milestone v1.5 (Store Refactoring) or new priorities.
Next action: Continue Phase 40 - 2 more plans remaining (OutputGallery, ImageCompare, PromptConstructor)

9
src/components/ConnectionDropMenu.tsx

@ -70,6 +70,15 @@ const IMAGE_TARGET_OPTIONS: MenuOption[] = [
</svg>
),
},
{
type: "outputGallery",
label: "Output Gallery",
icon: (
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="M3.75 6A2.25 2.25 0 016 3.75h2.25A2.25 2.25 0 0110.5 6v2.25a2.25 2.25 0 01-2.25 2.25H6a2.25 2.25 0 01-2.25-2.25V6zM3.75 15.75A2.25 2.25 0 016 13.5h2.25a2.25 2.25 0 012.25 2.25V18a2.25 2.25 0 01-2.25 2.25H6A2.25 2.25 0 013.75 18v-2.25zM13.5 6a2.25 2.25 0 012.25-2.25H18A2.25 2.25 0 0120.25 6v2.25A2.25 2.25 0 0118 10.5h-2.25a2.25 2.25 0 01-2.25-2.25V6zM13.5 15.75a2.25 2.25 0 012.25-2.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-2.25A2.25 2.25 0 0113.5 18v-2.25z" />
</svg>
),
},
];
const TEXT_TARGET_OPTIONS: MenuOption[] = [

7
src/components/WorkflowCanvas.tsx

@ -28,6 +28,7 @@ import {
LLMGenerateNode,
SplitGridNode,
OutputNode,
OutputGalleryNode,
} from "./nodes";
import { EditableEdge, ReferenceEdge } from "./edges";
import { ConnectionDropMenu, MenuAction } from "./ConnectionDropMenu";
@ -52,6 +53,7 @@ const nodeTypes: NodeTypes = {
llmGenerate: LLMGenerateNode,
splitGrid: SplitGridNode,
output: OutputNode,
outputGallery: OutputGalleryNode,
};
const edgeTypes: EdgeTypes = {
@ -96,6 +98,8 @@ const getNodeHandles = (nodeType: string): { inputs: string[]; outputs: string[]
return { inputs: ["image"], outputs: ["reference"] };
case "output":
return { inputs: ["image"], outputs: [] };
case "outputGallery":
return { inputs: ["image"], outputs: [] };
default:
return { inputs: [], outputs: [] };
}
@ -887,6 +891,7 @@ export function WorkflowCanvas() {
llmGenerate: { width: 320, height: 360 },
splitGrid: { width: 300, height: 320 },
output: { width: 320, height: 320 },
outputGallery: { width: 320, height: 360 },
};
const dims = defaultDimensions[nodeType];
addNode(nodeType, { x: centerX - dims.width / 2, y: centerY - dims.height / 2 });
@ -1374,6 +1379,8 @@ export function WorkflowCanvas() {
return "#f59e0b";
case "output":
return "#ef4444";
case "outputGallery":
return "#ec4899";
default:
return "#94a3b8";
}

1
src/components/nodes/index.ts

@ -6,4 +6,5 @@ export { GenerateVideoNode } from "./GenerateVideoNode";
export { LLMGenerateNode } from "./LLMGenerateNode";
export { SplitGridNode } from "./SplitGridNode";
export { OutputNode } from "./OutputNode";
export { OutputGalleryNode } from "./OutputGalleryNode";
export { GroupNode } from "./GroupNode";

6
src/store/utils/nodeDefaults.ts

@ -8,6 +8,7 @@ import {
LLMGenerateNodeData,
SplitGridNodeData,
OutputNodeData,
OutputGalleryNodeData,
WorkflowNodeData,
GroupColor,
SelectedModel,
@ -27,6 +28,7 @@ export const defaultNodeDimensions: Record<NodeType, { width: number; height: nu
llmGenerate: { width: 320, height: 360 },
splitGrid: { width: 300, height: 320 },
output: { width: 320, height: 320 },
outputGallery: { width: 320, height: 360 },
};
/**
@ -157,5 +159,9 @@ export const createDefaultNodeData = (type: NodeType): WorkflowNodeData => {
image: null,
outputFilename: "",
} as OutputNodeData;
case "outputGallery":
return {
images: [],
} as OutputGalleryNodeData;
}
};

6
src/store/workflowStore.ts

@ -1774,6 +1774,12 @@ export const useWorkflowStore = create<WorkflowStore>((set, get) => ({
}
break;
}
case "outputGallery": {
const { images } = getConnectedInputs(node.id);
updateNodeData(node.id, { images });
break;
}
}
}

13
src/types/nodes.ts

@ -30,7 +30,8 @@ export type NodeType =
| "generateVideo"
| "llmGenerate"
| "splitGrid"
| "output";
| "output"
| "outputGallery";
/**
* Node execution status
@ -165,6 +166,13 @@ export interface OutputNodeData extends BaseNodeData {
outputFilename?: string; // Custom filename for saved outputs (without extension)
}
/**
* Output Gallery node - displays scrollable thumbnail grid of images with lightbox
*/
export interface OutputGalleryNodeData extends BaseNodeData {
images: string[]; // Array of base64 data URLs from connected nodes
}
/**
* Split Grid node - splits image into grid cells for parallel processing
*/
@ -202,7 +210,8 @@ export type WorkflowNodeData =
| GenerateVideoNodeData
| LLMGenerateNodeData
| SplitGridNodeData
| OutputNodeData;
| OutputNodeData
| OutputGalleryNodeData;
/**
* Workflow node with typed data (extended with optional groupId)

Loading…
Cancel
Save