mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-27 15:24:56 +00:00
10 KiB
10 KiB
Phase 3 Quick Reference Guide
New Hooks Available
1. useExecution - Workflow Execution Management
import { useExecution } from '@/hooks';
function MyComponent() {
const {
execute, // Execute workflow
stop, // Stop running execution
getDetails, // Get execution details
getStats, // Get statistics
getHistory, // Get past executions
currentExecution, // Current Redux state
executionHistory // History Redux state
} = useExecution();
// Execute a workflow
const handleExecute = async () => {
try {
const result = await execute('workflow-id', { param: 'value' });
console.log('Status:', result.status);
} catch (error) {
console.error('Failed:', error.message);
}
};
// Get execution history
const handleHistory = async () => {
const history = await getHistory('workflow-id', 'default', 10);
history.forEach(exec => console.log(exec.status));
};
// Get statistics
const handleStats = async () => {
const stats = await getStats('workflow-id');
console.log(`Success rate: ${stats.successCount}/${stats.totalExecutions}`);
};
// Stop execution
const handleStop = async () => {
if (currentExecution?.status === 'running') {
await stop();
}
};
return (
<div>
<button onClick={handleExecute}>Execute</button>
<button onClick={handleHistory}>Show History</button>
<button onClick={handleStats}>Show Stats</button>
<button onClick={handleStop} disabled={currentExecution?.status !== 'running'}>
Stop
</button>
<p>Current: {currentExecution?.status || 'idle'}</p>
</div>
);
}
Return Type:
{
// State
currentExecution: ExecutionResult | null,
executionHistory: ExecutionResult[],
// Actions (all return Promises)
execute: (workflowId: string, inputs?: any, tenantId?: string) => Promise<ExecutionResult>,
stop: () => Promise<void>,
getDetails: (executionId: string) => Promise<ExecutionResult | null>,
getStats: (workflowId: string, tenantId?: string) => Promise<ExecutionStats>,
getHistory: (workflowId: string, tenantId?: string, limit?: number) => Promise<ExecutionResult[]>
}
2. useCanvasKeyboard - Canvas Keyboard Shortcuts
Already integrated into InfiniteCanvas component. Use these shortcuts:
| Key | Action | Notes |
|---|---|---|
| Ctrl+A / Cmd+A | Select all cards | Selects all items on canvas |
| Delete / Backspace | Delete selected | Removes selected cards |
| Ctrl+D / Cmd+D | Duplicate selected | Creates copies with 20px offset |
| Ctrl+F / Cmd+F | Search | Phase 4: Will open search dialog |
| Escape | Clear selection | Deselects all items |
| Arrow Keys | Pan canvas | Moves canvas view (50px per press) |
Don't use in: Input fields, textareas, contentEditable elements (shortcuts automatically disabled)
For custom handlers, import and use directly:
import { useCanvasKeyboard } from '@/hooks';
function CustomComponent() {
useCanvasKeyboard({
onSelectAll: () => console.log('Select all'),
onDeleteSelected: () => console.log('Delete'),
onDuplicateSelected: () => console.log('Duplicate'),
onSearch: () => console.log('Search')
});
return <div>Keyboard shortcuts active</div>;
}
3. useCanvasVirtualization - Performance Optimization
import { useCanvasVirtualization } from '@/hooks';
function CanvasRenderer() {
const {
visibleItems, // Only items in viewport
stats, // Performance stats
viewportBounds // Current viewport bounds
} = useCanvasVirtualization(
allItems, // All canvas items
{ x: -100, y: -50 }, // Current pan
1.2, // Current zoom
{
padding: 100, // Preload area outside viewport
containerWidth: 1200,
containerHeight: 800
}
);
// Render only visible items for performance
return (
<div>
{visibleItems.map(item => (
<Item key={item.id} item={item} />
))}
<div>
Rendering: {stats.visibleItems} / {stats.totalItems}
({stats.percentVisible}%)
</div>
</div>
);
}
Return Type:
{
visibleItems: ProjectCanvasItem[], // Items in viewport + padding
stats: {
totalItems: number,
visibleItems: number,
hiddenItems: number,
percentVisible: number
},
viewportBounds: {
minX: number,
maxX: number,
minY: number,
maxY: number
}
}
4. useRealtimeService - Collaboration Features
import { useRealtimeService } from '@/hooks';
function CollaborativeCanvas() {
const {
isConnected,
connectedUsers,
broadcastCanvasUpdate,
broadcastCursorPosition,
lockCanvasItem,
releaseCanvasItem
} = useRealtimeService({
projectId: 'project-123',
enabled: true,
onError: (error) => console.error('Realtime error:', error)
});
const handleItemMove = (itemId: string, x: number, y: number) => {
broadcastCanvasUpdate(itemId, { x, y }, { width: 100, height: 100 });
};
const handleMouseMove = (x: number, y: number) => {
broadcastCursorPosition(x, y);
};
const handleItemEdit = (itemId: string) => {
lockCanvasItem(itemId);
// ... edit ...
releaseCanvasItem(itemId);
};
return (
<div>
<p>Connected: {isConnected ? '✓' : '✗'}</p>
<p>Users: {connectedUsers.length}</p>
{connectedUsers.map(user => (
<span key={user.userId} style={{ color: user.userColor }}>
{user.userName}
</span>
))}
</div>
);
}
Return Type:
{
isConnected: boolean,
connectedUsers: Array<{
userId: string,
userName: string,
userColor: string,
cursorPosition?: { x: number, y: number }
}>,
broadcastCanvasUpdate: (itemId: string, position: any, size: any) => void,
broadcastCursorPosition: (x: number, y: number) => void,
lockCanvasItem: (itemId: string) => void,
releaseCanvasItem: (itemId: string) => void
}
Redux Integration Points
Canvas Actions (useCanvasKeyboard)
import {
setSelection,
deleteCanvasItems,
duplicateCanvasItems
} from '@/store/slices/canvasItemsSlice';
dispatch(setSelection(new Set(['id1', 'id2'])));
dispatch(deleteCanvasItems(['id1', 'id2']));
dispatch(duplicateCanvasItems(['id1']));
Execution State (useExecution)
import {
startExecution,
endExecution
} from '@/store/slices/workflowSlice';
// Automatically dispatched by useExecution hook
// Access via:
const { currentExecution, executionHistory } = useSelector(
state => ({
currentExecution: state.workflow.currentExecution,
executionHistory: state.workflow.executionHistory
})
);
Type Definitions
ExecutionResult
{
id: string; // Unique execution ID
workflowId: string; // Workflow being executed
workflowName: string; // Display name
tenantId: string; // Tenant identifier
status: 'pending' | 'running' | 'success' | 'error' | 'stopped';
startTime: number; // Unix timestamp
endTime?: number; // Unix timestamp when complete
duration?: number; // Milliseconds
nodes: NodeExecutionResult[]; // Per-node results
error?: { // Error details if failed
code: string;
message: string;
nodeId?: string;
};
input?: Record<string, any>; // Input parameters
output?: Record<string, any>; // Output data
triggeredBy?: string; // User ID or "api"
}
ExecutionStats
{
totalExecutions: number; // Total count
successCount: number; // Successful executions
errorCount: number; // Failed executions
averageDuration: number; // Average duration in seconds
lastExecution?: ExecutionResult; // Most recent execution
}
Error Handling
Try-Catch Pattern
try {
const result = await execute('workflow-id');
console.log('Success:', result.status);
} catch (error) {
if (error instanceof Error) {
console.error('Error:', error.message);
}
}
Common Errors
| Error | Cause | Solution |
|---|---|---|
| "No execution running" | Tried to stop with no active execution | Check currentExecution?.status === 'running' first |
| "Failed to execute workflow" | Backend error or invalid workflow | Check workflow ID and inputs |
| "Execution failed" | Network error or local cache failure | App has offline-first support, will retry |
Performance Tips
1. Use Virtualization for Large Canvases
// For 100+ items, always use virtualization
const { visibleItems } = useCanvasVirtualization(allItems, pan, zoom);
2. Debounce Cursor Updates
const debouncedBroadcast = useMemo(
() => debounce((x, y) => broadcastCursorPosition(x, y), 100),
[broadcastCursorPosition]
);
3. Batch Item Operations
// Good: Single dispatch for multiple items
dispatch(deleteCanvasItems(['id1', 'id2', 'id3']));
// Avoid: Multiple dispatches
dispatch(deleteCanvasItems(['id1']));
dispatch(deleteCanvasItems(['id2']));
dispatch(deleteCanvasItems(['id3']));
Phase 4 Roadmap
Features coming in Phase 4:
- Real-time execution progress streaming
- Conflict resolution for concurrent edits
- Search dialog integration (Ctrl+F)
- Execution result streaming
- Presence awareness with timeouts
- Connection health metrics
Migration from Phase 2
No migration needed! All Phase 2 APIs remain unchanged. Phase 3 hooks are purely additive.
What Changed
- useExecution: Stub → Full implementation
- useCanvasKeyboard: Not exported → Integrated into InfiniteCanvas
- useRealtimeService: Documentation enhanced for Phase 4
What Stayed the Same
- All Redux slices
- All service layers
- All type definitions
- All other hooks
Support & Troubleshooting
Keyboard shortcuts not working?
- Check if
InfiniteCanvasis in DOM - Verify no modal dialogs are open
- Check browser console for errors
Execution not completing?
- Verify workflow ID is correct
- Check network tab for API errors
- Look in browser's IndexedDB for offline records
Realtime not connecting?
- Verify WebSocket URL in environment
- Check auth token is valid
- Verify browser WebSocket support
See PHASE_3_IMPLEMENTATION.md for detailed docs.