@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.
Files changed (69) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.html +9 -9
  3. package/dist/index.js +1 -1
  4. package/dist/src/components/app-sidebar.js +2 -2
  5. package/dist/src/components/endpoints/endpoint-call.js +2 -2
  6. package/dist/src/components/header/header.js +1 -1
  7. package/dist/src/components/logs/log-console.js +1 -1
  8. package/dist/src/components/observability/events/code/function-call.d.ts +13 -0
  9. package/dist/src/components/observability/events/code/function-call.js +16 -0
  10. package/dist/src/components/observability/events/event-icon.d.ts +7 -0
  11. package/dist/src/components/observability/events/event-icon.js +16 -0
  12. package/dist/src/components/observability/events/trace-emit-event.d.ts +5 -0
  13. package/dist/src/components/observability/events/trace-emit-event.js +5 -0
  14. package/dist/src/components/observability/events/trace-event.d.ts +5 -0
  15. package/dist/src/components/observability/events/trace-event.js +20 -0
  16. package/dist/src/components/observability/events/trace-log-event.d.ts +5 -0
  17. package/dist/src/components/observability/events/trace-log-event.js +5 -0
  18. package/dist/src/components/observability/events/trace-state-event.d.ts +5 -0
  19. package/dist/src/components/observability/events/trace-state-event.js +5 -0
  20. package/dist/src/components/observability/events/trace-stream-event.d.ts +5 -0
  21. package/dist/src/components/observability/events/trace-stream-event.js +5 -0
  22. package/dist/src/components/observability/hooks/use-get-endtime.d.ts +2 -0
  23. package/dist/src/components/observability/hooks/use-get-endtime.js +15 -0
  24. package/dist/src/components/observability/observability-stats.d.ts +5 -0
  25. package/dist/src/components/observability/observability-stats.js +17 -0
  26. package/dist/src/components/observability/trace-item/trace-item-detail.d.ts +7 -0
  27. package/dist/src/components/observability/trace-item/trace-item-detail.js +10 -0
  28. package/dist/src/components/observability/trace-item/trace-item.d.ts +9 -0
  29. package/dist/src/components/observability/trace-item/trace-item.js +20 -0
  30. package/dist/src/components/observability/trace-status.d.ts +12 -0
  31. package/dist/src/components/observability/trace-status.js +43 -0
  32. package/dist/src/components/observability/trace-timeline.d.ts +6 -0
  33. package/dist/src/components/observability/trace-timeline.js +17 -0
  34. package/dist/src/components/observability/traces-groups.d.ts +9 -0
  35. package/dist/src/components/observability/traces-groups.js +15 -0
  36. package/dist/src/components/ui/card.d.ts +8 -0
  37. package/dist/src/components/ui/card.js +16 -0
  38. package/dist/src/components/ui/navigation-menu.d.ts +9 -10
  39. package/dist/src/components/ui/navigation-menu.js +9 -10
  40. package/dist/src/components/ui/scroll-area.d.ts +5 -0
  41. package/dist/src/components/ui/scroll-area.js +9 -0
  42. package/dist/src/components/ui/sheet.d.ts +1 -1
  43. package/dist/src/components/ui/sidebar.js +1 -1
  44. package/dist/src/components/ui/tabs.d.ts +7 -0
  45. package/dist/src/components/ui/tabs.js +12 -0
  46. package/dist/src/hooks/use-fetch-flows.d.ts +5 -0
  47. package/dist/src/hooks/use-fetch-flows.js +17 -0
  48. package/dist/src/hooks/use-list-flows.d.ts +3 -2
  49. package/dist/src/index.css +2 -155
  50. package/dist/src/lib/utils.d.ts +1 -0
  51. package/dist/src/lib/utils.js +7 -0
  52. package/dist/src/main.js +2 -1
  53. package/dist/src/routes/flow.js +2 -13
  54. package/dist/src/routes/index.js +2 -2
  55. package/dist/src/routes/traces-page.d.ts +1 -0
  56. package/dist/src/routes/traces-page.js +14 -0
  57. package/dist/src/types/observability.d.ts +78 -0
  58. package/dist/src/types/observability.js +1 -0
  59. package/dist/src/views/flow/flow-view.js +2 -17
  60. package/dist/src/views/flow/hooks/use-get-flow-state.d.ts +5 -2
  61. package/dist/src/views/flow/hooks/use-get-flow-state.js +97 -27
  62. package/dist/src/views/flow/hooks/use-save-workflow-config.d.ts +2 -9
  63. package/dist/src/views/flow/hooks/use-save-workflow-config.js +5 -6
  64. package/dist/src/views/flow/legend.js +1 -1
  65. package/dist/src/views/flow/node-organizer.js +4 -2
  66. package/dist/tsconfig.app.tsbuildinfo +1 -1
  67. package/package.json +12 -6
  68. package/dist/src/components/ui/button.d.ts +0 -11
  69. package/dist/src/components/ui/button.js +0 -33
