@motiadev/workbench 0.12.1-beta.159 → 0.13.0-beta.161

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.
@@ -1 +1 @@
1
- export declare const FlowPage: import("react").MemoExoticComponent<() => import("react/jsx-runtime").JSX.Element>;
1
+ export declare const FlowPage: import("react").MemoExoticComponent<() => import("react/jsx-runtime").JSX.Element | null>;
@@ -1,17 +1,25 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useStreamItem } from '@motiadev/stream-client-react';
3
+ import { Button, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from '@motiadev/ui';
3
4
  import { ReactFlowProvider } from '@xyflow/react';
5
+ import { ExternalLink, Workflow } from 'lucide-react';
4
6
  import { memo, useMemo } from 'react';
7
+ import { useShallow } from 'zustand/react/shallow';
8
+ import { motiaAnalytics } from '@/lib/motia-analytics';
5
9
  import { useFlowStore } from '@/stores/use-flow-store';
6
10
  import { FlowView } from './flow-view';
7
11
  export const FlowPage = memo(() => {
8
12
  const selectedFlowId = useFlowStore((state) => state.selectedFlowId);
13
+ const flows = useFlowStore(useShallow((state) => Object.values(state.flows)));
9
14
  const streamItemArgs = useMemo(() => ({ streamName: '__motia.flows', groupId: 'default', id: selectedFlowId ?? '' }), [selectedFlowId]);
10
15
  const { data: flow } = useStreamItem(streamItemArgs);
11
16
  const streamItemArgsConfig = useMemo(() => ({ streamName: '__motia.flowsConfig', groupId: 'default', id: selectedFlowId ?? '' }), [selectedFlowId]);
12
17
  const { data: flowConfig } = useStreamItem(streamItemArgsConfig);
13
- if (!flow || flow.error)
14
- return (_jsx("div", { className: "w-full h-full bg-background flex flex-col items-center justify-center", children: _jsx("p", { children: flow?.error }) }));
18
+ if (flows.length === 0 || flow?.error) {
19
+ return (_jsx("div", { className: "flex w-full h-full bg-background", children: _jsxs(Empty, { children: [_jsxs(EmptyHeader, { children: [_jsx(EmptyMedia, { variant: "icon", children: _jsx(Workflow, {}) }), flow?.error ? (_jsxs(_Fragment, { children: [_jsx(EmptyTitle, { children: "Error loading flow" }), _jsx(EmptyDescription, { children: flow.error })] })) : (_jsxs(_Fragment, { children: [_jsx(EmptyTitle, { children: "No flows registered" }), _jsx(EmptyDescription, { children: "You haven't registered any flows yet. Get started by registering your first flow." })] }))] }), _jsx(EmptyContent, { children: _jsx(Button, { variant: "link", asChild: true, size: "sm", children: _jsxs("a", { href: "https://www.motia.dev/docs/development-guide/flows", target: "_blank", rel: "noopener noreferrer", onClick: () => motiaAnalytics.track('flows_docs_link_clicked'), children: ["Learn more ", _jsx(ExternalLink, {})] }) }) })] }) }));
20
+ }
21
+ if (!flow)
22
+ return null;
15
23
  return (_jsx(ReactFlowProvider, { children: _jsx(FlowView, { flow: flow, flowConfig: flowConfig }) }));
16
24
  });
17
25
  FlowPage.displayName = 'FlowPage';
@@ -1 +1 @@
1
- export declare const FlowTabMenuItem: () => import("react/jsx-runtime").JSX.Element | null;
1
+ export declare const FlowTabMenuItem: () => import("react/jsx-runtime").JSX.Element;
@@ -10,12 +10,9 @@ export const FlowTabMenuItem = () => {
10
10
  const selectFlowId = useFlowStore((state) => state.selectFlowId);
11
11
  const flows = useFlowStore(useShallow((state) => Object.values(state.flows)));
12
12
  const selectedFlowId = useFlowStore((state) => state.selectedFlowId);
13
- if (flows.length === 0) {
14
- return null;
15
- }
16
13
  const handleFlowSelect = (flowId) => {
17
14
  selectFlowId(flowId);
18
15
  motiaAnalytics.track('flow_selected', { flow: flowId });
19
16
  };
20
- return (_jsxs("div", { className: "flex flex-row justify-center items-center gap-2 cursor-pointer", children: [_jsx(Workflow, {}), selectedFlowId ?? 'No flow selected', _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("div", { className: "flex flex-row justify-center items-center gap-2 cursor-pointer", "data-testid": "flows-dropdown-trigger", children: _jsx(ChevronsUpDown, { className: "size-4" }) }) }), _jsx(DropdownMenuContent, { className: "bg-background text-foreground flows-dropdown", children: flows.map((item) => (_jsx(DropdownMenuItem, { "data-testid": `dropdown-${item}`, className: "cursor-pointer gap-2 flow-link", onClick: () => handleFlowSelect(item), children: item }, `dropdown-${item}`))) })] })] }));
17
+ return (_jsxs("div", { className: "flex flex-row justify-center items-center gap-2 cursor-pointer", children: [_jsx(Workflow, {}), flows.length > 0 && selectedFlowId ? selectedFlowId : 'Flows', flows.length > 0 && (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("div", { className: "flex flex-row justify-center items-center gap-2 cursor-pointer", "data-testid": "flows-dropdown-trigger", children: _jsx(ChevronsUpDown, { className: "size-4" }) }) }), _jsx(DropdownMenuContent, { className: "bg-background text-foreground flows-dropdown", children: flows.map((item) => (_jsx(DropdownMenuItem, { "data-testid": `dropdown-${item}`, className: "cursor-pointer gap-2 flow-link", onClick: () => handleFlowSelect(item), children: item }, `dropdown-${item}`))) })] }))] }));
21
18
  };
