@motiadev/workbench 0.2.2 → 0.3.0-beta.79
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 +1 -1
- package/dist/index.html +9 -9
- package/dist/index.js +1 -1
- package/dist/src/components/app-sidebar.js +2 -2
- package/dist/src/components/endpoints/endpoint-call.js +2 -2
- package/dist/src/components/header/header.js +1 -1
- package/dist/src/components/logs/log-console.js +1 -1
- package/dist/src/components/observability/events/code/function-call.d.ts +13 -0
- package/dist/src/components/observability/events/code/function-call.js +16 -0
- package/dist/src/components/observability/events/event-icon.d.ts +7 -0
- package/dist/src/components/observability/events/event-icon.js +16 -0
- package/dist/src/components/observability/events/trace-emit-event.d.ts +5 -0
- package/dist/src/components/observability/events/trace-emit-event.js +5 -0
- package/dist/src/components/observability/events/trace-event.d.ts +5 -0
- package/dist/src/components/observability/events/trace-event.js +20 -0
- package/dist/src/components/observability/events/trace-log-event.d.ts +5 -0
- package/dist/src/components/observability/events/trace-log-event.js +5 -0
- package/dist/src/components/observability/events/trace-state-event.d.ts +5 -0
- package/dist/src/components/observability/events/trace-state-event.js +5 -0
- package/dist/src/components/observability/events/trace-stream-event.d.ts +5 -0
- package/dist/src/components/observability/events/trace-stream-event.js +5 -0
- package/dist/src/components/observability/hooks/use-get-endtime.d.ts +2 -0
- package/dist/src/components/observability/hooks/use-get-endtime.js +15 -0
- package/dist/src/components/observability/observability-stats.d.ts +5 -0
- package/dist/src/components/observability/observability-stats.js +17 -0
- package/dist/src/components/observability/trace-item/trace-item-detail.d.ts +7 -0
- package/dist/src/components/observability/trace-item/trace-item-detail.js +10 -0
- package/dist/src/components/observability/trace-item/trace-item.d.ts +9 -0
- package/dist/src/components/observability/trace-item/trace-item.js +20 -0
- package/dist/src/components/observability/trace-status.d.ts +12 -0
- package/dist/src/components/observability/trace-status.js +43 -0
- package/dist/src/components/observability/trace-timeline.d.ts +6 -0
- package/dist/src/components/observability/trace-timeline.js +17 -0
- package/dist/src/components/observability/traces-groups.d.ts +9 -0
- package/dist/src/components/observability/traces-groups.js +15 -0
- package/dist/src/components/ui/card.d.ts +8 -0
- package/dist/src/components/ui/card.js +16 -0
- package/dist/src/components/ui/navigation-menu.d.ts +9 -10
- package/dist/src/components/ui/navigation-menu.js +9 -10
- package/dist/src/components/ui/scroll-area.d.ts +5 -0
- package/dist/src/components/ui/scroll-area.js +9 -0
- package/dist/src/components/ui/sheet.d.ts +1 -1
- package/dist/src/components/ui/sidebar.js +1 -1
- package/dist/src/components/ui/tabs.d.ts +7 -0
- package/dist/src/components/ui/tabs.js +12 -0
- package/dist/src/hooks/use-fetch-flows.d.ts +5 -0
- package/dist/src/hooks/use-fetch-flows.js +17 -0
- package/dist/src/hooks/use-list-flows.d.ts +3 -2
- package/dist/src/index.css +2 -155
- package/dist/src/lib/utils.d.ts +1 -0
- package/dist/src/lib/utils.js +7 -0
- package/dist/src/main.js +2 -1
- package/dist/src/routes/flow.js +2 -13
- package/dist/src/routes/index.js +2 -2
- package/dist/src/routes/traces-page.d.ts +1 -0
- package/dist/src/routes/traces-page.js +14 -0
- package/dist/src/types/observability.d.ts +78 -0
- package/dist/src/types/observability.js +1 -0
- package/dist/src/views/flow/flow-view.js +2 -17
- package/dist/src/views/flow/hooks/use-get-flow-state.d.ts +5 -2
- package/dist/src/views/flow/hooks/use-get-flow-state.js +97 -27
- package/dist/src/views/flow/hooks/use-save-workflow-config.d.ts +2 -9
- package/dist/src/views/flow/hooks/use-save-workflow-config.js +5 -6
- package/dist/src/views/flow/legend.js +1 -1
- package/dist/src/views/flow/node-organizer.js +4 -2
- package/dist/tsconfig.app.tsbuildinfo +1 -1
- package/package.json +12 -6
- package/dist/src/components/ui/button.d.ts +0 -11
- package/dist/src/components/ui/button.js +0 -33
|
@@ -1,38 +1,55 @@
|
|
|
1
1
|
import { useEdgesState, useNodesState } from '@xyflow/react';
|
|
2
|
-
import { useEffect, useState } from 'react';
|
|
2
|
+
import { useCallback, useEffect, useRef, useState, useMemo } from 'react';
|
|
3
3
|
import { ApiFlowNode } from '../nodes/api-flow-node';
|
|
4
4
|
import { NoopFlowNode } from '../nodes/noop-flow-node';
|
|
5
5
|
import { EventFlowNode } from '../nodes/event-flow-node';
|
|
6
6
|
import { CronNode } from '@/publicComponents/cron-node';
|
|
7
|
+
import isEqual from 'fast-deep-equal';
|
|
8
|
+
import { useSaveWorkflowConfig } from '@/views/flow/hooks/use-save-workflow-config';
|
|
9
|
+
const DEFAULT_POSITION = { x: 0, y: 0 };
|
|
7
10
|
const getNodePosition = (flowConfig, stepName) => {
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
return flowConfig?.config[stepName] || DEFAULT_POSITION;
|
|
12
|
+
};
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
|
+
const nodeComponentCache = new Map();
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
|
+
const BASE_NODE_TYPES = {
|
|
17
|
+
event: EventFlowNode,
|
|
18
|
+
api: ApiFlowNode,
|
|
19
|
+
noop: NoopFlowNode,
|
|
20
|
+
cron: CronNode,
|
|
10
21
|
};
|
|
11
22
|
async function importFlow(flow, flowConfig) {
|
|
12
23
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
|
-
const nodeTypes = {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
const nodeTypes = { ...BASE_NODE_TYPES };
|
|
25
|
+
const customNodePromises = flow.steps
|
|
26
|
+
.filter((step) => step.nodeComponentPath)
|
|
27
|
+
.map(async (step) => {
|
|
28
|
+
const path = step.nodeComponentPath;
|
|
29
|
+
// Check cache first
|
|
30
|
+
if (nodeComponentCache.has(path)) {
|
|
31
|
+
nodeTypes[path] = nodeComponentCache.get(path);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const module = await import(/* @vite-ignore */ `/@fs/${path}`);
|
|
36
|
+
const component = module.Node ?? module.default;
|
|
37
|
+
nodeComponentCache.set(path, component);
|
|
38
|
+
nodeTypes[path] = component;
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
console.error(`Failed to load custom node component: ${path}`, error);
|
|
24
42
|
}
|
|
25
|
-
}
|
|
26
|
-
|
|
43
|
+
});
|
|
44
|
+
await Promise.all(customNodePromises);
|
|
27
45
|
const nodes = flow.steps.map((step) => ({
|
|
28
46
|
id: step.id,
|
|
29
|
-
type: step.nodeComponentPath
|
|
47
|
+
type: step.nodeComponentPath || step.type,
|
|
30
48
|
filePath: step.filePath,
|
|
31
|
-
position: step.filePath ? getNodePosition(flowConfig, step.filePath) :
|
|
49
|
+
position: step.filePath ? getNodePosition(flowConfig, step.filePath) : DEFAULT_POSITION,
|
|
32
50
|
data: step,
|
|
33
51
|
language: step.language,
|
|
34
52
|
}));
|
|
35
|
-
// Use the edges provided by the API, adding required ReactFlow properties
|
|
36
53
|
const edges = flow.edges.map((edge) => ({
|
|
37
54
|
...edge,
|
|
38
55
|
type: 'base',
|
|
@@ -41,17 +58,70 @@ async function importFlow(flow, flowConfig) {
|
|
|
41
58
|
}
|
|
42
59
|
export const useGetFlowState = (flow, flowConfig) => {
|
|
43
60
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
|
-
const [nodeTypes, setNodeTypes] = useState();
|
|
61
|
+
const [nodeTypes, setNodeTypes] = useState(BASE_NODE_TYPES);
|
|
45
62
|
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
|
46
63
|
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
|
64
|
+
const saveConfig = useSaveWorkflowConfig();
|
|
65
|
+
const flowIdRef = useRef('');
|
|
66
|
+
const saveTimeoutRef = useRef(null);
|
|
67
|
+
const lastSavedConfigRef = useRef(null);
|
|
68
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
69
|
+
const memoizedFlowConfig = useMemo(() => flowConfig, [flowConfig?.id, flowConfig?.config]);
|
|
47
70
|
useEffect(() => {
|
|
48
71
|
if (!flow || flow.error)
|
|
49
72
|
return;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
73
|
+
if (isEqual(lastSavedConfigRef.current, memoizedFlowConfig?.config))
|
|
74
|
+
return;
|
|
75
|
+
lastSavedConfigRef.current = memoizedFlowConfig?.config;
|
|
76
|
+
flowIdRef.current = flow.id;
|
|
77
|
+
const importFlowAsync = async () => {
|
|
78
|
+
try {
|
|
79
|
+
const { nodes, edges, nodeTypes } = await importFlow(flow, flowConfig);
|
|
80
|
+
setNodes(nodes);
|
|
81
|
+
setEdges(edges);
|
|
82
|
+
setNodeTypes(nodeTypes);
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
console.error('Failed to import flow:', error);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
importFlowAsync();
|
|
89
|
+
}, [flow, memoizedFlowConfig, setNodes, setEdges, flowConfig]);
|
|
90
|
+
const saveFlowConfig = useCallback((nodesToSave) => {
|
|
91
|
+
if (saveTimeoutRef.current) {
|
|
92
|
+
clearTimeout(saveTimeoutRef.current);
|
|
93
|
+
}
|
|
94
|
+
saveTimeoutRef.current = setTimeout(async () => {
|
|
95
|
+
const steps = nodesToSave.reduce((acc, node) => {
|
|
96
|
+
if (node.data.filePath) {
|
|
97
|
+
acc[node.data.filePath] = {
|
|
98
|
+
x: Math.round(node.position.x),
|
|
99
|
+
y: Math.round(node.position.y),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return acc;
|
|
103
|
+
}, {});
|
|
104
|
+
if (!isEqual(steps, lastSavedConfigRef.current)) {
|
|
105
|
+
lastSavedConfigRef.current = steps;
|
|
106
|
+
const newConfig = { id: flowIdRef.current, config: steps };
|
|
107
|
+
try {
|
|
108
|
+
await saveConfig(newConfig);
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
console.error('Failed to save flow config:', error);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}, 300);
|
|
115
|
+
}, [saveConfig]);
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
if (nodes.length > 0) {
|
|
118
|
+
saveFlowConfig(nodes);
|
|
119
|
+
}
|
|
120
|
+
return () => {
|
|
121
|
+
if (saveTimeoutRef.current) {
|
|
122
|
+
clearTimeout(saveTimeoutRef.current);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
}, [nodes, saveFlowConfig]);
|
|
126
|
+
return useMemo(() => ({ nodes, edges, onNodesChange, onEdgesChange, nodeTypes }), [nodes, edges, onNodesChange, onEdgesChange, nodeTypes]);
|
|
57
127
|
};
|
|
@@ -1,9 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
x: number;
|
|
4
|
-
y: number;
|
|
5
|
-
};
|
|
6
|
-
};
|
|
7
|
-
export declare const useSaveWorkflowConfig: (flowId: string) => {
|
|
8
|
-
saveConfig: (body: NodePosition) => Promise<any>;
|
|
9
|
-
};
|
|
1
|
+
import { FlowConfigResponse } from '@/views/flow/hooks/use-get-flow-state';
|
|
2
|
+
export declare const useSaveWorkflowConfig: () => (body: FlowConfigResponse) => Promise<any>;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { useCallback } from 'react';
|
|
2
|
-
export const useSaveWorkflowConfig = (
|
|
3
|
-
|
|
2
|
+
export const useSaveWorkflowConfig = () => {
|
|
3
|
+
return useCallback(async (body) => {
|
|
4
4
|
try {
|
|
5
|
-
const response = await fetch(`/flows/${
|
|
5
|
+
const response = await fetch(`/flows/${body.id}/config`, {
|
|
6
6
|
method: 'POST',
|
|
7
7
|
headers: {
|
|
8
8
|
'Content-Type': 'application/json',
|
|
9
9
|
},
|
|
10
|
-
body: JSON.stringify(
|
|
10
|
+
body: JSON.stringify(body),
|
|
11
11
|
});
|
|
12
12
|
if (!response.ok) {
|
|
13
13
|
throw new Error(`Failed to save config: ${response.statusText}`);
|
|
@@ -18,6 +18,5 @@ export const useSaveWorkflowConfig = (flowId) => {
|
|
|
18
18
|
console.error('Error saving workflow config:', error);
|
|
19
19
|
throw error;
|
|
20
20
|
}
|
|
21
|
-
}, [
|
|
22
|
-
return { saveConfig };
|
|
21
|
+
}, []);
|
|
23
22
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { Button } from '
|
|
2
|
+
import { Button } from '@motiadev/ui';
|
|
3
3
|
import { cn } from '@/lib/utils';
|
|
4
4
|
import { LayoutList, X } from 'lucide-react';
|
|
5
5
|
import { useState } from 'react';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useNodesInitialized, useReactFlow } from '@xyflow/react';
|
|
2
2
|
import dagre from 'dagre';
|
|
3
|
-
import { useEffect } from 'react';
|
|
3
|
+
import { useEffect, useRef } from 'react';
|
|
4
4
|
const organizeNodes = (nodes, edges) => {
|
|
5
5
|
const dagreGraph = new dagre.graphlib.Graph({ compound: true });
|
|
6
6
|
dagreGraph.setDefaultEdgeLabel(() => ({}));
|
|
@@ -37,8 +37,10 @@ const organizeNodes = (nodes, edges) => {
|
|
|
37
37
|
export const NodeOrganizer = ({ onInitialized }) => {
|
|
38
38
|
const { setNodes, getNodes, getEdges, fitView } = useReactFlow();
|
|
39
39
|
const nodesInitialized = useNodesInitialized();
|
|
40
|
+
const initialized = useRef(false);
|
|
40
41
|
useEffect(() => {
|
|
41
|
-
if (nodesInitialized) {
|
|
42
|
+
if (nodesInitialized && !initialized.current) {
|
|
43
|
+
initialized.current = true;
|
|
42
44
|
const nodes = getNodes();
|
|
43
45
|
const edges = getEdges();
|
|
44
46
|
const organizedNodes = organizeNodes(nodes, edges);
|