@auser/workflow-graph-web 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +186 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +190 -0
- package/dist/index.js.map +1 -0
- package/package.json +37 -0
- package/src/index.ts +385 -0
- package/src/wasm.d.ts +19 -0
- package/wasm/workflow_graph_web.js +1079 -0
- package/wasm/workflow_graph_web_bg.wasm +0 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* workflow-graph — Interactive workflow DAG visualizer
|
|
3
|
+
*
|
|
4
|
+
* TypeScript wrapper around the WASM module.
|
|
5
|
+
*/
|
|
6
|
+
export interface Workflow {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
trigger: string;
|
|
10
|
+
jobs: Job[];
|
|
11
|
+
}
|
|
12
|
+
export interface Job {
|
|
13
|
+
id: string;
|
|
14
|
+
name: string;
|
|
15
|
+
status: 'queued' | 'running' | 'success' | 'failure' | 'skipped' | 'cancelled';
|
|
16
|
+
command: string;
|
|
17
|
+
duration_secs?: number;
|
|
18
|
+
started_at?: number;
|
|
19
|
+
depends_on: string[];
|
|
20
|
+
output?: string;
|
|
21
|
+
required_labels?: string[];
|
|
22
|
+
max_retries?: number;
|
|
23
|
+
attempt?: number;
|
|
24
|
+
}
|
|
25
|
+
export interface ThemeColors {
|
|
26
|
+
success?: string;
|
|
27
|
+
failure?: string;
|
|
28
|
+
running?: string;
|
|
29
|
+
queued?: string;
|
|
30
|
+
skipped?: string;
|
|
31
|
+
cancelled?: string;
|
|
32
|
+
node_bg?: string;
|
|
33
|
+
node_border?: string;
|
|
34
|
+
text?: string;
|
|
35
|
+
text_secondary?: string;
|
|
36
|
+
bg?: string;
|
|
37
|
+
graph_bg?: string;
|
|
38
|
+
edge?: string;
|
|
39
|
+
junction?: string;
|
|
40
|
+
highlight?: string;
|
|
41
|
+
selected?: string;
|
|
42
|
+
header_text?: string;
|
|
43
|
+
header_trigger?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface ThemeFonts {
|
|
46
|
+
family?: string;
|
|
47
|
+
size_name?: number;
|
|
48
|
+
size_duration?: number;
|
|
49
|
+
size_header?: number;
|
|
50
|
+
}
|
|
51
|
+
export interface ThemeLayout {
|
|
52
|
+
node_width?: number;
|
|
53
|
+
node_height?: number;
|
|
54
|
+
node_radius?: number;
|
|
55
|
+
h_gap?: number;
|
|
56
|
+
v_gap?: number;
|
|
57
|
+
header_height?: number;
|
|
58
|
+
padding?: number;
|
|
59
|
+
junction_dot_radius?: number;
|
|
60
|
+
status_icon_radius?: number;
|
|
61
|
+
status_icon_margin?: number;
|
|
62
|
+
}
|
|
63
|
+
export type LayoutDirection = 'LeftToRight' | 'TopToBottom';
|
|
64
|
+
/** Per-edge style override. */
|
|
65
|
+
export interface EdgeStyle {
|
|
66
|
+
/** CSS color for this edge (overrides theme default). */
|
|
67
|
+
color?: string;
|
|
68
|
+
/** Line width in px. */
|
|
69
|
+
width?: number;
|
|
70
|
+
/** Dash pattern array (e.g., [5, 3] for dashed). Empty = solid. */
|
|
71
|
+
dash?: number[];
|
|
72
|
+
}
|
|
73
|
+
/** Internationalization labels for status text and duration formatting. */
|
|
74
|
+
export interface Labels {
|
|
75
|
+
queued?: string;
|
|
76
|
+
running?: string;
|
|
77
|
+
success?: string;
|
|
78
|
+
failure?: string;
|
|
79
|
+
skipped?: string;
|
|
80
|
+
cancelled?: string;
|
|
81
|
+
/** Duration format for minutes+seconds. Use {m} and {s} placeholders. Default: "{m}m {s}s" */
|
|
82
|
+
duration_minutes?: string;
|
|
83
|
+
/** Duration format for seconds only. Use {s} placeholder. Default: "{s}s" */
|
|
84
|
+
duration_seconds?: string;
|
|
85
|
+
}
|
|
86
|
+
/** Theme configuration. All fields are optional — omitted fields use light-theme defaults. */
|
|
87
|
+
export interface ThemeConfig {
|
|
88
|
+
colors?: ThemeColors;
|
|
89
|
+
fonts?: ThemeFonts;
|
|
90
|
+
layout?: ThemeLayout;
|
|
91
|
+
direction?: LayoutDirection;
|
|
92
|
+
labels?: Labels;
|
|
93
|
+
/** Per-edge style overrides keyed by "from_id->to_id". */
|
|
94
|
+
edge_styles?: Record<string, EdgeStyle>;
|
|
95
|
+
/** Show the minimap overlay. Default: false. */
|
|
96
|
+
minimap?: boolean;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Custom node render callback.
|
|
100
|
+
* Called for each node during rendering.
|
|
101
|
+
* @param x - Node x position
|
|
102
|
+
* @param y - Node y position
|
|
103
|
+
* @param w - Node width
|
|
104
|
+
* @param h - Node height
|
|
105
|
+
* @param job - The job data object
|
|
106
|
+
* @returns `true` to skip default node rendering, `false` to render default on top.
|
|
107
|
+
*/
|
|
108
|
+
export type OnRenderNode = (x: number, y: number, w: number, h: number, job: Job) => boolean;
|
|
109
|
+
export interface GraphOptions {
|
|
110
|
+
onNodeClick?: (jobId: string) => void;
|
|
111
|
+
onNodeHover?: (jobId: string | null) => void;
|
|
112
|
+
onCanvasClick?: () => void;
|
|
113
|
+
onSelectionChange?: (selectedIds: string[]) => void;
|
|
114
|
+
onNodeDragEnd?: (jobId: string, x: number, y: number) => void;
|
|
115
|
+
/** Called when an edge is clicked. Requires bezier hit testing. */
|
|
116
|
+
onEdgeClick?: (fromId: string, toId: string) => void;
|
|
117
|
+
/** Custom node rendering callback. */
|
|
118
|
+
onRenderNode?: OnRenderNode;
|
|
119
|
+
/** Custom theme configuration. */
|
|
120
|
+
theme?: ThemeConfig;
|
|
121
|
+
/** Automatically resize the canvas when the container resizes. */
|
|
122
|
+
autoResize?: boolean;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Configure the URL to the WASM binary. Call this before creating any WorkflowGraph instances.
|
|
126
|
+
* Only needed if the default resolution doesn't work in your environment.
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```typescript
|
|
130
|
+
* setWasmUrl('/assets/workflow_graph_web_bg.wasm');
|
|
131
|
+
* // or from a CDN:
|
|
132
|
+
* setWasmUrl('https://cdn.example.com/wasm/workflow_graph_web_bg.wasm');
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
export declare function setWasmUrl(url: string | URL): void;
|
|
136
|
+
/**
|
|
137
|
+
* Interactive workflow DAG graph component.
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```typescript
|
|
141
|
+
* const graph = new WorkflowGraph(document.getElementById('container')!, {
|
|
142
|
+
* onNodeClick: (jobId) => console.log('clicked', jobId),
|
|
143
|
+
* theme: darkTheme,
|
|
144
|
+
* autoResize: true,
|
|
145
|
+
* });
|
|
146
|
+
* graph.setWorkflow(workflowData);
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
export declare class WorkflowGraph {
|
|
150
|
+
private canvasId;
|
|
151
|
+
private canvas;
|
|
152
|
+
private options;
|
|
153
|
+
private initialized;
|
|
154
|
+
constructor(container: HTMLElement, options?: GraphOptions);
|
|
155
|
+
/** Render a workflow. Call this on initial load. */
|
|
156
|
+
setWorkflow(workflow: Workflow): Promise<void>;
|
|
157
|
+
/** Update workflow data without resetting positions or zoom. */
|
|
158
|
+
updateStatus(workflow: Workflow): Promise<void>;
|
|
159
|
+
/** Update the theme at runtime. Triggers re-layout if dimensions or direction changed. */
|
|
160
|
+
setTheme(theme: ThemeConfig): Promise<void>;
|
|
161
|
+
/** Enable or disable auto-resize via ResizeObserver. */
|
|
162
|
+
setAutoResize(enabled: boolean): Promise<void>;
|
|
163
|
+
/** Programmatically select a node. */
|
|
164
|
+
selectNode(jobId: string): Promise<void>;
|
|
165
|
+
/** Deselect all nodes. */
|
|
166
|
+
deselectAll(): Promise<void>;
|
|
167
|
+
/** Reset node positions to auto-layout. */
|
|
168
|
+
resetLayout(): Promise<void>;
|
|
169
|
+
/** Zoom to fit the entire graph. */
|
|
170
|
+
zoomToFit(): Promise<void>;
|
|
171
|
+
/** Set zoom level (0.25 to 4.0). */
|
|
172
|
+
setZoom(level: number): Promise<void>;
|
|
173
|
+
/** Get current node positions for persistence. */
|
|
174
|
+
getNodePositions(): Promise<Record<string, [number, number]>>;
|
|
175
|
+
/** Restore previously saved node positions. */
|
|
176
|
+
setNodePositions(positions: Record<string, [number, number]>): Promise<void>;
|
|
177
|
+
/** Clean up event listeners, resize observer, and remove the canvas. */
|
|
178
|
+
destroy(): Promise<void>;
|
|
179
|
+
}
|
|
180
|
+
/** GitHub Actions dark mode theme preset. */
|
|
181
|
+
export declare const darkTheme: ThemeConfig;
|
|
182
|
+
/** Default GitHub Actions light theme (no-op, but useful for toggling back). */
|
|
183
|
+
export declare const lightTheme: ThemeConfig;
|
|
184
|
+
/** WCAG AA high-contrast theme for accessibility. */
|
|
185
|
+
export declare const highContrastTheme: ThemeConfig;
|
|
186
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* workflow-graph — Interactive workflow DAG visualizer
|
|
3
|
+
*
|
|
4
|
+
* TypeScript wrapper around the WASM module.
|
|
5
|
+
*/
|
|
6
|
+
let wasmModule = null;
|
|
7
|
+
let customWasmUrl;
|
|
8
|
+
/**
|
|
9
|
+
* Configure the URL to the WASM binary. Call this before creating any WorkflowGraph instances.
|
|
10
|
+
* Only needed if the default resolution doesn't work in your environment.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* setWasmUrl('/assets/workflow_graph_web_bg.wasm');
|
|
15
|
+
* // or from a CDN:
|
|
16
|
+
* setWasmUrl('https://cdn.example.com/wasm/workflow_graph_web_bg.wasm');
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function setWasmUrl(url) {
|
|
20
|
+
customWasmUrl = url;
|
|
21
|
+
}
|
|
22
|
+
async function ensureWasm() {
|
|
23
|
+
if (wasmModule)
|
|
24
|
+
return wasmModule;
|
|
25
|
+
// Dynamic import of the WASM glue code bundled in wasm/
|
|
26
|
+
// @ts-expect-error — external wasm-pack artifact, not a TS module
|
|
27
|
+
const mod = await import('../wasm/workflow_graph_web.js');
|
|
28
|
+
await mod.default(customWasmUrl);
|
|
29
|
+
wasmModule = mod;
|
|
30
|
+
return wasmModule;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Interactive workflow DAG graph component.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* const graph = new WorkflowGraph(document.getElementById('container')!, {
|
|
38
|
+
* onNodeClick: (jobId) => console.log('clicked', jobId),
|
|
39
|
+
* theme: darkTheme,
|
|
40
|
+
* autoResize: true,
|
|
41
|
+
* });
|
|
42
|
+
* graph.setWorkflow(workflowData);
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export class WorkflowGraph {
|
|
46
|
+
constructor(container, options = {}) {
|
|
47
|
+
this.initialized = false;
|
|
48
|
+
this.canvasId = `gg-${Math.random().toString(36).slice(2, 9)}`;
|
|
49
|
+
this.canvas = document.createElement('canvas');
|
|
50
|
+
this.canvas.id = this.canvasId;
|
|
51
|
+
this.canvas.style.display = 'block';
|
|
52
|
+
this.canvas.setAttribute('role', 'img');
|
|
53
|
+
this.canvas.setAttribute('aria-label', 'Workflow DAG visualization');
|
|
54
|
+
this.canvas.tabIndex = 0;
|
|
55
|
+
container.appendChild(this.canvas);
|
|
56
|
+
this.options = options;
|
|
57
|
+
}
|
|
58
|
+
/** Render a workflow. Call this on initial load. */
|
|
59
|
+
async setWorkflow(workflow) {
|
|
60
|
+
const wasm = await ensureWasm();
|
|
61
|
+
const json = JSON.stringify(workflow);
|
|
62
|
+
const themeJson = this.options.theme ? JSON.stringify(this.options.theme) : null;
|
|
63
|
+
wasm.render_workflow(this.canvasId, json, this.options.onNodeClick || null, this.options.onNodeHover || null, this.options.onCanvasClick || null, this.options.onSelectionChange || null, this.options.onNodeDragEnd || null, themeJson);
|
|
64
|
+
this.initialized = true;
|
|
65
|
+
// Wire up optional callbacks that use separate WASM functions
|
|
66
|
+
if (this.options.onEdgeClick) {
|
|
67
|
+
wasm.set_on_edge_click(this.canvasId, this.options.onEdgeClick);
|
|
68
|
+
}
|
|
69
|
+
if (this.options.onRenderNode) {
|
|
70
|
+
wasm.set_on_render_node(this.canvasId, this.options.onRenderNode);
|
|
71
|
+
}
|
|
72
|
+
if (this.options.autoResize) {
|
|
73
|
+
wasm.set_auto_resize(this.canvasId, true);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/** Update workflow data without resetting positions or zoom. */
|
|
77
|
+
async updateStatus(workflow) {
|
|
78
|
+
const wasm = await ensureWasm();
|
|
79
|
+
if (this.initialized) {
|
|
80
|
+
wasm.update_workflow_data(this.canvasId, JSON.stringify(workflow));
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
await this.setWorkflow(workflow);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** Update the theme at runtime. Triggers re-layout if dimensions or direction changed. */
|
|
87
|
+
async setTheme(theme) {
|
|
88
|
+
const wasm = await ensureWasm();
|
|
89
|
+
wasm.set_theme(this.canvasId, JSON.stringify(theme));
|
|
90
|
+
this.options.theme = theme;
|
|
91
|
+
}
|
|
92
|
+
/** Enable or disable auto-resize via ResizeObserver. */
|
|
93
|
+
async setAutoResize(enabled) {
|
|
94
|
+
const wasm = await ensureWasm();
|
|
95
|
+
wasm.set_auto_resize(this.canvasId, enabled);
|
|
96
|
+
this.options.autoResize = enabled;
|
|
97
|
+
}
|
|
98
|
+
/** Programmatically select a node. */
|
|
99
|
+
async selectNode(jobId) {
|
|
100
|
+
const wasm = await ensureWasm();
|
|
101
|
+
wasm.select_node(this.canvasId, jobId);
|
|
102
|
+
}
|
|
103
|
+
/** Deselect all nodes. */
|
|
104
|
+
async deselectAll() {
|
|
105
|
+
const wasm = await ensureWasm();
|
|
106
|
+
wasm.deselect_all(this.canvasId);
|
|
107
|
+
}
|
|
108
|
+
/** Reset node positions to auto-layout. */
|
|
109
|
+
async resetLayout() {
|
|
110
|
+
const wasm = await ensureWasm();
|
|
111
|
+
wasm.reset_layout(this.canvasId);
|
|
112
|
+
}
|
|
113
|
+
/** Zoom to fit the entire graph. */
|
|
114
|
+
async zoomToFit() {
|
|
115
|
+
const wasm = await ensureWasm();
|
|
116
|
+
wasm.zoom_to_fit(this.canvasId);
|
|
117
|
+
}
|
|
118
|
+
/** Set zoom level (0.25 to 4.0). */
|
|
119
|
+
async setZoom(level) {
|
|
120
|
+
const wasm = await ensureWasm();
|
|
121
|
+
wasm.set_zoom(this.canvasId, level);
|
|
122
|
+
}
|
|
123
|
+
/** Get current node positions for persistence. */
|
|
124
|
+
async getNodePositions() {
|
|
125
|
+
const wasm = await ensureWasm();
|
|
126
|
+
return wasm.get_node_positions(this.canvasId);
|
|
127
|
+
}
|
|
128
|
+
/** Restore previously saved node positions. */
|
|
129
|
+
async setNodePositions(positions) {
|
|
130
|
+
const wasm = await ensureWasm();
|
|
131
|
+
wasm.set_node_positions(this.canvasId, JSON.stringify(positions));
|
|
132
|
+
}
|
|
133
|
+
/** Clean up event listeners, resize observer, and remove the canvas. */
|
|
134
|
+
async destroy() {
|
|
135
|
+
const wasm = await ensureWasm();
|
|
136
|
+
wasm.destroy(this.canvasId);
|
|
137
|
+
this.canvas.remove();
|
|
138
|
+
this.initialized = false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// ─── Preset themes ───────────────────────────────────────────────────────────
|
|
142
|
+
/** GitHub Actions dark mode theme preset. */
|
|
143
|
+
export const darkTheme = {
|
|
144
|
+
colors: {
|
|
145
|
+
success: '#3fb950',
|
|
146
|
+
failure: '#f85149',
|
|
147
|
+
running: '#d29922',
|
|
148
|
+
queued: '#8b949e',
|
|
149
|
+
skipped: '#8b949e',
|
|
150
|
+
cancelled: '#8b949e',
|
|
151
|
+
node_bg: '#161b22',
|
|
152
|
+
node_border: '#30363d',
|
|
153
|
+
text: '#e6edf3',
|
|
154
|
+
text_secondary: '#8b949e',
|
|
155
|
+
bg: '#0d1117',
|
|
156
|
+
graph_bg: '#161b22',
|
|
157
|
+
edge: '#30363d',
|
|
158
|
+
junction: '#484f58',
|
|
159
|
+
highlight: '#58a6ff',
|
|
160
|
+
selected: '#58a6ff',
|
|
161
|
+
header_text: '#e6edf3',
|
|
162
|
+
header_trigger: '#8b949e',
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
/** Default GitHub Actions light theme (no-op, but useful for toggling back). */
|
|
166
|
+
export const lightTheme = {};
|
|
167
|
+
/** WCAG AA high-contrast theme for accessibility. */
|
|
168
|
+
export const highContrastTheme = {
|
|
169
|
+
colors: {
|
|
170
|
+
success: '#008000',
|
|
171
|
+
failure: '#ff0000',
|
|
172
|
+
running: '#ff8c00',
|
|
173
|
+
queued: '#555555',
|
|
174
|
+
skipped: '#555555',
|
|
175
|
+
cancelled: '#555555',
|
|
176
|
+
node_bg: '#ffffff',
|
|
177
|
+
node_border: '#000000',
|
|
178
|
+
text: '#000000',
|
|
179
|
+
text_secondary: '#333333',
|
|
180
|
+
bg: '#ffffff',
|
|
181
|
+
graph_bg: '#f0f0f0',
|
|
182
|
+
edge: '#000000',
|
|
183
|
+
junction: '#000000',
|
|
184
|
+
highlight: '#0000ff',
|
|
185
|
+
selected: '#0000ff',
|
|
186
|
+
header_text: '#000000',
|
|
187
|
+
header_trigger: '#333333',
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@auser/workflow-graph-web",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Interactive workflow DAG visualizer (WASM + Canvas)",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": ["dist/", "wasm/", "src/", "README.md"],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"copy-wasm": "mkdir -p wasm && cp ../../crates/web/pkg/workflow_graph_web.js ../../crates/web/pkg/workflow_graph_web_bg.wasm wasm/",
|
|
11
|
+
"build": "npm run copy-wasm && tsc",
|
|
12
|
+
"prepublishOnly": "npm run build"
|
|
13
|
+
},
|
|
14
|
+
"keywords": ["workflow", "dag", "graph", "wasm", "canvas", "github-actions", "visualization"],
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/auser/workflow-graph",
|
|
19
|
+
"directory": "packages/web"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://auser.github.io/workflow-graph/",
|
|
22
|
+
"sideEffects": false,
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"typescript": "^5.0.0"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=18"
|
|
28
|
+
},
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"import": "./dist/index.js",
|
|
33
|
+
"default": "./dist/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./wasm/*": "./wasm/*"
|
|
36
|
+
}
|
|
37
|
+
}
|