@motiadev/workbench 0.13.2-beta.164-110989 → 0.13.2-beta.164-704005

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.
Files changed (237) hide show
  1. package/dist/index.d.ts +10 -189
  2. package/dist/index.html +1 -1
  3. package/dist/index.js +7 -1065
  4. package/dist/middleware.d.ts +8 -66
  5. package/dist/middleware.js +86 -694
  6. package/dist/motia-plugin/__tests__/generator.test.d.ts +1 -0
  7. package/dist/motia-plugin/__tests__/generator.test.js +97 -0
  8. package/dist/motia-plugin/__tests__/resolver.test.d.ts +1 -0
  9. package/dist/motia-plugin/__tests__/resolver.test.js +64 -0
  10. package/dist/motia-plugin/__tests__/validator.test.d.ts +1 -0
  11. package/dist/motia-plugin/__tests__/validator.test.js +59 -0
  12. package/dist/motia-plugin/generator.d.ts +78 -0
  13. package/dist/motia-plugin/{generator.ts → generator.js} +35 -37
  14. package/dist/motia-plugin/hmr.d.ts +22 -0
  15. package/dist/motia-plugin/hmr.js +100 -0
  16. package/dist/motia-plugin/index.d.ts +3 -0
  17. package/dist/motia-plugin/index.js +153 -0
  18. package/dist/motia-plugin/{resolver.ts → resolver.d.ts} +5 -38
  19. package/dist/motia-plugin/resolver.js +92 -0
  20. package/dist/motia-plugin/types.d.ts +169 -0
  21. package/dist/motia-plugin/types.js +36 -0
  22. package/dist/motia-plugin/{utils.ts → utils.d.ts} +4 -17
  23. package/dist/motia-plugin/utils.js +75 -0
  24. package/dist/motia-plugin/validator.d.ts +19 -0
  25. package/dist/motia-plugin/validator.js +163 -0
  26. package/dist/src/App.d.ts +2 -0
  27. package/dist/src/App.js +35 -0
  28. package/dist/src/components/NotFoundPage.d.ts +1 -0
  29. package/dist/src/components/NotFoundPage.js +3 -0
  30. package/dist/src/components/bottom-panel.d.ts +1 -0
  31. package/dist/src/components/bottom-panel.js +15 -0
  32. package/dist/src/components/flow/base-edge.d.ts +3 -0
  33. package/dist/src/components/flow/base-edge.js +39 -0
  34. package/dist/src/components/flow/flow-loader.d.ts +1 -0
  35. package/dist/src/components/flow/flow-loader.js +4 -0
  36. package/dist/src/components/flow/flow-page.d.ts +1 -0
  37. package/dist/src/components/flow/flow-page.js +25 -0
  38. package/dist/src/components/flow/flow-tab-menu-item.d.ts +1 -0
  39. package/dist/src/components/flow/flow-tab-menu-item.js +18 -0
  40. package/dist/src/components/flow/flow-view.d.ts +12 -0
  41. package/dist/src/components/flow/flow-view.js +22 -0
  42. package/dist/src/components/flow/hooks/use-get-flow-state.d.ts +10 -0
  43. package/dist/src/components/flow/hooks/use-get-flow-state.js +133 -0
  44. package/dist/src/components/flow/hooks/use-save-workflow-config.d.ts +2 -0
  45. package/dist/src/components/flow/hooks/use-save-workflow-config.js +22 -0
  46. package/dist/src/components/flow/node-organizer.d.ts +10 -0
  47. package/dist/src/components/flow/node-organizer.js +82 -0
  48. package/dist/src/components/flow/nodes/api-flow-node.d.ts +2 -0
  49. package/dist/src/components/flow/nodes/api-flow-node.js +5 -0
  50. package/dist/src/components/flow/nodes/cron-flow-node.d.ts +2 -0
  51. package/dist/src/components/flow/nodes/cron-flow-node.js +5 -0
  52. package/dist/src/components/flow/nodes/event-flow-node.d.ts +2 -0
  53. package/dist/src/components/flow/nodes/event-flow-node.js +5 -0
  54. package/dist/src/components/flow/nodes/noop-flow-node.d.ts +2 -0
  55. package/dist/src/components/flow/nodes/noop-flow-node.js +5 -0
  56. package/dist/src/components/header/deploy-button.d.ts +1 -0
  57. package/dist/src/components/header/deploy-button.js +28 -0
  58. package/dist/src/components/header/header.d.ts +2 -0
  59. package/dist/src/components/header/header.js +23 -0
  60. package/dist/src/components/root-motia.d.ts +2 -0
  61. package/dist/src/components/root-motia.js +7 -0
  62. package/dist/src/components/top-panel.d.ts +1 -0
  63. package/dist/src/components/top-panel.js +15 -0
  64. package/dist/src/components/tutorial/engine/tutorial-engine.d.ts +12 -0
  65. package/dist/src/components/tutorial/engine/tutorial-engine.js +36 -0
  66. package/dist/src/components/tutorial/engine/tutorial-types.d.ts +22 -0
  67. package/dist/src/components/tutorial/engine/tutorial-types.js +1 -0
  68. package/dist/src/components/tutorial/engine/workbench-xpath.d.ts +45 -0
  69. package/dist/src/components/tutorial/engine/workbench-xpath.js +45 -0
  70. package/dist/src/components/tutorial/hooks/tutorial-utils.d.ts +1 -0
  71. package/dist/src/components/tutorial/hooks/tutorial-utils.js +17 -0
  72. package/dist/src/components/tutorial/hooks/use-tutorial-engine.d.ts +15 -0
  73. package/dist/src/components/tutorial/hooks/use-tutorial-engine.js +183 -0
  74. package/dist/src/components/tutorial/hooks/use-tutorial.d.ts +5 -0
  75. package/dist/src/components/tutorial/hooks/use-tutorial.js +10 -0
  76. package/dist/src/components/tutorial/tutorial-button.d.ts +2 -0
  77. package/dist/src/components/tutorial/tutorial-button.js +21 -0
  78. package/dist/src/components/tutorial/tutorial-step.d.ts +14 -0
  79. package/dist/src/components/tutorial/tutorial-step.js +19 -0
  80. package/dist/src/components/tutorial/tutorial.css +2 -2
  81. package/dist/src/components/tutorial/tutorial.d.ts +2 -0
  82. package/dist/src/components/tutorial/tutorial.js +32 -0
  83. package/dist/src/components/ui/json-editor.d.ts +12 -0
  84. package/dist/src/components/ui/json-editor.js +35 -0
  85. package/dist/src/components/ui/table.d.ts +10 -0
  86. package/dist/src/components/ui/table.js +20 -0
  87. package/dist/src/components/ui/theme-toggle.d.ts +2 -0
  88. package/dist/src/components/ui/theme-toggle.js +19 -0
  89. package/dist/src/components/ui/tooltip.d.ts +6 -0
  90. package/dist/src/components/ui/tooltip.js +3 -0
  91. package/dist/src/hooks/use-debounced.d.ts +1 -0
  92. package/dist/src/hooks/use-debounced.js +18 -0
  93. package/dist/src/hooks/use-fetch-flows.d.ts +1 -0
  94. package/dist/src/hooks/use-fetch-flows.js +26 -0
  95. package/dist/src/hooks/use-mobile.d.ts +1 -0
  96. package/dist/src/hooks/use-mobile.js +15 -0
  97. package/dist/src/hooks/use-update-handle-positions.d.ts +10 -0
  98. package/dist/src/hooks/use-update-handle-positions.js +35 -0
  99. package/dist/src/index.css +5 -5
  100. package/dist/src/lib/__tests__/utils.test.d.ts +1 -0
  101. package/dist/src/lib/__tests__/utils.test.js +94 -0
  102. package/dist/src/lib/motia-analytics.d.ts +38 -0
  103. package/dist/src/lib/motia-analytics.js +132 -0
  104. package/dist/src/lib/plugins.d.ts +2 -0
  105. package/dist/src/lib/plugins.js +105 -0
  106. package/dist/src/lib/utils.d.ts +7 -0
  107. package/dist/src/lib/utils.js +34 -0
  108. package/dist/src/main.d.ts +2 -0
  109. package/dist/src/main.js +17 -0
  110. package/dist/src/project-view-mode.d.ts +1 -0
  111. package/dist/src/project-view-mode.js +20 -0
  112. package/dist/src/publicComponents/api-node.d.ts +5 -0
  113. package/dist/src/publicComponents/api-node.js +5 -0
  114. package/dist/src/publicComponents/base-node/base-handle.d.ts +9 -0
  115. package/dist/src/publicComponents/base-node/base-handle.js +8 -0
  116. package/dist/src/publicComponents/base-node/base-node.d.ts +15 -0
  117. package/dist/src/publicComponents/base-node/base-node.js +30 -0
  118. package/dist/src/publicComponents/base-node/code-display.d.ts +9 -0
  119. package/dist/src/publicComponents/base-node/code-display.js +64 -0
  120. package/dist/src/publicComponents/base-node/emits.d.ts +5 -0
  121. package/dist/src/publicComponents/base-node/emits.js +5 -0
  122. package/dist/src/publicComponents/base-node/feature-card.d.ts +10 -0
  123. package/dist/src/publicComponents/base-node/feature-card.js +5 -0
  124. package/dist/src/publicComponents/base-node/language-indicator.d.ts +10 -0
  125. package/dist/src/publicComponents/base-node/language-indicator.js +29 -0
  126. package/dist/src/publicComponents/base-node/node-header.d.ts +13 -0
  127. package/dist/src/publicComponents/base-node/node-header.js +30 -0
  128. package/dist/src/publicComponents/base-node/node-sidebar.d.ts +14 -0
  129. package/dist/src/publicComponents/base-node/node-sidebar.js +9 -0
  130. package/dist/src/publicComponents/base-node/subscribe.d.ts +4 -0
  131. package/dist/src/publicComponents/base-node/subscribe.js +4 -0
  132. package/dist/src/publicComponents/cron-node.d.ts +4 -0
  133. package/dist/src/publicComponents/cron-node.js +6 -0
  134. package/dist/src/publicComponents/event-node.d.ts +4 -0
  135. package/dist/src/publicComponents/event-node.js +5 -0
  136. package/dist/src/publicComponents/node-props.d.ts +21 -0
  137. package/dist/src/publicComponents/node-props.js +1 -0
  138. package/dist/src/publicComponents/noop-node.d.ts +4 -0
  139. package/dist/src/publicComponents/noop-node.js +5 -0
  140. package/dist/src/setupTests.d.ts +1 -0
  141. package/dist/src/setupTests.js +1 -0
  142. package/dist/src/stores/use-app-tabs-store.d.ts +16 -0
  143. package/dist/src/stores/use-app-tabs-store.js +31 -0
  144. package/dist/src/stores/use-flow-store.d.ts +21 -0
  145. package/dist/src/stores/use-flow-store.js +16 -0
  146. package/dist/src/stores/use-global-store.d.ts +18 -0
  147. package/dist/src/stores/use-global-store.js +12 -0
  148. package/dist/src/stores/use-motia-config-store.d.ts +12 -0
  149. package/dist/src/stores/use-motia-config-store.js +24 -0
  150. package/dist/src/stores/use-tabs-store.d.ts +19 -0
  151. package/dist/src/stores/use-tabs-store.js +22 -0
  152. package/dist/src/system-view-mode.d.ts +1 -0
  153. package/dist/src/system-view-mode.js +10 -0
  154. package/dist/src/types/endpoint.d.ts +14 -0
  155. package/dist/src/types/endpoint.js +1 -0
  156. package/dist/src/types/file.d.ts +7 -0
  157. package/dist/src/types/file.js +1 -0
  158. package/dist/src/types/flow.d.ts +115 -0
  159. package/dist/src/types/flow.js +1 -0
  160. package/dist/tsconfig.app.tsbuildinfo +1 -0
  161. package/dist/tsconfig.node.tsbuildinfo +1 -0
  162. package/package.json +51 -53
  163. package/dist/motia-plugin/__tests__/generator.test.ts +0 -129
  164. package/dist/motia-plugin/__tests__/resolver.test.ts +0 -82
  165. package/dist/motia-plugin/__tests__/validator.test.ts +0 -71
  166. package/dist/motia-plugin/hmr.ts +0 -123
  167. package/dist/motia-plugin/index.ts +0 -183
  168. package/dist/motia-plugin/types.ts +0 -198
  169. package/dist/motia-plugin/validator.ts +0 -197
  170. package/dist/src/App.tsx +0 -41
  171. package/dist/src/components/NotFoundPage.tsx +0 -11
  172. package/dist/src/components/bottom-panel.tsx +0 -39
  173. package/dist/src/components/flow/base-edge.tsx +0 -61
  174. package/dist/src/components/flow/flow-loader.tsx +0 -3
  175. package/dist/src/components/flow/flow-page.tsx +0 -75
  176. package/dist/src/components/flow/flow-tab-menu-item.tsx +0 -52
  177. package/dist/src/components/flow/flow-view.tsx +0 -66
  178. package/dist/src/components/flow/hooks/use-get-flow-state.tsx +0 -171
  179. package/dist/src/components/flow/hooks/use-save-workflow-config.ts +0 -25
  180. package/dist/src/components/flow/node-organizer.tsx +0 -103
  181. package/dist/src/components/flow/nodes/api-flow-node.tsx +0 -6
  182. package/dist/src/components/flow/nodes/cron-flow-node.tsx +0 -6
  183. package/dist/src/components/flow/nodes/event-flow-node.tsx +0 -6
  184. package/dist/src/components/flow/nodes/noop-flow-node.tsx +0 -6
  185. package/dist/src/components/header/deploy-button.tsx +0 -110
  186. package/dist/src/components/header/header.tsx +0 -39
  187. package/dist/src/components/root-motia.tsx +0 -10
  188. package/dist/src/components/top-panel.tsx +0 -40
  189. package/dist/src/components/tutorial/engine/tutorial-engine.ts +0 -26
  190. package/dist/src/components/tutorial/engine/tutorial-types.ts +0 -26
  191. package/dist/src/components/tutorial/engine/workbench-xpath.ts +0 -53
  192. package/dist/src/components/tutorial/hooks/tutorial-utils.ts +0 -26
  193. package/dist/src/components/tutorial/hooks/use-tutorial-engine.ts +0 -213
  194. package/dist/src/components/tutorial/hooks/use-tutorial.ts +0 -14
  195. package/dist/src/components/tutorial/tutorial-button.tsx +0 -46
  196. package/dist/src/components/tutorial/tutorial-step.tsx +0 -82
  197. package/dist/src/components/tutorial/tutorial.tsx +0 -59
  198. package/dist/src/components/ui/json-editor.tsx +0 -68
  199. package/dist/src/components/ui/table.tsx +0 -75
  200. package/dist/src/components/ui/theme-toggle.tsx +0 -54
  201. package/dist/src/components/ui/tooltip.tsx +0 -26
  202. package/dist/src/hooks/use-debounced.ts +0 -22
  203. package/dist/src/hooks/use-fetch-flows.ts +0 -33
  204. package/dist/src/hooks/use-mobile.ts +0 -19
  205. package/dist/src/hooks/use-update-handle-positions.ts +0 -42
  206. package/dist/src/lib/__tests__/utils.test.ts +0 -110
  207. package/dist/src/lib/motia-analytics.ts +0 -140
  208. package/dist/src/lib/plugins.tsx +0 -132
  209. package/dist/src/lib/utils.ts +0 -37
  210. package/dist/src/main.tsx +0 -30
  211. package/dist/src/project-view-mode.tsx +0 -32
  212. package/dist/src/publicComponents/api-node.tsx +0 -26
  213. package/dist/src/publicComponents/base-node/base-handle.tsx +0 -50
  214. package/dist/src/publicComponents/base-node/base-node.tsx +0 -114
  215. package/dist/src/publicComponents/base-node/code-display.tsx +0 -119
  216. package/dist/src/publicComponents/base-node/emits.tsx +0 -17
  217. package/dist/src/publicComponents/base-node/feature-card.tsx +0 -32
  218. package/dist/src/publicComponents/base-node/language-indicator.tsx +0 -131
  219. package/dist/src/publicComponents/base-node/node-header.tsx +0 -49
  220. package/dist/src/publicComponents/base-node/node-sidebar.tsx +0 -41
  221. package/dist/src/publicComponents/base-node/subscribe.tsx +0 -13
  222. package/dist/src/publicComponents/cron-node.tsx +0 -24
  223. package/dist/src/publicComponents/event-node.tsx +0 -20
  224. package/dist/src/publicComponents/node-props.tsx +0 -15
  225. package/dist/src/publicComponents/noop-node.tsx +0 -19
  226. package/dist/src/setupTests.ts +0 -1
  227. package/dist/src/stores/use-app-tabs-store.ts +0 -49
  228. package/dist/src/stores/use-flow-store.ts +0 -31
  229. package/dist/src/stores/use-global-store.ts +0 -24
  230. package/dist/src/stores/use-motia-config-store.ts +0 -36
  231. package/dist/src/stores/use-tabs-store.ts +0 -34
  232. package/dist/src/system-view-mode.tsx +0 -28
  233. package/dist/src/types/endpoint.ts +0 -12
  234. package/dist/src/types/file.ts +0 -7
  235. package/dist/src/types/flow.ts +0 -103
  236. package/eslint.config.cjs +0 -22
  237. package/jest.config.cjs +0 -68
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { motiaAnalytics } from '@/lib/motia-analytics';
3
+ import { useTutorialEngine } from './hooks/use-tutorial-engine';
4
+ import { TutorialStep } from './tutorial-step';
5
+ import './tutorial.css';
6
+ export const Tutorial = () => {
7
+ const engine = useTutorialEngine();
8
+ const onNext = () => {
9
+ const currentStep = engine.currentStepRef.current;
10
+ const nextStep = currentStep + 1;
11
+ engine.moveStep(nextStep);
12
+ if (engine.currentStep === engine.totalSteps) {
13
+ motiaAnalytics.track('tutorial_completed', {
14
+ manualOpen: engine.manualOpenRef.current,
15
+ });
16
+ }
17
+ else {
18
+ motiaAnalytics.track('tutorial_next_step', {
19
+ step: nextStep,
20
+ manualOpen: engine.manualOpenRef.current,
21
+ });
22
+ }
23
+ };
24
+ const onClose = () => {
25
+ motiaAnalytics.track('tutorial_closed', {
26
+ step: engine.currentStepRef.current,
27
+ manualOpen: engine.manualOpenRef.current,
28
+ });
29
+ engine.onClose();
30
+ };
31
+ return (_jsxs("div", { children: [_jsx("div", { className: "fixed inset-0 z-[9999]" }), _jsx("div", { className: "absolute top-5 left-5 w-full h-full rounded-lg shadow-[0_0_0_9999px_rgba(0,0,0,0.5)] z-[10000] pointer-events-none", ref: engine.highlighterRef }), _jsx(TutorialStep, { ref: engine.ref, step: engine.currentStep, totalSteps: engine.totalSteps, title: engine.title, description: engine.description, link: engine.link, image: engine.image, onNext: onNext, onClose: onClose })] }));
32
+ };
@@ -0,0 +1,12 @@
1
+ import { type FC } from 'react';
2
+ type JsonEditorProps = {
3
+ value: string;
4
+ height?: number | string;
5
+ schema?: Record<string, unknown>;
6
+ onChange?: (value: string) => void;
7
+ onValidate?: (isValid: boolean) => void;
8
+ language?: 'json' | string;
9
+ readOnly?: boolean;
10
+ };
11
+ export declare const JsonEditor: FC<JsonEditorProps>;
12
+ export {};
@@ -0,0 +1,35 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import Editor, { useMonaco } from '@monaco-editor/react';
3
+ import { useThemeStore } from '@motiadev/ui';
4
+ import { useEffect, useMemo } from 'react';
5
+ export const JsonEditor = ({ value, height = 300, schema, onChange, onValidate, language = 'json', readOnly = false, }) => {
6
+ const monaco = useMonaco();
7
+ const theme = useThemeStore((state) => state.theme);
8
+ const editorTheme = useMemo(() => (theme === 'dark' ? 'vs-dark' : 'light'), [theme]);
9
+ useEffect(() => {
10
+ if (!monaco)
11
+ return;
12
+ monaco.languages.typescript.javascriptDefaults.setCompilerOptions({ isolatedModules: true });
13
+ monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
14
+ schemas: schema
15
+ ? [
16
+ {
17
+ uri: window.location.href,
18
+ fileMatch: ['*'],
19
+ schema,
20
+ },
21
+ ]
22
+ : [],
23
+ });
24
+ }, [monaco, schema, language]);
25
+ return (_jsx(Editor, { "data-testid": "json-editor", height: height, language: language, value: value, theme: editorTheme, onChange: (value) => {
26
+ if (!value) {
27
+ onValidate?.(false);
28
+ }
29
+ onChange?.(value ?? '');
30
+ }, onValidate: (markers) => onValidate?.(markers.length === 0), options: {
31
+ readOnly,
32
+ scrollBeyondLastLine: false,
33
+ minimap: { enabled: false },
34
+ } }));
35
+ };
@@ -0,0 +1,10 @@
1
+ import * as React from 'react';
2
+ declare const Table: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLTableElement> & React.RefAttributes<HTMLTableElement>>;
3
+ declare const TableHeader: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLTableSectionElement> & React.RefAttributes<HTMLTableSectionElement>>;
4
+ declare const TableBody: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLTableSectionElement> & React.RefAttributes<HTMLTableSectionElement>>;
5
+ declare const TableFooter: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLTableSectionElement> & React.RefAttributes<HTMLTableSectionElement>>;
6
+ declare const TableRow: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLTableRowElement> & React.RefAttributes<HTMLTableRowElement>>;
7
+ declare const TableHead: React.ForwardRefExoticComponent<React.ThHTMLAttributes<HTMLTableCellElement> & React.RefAttributes<HTMLTableCellElement>>;
8
+ declare const TableCell: React.ForwardRefExoticComponent<React.TdHTMLAttributes<HTMLTableCellElement> & React.RefAttributes<HTMLTableCellElement>>;
9
+ declare const TableCaption: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLTableCaptionElement> & React.RefAttributes<HTMLTableCaptionElement>>;
10
+ export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption };
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from '@motiadev/ui';
3
+ import * as React from 'react';
4
+ const Table = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { className: "relative w-full overflow-auto", children: _jsx("table", { ref: ref, className: cn('w-full caption-bottom text-sm', className), ...props }) })));
5
+ Table.displayName = 'Table';
6
+ const TableHeader = React.forwardRef(({ className, ...props }, ref) => _jsx("thead", { ref: ref, className: cn('[&_tr]:border-b', className), ...props }));
7
+ TableHeader.displayName = 'TableHeader';
8
+ const TableBody = React.forwardRef(({ className, ...props }, ref) => (_jsx("tbody", { ref: ref, className: cn('[&_tr:last-child]:border-0', className), ...props })));
9
+ TableBody.displayName = 'TableBody';
10
+ const TableFooter = React.forwardRef(({ className, ...props }, ref) => (_jsx("tfoot", { ref: ref, className: cn('border-t bg-muted/50 font-medium [&>tr]:last:border-b-0', className), ...props })));
11
+ TableFooter.displayName = 'TableFooter';
12
+ const TableRow = React.forwardRef(({ className, ...props }, ref) => (_jsx("tr", { ref: ref, className: cn('border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted', className), ...props })));
13
+ TableRow.displayName = 'TableRow';
14
+ const TableHead = React.forwardRef(({ className, ...props }, ref) => (_jsx("th", { ref: ref, className: cn('h-10 px-2 text-left align-middle text-md font-medium bg-muted text-muted-foreground font-bold [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]', className), ...props })));
15
+ TableHead.displayName = 'TableHead';
16
+ const TableCell = React.forwardRef(({ className, ...props }, ref) => (_jsx("td", { ref: ref, className: cn('p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]', className), ...props })));
17
+ TableCell.displayName = 'TableCell';
18
+ const TableCaption = React.forwardRef(({ className, ...props }, ref) => (_jsx("caption", { ref: ref, className: cn('mt-4 text-sm text-muted-foreground', className), ...props })));
19
+ TableCaption.displayName = 'TableCaption';
20
+ export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption };
@@ -0,0 +1,2 @@
1
+ import type React from 'react';
2
+ export declare const ThemeToggle: React.FC;
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn, useThemeStore } from '@motiadev/ui';
3
+ import { Moon, Sun } from 'lucide-react';
4
+ import { useEffect } from 'react';
5
+ export const ThemeToggle = () => {
6
+ const theme = useThemeStore((state) => state.theme);
7
+ const setTheme = useThemeStore((state) => state.setTheme);
8
+ const toggleTheme = () => {
9
+ setTheme(theme === 'light' ? 'dark' : 'light');
10
+ };
11
+ useEffect(() => {
12
+ const url = new URL(window.location.href);
13
+ const colorScheme = url.searchParams.get('color-scheme');
14
+ if (colorScheme) {
15
+ setTheme(colorScheme);
16
+ }
17
+ }, [setTheme]);
18
+ return (_jsxs("button", { onClick: toggleTheme, className: "relative flex items-center cursor-pointer w-16 h-8 border bg-muted-foreground/10 rounded-full p-1 transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", "aria-label": `Switch to ${theme === 'light' ? 'dark' : 'light'} theme`, children: [_jsx("div", { className: cn('absolute w-6 h-6 bg-background border border-border rounded-full shadow-sm transition-transform duration-200 ease-in-out', theme === 'dark' ? 'translate-x-8' : 'translate-x-0') }), _jsx("div", { className: "flex items-center justify-center w-6 h-6 z-10", children: _jsx(Sun, { className: cn('h-3.5 w-3.5 transition-colors duration-200', theme === 'light' ? 'text-foreground' : 'text-muted-foreground') }) }), _jsx("div", { className: "flex items-center justify-center w-6 h-6 z-10 ml-2", children: _jsx(Moon, { className: cn('h-3.5 w-3.5 transition-colors duration-200', theme === 'dark' ? 'text-foreground' : 'text-muted-foreground') }) })] }));
19
+ };
@@ -0,0 +1,6 @@
1
+ import type { ReactNode } from 'react';
2
+ export declare const Tooltip: ({ children, content, disabled, }: {
3
+ children: ReactNode;
4
+ content: string | ReactNode;
5
+ disabled?: boolean;
6
+ }) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
3
+ export const Tooltip = ({ children, content, disabled, }) => (_jsx(TooltipPrimitive.Provider, { disableHoverableContent: disabled, children: _jsxs(TooltipPrimitive.Root, { children: [_jsx(TooltipPrimitive.Trigger, { asChild: true, children: children }), _jsx(TooltipPrimitive.Portal, { children: _jsxs(TooltipPrimitive.Content, { className: "TooltipContent", side: "bottom", children: [_jsx("div", { className: "p-2 bg-background text-popover-foreground text-sm rounded-lg border border-light-800", children: content }), _jsx(TooltipPrimitive.Arrow, { className: "TooltipArrow" })] }) })] }) }));
@@ -0,0 +1 @@
1
+ export declare const useDebounced: (fn: () => void, delay?: number) => () => void;
@@ -0,0 +1,18 @@
1
+ import { useCallback, useEffect, useRef } from 'react';
2
+ export const useDebounced = (fn, delay = 500) => {
3
+ const saveTimeoutRef = useRef(null);
4
+ const debouncedFn = useCallback(() => {
5
+ if (saveTimeoutRef.current) {
6
+ clearTimeout(saveTimeoutRef.current);
7
+ }
8
+ saveTimeoutRef.current = setTimeout(fn, delay);
9
+ }, [fn, delay]);
10
+ useEffect(() => {
11
+ return () => {
12
+ if (saveTimeoutRef.current) {
13
+ clearTimeout(saveTimeoutRef.current);
14
+ }
15
+ };
16
+ }, []);
17
+ return debouncedFn;
18
+ };
@@ -0,0 +1 @@
1
+ export declare const useFetchFlows: () => void;
@@ -0,0 +1,26 @@
1
+ import { useStreamGroup } from '@motiadev/stream-client-react';
2
+ import { useEffect } from 'react';
3
+ import { useFlowStore } from '@/stores/use-flow-store';
4
+ const streamGroupArgs = { streamName: '__motia.flows', groupId: 'default' };
5
+ export const useFetchFlows = () => {
6
+ const setFlows = useFlowStore((state) => state.setFlows);
7
+ const selectFlowId = useFlowStore((state) => state.selectFlowId);
8
+ const clearSelectedFlowId = useFlowStore((state) => state.clearSelectedFlowId);
9
+ const selectedFlowId = useFlowStore((state) => state.selectedFlowId);
10
+ const { data: flows } = useStreamGroup(streamGroupArgs);
11
+ useEffect(() => {
12
+ if (flows)
13
+ setFlows(flows.map((flow) => flow.id));
14
+ }, [flows, setFlows]);
15
+ useEffect(() => {
16
+ const hasFlows = flows.length > 0;
17
+ const isSelectedFlowValid = selectedFlowId && flows.some((flow) => flow.id === selectedFlowId);
18
+ if (!hasFlows && selectedFlowId) {
19
+ clearSelectedFlowId();
20
+ return;
21
+ }
22
+ if (hasFlows && (!selectedFlowId || !isSelectedFlowValid)) {
23
+ selectFlowId(flows[0].id);
24
+ }
25
+ }, [flows, selectedFlowId, selectFlowId, clearSelectedFlowId]);
26
+ };
@@ -0,0 +1 @@
1
+ export declare function useIsMobile(): boolean;
@@ -0,0 +1,15 @@
1
+ import * as React from 'react';
2
+ const MOBILE_BREAKPOINT = 768;
3
+ export function useIsMobile() {
4
+ const [isMobile, setIsMobile] = React.useState(undefined);
5
+ React.useEffect(() => {
6
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
7
+ const onChange = () => {
8
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
9
+ };
10
+ mql.addEventListener('change', onChange);
11
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
12
+ return () => mql.removeEventListener('change', onChange);
13
+ }, []);
14
+ return !!isMobile;
15
+ }
@@ -0,0 +1,10 @@
1
+ import { Position } from '@xyflow/react';
2
+ import type { BaseNodeProps } from '../publicComponents/node-props';
3
+ export declare const useHandlePositions: (data: BaseNodeProps) => {
4
+ sourcePosition: Position;
5
+ targetPosition: Position;
6
+ updateSourcePosition: (position: "bottom" | "right") => void;
7
+ updateTargetPosition: (position: "top" | "left") => void;
8
+ toggleTargetPosition: () => void;
9
+ toggleSourcePosition: () => void;
10
+ };
@@ -0,0 +1,35 @@
1
+ import { Position, useReactFlow, useUpdateNodeInternals } from '@xyflow/react';
2
+ export const useHandlePositions = (data) => {
3
+ const reactFlow = useReactFlow();
4
+ const updateNodeInternals = useUpdateNodeInternals();
5
+ const sourcePosition = data.nodeConfig?.sourceHandlePosition === 'bottom' ? Position.Bottom : Position.Right;
6
+ const targetPosition = data.nodeConfig?.targetHandlePosition === 'top' ? Position.Top : Position.Left;
7
+ const updateSourcePosition = (position) => {
8
+ reactFlow.updateNode(data.id, {
9
+ data: { ...data, nodeConfig: { ...data.nodeConfig, sourceHandlePosition: position } },
10
+ });
11
+ updateNodeInternals(data.id);
12
+ };
13
+ const updateTargetPosition = (position) => {
14
+ reactFlow.updateNode(data.id, {
15
+ data: { ...data, nodeConfig: { ...data.nodeConfig, targetHandlePosition: position } },
16
+ });
17
+ updateNodeInternals(data.id);
18
+ };
19
+ const toggleTargetPosition = () => {
20
+ const newPosition = targetPosition === Position.Top ? Position.Left : Position.Top;
21
+ updateTargetPosition(newPosition);
22
+ };
23
+ const toggleSourcePosition = () => {
24
+ const newPosition = sourcePosition === Position.Bottom ? Position.Right : Position.Bottom;
25
+ updateSourcePosition(newPosition);
26
+ };
27
+ return {
28
+ sourcePosition,
29
+ targetPosition,
30
+ updateSourcePosition,
31
+ updateTargetPosition,
32
+ toggleTargetPosition,
33
+ toggleSourcePosition,
34
+ };
35
+ };
@@ -1,7 +1,7 @@
1
- @import '@motiadev/ui/styles.css';
2
- @import '@motiadev/ui/globals.css';
1
+ @import "@motiadev/ui/styles.css";
2
+ @import "@motiadev/ui/globals.css";
3
3
 