@@ -5,6 +5,7 @@ const streamGroupArgs = { streamName: '__motia.flows', groupId: 'default' };
5
5
  export const useFetchFlows = () => {
6
6
  const setFlows = useFlowStore((state) => state.setFlows);
7
7
  const selectFlowId = useFlowStore((state) => state.selectFlowId);
8
+ const clearSelectedFlowId = useFlowStore((state) => state.clearSelectedFlowId);
8
9
  const selectedFlowId = useFlowStore((state) => state.selectedFlowId);
9
10
  const { data: flows } = useStreamGroup(streamGroupArgs);
10
11
  useEffect(() => {
@@ -12,9 +13,14 @@ export const useFetchFlows = () => {
12
13
  setFlows(flows.map((flow) => flow.id));
13
14
  }, [flows, setFlows]);
14
15
  useEffect(() => {
15
- if ((!selectedFlowId && flows.length > 0) ||
16
- (selectedFlowId && flows.length > 0 && !flows.find((flow) => flow.id === selectedFlowId))) {
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)) {
17
23
  selectFlowId(flows[0].id);
18
24
  }
19
- }, [flows, selectedFlowId, selectFlowId]);
25
+ }, [flows, selectedFlowId, selectFlowId, clearSelectedFlowId]);
20
26
  };
@@ -1,6 +1,7 @@
1
1
  type UseFlowStore = {
2
2
  selectedFlowId?: string;
3
3
  selectFlowId: (flowId: string) => void;
4
+ clearSelectedFlowId: () => void;
4
5
  flows: string[];
5
6
  setFlows: (flows: string[]) => void;
6
7
  };
@@ -9,6 +9,7 @@ export const useFlowStore = create(persist((set) => ({
9
9
  }
10
10
  return { selectedFlowId: flowId };
11
11
  }),
12
+ clearSelectedFlowId: () => set({ selectedFlowId: undefined }),
12
13
  }), {
13
14
  name: 'motia-flow-storage',
14
15
  storage: createJSONStorage(() => localStorage),