Browse Source

feat(40-02): add image connection sequence numbering

- Add createdAt timestamp to WorkflowEdgeData interface
- Store createdAt on edge creation in onConnect and addEdgeWithType
- Add getImageSequenceNumber helper to EdgeToolbar
- Display "Image N" label for image connections with 2+ edges to same target
- Sequence numbers based on createdAt for stable ordering
- Single connections and text connections show no numbering
handoff-20260429-1057
shrimbly 5 months ago
parent
commit
d2ea913784
  1. 29
      .planning/ROADMAP.md
  2. 1
      .planning/STATE.md
  3. 41
      src/components/EdgeToolbar.tsx
  4. 2
      src/store/workflowStore.ts
  5. 1
      src/types/workflow.ts

29
.planning/ROADMAP.md

@ -14,7 +14,7 @@ None
- ✅ **v1.1 Improvements** - Phases 7-14 (shipped 2026-01-12) - ✅ **v1.1 Improvements** - Phases 7-14 (shipped 2026-01-12)
- ✅ **v1.2 Improvements** - Phases 15-24 (shipped 2026-01-17) - ✅ **v1.2 Improvements** - Phases 15-24 (shipped 2026-01-17)
- ✅ **v1.3 Improvements** - Phases 25-30 (shipped 2026-01-24) - ✅ **v1.3 Improvements** - Phases 25-30 (shipped 2026-01-24)
- 🚧 **v1.4 Features** - Phases 31-35 (in progress) - 🚧 **v1.4 Features** - Phases 31-35, 40 (in progress)
- 📋 **v1.5 Store Refactoring** - Phases 36-39 (planned) - 📋 **v1.5 Store Refactoring** - Phases 36-39 (planned)
## Phases ## Phases
@ -517,6 +517,26 @@ Plans:
- [ ] 35-02-PLAN.md — Selection-aware subgraph extraction (TDD) - [ ] 35-02-PLAN.md — Selection-aware subgraph extraction (TDD)
- [ ] 35-03-PLAN.md — Client-side wiring, ChatPanel selection chip, API subgraph integration - [ ] 35-03-PLAN.md — Client-side wiring, ChatPanel selection chip, API subgraph integration
#### Phase 40: Node Enhancements
**Goal**: Add new node types and UI improvements — output gallery, image compare node, prompt constructor node, and image numbering on connections
**Depends on**: Phase 35
**Research**: Likely (gallery UI patterns, image comparison approaches)
**Research topics**: Gallery/carousel component patterns, image diff/compare slider UX, prompt builder UX patterns, edge label rendering in React Flow
**Plans**: 4 plans
**Features:**
1. Output gallery node — scrollable thumbnail grid with full-screen lightbox
2. Image compare node — slider overlay comparison of two images
3. Prompt constructor node — template-based prompts with @variable interpolation
4. Connection numbering — "Image N" labels on image edges when selected
Plans:
- [ ] 40-01-PLAN.md — OutputGallery node (thumbnail grid + lightbox)
- [ ] 40-02-PLAN.md — Connection numbering (image edge sequence labels)
- [ ] 40-03-PLAN.md — ImageCompare node (react-compare-slider)
- [ ] 40-04-PLAN.md — PromptConstructor node (variable system + template interpolation)
### 📋 v1.5 Store Refactoring (Planned) ### 📋 v1.5 Store Refactoring (Planned)
**Milestone Goal:** Major refactoring of workflowStore.ts (2,900+ lines) into modular, testable components. Extract execution engine, create Zustand slices, and improve code maintainability while maintaining full backward compatibility. **Milestone Goal:** Major refactoring of workflowStore.ts (2,900+ lines) into modular, testable components. Extract execution engine, create Zustand slices, and improve code maintainability while maintaining full backward compatibility.
@ -631,7 +651,7 @@ Plans:
## Progress ## Progress
**Execution Order:** **Execution Order:**
Phases execute in numeric order: 1 → 2 → ... → 35 → 36 → 37 → 38 → 39 Phases execute in numeric order: 1 → 2 → ... → 35 → 40 → 36 → 37 → 38 → 39
| Phase | Milestone | Plans Complete | Status | Completed | | Phase | Milestone | Plans Complete | Status | Completed |
|-------|-----------|----------------|--------|-----------| |-------|-----------|----------------|--------|-----------|
@ -668,8 +688,9 @@ Phases execute in numeric order: 1 → 2 → ... → 35 → 36 → 37 → 38 →
| 31. Workflow Proposal System | v1.4 | 2/2 | Complete | 2026-01-26 | | 31. Workflow Proposal System | v1.4 | 2/2 | Complete | 2026-01-26 |
| 32. Chat UI Foundation | v1.4 | 2/2 | Complete | 2026-01-27 | | 32. Chat UI Foundation | v1.4 | 2/2 | Complete | 2026-01-27 |
| 33. Workflow Edit Safety | v1.4 | 2/2 | Complete | 2026-01-30 | | 33. Workflow Edit Safety | v1.4 | 2/2 | Complete | 2026-01-30 |
| 34. Context-Aware Agentic Editing | v1.4 | 1/3 | In progress | - | | 34. Context-Aware Agentic Editing | v1.4 | 3/3 | Complete | 2026-01-31 |
| 35. Large Workflow Handling | v1.4 | 0/? | Not started | - | | 35. Large Workflow Handling | v1.4 | 3/3 | Complete | 2026-01-31 |
| 40. Node Enhancements | v1.4 | 0/? | Not started | - |
| 36. Execution Engine Extraction | v1.5 | 0/3 | Not started | - | | 36. Execution Engine Extraction | v1.5 | 0/3 | Not started | - |
| 37. Pure Helpers Extraction | v1.5 | 0/2 | Not started | - | | 37. Pure Helpers Extraction | v1.5 | 0/2 | Not started | - |
| 38. Zustand Slice Pattern | v1.5 | 0/3 | Not started | - | | 38. Zustand Slice Pattern | v1.5 | 0/3 | Not started | - |