4
- @import 'tw-animate-css';
4
+ @import "tw-animate-css";
5
5
  @config "../tailwind.config.js";
6
6
 
7
7
  @keyframes flowDash {
@@ -27,7 +27,7 @@
27
27
  }
28
28
 
29
29
  .font-mono {
30
- font-family: 'IBM Plex Mono', 'Courier New', monospace;
30
+ font-family: "IBM Plex Mono", "Courier New", monospace;
31
31
  font-size: 14px;
32
32
  }
33
33
 
@@ -40,7 +40,7 @@
40
40
  .json-view {
41
41
  border-radius: 8px;
42
42
  padding: 12px 12px;
43
- font-family: 'IBM Plex Mono', 'Courier New', monospace;
43
+ font-family: "IBM Plex Mono", "Courier New", monospace;
44
44
  font-size: 14px;
45
45
  line-height: 1.5;
46
46
  font-weight: 500;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,94 @@
1
+ import { formatDuration } from '../utils';
2
+ describe('formatDuration', () => {
3
+ describe('milliseconds', () => {
4
+ it('should format values under 1 second as milliseconds', () => {
5
+ expect(formatDuration(0)).toBe('0ms');
6
+ expect(formatDuration(1)).toBe('1ms');
7
+ expect(formatDuration(250)).toBe('250ms');
8
+ expect(formatDuration(500)).toBe('500ms');
9
+ expect(formatDuration(999)).toBe('999ms');
10
+ });
11
+ });
12
+ describe('seconds', () => {
13
+ it('should format values between 1 second and 1 minute as seconds with 1 decimal', () => {
14
+ expect(formatDuration(1000)).toBe('1.0s');
15
+ expect(formatDuration(1500)).toBe('1.5s');
16
+ expect(formatDuration(15000)).toBe('15.0s');
17
+ expect(formatDuration(45500)).toBe('45.5s');
18
+ expect(formatDuration(59999)).toBe('60.0s');
19
+ });
20
+ it('should round to 1 decimal place', () => {
21
+ expect(formatDuration(1234)).toBe('1.2s');
22
+ expect(formatDuration(1567)).toBe('1.6s');
23
+ expect(formatDuration(12345)).toBe('12.3s');
24
+ });
25
+ });
26
+ describe('minutes', () => {
27
+ it('should format values between 1 minute and 1 hour as minutes with 1 decimal', () => {
28
+ expect(formatDuration(60000)).toBe('1.0min');
29
+ expect(formatDuration(90000)).toBe('1.5min');
30
+ expect(formatDuration(300000)).toBe('5.0min');
31
+ expect(formatDuration(1800000)).toBe('30.0min');
32
+ expect(formatDuration(3599999)).toBe('60.0min');
33
+ });
34
+ it('should round to 1 decimal place', () => {
35
+ expect(formatDuration(123456)).toBe('2.1min');
36
+ expect(formatDuration(567890)).toBe('9.5min');
37
+ });
38
+ });
39
+ describe('hours', () => {
40
+ it('should format values 1 hour or more as hours with 1 decimal', () => {
41
+ expect(formatDuration(3600000)).toBe('1.0h');
42
+ expect(formatDuration(5400000)).toBe('1.5h');
43
+ expect(formatDuration(7200000)).toBe('2.0h');
44
+ expect(formatDuration(36000000)).toBe('10.0h');
45
+ });
46
+ it('should round to 1 decimal place', () => {
47
+ expect(formatDuration(3661000)).toBe('1.0h');
48
+ expect(formatDuration(5432100)).toBe('1.5h');
49
+ expect(formatDuration(9000000)).toBe('2.5h');
50
+ });
51
+ });
52
+ describe('edge cases', () => {
53
+ it('should return "N/A" for undefined', () => {
54
+ expect(formatDuration(undefined)).toBe('N/A');
55
+ });
56
+ it('should return "N/A" for null', () => {
57
+ expect(formatDuration(null)).toBe('N/A');
58
+ });
59
+ it('should return "N/A" for 0 when treated as falsy', () => {
60
+ expect(formatDuration(0)).toBe('0ms');
61
+ });
62
+ });
63
+ describe('boundary values', () => {
64
+ it('should correctly handle millisecond-second boundary (999ms vs 1.0s)', () => {
65
+ expect(formatDuration(999)).toBe('999ms');
66
+ expect(formatDuration(1000)).toBe('1.0s');
67
+ });
68
+ it('should correctly handle second-minute boundary (59.9s vs 1.0min)', () => {
69
+ expect(formatDuration(59999)).toBe('60.0s');
70
+ expect(formatDuration(60000)).toBe('1.0min');
71
+ });
72
+ it('should correctly handle minute-hour boundary (59.9min vs 1.0h)', () => {
73
+ expect(formatDuration(3599999)).toBe('60.0min');
74
+ expect(formatDuration(3600000)).toBe('1.0h');
75
+ });
76
+ });
77
+ describe('real-world scenarios', () => {
78
+ it('should format typical API response times', () => {
79
+ expect(formatDuration(50)).toBe('50ms');
80
+ expect(formatDuration(150)).toBe('150ms');
81
+ expect(formatDuration(2500)).toBe('2.5s');
82
+ });
83
+ it('should format typical workflow execution times', () => {
84
+ expect(formatDuration(5000)).toBe('5.0s');
85
+ expect(formatDuration(30000)).toBe('30.0s');
86
+ expect(formatDuration(120000)).toBe('2.0min');
87
+ });
88
+ it('should format long-running tasks', () => {
89
+ expect(formatDuration(600000)).toBe('10.0min');
90
+ expect(formatDuration(1800000)).toBe('30.0min');
91
+ expect(formatDuration(7200000)).toBe('2.0h');
92
+ });
93
+ });
94
+ });
@@ -0,0 +1,38 @@
1
+ interface AmplitudeInstance {
2
+ setOptOut(optOut: boolean): void;
3
+ track(eventName: string, eventProperties?: Record<string, any>): void;
4
+ identify(userId: string, userProperties?: Record<string, any>): void;
5
+ setUserId(userId: string): void;
6
+ getUserId(): string | undefined;
7
+ }
8
+ declare global {
9
+ interface Window {
10
+ amplitude: AmplitudeInstance;
11
+ }
12
+ }
13
+ declare class WorkbenchAnalytics {
14
+ private isInitialized;
15
+ private userIdCache;
16
+ private projectIdCache;
17
+ private motiaVersion;
18
+ constructor();
19
+ private initialize;
20
+ private fetchUserData;
21
+ private generateFallbackUserId;
22
+ private identifyUser;
23
+ private getBrowserInfo;
24
+ getAnalyticsIds(): {
25
+ userId: string | null;
26
+ projectId: string | null;
27
+ };
28
+ track(eventName: string, properties?: Record<string, any>): void;
29
+ }
30
+ export declare const motiaAnalytics: WorkbenchAnalytics;
31
+ export declare const useAnalytics: () => {
32
+ track: (eventName: string, properties?: Record<string, any>) => void;
33
+ getAnalyticsIds: () => {
34
+ userId: string | null;
35
+ projectId: string | null;
36
+ };
37
+ };
38
+ export {};
@@ -0,0 +1,132 @@
1
+ import { useCallback } from 'react';
2
+ class WorkbenchAnalytics {
3
+ constructor() {
4
+ Object.defineProperty(this, "isInitialized", {
5
+ enumerable: true,
6
+ configurable: true,
7
+ writable: true,
8
+ value: false
9
+ });
10
+ Object.defineProperty(this, "userIdCache", {
11
+ enumerable: true,
12
+ configurable: true,
13
+ writable: true,
14
+ value: null
15
+ });
16
+ Object.defineProperty(this, "projectIdCache", {
17
+ enumerable: true,
18
+ configurable: true,
19
+ writable: true,
20
+ value: null
21
+ });
22
+ Object.defineProperty(this, "motiaVersion", {
23
+ enumerable: true,
24
+ configurable: true,
25
+ writable: true,
26
+ value: null
27
+ });
28
+ this.initialize();
29
+ }
30
+ async initialize() {
31
+ if (typeof window !== 'undefined' && window.amplitude) {
32
+ await this.fetchUserData();
33
+ this.isInitialized = true;
34
+ this.identifyUser();
35
+ }
36
+ }
37
+ async fetchUserData() {
38
+ try {
39
+ const response = await fetch('/motia/analytics/user');
40
+ if (response.ok) {
41
+ const data = await response.json();
42
+ this.userIdCache = data.userId;
43
+ this.projectIdCache = data.projectId;
44
+ this.motiaVersion = data.motiaVersion;
45
+ window.amplitude.setOptOut(!data.analyticsEnabled);
46
+ // Set the user ID in Amplitude to match backend
47
+ if (window.amplitude && data.userId) {
48
+ window.amplitude.setUserId(data.userId);
49
+ }
50
+ }
51
+ else {
52
+ console.warn('Failed to fetch user data from backend, using fallback');
53
+ this.userIdCache = this.generateFallbackUserId();
54
+ }
55
+ }
56
+ catch (error) {
57
+ console.warn('Error fetching user data:', error);
58
+ this.userIdCache = this.generateFallbackUserId();
59
+ }
60
+ }
61
+ generateFallbackUserId() {
62
+ let userId = localStorage.getItem('motia-user-id');
63
+ if (!userId) {
64
+ userId = `user-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
65
+ localStorage.setItem('motia-user-id', userId);
66
+ }
67
+ return userId;
68
+ }
69
+ identifyUser() {
70
+ if (!this.isInitialized || !this.userIdCache)
71
+ return;
72
+ try {
73
+ window.amplitude.identify(this.userIdCache, {
74
+ project_id: this.projectIdCache,
75
+ browser: this.getBrowserInfo(),
76
+ screen_resolution: `${window.screen.width}x${window.screen.height}`,
77
+ workbench_version: this.motiaVersion,
78
+ });
79
+ }
80
+ catch (error) {
81
+ console.warn('Analytics user identification failed:', error);
82
+ }
83
+ }
84
+ getBrowserInfo() {
85
+ const ua = navigator.userAgent;
86
+ if (ua.includes('Chrome'))
87
+ return 'Chrome';
88
+ if (ua.includes('Firefox'))
89
+ return 'Firefox';
90
+ if (ua.includes('Safari'))
91
+ return 'Safari';
92
+ if (ua.includes('Edge'))
93
+ return 'Edge';
94
+ return 'Unknown';
95
+ }
96
+ // Method to get current user and project IDs for external use
97
+ getAnalyticsIds() {
98
+ return {
99
+ userId: this.userIdCache,
100
+ projectId: this.projectIdCache,
101
+ };
102
+ }
103
+ // Simple track method that preserves the user binding
104
+ track(eventName, properties) {
105
+ if (!this.isInitialized)
106
+ return;
107
+ const eventProperties = {
108
+ project_id: this.projectIdCache,
109
+ source: 'frontend',
110
+ ...properties,
111
+ };
112
+ try {
113
+ window.amplitude.track(eventName, eventProperties);
114
+ }
115
+ catch (error) {
116
+ console.warn('Analytics tracking failed:', error);
117
+ }
118
+ }
119
+ }
120
+ export const motiaAnalytics = new WorkbenchAnalytics();
121
+ export const useAnalytics = () => {
122
+ const track = useCallback((eventName, properties) => {
123
+ motiaAnalytics.track(eventName, properties);
124
+ }, []);
125
+ const getAnalyticsIds = useCallback(() => {
126
+ return motiaAnalytics.getAnalyticsIds();
127
+ }, []);
128
+ return {
129
+ track,
130
+ getAnalyticsIds,
131
+ };
132
+ };
@@ -0,0 +1,2 @@
1
+ import { type AppTab, TabLocation } from '@/stores/use-app-tabs-store';
2
+ export declare const registerPluginTabs: (addTab: (position: TabLocation, tab: AppTab) => void) => void;