@@ -0,0 +1,5 @@
1
+ import * as React from 'react';
2
+ import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
3
+ declare const ScrollArea: React.ForwardRefExoticComponent<Omit<ScrollAreaPrimitive.ScrollAreaProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
4
+ declare const ScrollBar: React.ForwardRefExoticComponent<Omit<ScrollAreaPrimitive.ScrollAreaScrollbarProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
5
+ export { ScrollArea, ScrollBar };
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as React from 'react';
3
+ import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
4
+ import { cn } from '@/lib/utils';
5
+ const ScrollArea = React.forwardRef(({ className, children, ...props }, ref) => (_jsxs(ScrollAreaPrimitive.Root, { ref: ref, className: cn('relative overflow-hidden', className), ...props, children: [_jsx(ScrollAreaPrimitive.Viewport, { className: "h-full w-full rounded-[inherit]", children: children }), _jsx(ScrollBar, {}), _jsx(ScrollAreaPrimitive.Corner, {})] })));
6
+ ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
7
+ const ScrollBar = React.forwardRef(({ className, orientation = 'vertical', ...props }, ref) => (_jsx(ScrollAreaPrimitive.ScrollAreaScrollbar, { ref: ref, orientation: orientation, className: cn('flex touch-none select-none transition-colors', orientation === 'vertical' && 'h-full w-2.5 border-l border-l-transparent p-[1px]', orientation === 'horizontal' && 'h-2.5 flex-col border-t border-t-transparent p-[1px]', className), ...props, children: _jsx(ScrollAreaPrimitive.ScrollAreaThumb, { className: "relative flex-1 rounded-full bg-border" }) })));
8
+ ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
9
+ export { ScrollArea, ScrollBar };
@@ -7,7 +7,7 @@ declare const SheetClose: React.ForwardRefExoticComponent<SheetPrimitive.DialogC
7
7
  declare const SheetPortal: React.FC<SheetPrimitive.DialogPortalProps>;
8
8
  declare const SheetOverlay: React.ForwardRefExoticComponent<Omit<SheetPrimitive.DialogOverlayProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