1
.planning/STATE.md

@ -211,6 +211,7 @@ Recent decisions affecting current work:
- Phase 30 added: Small fixes - Phase 30 added: Small fixes
- Milestone v1.4 Features created: 5 phases (Phase 31-35), agentic workflow builder with proposal dialogs and chat-based editing - Milestone v1.4 Features created: 5 phases (Phase 31-35), agentic workflow builder with proposal dialogs and chat-based editing
- Milestone v1.5 Store Refactoring created: 4 phases (Phase 36-39), major refactor of workflowStore.ts into modular execution engine and Zustand slices - Milestone v1.5 Store Refactoring created: 4 phases (Phase 36-39), major refactor of workflowStore.ts into modular execution engine and Zustand slices
- Phase 40 added to v1.4: Node enhancements — output gallery, image compare node, prompt constructor node, image numbering on connections
## Session Continuity ## Session Continuity

41
src/components/EdgeToolbar.tsx

@ -1,6 +1,7 @@
"use client"; "use client";
import { useWorkflowStore } from "@/store/workflowStore"; import { useWorkflowStore } from "@/store/workflowStore";
import { WorkflowEdgeData } from "@/types";
import { useMemo, useEffect, useState, useRef } from "react"; import { useMemo, useEffect, useState, useRef } from "react";
export function EdgeToolbar() { export function EdgeToolbar() {
@ -13,6 +14,41 @@ export function EdgeToolbar() {
[edges] [edges]
); );
// Helper function to compute the image connection sequence number
const getImageSequenceNumber = (edge: typeof selectedEdge): number | null => {
if (!edge) return null;
// Only show for image connections
const sourceHandle = edge.sourceHandle;
const targetHandle = edge.targetHandle;
const isImageConnection =
(sourceHandle === "image" || sourceHandle?.startsWith("image-")) ||
(targetHandle === "image" || targetHandle?.startsWith("image-"));
if (!isImageConnection) return null;
// Find all image edges going to the same target + target handle
const siblingEdges = edges.filter(
(e) => e.target === edge.target && e.targetHandle === edge.targetHandle
);
// If only one connection, no need for numbering
if (siblingEdges.length <= 1) return null;
// Sort by createdAt timestamp (fallback to edge ID for legacy edges without timestamp)
const sorted = [...siblingEdges].sort((a, b) => {
const timeA = (a.data as WorkflowEdgeData)?.createdAt || 0;
const timeB = (b.data as WorkflowEdgeData)?.createdAt || 0;
if (timeA !== timeB) return timeA - timeB;
return a.id.localeCompare(b.id);
});
const index = sorted.findIndex((e) => e.id === edge.id);
return index >= 0 ? index + 1 : null;
};
const sequenceNumber = getImageSequenceNumber(selectedEdge);
// Track mouse position when edge selection changes // Track mouse position when edge selection changes
useEffect(() => { useEffect(() => {
const handleMouseDown = (e: MouseEvent) => { const handleMouseDown = (e: MouseEvent) => {
@ -62,6 +98,11 @@ export function EdgeToolbar() {
transform: "translateX(-50%)", transform: "translateX(-50%)",
}} }}
> >
{sequenceNumber !== null && (
<span className="text-[10px] font-medium text-neutral-300 px-2 border-r border-neutral-600">
Image {sequenceNumber}
</span>
)}
<button <button
onClick={handleTogglePause} onClick={handleTogglePause}
className={`p-1.5 rounded hover:bg-neutral-700 transition-colors ${ className={`p-1.5 rounded hover:bg-neutral-700 transition-colors ${

2
src/store/workflowStore.ts

@ -477,6 +477,7 @@ export const useWorkflowStore = create<WorkflowStore>((set, get) => ({
{ {
...connection, ...connection,
id: `edge-${connection.source}-${connection.target}-${connection.sourceHandle || "default"}-${connection.targetHandle || "default"}`, id: `edge-${connection.source}-${connection.target}-${connection.sourceHandle || "default"}-${connection.targetHandle || "default"}`,
data: { createdAt: Date.now() },
}, },
state.edges state.edges
), ),
@ -492,6 +493,7 @@ export const useWorkflowStore = create<WorkflowStore>((set, get) => ({
...connection, ...connection,
id: `edge-${connection.source}-${connection.target}-${connection.sourceHandle || "default"}-${connection.targetHandle || "default"}`, id: `edge-${connection.source}-${connection.target}-${connection.sourceHandle || "default"}-${connection.targetHandle || "default"}`,
type: edgeType, type: edgeType,
data: { createdAt: Date.now() },
}, },
state.edges state.edges
), ),

1
src/types/workflow.ts

@ -10,6 +10,7 @@ import { Edge } from "@xyflow/react";
// Workflow Edge Data // Workflow Edge Data
export interface WorkflowEdgeData extends Record<string, unknown> { export interface WorkflowEdgeData extends Record<string, unknown> {
hasPause?: boolean; hasPause?: boolean;
createdAt?: number;
} }
// Workflow Edge // Workflow Edge

Loading…
Cancel
Save