@motiadev/workbench 0.5.11-beta.120-167191 → 0.5.11-beta.120-722203
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/src/App.js +25 -3
- package/dist/src/components/tutorial/engine/workbench-xpath.d.ts +1 -0
- package/dist/src/components/tutorial/engine/workbench-xpath.js +2 -1
- package/dist/src/components/tutorial/hooks/use-tutorial-engine.d.ts +1 -0
- package/dist/src/components/tutorial/hooks/use-tutorial-engine.js +14 -8
- package/dist/src/components/tutorial/tutorial-button.js +3 -1
- package/dist/src/components/tutorial/tutorial.js +25 -1
- package/dist/src/components/ui/theme-toggle.js +8 -0
- package/dist/src/publicComponents/base-node/feature-card.d.ts +1 -0
- package/dist/src/stores/use-theme-store.d.ts +1 -2
- package/dist/tsconfig.app.tsbuildinfo +1 -1
- package/package.json +3 -3
package/dist/src/App.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { CollapsiblePanel, CollapsiblePanelGroup, Panel, TabsContent, TabsList, TabsTrigger } from '@motiadev/ui';
|
|
2
3
|
import { analytics } from '@/lib/analytics';
|
|
3
|
-
import { CollapsiblePanel, CollapsiblePanelGroup, TabsContent, TabsList, TabsTrigger } from '@motiadev/ui';
|
|
4
4
|
import { ReactFlowProvider } from '@xyflow/react';
|
|
5
5
|
import { File, GanttChart, Link2, LogsIcon } from 'lucide-react';
|
|
6
|
-
import { useCallback, useMemo } from 'react';
|
|
6
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
7
7
|
import { EndpointsPage } from './components/endpoints/endpoints-page';
|
|
8
8
|
import { FlowPage } from './components/flow/flow-page';
|
|
9
9
|
import { FlowTabMenuItem } from './components/flow/flow-tab-menu-item';
|
|
@@ -23,6 +23,7 @@ export const App = () => {
|
|
|
23
23
|
const tab = useTabsStore((state) => state.tab);
|
|
24
24
|
const setTopTab = useTabsStore((state) => state.setTopTab);
|
|
25
25
|
const setBottomTab = useTabsStore((state) => state.setBottomTab);
|
|
26
|
+
const [viewMode, setViewMode] = useState('system');
|
|
26
27
|
const tabChangeCallbacks = useMemo(() => ({
|
|
27
28
|
[TabLocation.TOP]: setTopTab,
|
|
28
29
|
[TabLocation.BOTTOM]: setBottomTab,
|
|
@@ -31,5 +32,26 @@ export const App = () => {
|
|
|
31
32
|
analytics.track(`${location} tab changed`, { [`new.${location}`]: newTab, tab });
|
|
32
33
|
tabChangeCallbacks[location](newTab);
|
|
33
34
|
}, [tabChangeCallbacks, tab]);
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
const url = new URL(window.location.href);
|
|
37
|
+
const viewMode = url.searchParams.get('view-mode');
|
|
38
|
+
if (viewMode) {
|
|
39
|
+
setViewMode(viewMode);
|
|
40
|
+
}
|
|
41
|
+
}, [setViewMode]);
|
|
42
|
+
if (viewMode === 'project') {
|
|
43
|
+
return (_jsxs("div", { className: "grid grid-rows-[auto_1fr] grid-cols-[1fr_auto] bg-background text-foreground h-screen ", children: [_jsx("main", { className: "m-2 overflow-hidden", role: "main", children: _jsx(Panel, { tabs: [
|
|
44
|
+
{
|
|
45
|
+
label: 'Flow',
|
|
46
|
+
labelComponent: _jsx(FlowTabMenuItem, {}),
|
|
47
|
+
content: (_jsx(ReactFlowProvider, { children: _jsx("div", { className: "h-[calc(100vh-100px)] w-full", children: _jsx(FlowPage, {}) }) })),
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
label: 'Endpoint',
|
|
51
|
+
labelComponent: (_jsxs(_Fragment, { children: [_jsx(Link2, {}), "Endpoint"] })),
|
|
52
|
+
content: _jsx(EndpointsPage, {}),
|
|
53
|
+
},
|
|
54
|
+
] }) }), _jsx("div", { id: APP_SIDEBAR_CONTAINER_ID })] }));
|
|
55
|
+
}
|
|
34
56
|
return (_jsxs("div", { className: "grid grid-rows-[auto_1fr] grid-cols-[1fr_auto] bg-background text-foreground h-screen", children: [_jsx("div", { className: "col-span-2", children: _jsx(Header, {}) }), _jsx("main", { className: "m-2 overflow-hidden", role: "main", children: _jsxs(CollapsiblePanelGroup, { autoSaveId: "app-panel", direction: "vertical", className: "gap-1 h-full", "aria-label": "Workbench panels", children: [_jsxs(CollapsiblePanel, { id: "top-panel", variant: 'tabs', defaultTab: tab.top, onTabChange: onTabChange(TabLocation.TOP), header: _jsxs(TabsList, { children: [_jsx(TabsTrigger, { value: "flow", "data-testid": "flows-link", children: _jsx(FlowTabMenuItem, {}) }), _jsxs(TabsTrigger, { value: "endpoint", "data-testid": "endpoints-link", className: "cursor-pointer", children: [_jsx(Link2, {}), "Endpoint"] })] }), children: [_jsx(TabsContent, { value: "flow", className: "h-full", asChild: true, children: _jsx(ReactFlowProvider, { children: _jsx(FlowPage, {}) }) }), _jsx(TabsContent, { value: "endpoint", asChild: true, children: _jsx(EndpointsPage, {}) })] }), _jsxs(CollapsiblePanel, { id: "bottom-panel", variant: 'tabs', defaultTab: tab.bottom, onTabChange: onTabChange(TabLocation.BOTTOM), header: _jsxs(TabsList, { children: [_jsxs(TabsTrigger, { value: "tracing", "data-testid": "traces-link", className: "cursor-pointer", children: [_jsx(GanttChart, {}), " Tracing"] }), _jsxs(TabsTrigger, { value: "logs", "data-testid": "logs-link", className: "cursor-pointer", children: [_jsx(LogsIcon, {}), "Logs"] }), _jsxs(TabsTrigger, { value: "states", "data-testid": "states-link", className: "cursor-pointer", children: [_jsx(File, {}), "States"] })] }), children: [_jsx(TabsContent, { value: "tracing", className: "max-h-fit", asChild: true, children: _jsx(TracesPage, {}) }), _jsx(TabsContent, { value: "logs", asChild: true, children: _jsx(LogsPage, {}) }), _jsx(TabsContent, { value: "states", asChild: true, children: _jsx(StatesPage, {}) })] })] }) }), _jsx("div", { id: APP_SIDEBAR_CONTAINER_ID }), _jsx(Tutorial, {})] }));
|
|
35
57
|
};
|
|
@@ -3,6 +3,7 @@ export const workbenchXPath = {
|
|
|
3
3
|
closePanelButton: '//div[@id="app-sidebar-container"]//button[@data-testid="close-panel"]',
|
|
4
4
|
bottomPanel: '//div[@id="bottom-panel"]',
|
|
5
5
|
flows: {
|
|
6
|
+
dropdownFlow: (flowId) => `//div[@data-testid="dropdown-${flowId}"]`,
|
|
6
7
|
feature: (featureId) => `//div[@data-feature-id="${featureId}"]`,
|
|
7
8
|
previewButton: (stepId) => `//button[@data-testid="open-code-preview-button-${stepId}"]`,
|
|
8
9
|
node: (stepId) => `//div[@data-testid="node-${stepId}"]`,
|
|
@@ -30,7 +31,7 @@ export const workbenchXPath = {
|
|
|
30
31
|
row: (index) => `(//tr[starts-with(@data-testid, 'item-')])[${index}]`,
|
|
31
32
|
},
|
|
32
33
|
links: {
|
|
33
|
-
flows: '//
|
|
34
|
+
flows: '//div[@data-testid="flows-dropdown-trigger"]',
|
|
34
35
|
endpoints: '//button[@data-testid="endpoints-link"]',
|
|
35
36
|
tracing: '//button[@data-testid="traces-link"]',
|
|
36
37
|
logs: '//button[@data-testid="logs-link"]',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from 'react';
|
|
2
|
-
import { waitForElementByXPath } from './tutorial-utils';
|
|
3
2
|
import { MotiaTutorial } from '../engine/tutorial-engine';
|
|
3
|
+
import { waitForElementByXPath } from './tutorial-utils';
|
|
4
4
|
export const useTutorialEngine = () => {
|
|
5
5
|
const ref = useRef(null);
|
|
6
6
|
const highlighterRef = useRef(null);
|
|
@@ -10,15 +10,11 @@ export const useTutorialEngine = () => {
|
|
|
10
10
|
const [link, setLink] = useState(undefined);
|
|
11
11
|
const [currentStep, setCurrentStep] = useState(0);
|
|
12
12
|
const [totalSteps, setTotalSteps] = useState(MotiaTutorial.steps.length);
|
|
13
|
+
const manualOpenRef = useRef(false);
|
|
13
14
|
const loading = useRef(false);
|
|
14
15
|
const currentStepRef = useRef(0);
|
|
15
16
|
const moveComponent = (x, y) => {
|
|
16
17
|
if (ref.current) {
|
|
17
|
-
if (ref.current.parentElement) {
|
|
18
|
-
ref.current.style.transition = 'all 0.3s ease-in-out';
|
|
19
|
-
ref.current.parentElement.style.opacity = '1';
|
|
20
|
-
ref.current.parentElement.style.display = 'block';
|
|
21
|
-
}
|
|
22
18
|
ref.current.style.position = 'absolute';
|
|
23
19
|
ref.current.style.left = `${x}px`;
|
|
24
20
|
ref.current.style.top = `${y}px`;
|
|
@@ -31,6 +27,11 @@ export const useTutorialEngine = () => {
|
|
|
31
27
|
onClose();
|
|
32
28
|
return;
|
|
33
29
|
}
|
|
30
|
+
if (container.parentElement) {
|
|
31
|
+
container.style.transition = 'all 0.3s ease-in-out';
|
|
32
|
+
container.parentElement.style.opacity = '1';
|
|
33
|
+
container.parentElement.style.display = 'block';
|
|
34
|
+
}
|
|
34
35
|
loading.current = true;
|
|
35
36
|
currentStepRef.current = stepNumber;
|
|
36
37
|
const step = MotiaTutorial.steps[stepNumber];
|
|
@@ -113,7 +114,7 @@ export const useTutorialEngine = () => {
|
|
|
113
114
|
// Fallback to center of screen
|
|
114
115
|
moveComponent(window.innerWidth / 2 - width / 2, window.innerHeight / 2 - height / 2);
|
|
115
116
|
}
|
|
116
|
-
},
|
|
117
|
+
}, 1);
|
|
117
118
|
loading.current = false;
|
|
118
119
|
}
|
|
119
120
|
};
|
|
@@ -147,9 +148,13 @@ export const useTutorialEngine = () => {
|
|
|
147
148
|
moveStep(0);
|
|
148
149
|
}
|
|
149
150
|
};
|
|
150
|
-
MotiaTutorial.onOpen(
|
|
151
|
+
MotiaTutorial.onOpen(() => {
|
|
152
|
+
manualOpenRef.current = true;
|
|
153
|
+
onOpen();
|
|
154
|
+
});
|
|
151
155
|
MotiaTutorial.onStepsRegistered(() => {
|
|
152
156
|
if (localStorage.getItem('motia-tutorial-closed') !== 'true') {
|
|
157
|
+
manualOpenRef.current = false;
|
|
153
158
|
onOpen();
|
|
154
159
|
}
|
|
155
160
|
});
|
|
@@ -166,5 +171,6 @@ export const useTutorialEngine = () => {
|
|
|
166
171
|
onClose,
|
|
167
172
|
moveStep,
|
|
168
173
|
currentStepRef,
|
|
174
|
+
manualOpenRef,
|
|
169
175
|
};
|
|
170
176
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { analytics } from '@/lib/analytics';
|
|
2
3
|
import { Button } from '@motiadev/ui';
|
|
3
4
|
import { Book } from 'lucide-react';
|
|
4
|
-
import { useTutorial } from './hooks/use-tutorial';
|
|
5
5
|
import { Tooltip } from '../ui/tooltip';
|
|
6
|
+
import { useTutorial } from './hooks/use-tutorial';
|
|
6
7
|
export const TutorialButton = () => {
|
|
7
8
|
const { open, steps } = useTutorial();
|
|
8
9
|
const isTutorialFlowMissing = steps.length === 0;
|
|
@@ -10,6 +11,7 @@ export const TutorialButton = () => {
|
|
|
10
11
|
if (!isTutorialFlowMissing) {
|
|
11
12
|
open();
|
|
12
13
|
}
|
|
14
|
+
analytics.track('tutorial_button_clicked', { isTutorialFlowMissing });
|
|
13
15
|
};
|
|
14
16
|
const trigger = (_jsxs(Button, { "data-testid": "tutorial-trigger", variant: "default", onClick: () => onTutorialButtonClick(), children: [_jsx(Book, { className: "h-4 w-4" }), "Tutorial"] }));
|
|
15
17
|
if (isTutorialFlowMissing) {
|
|
@@ -1,8 +1,32 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { analytics } from '@/lib/analytics';
|
|
2
3
|
import { useTutorialEngine } from './hooks/use-tutorial-engine';
|
|
3
4
|
import { TutorialStep } from './tutorial-step';
|
|
4
5
|
import './tutorial.css';
|
|
5
6
|
export const Tutorial = () => {
|
|
6
7
|
const engine = useTutorialEngine();
|
|
7
|
-
|
|
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
|
+
analytics.track('tutorial_completed', {
|
|
14
|
+
manualOpen: engine.manualOpenRef.current,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
analytics.track('tutorial_next_step', {
|
|
19
|
+
step: nextStep,
|
|
20
|
+
manualOpen: engine.manualOpenRef.current,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const onClose = () => {
|
|
25
|
+
analytics.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 })] }));
|
|
8
32
|
};
|
|
@@ -2,11 +2,19 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Moon, Sun } from 'lucide-react';
|
|
3
3
|
import { useThemeStore } from '@/stores/use-theme-store';
|
|
4
4
|
import { cn } from '@/lib/utils';
|
|
5
|
+
import { useEffect } from 'react';
|
|
5
6
|
export const ThemeToggle = () => {
|
|
6
7
|
const theme = useThemeStore((state) => state.theme);
|
|
7
8
|
const setTheme = useThemeStore((state) => state.setTheme);
|
|
8
9
|
const toggleTheme = () => {
|
|
9
10
|
setTheme(theme === 'light' ? 'dark' : 'light');
|
|
10
11
|
};
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
const url = new URL(window.location.href);
|
|
14
|
+
const colorScheme = url.searchParams.get('color-scheme');
|
|
15
|
+
if (colorScheme) {
|
|
16
|
+
setTheme(colorScheme);
|
|
17
|
+
}
|
|
18
|
+
}, [setTheme]);
|
|
11
19
|
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') }) })] }));
|
|
12
20
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
type Theme = 'dark' | 'light' | 'system';
|
|
1
|
+
export type Theme = 'dark' | 'light' | 'system';
|
|
2
2
|
export type ThemeState = {
|
|
3
3
|
theme: Theme;
|
|
4
4
|
setTheme: (theme: Theme) => void;
|
|
@@ -14,4 +14,3 @@ export declare const useThemeStore: import("zustand").UseBoundStore<Omit<import(
|
|
|
14
14
|
getOptions: () => Partial<import("zustand/middleware").PersistOptions<ThemeState, unknown>>;
|
|
15
15
|
};
|
|
16
16
|
}>;
|
|
17
|
-
export {};
|