@motiadev/workbench 0.0.6 → 0.0.7-build.20250529212805
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/LICENSE +21 -0
- package/README.md +95 -40
- package/dist/README.md +105 -0
- package/dist/index.d.ts +1 -2
- package/dist/index.html +31 -0
- package/dist/index.js +0 -1
- package/dist/middleware.d.ts +2 -2
- package/dist/middleware.js +10 -17
- package/dist/postcss.config.mjs +9 -0
- package/dist/src/components/app-sidebar.d.ts +0 -1
- package/dist/src/components/app-sidebar.js +15 -8
- package/dist/src/components/endpoints/endpoint-badge.d.ts +10 -0
- package/dist/src/components/endpoints/endpoint-badge.js +22 -0
- package/dist/src/components/endpoints/endpoint-call.d.ts +8 -0
- package/dist/src/components/endpoints/endpoint-call.js +57 -0
- package/dist/src/components/endpoints/endpoints.d.ts +1 -0
- package/dist/src/components/endpoints/endpoints.js +34 -0
- package/dist/src/components/endpoints/hooks/use-get-endpoints.d.ts +15 -0
- package/dist/src/components/endpoints/hooks/use-get-endpoints.js +8 -0
- package/dist/src/components/endpoints/hooks/use-json-schema-to-json.d.ts +4 -0
- package/dist/src/components/endpoints/hooks/use-json-schema-to-json.js +11 -0
- package/dist/src/components/endpoints/hooks/use-path-params.d.ts +1 -0
- package/dist/src/components/endpoints/hooks/use-path-params.js +4 -0
- package/dist/src/components/endpoints/hooks/use-state-stream.d.ts +4 -0
- package/dist/src/components/endpoints/hooks/use-state-stream.js +8 -0
- package/dist/src/components/endpoints/hooks/utils.d.ts +1 -0
- package/dist/src/components/endpoints/hooks/utils.js +29 -0
- package/dist/src/components/endpoints/response-body.d.ts +7 -0
- package/dist/src/components/endpoints/response-body.js +6 -0
- package/dist/src/components/endpoints/selected-endpoint.d.ts +7 -0
- package/dist/src/components/endpoints/selected-endpoint.js +7 -0
- package/dist/src/components/{log-console.d.ts → logs/log-console.d.ts} +0 -1
- package/dist/src/components/logs/log-console.js +69 -0
- package/dist/src/components/logs/log-detail.d.ts +8 -0
- package/dist/src/components/logs/log-detail.js +15 -0
- package/dist/src/components/logs/log-field.d.ts +8 -0
- package/dist/src/components/logs/log-field.js +20 -0
- package/dist/src/components/{log-level-badge.d.ts → logs/log-level-badge.d.ts} +2 -1
- package/dist/src/components/{log-level-badge.js → logs/log-level-badge.js} +2 -2
- package/dist/src/components/logs/log-level-dot.d.ts +4 -0
- package/dist/src/components/logs/log-level-dot.js +17 -0
- package/dist/src/components/logs/logs.d.ts +1 -0
- package/dist/src/components/logs/logs.js +18 -0
- package/dist/src/components/root-motia.d.ts +2 -0
- package/dist/src/components/root-motia.js +5 -0
- package/dist/src/components/states/hooks/states-hooks.d.ts +3 -0
- package/dist/src/components/states/hooks/states-hooks.js +36 -0
- package/dist/src/components/states/state-detail.d.ts +7 -0
- package/dist/src/components/states/state-detail.js +12 -0
- package/dist/src/components/states/state-value.d.ts +8 -0
- package/dist/src/components/states/state-value.js +51 -0
- package/dist/src/components/states/states.d.ts +1 -0
- package/dist/src/components/states/states.js +21 -0
- package/dist/src/components/ui/badge.d.ts +3 -4
- package/dist/src/components/ui/badge.js +4 -4
- package/dist/src/components/ui/button.d.ts +2 -3
- package/dist/src/components/ui/button.js +2 -3
- package/dist/src/components/ui/collapsible.d.ts +1 -2
- package/dist/src/components/ui/collapsible.js +1 -1
- package/dist/src/components/ui/dialog.d.ts +2 -3
- package/dist/src/components/ui/dialog.js +12 -12
- package/dist/src/components/ui/dropdown-menu.d.ts +25 -0
- package/dist/src/components/ui/dropdown-menu.js +50 -0
- package/dist/src/components/ui/input.d.ts +0 -1
- package/dist/src/components/ui/label.d.ts +3 -4
- package/dist/src/components/ui/label.js +6 -6
- package/dist/src/components/ui/select.d.ts +2 -3
- package/dist/src/components/ui/select.js +14 -15
- package/dist/src/components/ui/separator.d.ts +0 -1
- package/dist/src/components/ui/sheet.d.ts +1 -2
- package/dist/src/components/ui/sheet.js +2 -2
- package/dist/src/components/ui/sidebar.d.ts +12 -67
- package/dist/src/components/ui/sidebar.js +14 -219
- package/dist/src/components/ui/skeleton.d.ts +1 -1
- package/dist/src/components/ui/switch.d.ts +2 -3
- package/dist/src/components/ui/switch.js +4 -4
- package/dist/src/components/ui/table.d.ts +0 -1
- package/dist/src/components/ui/table.js +1 -1
- package/dist/src/components/ui/textarea.d.ts +1 -2
- package/dist/src/components/ui/textarea.js +4 -4
- package/dist/src/components/ui/theme-toggle.d.ts +2 -0
- package/dist/src/components/ui/theme-toggle.js +11 -0
- package/dist/src/components/ui/tooltip.d.ts +0 -1
- package/dist/src/hooks/use-debounced.d.ts +1 -0
- package/dist/src/hooks/use-debounced.js +18 -0
- package/dist/src/hooks/use-list-flows.d.ts +0 -2
- package/dist/src/hooks/use-list-flows.js +6 -10
- package/dist/src/hooks/use-log-listener.d.ts +1 -6
- package/dist/src/hooks/use-log-listener.js +3 -18
- package/dist/src/hooks/use-mobile.d.ts +0 -1
- package/dist/src/hooks/use-theme.d.ts +6 -0
- package/dist/src/hooks/use-theme.js +28 -0
- package/dist/src/index.css +169 -0
- package/dist/src/lib/utils.d.ts +0 -1
- package/dist/src/main.d.ts +0 -8
- package/dist/src/main.js +11 -7
- package/dist/src/publicComponents/api-node.d.ts +2 -5
- package/dist/src/publicComponents/api-node.js +3 -3
- package/dist/src/publicComponents/base-handle.d.ts +1 -1
- package/dist/src/publicComponents/base-handle.js +5 -2
- package/dist/src/publicComponents/base-node.d.ts +5 -5
- package/dist/src/publicComponents/base-node.js +13 -8
- package/dist/src/publicComponents/colorMap.d.ts +6 -0
- package/dist/src/publicComponents/colorMap.js +6 -0
- package/dist/src/publicComponents/components/header-bar.d.ts +11 -0
- package/dist/src/publicComponents/components/header-bar.js +15 -0
- package/dist/src/publicComponents/cron-node.d.ts +2 -0
- package/dist/src/publicComponents/cron-node.js +7 -0
- package/dist/src/publicComponents/emits.d.ts +1 -1
- package/dist/src/publicComponents/emits.js +2 -2
- package/dist/src/publicComponents/event-node.d.ts +0 -2
- package/dist/src/publicComponents/event-node.js +3 -5
- package/dist/src/publicComponents/node-details.d.ts +17 -0
- package/dist/src/publicComponents/node-details.js +19 -0
- package/dist/src/publicComponents/node-props.d.ts +5 -3
- package/dist/src/publicComponents/noop-node.d.ts +0 -1
- package/dist/src/publicComponents/noop-node.js +1 -1
- package/dist/src/publicComponents/subscribe.d.ts +2 -3
- package/dist/src/publicComponents/subscribe.js +2 -2
- package/dist/src/route-wrapper.d.ts +2 -4
- package/dist/src/route-wrapper.js +2 -2
- package/dist/src/routes/endpoints-page.d.ts +1 -0
- package/dist/src/routes/endpoints-page.js +5 -0
- package/dist/src/routes/flow.d.ts +1 -0
- package/dist/src/routes/flow.js +22 -0
- package/dist/src/routes/index.d.ts +1 -2
- package/dist/src/routes/index.js +5 -8
- package/dist/src/routes/logs-page.d.ts +1 -0
- package/dist/src/routes/logs-page.js +12 -0
- package/dist/src/routes/states-page.d.ts +1 -0
- package/dist/src/routes/states-page.js +5 -0
- package/dist/src/stores/use-logs.d.ts +3 -2
- package/dist/src/stores/use-logs.js +52 -6
- package/dist/src/views/flow/arrow-head.d.ts +2 -2
- package/dist/src/views/flow/arrow-head.js +5 -1
- package/dist/src/views/flow/base-edge.d.ts +0 -1
- package/dist/src/views/flow/base-edge.js +25 -10
- package/dist/src/views/flow/flow-loader.d.ts +0 -1
- package/dist/src/views/flow/flow-loader.js +1 -1
- package/dist/src/views/flow/flow-view.d.ts +7 -2
- package/dist/src/views/flow/flow-view.js +44 -20
- package/dist/src/views/flow/hooks/use-get-flow-state.d.ts +14 -5
- package/dist/src/views/flow/hooks/use-get-flow-state.js +17 -8
- package/dist/src/views/flow/hooks/use-organize-nodes.d.ts +0 -1
- package/dist/src/views/flow/hooks/use-save-workflow-config.d.ts +9 -0
- package/dist/src/views/flow/hooks/use-save-workflow-config.js +23 -0
- package/dist/src/views/flow/legend.d.ts +3 -3
- package/dist/src/views/flow/legend.js +49 -39
- package/dist/src/views/flow/node-organizer.d.ts +1 -1
- package/dist/src/views/flow/node-organizer.js +4 -2
- package/dist/src/views/flow/nodes/api-flow-node.d.ts +0 -1
- package/dist/src/views/flow/nodes/event-flow-node.d.ts +0 -1
- package/dist/src/views/flow/nodes/language-indicator.d.ts +0 -1
- package/dist/src/views/flow/nodes/language-indicator.js +7 -7
- package/dist/src/views/flow/nodes/nodes.types.d.ts +39 -6
- package/dist/src/views/flow/nodes/noop-flow-node.d.ts +0 -1
- package/dist/tailwind.config.js +9 -77
- package/dist/tsconfig.app.tsbuildinfo +1 -1
- package/dist/tsconfig.node.tsbuildinfo +1 -1
- package/package.json +36 -42
- package/postcss.config.mjs +9 -0
- package/dist/index.d.ts.map +0 -1
- package/dist/middleware.d.ts.map +0 -1
- package/dist/src/components/app-sidebar.d.ts.map +0 -1
- package/dist/src/components/log-console.d.ts.map +0 -1
- package/dist/src/components/log-console.js +0 -20
- package/dist/src/components/log-level-badge.d.ts.map +0 -1
- package/dist/src/components/ui/badge.d.ts.map +0 -1
- package/dist/src/components/ui/button.d.ts.map +0 -1
- package/dist/src/components/ui/collapsible.d.ts.map +0 -1
- package/dist/src/components/ui/dialog.d.ts.map +0 -1
- package/dist/src/components/ui/input.d.ts.map +0 -1
- package/dist/src/components/ui/label.d.ts.map +0 -1
- package/dist/src/components/ui/select.d.ts.map +0 -1
- package/dist/src/components/ui/separator.d.ts.map +0 -1
- package/dist/src/components/ui/sheet.d.ts.map +0 -1
- package/dist/src/components/ui/sidebar.d.ts.map +0 -1
- package/dist/src/components/ui/skeleton.d.ts.map +0 -1
- package/dist/src/components/ui/switch.d.ts.map +0 -1
- package/dist/src/components/ui/table.d.ts.map +0 -1
- package/dist/src/components/ui/textarea.d.ts.map +0 -1
- package/dist/src/components/ui/tooltip.d.ts.map +0 -1
- package/dist/src/hooks/use-list-flows.d.ts.map +0 -1
- package/dist/src/hooks/use-log-listener.d.ts.map +0 -1
- package/dist/src/hooks/use-mobile.d.ts.map +0 -1
- package/dist/src/lib/utils.d.ts.map +0 -1
- package/dist/src/main.d.ts.map +0 -1
- package/dist/src/publicComponents/api-node.d.ts.map +0 -1
- package/dist/src/publicComponents/base-handle.d.ts.map +0 -1
- package/dist/src/publicComponents/base-node.d.ts.map +0 -1
- package/dist/src/publicComponents/emits.d.ts.map +0 -1
- package/dist/src/publicComponents/event-node.d.ts.map +0 -1
- package/dist/src/publicComponents/node-props.d.ts.map +0 -1
- package/dist/src/publicComponents/noop-node.d.ts.map +0 -1
- package/dist/src/publicComponents/subscribe.d.ts.map +0 -1
- package/dist/src/route-wrapper.d.ts.map +0 -1
- package/dist/src/routeTree.gen.d.ts +0 -53
- package/dist/src/routeTree.gen.d.ts.map +0 -1
- package/dist/src/routeTree.gen.js +0 -45
- package/dist/src/routes/__root.d.ts +0 -2
- package/dist/src/routes/__root.d.ts.map +0 -1
- package/dist/src/routes/__root.js +0 -15
- package/dist/src/routes/flow/$id.d.ts +0 -4
- package/dist/src/routes/flow/$id.d.ts.map +0 -1
- package/dist/src/routes/flow/$id.js +0 -15
- package/dist/src/routes/index.d.ts.map +0 -1
- package/dist/src/stores/use-logs.d.ts.map +0 -1
- package/dist/src/views/flow/arrow-head.d.ts.map +0 -1
- package/dist/src/views/flow/base-edge.d.ts.map +0 -1
- package/dist/src/views/flow/flow-loader.d.ts.map +0 -1
- package/dist/src/views/flow/flow-view.d.ts.map +0 -1
- package/dist/src/views/flow/hooks/use-get-flow-state.d.ts.map +0 -1
- package/dist/src/views/flow/hooks/use-organize-nodes.d.ts.map +0 -1
- package/dist/src/views/flow/legend.d.ts.map +0 -1
- package/dist/src/views/flow/node-organizer.d.ts.map +0 -1
- package/dist/src/views/flow/nodes/api-flow-node.d.ts.map +0 -1
- package/dist/src/views/flow/nodes/event-flow-node.d.ts.map +0 -1
- package/dist/src/views/flow/nodes/json-schema-form.d.ts +0 -9
- package/dist/src/views/flow/nodes/json-schema-form.d.ts.map +0 -1
- package/dist/src/views/flow/nodes/json-schema-form.js +0 -35
- package/dist/src/views/flow/nodes/language-indicator.d.ts.map +0 -1
- package/dist/src/views/flow/nodes/nodes.types.d.ts.map +0 -1
- package/dist/src/views/flow/nodes/noop-flow-node.d.ts.map +0 -1
- package/dist/tailwind.config.d.ts +0 -4
- package/dist/tailwind.config.d.ts.map +0 -1
- package/dist/vite.config.d.ts +0 -11
- package/dist/vite.config.d.ts.map +0 -1
- package/dist/vite.config.js +0 -18
- package/eslint.config.js +0 -28
- package/index.html +0 -19
- package/index.tsx +0 -10
- package/middleware.ts +0 -48
- package/postcss.config.js +0 -6
- package/src/assets/.empty +0 -0
- package/src/components/app-sidebar.tsx +0 -55
- package/src/components/log-console.tsx +0 -76
- package/src/components/log-level-badge.tsx +0 -12
- package/src/components/ui/badge.tsx +0 -31
- package/src/components/ui/button.tsx +0 -47
- package/src/components/ui/collapsible.tsx +0 -9
- package/src/components/ui/dialog.tsx +0 -120
- package/src/components/ui/input.tsx +0 -21
- package/src/components/ui/label.tsx +0 -26
- package/src/components/ui/select.tsx +0 -157
- package/src/components/ui/separator.tsx +0 -22
- package/src/components/ui/sheet.tsx +0 -106
- package/src/components/ui/sidebar.tsx +0 -637
- package/src/components/ui/skeleton.tsx +0 -7
- package/src/components/ui/switch.tsx +0 -27
- package/src/components/ui/table.tsx +0 -76
- package/src/components/ui/textarea.tsx +0 -22
- package/src/components/ui/tooltip.tsx +0 -32
- package/src/hooks/use-list-flows.tsx +0 -20
- package/src/hooks/use-log-listener.tsx +0 -32
- package/src/hooks/use-mobile.tsx +0 -19
- package/src/index.css +0 -190
- package/src/lib/utils.ts +0 -6
- package/src/main.tsx +0 -28
- package/src/publicComponents/api-node.tsx +0 -28
- package/src/publicComponents/base-handle.tsx +0 -43
- package/src/publicComponents/base-node.tsx +0 -57
- package/src/publicComponents/emits.tsx +0 -22
- package/src/publicComponents/event-node.tsx +0 -36
- package/src/publicComponents/node-props.tsx +0 -15
- package/src/publicComponents/noop-node.tsx +0 -21
- package/src/publicComponents/subscribe.tsx +0 -19
- package/src/route-wrapper.tsx +0 -9
- package/src/routeTree.gen.ts +0 -109
- package/src/routes/__root.tsx +0 -26
- package/src/routes/flow/$id.tsx +0 -21
- package/src/routes/index.tsx +0 -13
- package/src/stores/use-logs.ts +0 -22
- package/src/views/flow/arrow-head.tsx +0 -13
- package/src/views/flow/base-edge.tsx +0 -31
- package/src/views/flow/flow-loader.tsx +0 -3
- package/src/views/flow/flow-view.tsx +0 -72
- package/src/views/flow/hooks/use-get-flow-state.tsx +0 -93
- package/src/views/flow/hooks/use-organize-nodes.ts +0 -60
- package/src/views/flow/legend.tsx +0 -96
- package/src/views/flow/node-organizer.tsx +0 -70
- package/src/views/flow/nodes/api-flow-node.tsx +0 -6
- package/src/views/flow/nodes/event-flow-node.tsx +0 -6
- package/src/views/flow/nodes/json-schema-form.tsx +0 -110
- package/src/views/flow/nodes/language-indicator.tsx +0 -74
- package/src/views/flow/nodes/nodes.types.ts +0 -36
- package/src/views/flow/nodes/noop-flow-node.tsx +0 -6
- package/src/vite-env.d.ts +0 -1
- package/tailwind.config.ts +0 -75
- package/tsconfig.app.json +0 -32
- package/tsconfig.json +0 -14
- package/tsconfig.node.json +0 -32
- package/tsconfig.node.tsbuildinfo +0 -1
- package/vite.config.ts +0 -14
- /package/{components.json → dist/components.json} +0 -0
- /package/{public → dist/public}/.empty +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Motia
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,50 +1,105 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @motiadev/workbench
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A web-based interface for building, visualizing, and managing Motia workflows.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Overview
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
|
7
|
+
`@motiadev/workbench` provides a powerful visual interface for Motia workflows, offering:
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
- Flow visualization with interactive diagrams
|
|
10
|
+
- Real-time log monitoring
|
|
11
|
+
- State inspection and management
|
|
12
|
+
- API testing capabilities
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
## Installation
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
```bash
|
|
17
|
+
npm install @motiadev/workbench
|
|
18
|
+
# or
|
|
19
|
+
yarn add @motiadev/workbench
|
|
20
|
+
# or
|
|
21
|
+
pnpm add @motiadev/workbench
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
The Workbench is automatically integrated when you run a Motia project in development mode:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx motia dev
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
This starts the development server and makes the Workbench available at `http://localhost:3000` by default.
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
### Flow Visualization
|
|
37
|
+
|
|
38
|
+
Visualize your workflows as interactive diagrams, showing the connections between steps and the flow of events through your application.
|
|
39
|
+
|
|
40
|
+
### Log Monitoring
|
|
41
|
+
|
|
42
|
+
Monitor logs in real-time with filtering capabilities, log level indicators, and detailed log inspection.
|
|
43
|
+
|
|
44
|
+
### State Management
|
|
45
|
+
|
|
46
|
+
Inspect and manage application state, with support for viewing complex nested objects and state changes over time.
|
|
15
47
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
48
|
+
### API Testing
|
|
49
|
+
|
|
50
|
+
Test API endpoints directly from the Workbench interface, with support for different HTTP methods and request bodies.
|
|
51
|
+
|
|
52
|
+
## Components
|
|
53
|
+
|
|
54
|
+
The package exports several components that can be used to customize the visualization of your workflows:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import {
|
|
58
|
+
EventNode,
|
|
59
|
+
ApiNode,
|
|
60
|
+
NoopNode,
|
|
61
|
+
BaseNode,
|
|
62
|
+
BaseHandle
|
|
63
|
+
} from '@motiadev/workbench'
|
|
26
64
|
```
|
|
27
65
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
66
|
+
### Node Components
|
|
67
|
+
|
|
68
|
+
- `EventNode`: Visualizes event-based steps
|
|
69
|
+
- `ApiNode`: Visualizes API endpoint steps
|
|
70
|
+
- `NoopNode`: A placeholder node with no specific functionality
|
|
71
|
+
- `BaseNode`: Base component for creating custom node types
|
|
72
|
+
- `BaseHandle`: Connection point component for nodes
|
|
73
|
+
|
|
74
|
+
## Customization
|
|
75
|
+
|
|
76
|
+
You can customize the appearance and behavior of the Workbench by creating custom node components:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { BaseNode, Position } from '@motiadev/workbench'
|
|
80
|
+
|
|
81
|
+
export const CustomNode = ({ data, ...props }) => {
|
|
82
|
+
return (
|
|
83
|
+
<BaseNode
|
|
84
|
+
{...props}
|
|
85
|
+
title="Custom Node"
|
|
86
|
+
color="#8B5CF6"
|
|
87
|
+
>
|
|
88
|
+
<div className="p-4">
|
|
89
|
+
{data.customContent}
|
|
90
|
+
</div>
|
|
91
|
+
</BaseNode>
|
|
92
|
+
)
|
|
93
|
+
}
|
|
50
94
|
```
|
|
95
|
+
|
|
96
|
+
## Technical Details
|
|
97
|
+
|
|
98
|
+
- Built with React and TypeScript
|
|
99
|
+
- Uses [XY Flow](https://xyflow.com/) for flow visualization
|
|
100
|
+
- Styled with Tailwind CSS and shadcn/ui components
|
|
101
|
+
- Supports real-time updates via WebSockets
|
|
102
|
+
|
|
103
|
+
## License
|
|
104
|
+
|
|
105
|
+
This package is part of the Motia framework and is licensed under the same terms.
|
package/dist/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# @motiadev/workbench
|
|
2
|
+
|
|
3
|
+
A web-based interface for building, visualizing, and managing Motia workflows.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`@motiadev/workbench` provides a powerful visual interface for Motia workflows, offering:
|
|
8
|
+
|
|
9
|
+
- Flow visualization with interactive diagrams
|
|
10
|
+
- Real-time log monitoring
|
|
11
|
+
- State inspection and management
|
|
12
|
+
- API testing capabilities
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @motiadev/workbench
|
|
18
|
+
# or
|
|
19
|
+
yarn add @motiadev/workbench
|
|
20
|
+
# or
|
|
21
|
+
pnpm add @motiadev/workbench
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
The Workbench is automatically integrated when you run a Motia project in development mode:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx motia dev
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
This starts the development server and makes the Workbench available at `http://localhost:3000` by default.
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
### Flow Visualization
|
|
37
|
+
|
|
38
|
+
Visualize your workflows as interactive diagrams, showing the connections between steps and the flow of events through your application.
|
|
39
|
+
|
|
40
|
+
### Log Monitoring
|
|
41
|
+
|
|
42
|
+
Monitor logs in real-time with filtering capabilities, log level indicators, and detailed log inspection.
|
|
43
|
+
|
|
44
|
+
### State Management
|
|
45
|
+
|
|
46
|
+
Inspect and manage application state, with support for viewing complex nested objects and state changes over time.
|
|
47
|
+
|
|
48
|
+
### API Testing
|
|
49
|
+
|
|
50
|
+
Test API endpoints directly from the Workbench interface, with support for different HTTP methods and request bodies.
|
|
51
|
+
|
|
52
|
+
## Components
|
|
53
|
+
|
|
54
|
+
The package exports several components that can be used to customize the visualization of your workflows:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import {
|
|
58
|
+
EventNode,
|
|
59
|
+
ApiNode,
|
|
60
|
+
NoopNode,
|
|
61
|
+
BaseNode,
|
|
62
|
+
BaseHandle
|
|
63
|
+
} from '@motiadev/workbench'
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Node Components
|
|
67
|
+
|
|
68
|
+
- `EventNode`: Visualizes event-based steps
|
|
69
|
+
- `ApiNode`: Visualizes API endpoint steps
|
|
70
|
+
- `NoopNode`: A placeholder node with no specific functionality
|
|
71
|
+
- `BaseNode`: Base component for creating custom node types
|
|
72
|
+
- `BaseHandle`: Connection point component for nodes
|
|
73
|
+
|
|
74
|
+
## Customization
|
|
75
|
+
|
|
76
|
+
You can customize the appearance and behavior of the Workbench by creating custom node components:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { BaseNode, Position } from '@motiadev/workbench'
|
|
80
|
+
|
|
81
|
+
export const CustomNode = ({ data, ...props }) => {
|
|
82
|
+
return (
|
|
83
|
+
<BaseNode
|
|
84
|
+
{...props}
|
|
85
|
+
title="Custom Node"
|
|
86
|
+
color="#8B5CF6"
|
|
87
|
+
>
|
|
88
|
+
<div className="p-4">
|
|
89
|
+
{data.customContent}
|
|
90
|
+
</div>
|
|
91
|
+
</BaseNode>
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Technical Details
|
|
97
|
+
|
|
98
|
+
- Built with React and TypeScript
|
|
99
|
+
- Uses [XY Flow](https://xyflow.com/) for flow visualization
|
|
100
|
+
- Styled with Tailwind CSS and shadcn/ui components
|
|
101
|
+
- Supports real-time updates via WebSockets
|
|
102
|
+
|
|
103
|
+
## License
|
|
104
|
+
|
|
105
|
+
This package is part of the Motia framework and is licensed under the same terms.
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,5 @@ export { BaseNode } from './src/publicComponents/base-node';
|
|
|
5
5
|
export { BaseHandle } from './src/publicComponents/base-handle';
|
|
6
6
|
export { Position } from '@xyflow/react';
|
|
7
7
|
export type { EventNodeData, ApiNodeData } from './src/views/flow/nodes/nodes.types';
|
|
8
|
-
export
|
|
8
|
+
export type { ApiNodeProps, BaseNodeProps, CronNodeProps, EventNodeProps, NoopNodeProps, } from './src/publicComponents/node-props';
|
|
9
9
|
export { Button } from './src/components/ui/button';
|
|
10
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.html
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
|
|
6
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
7
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
8
|
+
<link
|
|
9
|
+
href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap"
|
|
10
|
+
rel="stylesheet"
|
|
11
|
+
/>
|
|
12
|
+
<script src="https://cdn.amplitude.com/libs/analytics-browser-2.11.1-min.js.gz"></script>
|
|
13
|
+
<script>
|
|
14
|
+
window.amplitude.init('ab2408031a38aa5cb85587a27ecfc69c', {
|
|
15
|
+
autocapture: {
|
|
16
|
+
fileDownloads: false,
|
|
17
|
+
formInteractions: false,
|
|
18
|
+
},
|
|
19
|
+
fetchRemoteConfig: true,
|
|
20
|
+
recording: false
|
|
21
|
+
})
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
25
|
+
<title>Motia</title>
|
|
26
|
+
</head>
|
|
27
|
+
<body class="dark">
|
|
28
|
+
<div id="root"></div>
|
|
29
|
+
<script type="module" src="/src/main.js"></script>
|
|
30
|
+
</body>
|
|
31
|
+
</html>
|
package/dist/index.js
CHANGED
|
@@ -4,5 +4,4 @@ export { NoopNode } from './src/publicComponents/noop-node';
|
|
|
4
4
|
export { BaseNode } from './src/publicComponents/base-node';
|
|
5
5
|
export { BaseHandle } from './src/publicComponents/base-handle';
|
|
6
6
|
export { Position } from '@xyflow/react';
|
|
7
|
-
export * from './src/publicComponents/node-props';
|
|
8
7
|
export { Button } from './src/components/ui/button';
|
package/dist/middleware.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import type { Express } from 'express';
|
|
2
|
+
export declare const applyMiddleware: (app: Express) => Promise<void>;
|
package/dist/middleware.js
CHANGED
|
@@ -4,39 +4,32 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.applyMiddleware = void 0;
|
|
7
|
-
const
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const vite_1 = require("vite");
|
|
10
|
+
const plugin_react_1 = __importDefault(require("@vitejs/plugin-react"));
|
|
8
11
|
const applyMiddleware = async (app) => {
|
|
9
|
-
|
|
10
|
-
const fs = await import('fs');
|
|
11
|
-
const path = await import('path');
|
|
12
|
-
const { default: Express } = await import('express');
|
|
13
|
-
const { createServer } = await import('vite');
|
|
14
|
-
const { default: autoprefixer } = await import('autoprefixer');
|
|
15
|
-
const { default: tailwindcss } = await import('tailwindcss');
|
|
16
|
-
const vite = await createServer({
|
|
12
|
+
const vite = await (0, vite_1.createServer)({
|
|
17
13
|
appType: 'spa',
|
|
18
14
|
root: __dirname,
|
|
19
15
|
server: {
|
|
20
16
|
middlewareMode: true,
|
|
17
|
+
host: true,
|
|
21
18
|
fs: {
|
|
22
|
-
allow: [__dirname,
|
|
19
|
+
allow: [__dirname, path_1.default.join(process.cwd(), './steps')],
|
|
23
20
|
},
|
|
24
21
|
},
|
|
25
22
|
resolve: {
|
|
26
|
-
alias: { '@':
|
|
27
|
-
},
|
|
28
|
-
css: {
|
|
29
|
-
postcss: {
|
|
30
|
-
plugins: [autoprefixer(), tailwindcss(tailwind_config_1.default)],
|
|
31
|
-
},
|
|
23
|
+
alias: { '@': path_1.default.resolve(__dirname, './src') },
|
|
32
24
|
},
|
|
25
|
+
plugins: [(0, plugin_react_1.default)()],
|
|
33
26
|
});
|
|
34
27
|
app.use(vite.middlewares);
|
|
35
28
|
app.use('*', async (req, res, next) => {
|
|
36
29
|
const url = req.originalUrl;
|
|
37
30
|
console.log('[UI] Request', { url });
|
|
38
31
|
try {
|
|
39
|
-
const index =
|
|
32
|
+
const index = fs_1.default.readFileSync(path_1.default.resolve(__dirname, 'index.html'), 'utf-8');
|
|
40
33
|
const html = await vite.transformIndexHtml(url, index);
|
|
41
34
|
res.status(200).set({ 'Content-Type': 'text/html' }).end(html);
|
|
42
35
|
}
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useListFlows } from '@/hooks/use-list-flows';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { File, Link2, Logs, Workflow } from 'lucide-react';
|
|
4
|
+
import { Link, useLocation } from 'react-router';
|
|
5
|
+
import { Sidebar, SidebarButton, SidebarGroup } from './ui/sidebar';
|
|
6
|
+
import { Badge } from './ui/badge';
|
|
7
|
+
import { useLogs } from '@/stores/use-logs';
|
|
8
|
+
const BadgeCount = () => {
|
|
9
|
+
const unreadLogsCount = useLogs((state) => state.unreadLogsCount);
|
|
10
|
+
if (!unreadLogsCount) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
return _jsx(Badge, { variant: "red-rounded", children: unreadLogsCount });
|
|
14
|
+
};
|
|
6
15
|
export const AppSidebar = () => {
|
|
7
16
|
const { flows } = useListFlows();
|
|
8
|
-
const
|
|
9
|
-
const isActive = (flowId) => {
|
|
10
|
-
|
|
11
|
-
};
|
|
12
|
-
return (_jsxs(Sidebar, { children: [_jsx(SidebarHeader, {}), _jsx(SidebarContent, { children: _jsxs(SidebarGroup, { children: [_jsx(SidebarGroupLabel, { children: "Flows" }), _jsx(SidebarGroupContent, { children: _jsx(SidebarMenu, { children: flows.map((flow) => (_jsx(SidebarMenuItem, { children: _jsx(SidebarMenuButton, { asChild: true, className: "cursor-pointer", isActive: isActive(flow.id), children: _jsxs(Link, { to: "/flow/$id", params: { id: flow.id }, className: "flex items-center gap-2", "data-testid": `flow-link-${flow.id}`, children: [_jsx(Workflow, {}), _jsx("span", { children: flow.name })] }) }) }, flow.id))) }) })] }) }), _jsx(SidebarFooter, {})] }));
|
|
17
|
+
const { pathname } = useLocation();
|
|
18
|
+
const isActive = (flowId) => pathname.includes(`/flow/${flowId}`);
|
|
19
|
+
return (_jsxs(Sidebar, { children: [_jsxs(SidebarGroup, { testId: "motia-title", title: "Motia", children: [_jsx(Link, { "data-testid": "logs-link", to: "/logs", children: _jsxs(SidebarButton, { isActive: pathname === '/logs', icon: _jsx(Logs, { className: "w-4 h-4" }), children: ["Logs", pathname !== '/logs' && _jsx(BadgeCount, {})] }) }), _jsx(Link, { "data-testid": "states-link", to: "/states", children: _jsx(SidebarButton, { isActive: pathname === '/states', icon: _jsx(File, { className: "w-4 h-4" }), children: "States" }) }), _jsx(Link, { "data-testid": "endpoints-link", to: "/endpoints", children: _jsx(SidebarButton, { isActive: pathname === '/endpoints', icon: _jsx(Link2, { className: "w-4 h-4" }), children: "Endpoints" }) })] }), _jsx(SidebarGroup, { testId: "flows-title", title: "Flows", children: flows.map((flow) => (_jsx(Link, { "data-testid": `flow-${flow.name}-link`, to: `/flow/${flow.id}`, children: _jsx(SidebarButton, { isActive: isActive(flow.id), icon: _jsx(Workflow, { className: "w-4 h-4" }), children: flow.name }) }, flow.id))) })] }));
|
|
13
20
|
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type VariantProps } from 'class-variance-authority';
|
|
3
|
+
declare const badgeVariants: (props?: ({
|
|
4
|
+
variant?: "POST" | "GET" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS" | null | undefined;
|
|
5
|
+
defaultVariants?: "variant" | null | undefined;
|
|
6
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
|
+
interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {
|
|
8
|
+
}
|
|
9
|
+
export declare function EndpointBadge({ className, variant, ...props }: BadgeProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cva } from 'class-variance-authority';
|
|
3
|
+
import { cn } from '@/lib/utils';
|
|
4
|
+
const badgeVariants = cva('inline-flex items-center rounded-lg border px-2 py-1 text-xs font-bold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', {
|
|
5
|
+
variants: {
|
|
6
|
+
variant: {
|
|
7
|
+
POST: 'bg-sky-500/50 text-sky-100',
|
|
8
|
+
GET: 'bg-lime-500/50 text-lime-100',
|
|
9
|
+
PUT: 'bg-yellow-500/50 text-yellow-100',
|
|
10
|
+
DELETE: 'bg-red-500/50 text-red-100',
|
|
11
|
+
PATCH: 'bg-yellow-500/50 text-yellow-100',
|
|
12
|
+
HEAD: 'bg-blue-500/50 text-blue-100',
|
|
13
|
+
OPTIONS: 'bg-purple-500/50 text-purple-100',
|
|
14
|
+
},
|
|
15
|
+
defaultVariants: {
|
|
16
|
+
variant: 'bg-blue-500/50 text-blue-100',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
export function EndpointBadge({ className, variant, ...props }) {
|
|
21
|
+
return _jsx("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
22
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo, useState } from 'react';
|
|
3
|
+
import { Loader2, Play, X } from 'lucide-react';
|
|
4
|
+
import { Button } from '../ui/button';
|
|
5
|
+
import { Input } from '../ui/input';
|
|
6
|
+
import { Textarea } from '../ui/textarea';
|
|
7
|
+
import { EndpointBadge } from './endpoint-badge';
|
|
8
|
+
import { useJsonSchemaToJson } from './hooks/use-json-schema-to-json';
|
|
9
|
+
import { usePathParams } from './hooks/use-path-params';
|
|
10
|
+
import { useStateStream } from './hooks/use-state-stream';
|
|
11
|
+
export const EndpointCall = ({ endpoint, onClose }) => {
|
|
12
|
+
const shouldHaveBody = ['post', 'put', 'patch'].includes(endpoint.method.toLowerCase());
|
|
13
|
+
const [isRequestLoading, setIsRequestLoading] = useState(false);
|
|
14
|
+
const [responseCode, setResponseCode] = useState();
|
|
15
|
+
const [responseBody, setResponseBody] = useState();
|
|
16
|
+
const [executionTime, setExecutionTime] = useState();
|
|
17
|
+
const { body, setBody } = useJsonSchemaToJson(endpoint.bodySchema);
|
|
18
|
+
const pathParams = usePathParams(endpoint.path);
|
|
19
|
+
const [pathParamsValues, setPathParamsValues] = useState(pathParams?.reduce((acc, param) => ({ ...acc, [param]: '' }), {}));
|
|
20
|
+
const [queryParamsValues, setQueryParamsValues] = useState(endpoint.queryParams?.reduce((acc, param) => ({ ...acc, [param.name]: '' }), {}) ?? {});
|
|
21
|
+
const { data: responseBodyData, isStreamed } = useStateStream(responseBody);
|
|
22
|
+
const isPlayEnabled = useMemo(() => {
|
|
23
|
+
if (!pathParams)
|
|
24
|
+
return true;
|
|
25
|
+
return pathParams?.every((param) => pathParamsValues[param]);
|
|
26
|
+
}, [pathParams, pathParamsValues]);
|
|
27
|
+
const onPathParamChange = (param, value) => {
|
|
28
|
+
setPathParamsValues((prev) => ({ ...prev, [param]: value }));
|
|
29
|
+
};
|
|
30
|
+
const onQueryParamChange = (param, value) => {
|
|
31
|
+
setQueryParamsValues((prev) => ({ ...prev, [param]: value }));
|
|
32
|
+
};
|
|
33
|
+
const handleRequest = async () => {
|
|
34
|
+
setIsRequestLoading(true);
|
|
35
|
+
const startTime = Date.now();
|
|
36
|
+
const path = new URL(window.location.origin +
|
|
37
|
+
pathParams.reduce((acc, param) => {
|
|
38
|
+
return acc.replace(`:${param}`, pathParamsValues[param]);
|
|
39
|
+
}, endpoint.path));
|
|
40
|
+
for (const [key, value] of Object.entries(queryParamsValues)) {
|
|
41
|
+
path.searchParams.set(key, value);
|
|
42
|
+
}
|
|
43
|
+
const response = await fetch(path.toString(), {
|
|
44
|
+
method: endpoint.method,
|
|
45
|
+
headers: { 'Content-Type': 'application/json' },
|
|
46
|
+
body: endpoint.method === 'GET' ? null : body,
|
|
47
|
+
});
|
|
48
|
+
const endTime = Date.now();
|
|
49
|
+
const executionTime = endTime - startTime;
|
|
50
|
+
const json = await response.json();
|
|
51
|
+
setResponseCode(response.status);
|
|
52
|
+
setResponseBody(json);
|
|
53
|
+
setExecutionTime(executionTime);
|
|
54
|
+
setIsRequestLoading(false);
|
|
55
|
+
};
|
|
56
|
+
return (_jsxs("div", { className: "flex flex-col gap-2 overflow-y-auto", children: [_jsxs("div", { className: "text-xs flex flex-row gap-2 items-center justify-between w-full", children: [_jsx("span", { className: "font-bold", children: "Request" }), _jsx("div", { className: "flex flex-row gap-2 items-center hover:bg-white/10 rounded-md p-1", children: _jsx(X, { className: "cursor-pointer w-4 h-4", onClick: onClose }) })] }), _jsxs("div", { className: "flex flex-row gap-2 items-center", children: [_jsx(EndpointBadge, { variant: endpoint.method, children: endpoint.method.toUpperCase() }), _jsx("span", { className: "text-md font-bold", children: endpoint.path })] }), _jsx("span", { className: "text-xs text-muted-foreground", children: endpoint.description }), !!pathParams.length && (_jsxs("div", { className: "flex flex-col gap-2 p-4 rounded-lg bg-muted", children: [_jsx("span", { className: "text-xs font-bold", children: "Path Params" }), _jsx("div", { className: "flex flex-col gap-4", children: pathParams.map((param) => (_jsxs("div", { className: "text-xs", children: [_jsx("div", { className: "font-bold mb-2", children: param }), _jsx(Input, { className: "w-full", value: pathParamsValues[param], onChange: (e) => onPathParamChange(param, e.target.value) })] }, param))) })] })), !!endpoint.queryParams?.length && (_jsxs("div", { className: "flex flex-col gap-2 p-4 rounded-lg bg-muted", children: [_jsx("span", { className: "text-xs font-bold", children: "Query Params" }), _jsx("div", { className: "flex flex-col gap-4", children: endpoint.queryParams.map((param) => (_jsxs("div", { className: "text-xs", children: [_jsx("div", { className: "font-bold mb-2", children: param.name }), _jsx(Input, { className: "w-full", value: queryParamsValues[param.name], onChange: (e) => onQueryParamChange(param.name, e.target.value) })] }, param.name))) })] })), shouldHaveBody && (_jsxs("div", { className: "flex flex-col gap-2 rounded-lg bg-muted", children: [_jsx("span", { className: "text-xs font-bold", children: "Body" }), _jsx(Textarea, { className: "w-full font-mono font-medium min-h-[200px]", value: body, onChange: (e) => setBody(e.target.value) })] })), _jsxs(Button, { className: "w-fit", onClick: handleRequest, disabled: isRequestLoading || !isPlayEnabled, children: [isRequestLoading ? _jsx(Loader2, { className: "animate-spin" }) : _jsx(Play, {}), " Play"] }), responseCode !== undefined && (_jsxs("div", { className: "flex flex-col gap-2 rounded-lg bg-muted", children: [_jsxs("span", { className: "text-xs font-bold", children: [_jsx(EndpointBadge, { variant: responseCode >= 400 ? 'DELETE' : 'GET', children: responseCode }), " Execution time: ", _jsxs("span", { className: "text-muted-foreground", children: [executionTime, "ms"] })] }), isStreamed && (_jsxs("span", { className: "flex flex-row items-center font-medium text-muted-foreground text-xs", children: [_jsxs("span", { className: "ml-1 inline-block w-2 h-2 rounded-full bg-green-500 mr-2 relative", children: [_jsx("span", { className: "absolute inset-0 rounded-full bg-green-500 animate-[ping_1.5s_ease-in-out_infinite]" }), _jsx("span", { className: "absolute inset-0 rounded-full bg-green-500" })] }), "Object is being streamed, this is not the actual response from the API Endpoint"] })), _jsx("span", { className: "text-xs font-mono font-bold dark:bg-black/50 bg-white/50 p-2 rounded-lg whitespace-pre-wrap", children: JSON.stringify(responseBodyData, null, 2) })] }))] }));
|
|
57
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const Endpoints: () => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cva } from 'class-variance-authority';
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
import { EndpointBadge } from './endpoint-badge';
|
|
5
|
+
import { EndpointCall } from './endpoint-call';
|
|
6
|
+
import { useGetEndpoints } from './hooks/use-get-endpoints';
|
|
7
|
+
import { SelectedEndpoint } from './selected-endpoint';
|
|
8
|
+
const endpointVariants = cva('flex flex-col gap-2 font-mono p-2 rounded-lg cursor-pointer', {
|
|
9
|
+
variants: {
|
|
10
|
+
method: {
|
|
11
|
+
GET: 'bg-lime-500/20',
|
|
12
|
+
POST: 'bg-blue-500/20',
|
|
13
|
+
PUT: 'bg-yellow-500/20',
|
|
14
|
+
DELETE: 'bg-red-500/20',
|
|
15
|
+
PATCH: 'bg-yellow-500/20',
|
|
16
|
+
HEAD: 'bg-blue-500/20',
|
|
17
|
+
OPTIONS: 'bg-purple-500/20',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultVariants: { method: 'GET' },
|
|
21
|
+
});
|
|
22
|
+
export const Endpoints = () => {
|
|
23
|
+
const endpoints = useGetEndpoints();
|
|
24
|
+
const [selectedEndpoint, setSelectedEndpoint] = useState(null);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
setSelectedEndpoint((selected) => {
|
|
27
|
+
if (!selected)
|
|
28
|
+
return null;
|
|
29
|
+
const endpoint = endpoints.find((endpoint) => endpoint.method === selected.method && endpoint.path === selected.path);
|
|
30
|
+
return endpoint ?? null;
|
|
31
|
+
});
|
|
32
|
+
}, [endpoints]);
|
|
33
|
+
return (_jsxs("div", { className: "flex flex-row w-full h-screen", children: [_jsxs("div", { className: "flex flex-col gap-2 flex-1 m-4 mr-2 max-h-full overflow-y-auto", children: [_jsxs("header", { children: [_jsx("h1", { className: "text-2xl font-bold", children: "API Endpoints" }), _jsx("span", { className: "text-sm text-zinc-400", children: "Check all API endpoints" })] }), endpoints.map((endpoint) => (_jsxs("div", { className: endpointVariants({ method: endpoint.method }), onClick: () => setSelectedEndpoint(endpoint), children: [_jsxs("div", { className: "flex flex-row gap-2 items-center", children: [_jsx(EndpointBadge, { variant: endpoint.method, children: endpoint.method.toUpperCase() }), _jsx("span", { className: "text-md font-bold", children: endpoint.path }), !selectedEndpoint && _jsx("span", { className: "text-xs text-muted-foreground", children: endpoint.description })] }), selectedEndpoint && _jsx("span", { className: "text-xs text-muted-foreground", children: endpoint.description }), selectedEndpoint === endpoint && _jsx(SelectedEndpoint, { endpoint: selectedEndpoint })] }, `${endpoint.method} ${endpoint.path}`)))] }), selectedEndpoint && (_jsx("div", { className: "flex flex-col gap-2 flex-1 m-4 ml-2 p-4 rounded-lg bg-muted", children: _jsx(EndpointCall, { endpoint: selectedEndpoint, onClose: () => setSelectedEndpoint(null) }) }))] }));
|
|
34
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
type ApiRouteMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'OPTIONS' | 'HEAD';
|
|
2
|
+
type QueryParam = {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
};
|
|
6
|
+
export type ApiEndpoint = {
|
|
7
|
+
method: ApiRouteMethod;
|
|
8
|
+
path: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
queryParams?: QueryParam[];
|
|
11
|
+
responseSchema?: Record<string, any>;
|
|
12
|
+
bodySchema?: Record<string, Record<string, any>>;
|
|
13
|
+
};
|
|
14
|
+
export declare const useGetEndpoints: () => ApiEndpoint[];
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { convertJsonSchemaToJson } from './utils';
|
|
3
|
+
export const useJsonSchemaToJson = (schema) => {
|
|
4
|
+
const [body, setBody] = useState('');
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
if (schema) {
|
|
7
|
+
setBody(JSON.stringify(convertJsonSchemaToJson(schema), null, 2));
|
|
8
|
+
}
|
|
9
|
+
}, [schema]);
|
|
10
|
+
return { body, setBody };
|
|
11
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const usePathParams: (path: string) => string[];
|