9
9
  declare const sheetVariants: (props?: ({
10
- side?: "left" | "right" | "top" | "bottom" | null | undefined;
10
+ side?: "bottom" | "left" | "right" | "top" | null | undefined;
11
11
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
12
12
  interface SheetContentProps extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>, VariantProps<typeof sheetVariants> {
13
13
  }
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState, useEffect } from 'react';
3
3
  import { cn } from '@/lib/utils';
4
4
  import { PanelLeftClose, PanelLeftOpen } from 'lucide-react';
5
- import { Button } from './button';
5
+ import { Button } from '@motiadev/ui';
6
6
  const SIDEBAR_COLLAPSED_KEY = 'sidebar-collapsed';
7
7
  export const Sidebar = ({ children }) => {
8
8
  const [isCollapsed, setIsCollapsed] = useState(() => {
@@ -0,0 +1,7 @@
1
+ import * as React from 'react';
2
+ import * as TabsPrimitive from '@radix-ui/react-tabs';
3
+ declare const Tabs: React.ForwardRefExoticComponent<TabsPrimitive.TabsProps & React.RefAttributes<HTMLDivElement>>;
4
+ declare const TabsList: React.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsListProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
5
+ declare const TabsTrigger: React.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsTriggerProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
6
+ declare const TabsContent: React.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
7
+ export { Tabs, TabsList, TabsTrigger, TabsContent };
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as React from 'react';
3
+ import * as TabsPrimitive from '@radix-ui/react-tabs';
4
+ import { cn } from '@/lib/utils';
5
+ const Tabs = TabsPrimitive.Root;
6
+ const TabsList = React.forwardRef(({ className, ...props }, ref) => (_jsx(TabsPrimitive.List, { ref: ref, className: cn('inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground', className), ...props })));
7
+ TabsList.displayName = TabsPrimitive.List.displayName;
8
+ const TabsTrigger = React.forwardRef(({ className, ...props }, ref) => (_jsx(TabsPrimitive.Trigger, { ref: ref, className: cn('inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm', className), ...props })));
9
+ TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
10
+ const TabsContent = React.forwardRef(({ className, ...props }, ref) => (_jsx(TabsPrimitive.Content, { ref: ref, className: cn('mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2', className), ...props })));
11
+ TabsContent.displayName = TabsPrimitive.Content.displayName;
12
+ export { Tabs, TabsList, TabsTrigger, TabsContent };
@@ -0,0 +1,5 @@
1
+ import { FlowConfigResponse, FlowResponse } from '@/views/flow/hooks/use-get-flow-state';
2
+ export declare const useFetchFlows: (flowId: string) => {
3
+ flow: FlowResponse | null;
4
+ flowConfig: FlowConfigResponse | null;
5
+ };
@@ -0,0 +1,17 @@
1
+ import { useStreamItem } from '@motiadev/stream-client-react';
2
+ export const useFetchFlows = (flowId) => {
3
+ const { data: flow } = useStreamItem({
4
+ streamName: '__motia.flows',
5
+ groupId: 'default',
6
+ id: flowId,
7
+ });
8
+ const { data: flowConfig } = useStreamItem({
9
+ streamName: '__motia.flowsConfig',
10
+ groupId: 'default',
11
+ id: flowId,
12
+ });
13
+ return {
14
+ flow,
15
+ flowConfig,
16
+ };
17
+ };
@@ -1,8 +1,9 @@
1
- type Flow = {
1
+ import { FlowResponse } from '@/views/flow/hooks/use-get-flow-state';
2
+ export type Flow = {
2
3
  id: string;
3
4
  name: string;
5
+ data?: FlowResponse;
4
6
  };
5
7
  export declare const useListFlows: () => {
6
8
  flows: Flow[];
7
9
  };
8
- export {};
@@ -1,157 +1,13 @@
1
- @import 'tailwindcss';
1
+ @import '@motiadev/ui/globals.css';
2
2
  @import 'tw-animate-css';
3
3
  @config "../tailwind.config.js";
4
4
 
5
- @custom-variant dark (&:is(.dark *));
6
-
7
- :root {
8
- line-height: 1.5;
9
- font-size: 16px;
10
-
11
- color-scheme: light dark;
12
- font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"), serif;
13
- font-synthesis: none;
14
- text-rendering: optimizeLegibility;
15
- -webkit-font-smoothing: antialiased;
16
- -moz-osx-font-smoothing: grayscale;
17
- width: 100%;
18
- font-optical-sizing: auto;
19
-
20
- --radius: 0.625rem;
21
- --background: oklch(1 0 0);
22
- --foreground: oklch(0.145 0 0);
23
- --card: oklch(0.98 0 0);
24
- --card-foreground: oklch(0.145 0 0);
25
- --popover: oklch(1 0 0);
26
- --popover-foreground: oklch(0.145 0 0);
27
- --primary: oklch(0.205 0 0);
28
- --primary-foreground: oklch(0.985 0 0);
29
- --secondary: oklch(0.97 0 0);
30
- --secondary-foreground: oklch(0.205 0 0);
31
- --muted: oklch(0.97 0 0);
32
- --muted-foreground: oklch(0.556 0 0);
33
- --accent: oklch(0.97 0 0);
34
- --accent-foreground: oklch(0.205 0 0);
35
- --destructive: oklch(0.577 0.245 27.325);
36
- --border: oklch(0.922 0 0);
37
- --input: oklch(0.922 0 0);
38
- --ring: oklch(0.708 0 0);
39
- --chart-1: oklch(0.646 0.222 41.116);
40
- --chart-2: oklch(0.6 0.118 184.704);
41
- --chart-3: oklch(0.398 0.07 227.392);
42
- --chart-4: oklch(0.828 0.189 84.429);
43
- --chart-5: oklch(0.769 0.188 70.08);
44
- --header: oklch(0.985 0 0);
45
- --header-foreground: oklch(0.145 0 0);
46
- --header-primary: oklch(0.205 0 0);
47
- --header-primary-foreground: oklch(0.985 0 0);
48
- --header-accent: oklch(0.97 0 0);
49
- --header-accent-foreground: oklch(0.205 0 0);
50
- --header-border: oklch(0.922 0 0);
51
- --header-ring: oklch(0.708 0 0);
52
- --sidebar: oklch(0.985 0 0);
53
- --sidebar-foreground: oklch(0.145 0 0);
54
- --sidebar-primary: oklch(0.205 0 0);
55
- --sidebar-primary-foreground: oklch(0.985 0 0);
56
- --sidebar-accent: oklch(0.97 0 0);
57
- --sidebar-accent-foreground: oklch(0.205 0 0);
58
- --sidebar-border: oklch(0.922 0 0);
59
- --sidebar-ring: oklch(0.708 0 0);
60
- }
61
-
62
- .dark {
63
- --background: oklch(0.145 0 0);
64
- --foreground: oklch(0.985 0 0);
65
- --card: oklch(0.205 0 0);
66
- --card-foreground: oklch(0.985 0 0);
67
- --popover: oklch(0.205 0 0);
68
- --popover-foreground: oklch(0.985 0 0);
69
- --primary: oklch(0.922 0 0);
70
- --primary-foreground: oklch(0.205 0 0);
71
- --secondary: oklch(0.269 0 0);
72
- --secondary-foreground: oklch(0.985 0 0);
73
- --muted: oklch(0.269 0 0);
74
- --muted-foreground: oklch(0.708 0 0);
75
- --accent: oklch(0.269 0 0);
76
- --accent-foreground: oklch(0.985 0 0);
77
- --destructive: oklch(0.704 0.191 22.216);
78
- --border: oklch(1 0 0 / 10%);
79
- --input: oklch(1 0 0 / 15%);
80
- --ring: oklch(0.556 0 0);
81
- --chart-1: oklch(0.488 0.243 264.376);
82
- --chart-2: oklch(0.696 0.17 162.48);
83
- --chart-3: oklch(0.769 0.188 70.08);
84
- --chart-4: oklch(0.627 0.265 303.9);
85
- --chart-5: oklch(0.645 0.246 16.439);
86
- --header: oklch(0.205 0 0);
87
- --header-foreground: oklch(0.985 0 0);
88
- --header-primary: oklch(0.488 0.243 264.376);
89
- --header-primary-foreground: oklch(0.985 0 0);
90
- --header-accent: oklch(0.269 0 0);
91
- --header-accent-foreground: oklch(0.985 0 0);
92
- --header-border: oklch(1 0 0 / 10%);
93
- --header-ring: oklch(0.556 0 0);
94
- --sidebar: oklch(0.205 0 0);
95
- --sidebar-foreground: oklch(0.985 0 0);
96
- --sidebar-primary: oklch(0.488 0.243 264.376);
97
- --sidebar-primary-foreground: oklch(0.985 0 0);
98
- --sidebar-accent: oklch(0.269 0 0);
99
- --sidebar-accent-foreground: oklch(0.985 0 0);
100
- --sidebar-border: oklch(1 0 0 / 10%);
101
- --sidebar-ring: oklch(0.556 0 0);
102
- }
103
-
104
- @theme inline {
105
- --radius-sm: calc(var(--radius) - 4px);
106
- --radius-md: calc(var(--radius) - 2px);
107
- --radius-lg: var(--radius);
108
- --radius-xl: calc(var(--radius) + 4px);
109
- --color-background: var(--background);
110
- --color-foreground: var(--foreground);
111
- --color-card: var(--card);
112
- --color-card-foreground: var(--card-foreground);
113
- --color-popover: var(--popover);
114
- --color-popover-foreground: var(--popover-foreground);
115
- --color-primary: var(--primary);
116
- --color-primary-foreground: var(--primary-foreground);
117
- --color-secondary: var(--secondary);
118
- --color-secondary-foreground: var(--secondary-foreground);
119
- --color-muted: var(--muted);
120
- --color-muted-foreground: var(--muted-foreground);
121
- --color-accent: var(--accent);
122
- --color-accent-foreground: var(--accent-foreground);
123
- --color-destructive: var(--destructive);
124
- --color-border: var(--border);
125
- --color-input: var(--input);
126
- --color-ring: var(--ring);
127
- --color-chart-1: var(--chart-1);
128
- --color-chart-2: var(--chart-2);
129
- --color-chart-3: var(--chart-3);
130
- --color-chart-4: var(--chart-4);
131
- --color-chart-5: var(--chart-5);
132
- --color-header: var(--header);
133
- --color-header-foreground: var(--header-foreground);
134
- --color-header-primary: var(--header-primary);
135
- --color-header-primary-foreground: var(--header-primary-foreground);
136
- --color-header-accent: var(--header-accent);
137
- --color-header-accent-foreground: var(--header-accent-foreground);
138
- --color-header-border: var(--header-border);
139
- --color-header-ring: var(--header-ring);
140
- --color-sidebar: var(--sidebar);
141
- --color-sidebar-foreground: var(--sidebar-foreground);
142
- --color-sidebar-primary: var(--sidebar-primary);
143
- --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
144
- --color-sidebar-accent: var(--sidebar-accent);
145
- --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
146
- --color-sidebar-border: var(--sidebar-border);
147
- --color-sidebar-ring: var(--sidebar-ring);
148
- }
149
-
150
5
  body {
151
6
  margin: 0;
152
7
  place-items: center;
153
8
  min-height: 100dvh;
154
9
  width: 100%;
10
+ font-family: 'DM Sans', sans-serif;
155
11
  }
156
12
 
157
13
  body,
@@ -168,15 +24,6 @@ strong {
168
24
  display: none;
169
25
  }
170
26
 
171
- @layer base {
172
- * {
173
- @apply border-border;
174
- }
175
- body {
176
- @apply bg-background text-foreground;
177
- }
178
- }
179
-
180
27
  @keyframes flowDash {
181
28
  0% {
182
29
  stroke-dashoffset: 0;
@@ -1,2 +1,3 @@
1
1
  import { type ClassValue } from 'clsx';
2
2
  export declare function cn(...inputs: ClassValue[]): string;
3
+ export declare const formatDuration: (duration?: number) => string;
@@ -3,3 +3,10 @@ import { twMerge } from 'tailwind-merge';
3
3
  export function cn(...inputs) {
4
4
  return twMerge(clsx(inputs));
5
5
  }
6
+ export const formatDuration = (duration) => {
7
+ if (!duration)
8
+ return 'N/A';
9
+ if (duration < 1000)
10
+ return `${duration}ms`;
11
+ return `${(duration / 1000).toFixed(1)}s`;
12
+ };
package/dist/src/main.js CHANGED
@@ -11,10 +11,11 @@ import { EndpointsPage } from './routes/endpoints-page';
11
11
  import { Flow } from './routes/flow';
12
12
  import { LogsPage } from './routes/logs-page';
13
13
  import { StatesPage } from './routes/states-page';
14
+ import { TracesPage } from './routes/traces-page';
14
15
  // Render the app
15
16
  const rootElement = document.getElementById('root');
16
17
  if (!rootElement.innerHTML) {
17
18
  const root = createRoot(rootElement);
18
19
  const address = window.location.origin.replace('http', 'ws');
19
- root.render(_jsx(StrictMode, { children: _jsx(MotiaStreamProvider, { address: address, children: _jsx(BrowserRouter, { children: _jsx(RootMotia, { children: _jsx(RouteWrapper, { children: _jsxs(Routes, { children: [_jsx(Route, { path: "/", element: _jsx(Index, {}) }), _jsx(Route, { path: "/flow/:id", element: _jsx(Flow, {}) }), _jsx(Route, { path: "/logs", element: _jsx(LogsPage, {}) }), _jsx(Route, { path: "/states", element: _jsx(StatesPage, {}) }), _jsx(Route, { path: "/endpoints", element: _jsx(EndpointsPage, {}) })] }) }) }) }) }) }));
20
+ root.render(_jsx(StrictMode, { children: _jsx(MotiaStreamProvider, { address: address, children: _jsx(BrowserRouter, { children: _jsx(RootMotia, { children: _jsx(RouteWrapper, { children: _jsxs(Routes, { children: [_jsx(Route, { path: "/", element: _jsx(Index, {}) }), _jsx(Route, { path: "/flow/:id", element: _jsx(Flow, {}) }), _jsx(Route, { path: "/logs", element: _jsx(LogsPage, {}) }), _jsx(Route, { path: "/states", element: _jsx(StatesPage, {}) }), _jsx(Route, { path: "/endpoints", element: _jsx(EndpointsPage, {}) }), _jsx(Route, { path: "/traces", element: _jsx(TracesPage, {}) })] }) }) }) }) }) }));
20
21
  }
@@ -1,21 +1,10 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { FlowView } from '@/views/flow/flow-view';
3
- import { useCallback, useEffect, useState } from 'react';
4
3
  import { useParams } from 'react-router';
4
+ import { useFetchFlows } from '@/hooks/use-fetch-flows';
5
5
  export const Flow = () => {
6
6
  const { id } = useParams();
7
- const flowId = id;
8
- const [flow, setFlow] = useState(null);
9
- const [flowConfig, setFlowConfig] = useState(null);
10
- const fetchFlow = useCallback(() => {
11
- Promise.all([fetch(`/flows/${flowId}`), fetch(`/flows/${flowId}/config`)])
12
- .then(([flowRes, configRes]) => Promise.all([flowRes.json(), configRes.json()]))
13
- .then(([flow, config]) => {
14
- setFlow(flow);
15
- setFlowConfig(config);
16
- });
17
- }, [flowId]);
18
- useEffect(fetchFlow, [fetchFlow]);
7
+ const { flow, flowConfig } = useFetchFlows(id);
19
8
  if (!flow || flow.error)
20
9
  return (_jsx("div", { className: "w-full h-full bg-background flex flex-col items-center justify-center", children: _jsx("p", { children: flow?.error }) }));
21
10
  return (_jsx("div", { className: "w-full h-full bg-background", children: _jsx(FlowView, { flow: flow, flowConfig: flowConfig }) }));
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Button } from '@/components/ui/button';
2
+ import { Button } from '@motiadev/ui';
3
3
  export const Index = () => {
4
- return (_jsxs("div", { className: "flex flex-col items-center justify-center w-full h-full gap-10 bg-gradient-to-r from-background via-background to-muted", children: [_jsx("h1", { className: "text-5xl font-extrabold max-w-[600px] text-center text-foreground", children: "Code-first framework for intelligent workflows" }), _jsx("div", { className: "max-w-[600px] text-center text-xl font-medium text-muted-foreground", children: "Write in any language. Automate anything. From AI agents to backend automation, Motia runs event-driven workflows with zero overhead." }), _jsx("div", { className: "p-[1px] min-w-[600px] rounded-lg shadow-lg border border-border", children: _jsx("div", { className: "rounded-lg bg-card p-8 font-semibold text-xl min-h-[100px] flex items-center", children: _jsxs("div", { className: "flex items-center gap-2 font-mono", children: [_jsx("span", { className: "text-primary", children: "$" }), _jsx("span", { className: "text-card-foreground", children: "npx motia generate step" })] }) }) }), _jsxs("div", { className: "flex flex-col gap-8 items-center", children: [_jsx("span", { className: "text-muted-foreground text-xl", children: "or" }), _jsx("a", { href: "https://motia.dev/docs", target: "_blank", children: _jsx(Button, { size: "lg", className: "text-xl py-6 px-8", children: "Read developer docs" }) })] })] }));
4
+ return (_jsxs("div", { className: "flex flex-col items-center justify-center w-full h-full gap-10 bg-gradient-to-r from-background via-background to-muted", children: [_jsx("h1", { className: "text-5xl font-extrabold max-w-[600px] text-center text-foreground", children: "Unified Backend Framework for APIs, Events and AI Agents" }), _jsx("div", { className: "max-w-[600px] text-center text-xl font-medium text-muted-foreground", children: "Write in any language. Automate anything. From AI agents to backend automation, Motia runs event-driven workflows with zero overhead." }), _jsx("div", { className: "p-[1px] min-w-[600px] rounded-lg shadow-lg border border-border", children: _jsx("div", { className: "rounded-lg bg-card p-8 font-semibold text-xl min-h-[100px] flex items-center", children: _jsxs("div", { className: "flex items-center gap-2 font-mono", children: [_jsx("span", { className: "text-primary", children: "$" }), _jsx("span", { className: "text-card-foreground", children: "npx motia generate step" })] }) }) }), _jsxs("div", { className: "flex flex-col gap-8 items-center", children: [_jsx("span", { className: "text-muted-foreground text-xl", children: "or" }), _jsx("a", { href: "https://motia.dev/docs", target: "_blank", children: _jsx(Button, { size: "lg", className: "text-xl py-6 px-8", children: "Read developer docs" }) })] })] }));
5
5
  };
@@ -0,0 +1 @@
1
+ export declare const TracesPage: () => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ObservabilityStats } from '@/components/observability/observability-stats';
3
+ import { TraceTimeline } from '@/components/observability/trace-timeline';
4
+ import { useStreamGroup } from '@motiadev/stream-client-react';
5
+ import { useState } from 'react';
6
+ import { TracesGroups } from '../components/observability/traces-groups';
7
+ export const TracesPage = () => {
8
+ const [selectedGroupId, setSelectedGroupId] = useState(null);
9
+ const { data } = useStreamGroup({ streamName: 'motia-trace-group', groupId: 'default' });
10
+ const handleGroupSelect = (group) => {
11
+ setSelectedGroupId(group.id);
12
+ };
13
+ return (_jsxs("div", { className: "flex flex-col h-screen", children: [_jsx("div", { className: "border-b border-border p-4", children: _jsx(ObservabilityStats, { groups: data }) }), _jsxs("div", { className: "flex flex-1 overflow-hidden", children: [_jsx("div", { className: "w-1/3 border-r border-border overflow-auto", "data-testid": "traces-container", children: _jsx(TracesGroups, { groups: data, selectedGroupId: selectedGroupId, onGroupSelect: handleGroupSelect }) }), _jsxs("div", { className: "flex-1 overflow-auto", "data-testid": "trace-details", children: [selectedGroupId && _jsx(TraceTimeline, { groupId: selectedGroupId }), !selectedGroupId && (_jsx("div", { className: "flex items-center justify-center h-full text-muted-foreground", children: "Select a trace or trace group to view the timeline" }))] })] })] }));
14
+ };
@@ -0,0 +1,78 @@
1
+ export interface TraceGroup {
2
+ id: string;
3
+ correlationId: string | undefined;
4
+ name: string;
5
+ status: 'running' | 'completed' | 'failed';
6
+ startTime: number;
7
+ endTime?: number;
8
+ lastActivity: number;
9
+ metadata: {
10
+ completedSteps: number;
11
+ activeSteps: number;
12
+ totalSteps: number;
13
+ };
14
+ }
15
+ export interface Trace {
16
+ id: string;
17
+ name: string;
18
+ correlationId?: string;
19
+ parentTraceId?: string;
20
+ status: 'running' | 'completed' | 'failed';
21
+ startTime: number;
22
+ endTime?: number;
23
+ entryPoint: {
24
+ type: 'api' | 'event' | 'cron';
25
+ stepName: string;
26
+ };
27
+ events: TraceEvent[];
28
+ error?: TraceError;
29
+ }
30
+ export type TraceError = {
31
+ message: string;
32
+ code?: string | number;
33
+ stack?: string;
34
+ };
35
+ export type TraceEvent = StateEvent | EmitEvent | StreamEvent | LogEntry;
36
+ export type StateOperation = 'get' | 'getGroup' | 'set' | 'delete' | 'clear';
37
+ export type StreamOperation = 'get' | 'getGroup' | 'set' | 'delete' | 'clear' | 'send';
38
+ export interface StateEvent {
39
+ type: 'state';
40
+ timestamp: number;
41
+ operation: 'get' | 'getGroup' | 'set' | 'delete' | 'clear';
42
+ key?: string;
43
+ duration?: number;
44
+ data: any;
45
+ }
46
+ export interface EmitEvent {
47
+ type: 'emit';
48
+ timestamp: number;
49
+ topic: string;
50
+ success: boolean;
51
+ data: unknown;
52
+ }
53
+ export interface StreamEvent {
54
+ type: 'stream';
55
+ timestamp: number;
56
+ operation: StreamOperation;
57
+ streamName: string;
58
+ duration?: number;
59
+ data: {
60
+ groupId: string;
61
+ id: string;
62
+ data?: unknown;
63
+ };
64
+ calls: number;
65
+ }
66
+ export interface LogEntry {
67
+ type: 'log';
68
+ timestamp: number;
69
+ level: string;
70
+ message: string;
71
+ metadata?: unknown;
72
+ }
73
+ export interface ObservabilityStats {
74
+ total: number;
75
+ running: number;
76
+ completed: number;
77
+ failed: number;
78
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,15 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { LogConsole } from '@/components/logs/log-console';
3
- import { Background, BackgroundVariant, ReactFlow, useReactFlow } from '@xyflow/react';
3
+ import { Background, BackgroundVariant, ReactFlow } from '@xyflow/react';
4
4
  import { useCallback, useEffect, useMemo, useState } from 'react';
5
5
  import { ArrowHead } from './arrow-head';
6
6
  import { BaseEdge } from './base-edge';
7
7
  import { FlowLoader } from './flow-loader';
8
8
  import { useGetFlowState } from './hooks/use-get-flow-state';
9
9
  import { Legend } from './legend';
10
- import { useSaveWorkflowConfig } from './hooks/use-save-workflow-config';
11
10
  import { NodeOrganizer } from './node-organizer';
12
- import { useDebounced } from '@/hooks/use-debounced';
13
11
  import '@xyflow/react/dist/style.css';
14
12
  const edgeTypes = {
15
13
  base: BaseEdge,
@@ -17,8 +15,6 @@ const edgeTypes = {
17
15
  export const FlowView = ({ flow, flowConfig }) => {
18
16
  const { nodes, edges, onNodesChange, onEdgesChange, nodeTypes } = useGetFlowState(flow, flowConfig);
19
17
  const [initialized, setInitialized] = useState(false);
20
- const { getNodes } = useReactFlow();
21
- const { saveConfig } = useSaveWorkflowConfig(flow.id);
22
18
  const [hoveredType, setHoveredType] = useState(null);
23
19
  useEffect(() => setInitialized(false), [flow]);
24
20
  const onInitialized = useCallback(() => {
@@ -43,20 +39,9 @@ export const FlowView = ({ flow, flowConfig }) => {
43
39
  ...edge,
44
40
  className: getClassName(), // No argument means it's an edge
45
41
  })), [edges, getClassName]);
46
- const saveFlowConfig = useCallback(() => {
47
- const steps = getNodes().reduce((acc, node) => {
48
- if (node.data.filePath) {
49
- acc[node.data.filePath] = node.position;
50
- }
51
- return acc;
52
- }, {});
53
- return saveConfig(steps);
54
- }, [saveConfig, getNodes]);
55
- const debouncedSaveConfig = useDebounced(saveFlowConfig);
56
42
  const onNodesChangeHandler = useCallback((changes) => {
57
43
  onNodesChange(changes);
58
- debouncedSaveConfig();
59
- }, [onNodesChange, debouncedSaveConfig]);
44
+ }, [onNodesChange]);
60
45
  if (!nodeTypes) {
61
46
  return null;
62
47
  }
@@ -27,7 +27,10 @@ export type FlowResponse = {
27
27
  error?: string;
28
28
  };
29
29
  export type FlowConfigResponse = {
30
- [key: string]: Position;
30
+ id: string;
31
+ config: {
32
+ [stepName: string]: Position;
33
+ };
31
34
  };
32
35
  type FlowEdge = {
33
36
  id: string;
@@ -44,6 +47,6 @@ export declare const useGetFlowState: (flow: FlowResponse, flowConfig: FlowConfi
44
47
  edges: Edge<EdgeData>[];
45
48
  onNodesChange: import("@xyflow/react").OnNodesChange<Node<NodeData>>;
46
49
  onEdgesChange: import("@xyflow/react").OnEdgesChange<Edge<EdgeData>>;
47
- nodeTypes: Record<string, React.ComponentType<any>> | undefined;
50
+ nodeTypes: Record<string, React.ComponentType<any>>;
48
51
  };
49
52
  export {};