@motiadev/workbench 0.13.1-beta.163-660633 → 0.13.1-beta.163-584961
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 +10 -189
- package/dist/index.html +1 -1
- package/dist/index.js +7 -1065
- package/dist/middleware.d.ts +8 -66
- package/dist/middleware.js +86 -694
- package/dist/motia-plugin/__tests__/generator.test.d.ts +1 -0
- package/dist/motia-plugin/__tests__/generator.test.js +97 -0
- package/dist/motia-plugin/__tests__/resolver.test.d.ts +1 -0
- package/dist/motia-plugin/__tests__/resolver.test.js +64 -0
- package/dist/motia-plugin/__tests__/validator.test.d.ts +1 -0
- package/dist/motia-plugin/__tests__/validator.test.js +59 -0
- package/dist/motia-plugin/generator.d.ts +78 -0
- package/dist/motia-plugin/{generator.ts → generator.js} +35 -37
- package/dist/motia-plugin/hmr.d.ts +22 -0
- package/dist/motia-plugin/hmr.js +100 -0
- package/dist/motia-plugin/index.d.ts +3 -0
- package/dist/motia-plugin/index.js +153 -0
- package/dist/motia-plugin/{resolver.ts → resolver.d.ts} +5 -38
- package/dist/motia-plugin/resolver.js +92 -0
- package/dist/motia-plugin/types.d.ts +169 -0
- package/dist/motia-plugin/types.js +36 -0
- package/dist/motia-plugin/{utils.ts → utils.d.ts} +4 -17
- package/dist/motia-plugin/utils.js +75 -0
- package/dist/motia-plugin/validator.d.ts +19 -0
- package/dist/motia-plugin/validator.js +163 -0
- package/dist/src/App.d.ts +2 -0
- package/dist/src/App.js +35 -0
- package/dist/src/components/NotFoundPage.d.ts +1 -0
- package/dist/src/components/NotFoundPage.js +3 -0
- package/dist/src/components/bottom-panel.d.ts +1 -0
- package/dist/src/components/bottom-panel.js +15 -0
- package/dist/src/components/flow/base-edge.d.ts +3 -0
- package/dist/src/components/flow/base-edge.js +39 -0
- package/dist/src/components/flow/flow-loader.d.ts +1 -0
- package/dist/src/components/flow/flow-loader.js +4 -0
- package/dist/src/components/flow/flow-page.d.ts +1 -0
- package/dist/src/components/flow/flow-page.js +25 -0
- package/dist/src/components/flow/flow-tab-menu-item.d.ts +1 -0
- package/dist/src/components/flow/flow-tab-menu-item.js +18 -0
- package/dist/src/components/flow/flow-view.d.ts +12 -0
- package/dist/src/components/flow/flow-view.js +22 -0
- package/dist/src/components/flow/hooks/use-get-flow-state.d.ts +10 -0
- package/dist/src/components/flow/hooks/use-get-flow-state.js +133 -0
- package/dist/src/components/flow/hooks/use-save-workflow-config.d.ts +2 -0
- package/dist/src/components/flow/hooks/use-save-workflow-config.js +22 -0
- package/dist/src/components/flow/node-organizer.d.ts +10 -0
- package/dist/src/components/flow/node-organizer.js +82 -0
- package/dist/src/components/flow/nodes/api-flow-node.d.ts +2 -0
- package/dist/src/components/flow/nodes/api-flow-node.js +5 -0
- package/dist/src/components/flow/nodes/cron-flow-node.d.ts +2 -0
- package/dist/src/components/flow/nodes/cron-flow-node.js +5 -0
- package/dist/src/components/flow/nodes/event-flow-node.d.ts +2 -0
- package/dist/src/components/flow/nodes/event-flow-node.js +5 -0
- package/dist/src/components/flow/nodes/noop-flow-node.d.ts +2 -0
- package/dist/src/components/flow/nodes/noop-flow-node.js +5 -0
- package/dist/src/components/header/deploy-button.d.ts +1 -0
- package/dist/src/components/header/deploy-button.js +28 -0
- package/dist/src/components/header/header.d.ts +2 -0
- package/dist/src/components/header/header.js +23 -0
- package/dist/src/components/root-motia.d.ts +2 -0
- package/dist/src/components/root-motia.js +7 -0
- package/dist/src/components/top-panel.d.ts +1 -0
- package/dist/src/components/top-panel.js +15 -0
- package/dist/src/components/tutorial/engine/tutorial-engine.d.ts +12 -0
- package/dist/src/components/tutorial/engine/tutorial-engine.js +36 -0
- package/dist/src/components/tutorial/engine/tutorial-types.d.ts +22 -0
- package/dist/src/components/tutorial/engine/tutorial-types.js +1 -0
- package/dist/src/components/tutorial/engine/workbench-xpath.d.ts +45 -0
- package/dist/src/components/tutorial/engine/workbench-xpath.js +45 -0
- package/dist/src/components/tutorial/hooks/tutorial-utils.d.ts +1 -0
- package/dist/src/components/tutorial/hooks/tutorial-utils.js +17 -0
- package/dist/src/components/tutorial/hooks/use-tutorial-engine.d.ts +15 -0
- package/dist/src/components/tutorial/hooks/use-tutorial-engine.js +183 -0
- package/dist/src/components/tutorial/hooks/use-tutorial.d.ts +5 -0
- package/dist/src/components/tutorial/hooks/use-tutorial.js +10 -0
- package/dist/src/components/tutorial/tutorial-button.d.ts +2 -0
- package/dist/src/components/tutorial/tutorial-button.js +21 -0
- package/dist/src/components/tutorial/tutorial-step.d.ts +14 -0
- package/dist/src/components/tutorial/tutorial-step.js +19 -0
- package/dist/src/components/tutorial/tutorial.css +2 -2
- package/dist/src/components/tutorial/tutorial.d.ts +2 -0
- package/dist/src/components/tutorial/tutorial.js +32 -0
- package/dist/src/components/ui/json-editor.d.ts +12 -0
- package/dist/src/components/ui/json-editor.js +35 -0
- package/dist/src/components/ui/table.d.ts +10 -0
- package/dist/src/components/ui/table.js +20 -0
- package/dist/src/components/ui/theme-toggle.d.ts +2 -0
- package/dist/src/components/ui/theme-toggle.js +19 -0
- package/dist/src/components/ui/tooltip.d.ts +6 -0
- package/dist/src/components/ui/tooltip.js +3 -0
- package/dist/src/hooks/use-debounced.d.ts +1 -0
- package/dist/src/hooks/use-debounced.js +18 -0
- package/dist/src/hooks/use-fetch-flows.d.ts +1 -0
- package/dist/src/hooks/use-fetch-flows.js +26 -0
- package/dist/src/hooks/use-mobile.d.ts +1 -0
- package/dist/src/hooks/use-mobile.js +15 -0
- package/dist/src/hooks/use-update-handle-positions.d.ts +10 -0
- package/dist/src/hooks/use-update-handle-positions.js +35 -0
- package/dist/src/index.css +5 -5
- package/dist/src/lib/__tests__/utils.test.d.ts +1 -0
- package/dist/src/lib/__tests__/utils.test.js +94 -0
- package/dist/src/lib/motia-analytics.d.ts +38 -0
- package/dist/src/lib/motia-analytics.js +132 -0
- package/dist/src/lib/plugins.d.ts +2 -0
- package/dist/src/lib/plugins.js +105 -0
- package/dist/src/lib/utils.d.ts +7 -0
- package/dist/src/lib/utils.js +34 -0
- package/dist/src/main.d.ts +2 -0
- package/dist/src/main.js +17 -0
- package/dist/src/project-view-mode.d.ts +1 -0
- package/dist/src/project-view-mode.js +20 -0
- package/dist/src/publicComponents/api-node.d.ts +5 -0
- package/dist/src/publicComponents/api-node.js +5 -0
- package/dist/src/publicComponents/base-node/base-handle.d.ts +9 -0
- package/dist/src/publicComponents/base-node/base-handle.js +8 -0
- package/dist/src/publicComponents/base-node/base-node.d.ts +15 -0
- package/dist/src/publicComponents/base-node/base-node.js +30 -0
- package/dist/src/publicComponents/base-node/code-display.d.ts +9 -0
- package/dist/src/publicComponents/base-node/code-display.js +64 -0
- package/dist/src/publicComponents/base-node/emits.d.ts +5 -0
- package/dist/src/publicComponents/base-node/emits.js +5 -0
- package/dist/src/publicComponents/base-node/feature-card.d.ts +10 -0
- package/dist/src/publicComponents/base-node/feature-card.js +5 -0
- package/dist/src/publicComponents/base-node/language-indicator.d.ts +10 -0
- package/dist/src/publicComponents/base-node/language-indicator.js +29 -0
- package/dist/src/publicComponents/base-node/node-header.d.ts +13 -0
- package/dist/src/publicComponents/base-node/node-header.js +30 -0
- package/dist/src/publicComponents/base-node/node-sidebar.d.ts +14 -0
- package/dist/src/publicComponents/base-node/node-sidebar.js +9 -0
- package/dist/src/publicComponents/base-node/subscribe.d.ts +4 -0
- package/dist/src/publicComponents/base-node/subscribe.js +4 -0
- package/dist/src/publicComponents/cron-node.d.ts +4 -0
- package/dist/src/publicComponents/cron-node.js +6 -0
- package/dist/src/publicComponents/event-node.d.ts +4 -0
- package/dist/src/publicComponents/event-node.js +5 -0
- package/dist/src/publicComponents/node-props.d.ts +21 -0
- package/dist/src/publicComponents/node-props.js +1 -0
- package/dist/src/publicComponents/noop-node.d.ts +4 -0
- package/dist/src/publicComponents/noop-node.js +5 -0
- package/dist/src/setupTests.d.ts +1 -0
- package/dist/src/setupTests.js +1 -0
- package/dist/src/stores/use-app-tabs-store.d.ts +16 -0
- package/dist/src/stores/use-app-tabs-store.js +31 -0
- package/dist/src/stores/use-flow-store.d.ts +21 -0
- package/dist/src/stores/use-flow-store.js +16 -0
- package/dist/src/stores/use-global-store.d.ts +18 -0
- package/dist/src/stores/use-global-store.js +12 -0
- package/dist/src/stores/use-motia-config-store.d.ts +12 -0
- package/dist/src/stores/use-motia-config-store.js +24 -0
- package/dist/src/stores/use-tabs-store.d.ts +19 -0
- package/dist/src/stores/use-tabs-store.js +22 -0
- package/dist/src/system-view-mode.d.ts +1 -0
- package/dist/src/system-view-mode.js +10 -0
- package/dist/src/types/endpoint.d.ts +14 -0
- package/dist/src/types/endpoint.js +1 -0
- package/dist/src/types/file.d.ts +7 -0
- package/dist/src/types/file.js +1 -0
- package/dist/src/types/flow.d.ts +115 -0
- package/dist/src/types/flow.js +1 -0
- package/dist/tsconfig.app.tsbuildinfo +1 -0
- package/dist/tsconfig.node.tsbuildinfo +1 -0
- package/package.json +51 -55
- package/dist/motia-plugin/__tests__/generator.test.ts +0 -129
- package/dist/motia-plugin/__tests__/resolver.test.ts +0 -82
- package/dist/motia-plugin/__tests__/validator.test.ts +0 -71
- package/dist/motia-plugin/hmr.ts +0 -123
- package/dist/motia-plugin/index.ts +0 -183
- package/dist/motia-plugin/types.ts +0 -198
- package/dist/motia-plugin/validator.ts +0 -197
- package/dist/src/App.tsx +0 -41
- package/dist/src/components/NotFoundPage.tsx +0 -11
- package/dist/src/components/bottom-panel.tsx +0 -39
- package/dist/src/components/flow/base-edge.tsx +0 -61
- package/dist/src/components/flow/flow-loader.tsx +0 -3
- package/dist/src/components/flow/flow-page.tsx +0 -75
- package/dist/src/components/flow/flow-tab-menu-item.tsx +0 -50
- package/dist/src/components/flow/flow-view.tsx +0 -66
- package/dist/src/components/flow/hooks/use-get-flow-state.tsx +0 -171
- package/dist/src/components/flow/hooks/use-save-workflow-config.ts +0 -25
- package/dist/src/components/flow/node-organizer.tsx +0 -103
- package/dist/src/components/flow/nodes/api-flow-node.tsx +0 -6
- package/dist/src/components/flow/nodes/cron-flow-node.tsx +0 -6
- package/dist/src/components/flow/nodes/event-flow-node.tsx +0 -6
- package/dist/src/components/flow/nodes/noop-flow-node.tsx +0 -6
- package/dist/src/components/header/deploy-button.tsx +0 -110
- package/dist/src/components/header/header.tsx +0 -39
- package/dist/src/components/root-motia.tsx +0 -10
- package/dist/src/components/top-panel.tsx +0 -40
- package/dist/src/components/tutorial/engine/tutorial-engine.ts +0 -26
- package/dist/src/components/tutorial/engine/tutorial-types.ts +0 -26
- package/dist/src/components/tutorial/engine/workbench-xpath.ts +0 -53
- package/dist/src/components/tutorial/hooks/tutorial-utils.ts +0 -26
- package/dist/src/components/tutorial/hooks/use-tutorial-engine.ts +0 -213
- package/dist/src/components/tutorial/hooks/use-tutorial.ts +0 -14
- package/dist/src/components/tutorial/tutorial-button.tsx +0 -46
- package/dist/src/components/tutorial/tutorial-step.tsx +0 -82
- package/dist/src/components/tutorial/tutorial.tsx +0 -59
- package/dist/src/components/ui/json-editor.tsx +0 -68
- package/dist/src/components/ui/table.tsx +0 -75
- package/dist/src/components/ui/theme-toggle.tsx +0 -54
- package/dist/src/components/ui/tooltip.tsx +0 -26
- package/dist/src/hooks/use-debounced.ts +0 -22
- package/dist/src/hooks/use-fetch-flows.ts +0 -33
- package/dist/src/hooks/use-mobile.ts +0 -19
- package/dist/src/hooks/use-update-handle-positions.ts +0 -42
- package/dist/src/lib/__tests__/utils.test.ts +0 -110
- package/dist/src/lib/motia-analytics.ts +0 -140
- package/dist/src/lib/plugins.tsx +0 -132
- package/dist/src/lib/utils.ts +0 -37
- package/dist/src/main.tsx +0 -30
- package/dist/src/project-view-mode.tsx +0 -32
- package/dist/src/publicComponents/api-node.tsx +0 -26
- package/dist/src/publicComponents/base-node/base-handle.tsx +0 -50
- package/dist/src/publicComponents/base-node/base-node.tsx +0 -114
- package/dist/src/publicComponents/base-node/code-display.tsx +0 -119
- package/dist/src/publicComponents/base-node/emits.tsx +0 -17
- package/dist/src/publicComponents/base-node/feature-card.tsx +0 -32
- package/dist/src/publicComponents/base-node/language-indicator.tsx +0 -131
- package/dist/src/publicComponents/base-node/node-header.tsx +0 -49
- package/dist/src/publicComponents/base-node/node-sidebar.tsx +0 -41
- package/dist/src/publicComponents/base-node/subscribe.tsx +0 -13
- package/dist/src/publicComponents/cron-node.tsx +0 -24
- package/dist/src/publicComponents/event-node.tsx +0 -20
- package/dist/src/publicComponents/node-props.tsx +0 -15
- package/dist/src/publicComponents/noop-node.tsx +0 -19
- package/dist/src/setupTests.ts +0 -1
- package/dist/src/stores/use-app-tabs-store.ts +0 -49
- package/dist/src/stores/use-flow-store.ts +0 -31
- package/dist/src/stores/use-global-store.ts +0 -24
- package/dist/src/stores/use-motia-config-store.ts +0 -36
- package/dist/src/stores/use-tabs-store.ts +0 -34
- package/dist/src/system-view-mode.tsx +0 -28
- package/dist/src/types/endpoint.ts +0 -12
- package/dist/src/types/file.ts +0 -7
- package/dist/src/types/flow.ts +0 -103
- package/eslint.config.cjs +0 -22
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Configuration for a single workbench plugin.
|
|
3
|
-
* This interface defines how plugins are registered and configured in the Motia workbench.
|
|
4
|
-
*/
|
|
5
|
-
export interface WorkbenchPlugin {
|
|
6
|
-
/**
|
|
7
|
-
* The package name or local path to the plugin.
|
|
8
|
-
* - For npm packages: use the package name (e.g., '@my-org/my-plugin')
|
|
9
|
-
* - For local plugins: use the tilde prefix (e.g., '~/plugins/my-plugin')
|
|
10
|
-
*/
|
|
11
|
-
packageName: string
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Optional named export to use from the plugin package.
|
|
15
|
-
* If not specified, the default export will be used.
|
|
16
|
-
* Can be overridden by the plugin's own config.
|
|
17
|
-
*/
|
|
18
|
-
componentName?: string
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Position where the plugin tab should appear in the workbench.
|
|
22
|
-
* - 'top': Display in the top tab bar
|
|
23
|
-
* - 'bottom': Display in the bottom tab bar
|
|
24
|
-
* @default 'top'
|
|
25
|
-
*/
|
|
26
|
-
position?: 'top' | 'bottom'
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Display label for the plugin tab.
|
|
30
|
-
* Can be overridden by the plugin's own config.
|
|
31
|
-
*/
|
|
32
|
-
label?: string
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Icon name from lucide-react to display next to the label.
|
|
36
|
-
* Can be overridden by the plugin's own config.
|
|
37
|
-
* @default 'toy-brick'
|
|
38
|
-
*/
|
|
39
|
-
labelIcon?: string
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Array of CSS package imports to inject into the workbench.
|
|
43
|
-
* These will be added to the main index.css file.
|
|
44
|
-
* Example: ['@my-org/my-plugin/styles.css']
|
|
45
|
-
*/
|
|
46
|
-
cssImports?: string[]
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Props to pass to the plugin component when it's rendered.
|
|
50
|
-
* Can be overridden by the plugin's own config.
|
|
51
|
-
*/
|
|
52
|
-
props?: Record<string, any>
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Result of validating a plugin configuration.
|
|
57
|
-
*/
|
|
58
|
-
export interface ValidationResult {
|
|
59
|
-
/**
|
|
60
|
-
* Whether the validation passed
|
|
61
|
-
*/
|
|
62
|
-
valid: boolean
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Array of error messages if validation failed
|
|
66
|
-
*/
|
|
67
|
-
errors: string[]
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Array of warning messages for non-critical issues
|
|
71
|
-
*/
|
|
72
|
-
warnings: string[]
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* The validated and normalized plugin configuration (if valid)
|
|
76
|
-
*/
|
|
77
|
-
plugin?: WorkbenchPlugin
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Context object passed to various plugin internals functions.
|
|
82
|
-
* Contains shared state and configuration.
|
|
83
|
-
*/
|
|
84
|
-
export interface PluginContext {
|
|
85
|
-
/**
|
|
86
|
-
* Array of plugin configurations
|
|
87
|
-
*/
|
|
88
|
-
plugins: WorkbenchPlugin[]
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Vite dev server instance (only available in dev mode)
|
|
92
|
-
*/
|
|
93
|
-
server?: any
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Package resolution result.
|
|
98
|
-
*/
|
|
99
|
-
export interface ResolvedPackage {
|
|
100
|
-
/**
|
|
101
|
-
* The original package name from the configuration
|
|
102
|
-
*/
|
|
103
|
-
packageName: string
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Resolved absolute path to the package
|
|
107
|
-
*/
|
|
108
|
-
resolvedPath: string
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Whether this is a local plugin (starts with ~/)
|
|
112
|
-
*/
|
|
113
|
-
isLocal: boolean
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Alias to use for imports
|
|
117
|
-
*/
|
|
118
|
-
alias: string
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Generated virtual module exports interface.
|
|
123
|
-
* This is what consumers will import from 'virtual:motia-plugins'.
|
|
124
|
-
*/
|
|
125
|
-
export interface VirtualModuleExports {
|
|
126
|
-
/**
|
|
127
|
-
* Array of processed plugin configurations ready to be registered
|
|
128
|
-
*/
|
|
129
|
-
plugins: ProcessedPlugin[]
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* A plugin configuration after processing and normalization.
|
|
134
|
-
* This is the format used by the workbench to register tabs.
|
|
135
|
-
*/
|
|
136
|
-
export interface ProcessedPlugin {
|
|
137
|
-
/**
|
|
138
|
-
* Display label for the plugin tab
|
|
139
|
-
*/
|
|
140
|
-
label: string
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Icon name from lucide-react
|
|
144
|
-
*/
|
|
145
|
-
labelIcon: string
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Position in the workbench ('top' or 'bottom')
|
|
149
|
-
*/
|
|
150
|
-
position: 'top' | 'bottom'
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Props to pass to the component
|
|
154
|
-
*/
|
|
155
|
-
props: Record<string, any>
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* The React component to render
|
|
159
|
-
*/
|
|
160
|
-
component: any
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Type guard to check if position is valid.
|
|
165
|
-
*/
|
|
166
|
-
export function isValidPosition(position: any): position is 'top' | 'bottom' {
|
|
167
|
-
return position === 'top' || position === 'bottom'
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Constants used throughout the plugin system.
|
|
172
|
-
*/
|
|
173
|
-
export const CONSTANTS = {
|
|
174
|
-
/**
|
|
175
|
-
* Virtual module ID for importing plugins
|
|
176
|
-
*/
|
|
177
|
-
VIRTUAL_MODULE_ID: 'virtual:motia-plugins',
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Resolved virtual module ID (with null byte prefix for Vite)
|
|
181
|
-
*/
|
|
182
|
-
RESOLVED_VIRTUAL_MODULE_ID: '\0virtual:motia-plugins',
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Log prefix for all plugin messages
|
|
186
|
-
*/
|
|
187
|
-
LOG_PREFIX: '[motia-plugins]',
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Default values for optional plugin fields
|
|
191
|
-
*/
|
|
192
|
-
DEFAULTS: {
|
|
193
|
-
POSITION: 'top' as const,
|
|
194
|
-
LABEL: 'Plugin label',
|
|
195
|
-
ICON: 'toy-brick',
|
|
196
|
-
PROPS: {},
|
|
197
|
-
},
|
|
198
|
-
} as const
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'fs'
|
|
2
|
-
import { z } from 'zod'
|
|
3
|
-
import type { ValidationResult, WorkbenchPlugin } from './types'
|
|
4
|
-
import { CONSTANTS, isValidPosition } from './types'
|
|
5
|
-
import { isLocalPlugin, resolveLocalPath } from './utils'
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Zod schema for WorkbenchPlugin configuration.
|
|
9
|
-
* Provides runtime type validation with detailed error messages.
|
|
10
|
-
*/
|
|
11
|
-
const WorkbenchPluginSchema = z.object({
|
|
12
|
-
packageName: z
|
|
13
|
-
.string()
|
|
14
|
-
.min(1, 'packageName is required and cannot be empty')
|
|
15
|
-
.refine((name) => name.startsWith('~/') || name.startsWith('@') || /^[a-z0-9-_]+$/i.test(name), {
|
|
16
|
-
message: 'packageName must be a valid npm package name or local path (starting with ~/)',
|
|
17
|
-
}),
|
|
18
|
-
|
|
19
|
-
componentName: z.string().optional(),
|
|
20
|
-
|
|
21
|
-
position: z
|
|
22
|
-
.enum(['top', 'bottom'])
|
|
23
|
-
.optional()
|
|
24
|
-
.refine((pos) => pos === undefined || isValidPosition(pos), {
|
|
25
|
-
message: 'position must be either "top" or "bottom"',
|
|
26
|
-
}),
|
|
27
|
-
|
|
28
|
-
label: z.string().optional(),
|
|
29
|
-
|
|
30
|
-
labelIcon: z.string().optional(),
|
|
31
|
-
|
|
32
|
-
cssImports: z.array(z.string()).optional(),
|
|
33
|
-
|
|
34
|
-
props: z.record(z.any(), z.any()).optional(),
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Validates a single plugin configuration.
|
|
39
|
-
*
|
|
40
|
-
* @param plugin - The plugin configuration to validate
|
|
41
|
-
* @param index - The index of the plugin in the array (for error messages)
|
|
42
|
-
* @returns A validation result with errors, warnings, and normalized plugin
|
|
43
|
-
*/
|
|
44
|
-
export function validatePluginConfig(plugin: any, index: number): ValidationResult {
|
|
45
|
-
const errors: string[] = []
|
|
46
|
-
const warnings: string[] = []
|
|
47
|
-
|
|
48
|
-
if (typeof plugin !== 'object' || plugin === null) {
|
|
49
|
-
return {
|
|
50
|
-
valid: false,
|
|
51
|
-
errors: [`Plugin at index ${index}: expected object, got ${typeof plugin}`],
|
|
52
|
-
warnings: [],
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
try {
|
|
57
|
-
const result = WorkbenchPluginSchema.safeParse(plugin)
|
|
58
|
-
|
|
59
|
-
if (!result.success) {
|
|
60
|
-
result.error.issues.forEach((err: z.core.$ZodIssue) => {
|
|
61
|
-
const path = err.path.join('.')
|
|
62
|
-
errors.push(`Plugin at index ${index}, field "${path}": ${err.message}`)
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
return { valid: false, errors, warnings }
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const validatedPlugin = result.data as WorkbenchPlugin
|
|
69
|
-
|
|
70
|
-
if (isLocalPlugin(validatedPlugin.packageName)) {
|
|
71
|
-
const resolvedPath = resolveLocalPath(validatedPlugin.packageName)
|
|
72
|
-
if (!existsSync(resolvedPath)) {
|
|
73
|
-
warnings.push(
|
|
74
|
-
`Plugin at index ${index}: local path "${validatedPlugin.packageName}" does not exist at "${resolvedPath}". ` +
|
|
75
|
-
`Make sure the path is correct relative to the project root.`,
|
|
76
|
-
)
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (!validatedPlugin.label) {
|
|
81
|
-
warnings.push(`Plugin at index ${index}: "label" not specified, will use default "${CONSTANTS.DEFAULTS.LABEL}"`)
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (!validatedPlugin.labelIcon) {
|
|
85
|
-
warnings.push(
|
|
86
|
-
`Plugin at index ${index}: "labelIcon" not specified, will use default "${CONSTANTS.DEFAULTS.ICON}"`,
|
|
87
|
-
)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (!validatedPlugin.position) {
|
|
91
|
-
warnings.push(
|
|
92
|
-
`Plugin at index ${index}: "position" not specified, will use default "${CONSTANTS.DEFAULTS.POSITION}"`,
|
|
93
|
-
)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (validatedPlugin.props && Object.keys(validatedPlugin.props).length === 0) {
|
|
97
|
-
warnings.push(`Plugin at index ${index}: "props" is an empty object`)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (validatedPlugin.cssImports) {
|
|
101
|
-
if (validatedPlugin.cssImports.length === 0) {
|
|
102
|
-
warnings.push(`Plugin at index ${index}: "cssImports" is an empty array`)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
validatedPlugin.cssImports.forEach((cssImport, cssIndex) => {
|
|
106
|
-
if (!cssImport || cssImport.trim() === '') {
|
|
107
|
-
warnings.push(`Plugin at index ${index}: cssImport at index ${cssIndex} is empty or whitespace`)
|
|
108
|
-
}
|
|
109
|
-
})
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return {
|
|
113
|
-
valid: true,
|
|
114
|
-
errors: [],
|
|
115
|
-
warnings,
|
|
116
|
-
plugin: validatedPlugin,
|
|
117
|
-
}
|
|
118
|
-
} catch (error) {
|
|
119
|
-
return {
|
|
120
|
-
valid: false,
|
|
121
|
-
errors: [`Plugin at index ${index}: unexpected validation error: ${error}`],
|
|
122
|
-
warnings: [],
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Validates an array of plugin configurations.
|
|
129
|
-
*
|
|
130
|
-
* @param plugins - Array of plugin configurations to validate
|
|
131
|
-
* @param options - Validation options
|
|
132
|
-
* @returns Combined validation result for all plugins
|
|
133
|
-
*/
|
|
134
|
-
export function validatePlugins(plugins: any[], options: { failFast?: boolean } = {}): ValidationResult {
|
|
135
|
-
const allErrors: string[] = []
|
|
136
|
-
const allWarnings: string[] = []
|
|
137
|
-
const validatedPlugins: WorkbenchPlugin[] = []
|
|
138
|
-
|
|
139
|
-
if (!Array.isArray(plugins)) {
|
|
140
|
-
return {
|
|
141
|
-
valid: false,
|
|
142
|
-
errors: [`Expected plugins to be an array, got ${typeof plugins}`],
|
|
143
|
-
warnings: [],
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (plugins.length === 0) {
|
|
148
|
-
console.warn('[motia-plugins] No plugins provided to validate')
|
|
149
|
-
return {
|
|
150
|
-
valid: true,
|
|
151
|
-
errors: [],
|
|
152
|
-
warnings: ['No plugins configured'],
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
for (let i = 0; i < plugins.length; i++) {
|
|
157
|
-
const result = validatePluginConfig(plugins[i], i)
|
|
158
|
-
|
|
159
|
-
allErrors.push(...result.errors)
|
|
160
|
-
allWarnings.push(...result.warnings)
|
|
161
|
-
|
|
162
|
-
if (result.valid && result.plugin) {
|
|
163
|
-
validatedPlugins.push(result.plugin)
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if (options.failFast && result.errors.length > 0) {
|
|
167
|
-
break
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const packageNames = validatedPlugins.map((p) => p.packageName)
|
|
172
|
-
const duplicates = packageNames.filter((name, index) => packageNames.indexOf(name) !== index)
|
|
173
|
-
|
|
174
|
-
if (duplicates.length > 0) {
|
|
175
|
-
const uniqueDuplicates = [...new Set(duplicates)]
|
|
176
|
-
uniqueDuplicates.forEach((dup) => {
|
|
177
|
-
allWarnings.push(`Duplicate package name found: "${dup}". This may cause conflicts.`)
|
|
178
|
-
})
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const valid = allErrors.length === 0
|
|
182
|
-
|
|
183
|
-
if (valid) {
|
|
184
|
-
console.log(`[motia-plugins] ✓ Validated ${validatedPlugins.length} plugin(s) successfully`)
|
|
185
|
-
if (allWarnings.length > 0) {
|
|
186
|
-
console.warn(`[motia-plugins] Found ${allWarnings.length} warning(s)`)
|
|
187
|
-
}
|
|
188
|
-
} else {
|
|
189
|
-
console.error(`[motia-plugins] ✗ Validation failed with ${allErrors.length} error(s)`)
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
return {
|
|
193
|
-
valid,
|
|
194
|
-
errors: allErrors,
|
|
195
|
-
warnings: allWarnings,
|
|
196
|
-
}
|
|
197
|
-
}
|
package/dist/src/App.tsx
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { type FC, memo, useEffect, useMemo } from 'react'
|
|
2
|
-
import { FlowPage } from './components/flow/flow-page'
|
|
3
|
-
import { FlowTabMenuItem } from './components/flow/flow-tab-menu-item'
|
|
4
|
-
import { registerPluginTabs } from './lib/plugins'
|
|
5
|
-
import { getViewModeFromURL, type ViewMode } from './lib/utils'
|
|
6
|
-
import { ProjectViewMode } from './project-view-mode'
|
|
7
|
-
import { type AppTab, TabLocation, useAppTabsStore } from './stores/use-app-tabs-store'
|
|
8
|
-
import { SystemViewMode } from './system-view-mode'
|
|
9
|
-
|
|
10
|
-
const TAB_IDS = {
|
|
11
|
-
FLOW: 'flow',
|
|
12
|
-
LOGS: 'logs',
|
|
13
|
-
} as const
|
|
14
|
-
|
|
15
|
-
const topTabs: AppTab[] = [
|
|
16
|
-
{
|
|
17
|
-
id: TAB_IDS.FLOW,
|
|
18
|
-
tabLabel: FlowTabMenuItem,
|
|
19
|
-
content: FlowPage,
|
|
20
|
-
},
|
|
21
|
-
]
|
|
22
|
-
|
|
23
|
-
export const App: FC = memo(() => {
|
|
24
|
-
const setTabs = useAppTabsStore((state) => state.setTabs)
|
|
25
|
-
const addTab = useAppTabsStore((state) => state.addTab)
|
|
26
|
-
|
|
27
|
-
useEffect(() => {
|
|
28
|
-
const timeout = setTimeout(() => {
|
|
29
|
-
setTabs(TabLocation.TOP, topTabs)
|
|
30
|
-
registerPluginTabs(addTab)
|
|
31
|
-
}, 10)
|
|
32
|
-
return () => clearTimeout(timeout)
|
|
33
|
-
}, [setTabs, addTab])
|
|
34
|
-
|
|
35
|
-
const viewMode = useMemo<ViewMode>(getViewModeFromURL, [])
|
|
36
|
-
|
|
37
|
-
const ViewComponent = viewMode === 'project' ? ProjectViewMode : SystemViewMode
|
|
38
|
-
|
|
39
|
-
return <ViewComponent />
|
|
40
|
-
})
|
|
41
|
-
App.displayName = 'App'
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { Header } from './header/header'
|
|
2
|
-
|
|
3
|
-
export const NotFoundPage = () => (
|
|
4
|
-
<div className="grid grid-rows-[auto_1fr] h-screen bg-background text-foreground">
|
|
5
|
-
<Header />
|
|
6
|
-
<div className="flex flex-col items-center justify-center">
|
|
7
|
-
<h1 className="text-4xl font-bold mb-4">404 – Page Not Found</h1>
|
|
8
|
-
<p className="text-lg opacity-80 mb-6">This route doesn’t exist.</p>
|
|
9
|
-
</div>
|
|
10
|
-
</div>
|
|
11
|
-
)
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { CollapsiblePanel, TabsContent, TabsList, TabsTrigger } from '@motiadev/ui'
|
|
2
|
-
import { memo } from 'react'
|
|
3
|
-
import { useShallow } from 'zustand/react/shallow'
|
|
4
|
-
import { type AppTabsState, TabLocation, useAppTabsStore } from '../stores/use-app-tabs-store'
|
|
5
|
-
import { useTabsStore } from '../stores/use-tabs-store'
|
|
6
|
-
|
|
7
|
-
const bottomTabsSelector = (state: AppTabsState) => state.tabs[TabLocation.BOTTOM]
|
|
8
|
-
const bottomPanelId = 'bottom-panel'
|
|
9
|
-
|
|
10
|
-
export const BottomPanel = memo(() => {
|
|
11
|
-
const defaultTab = useTabsStore((state) => state.tab.bottom)
|
|
12
|
-
const setBottomTab = useTabsStore((state) => state.setBottomTab)
|
|
13
|
-
const tabs = useAppTabsStore(useShallow(bottomTabsSelector))
|
|
14
|
-
|
|
15
|
-
return (
|
|
16
|
-
<CollapsiblePanel
|
|
17
|
-
id={bottomPanelId}
|
|
18
|
-
variant={'tabs'}
|
|
19
|
-
defaultTab={defaultTab}
|
|
20
|
-
onTabChange={setBottomTab}
|
|
21
|
-
header={
|
|
22
|
-
<TabsList>
|
|
23
|
-
{tabs.map(({ id, tabLabel: Label }) => (
|
|
24
|
-
<TabsTrigger key={id} value={id} data-testid={`${id.toLowerCase()}-link`} className="cursor-pointer">
|
|
25
|
-
<Label />
|
|
26
|
-
</TabsTrigger>
|
|
27
|
-
))}
|
|
28
|
-
</TabsList>
|
|
29
|
-
}
|
|
30
|
-
>
|
|
31
|
-
{tabs.map(({ id, content: Element }) => (
|
|
32
|
-
<TabsContent key={id} value={id} className="h-full">
|
|
33
|
-
<Element />
|
|
34
|
-
</TabsContent>
|
|
35
|
-
))}
|
|
36
|
-
</CollapsiblePanel>
|
|
37
|
-
)
|
|
38
|
-
})
|
|
39
|
-
BottomPanel.displayName = 'BottomPanel'
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { cn, useThemeStore } from '@motiadev/ui'
|
|
2
|
-
import { BaseEdge as BaseReactFlowEdge, EdgeLabelRenderer, type EdgeProps, getSmoothStepPath } from '@xyflow/react'
|
|
3
|
-
import { cva } from 'class-variance-authority'
|
|
4
|
-
import type React from 'react'
|
|
5
|
-
|
|
6
|
-
const labelVariants = cva('absolute pointer-events-all text-cs border p-1 px-2', {
|
|
7
|
-
variants: {
|
|
8
|
-
color: {
|
|
9
|
-
default: 'border-[#b3b3b3] bg-[#060014] text-gray-100 font-semibold border-solid rounded-full',
|
|
10
|
-
conditional: 'bg-amber-300 border-amber-950 text-amber-950 border-solid font-semibold italic rounded-lg',
|
|
11
|
-
},
|
|
12
|
-
},
|
|
13
|
-
defaultVariants: {
|
|
14
|
-
color: 'default',
|
|
15
|
-
},
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
export const BaseEdge: React.FC<EdgeProps> = (props: EdgeProps) => {
|
|
19
|
-
const theme = useThemeStore((state) => state.theme)
|
|
20
|
-
const { sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, data } = props
|
|
21
|
-
const label = data?.label as string | undefined
|
|
22
|
-
const labelVariant = data?.labelVariant as 'default' | 'conditional' | null | undefined
|
|
23
|
-
const virtualColor = theme === 'dark' ? 'rgb(225, 225, 225)' : 'rgb(85, 85, 85)'
|
|
24
|
-
|
|
25
|
-
const [edgePath, labelX, labelY] = getSmoothStepPath({
|
|
26
|
-
sourceX,
|
|
27
|
-
sourceY,
|
|
28
|
-
targetX,
|
|
29
|
-
targetY,
|
|
30
|
-
sourcePosition,
|
|
31
|
-
targetPosition,
|
|
32
|
-
borderRadius: 20,
|
|
33
|
-
offset: 10,
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
return (
|
|
37
|
-
<>
|
|
38
|
-
<BaseReactFlowEdge
|
|
39
|
-
path={edgePath}
|
|
40
|
-
style={{
|
|
41
|
-
stroke: data?.variant === 'virtual' ? virtualColor : '#0094FF',
|
|
42
|
-
strokeWidth: 2,
|
|
43
|
-
shapeRendering: 'geometricPrecision',
|
|
44
|
-
fill: 'none',
|
|
45
|
-
mixBlendMode: 'screen',
|
|
46
|
-
}}
|
|
47
|
-
className="edge-animated"
|
|
48
|
-
/>
|
|
49
|
-
{label && (
|
|
50
|
-
<EdgeLabelRenderer>
|
|
51
|
-
<div
|
|
52
|
-
className={cn(labelVariants({ color: labelVariant }))}
|
|
53
|
-
style={{ transform: `translateX(-50%) translateY(-50%) translate(${labelX}px, ${labelY}px)` }}
|
|
54
|
-
>
|
|
55
|
-
<div className="text-xs font-mono">{label}</div>
|
|
56
|
-
</div>
|
|
57
|
-
</EdgeLabelRenderer>
|
|
58
|
-
)}
|
|
59
|
-
</>
|
|
60
|
-
)
|
|
61
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { useStreamItem } from '@motiadev/stream-client-react'
|
|
2
|
-
import { Button, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from '@motiadev/ui'
|
|
3
|
-
import { ReactFlowProvider } from '@xyflow/react'
|
|
4
|
-
import { ExternalLink, Workflow } from 'lucide-react'
|
|
5
|
-
import { memo, useMemo } from 'react'
|
|
6
|
-
import { useShallow } from 'zustand/react/shallow'
|
|
7
|
-
import { motiaAnalytics } from '../../lib/motia-analytics'
|
|
8
|
-
import { useFlowStore } from '../../stores/use-flow-store'
|
|
9
|
-
import type { FlowConfigResponse, FlowResponse } from '../../types/flow'
|
|
10
|
-
import { FlowView } from './flow-view'
|
|
11
|
-
|
|
12
|
-
export const FlowPage = memo(() => {
|
|
13
|
-
const selectedFlowId = useFlowStore((state) => state.selectedFlowId)
|
|
14
|
-
const flows = useFlowStore(useShallow((state) => Object.values(state.flows)))
|
|
15
|
-
|
|
16
|
-
const streamItemArgs = useMemo(
|
|
17
|
-
() => ({ streamName: '__motia.flows', groupId: 'default', id: selectedFlowId ?? '' }),
|
|
18
|
-
[selectedFlowId],
|
|
19
|
-
)
|
|
20
|
-
const { data: flow } = useStreamItem<FlowResponse>(streamItemArgs)
|
|
21
|
-
|
|
22
|
-
const streamItemArgsConfig = useMemo(
|
|
23
|
-
() => ({ streamName: '__motia.flowsConfig', groupId: 'default', id: selectedFlowId ?? '' }),
|
|
24
|
-
[selectedFlowId],
|
|
25
|
-
)
|
|
26
|
-
const { data: flowConfig } = useStreamItem<FlowConfigResponse>(streamItemArgsConfig)
|
|
27
|
-
|
|
28
|
-
if (flows.length === 0 || flow?.error) {
|
|
29
|
-
return (
|
|
30
|
-
<div className="flex w-full h-full bg-background">
|
|
31
|
-
<Empty>
|
|
32
|
-
<EmptyHeader>
|
|
33
|
-
<EmptyMedia variant="icon">
|
|
34
|
-
<Workflow />
|
|
35
|
-
</EmptyMedia>
|
|
36
|
-
{flow?.error ? (
|
|
37
|
-
<>
|
|
38
|
-
<EmptyTitle>Error loading flow</EmptyTitle>
|
|
39
|
-
<EmptyDescription>{flow.error}</EmptyDescription>
|
|
40
|
-
</>
|
|
41
|
-
) : (
|
|
42
|
-
<>
|
|
43
|
-
<EmptyTitle>No flows registered</EmptyTitle>
|
|
44
|
-
<EmptyDescription>
|
|
45
|
-
You haven't registered any flows yet. Get started by registering your first flow.
|
|
46
|
-
</EmptyDescription>
|
|
47
|
-
</>
|
|
48
|
-
)}
|
|
49
|
-
</EmptyHeader>
|
|
50
|
-
<EmptyContent>
|
|
51
|
-
<Button variant="link" asChild size="sm">
|
|
52
|
-
<a
|
|
53
|
-
href="https://www.motia.dev/docs/development-guide/flows"
|
|
54
|
-
target="_blank"
|
|
55
|
-
rel="noopener noreferrer"
|
|
56
|
-
onClick={() => motiaAnalytics.track('flows_docs_link_clicked')}
|
|
57
|
-
>
|
|
58
|
-
Learn more <ExternalLink />
|
|
59
|
-
</a>
|
|
60
|
-
</Button>
|
|
61
|
-
</EmptyContent>
|
|
62
|
-
</Empty>
|
|
63
|
-
</div>
|
|
64
|
-
)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (!flow) return null
|
|
68
|
-
|
|
69
|
-
return (
|
|
70
|
-
<ReactFlowProvider>
|
|
71
|
-
<FlowView flow={flow} flowConfig={flowConfig!} />
|
|
72
|
-
</ReactFlowProvider>
|
|
73
|
-
)
|
|
74
|
-
})
|
|
75
|
-
FlowPage.displayName = 'FlowPage'
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@motiadev/ui'
|
|
2
|
-
import { ChevronsUpDown, Workflow } from 'lucide-react'
|
|
3
|
-
import { useShallow } from 'zustand/react/shallow'
|
|
4
|
-
import { useFetchFlows } from '../../hooks/use-fetch-flows'
|
|
5
|
-
import { motiaAnalytics } from '../../lib/motia-analytics'
|
|
6
|
-
import { useFlowStore } from '../../stores/use-flow-store'
|
|
7
|
-
|
|
8
|
-
export const FlowTabMenuItem = () => {
|
|
9
|
-
useFetchFlows()
|
|
10
|
-
|
|
11
|
-
const selectFlowId = useFlowStore((state) => state.selectFlowId)
|
|
12
|
-
const flows = useFlowStore(useShallow((state) => Object.values(state.flows)))
|
|
13
|
-
const selectedFlowId = useFlowStore((state) => state.selectedFlowId)
|
|
14
|
-
|
|
15
|
-
const handleFlowSelect = (flowId: string) => {
|
|
16
|
-
selectFlowId(flowId)
|
|
17
|
-
motiaAnalytics.track('flow_selected', { flow: flowId })
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return (
|
|
21
|
-
<div className="flex flex-row justify-center items-center gap-2 cursor-pointer">
|
|
22
|
-
<Workflow />
|
|
23
|
-
{flows.length > 0 && selectedFlowId ? selectedFlowId : 'Flows'}
|
|
24
|
-
{flows.length > 0 && (
|
|
25
|
-
<DropdownMenu>
|
|
26
|
-
<DropdownMenuTrigger asChild>
|
|
27
|
-
<div
|
|
28
|
-
className="flex flex-row justify-center items-center gap-2 cursor-pointer"
|
|
29
|
-
data-testid="flows-dropdown-trigger"
|
|
30
|
-
>
|
|
31
|
-
<ChevronsUpDown className="size-4" />
|
|
32
|
-
</div>
|
|
33
|
-
</DropdownMenuTrigger>
|
|
34
|
-
<DropdownMenuContent className="bg-background text-foreground flows-dropdown">
|
|
35
|
-
{flows.map((item) => (
|
|
36
|
-
<DropdownMenuItem
|
|
37
|
-
data-testid={`dropdown-${item}`}
|
|
38
|
-
key={`dropdown-${item}`}
|
|
39
|
-
className="cursor-pointer gap-2 flow-link"
|
|
40
|
-
onSelect={() => handleFlowSelect(item)}
|
|
41
|
-
>
|
|
42
|
-
{item}
|
|
43
|
-
</DropdownMenuItem>
|
|
44
|
-
))}
|
|
45
|
-
</DropdownMenuContent>
|
|
46
|
-
</DropdownMenu>
|
|
47
|
-
)}
|
|
48
|
-
</div>
|
|
49
|
-
)
|
|
50
|
-
}
|