@boltic/swirl 1.0.0

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Boltic Team
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 ADDED
@@ -0,0 +1,398 @@
1
+ # 🌀 Swirl — Visual Workflow Builder Library
2
+
3
+ **A powerful React library for building visual workflow automation systems with drag-and-drop interface, built on React Flow and Material-UI.**
4
+
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
6
+ [![React Flow](https://img.shields.io/badge/React%20Flow-Powered-green.svg)](https://reactflow.dev/)
7
+ [![Material-UI](https://img.shields.io/badge/Material--UI-5.x-blue.svg)](https://mui.com/)
8
+
9
+ ## ✨ Features
10
+
11
+ - 🎨 **Visual Workflow Builder** - Drag-and-drop interface for creating complex workflows
12
+ - 🔗 **Node-Based Architecture** - Connect activities, triggers, and conditions visually
13
+ - 📊 **Execution Monitoring** - Real-time workflow execution tracking and debugging
14
+ - 🎯 **80+ Built-in Activities** - Pre-built integrations and actions
15
+ - 🔄 **Conditional Logic** - IF/ELSE conditions, loops, and parallel execution
16
+ - 🌐 **API Integration** - HTTP requests, webhooks, and custom API calls
17
+ - 📧 **Communication** - Email, Slack, and notification activities
18
+ - 📊 **Data Processing** - JSON manipulation, mapping, and transformation
19
+ - 🔐 **Secure Execution** - Token-based authentication and secure API calls
20
+ - 📱 **Responsive Design** - Works seamlessly on desktop and tablet devices
21
+ - 🎨 **Customizable Theming** - Full Material-UI theme customization
22
+ - 🔌 **Extensible Architecture** - Add custom activities and integrations
23
+
24
+ ## 🚀 Quick Start
25
+
26
+ ### Installation
27
+
28
+ ```bash
29
+ npm install @boltic/swirl
30
+ ```
31
+
32
+ ### Peer Dependencies
33
+
34
+ Swirl requires the following peer dependencies:
35
+
36
+ ```bash
37
+ npm install @emotion/react @emotion/styled @mui/material react react-dom
38
+ ```
39
+
40
+ ### Basic Usage
41
+
42
+ ```tsx
43
+ import React from 'react';
44
+ import { WorkflowBuilder } from '@boltic/swirl';
45
+ import '@boltic/swirl/dist/style.css';
46
+
47
+ const App = () => {
48
+ const WORKFLOW_URLS = {
49
+ VORTEX_MAIN_URL: 'https://api.example.com/workflow',
50
+ FRONTEND_URL: 'https://yourapp.com',
51
+ VORTEX_WEBHOOK_URL: 'https://api.example.com/webhook',
52
+ // ... other required URLs
53
+ };
54
+
55
+ const handleIntegrationDrawer = (data: any) => {
56
+ console.log('Integration drawer opened:', data);
57
+ };
58
+
59
+ return (
60
+ <WorkflowBuilder
61
+ WORKFLOW_URLS={WORKFLOW_URLS}
62
+ ENTITY_ID="your-entity-id"
63
+ TOKEN="your-auth-token"
64
+ api={{}}
65
+ openIntegrationDrawer={handleIntegrationDrawer}
66
+ INTEGRATION_DATA={{}}
67
+ SET_INTEGRATION_DATA={() => {}}
68
+ analytics={{}}
69
+ navigate={() => {}}
70
+ />
71
+ );
72
+ };
73
+
74
+ export default App;
75
+ ```
76
+
77
+ ### Execution Data Viewer
78
+
79
+ ```tsx
80
+ import React from 'react';
81
+ import { ExecutionData } from '@boltic/swirl';
82
+ import '@boltic/swirl/dist/style.css';
83
+
84
+ const ExecutionViewer = () => {
85
+ return (
86
+ <ExecutionData
87
+ WORKFLOW_URLS={WORKFLOW_URLS}
88
+ ENTITY_ID="your-entity-id"
89
+ TOKEN="your-auth-token"
90
+ workflowId="workflow-123"
91
+ executionId="execution-456"
92
+ />
93
+ );
94
+ };
95
+ ```
96
+
97
+ ## 🎯 Core Components
98
+
99
+ ### WorkflowBuilder
100
+
101
+ The main visual workflow editor component that provides:
102
+
103
+ - **Canvas Interface** - Drag-and-drop workflow design
104
+ - **Activity Palette** - Library of available workflow activities
105
+ - **Node Configuration** - Form-based activity configuration using Ripple
106
+ - **Connection Management** - Visual connections between workflow steps
107
+ - **Execution Controls** - Test, save, and deploy workflows
108
+
109
+ ### ExecutionData
110
+
111
+ Workflow execution monitoring and debugging component:
112
+
113
+ - **Execution Timeline** - Step-by-step execution visualization
114
+ - **Debug Logs** - Detailed execution logs and error tracking
115
+ - **Data Flow** - Input/output data for each workflow step
116
+ - **Performance Metrics** - Execution time and performance analytics
117
+
118
+ ## 🔧 Available Activities
119
+
120
+ Swirl comes with 80+ built-in activities organized by category:
121
+
122
+ ### **🌐 API & HTTP**
123
+
124
+ - **HTTP Activity** - Make REST API calls
125
+ - **Webhook** - Receive webhook notifications
126
+ - **API Activity** - Advanced API integrations
127
+ - **Custom Activity** - Build custom API interactions
128
+
129
+ ### **📧 Communication**
130
+
131
+ - **Email Activity** - Send emails with templates
132
+ - **Slack Activity** - Send Slack messages and notifications
133
+ - **Gmail Activity** - Gmail integration for sending emails
134
+ - **Gmail Trigger** - Trigger workflows from Gmail events
135
+
136
+ ### **📊 Data Processing**
137
+
138
+ - **Mapper** - Transform and map data between formats
139
+ - **Converter Activity** - Convert data types and formats
140
+ - **Template** - Generate content from templates
141
+ - **JSON Processing** - Manipulate JSON data structures
142
+
143
+ ### **🔄 Flow Control**
144
+
145
+ - **IF Activity** - Conditional branching logic
146
+ - **Switch Activity** - Multi-branch conditional logic
147
+ - **Loop** - Iterate over data collections
148
+ - **Parallel** - Execute multiple activities simultaneously
149
+ - **Sleep** - Add delays to workflow execution
150
+
151
+ ### **📅 Scheduling & Time**
152
+
153
+ - **Schedule** - Time-based workflow triggers
154
+ - **Google Calendar** - Calendar event management
155
+ - **Calendly** - Appointment scheduling integration
156
+ - **Date/Time Operations** - Date manipulation activities
157
+
158
+ ### **💾 Data Storage**
159
+
160
+ - **Boltic Storage** - Cloud storage operations
161
+ - **Boltic Tables** - Database table operations
162
+ - **Cloud Database** - Database connectivity
163
+ - **Google Sheets** - Spreadsheet read/write operations
164
+
165
+ ### **🤖 AI & Automation**
166
+
167
+ - **GPT** - AI text generation and processing
168
+ - **MCP (Model Context Protocol)** - AI model interactions
169
+ - **Function Activity** - Custom function execution
170
+ - **Serverless** - Serverless function execution
171
+
172
+ ### **🔧 Utilities**
173
+
174
+ - **Log Console** - Debug logging and monitoring
175
+ - **Monitor** - System monitoring and alerts
176
+ - **Response** - HTTP response handling
177
+ - **Execute Child Workflow** - Nested workflow execution
178
+
179
+ ## 📋 API Reference
180
+
181
+ ### WorkflowBuilder Props
182
+
183
+ | Prop | Type | Required | Description |
184
+ | ----------------------- | ---------- | -------- | ----------------------------------------- |
185
+ | `WORKFLOW_URLS` | `object` | ✅ | Configuration URLs for workflow services |
186
+ | `ENTITY_ID` | `string` | ✅ | Unique identifier for the workflow entity |
187
+ | `TOKEN` | `string` | ✅ | Authentication token for API calls |
188
+ | `INTEGRATION_DATA` | `object` | ✅ | Integration configuration data |
189
+ | `SET_INTEGRATION_DATA` | `function` | ✅ | Function to update integration data |
190
+ | `api` | `object` | ❌ | Custom API interface (optional) |
191
+ | `openIntegrationDrawer` | `function` | ❌ | Callback for opening integration drawer |
192
+ | `analytics` | `object` | ❌ | Analytics tracking configuration |
193
+ | `navigate` | `function` | ❌ | Navigation function for routing |
194
+
195
+ ### ExecutionData Props
196
+
197
+ | Prop | Type | Required | Description |
198
+ | --------------- | ---------- | -------- | ----------------------------------------- |
199
+ | `WORKFLOW_URLS` | `object` | ✅ | Configuration URLs for workflow services |
200
+ | `ENTITY_ID` | `string` | ✅ | Unique identifier for the workflow entity |
201
+ | `TOKEN` | `string` | ✅ | Authentication token for API calls |
202
+ | `workflowId` | `string` | ✅ | ID of the workflow to monitor |
203
+ | `executionId` | `string` | ✅ | ID of the specific execution |
204
+ | `api` | `object` | ❌ | Custom API interface (optional) |
205
+ | `navigate` | `function` | ❌ | Navigation function for routing |
206
+
207
+ ### WORKFLOW_URLS Configuration
208
+
209
+ ```tsx
210
+ const WORKFLOW_URLS = {
211
+ VORTEX_MAIN_URL: string; // Main workflow engine URL
212
+ FRONTEND_URL: string; // Frontend application URL
213
+ VORTEX_WEBHOOK_URL: string; // Webhook handler URL
214
+ VORTEX_SYNC_DOMAIN: string; // Sync service domain
215
+ SERVERLESS_URL: string; // Serverless functions URL
216
+ TESSERACT_MAIN_URL: string; // OCR service URL
217
+ FC_DOMAIN: string; // File conversion domain
218
+ MADROX_MAIN_URL: string; // Duplication service URL
219
+ HITMAN_PUBLIC_DOMAIN: string; // Public API domain
220
+ HITMAN_PLTM_URL: string; // Platform API URL
221
+ ATHENA_MAIN_URL: string; // Analytics service URL
222
+ GYRATE_MAIN_URL: string; // Rotation service URL
223
+ BOLTIC_EMAIL_DOMAIN: string; // Email service domain
224
+ };
225
+ ```
226
+
227
+ ## 🎨 Theming & Customization
228
+
229
+ Swirl supports full Material-UI theming:
230
+
231
+ ```tsx
232
+ import { ThemeProvider, createTheme } from '@mui/material/styles';
233
+ import { WorkflowBuilder } from '@boltic/swirl';
234
+
235
+ const customTheme = createTheme({
236
+ palette: {
237
+ primary: {
238
+ main: '#1976d2',
239
+ },
240
+ secondary: {
241
+ main: '#dc004e',
242
+ },
243
+ },
244
+ components: {
245
+ MuiButton: {
246
+ styleOverrides: {
247
+ root: {
248
+ borderRadius: 8,
249
+ },
250
+ },
251
+ },
252
+ },
253
+ });
254
+
255
+ const App = () => (
256
+ <ThemeProvider theme={customTheme}>
257
+ <WorkflowBuilder {...props} />
258
+ </ThemeProvider>
259
+ );
260
+ ```
261
+
262
+ ## 🏗️ Architecture
263
+
264
+ Swirl is built with modern React patterns:
265
+
266
+ - **React Flow** - Visual node-based workflow canvas
267
+ - **Redux Toolkit** - Centralized state management
268
+ - **Material-UI** - Consistent design system
269
+ - **TypeScript** - Full type safety
270
+ - **Vite** - Fast development and build tooling
271
+ - **Ripple Integration** - Dynamic form generation for activity configuration
272
+
273
+ ### Tech Stack
274
+
275
+ - [React](https://reactjs.org/) 18.x
276
+ - [Redux Toolkit](https://redux-toolkit.js.org/) - State management
277
+ - [TypeScript](https://www.typescriptlang.org/) - Type safety
278
+ - [Material-UI](https://mui.com/) 5.x - UI components
279
+ - [React Flow](https://reactflow.dev/) - Node-based canvas
280
+ - [Vite](https://vite.dev/) 7.x - Build tooling
281
+
282
+ ## 📦 Build Outputs
283
+
284
+ The library provides multiple distribution formats:
285
+
286
+ - **ESM**: `dist/swirl.es.js` - Modern ES modules
287
+ - **UMD**: `dist/swirl.umd.js` - Universal module (global `swirl`)
288
+ - **CSS**: `dist/style.css` - Stylesheet
289
+ - **Types**: `dist/index.d.ts` - TypeScript declarations
290
+
291
+ ### UMD Usage (Script Tag)
292
+
293
+ ```html
294
+ <link rel="stylesheet" href="/dist/style.css" />
295
+ <script src="/dist/swirl.umd.js"></script>
296
+ <div id="workflow-root"></div>
297
+ <script>
298
+ const { WorkflowBuilder } = window.swirl;
299
+ // Initialize WorkflowBuilder with your framework
300
+ console.log('WorkflowBuilder available:', typeof WorkflowBuilder === 'function');
301
+ </script>
302
+ ```
303
+
304
+ ## 🚀 Development Setup
305
+
306
+ ### Prerequisites
307
+
308
+ - Node.js ≥ 20.19 (or ≥ 22.12)
309
+ - npm ≥ 10
310
+
311
+ ### Local Development
312
+
313
+ 1. **Clone the repository**
314
+
315
+ ```bash
316
+ git clone <repo-link>
317
+ cd swirl
318
+ ```
319
+
320
+ 2. **Install dependencies**
321
+
322
+ ```bash
323
+ npm install
324
+ ```
325
+
326
+ 3. **Set up SSL certificate** (for HTTPS development)
327
+
328
+ ```bash
329
+ # Install mkcert
330
+ # Generate certificate
331
+ mkcert -key-file key.pem -cert-file cert.pem "*.fcz0.de"
332
+
333
+ # Create ssl folder and copy certificates
334
+ mkdir ssl
335
+ cp key.pem cert.pem ssl/
336
+
337
+ # Add to /etc/hosts
338
+ echo "127.0.0.1 local.fcz0.de" >> /etc/hosts
339
+ ```
340
+
341
+ 4. **Configure environment**
342
+
343
+ ```bash
344
+ chmod +x ./run.local.sh
345
+ # Edit run.local.sh with your environment variables
346
+ ```
347
+
348
+ 5. **Start development server**
349
+
350
+ ```bash
351
+ ./run.local.sh
352
+ ```
353
+
354
+ Access at: `https://local.fcz0.de:3000`
355
+
356
+ 6. **Build the library**
357
+ ```bash
358
+ npm run build
359
+ ```
360
+
361
+ ## 🔧 Environment Variables
362
+
363
+ Required environment variables for development:
364
+
365
+ ```bash
366
+ VITE_VORTEX_MAIN_URL=https://api.example.com/workflow
367
+ VITE_FRONTEND_URL=https://yourapp.com
368
+ VITE_ENTITY_ID=your-entity-id
369
+ VITE_TOKEN=your-auth-token
370
+ # ... other service URLs
371
+ ```
372
+
373
+ ## 🎯 Use Cases
374
+
375
+ Swirl is perfect for building:
376
+
377
+ - **Business Process Automation** - Automate repetitive business workflows
378
+ - **Data Integration Platforms** - Connect and sync data between systems
379
+ - **Notification Systems** - Multi-channel notification workflows
380
+ - **Content Management** - Automated content processing pipelines
381
+ - **E-commerce Automation** - Order processing and inventory management
382
+ - **Customer Support** - Automated ticket routing and responses
383
+ - **Marketing Automation** - Lead nurturing and campaign workflows
384
+ - **DevOps Pipelines** - CI/CD and deployment automation
385
+
386
+ ## 📤 Publishing (maintainers)
387
+
388
+ - **Build before publish**: `prepublishOnly` runs `npm run build` automatically when you run `npm publish`.
389
+ - **Package name**: If the name `swirl` is taken on npm, use a scoped name (e.g. `@boltic/swirl`) and set it in `package.json`.
390
+ - **Private dependencies**: This package depends on `@fynd/intelligence` and `ripple` from Azure DevOps. For **public npm**, installs will fail for users without access to those repos. Options: publish to a **private registry** (e.g. Azure Artifacts) where those deps resolve, or move those deps to `optionalDependencies` and document fallbacks for public npm.
391
+
392
+ ## 🙋‍♂️ Support
393
+
394
+ - **Email**: ahmedsakri@gofynd.com
395
+
396
+ ---
397
+
398
+ **Made with ❤️ by the Boltic Team**
Binary file
@@ -0,0 +1,50 @@
1
+ import React from 'react';
2
+
3
+ export interface WorkflowBuilderProps {
4
+ WORKFLOW_URLS: any;
5
+ ALERT_TOP_BAR: React.ElementType | React.ReactNode;
6
+ currentSubscription: any;
7
+ INTEGRATION_DATA: any;
8
+ SET_INTEGRATION_DATA: any;
9
+ ENTITY_ID: string;
10
+ TOKEN: string;
11
+ openIntegrationDrawer?: (data: any, action?: string) => void;
12
+ [key: string]: any; // Allow additional props
13
+ }
14
+
15
+ export interface ExecutionDataProps {
16
+ WORKFLOW_URLS: any;
17
+ ENTITY_ID: string;
18
+ TOKEN: string;
19
+ api?: any;
20
+ navigate?: any;
21
+ [key: string]: any;
22
+ openUpgradeModal: () => void;
23
+ currentSubscription: any;
24
+ }
25
+
26
+ export interface IntegrationFormProps {
27
+ selectedNode: any;
28
+ onClose: () => void;
29
+ onSubmit: (data: any) => void;
30
+ drawerWidth?: string;
31
+ openIntegrationDrawer?: (data: any) => void;
32
+ initialState?: any;
33
+ setSelectedNode: (node: any) => void;
34
+ nodes?: any[];
35
+ setNodes?: (nodes: any[]) => void;
36
+ ENTITY_ID: string;
37
+ WORKFLOW_URLS: any;
38
+ INTEGRATION_DATA: any;
39
+ SET_INTEGRATION_DATA: (data: any) => void;
40
+ PLAYGROUND_ENABLED?: boolean;
41
+ TOKEN: string;
42
+ api?: any;
43
+ actionRef?: React.RefObject<any>;
44
+ MCP_INTEGRATION_FORM?: boolean;
45
+ [key: string]: any; // Allow additional props
46
+ }
47
+
48
+ export declare const WorkflowBuilder: React.ComponentType<WorkflowBuilderProps>;
49
+ export declare const ExecutionData: React.ComponentType<ExecutionDataProps>;
50
+ export declare const IntegrationForm: React.ComponentType<IntegrationFormProps>;
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ @import"https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap";@import"https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&display=swap";body{margin:0;font-family:Inter,sans-serif}.loop .setup,.loop .config{font-size:16px}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}.setup-section,.configure-section{gap:12px}.objectContent,.arrayContent{position:relative}.objectContent .jsonValue,.arrayContent .jsonValue{margin-left:15px}.objectContent .jsonKey,.arrayContent .jsonKey{margin-left:18px}.objectContent .arrayContent,.arrayContent .arrayContent{margin-left:20px}.objectContent{width:490px}.indexLine{position:relative;margin-bottom:5px}.mt15{display:flex;margin-top:7px}.collapse{position:relative;transform-origin:center;transition:transform .2s cubic-bezier(.4,0,.2,1);cursor:pointer}.collapse.up{transform:rotate(90deg)}.collapse.down{transform:rotate(0)}.react-flow__edge-delete-button{opacity:0;pointer-events:none;cursor:pointer}.react-flow__edge-delete-square{pointer-events:all}.react-flow__edge-delete-square-inner{width:100%;height:100%;background:#fff;border:1px solid #d3d3d3;border-radius:2px;transition:border-color .2s ease}.react-flow__edge-delete-icon{pointer-events:all;width:20px;height:20px;display:flex;align-items:center;justify-content:center}.react-flow__edge-delete-icon path{transition:fill .2s ease}.react-flow__edge-delete-button:hover .react-flow__edge-delete-square-inner{border-color:#c41c1c}.react-flow__edge-delete-button:hover .react-flow__edge-delete-icon path{fill:#c41c1c}.react-flow__edge-add-button{opacity:0;pointer-events:none;cursor:pointer;transition:opacity .2s ease}.react-flow__edge-add-square{pointer-events:all}.react-flow__edge-add-square-inner{width:100%;height:100%;background:#fff;border:1px solid #d3d3d3;border-radius:4px;transition:border-color .2s ease}.react-flow__edge-add-icon{pointer-events:all;width:20px;height:20px;display:flex;align-items:center;justify-content:center}.react-flow__edge-add-icon .add-button-border{transition:stroke .2s ease}.react-flow__edge-add-icon .add-button-icon{transition:fill .2s ease}.react-flow__edge:hover .react-flow__edge-add-button{opacity:1;pointer-events:all}.react-flow__edge:hover .react-flow__edge-add-square-inner{border-color:#d3d3d3}.react-flow__edge-add-button:hover .react-flow__edge-add-square-inner{border-color:#595d61!important}.react-flow__edge-add-button:hover .add-button-border{stroke:#595d61!important}.react-flow__edge-add-button:hover .add-button-icon{fill:#595d61!important}.react-flow__edge-add-button:active .react-flow__edge-add-square-inner{border-color:#ff592f!important}.react-flow__edge-add-button:active .add-button-border{stroke:#ff592f!important}.react-flow__edge-add-button:active .add-button-icon{fill:#ff592f!important}.react-flow__edge-add-button.selected .react-flow__edge-add-square-inner{border-color:#ff592f!important}.react-flow__edge-add-button.selected .add-button-border{stroke:#ff592f!important}.react-flow__edge-add-button.selected .add-button-icon{fill:#ff592f!important}.react-flow__edge-add-button.selected,.react-flow__edge-delete-button.selected{opacity:1;pointer-events:all}.handle_icon{position:absolute;left:50%;transform:translate(-50%);width:0;height:0;pointer-events:none;transition:width .1s ease-in-out,height .1s ease-in-out}.react-flow__handle{position:absolute;min-width:10px;min-height:10px;z-index:2;display:flex;align-items:center;justify-content:center}.react-flow__handle:hover:not(.viewModeCursor){width:16px;height:16px;border:none!important;background-color:transparent!important}.react-flow__handle:hover:not(.viewModeCursor) .handle_icon{display:block;width:16px;height:16px;left:calc(50% - 4px)}.viewModeCursor{pointer-events:none;cursor:not-allowed}.react-flow__edge:hover .react-flow__edge-delete-button,.react-flow__edge:hover .react-flow__edge-add-button{opacity:1;pointer-events:all}.react-flow__edge:hover-path{stroke:#3448c5;stroke-width:2px}.react-flow__edge.selected .react-flow__edge-delete-button,.react-flow__edge.selected .react-flow__edge-add-button{opacity:1;pointer-events:all}.react-flow__edge.selected-path,.react-flow__edge-path{stroke:#3448c5;stroke-width:2px}.react-flow__edge-path.selected .react-flow__edge-delete-button,.react-flow__edge-path.selected .react-flow__edge-add-button,.react-flow__edge-path:hover .react-flow__edge-delete-button,.react-flow__edge-path:hover .react-flow__edge-add-button{opacity:1;pointer-events:all}.react-flow__edge{pointer-events:all;cursor:pointer}.react-flow__edge.viewModeCursor{cursor:default}.react-flow__pane{cursor:grab}.react-flow__pane:has(path.animated){cursor:grabbing}path.react-flow__edge-path{stroke-width:1;stroke-linecap:round;stroke-linejoin:round}path.react-flow__edge-path:hover{stroke-width:1}.react-flow__edge-interaction{stroke-width:12;stroke:transparent;fill:none;pointer-events:stroke}.react-flow__connectionline,path.animated{cursor:grabbing}.targetHandleStyle{border-width:2px;height:8px;width:8px;border-radius:50%}.sourceHandleStyle{border-width:2px;top:50%;height:8px;width:8px;border-radius:50%}.handleStyle{border-width:3px;height:8px;width:8px;border-radius:50%}.nodeContainer{min-width:260px;min-height:84px;box-shadow:0 4px 16px #00000014;border-radius:8px;background:#fff;display:flex;flex-direction:column}.react-flow{direction:ltr;--xy-edge-stroke-default: #b1b1b7;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #555;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(255, 255, 255, .5);--xy-minimap-background-color-default: #fff;--xy-minimap-mask-background-color-default: rgba(240, 240, 240, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #e2e2e2;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: transparent;--xy-background-pattern-dots-color-default: #91919a;--xy-background-pattern-lines-color-default: #eee;--xy-background-pattern-cross-color-default: #e2e2e2;background-color:var(--xy-background-color, var(--xy-background-color-default));--xy-node-color-default: inherit;--xy-node-border-default: 1px solid #1a192b;--xy-node-background-color-default: #fff;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #1a192b;--xy-node-border-radius-default: 3px;--xy-handle-background-color-default: #1a192b;--xy-handle-border-color-default: #fff;--xy-selection-background-color-default: rgba(0, 89, 220, .08);--xy-selection-border-default: 1px dotted rgba(0, 89, 220, .8);--xy-controls-button-background-color-default: #fefefe;--xy-controls-button-background-color-hover-default: #f4f4f4;--xy-controls-button-color-default: inherit;--xy-controls-button-color-hover-default: inherit;--xy-controls-button-border-color-default: #eee;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #ffffff;--xy-edge-label-color-default: inherit;--xy-resize-background-color-default: #3367d9}.react-flow.dark{--xy-edge-stroke-default: #3e3e3e;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #727272;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(150, 150, 150, .25);--xy-minimap-background-color-default: #141414;--xy-minimap-mask-background-color-default: rgba(60, 60, 60, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #2b2b2b;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: #141414;--xy-background-pattern-dots-color-default: #777;--xy-background-pattern-lines-color-default: #777;--xy-background-pattern-cross-color-default: #777;--xy-node-color-default: #f8f8f8;--xy-node-border-default: 1px solid #3c3c3c;--xy-node-background-color-default: #1e1e1e;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #999;--xy-handle-background-color-default: #bebebe;--xy-handle-border-color-default: #1e1e1e;--xy-selection-background-color-default: rgba(200, 200, 220, .08);--xy-selection-border-default: 1px dotted rgba(200, 200, 220, .8);--xy-controls-button-background-color-default: #2b2b2b;--xy-controls-button-background-color-hover-default: #3e3e3e;--xy-controls-button-color-default: #f8f8f8;--xy-controls-button-color-hover-default: #fff;--xy-controls-button-border-color-default: #5b5b5b;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #141414;--xy-edge-label-color-default: #f8f8f8}.react-flow__background{background-color:var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));pointer-events:none;z-index:-1}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1}.react-flow__pane.draggable{cursor:grab}.react-flow__pane.dragging{cursor:grabbing}.react-flow__pane.selection{cursor:pointer}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow__edge-path{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));fill:none}.react-flow__connection-path{stroke:var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));fill:none}.react-flow .react-flow__edges{position:absolute}.react-flow .react-flow__edges svg{overflow:visible;position:absolute;pointer-events:none}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.selectable{cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selectable:focus .react-flow__edge-path,.react-flow__edge.selectable:focus-visible .react-flow__edge-path{stroke:var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default))}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__arrowhead polyline{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}svg.react-flow__connectionline{z-index:1001;overflow:visible;position:absolute}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.react-flow__node.selectable{cursor:pointer}.react-flow__node.draggable{cursor:grab;pointer-events:all}.react-flow__node.draggable.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background-color:var(--xy-handle-background-color, var(--xy-handle-background-color-default));border:1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));border-radius:100%}.react-flow__handle.connectingfrom{pointer-events:all}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:0;transform:translate(-50%,50%)}.react-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.react-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.react-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__pane.selection .react-flow__panel{pointer-events:none}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.top.center,.react-flow__panel.bottom.center{left:50%;transform:translate(-15px) translate(-50%)}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.left.center,.react-flow__panel.right.center{top:50%;transform:translateY(-15px) translateY(-50%)}.react-flow__attribution{font-size:10px;background:var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;left:0;top:0}.react-flow__viewport-portal{position:absolute;width:100%;height:100%;left:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__minimap{background:var( --xy-minimap-background-color-props, var(--xy-minimap-background-color, var(--xy-minimap-background-color-default)) )}.react-flow__minimap-svg{display:block}.react-flow__minimap-mask{fill:var( --xy-minimap-mask-background-color-props, var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default)) );stroke:var( --xy-minimap-mask-stroke-color-props, var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default)) );stroke-width:var( --xy-minimap-mask-stroke-width-props, var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default)) )}.react-flow__minimap-node{fill:var( --xy-minimap-node-background-color-props, var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default)) );stroke:var( --xy-minimap-node-stroke-color-props, var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default)) );stroke-width:var( --xy-minimap-node-stroke-width-props, var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default)) )}.react-flow__background-pattern.dots{fill:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default)) )}.react-flow__background-pattern.lines{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default)) )}.react-flow__background-pattern.cross{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default)) )}.react-flow__controls{display:flex;flex-direction:column;box-shadow:var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default))}.react-flow__controls.horizontal{flex-direction:row}.react-flow__controls-button{display:flex;justify-content:center;align-items:center;height:26px;width:26px;padding:4px;border:none;background:var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));border-bottom:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) );color:var( --xy-controls-button-color-props, var(--xy-controls-button-color, var(--xy-controls-button-color-default)) );cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px;fill:currentColor}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-input,.react-flow__node-default,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:var(--xy-node-border-radius, var(--xy-node-border-radius-default));width:150px;font-size:12px;color:var(--xy-node-color, var(--xy-node-color-default));text-align:center;border:var(--xy-node-border, var(--xy-node-border-default));background-color:var(--xy-node-background-color, var(--xy-node-background-color-default))}.react-flow__node-input.selectable:hover,.react-flow__node-default.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default))}.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default))}.react-flow__node-group{background-color:var(--xy-node-group-background-color, var(--xy-node-group-background-color-default))}.react-flow__nodesselection-rect,.react-flow__selection{background:var(--xy-selection-background-color, var(--xy-selection-background-color-default));border:var(--xy-selection-border, var(--xy-selection-border-default))}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls-button:hover{background:var( --xy-controls-button-background-color-hover-props, var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default)) );color:var( --xy-controls-button-color-hover-props, var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default)) )}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__controls-button:last-child{border-bottom:none}.react-flow__controls.horizontal .react-flow__controls-button{border-bottom:none;border-right:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) )}.react-flow__controls.horizontal .react-flow__controls-button:last-child{border-right:none}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:5px;height:5px;border:1px solid #fff;border-radius:1px;background-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));translate:-50% -50%}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.react-flow__edge-textbg{fill:var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default))}.react-flow__edge-text{fill:var(--xy-edge-label-color, var(--xy-edge-label-color-default))}