Phase 3 - Widget I/O + Data Pipeline
Enable widgets to accept inputs/outputs and create data flow with Singularity
Phase 3: Widget I/O + Data Pipeline
Priority: P1 - HIGH
Duration: 3-4 days
Status: ๐ข STARTING
Started: October 28, 2025
๐ฏ Objectives
Transform widgets from static UI elements into dynamic, data-driven components that can:
- Accept inputs from flows, other widgets, or external sources
- Produce outputs that feed into flows or other widgets
- Participate in complex data pipelines
- React to data changes in real-time
Problems Being Solved
- Widgets are static - No way to pass data into or out of widgets
- No data flow - Can't connect widget outputs to flow inputs
- Manual wiring - No visual way to configure widget I/O
- Flow isolation - Flows execute but can't interact with widgets
๐ Architecture Overview
Widget I/O Contract
interface WidgetIOContract {
inputs: {
[key: string]: WidgetInputDefinition;
};
outputs: {
[key: string]: WidgetOutputDefinition;
};
}
interface WidgetInputDefinition {
name: string;
type: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'any';
required: boolean;
default?: any;
description?: string;
source?: WidgetInputSource;
}
interface WidgetInputSource {
type: 'flow' | 'widget' | 'page' | 'static' | 'user';
flowId?: string;
widgetId?: string;
propertyPath?: string;
staticValue?: any;
}
interface WidgetOutputDefinition {
name: string;
type: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'event' | 'any';
description?: string;
targets?: WidgetOutputTarget[];
}
interface WidgetOutputTarget {
type: 'flow' | 'widget' | 'page';
flowId?: string;
widgetId?: string;
propertyPath?: string;
}
Data Pipeline Service
The DataPipelineService orchestrates data flow between:
- Flows โ Widgets
- Widgets โ Flows
- Widgets โ Widgets
- Page Context โ Widgets
- External Sources โ Widgets
@Injectable({ providedIn: 'root' })
export class DataPipelineService {
// Configure widget inputs
async setWidgetInput(widgetId: string, inputName: string, source: WidgetInputSource): Promise<void>
// Configure widget outputs
async setWidgetOutput(widgetId: string, outputName: string, targets: WidgetOutputTarget[]): Promise<void>
// Execute flow and pipe output to widget
async executeFlowToWidget(flowId: string, targetWidgetId: string, inputMapping: Record<string, string>): Promise<void>
// Listen to widget output and pipe to flow
async pipeWidgetOutputToFlow(widgetId: string, outputName: string, flowId: string, inputMapping: Record<string, string>): Promise<void>
// Get widget's current input values (resolved from sources)
getWidgetInputs(widgetId: string): Signal<Record<string, any>>
// Subscribe to widget output events
subscribeToWidgetOutput(widgetId: string, outputName: string, callback: (value: any) => void): Subscription
}
๐๏ธ Implementation Plan
Step 1: Define Widget I/O Contracts (1 day)
Files to Create:
libs/core-models/src/lib/types/widget-io.types.ts- Widget I/O type definitions
- Input/output source/target interfaces
- Data type definitions
libs/core-models/src/lib/interfaces/widget-io-contract.interface.ts- Widget I/O contract interface
- Methods for widgets to implement
Files to Modify:
3. libs/core-models/src/lib/types/widget.types.ts
- Add
ioContract?: WidgetIOContracttoWidgetinterface - Add
inputs?: Record<string, any>for runtime input values - Add
outputs?: Record<string, any>for runtime output values
Step 2: Create DataPipelineService (1 day)
Files to Create:
4. libs/core-angular/src/lib/services/data-pipeline.service.ts
- Core data pipeline service
- Input/output resolution
- FlowโWidget integration
- Real-time reactive updates
libs/core-angular/src/lib/types/data-pipeline.types.ts- Pipeline configuration types
- Data transformation types
- Connection metadata
Files to Modify:
6. libs/core-angular/src/lib/services/index.ts
- Export DataPipelineService
Step 3: Update Widget Base Classes (1 day)
Files to Modify:
7. libs/widgets/src/lib/base/widget-module-base.ts
- Add I/O contract support
- Add input/output getters/setters
- Add event emitters for outputs
libs/widgets/src/lib/widgets/button/button-widget.module.ts(Example)- Define I/O contract (outputs: 'click' event)
- Emit output on button click
libs/widgets/src/lib/widgets/text-display/text-display-widget.module.ts(Example)- Define I/O contract (inputs: 'text', 'style')
- Accept input data
Step 4: Flow Execution Integration (1 day)
Files to Create:
10. libs/core-angular/src/lib/services/flow-execution.service.ts
- Wrap Singularity execution engine
- Handle flowโwidget data transfer
- Handle widgetโflow data transfer
Files to Modify:
11. libs/core-angular/src/lib/services/flow-attachment.service.ts
- Use FlowExecutionService for execution
- Integrate with DataPipelineService
- Pass widget context to flows
Step 5: Editor UI for Widget I/O (1-2 days)
Files to Create:
12. libs/editor-ui/src/lib/components/widget-io-config/widget-io-config.component.ts
- UI for configuring widget inputs/outputs
- Visual source/target selector
- Data mapping editor
libs/editor-ui/src/lib/components/widget-io-config/input-source-selector.component.ts- Dropdown/picker for input sources
- Browse flows, widgets, page context
libs/editor-ui/src/lib/components/widget-io-config/output-target-selector.component.ts- Dropdown/picker for output targets
- Browse flows, widgets
Files to Modify:
15. libs/editor-ui/src/lib/components/properties-panel/properties-panel-new.component.ts
- Add "I/O" tab to properties panel
- Show widget-io-config component
โ Acceptance Criteria
Widget I/O Contract
- All widgets can define inputs/outputs in their manifest
- Inputs/outputs are typed and validated
- Default values work correctly
- Optional vs required inputs enforced
Data Pipeline
- Can set widget input from static value
- Can set widget input from flow output
- Can set widget input from another widget's output
- Can pipe widget output to flow input
- Can pipe widget output to another widget's input
- Reactive updates work in real-time
Flow Execution
- Can execute flow and pass result to widget
- Can trigger flow from widget event (button click, form submit)
- Flow execution errors are caught and displayed
- Flow execution context includes page data
Editor UI
- Properties panel has "I/O" tab for widgets
- Can configure input sources visually
- Can configure output targets visually
- Can test I/O configuration
- Visual feedback for connected vs disconnected I/O
Examples Working
- Button widget โ Click event โ Execute flow
- Flow โ Output โ Text display widget (shows result)
- Form widget โ Submit โ Flow โ Display result
- Timer flow โ Update widget every N seconds
๐งช Testing Plan
Unit Tests
describe('DataPipelineService', () => {
it('should resolve static input value', () => {
service.setWidgetInput('widget-1', 'text', {
type: 'static',
staticValue: 'Hello World'
});
expect(service.getWidgetInputs('widget-1')()['text']).toBe('Hello World');
});
it('should pipe flow output to widget input', async () => {
await service.executeFlowToWidget('flow-1', 'widget-1', { result: 'text' });
// Verify widget received data
});
});
Integration Tests
- Create page with button widget
- Attach flow to button click
- Flow outputs text
- Text display widget receives and shows text
- Verify end-to-end data flow
Manual Testing
- Open Editor
- Add Button widget
- Configure output: 'click' โ flow-1
- Add Text Display widget
- Configure input: 'text' โ flow-1.result
- Test: Click button โ See text update
๐ Progress Tracking
Phase 3 Checklist
- Documentation created
- Step 1: Widget I/O Contracts (0%)
- Step 2: DataPipelineService (0%)
- Step 3: Widget Base Updates (0%)
- Step 4: Flow Execution (0%)
- Step 5: Editor UI (0%)
Overall Progress: 0%
๐ Known Issues & Blockers
None yet - just starting implementation
๐ Notes & Learnings
- Widget I/O is inspired by Figma's variables and React's props/events
- Data pipeline uses Angular signals for reactivity
- Flow execution will use existing Singularity engine
- Need to be careful about circular dependencies (Widget A โ Widget B โ Widget A)
Last Updated: October 28, 2025 - Starting implementation
Next Checkpoint: Widget I/O contracts defined