@flowuent-org/diagramming-core 1.3.10 → 1.4.1
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/.editorconfig +13 -13
- package/.eslintignore +1 -1
- package/.eslintrc.json +35 -35
- package/.prettierignore +3 -3
- package/.prettierrc +3 -3
- package/.vscode/settings.json +6 -6
- package/README.md +95 -95
- package/apps/authentication/tsconfig.app.json +23 -23
- package/apps/authentication/tsconfig.json +21 -21
- package/apps/authentication/tsconfig.spec.json +28 -28
- package/apps/diagramming/.eslintrc.json +18 -18
- package/apps/diagramming/index.html +16 -16
- package/apps/diagramming/project.json +53 -53
- package/apps/diagramming/public/aws-icons/compute/App Runner.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/Application Auto Scaling.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/Batch.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/Bottlerocket.svg +19 -19
- package/apps/diagramming/public/aws-icons/compute/Compute Optimizer.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/EC2 Auto Scaling.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/EC2 Image Builder.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/EC2.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/Elastic Beanstalk.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/Elastic Fabric Adapter.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/Fargate.svg +19 -19
- package/apps/diagramming/public/aws-icons/compute/Genomics CLI.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/Lambda.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/Local Zones.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/NICE DCV.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/NICE EnginFrame.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/Nitro Enclaves.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/Outposts family.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/Outposts rack.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/Outposts servers.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/ParallelCluster.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/Serverless Application Repository.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/SimSpace Weaver.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/Thinkbox Deadline.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/Thinkbox Frost.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/Thinkbox Sequoia.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/Thinkbox Stoke.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/Thinkbox XMesh.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/VMware Cloud on AWS.svg +17 -17
- package/apps/diagramming/public/aws-icons/compute/Wavelength.svg +17 -17
- package/apps/diagramming/public/aws-icons/container/ECS Anywhere.svg +17 -17
- package/apps/diagramming/public/aws-icons/container/EKS Anywhere.svg +17 -17
- package/apps/diagramming/public/aws-icons/container/EKS Cloud.svg +17 -17
- package/apps/diagramming/public/aws-icons/container/EKS Distro.svg +17 -17
- package/apps/diagramming/public/aws-icons/container/Elastic Container Registry.svg +17 -17
- package/apps/diagramming/public/aws-icons/container/Elastic Container Service.svg +17 -17
- package/apps/diagramming/public/aws-icons/container/Elastic Kubernetes Service.svg +17 -17
- package/apps/diagramming/public/aws-icons/container/Fargate.svg +19 -19
- package/apps/diagramming/public/aws-icons/container/Red Hat OpenShift Service on AWS.svg +17 -17
- package/apps/diagramming/public/aws-icons/database/Aurora.svg +17 -17
- package/apps/diagramming/public/aws-icons/database/Database Migration Service.svg +17 -17
- package/apps/diagramming/public/aws-icons/database/DocumentDB.svg +17 -17
- package/apps/diagramming/public/aws-icons/database/ElastiCache.svg +17 -17
- package/apps/diagramming/public/aws-icons/database/Keyspaces.svg +15 -15
- package/apps/diagramming/public/aws-icons/database/MemoryDB for Redis.svg +17 -17
- package/apps/diagramming/public/aws-icons/database/Neptune.svg +17 -17
- package/apps/diagramming/public/aws-icons/database/RDS on VMware.svg +17 -17
- package/apps/diagramming/public/aws-icons/database/RDS.svg +17 -17
- package/apps/diagramming/public/aws-icons/database/Timestream.svg +17 -17
- package/apps/diagramming/public/aws-icons/networking/App Mesh.svg +17 -17
- package/apps/diagramming/public/aws-icons/networking/Client VPN.svg +17 -17
- package/apps/diagramming/public/aws-icons/networking/Cloud Directory.svg +17 -17
- package/apps/diagramming/public/aws-icons/networking/Cloud Map.svg +17 -17
- package/apps/diagramming/public/aws-icons/networking/Cloud WAN.svg +17 -17
- package/apps/diagramming/public/aws-icons/networking/CloudFront.svg +17 -17
- package/apps/diagramming/public/aws-icons/networking/Direct Connect.svg +17 -17
- package/apps/diagramming/public/aws-icons/networking/Elastic Load Balancing.svg +17 -17
- package/apps/diagramming/public/aws-icons/networking/Global Accelerator.svg +17 -17
- package/apps/diagramming/public/aws-icons/networking/Private 5G.svg +17 -17
- package/apps/diagramming/public/aws-icons/networking/PrivateLink.svg +17 -17
- package/apps/diagramming/public/aws-icons/networking/Route 53.svg +17 -17
- package/apps/diagramming/public/aws-icons/networking/Site to Site VPN.svg +17 -17
- package/apps/diagramming/public/aws-icons/networking/Transit Gateway.svg +17 -17
- package/apps/diagramming/public/aws-icons/networking/VPC Lattice.svg +17 -17
- package/apps/diagramming/public/aws-icons/networking/Verified Access.svg +17 -17
- package/apps/diagramming/public/aws-icons/networking/Virtual Private Cloud.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/Artifact.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/Audit Manager.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/Certificate Manager.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/CloudHSM.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/Cognito.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/Detective.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/Directory Service.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/Firewall Manager.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/GuardDuty.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/IAM Identity Center.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/Identity and Access Management.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/Inspector.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/Key Management Service.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/Macie.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/Network Firewall.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/Resource Access Manager.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/Secrets Manager.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/Security Hub.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/Security Lake.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/Shield.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/Signer.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/Verified Permissions.svg +17 -17
- package/apps/diagramming/public/aws-icons/security/WAF.svg +17 -17
- package/apps/diagramming/public/aws-icons/storage/Backup.svg +17 -17
- package/apps/diagramming/public/aws-icons/storage/EFS.svg +17 -17
- package/apps/diagramming/public/aws-icons/storage/Elastic Block Store.svg +17 -17
- package/apps/diagramming/public/aws-icons/storage/Elastic Disaster Recovery.svg +15 -15
- package/apps/diagramming/public/aws-icons/storage/FSx for Lustre.svg +17 -17
- package/apps/diagramming/public/aws-icons/storage/FSx for NetApp ONTAP.svg +17 -17
- package/apps/diagramming/public/aws-icons/storage/FSx for OpenZFS.svg +17 -17
- package/apps/diagramming/public/aws-icons/storage/FSx for WFS.svg +17 -17
- package/apps/diagramming/public/aws-icons/storage/FSx.svg +17 -17
- package/apps/diagramming/public/aws-icons/storage/File Cache.svg +17 -17
- package/apps/diagramming/public/aws-icons/storage/S3 on Outposts.svg +17 -17
- package/apps/diagramming/public/aws-icons/storage/Simple Storage Service Glacier.svg +17 -17
- package/apps/diagramming/public/aws-icons/storage/Simple Storage Service.svg +17 -17
- package/apps/diagramming/public/aws-icons/storage/Snowball Edge.svg +17 -17
- package/apps/diagramming/public/aws-icons/storage/Snowball.svg +17 -17
- package/apps/diagramming/public/aws-icons/storage/Snowcone.svg +17 -17
- package/apps/diagramming/public/aws-icons/storage/Snowmobile.svg +17 -17
- package/apps/diagramming/public/aws-icons/storage/Storage Gateway.svg +17 -17
- package/apps/diagramming/public/azure-icons/compute/02112-icon-service-Automanaged-VM.svg +1 -1
- package/apps/diagramming/public/azure-icons/databases/02390-icon-service-Azure-SQL.svg +1 -1
- package/apps/diagramming/public/azure-icons/databases/02392-icon-service-SSIS-Lift-And-Shift-IR.svg +1 -1
- package/apps/diagramming/public/azure-icons/networking/02145-icon-service-Resource-Management-Private-Link.svg +1 -1
- package/apps/diagramming/public/azure-icons/security/02247-icon-service-Microsoft-Defender-for-IoT.svg +1 -1
- package/apps/diagramming/public/sample-node-complete.json +63 -63
- package/apps/diagramming/public/sample-node-data.json +63 -63
- package/apps/diagramming/src/AutomationDiagramData.ts +147 -480
- package/apps/diagramming/src/CollaborationDiagramData.ts +127 -127
- package/apps/diagramming/src/CustomIconExamples.ts +233 -233
- package/apps/diagramming/src/DiagramTabs.tsx +205 -205
- package/apps/diagramming/src/Pages/DevPlayground.tsx +3 -3
- package/apps/diagramming/src/Pages/Home.tsx +111 -111
- package/apps/diagramming/src/SequenceDiagramData.ts +215 -215
- package/apps/diagramming/src/StateMachineDiagramData.ts +64 -64
- package/apps/diagramming/src/UseCaseDiagramData.ts +52 -52
- package/apps/diagramming/src/cloud-data.ts +371 -371
- package/apps/diagramming/src/components/AddNodeView.tsx +252 -252
- package/apps/diagramming/src/createSelecors.tsx +17 -17
- package/apps/diagramming/src/index.scss +12 -12
- package/apps/diagramming/src/main.tsx +463 -463
- package/apps/diagramming/src/node-data.ts +664 -664
- package/apps/diagramming/src/sample-workflow-content.ts +55 -55
- package/apps/diagramming/src/stencil-items.ts +31 -31
- package/apps/diagramming/src/style.css +13 -13
- package/apps/diagramming/src/tabsStore.tsx +152 -152
- package/apps/diagramming/src/vite-env.d.ts +1 -1
- package/apps/diagramming/tsconfig.app.json +23 -23
- package/apps/diagramming/tsconfig.json +21 -21
- package/apps/diagramming/tsconfig.spec.json +28 -28
- package/apps/diagramming/vite.config.ts +34 -34
- package/apps/diagramming/webpack.config.js +13 -13
- package/apps/workflow/.eslintrc.json +18 -18
- package/apps/workflow/group/group-form-hooks/index.ts +3 -3
- package/apps/workflow/group/group-form-hooks/useFormValidation.ts +20 -20
- package/apps/workflow/group/group-form-schema/SettingsTabFormSchema.ts +7 -7
- package/apps/workflow/group/group-form-schema/index.ts +3 -3
- package/apps/workflow/i18n.ts +19 -19
- package/apps/workflow/index.html +16 -16
- package/apps/workflow/locales/en/translation.json +713 -713
- package/apps/workflow/project.json +8 -8
- package/apps/workflow/src/app/app.module.css +1 -1
- package/apps/workflow/src/app/app.spec.tsx +15 -15
- package/apps/workflow/src/app/app.tsx +370 -370
- package/apps/workflow/src/main.tsx +13 -13
- package/apps/workflow/src/styles.css +1 -1
- package/apps/workflow/src/theme/index.ts +546 -546
- package/apps/workflow/tsconfig.app.json +23 -23
- package/apps/workflow/tsconfig.json +21 -21
- package/apps/workflow/tsconfig.spec.json +28 -28
- package/apps/workflow/vite.config.ts +51 -51
- package/nx.json +58 -58
- package/package.json +1 -1
- package/packages/api/.babelrc +12 -12
- package/packages/api/.eslintrc.json +18 -18
- package/packages/api/README.md +7 -7
- package/packages/api/project.json +8 -8
- package/packages/api/src/index.ts +3 -3
- package/packages/api/src/lib/jsonPlaceholderService/endpoints.ts +3 -3
- package/packages/api/src/lib/jsonPlaceholderService/service.ts +13 -13
- package/packages/api/tsconfig.json +17 -17
- package/packages/api/tsconfig.lib.json +24 -24
- package/packages/atoms/.babelrc +12 -12
- package/packages/atoms/.eslintrc.json +18 -18
- package/packages/atoms/README.md +7 -7
- package/packages/atoms/forms/AuthenticationTabForm/authenticationTabForm.json +224 -224
- package/packages/atoms/forms/AuthenticationTabForm/index.tsx +255 -255
- package/packages/atoms/forms/SettingsTabForm/index.tsx +85 -85
- package/packages/atoms/forms/SettingsTabForm/settingTabForm.json +27 -27
- package/packages/atoms/forms/index.ts +4 -4
- package/packages/atoms/project.json +8 -8
- package/packages/atoms/src/index.ts +33 -33
- package/packages/atoms/src/lib/Accordion/Accordion.module.css +7 -7
- package/packages/atoms/src/lib/Accordion/Accordion.spec.tsx +13 -13
- package/packages/atoms/src/lib/Accordion/Accordion.tsx +29 -29
- package/packages/atoms/src/lib/Alert/Alert.module.css +7 -7
- package/packages/atoms/src/lib/Alert/Alert.spec.tsx +10 -10
- package/packages/atoms/src/lib/Alert/Alert.tsx +19 -19
- package/packages/atoms/src/lib/Avatar/Avatar.module.css +7 -7
- package/packages/atoms/src/lib/Avatar/Avatar.spec.tsx +10 -10
- package/packages/atoms/src/lib/Avatar/Avatar.tsx +22 -22
- package/packages/atoms/src/lib/Box/Box.module.css +7 -7
- package/packages/atoms/src/lib/Box/Box.spec.tsx +10 -10
- package/packages/atoms/src/lib/Box/Box.tsx +19 -19
- package/packages/atoms/src/lib/BulkEdit/BulkEdit.module.css +7 -7
- package/packages/atoms/src/lib/BulkEdit/BulkEdit.spec.tsx +10 -10
- package/packages/atoms/src/lib/BulkEdit/BulkEdit.tsx +15 -15
- package/packages/atoms/src/lib/Button/Button.module.css +7 -7
- package/packages/atoms/src/lib/Button/Button.spec.tsx +10 -10
- package/packages/atoms/src/lib/Button/Button.tsx +78 -78
- package/packages/atoms/src/lib/Card/Card.module.css +7 -7
- package/packages/atoms/src/lib/Card/Card.spec.tsx +10 -10
- package/packages/atoms/src/lib/Card/Card.tsx +19 -19
- package/packages/atoms/src/lib/CardContent/CardContent.module.css +7 -7
- package/packages/atoms/src/lib/CardContent/CardContent.spec.tsx +10 -10
- package/packages/atoms/src/lib/CardContent/CardContent.tsx +22 -22
- package/packages/atoms/src/lib/FormTextField/FormTextField.module.css +7 -7
- package/packages/atoms/src/lib/FormTextField/FormTextField.spec.tsx +10 -10
- package/packages/atoms/src/lib/FormTextField/FormTextField.tsx +35 -35
- package/packages/atoms/src/lib/Grid/Grid.module.css +7 -7
- package/packages/atoms/src/lib/Grid/Grid.spec.tsx +10 -10
- package/packages/atoms/src/lib/Grid/Grid.tsx +19 -19
- package/packages/atoms/src/lib/Stack/Stack.module.css +7 -7
- package/packages/atoms/src/lib/Stack/Stack.spec.tsx +10 -10
- package/packages/atoms/src/lib/Stack/Stack.tsx +19 -19
- package/packages/atoms/src/lib/Switch/Switch.module.css +7 -7
- package/packages/atoms/src/lib/Switch/Switch.spec.tsx +10 -10
- package/packages/atoms/src/lib/Switch/Switch.tsx +46 -46
- package/packages/atoms/src/lib/TableView/TableView.module.css +7 -7
- package/packages/atoms/src/lib/TableView/TableView.spec.tsx +10 -10
- package/packages/atoms/src/lib/TableView/TableView.tsx +88 -88
- package/packages/atoms/src/lib/TextField/TextField.module.css +7 -7
- package/packages/atoms/src/lib/TextField/TextField.spec.tsx +10 -10
- package/packages/atoms/src/lib/TextField/TextField.tsx +17 -17
- package/packages/atoms/src/lib/Typography/Typography.module.css +7 -7
- package/packages/atoms/src/lib/Typography/Typography.spec.tsx +10 -10
- package/packages/atoms/src/lib/Typography/Typography.tsx +22 -22
- package/packages/atoms/tsconfig.json +17 -17
- package/packages/atoms/tsconfig.lib.json +30 -30
- package/packages/common/.babelrc +12 -12
- package/packages/common/.eslintrc.json +18 -18
- package/packages/common/README.md +7 -7
- package/packages/common/project.json +8 -8
- package/packages/common/src/index.ts +4 -4
- package/packages/common/src/lib/generateRandomProfilePic.ts +3 -3
- package/packages/common/src/lib/generateValidationSchema.ts +46 -46
- package/packages/common/tsconfig.json +17 -17
- package/packages/common/tsconfig.lib.json +24 -24
- package/packages/contexts/.babelrc +12 -12
- package/packages/contexts/.eslintrc.json +18 -18
- package/packages/contexts/README.md +7 -7
- package/packages/contexts/project.json +8 -8
- package/packages/contexts/src/index.ts +2 -2
- package/packages/contexts/tsconfig.json +17 -17
- package/packages/contexts/tsconfig.lib.json +24 -24
- package/packages/diagrams/.babelrc +12 -12
- package/packages/diagrams/.ctirc +208 -208
- package/packages/diagrams/.eslintrc.json +17 -17
- package/packages/diagrams/CUSTOM_ICONS.md +232 -232
- package/packages/diagrams/GOOGLE_SHEETS_IMPLEMENTATION.md +233 -233
- package/packages/diagrams/NODE_DATA_UPDATE_API.md +430 -430
- package/packages/diagrams/README.md +7 -7
- package/packages/diagrams/UNDO_REDO_API.md +306 -306
- package/packages/diagrams/locales/en/translation.json +713 -713
- package/packages/diagrams/package.json +27 -27
- package/packages/diagrams/pnpm-lock.yaml +2606 -2606
- package/packages/diagrams/project.json +42 -42
- package/packages/diagrams/rollup.config.js +26 -26
- package/packages/diagrams/src/DiagramFlow.tsx +7 -7
- package/packages/diagrams/src/declarations.d.ts +7 -7
- package/packages/diagrams/src/index.ts +8 -1
- package/packages/diagrams/src/index.ts.bak +99 -99
- package/packages/diagrams/src/lib/assets/markers/markers.param.tsx +101 -101
- package/packages/diagrams/src/lib/assets/markers/markers.type.ts +10 -10
- package/packages/diagrams/src/lib/atoms/ActorNode.tsx +123 -123
- package/packages/diagrams/src/lib/atoms/AddParallelColButton.tsx +26 -26
- package/packages/diagrams/src/lib/atoms/BendpointNode.tsx +71 -71
- package/packages/diagrams/src/lib/atoms/CardBlockTypeSelector.tsx +35 -35
- package/packages/diagrams/src/lib/atoms/CardEditableTitle.tsx +76 -76
- package/packages/diagrams/src/lib/atoms/CardMainContent.tsx +19 -19
- package/packages/diagrams/src/lib/atoms/ConnectionPoints.tsx +149 -149
- package/packages/diagrams/src/lib/atoms/ContentAssist.tsx +341 -341
- package/packages/diagrams/src/lib/atoms/DiagramControls.tsx +56 -56
- package/packages/diagrams/src/lib/atoms/ExpressionInput.tsx +437 -437
- package/packages/diagrams/src/lib/atoms/FloatingConnectionLine.tsx +73 -73
- package/packages/diagrams/src/lib/atoms/LazyIcon.tsx +31 -31
- package/packages/diagrams/src/lib/atoms/MarkerSelector.tsx +106 -106
- package/packages/diagrams/src/lib/atoms/MultiSelectInput.tsx +87 -87
- package/packages/diagrams/src/lib/atoms/ParameterInput.tsx +199 -199
- package/packages/diagrams/src/lib/atoms/PropertyInput.tsx +114 -114
- package/packages/diagrams/src/lib/atoms/StyledBox.tsx +69 -69
- package/packages/diagrams/src/lib/atoms/ValidationError.tsx +37 -37
- package/packages/diagrams/src/lib/atoms/ValidationMessage.tsx +63 -63
- package/packages/diagrams/src/lib/components/AiButton.tsx +52 -52
- package/packages/diagrams/src/lib/components/ControlEdgeList.tsx +303 -303
- package/packages/diagrams/src/lib/components/CreateFunctionModal.tsx +264 -264
- package/packages/diagrams/src/lib/components/CustomCodeModal.tsx +287 -287
- package/packages/diagrams/src/lib/components/DiagramPanel.tsx +331 -331
- package/packages/diagrams/src/lib/components/FunctionModalTooltip.tsx +30 -30
- package/packages/diagrams/src/lib/components/GraphQLCustomCodeModal.tsx +210 -210
- package/packages/diagrams/src/lib/components/Header.tsx +143 -143
- package/packages/diagrams/src/lib/components/MiniMapCommon.tsx +24 -24
- package/packages/diagrams/src/lib/components/ResizeIcon.tsx +81 -81
- package/packages/diagrams/src/lib/components/SideBar.tsx +40 -40
- package/packages/diagrams/src/lib/components/automation/AISuggestionsModal.tsx +269 -269
- package/packages/diagrams/src/lib/components/automation/AISuggestionsPanel.tsx +28 -175
- package/packages/diagrams/src/lib/components/automation/AutomationApiNode.tsx +1 -1
- package/packages/diagrams/src/lib/components/automation/AutomationDecisionNode.tsx +94 -0
- package/packages/diagrams/src/lib/components/automation/AutomationEndNode.tsx +1 -1
- package/packages/diagrams/src/lib/components/automation/AutomationExecutionPanel.tsx +439 -439
- package/packages/diagrams/src/lib/components/automation/AutomationFormattingNode.tsx +1 -1
- package/packages/diagrams/src/lib/components/automation/AutomationInteractionNode.tsx +693 -693
- package/packages/diagrams/src/lib/components/automation/AutomationMonitoringNode.tsx +399 -399
- package/packages/diagrams/src/lib/components/automation/AutomationNavigationNode.tsx +1 -1
- package/packages/diagrams/src/lib/components/automation/AutomationNodeCard.tsx +414 -0
- package/packages/diagrams/src/lib/components/automation/AutomationSlackNode.tsx +694 -694
- package/packages/diagrams/src/lib/components/automation/AutomationSmsNode.tsx +62 -0
- package/packages/diagrams/src/lib/components/automation/AutomationStartNode.tsx +1 -1
- package/packages/diagrams/src/lib/components/automation/AutomationTelegramNode.tsx +664 -664
- package/packages/diagrams/src/lib/components/automation/AutomationVoiceCallNode.tsx +65 -0
- package/packages/diagrams/src/lib/components/automation/AutomationWorkflowNode.tsx +85 -0
- package/packages/diagrams/src/lib/components/automation/NodeAIAssistantPopup.tsx +504 -504
- package/packages/diagrams/src/lib/components/automation/index.ts +29 -19
- package/packages/diagrams/src/lib/components/automation/statusColors.ts +124 -124
- package/packages/diagrams/src/lib/contexts/CardDataProvider.tsx +111 -111
- package/packages/diagrams/src/lib/contexts/DiagramProvider.tsx +392 -391
- package/packages/diagrams/src/lib/contexts/diagramStoreTypes.tsx +134 -134
- package/packages/diagrams/src/lib/contexts/onConnect.ts +39 -39
- package/packages/diagrams/src/lib/contexts/onDragStart.ts +45 -45
- package/packages/diagrams/src/lib/contexts/onNodeDragEnd.ts +179 -179
- package/packages/diagrams/src/lib/contexts/onNodesChange.ts +406 -406
- package/packages/diagrams/src/lib/contexts/onReconnect.ts +59 -59
- package/packages/diagrams/src/lib/contexts/onWorkflowNodeDelete.ts +65 -65
- package/packages/diagrams/src/lib/contexts/setContentHeight.ts +14 -14
- package/packages/diagrams/src/lib/contexts/setDiagramType.ts +10 -10
- package/packages/diagrams/src/lib/contexts/setEdgeShapeType.ts +7 -7
- package/packages/diagrams/src/lib/contexts/setEdges.ts +9 -9
- package/packages/diagrams/src/lib/contexts/setLayoutDirection.ts +9 -9
- package/packages/diagrams/src/lib/contexts/setNodeSetting.ts +17 -17
- package/packages/diagrams/src/lib/contexts/setNodes.ts +10 -10
- package/packages/diagrams/src/lib/contexts/setPannable.ts +7 -7
- package/packages/diagrams/src/lib/contexts/setSelectedEdge.ts +7 -7
- package/packages/diagrams/src/lib/contexts/setSelectedNode.ts +7 -7
- package/packages/diagrams/src/lib/contexts/undo.ts +163 -163
- package/packages/diagrams/src/lib/contexts/updateNodeSetting.ts +17 -17
- package/packages/diagrams/src/lib/examples/TwilioWhatsAppConfigExample.ts +128 -128
- package/packages/diagrams/src/lib/externals.ts +4 -4
- package/packages/diagrams/src/lib/hooks/customUseReactFlow.tsx +90 -90
- package/packages/diagrams/src/lib/hooks/updateNodes.ts +45 -45
- package/packages/diagrams/src/lib/hooks/useAddChildButton.tsx +61 -61
- package/packages/diagrams/src/lib/hooks/useAddSwitchCase.ts +75 -75
- package/packages/diagrams/src/lib/hooks/useAutoRegisterFunctions.ts +135 -135
- package/packages/diagrams/src/lib/hooks/useAutoRegisterVariables.ts +286 -286
- package/packages/diagrams/src/lib/hooks/useDeleteNodeByEvent.ts +64 -64
- package/packages/diagrams/src/lib/hooks/useDragCallbacks.tsx +122 -122
- package/packages/diagrams/src/lib/hooks/useFormValidation.ts +349 -349
- package/packages/diagrams/src/lib/hooks/useFunctionFormCallbacks.ts +136 -136
- package/packages/diagrams/src/lib/hooks/useIsSelectedNode.ts +11 -11
- package/packages/diagrams/src/lib/hooks/useModalControls.ts +13 -13
- package/packages/diagrams/src/lib/hooks/useNodeDragHandlers.ts +43 -43
- package/packages/diagrams/src/lib/hooks/useNodeSelection.ts +55 -55
- package/packages/diagrams/src/lib/hooks/useRenderDividers.tsx +19 -19
- package/packages/diagrams/src/lib/hooks/useRenderPins.tsx +74 -74
- package/packages/diagrams/src/lib/hooks/useResizeObserver.ts +21 -21
- package/packages/diagrams/src/lib/hooks/useTreeChildNode.ts +536 -536
- package/packages/diagrams/src/lib/i18n.ts +42 -42
- package/packages/diagrams/src/lib/icons/icons.tsx +324 -0
- package/packages/diagrams/src/lib/icons/index.ts +29 -0
- package/packages/diagrams/src/lib/icons/types.ts +7 -0
- package/packages/diagrams/src/lib/molecules/AddingBlock.tsx +147 -147
- package/packages/diagrams/src/lib/molecules/AvailableVariablesDisplay.tsx +57 -57
- package/packages/diagrams/src/lib/molecules/Block.tsx +143 -143
- package/packages/diagrams/src/lib/molecules/BlockProvider.tsx +28 -28
- package/packages/diagrams/src/lib/molecules/BlockWrapper.tsx +14 -14
- package/packages/diagrams/src/lib/molecules/ConditionRule.tsx +131 -131
- package/packages/diagrams/src/lib/molecules/DraggablePane.tsx +198 -198
- package/packages/diagrams/src/lib/molecules/EntityNodeBlocks.tsx +66 -66
- package/packages/diagrams/src/lib/molecules/SideHandles.tsx +215 -215
- package/packages/diagrams/src/lib/molecules/StencilItem.tsx +85 -85
- package/packages/diagrams/src/lib/molecules/WorkflowNodeActionButtons.tsx +62 -62
- package/packages/diagrams/src/lib/molecules/animated-add-button.tsx +83 -83
- package/packages/diagrams/src/lib/molecules/json-viewer.tsx +107 -107
- package/packages/diagrams/src/lib/organisms/AddNodeView.tsx +102 -102
- package/packages/diagrams/src/lib/organisms/Card/EntityNode.tsx +259 -259
- package/packages/diagrams/src/lib/organisms/Card/card.params.ts +29 -29
- package/packages/diagrams/src/lib/organisms/Card/card.types.ts +5 -5
- package/packages/diagrams/src/lib/organisms/CodeModal.tsx +105 -105
- package/packages/diagrams/src/lib/organisms/ConditionRuleGroup.tsx +138 -138
- package/packages/diagrams/src/lib/organisms/CustomEdge/EdgeMarkers.tsx +51 -51
- package/packages/diagrams/src/lib/organisms/CustomEdge/custom-edge-generator.tsx +135 -135
- package/packages/diagrams/src/lib/organisms/CustomEdge/custom-edge.params.ts +6 -6
- package/packages/diagrams/src/lib/organisms/CustomEdge/custom-edge.type.ts +15 -15
- package/packages/diagrams/src/lib/organisms/CustomEdge/useCreateBendPoint.tsx +121 -121
- package/packages/diagrams/src/lib/organisms/CustomEdge/useEdgeModal.ts +37 -37
- package/packages/diagrams/src/lib/organisms/CustomEdge/useEdgePath.tsx +99 -99
- package/packages/diagrams/src/lib/organisms/DownloadPanel.tsx +345 -345
- package/packages/diagrams/src/lib/organisms/EdgeModal.tsx +243 -243
- package/packages/diagrams/src/lib/organisms/HistoryPane.tsx +118 -118
- package/packages/diagrams/src/lib/organisms/NodeContextMenu.tsx +259 -259
- package/packages/diagrams/src/lib/organisms/PropertiesPane.tsx +276 -276
- package/packages/diagrams/src/lib/organisms/SmartDynamicForm.tsx +226 -226
- package/packages/diagrams/src/lib/organisms/Stencil.tsx +60 -60
- package/packages/diagrams/src/lib/organisms/UseDiagramStore.tsx +4 -4
- package/packages/diagrams/src/lib/organisms/WorkFlowNode/NodeActionButtons.tsx +45 -45
- package/packages/diagrams/src/lib/organisms/WorkFlowNode/NodeTypeDisplay.tsx +114 -114
- package/packages/diagrams/src/lib/organisms/WorkFlowNode/WorkflowNodeIcons.tsx +21 -23
- package/packages/diagrams/src/lib/organisms/WorkflowNode.tsx +484 -484
- package/packages/diagrams/src/lib/services/GoogleSheetsService.ts +961 -961
- package/packages/diagrams/src/lib/services/SlackService.ts +134 -134
- package/packages/diagrams/src/lib/services/TwilioWhatsAppService.ts +273 -273
- package/packages/diagrams/src/lib/styles.css +55 -55
- package/packages/diagrams/src/lib/templates/PageLinks.tsx +13 -13
- package/packages/diagrams/src/lib/templates/arch/ArchDiagram.tsx +793 -793
- package/packages/diagrams/src/lib/templates/arch/components/EdgeDialog.tsx +82 -82
- package/packages/diagrams/src/lib/templates/arch/components/EdgeSettings.tsx +81 -81
- package/packages/diagrams/src/lib/templates/arch/components/GroupControls.tsx +59 -59
- package/packages/diagrams/src/lib/templates/arch/components/GroupSizeDialog.tsx +81 -81
- package/packages/diagrams/src/lib/templates/arch/components/NodeDialog.tsx +214 -214
- package/packages/diagrams/src/lib/templates/arch/components/nodeTypes.ts +91 -91
- package/packages/diagrams/src/lib/templates/arch/controls/ArchDiagramControls.tsx +349 -349
- package/packages/diagrams/src/lib/templates/arch/data/templatee-data.ts +212 -212
- package/packages/diagrams/src/lib/templates/cloud-arch/components/CloudArchitectureDiagram.tsx +3912 -3912
- package/packages/diagrams/src/lib/templates/cloud-arch/components/FormatConverter.tsx +809 -809
- package/packages/diagrams/src/lib/templates/cloud-arch/components/FragmentImporter.tsx +276 -276
- package/packages/diagrams/src/lib/templates/cloud-arch/components/PropertiesPanel.tsx +1063 -1063
- package/packages/diagrams/src/lib/templates/cloud-arch/components/ServiceIconPicker.tsx +138 -138
- package/packages/diagrams/src/lib/templates/cloud-arch/components/SettingsSidebar.tsx +656 -656
- package/packages/diagrams/src/lib/templates/cloud-arch/components/SubnetSelector.tsx +468 -468
- package/packages/diagrams/src/lib/templates/cloud-arch/components/nodes/ServiceNode.tsx +310 -310
- package/packages/diagrams/src/lib/templates/cloud-arch/components/nodes/SubnetNode.tsx +475 -475
- package/packages/diagrams/src/lib/templates/cloud-arch/components/nodes/UsersNode.tsx +277 -277
- package/packages/diagrams/src/lib/templates/cloud-arch/data/diagramManager.ts +364 -364
- package/packages/diagrams/src/lib/templates/cloud-arch/data/types.ts +183 -183
- package/packages/diagrams/src/lib/templates/cloud-arch/integration/diagramValidator.ts +379 -379
- package/packages/diagrams/src/lib/templates/cloud-arch/messages/errorMessages.json +95 -95
- package/packages/diagrams/src/lib/templates/cloud-arch/types/localization.ts +368 -368
- package/packages/diagrams/src/lib/templates/cloud-arch/types/validation.ts +72 -72
- package/packages/diagrams/src/lib/templates/cloud-arch/utils/aws-icons.ts +557 -557
- package/packages/diagrams/src/lib/templates/cloud-arch/utils/awsValidation.ts +446 -446
- package/packages/diagrams/src/lib/templates/cloud-arch/utils/azure-icons.ts +802 -802
- package/packages/diagrams/src/lib/templates/cloud-arch/utils/azureValidation.ts +495 -495
- package/packages/diagrams/src/lib/templates/cloud-arch/utils/cloudValidation.ts +929 -929
- package/packages/diagrams/src/lib/templates/cloud-arch/utils/errorMessages.ts +283 -283
- package/packages/diagrams/src/lib/templates/cloud-arch/utils/gcp-icons.ts +186 -186
- package/packages/diagrams/src/lib/templates/cloud-arch/utils/gcpValidation.ts +312 -312
- package/packages/diagrams/src/lib/templates/cloud-arch/utils/genericValidation.ts +689 -689
- package/packages/diagrams/src/lib/templates/cloud-arch/utils/iconMapping.ts +383 -383
- package/packages/diagrams/src/lib/templates/cloud-arch/utils/idGenerator.ts +220 -220
- package/packages/diagrams/src/lib/templates/cloud-arch/utils/localizationManager.ts +300 -300
- package/packages/diagrams/src/lib/templates/cloud-arch/utils/restrictionEngine.ts +550 -550
- package/packages/diagrams/src/lib/templates/cloud-arch/utils/restrictionValidator.ts +400 -400
- package/packages/diagrams/src/lib/templates/cloud-arch/utils/serviceIcons.tsx +129 -129
- package/packages/diagrams/src/lib/templates/cloud-arch/utils/serviceMapping.ts +330 -330
- package/packages/diagrams/src/lib/templates/cloud-arch/utils/translations.ts +54 -54
- package/packages/diagrams/src/lib/templates/cloud-arch/utils/validationExtractor.ts +342 -342
- package/packages/diagrams/src/lib/templates/collaborationDiagram/CollaborationDiagram.tsx +15 -15
- package/packages/diagrams/src/lib/templates/collaborationDiagram/components/AddCollabEdgeDialog.tsx +181 -181
- package/packages/diagrams/src/lib/templates/collaborationDiagram/components/CollabLayout.ts +182 -182
- package/packages/diagrams/src/lib/templates/collaborationDiagram/components/CollabObjectNodeSettings.tsx +86 -86
- package/packages/diagrams/src/lib/templates/collaborationDiagram/components/CollaborationDiagramFlow.tsx +731 -731
- package/packages/diagrams/src/lib/templates/collaborationDiagram/components/DraggableEdgeLabel.tsx +123 -123
- package/packages/diagrams/src/lib/templates/collaborationDiagram/controls/CollaborationControls.tsx +131 -131
- package/packages/diagrams/src/lib/templates/collaborationDiagram/nodes/CollabEdge.tsx +170 -170
- package/packages/diagrams/src/lib/templates/collaborationDiagram/nodes/CollabObjectNode.tsx +178 -178
- package/packages/diagrams/src/lib/templates/home.style.css +16 -16
- package/packages/diagrams/src/lib/templates/node-forms/ApiForm.tsx +416 -416
- package/packages/diagrams/src/lib/templates/node-forms/CallForm.tsx +370 -370
- package/packages/diagrams/src/lib/templates/node-forms/ForLoopNode.tsx +313 -313
- package/packages/diagrams/src/lib/templates/node-forms/FunctionForm.tsx +211 -211
- package/packages/diagrams/src/lib/templates/node-forms/GraphQLForm.tsx +679 -679
- package/packages/diagrams/src/lib/templates/node-forms/IfNodeForm.tsx +97 -97
- package/packages/diagrams/src/lib/templates/node-forms/LetNodeForm.tsx +533 -533
- package/packages/diagrams/src/lib/templates/node-forms/LoopNode.tsx +149 -149
- package/packages/diagrams/src/lib/templates/node-forms/NodeForm.tsx +383 -383
- package/packages/diagrams/src/lib/templates/node-forms/ReturnNodeForm.tsx +96 -96
- package/packages/diagrams/src/lib/templates/node-forms/SetNodeForm.tsx +141 -141
- package/packages/diagrams/src/lib/templates/node-forms/SwitchNodeForm.tsx +249 -249
- package/packages/diagrams/src/lib/templates/node-forms/TryCatchForm.tsx +167 -167
- package/packages/diagrams/src/lib/templates/nodeFormSchema.json +84 -84
- package/packages/diagrams/src/lib/templates/sequence/SequenceDiagram.tsx +22 -22
- package/packages/diagrams/src/lib/templates/sequence/components/ActivationBarNode.tsx +33 -33
- package/packages/diagrams/src/lib/templates/sequence/components/AddMessageDialog.tsx +302 -302
- package/packages/diagrams/src/lib/templates/sequence/components/CombinedFragmentNode.tsx +65 -65
- package/packages/diagrams/src/lib/templates/sequence/components/EntitySettings.tsx +559 -559
- package/packages/diagrams/src/lib/templates/sequence/components/FragmentSettings.tsx +116 -116
- package/packages/diagrams/src/lib/templates/sequence/components/SequenceComponents.tsx +14 -14
- package/packages/diagrams/src/lib/templates/sequence/components/SequenceDiagramFlow.tsx +1361 -1361
- package/packages/diagrams/src/lib/templates/sequence/components/SequenceEntityNode.tsx +394 -394
- package/packages/diagrams/src/lib/templates/sequence/components/SequenceMessageEdge.tsx +272 -272
- package/packages/diagrams/src/lib/templates/sequence/components/SimpleEntitySettings.tsx +89 -89
- package/packages/diagrams/src/lib/templates/sequence/controls/DiagramControls.tsx +707 -707
- package/packages/diagrams/src/lib/templates/sequence/data/template-data.ts +635 -635
- package/packages/diagrams/src/lib/templates/stateMachine/StateMachineDiagram.tsx +66 -66
- package/packages/diagrams/src/lib/templates/stateMachine/components/CompositeStateNodeSettings.tsx +638 -638
- package/packages/diagrams/src/lib/templates/stateMachine/components/CustomEdge.tsx +220 -220
- package/packages/diagrams/src/lib/templates/stateMachine/components/EdgeSettings.tsx +193 -193
- package/packages/diagrams/src/lib/templates/stateMachine/components/SelfConnectingEdge.tsx +41 -41
- package/packages/diagrams/src/lib/templates/stateMachine/components/StateMachineComponents.tsx +49 -49
- package/packages/diagrams/src/lib/templates/stateMachine/components/StateMachineDiagramFlow.tsx +1238 -1238
- package/packages/diagrams/src/lib/templates/stateMachine/components/StateMachineLayout.ts +350 -350
- package/packages/diagrams/src/lib/templates/stateMachine/components/StateNodeSettings.tsx +188 -188
- package/packages/diagrams/src/lib/templates/stateMachine/components/useSelfTransition.ts +114 -114
- package/packages/diagrams/src/lib/templates/stateMachine/controls/StateDiagramControls.tsx +488 -488
- package/packages/diagrams/src/lib/templates/stateMachine/data/template-data.ts +4 -4
- package/packages/diagrams/src/lib/templates/stateMachine/nodes/ChoicePointNode.tsx +54 -54
- package/packages/diagrams/src/lib/templates/stateMachine/nodes/CompositeStateNode.tsx +225 -225
- package/packages/diagrams/src/lib/templates/stateMachine/nodes/EntryPointNode.tsx +31 -31
- package/packages/diagrams/src/lib/templates/stateMachine/nodes/ExitPointNode.tsx +44 -44
- package/packages/diagrams/src/lib/templates/stateMachine/nodes/FinalStateNode.tsx +41 -41
- package/packages/diagrams/src/lib/templates/stateMachine/nodes/ForkJoinNode.tsx +53 -53
- package/packages/diagrams/src/lib/templates/stateMachine/nodes/HistoryStateNode.tsx +36 -36
- package/packages/diagrams/src/lib/templates/stateMachine/nodes/InitialStateNode.tsx +29 -29
- package/packages/diagrams/src/lib/templates/stateMachine/nodes/JunctionPointNode.tsx +33 -33
- package/packages/diagrams/src/lib/templates/stateMachine/nodes/PinPointNode.tsx +111 -111
- package/packages/diagrams/src/lib/templates/stateMachine/nodes/StateNode.tsx +124 -124
- package/packages/diagrams/src/lib/templates/stateMachine/nodes/bendPoint.tsx +71 -71
- package/packages/diagrams/src/lib/templates/systemFlow/SystemFlowDiagram.tsx +67 -67
- package/packages/diagrams/src/lib/templates/systemFlow/components/EdgeSettings.tsx +330 -330
- package/packages/diagrams/src/lib/templates/systemFlow/components/FloatingEdge.tsx +219 -219
- package/packages/diagrams/src/lib/templates/systemFlow/components/SystemFlowComponents.tsx +28 -28
- package/packages/diagrams/src/lib/templates/systemFlow/components/SystemFlowDiagramFlow.tsx +1179 -1179
- package/packages/diagrams/src/lib/templates/systemFlow/components/SystemFlowNodeSettings.tsx +151 -151
- package/packages/diagrams/src/lib/templates/systemFlow/controls/SystemFlowControls.tsx +435 -435
- package/packages/diagrams/src/lib/templates/systemFlow/data/template-data.ts +308 -308
- package/packages/diagrams/src/lib/templates/systemFlow/demo.tsx +91 -91
- package/packages/diagrams/src/lib/templates/systemFlow/index.ts +5 -5
- package/packages/diagrams/src/lib/templates/systemFlow/nodes/BendpointNode.tsx +80 -80
- package/packages/diagrams/src/lib/templates/systemFlow/nodes/SystemNode.tsx +92 -92
- package/packages/diagrams/src/lib/templates/systemFlow/nodes/TreeSystemNode.tsx +755 -755
- package/packages/diagrams/src/lib/templates/useCaseDiagram/UseCaseDiagram.tsx +16 -16
- package/packages/diagrams/src/lib/templates/useCaseDiagram/components/ActorNodeSettings.tsx +103 -103
- package/packages/diagrams/src/lib/templates/useCaseDiagram/components/AddRelationshipDialog.tsx +186 -186
- package/packages/diagrams/src/lib/templates/useCaseDiagram/components/PackageNodeSettings.tsx +205 -205
- package/packages/diagrams/src/lib/templates/useCaseDiagram/components/UseCaseDiagramFlow.tsx +637 -637
- package/packages/diagrams/src/lib/templates/useCaseDiagram/components/UseCaseNodeSettings.tsx +120 -120
- package/packages/diagrams/src/lib/templates/useCaseDiagram/controls/UseCaseControls.tsx +289 -289
- package/packages/diagrams/src/lib/templates/useCaseDiagram/nodes/PackageNode.tsx +83 -83
- package/packages/diagrams/src/lib/templates/useCaseDiagram/nodes/UseCaseEdge.tsx +115 -115
- package/packages/diagrams/src/lib/templates/useCaseDiagram/nodes/UseCaseNode.tsx +230 -230
- package/packages/diagrams/src/lib/templates/validationSchema.json +277 -277
- package/packages/diagrams/src/lib/theme.ts +439 -439
- package/packages/diagrams/src/lib/types/FunctionSignature.ts +11 -11
- package/packages/diagrams/src/lib/types/SmartDynamicFormField.ts +37 -37
- package/packages/diagrams/src/lib/types/automation-node-data-types.ts +45 -131
- package/packages/diagrams/src/lib/types/available-variables.ts +18 -18
- package/packages/diagrams/src/lib/types/card-node.ts +68 -68
- package/packages/diagrams/src/lib/types/collaboration-types.ts +114 -114
- package/packages/diagrams/src/lib/types/colors.ts +25 -25
- package/packages/diagrams/src/lib/types/condition-builder.ts +18 -18
- package/packages/diagrams/src/lib/types/diagram-types.ts +14 -14
- package/packages/diagrams/src/lib/types/edge-types.ts +39 -39
- package/packages/diagrams/src/lib/types/function-execution.ts +35 -35
- package/packages/diagrams/src/lib/types/hooks.types.ts +6 -6
- package/packages/diagrams/src/lib/types/ndoe-form-types.ts +139 -139
- package/packages/diagrams/src/lib/types/node-types.ts +13 -23
- package/packages/diagrams/src/lib/types/sequence-types.ts +178 -178
- package/packages/diagrams/src/lib/types/shared-node-types.ts +21 -21
- package/packages/diagrams/src/lib/types/state-machine-types.ts +225 -225
- package/packages/diagrams/src/lib/types/stencil-item.ts +7 -7
- package/packages/diagrams/src/lib/types/structures.ts +80 -80
- package/packages/diagrams/src/lib/types/system-flow-types.ts +129 -129
- package/packages/diagrams/src/lib/types/usecase-types.ts +84 -84
- package/packages/diagrams/src/lib/types/validation-types.ts +134 -134
- package/packages/diagrams/src/lib/types/workflow-content-dynamic-form-type.ts +23 -23
- package/packages/diagrams/src/lib/types/workflow-node-data-types.ts +172 -172
- package/packages/diagrams/src/lib/utils/AutomationExecutionEngine.ts +658 -1179
- package/packages/diagrams/src/lib/utils/add-new-block.ts +34 -34
- package/packages/diagrams/src/lib/utils/add-new-node.ts +52 -52
- package/packages/diagrams/src/lib/utils/addToHistory.ts +15 -15
- package/packages/diagrams/src/lib/utils/automation-flow-processor.ts +556 -619
- package/packages/diagrams/src/lib/utils/closestPoint.ts +45 -45
- package/packages/diagrams/src/lib/utils/color-options.tsx +26 -26
- package/packages/diagrams/src/lib/utils/compress-img.ts +59 -59
- package/packages/diagrams/src/lib/utils/configLoader.ts +329 -329
- package/packages/diagrams/src/lib/utils/constant-lengths.ts +8 -8
- package/packages/diagrams/src/lib/utils/create-updated.tsx +40 -40
- package/packages/diagrams/src/lib/utils/createHistoryChange.ts +3 -3
- package/packages/diagrams/src/lib/utils/dividerUtils.tsx +59 -59
- package/packages/diagrams/src/lib/utils/edge-hooks.ts +53 -53
- package/packages/diagrams/src/lib/utils/elkLayout.ts +297 -297
- package/packages/diagrams/src/lib/utils/event-hooks.ts +69 -69
- package/packages/diagrams/src/lib/utils/event-store.ts +58 -58
- package/packages/diagrams/src/lib/utils/flow-node-hooks.ts +28 -28
- package/packages/diagrams/src/lib/utils/flow-to-js.ts +1465 -1465
- package/packages/diagrams/src/lib/utils/functionGenerator.ts +38 -38
- package/packages/diagrams/src/lib/utils/generateEdgesFromNodeOrder.ts +113 -113
- package/packages/diagrams/src/lib/utils/helpers.types.ts +10 -10
- package/packages/diagrams/src/lib/utils/highlightText.tsx +93 -93
- package/packages/diagrams/src/lib/utils/iconMapper.tsx +76 -76
- package/packages/diagrams/src/lib/utils/logger.ts +5 -5
- package/packages/diagrams/src/lib/utils/model-hooks.ts +129 -129
- package/packages/diagrams/src/lib/utils/node-hooks.ts +78 -78
- package/packages/diagrams/src/lib/utils/nodeAIAssistantConfig.ts +54 -54
- package/packages/diagrams/src/lib/utils/nodeOrderByEdges.ts +437 -437
- package/packages/diagrams/src/lib/utils/nodeutils.ts +242 -242
- package/packages/diagrams/src/lib/utils/object.ts +13 -13
- package/packages/diagrams/src/lib/utils/useDebounce.ts +19 -19
- package/packages/diagrams/src/lib/utils/utilities.ts +105 -105
- package/packages/diagrams/src/lib/utils/validationEngine.ts +610 -610
- package/packages/diagrams/src/lib/utils/vhToPixels.ts +9 -9
- package/packages/diagrams/tsconfig.json +21 -21
- package/packages/diagrams/tsconfig.lib.json +26 -25
- package/packages/diagrams/webpack.config.js +17 -17
- package/packages/interfaces/.babelrc +12 -12
- package/packages/interfaces/.eslintrc.json +18 -18
- package/packages/interfaces/README.md +7 -7
- package/packages/interfaces/project.json +8 -8
- package/packages/interfaces/src/index.ts +21 -21
- package/packages/interfaces/src/lib/Button.tsx +1 -1
- package/packages/interfaces/src/lib/DataGrid.ts +14 -14
- package/packages/interfaces/src/lib/StyledBox.tsx +1 -1
- package/packages/interfaces/src/lib/ToolbarItem.ts +7 -7
- package/packages/interfaces/src/lib/UserCard.ts +8 -8
- package/packages/interfaces/src/lib/yup.ts +3 -3
- package/packages/interfaces/tsconfig.json +17 -17
- package/packages/interfaces/tsconfig.lib.json +24 -24
- package/packages/molecules/.babelrc +12 -12
- package/packages/molecules/.eslintrc.json +18 -18
- package/packages/molecules/README.md +7 -7
- package/packages/molecules/project.json +8 -8
- package/packages/molecules/src/index.ts +47 -41
- package/packages/molecules/src/lib/ActionTextField/ActionTextField.module.css +7 -7
- package/packages/molecules/src/lib/ActionTextField/ActionTextField.spec.tsx +10 -10
- package/packages/molecules/src/lib/ActionTextField/ActionTextField.tsx +33 -33
- package/packages/molecules/src/lib/ClosableButton/CloseableButton.module.css +7 -7
- package/packages/molecules/src/lib/ClosableButton/CloseableButton.spec.tsx +11 -11
- package/packages/molecules/src/lib/ClosableButton/CloseableButton.tsx +69 -69
- package/packages/molecules/src/lib/EditorTab/EditorTab.module.css +7 -7
- package/packages/molecules/src/lib/EditorTab/EditorTab.spec.tsx +10 -10
- package/packages/molecules/src/lib/EditorTab/EditorTab.tsx +42 -42
- package/packages/molecules/src/lib/EditorTab/TabPanel.tsx +25 -25
- package/packages/molecules/src/lib/ParamsActionField/ParamsActionField.module.css +7 -7
- package/packages/molecules/src/lib/ParamsActionField/ParamsActionField.spec.tsx +10 -10
- package/packages/molecules/src/lib/ParamsActionField/ParamsActionField.tsx +24 -24
- package/packages/molecules/src/lib/SvgIcons/icons.tsx +323 -291
- package/packages/molecules/src/lib/SvgIcons/index.ts +31 -25
- package/packages/molecules/src/lib/SvgIcons/types.ts +7 -7
- package/packages/molecules/src/lib/TableWithInlineView/TableWithInlineView.module.css +7 -7
- package/packages/molecules/src/lib/TableWithInlineView/TableWithInlineView.spec.tsx +10 -10
- package/packages/molecules/src/lib/TableWithInlineView/TableWithInlineView.tsx +47 -47
- package/packages/molecules/src/lib/UserCard/UserCard.module.css +7 -7
- package/packages/molecules/src/lib/UserCard/UserCard.spec.tsx +11 -11
- package/packages/molecules/src/lib/UserCard/UserCard.tsx +22 -22
- package/packages/molecules/src/lib/VerbSelection/HTTPVerbSelection.module.css +7 -7
- package/packages/molecules/src/lib/VerbSelection/HTTPVerbSelection.spec.tsx +10 -10
- package/packages/molecules/src/lib/VerbSelection/HTTPVerbSelection.tsx +72 -72
- package/packages/molecules/tsconfig.json +17 -17
- package/packages/molecules/tsconfig.lib.json +30 -30
- package/packages/organisms/.babelrc +12 -12
- package/packages/organisms/.eslintrc.json +18 -18
- package/packages/organisms/README.md +7 -7
- package/packages/organisms/project.json +8 -8
- package/packages/organisms/src/index.ts +4 -4
- package/packages/organisms/src/lib/EditorToolbar/EditorToolbar.module.css +7 -7
- package/packages/organisms/src/lib/EditorToolbar/EditorToolbar.spec.tsx +10 -10
- package/packages/organisms/src/lib/EditorToolbar/EditorToolbar.tsx +117 -117
- package/packages/organisms/src/lib/EditorToolbar/SortableItem.tsx +51 -51
- package/packages/organisms/src/lib/UserList/UserList.module.css +7 -7
- package/packages/organisms/src/lib/UserList/UserList.spec.tsx +11 -11
- package/packages/organisms/src/lib/UserList/UserList.tsx +48 -48
- package/packages/organisms/src/lib/UserList/store.ts +49 -49
- package/packages/organisms/tsconfig.json +17 -17
- package/packages/organisms/tsconfig.lib.json +24 -24
- package/packages/zustand/.babelrc +12 -12
- package/packages/zustand/.eslintrc.json +18 -18
- package/packages/zustand/README.md +7 -7
- package/packages/zustand/project.json +8 -8
- package/packages/zustand/src/index.ts +4 -4
- package/packages/zustand/tsconfig.json +17 -17
- package/packages/zustand/tsconfig.lib.json +24 -24
- package/tsconfig.base.json +29 -29
- package/packages/diagrams/src/lib/components/automation/AutomationAISuggestionNode.tsx +0 -304
- package/packages/diagrams/src/lib/components/automation/AutomationEmailNode.tsx +0 -773
- package/packages/diagrams/src/lib/components/automation/AutomationGoogleServicesNode.tsx +0 -779
- package/packages/diagrams/src/lib/components/automation/AutomationNoteNode.tsx +0 -422
- package/packages/diagrams/src/lib/components/automation/AutomationSheetsNode.tsx +0 -1135
- package/packages/diagrams/src/lib/examples/GoogleSheetsConfigurationExamples.ts +0 -306
|
@@ -1,1179 +1,1179 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
useCallback,
|
|
3
|
-
useState,
|
|
4
|
-
useRef,
|
|
5
|
-
useEffect,
|
|
6
|
-
useMemo,
|
|
7
|
-
} from 'react';
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
ReactFlow,
|
|
11
|
-
Background,
|
|
12
|
-
useNodesState,
|
|
13
|
-
useEdgesState,
|
|
14
|
-
useReactFlow,
|
|
15
|
-
Panel,
|
|
16
|
-
BackgroundVariant,
|
|
17
|
-
Connection,
|
|
18
|
-
NodeChange,
|
|
19
|
-
applyNodeChanges,
|
|
20
|
-
ReactFlowProvider,
|
|
21
|
-
Node,
|
|
22
|
-
Edge,
|
|
23
|
-
NodeProps,
|
|
24
|
-
} from '@xyflow/react';
|
|
25
|
-
import '@xyflow/react/dist/style.css';
|
|
26
|
-
import {
|
|
27
|
-
SystemFlowNode,
|
|
28
|
-
SystemFlowEdge,
|
|
29
|
-
HistoryState,
|
|
30
|
-
EditingState,
|
|
31
|
-
SystemFlowNodeSettingsState,
|
|
32
|
-
SystemFlowEdgeSettingsState,
|
|
33
|
-
NodeSelectionContextType,
|
|
34
|
-
LayoutDirection,
|
|
35
|
-
UpdateFunction,
|
|
36
|
-
CloseFunction,
|
|
37
|
-
DeleteFunction
|
|
38
|
-
} from '../../../types/system-flow-types';
|
|
39
|
-
|
|
40
|
-
import {
|
|
41
|
-
Box,
|
|
42
|
-
Button,
|
|
43
|
-
Paper,
|
|
44
|
-
ToggleButton,
|
|
45
|
-
ToggleButtonGroup,
|
|
46
|
-
Snackbar,
|
|
47
|
-
Alert,
|
|
48
|
-
} from '@mui/material';
|
|
49
|
-
import DownloadIcon from '@mui/icons-material/Download';
|
|
50
|
-
import UploadIcon from '@mui/icons-material/Upload';
|
|
51
|
-
import FullscreenIcon from '@mui/icons-material/Fullscreen';
|
|
52
|
-
import FullscreenExitIcon from '@mui/icons-material/FullscreenExit';
|
|
53
|
-
import CloseIcon from '@mui/icons-material/Close';
|
|
54
|
-
import UndoIcon from '@mui/icons-material/Undo';
|
|
55
|
-
import RedoIcon from '@mui/icons-material/Redo';
|
|
56
|
-
import ViewWeekIcon from '@mui/icons-material/ViewWeek';
|
|
57
|
-
import ViewStreamIcon from '@mui/icons-material/ViewStream';
|
|
58
|
-
import {
|
|
59
|
-
systemFlowDefaultNodes,
|
|
60
|
-
systemFlowDefaultEdges,
|
|
61
|
-
treeStructureTemplate,
|
|
62
|
-
treeStructureTemplate1,
|
|
63
|
-
treeStructureTemplate2,
|
|
64
|
-
treeStructureTemplate3,
|
|
65
|
-
} from '../data/template-data';
|
|
66
|
-
import {
|
|
67
|
-
systemFlowEdgeTypes,
|
|
68
|
-
systemFlowNodeTypes as baseSystemFlowNodeTypes,
|
|
69
|
-
} from './SystemFlowComponents';
|
|
70
|
-
import DiagramControls from '../controls/SystemFlowControls';
|
|
71
|
-
import { NodeSelectionContext } from '../controls/SystemFlowControls';
|
|
72
|
-
import SystemFlowNodeSettings from './SystemFlowNodeSettings';
|
|
73
|
-
import EdgeSettings from './EdgeSettings';
|
|
74
|
-
import DiagramPanel from '../../../components/DiagramPanel';
|
|
75
|
-
import Sidebar from '../../../components/SideBar';
|
|
76
|
-
import AiButton from '../../../components/AiButton';
|
|
77
|
-
import MiniMapCommon from '../../../components/MiniMapCommon';
|
|
78
|
-
|
|
79
|
-
// Browser-specific fullscreen API types
|
|
80
|
-
interface WebkitElement extends Element {
|
|
81
|
-
webkitRequestFullscreen(): Promise<void>;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
interface WebkitDocument extends Document {
|
|
85
|
-
webkitExitFullscreen(): Promise<void>;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
interface MSElement extends Element {
|
|
89
|
-
msRequestFullscreen(): Promise<void>;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
interface MSDocument extends Document {
|
|
93
|
-
msExitFullscreen(): Promise<void>;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
interface SystemFlowDiagramFlowProps {
|
|
97
|
-
nodes: SystemFlowNode[];
|
|
98
|
-
setNodes: (nodes: SystemFlowNode[] | ((prev: SystemFlowNode[]) => SystemFlowNode[])) => void;
|
|
99
|
-
edges: SystemFlowEdge[];
|
|
100
|
-
setEdges: (edges: SystemFlowEdge[] | ((prev: SystemFlowEdge[]) => SystemFlowEdge[])) => void;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Utility: Deep compare node arrays by id, type, data, width, height
|
|
104
|
-
const deepCompareNodes = (a: Node[], b: Node[]) => {
|
|
105
|
-
if (a.length !== b.length) return false;
|
|
106
|
-
for (let i = 0; i < a.length; i++) {
|
|
107
|
-
const nodeA = a[i];
|
|
108
|
-
const nodeB = b[i];
|
|
109
|
-
if (
|
|
110
|
-
nodeA.id !== nodeB.id ||
|
|
111
|
-
nodeA.type !== nodeB.type ||
|
|
112
|
-
JSON.stringify(nodeA.data) !== JSON.stringify(nodeB.data)
|
|
113
|
-
) {
|
|
114
|
-
return false;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
return true;
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
// Utility: Deep compare edge arrays by id, source, target, type, data
|
|
121
|
-
const deepCompareEdges = (a: Edge[], b: Edge[]) => {
|
|
122
|
-
if (a.length !== b.length) return false;
|
|
123
|
-
for (let i = 0; i < a.length; i++) {
|
|
124
|
-
const edgeA = a[i];
|
|
125
|
-
const edgeB = b[i];
|
|
126
|
-
if (
|
|
127
|
-
edgeA.id !== edgeB.id ||
|
|
128
|
-
edgeA.source !== edgeB.source ||
|
|
129
|
-
edgeA.target !== edgeB.target ||
|
|
130
|
-
edgeA.type !== edgeB.type ||
|
|
131
|
-
JSON.stringify(edgeA.data) !== JSON.stringify(edgeB.data)
|
|
132
|
-
) {
|
|
133
|
-
return false;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
return true;
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
// Debounce utility
|
|
140
|
-
const debounce = (fn: Function, delay: number) => {
|
|
141
|
-
let timer: NodeJS.Timeout | null = null;
|
|
142
|
-
return (...args: unknown[]) => {
|
|
143
|
-
if (timer) clearTimeout(timer);
|
|
144
|
-
timer = setTimeout(() => fn(...args), delay);
|
|
145
|
-
};
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
// Helper: get center position in diagram
|
|
149
|
-
const getCenterPosition = (width: number, height: number) => {
|
|
150
|
-
return { x: width / 2 - 75, y: height / 2 - 40 };
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
const SystemFlowDiagramFlowContent: React.FC<
|
|
154
|
-
SystemFlowDiagramFlowProps
|
|
155
|
-
> = React.memo(({
|
|
156
|
-
nodes: initialNodes,
|
|
157
|
-
setNodes: parentSetNodes,
|
|
158
|
-
edges: initialEdges,
|
|
159
|
-
setEdges: parentSetEdges,
|
|
160
|
-
}) => {
|
|
161
|
-
// State declarations
|
|
162
|
-
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes as Node[]);
|
|
163
|
-
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges as Edge[]);
|
|
164
|
-
|
|
165
|
-
// Custom onNodesChange handler for synchronized tree structure movement
|
|
166
|
-
const customOnNodesChange = useCallback((changes: NodeChange[]) => {
|
|
167
|
-
// First apply the default changes
|
|
168
|
-
onNodesChange(changes);
|
|
169
|
-
|
|
170
|
-
// Then handle synchronized movement for tree structure nodes
|
|
171
|
-
changes.forEach((change: NodeChange) => {
|
|
172
|
-
if (change.type === 'position' && 'position' in change && change.position) {
|
|
173
|
-
const position = change.position as { x: number; y: number };
|
|
174
|
-
const node = nodes.find(n => n.id === change.id);
|
|
175
|
-
|
|
176
|
-
if (node && node.data.isTreeStructure && node.data.structureId) {
|
|
177
|
-
// This is a tree structure node being moved, move all nodes in the same structure
|
|
178
|
-
const currentNode = nodes.find(n => n.id === change.id);
|
|
179
|
-
if (!currentNode) return;
|
|
180
|
-
|
|
181
|
-
// Calculate the delta movement
|
|
182
|
-
const deltaX = position.x - currentNode.position.x;
|
|
183
|
-
const deltaY = position.y - currentNode.position.y;
|
|
184
|
-
|
|
185
|
-
// Move all nodes in the same structure by the same delta
|
|
186
|
-
const updatedNodes = nodes.map(n => {
|
|
187
|
-
if (n.data.isTreeStructure && n.data.structureId === node.data.structureId) {
|
|
188
|
-
return {
|
|
189
|
-
...n,
|
|
190
|
-
position: {
|
|
191
|
-
x: n.position.x + deltaX,
|
|
192
|
-
y: n.position.y + deltaY
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
return n;
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
setNodes(updatedNodes);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
}, [nodes, setNodes, onNodesChange]);
|
|
204
|
-
const [history, setHistory] = useState<HistoryState[]>([]);
|
|
205
|
-
const [historyIndex, setHistoryIndex] = useState<number>(-1);
|
|
206
|
-
const isUndoRedoAction = useRef(false);
|
|
207
|
-
const [isFullscreen, setIsFullscreen] = useState<boolean>(false);
|
|
208
|
-
const diagramContainerRef = useRef<HTMLDivElement>(null);
|
|
209
|
-
const [editing, setEditing] = useState<{
|
|
210
|
-
nodeId?: string | null;
|
|
211
|
-
edgeId?: string | null;
|
|
212
|
-
label?: string;
|
|
213
|
-
type?: 'node' | 'edge';
|
|
214
|
-
}>({});
|
|
215
|
-
const [systemFlowNodeSettings, setSystemFlowNodeSettings] = useState<{
|
|
216
|
-
id: string | null;
|
|
217
|
-
}>({ id: null });
|
|
218
|
-
const [edgeSettings, setEdgeSettings] = useState<{ id: string | null }>({
|
|
219
|
-
id: null,
|
|
220
|
-
});
|
|
221
|
-
const [isSettingsSidebarOpen, setIsSettingsSidebarOpen] = useState(false);
|
|
222
|
-
|
|
223
|
-
// Track if a child node has been edited and needs layout recalculation
|
|
224
|
-
const [pendingLayoutRecalculation, setPendingLayoutRecalculation] = useState<{
|
|
225
|
-
structureId: string;
|
|
226
|
-
rootNodeId: string;
|
|
227
|
-
} | null>(null);
|
|
228
|
-
|
|
229
|
-
// Function declarations in correct order
|
|
230
|
-
const saveLabel = useCallback(() => {
|
|
231
|
-
if (editing.nodeId && editing.type === 'node') {
|
|
232
|
-
setNodes((nds: Node[]) =>
|
|
233
|
-
nds.map((node: Node) => {
|
|
234
|
-
if (node.id === editing.nodeId) {
|
|
235
|
-
return {
|
|
236
|
-
...node,
|
|
237
|
-
data: {
|
|
238
|
-
...node.data,
|
|
239
|
-
label: editing.label,
|
|
240
|
-
},
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
return node;
|
|
244
|
-
}),
|
|
245
|
-
);
|
|
246
|
-
setEditing({
|
|
247
|
-
nodeId: undefined,
|
|
248
|
-
edgeId: undefined,
|
|
249
|
-
label: undefined,
|
|
250
|
-
type: undefined,
|
|
251
|
-
});
|
|
252
|
-
} else if (editing.edgeId && editing.type === 'edge') {
|
|
253
|
-
setEdges((eds: Edge[]) =>
|
|
254
|
-
eds.map((edge: Edge) => {
|
|
255
|
-
if (edge.id === editing.edgeId) {
|
|
256
|
-
return {
|
|
257
|
-
...edge,
|
|
258
|
-
data: {
|
|
259
|
-
...edge.data,
|
|
260
|
-
label: editing.label,
|
|
261
|
-
},
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
return edge;
|
|
265
|
-
}),
|
|
266
|
-
);
|
|
267
|
-
setEditing({
|
|
268
|
-
nodeId: undefined,
|
|
269
|
-
edgeId: undefined,
|
|
270
|
-
label: undefined,
|
|
271
|
-
type: undefined,
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
}, [editing, setNodes, setEdges]);
|
|
275
|
-
|
|
276
|
-
const handleKeyDown = useCallback(
|
|
277
|
-
(e: React.KeyboardEvent) => {
|
|
278
|
-
if (e.key === 'Enter') {
|
|
279
|
-
saveLabel();
|
|
280
|
-
} else if (e.key === 'Escape') {
|
|
281
|
-
setEditing({
|
|
282
|
-
nodeId: undefined,
|
|
283
|
-
edgeId: undefined,
|
|
284
|
-
label: undefined,
|
|
285
|
-
type: undefined,
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
},
|
|
289
|
-
[saveLabel],
|
|
290
|
-
);
|
|
291
|
-
|
|
292
|
-
const loadTemplateData = useCallback(
|
|
293
|
-
(templateType: string) => {
|
|
294
|
-
|
|
295
|
-
if (templateType === 'tree-structure') {
|
|
296
|
-
setNodes(treeStructureTemplate.nodes as Node[]);
|
|
297
|
-
setEdges(treeStructureTemplate.edges as Edge[]);
|
|
298
|
-
} else if (templateType === 'structure1') {
|
|
299
|
-
setNodes(treeStructureTemplate1.nodes as Node[]);
|
|
300
|
-
setEdges(treeStructureTemplate1.edges as Edge[]);
|
|
301
|
-
} else if (templateType === 'structure2') {
|
|
302
|
-
setNodes(treeStructureTemplate2.nodes as Node[]);
|
|
303
|
-
setEdges(treeStructureTemplate2.edges as Edge[]);
|
|
304
|
-
} else if (templateType === 'structure3') {
|
|
305
|
-
setNodes(treeStructureTemplate3.nodes as Node[]);
|
|
306
|
-
setEdges(treeStructureTemplate3.edges as Edge[]);
|
|
307
|
-
} else {
|
|
308
|
-
// Default system flow nodes/edges
|
|
309
|
-
setNodes(systemFlowDefaultNodes as Node[]);
|
|
310
|
-
setEdges(systemFlowDefaultEdges as Edge[]);
|
|
311
|
-
}
|
|
312
|
-
},
|
|
313
|
-
[setNodes, setEdges],
|
|
314
|
-
);
|
|
315
|
-
|
|
316
|
-
// Initialize nodes and edges with our data
|
|
317
|
-
useEffect(() => {
|
|
318
|
-
// Only initialize if history is empty
|
|
319
|
-
if (history.length === 0) {
|
|
320
|
-
const initialState: HistoryState = {
|
|
321
|
-
nodes: nodes as SystemFlowNode[],
|
|
322
|
-
edges: edges as SystemFlowEdge[],
|
|
323
|
-
};
|
|
324
|
-
setHistory([initialState]);
|
|
325
|
-
setHistoryIndex(0);
|
|
326
|
-
}
|
|
327
|
-
}, []);
|
|
328
|
-
|
|
329
|
-
// Save current state to history when nodes or edges change (debounced)
|
|
330
|
-
const debouncedUpdateHistory = useRef(
|
|
331
|
-
debounce(
|
|
332
|
-
(
|
|
333
|
-
nodes: Node[],
|
|
334
|
-
edges: Edge[],
|
|
335
|
-
history: HistoryState[],
|
|
336
|
-
historyIndex: number,
|
|
337
|
-
setHistory: React.Dispatch<React.SetStateAction<HistoryState[]>>,
|
|
338
|
-
setHistoryIndex: React.Dispatch<React.SetStateAction<number>>,
|
|
339
|
-
) => {
|
|
340
|
-
const newHistoryEntry: HistoryState = {
|
|
341
|
-
nodes: [...nodes] as SystemFlowNode[],
|
|
342
|
-
edges: [...edges] as SystemFlowEdge[],
|
|
343
|
-
};
|
|
344
|
-
const currentState = history[historyIndex];
|
|
345
|
-
if (
|
|
346
|
-
currentState &&
|
|
347
|
-
deepCompareNodes(currentState.nodes, newHistoryEntry.nodes) &&
|
|
348
|
-
deepCompareEdges(currentState.edges, newHistoryEntry.edges)
|
|
349
|
-
) {
|
|
350
|
-
return; // No change, don't add to history
|
|
351
|
-
}
|
|
352
|
-
// Trim future history if we're in the middle of the history stack
|
|
353
|
-
let newHistory = history.slice(0, historyIndex + 1);
|
|
354
|
-
newHistory.push(newHistoryEntry);
|
|
355
|
-
// Limit to last 50 entries
|
|
356
|
-
if (newHistory.length > 50) {
|
|
357
|
-
newHistory = newHistory.slice(newHistory.length - 50);
|
|
358
|
-
}
|
|
359
|
-
setHistory(newHistory);
|
|
360
|
-
setHistoryIndex(newHistory.length - 1);
|
|
361
|
-
},
|
|
362
|
-
300,
|
|
363
|
-
),
|
|
364
|
-
).current;
|
|
365
|
-
|
|
366
|
-
useEffect(() => {
|
|
367
|
-
if (isUndoRedoAction.current || history.length === 0) {
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
debouncedUpdateHistory(
|
|
371
|
-
nodes,
|
|
372
|
-
edges,
|
|
373
|
-
history,
|
|
374
|
-
historyIndex,
|
|
375
|
-
setHistory,
|
|
376
|
-
setHistoryIndex,
|
|
377
|
-
);
|
|
378
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
379
|
-
}, [nodes, edges]);
|
|
380
|
-
|
|
381
|
-
// Function to perform undo operation
|
|
382
|
-
const handleUndo = useCallback(() => {
|
|
383
|
-
if (historyIndex > 0) {
|
|
384
|
-
isUndoRedoAction.current = true;
|
|
385
|
-
const prevState = history[historyIndex - 1];
|
|
386
|
-
setNodes(prevState.nodes);
|
|
387
|
-
setEdges(prevState.edges);
|
|
388
|
-
setHistoryIndex(historyIndex - 1);
|
|
389
|
-
setTimeout(() => {
|
|
390
|
-
isUndoRedoAction.current = false;
|
|
391
|
-
}, 0);
|
|
392
|
-
}
|
|
393
|
-
}, [history, historyIndex, setNodes, setEdges]);
|
|
394
|
-
|
|
395
|
-
// Function to perform redo operation
|
|
396
|
-
const handleRedo = useCallback(() => {
|
|
397
|
-
if (historyIndex < history.length - 1) {
|
|
398
|
-
isUndoRedoAction.current = true;
|
|
399
|
-
const nextState = history[historyIndex + 1];
|
|
400
|
-
setNodes(nextState.nodes);
|
|
401
|
-
setEdges(nextState.edges);
|
|
402
|
-
setHistoryIndex(historyIndex + 1);
|
|
403
|
-
setTimeout(() => {
|
|
404
|
-
isUndoRedoAction.current = false;
|
|
405
|
-
}, 0);
|
|
406
|
-
}
|
|
407
|
-
}, [history, historyIndex, setNodes, setEdges]);
|
|
408
|
-
|
|
409
|
-
// Clear handler
|
|
410
|
-
const handleClear = useCallback(() => {
|
|
411
|
-
const cleared = { nodes: [], edges: [] };
|
|
412
|
-
const newHistory = history.slice(0, historyIndex + 1);
|
|
413
|
-
newHistory.push(cleared);
|
|
414
|
-
setNodes([]);
|
|
415
|
-
setEdges([]);
|
|
416
|
-
setHistory(newHistory);
|
|
417
|
-
setHistoryIndex(newHistory.length - 1);
|
|
418
|
-
}, [history, historyIndex, setNodes, setEdges]);
|
|
419
|
-
|
|
420
|
-
// Listen for keyboard shortcuts
|
|
421
|
-
useEffect(() => {
|
|
422
|
-
const handleKeyDown = (e: KeyboardEvent) => {
|
|
423
|
-
// Check for Ctrl+Z or Cmd+Z (undo)
|
|
424
|
-
if ((e.ctrlKey || e.metaKey) && e.key === 'z' && !e.shiftKey) {
|
|
425
|
-
e.preventDefault();
|
|
426
|
-
handleUndo();
|
|
427
|
-
}
|
|
428
|
-
// Check for Ctrl+Y or Cmd+Shift+Z (redo)
|
|
429
|
-
if (
|
|
430
|
-
((e.ctrlKey || e.metaKey) && e.key === 'y') ||
|
|
431
|
-
((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'z')
|
|
432
|
-
) {
|
|
433
|
-
e.preventDefault();
|
|
434
|
-
handleRedo();
|
|
435
|
-
}
|
|
436
|
-
};
|
|
437
|
-
|
|
438
|
-
window.addEventListener('keydown', handleKeyDown);
|
|
439
|
-
return () => {
|
|
440
|
-
window.removeEventListener('keydown', handleKeyDown);
|
|
441
|
-
};
|
|
442
|
-
}, [handleUndo, handleRedo]);
|
|
443
|
-
|
|
444
|
-
// Node type map for system flow nodes
|
|
445
|
-
const nodeTypeMap: Record<string, { type: string; data?: Record<string, unknown> }> = {
|
|
446
|
-
SystemNode: { type: 'SystemNode', data: { label: 'Node', color: '#2196F3' } },
|
|
447
|
-
bendpoint: { type: 'bendpoint', data: {} },
|
|
448
|
-
Structure1: {
|
|
449
|
-
type: 'TreeSystemNode',
|
|
450
|
-
data: {
|
|
451
|
-
label: 'Structure 1',
|
|
452
|
-
color: '#2196F3',
|
|
453
|
-
isTreeStructure: true,
|
|
454
|
-
structureId: `structure-1-${Date.now()}`,
|
|
455
|
-
nodeType: 'root',
|
|
456
|
-
structureType: 'structure1'
|
|
457
|
-
}
|
|
458
|
-
},
|
|
459
|
-
Structure2: {
|
|
460
|
-
type: 'TreeSystemNode',
|
|
461
|
-
data: {
|
|
462
|
-
label: 'Structure 2',
|
|
463
|
-
color: '#2196F3',
|
|
464
|
-
isTreeStructure: true,
|
|
465
|
-
structureId: `structure-2-${Date.now()}`,
|
|
466
|
-
nodeType: 'root',
|
|
467
|
-
structureType: 'structure2'
|
|
468
|
-
}
|
|
469
|
-
},
|
|
470
|
-
Structure3: {
|
|
471
|
-
type: 'TreeSystemNode',
|
|
472
|
-
data: {
|
|
473
|
-
label: 'Structure 3',
|
|
474
|
-
color: '#2196F3',
|
|
475
|
-
isTreeStructure: true,
|
|
476
|
-
structureId: `structure-3-${Date.now()}`,
|
|
477
|
-
nodeType: 'root',
|
|
478
|
-
structureType: 'structure3'
|
|
479
|
-
}
|
|
480
|
-
},
|
|
481
|
-
};
|
|
482
|
-
|
|
483
|
-
// Add node at center (internal)
|
|
484
|
-
const addNodeAtCenter = useCallback(
|
|
485
|
-
(nodeTypeId: string) => {
|
|
486
|
-
const nodeInfo = nodeTypeMap[nodeTypeId];
|
|
487
|
-
if (!nodeInfo) return;
|
|
488
|
-
const { type, data } = nodeInfo;
|
|
489
|
-
const width = diagramContainerRef.current?.offsetWidth || 1200;
|
|
490
|
-
const height = diagramContainerRef.current?.offsetHeight || 800;
|
|
491
|
-
const center = getCenterPosition(width, height);
|
|
492
|
-
const newId = `${nodeTypeId}-${nodes.length + 1}`;
|
|
493
|
-
|
|
494
|
-
// Add onResize handler to node data
|
|
495
|
-
const onResize = (id: string, width: number, height: number) => {
|
|
496
|
-
setNodes((nds) =>
|
|
497
|
-
nds.map((node) =>
|
|
498
|
-
node.id === id
|
|
499
|
-
? {
|
|
500
|
-
...node,
|
|
501
|
-
measured: { width, height },
|
|
502
|
-
width: width,
|
|
503
|
-
height: height,
|
|
504
|
-
}
|
|
505
|
-
: node,
|
|
506
|
-
),
|
|
507
|
-
);
|
|
508
|
-
};
|
|
509
|
-
|
|
510
|
-
setNodes((nds: Node[]) => [
|
|
511
|
-
...nds,
|
|
512
|
-
{
|
|
513
|
-
id: newId,
|
|
514
|
-
type,
|
|
515
|
-
position: center,
|
|
516
|
-
data: { ...data, onResize },
|
|
517
|
-
draggable: true,
|
|
518
|
-
},
|
|
519
|
-
]);
|
|
520
|
-
},
|
|
521
|
-
[nodes, setNodes],
|
|
522
|
-
);
|
|
523
|
-
|
|
524
|
-
// Update onAddEntity to use internal addNodeAtCenter
|
|
525
|
-
const handleAddEntity = useCallback(
|
|
526
|
-
(nodeTypeId = 'SystemNode') => {
|
|
527
|
-
addNodeAtCenter(nodeTypeId);
|
|
528
|
-
},
|
|
529
|
-
[addNodeAtCenter],
|
|
530
|
-
);
|
|
531
|
-
|
|
532
|
-
// Function to export diagram as JSON
|
|
533
|
-
const exportDiagram = useCallback(() => {
|
|
534
|
-
const diagramData = {
|
|
535
|
-
nodes: nodes,
|
|
536
|
-
edges: edges,
|
|
537
|
-
};
|
|
538
|
-
|
|
539
|
-
const dataStr = JSON.stringify(diagramData, null, 2);
|
|
540
|
-
const dataUri =
|
|
541
|
-
'data:application/json;charset=utf-8,' + encodeURIComponent(dataStr);
|
|
542
|
-
|
|
543
|
-
const exportFileDefaultName = 'system-flow-diagram.json';
|
|
544
|
-
|
|
545
|
-
const linkElement = document.createElement('a');
|
|
546
|
-
linkElement.setAttribute('href', dataUri);
|
|
547
|
-
linkElement.setAttribute('download', exportFileDefaultName);
|
|
548
|
-
linkElement.click();
|
|
549
|
-
}, [nodes, edges]);
|
|
550
|
-
|
|
551
|
-
// Function to import diagram from JSON
|
|
552
|
-
const importDiagram = useCallback(
|
|
553
|
-
(event: React.ChangeEvent<HTMLInputElement>) => {
|
|
554
|
-
if (!event.target.files || event.target.files.length === 0) return;
|
|
555
|
-
|
|
556
|
-
const fileReader = new FileReader();
|
|
557
|
-
fileReader.readAsText(event.target.files[0], 'UTF-8');
|
|
558
|
-
fileReader.onload = (e) => {
|
|
559
|
-
try {
|
|
560
|
-
if (!e.target || typeof e.target.result !== 'string') return;
|
|
561
|
-
|
|
562
|
-
const imported = JSON.parse(e.target.result);
|
|
563
|
-
if (imported.nodes && imported.edges) {
|
|
564
|
-
setNodes(imported.nodes);
|
|
565
|
-
setEdges(imported.edges);
|
|
566
|
-
}
|
|
567
|
-
} catch (error) {
|
|
568
|
-
alert('Failed to import diagram. Invalid file format.');
|
|
569
|
-
}
|
|
570
|
-
};
|
|
571
|
-
},
|
|
572
|
-
[setNodes, setEdges],
|
|
573
|
-
);
|
|
574
|
-
|
|
575
|
-
// Toggle fullscreen mode
|
|
576
|
-
const toggleFullscreen = useCallback(() => {
|
|
577
|
-
if (!diagramContainerRef.current) return;
|
|
578
|
-
|
|
579
|
-
if (!isFullscreen) {
|
|
580
|
-
if (diagramContainerRef.current.requestFullscreen) {
|
|
581
|
-
diagramContainerRef.current.requestFullscreen();
|
|
582
|
-
} else if ((diagramContainerRef.current as unknown as WebkitElement).webkitRequestFullscreen) {
|
|
583
|
-
(diagramContainerRef.current as unknown as WebkitElement).webkitRequestFullscreen?.();
|
|
584
|
-
} else if ((diagramContainerRef.current as unknown as MSElement).msRequestFullscreen) {
|
|
585
|
-
(diagramContainerRef.current as unknown as MSElement).msRequestFullscreen?.();
|
|
586
|
-
}
|
|
587
|
-
} else {
|
|
588
|
-
if (document.exitFullscreen) {
|
|
589
|
-
document.exitFullscreen();
|
|
590
|
-
} else if ((document as unknown as WebkitDocument).webkitExitFullscreen) {
|
|
591
|
-
(document as unknown as WebkitDocument).webkitExitFullscreen?.();
|
|
592
|
-
} else if ((document as unknown as MSDocument).msExitFullscreen) {
|
|
593
|
-
(document as unknown as MSDocument).msExitFullscreen?.();
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
setIsFullscreen(!isFullscreen);
|
|
598
|
-
}, [isFullscreen]);
|
|
599
|
-
|
|
600
|
-
// Listen for fullscreen change events from browser
|
|
601
|
-
useEffect(() => {
|
|
602
|
-
const handleFullscreenChange = () => {
|
|
603
|
-
setIsFullscreen(!!document.fullscreenElement);
|
|
604
|
-
};
|
|
605
|
-
|
|
606
|
-
document.addEventListener('fullscreenchange', handleFullscreenChange);
|
|
607
|
-
document.addEventListener('webkitfullscreenchange', handleFullscreenChange);
|
|
608
|
-
document.addEventListener('mozfullscreenchange', handleFullscreenChange);
|
|
609
|
-
document.addEventListener('MSFullscreenChange', handleFullscreenChange);
|
|
610
|
-
|
|
611
|
-
return () => {
|
|
612
|
-
document.removeEventListener('fullscreenchange', handleFullscreenChange);
|
|
613
|
-
document.removeEventListener(
|
|
614
|
-
'webkitfullscreenchange',
|
|
615
|
-
handleFullscreenChange,
|
|
616
|
-
);
|
|
617
|
-
document.removeEventListener(
|
|
618
|
-
'mozfullscreenchange',
|
|
619
|
-
handleFullscreenChange,
|
|
620
|
-
);
|
|
621
|
-
document.removeEventListener(
|
|
622
|
-
'MSFullscreenChange',
|
|
623
|
-
handleFullscreenChange,
|
|
624
|
-
);
|
|
625
|
-
};
|
|
626
|
-
}, []);
|
|
627
|
-
|
|
628
|
-
// Modified onConnect to open EdgeSettings after edge is created
|
|
629
|
-
const onConnect = useCallback(
|
|
630
|
-
(params: Connection) => {
|
|
631
|
-
if (!params.source || !params.target) return;
|
|
632
|
-
const sourceNode = nodes.find((n) => n.id === params.source);
|
|
633
|
-
const targetNode = nodes.find((n) => n.id === params.target);
|
|
634
|
-
if (!sourceNode || !targetNode) return;
|
|
635
|
-
|
|
636
|
-
const newEdge = {
|
|
637
|
-
id: `edge-${edges.length + 1}`,
|
|
638
|
-
source: params.source,
|
|
639
|
-
target: params.target,
|
|
640
|
-
type: 'floatingEdge',
|
|
641
|
-
sourceHandle: params.sourceHandle,
|
|
642
|
-
targetHandle: params.targetHandle,
|
|
643
|
-
data: {
|
|
644
|
-
label: `Flow ${edges.length + 1}`,
|
|
645
|
-
type: 'controlFlow',
|
|
646
|
-
color: '#666',
|
|
647
|
-
},
|
|
648
|
-
animated: false,
|
|
649
|
-
};
|
|
650
|
-
setEdges((eds: Edge[]) => [...eds, newEdge]);
|
|
651
|
-
setEdgeSettings({ id: newEdge.id });
|
|
652
|
-
setIsSettingsSidebarOpen(true);
|
|
653
|
-
},
|
|
654
|
-
[nodes, edges, setEdges],
|
|
655
|
-
);
|
|
656
|
-
|
|
657
|
-
// Update onNodeClick function
|
|
658
|
-
const onNodeClick = useCallback((event: React.MouseEvent, node: Node) => {
|
|
659
|
-
setSystemFlowNodeSettings({ id: node.id });
|
|
660
|
-
setIsSettingsSidebarOpen(true);
|
|
661
|
-
}, []);
|
|
662
|
-
|
|
663
|
-
// Update onNodeDoubleClick function
|
|
664
|
-
const onNodeDoubleClick = useCallback(
|
|
665
|
-
(event: React.MouseEvent, node: Node) => {
|
|
666
|
-
event.preventDefault();
|
|
667
|
-
event.stopPropagation();
|
|
668
|
-
setEditing({
|
|
669
|
-
nodeId: node.id,
|
|
670
|
-
edgeId: null,
|
|
671
|
-
label: (node.data?.label as string) || '',
|
|
672
|
-
type: 'node',
|
|
673
|
-
});
|
|
674
|
-
},
|
|
675
|
-
[setEditing],
|
|
676
|
-
);
|
|
677
|
-
|
|
678
|
-
// Open EdgeSettings on double click
|
|
679
|
-
const onEdgeDoubleClick = useCallback(
|
|
680
|
-
(event: React.MouseEvent, edge: Edge) => {
|
|
681
|
-
event.preventDefault();
|
|
682
|
-
event.stopPropagation();
|
|
683
|
-
if (edge.type === 'floatingEdge') {
|
|
684
|
-
setEdgeSettings({ id: edge.id });
|
|
685
|
-
setIsSettingsSidebarOpen(true);
|
|
686
|
-
}
|
|
687
|
-
},
|
|
688
|
-
[],
|
|
689
|
-
);
|
|
690
|
-
|
|
691
|
-
// Function to update selected system flow node
|
|
692
|
-
const updateSelectedSystemFlowNode = useCallback(
|
|
693
|
-
(updates: Record<string, unknown>) => {
|
|
694
|
-
if (!systemFlowNodeSettings.id) return;
|
|
695
|
-
|
|
696
|
-
const currentNode = nodes.find(n => n.id === systemFlowNodeSettings.id);
|
|
697
|
-
const isChildNode = currentNode &&
|
|
698
|
-
currentNode.data.isTreeStructure &&
|
|
699
|
-
currentNode.data.nodeType === 'child' &&
|
|
700
|
-
currentNode.data.structureId;
|
|
701
|
-
|
|
702
|
-
setNodes((nds: Node[]) =>
|
|
703
|
-
nds.map((node: Node) => {
|
|
704
|
-
if (node.id === systemFlowNodeSettings.id) {
|
|
705
|
-
return {
|
|
706
|
-
...node,
|
|
707
|
-
data: {
|
|
708
|
-
...node.data,
|
|
709
|
-
...updates,
|
|
710
|
-
},
|
|
711
|
-
};
|
|
712
|
-
}
|
|
713
|
-
return node;
|
|
714
|
-
}),
|
|
715
|
-
);
|
|
716
|
-
|
|
717
|
-
// If editing a child node, mark for layout recalculation
|
|
718
|
-
if (isChildNode) {
|
|
719
|
-
const rootNode = nodes.find(n =>
|
|
720
|
-
n.data.isTreeStructure &&
|
|
721
|
-
n.data.structureId === currentNode.data.structureId &&
|
|
722
|
-
n.data.nodeType === 'root'
|
|
723
|
-
);
|
|
724
|
-
|
|
725
|
-
if (rootNode) {
|
|
726
|
-
setPendingLayoutRecalculation({
|
|
727
|
-
structureId: currentNode.data.structureId as string,
|
|
728
|
-
rootNodeId: rootNode.id
|
|
729
|
-
});
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
},
|
|
733
|
-
[systemFlowNodeSettings.id, setNodes, nodes],
|
|
734
|
-
);
|
|
735
|
-
|
|
736
|
-
// Close system flow node settings
|
|
737
|
-
const closeSystemFlowNodeSettings = useCallback(() => {
|
|
738
|
-
const currentNodeId = systemFlowNodeSettings.id;
|
|
739
|
-
setSystemFlowNodeSettings({ id: null });
|
|
740
|
-
setIsSettingsSidebarOpen(false);
|
|
741
|
-
|
|
742
|
-
// If we're closing settings for a tree structure node, handle accordingly
|
|
743
|
-
if (currentNodeId) {
|
|
744
|
-
const currentNode = nodes.find(n => n.id === currentNodeId);
|
|
745
|
-
if (currentNode && currentNode.data.isTreeStructure) {
|
|
746
|
-
|
|
747
|
-
// If it's a root node being edited, auto-center it
|
|
748
|
-
if (currentNode.data.nodeType === 'root' && currentNode.data.isRootBeingEdited) {
|
|
749
|
-
const autoCenterRootNode = currentNode.data?.autoCenterRootNode;
|
|
750
|
-
if (typeof autoCenterRootNode === 'function') {
|
|
751
|
-
autoCenterRootNode();
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
// If it's a child node, trigger layout recalculation
|
|
756
|
-
else if (currentNode.data.nodeType === 'child' && currentNode.data.structureId) {
|
|
757
|
-
|
|
758
|
-
// Find the root node and trigger its layout recalculation
|
|
759
|
-
const rootNode = nodes.find(n =>
|
|
760
|
-
n.data.isTreeStructure &&
|
|
761
|
-
n.data.structureId === currentNode.data.structureId &&
|
|
762
|
-
n.data.nodeType === 'root'
|
|
763
|
-
);
|
|
764
|
-
|
|
765
|
-
if (rootNode) {
|
|
766
|
-
// Call the forceLayoutRecalculation function directly if available
|
|
767
|
-
const forceLayoutRecalculation = rootNode.data?.forceLayoutRecalculation;
|
|
768
|
-
if (typeof forceLayoutRecalculation === 'function') {
|
|
769
|
-
forceLayoutRecalculation();
|
|
770
|
-
} else {
|
|
771
|
-
// Fallback: Force a layout recalculation by updating the root node
|
|
772
|
-
setNodes((nds: Node[]) =>
|
|
773
|
-
nds.map((node: Node) => {
|
|
774
|
-
if (node.id === rootNode.id) {
|
|
775
|
-
return {
|
|
776
|
-
...node,
|
|
777
|
-
data: {
|
|
778
|
-
...node.data,
|
|
779
|
-
// Add a timestamp to force re-render and layout recalculation
|
|
780
|
-
lastLayoutUpdate: Date.now()
|
|
781
|
-
}
|
|
782
|
-
};
|
|
783
|
-
}
|
|
784
|
-
return node;
|
|
785
|
-
})
|
|
786
|
-
);
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
// Clear pending layout recalculation when settings close
|
|
794
|
-
setPendingLayoutRecalculation(null);
|
|
795
|
-
}, [systemFlowNodeSettings.id, nodes, setNodes]);
|
|
796
|
-
|
|
797
|
-
// Update edge from EdgeSettings
|
|
798
|
-
const updateSelectedEdge = useCallback(
|
|
799
|
-
(updates: Record<string, unknown>) => {
|
|
800
|
-
if (!edgeSettings.id) return;
|
|
801
|
-
|
|
802
|
-
setEdges((eds: Edge[]) => {
|
|
803
|
-
const currentEdge = eds.find(e => e.id === edgeSettings.id);
|
|
804
|
-
if (!currentEdge) return eds;
|
|
805
|
-
|
|
806
|
-
const newEdges = [...eds];
|
|
807
|
-
|
|
808
|
-
// Update the current edge
|
|
809
|
-
const edgeIndex = newEdges.findIndex(e => e.id === edgeSettings.id);
|
|
810
|
-
if (edgeIndex !== -1) {
|
|
811
|
-
newEdges[edgeIndex] = {
|
|
812
|
-
...newEdges[edgeIndex],
|
|
813
|
-
data: {
|
|
814
|
-
...newEdges[edgeIndex].data,
|
|
815
|
-
...updates,
|
|
816
|
-
},
|
|
817
|
-
};
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
// Handle two-way edge creation/removal
|
|
821
|
-
const isTwoWay = updates.isTwoWay as boolean;
|
|
822
|
-
const wasTwoWay = currentEdge.data?.isTwoWay as boolean;
|
|
823
|
-
|
|
824
|
-
if (isTwoWay && !wasTwoWay) {
|
|
825
|
-
// Create reverse edge for two-way connection
|
|
826
|
-
const reverseEdgeId = `reverse-${edgeSettings.id}`;
|
|
827
|
-
const reverseEdge: Edge = {
|
|
828
|
-
id: reverseEdgeId,
|
|
829
|
-
source: currentEdge.target,
|
|
830
|
-
target: currentEdge.source,
|
|
831
|
-
type: 'floatingEdge',
|
|
832
|
-
data: {
|
|
833
|
-
...currentEdge.data,
|
|
834
|
-
...updates,
|
|
835
|
-
isTwoWay: true,
|
|
836
|
-
reverseEdgeId: edgeSettings.id,
|
|
837
|
-
},
|
|
838
|
-
};
|
|
839
|
-
|
|
840
|
-
// Update current edge to reference reverse edge
|
|
841
|
-
newEdges[edgeIndex] = {
|
|
842
|
-
...newEdges[edgeIndex],
|
|
843
|
-
data: {
|
|
844
|
-
...newEdges[edgeIndex].data,
|
|
845
|
-
reverseEdgeId,
|
|
846
|
-
},
|
|
847
|
-
};
|
|
848
|
-
|
|
849
|
-
newEdges.push(reverseEdge);
|
|
850
|
-
} else if (!isTwoWay && wasTwoWay) {
|
|
851
|
-
// Remove reverse edge
|
|
852
|
-
const reverseEdgeId = currentEdge.data?.reverseEdgeId;
|
|
853
|
-
if (reverseEdgeId) {
|
|
854
|
-
// Remove reverse edge
|
|
855
|
-
const reverseEdgeIndex = newEdges.findIndex(e => e.id === reverseEdgeId);
|
|
856
|
-
if (reverseEdgeIndex !== -1) {
|
|
857
|
-
newEdges.splice(reverseEdgeIndex, 1);
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
// Remove reverse edge reference from current edge
|
|
861
|
-
newEdges[edgeIndex] = {
|
|
862
|
-
...newEdges[edgeIndex],
|
|
863
|
-
data: {
|
|
864
|
-
...newEdges[edgeIndex].data,
|
|
865
|
-
reverseEdgeId: undefined,
|
|
866
|
-
},
|
|
867
|
-
};
|
|
868
|
-
}
|
|
869
|
-
} else if (isTwoWay && wasTwoWay) {
|
|
870
|
-
// Update both edges when two-way is already enabled
|
|
871
|
-
const reverseEdgeId = currentEdge.data?.reverseEdgeId;
|
|
872
|
-
if (reverseEdgeId) {
|
|
873
|
-
const reverseEdgeIndex = newEdges.findIndex(e => e.id === reverseEdgeId);
|
|
874
|
-
if (reverseEdgeIndex !== -1) {
|
|
875
|
-
newEdges[reverseEdgeIndex] = {
|
|
876
|
-
...newEdges[reverseEdgeIndex],
|
|
877
|
-
data: {
|
|
878
|
-
...newEdges[reverseEdgeIndex].data,
|
|
879
|
-
...updates,
|
|
880
|
-
},
|
|
881
|
-
};
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
return newEdges;
|
|
887
|
-
});
|
|
888
|
-
},
|
|
889
|
-
[edgeSettings.id, setEdges],
|
|
890
|
-
);
|
|
891
|
-
|
|
892
|
-
// Close EdgeSettings
|
|
893
|
-
const closeEdgeSettings = useCallback(() => {
|
|
894
|
-
setEdgeSettings({ id: null });
|
|
895
|
-
setIsSettingsSidebarOpen(false);
|
|
896
|
-
}, []);
|
|
897
|
-
|
|
898
|
-
// Collapse all nodes on pane click
|
|
899
|
-
const handlePaneClick = useCallback(() => {
|
|
900
|
-
setSystemFlowNodeSettings({ id: null });
|
|
901
|
-
|
|
902
|
-
// Check if any root node is being edited and auto-center it
|
|
903
|
-
const rootNodesBeingEdited = nodes.filter(n =>
|
|
904
|
-
n.data.isTreeStructure &&
|
|
905
|
-
n.data.nodeType === 'root' &&
|
|
906
|
-
n.data.isRootBeingEdited
|
|
907
|
-
);
|
|
908
|
-
|
|
909
|
-
rootNodesBeingEdited.forEach(rootNode => {
|
|
910
|
-
const autoCenterRootNode = rootNode.data?.autoCenterRootNode;
|
|
911
|
-
if (typeof autoCenterRootNode === 'function') {
|
|
912
|
-
autoCenterRootNode();
|
|
913
|
-
}
|
|
914
|
-
});
|
|
915
|
-
|
|
916
|
-
// If there's a pending layout recalculation, trigger it now
|
|
917
|
-
if (pendingLayoutRecalculation) {
|
|
918
|
-
|
|
919
|
-
const rootNode = nodes.find(n => n.id === pendingLayoutRecalculation.rootNodeId);
|
|
920
|
-
if (rootNode) {
|
|
921
|
-
// Call the forceLayoutRecalculation function directly if available
|
|
922
|
-
const forceLayoutRecalculation = rootNode.data?.forceLayoutRecalculation;
|
|
923
|
-
if (typeof forceLayoutRecalculation === 'function') {
|
|
924
|
-
forceLayoutRecalculation();
|
|
925
|
-
} else {
|
|
926
|
-
// Fallback: Force a layout recalculation by updating the root node
|
|
927
|
-
setNodes((nds: Node[]) =>
|
|
928
|
-
nds.map((node: Node) => {
|
|
929
|
-
if (node.id === rootNode.id) {
|
|
930
|
-
return {
|
|
931
|
-
...node,
|
|
932
|
-
data: {
|
|
933
|
-
...node.data,
|
|
934
|
-
// Add a timestamp to force re-render and layout recalculation
|
|
935
|
-
lastLayoutUpdate: Date.now()
|
|
936
|
-
}
|
|
937
|
-
};
|
|
938
|
-
}
|
|
939
|
-
return node;
|
|
940
|
-
})
|
|
941
|
-
);
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
// Clear the pending layout recalculation
|
|
946
|
-
setPendingLayoutRecalculation(null);
|
|
947
|
-
}
|
|
948
|
-
}, [pendingLayoutRecalculation, nodes, setNodes]);
|
|
949
|
-
|
|
950
|
-
// Memoize node and edge maps for O(1) lookup
|
|
951
|
-
const nodeMap = useMemo(() => {
|
|
952
|
-
const map = new Map<string, Node>();
|
|
953
|
-
nodes.forEach((node) => map.set(node.id, node));
|
|
954
|
-
return map;
|
|
955
|
-
}, [nodes]);
|
|
956
|
-
const edgeMap = useMemo(() => {
|
|
957
|
-
const map = new Map<string, Edge>();
|
|
958
|
-
edges.forEach((edge) => map.set(edge.id, edge));
|
|
959
|
-
return map;
|
|
960
|
-
}, [edges]);
|
|
961
|
-
|
|
962
|
-
// Memoize styles to prevent recreation on every render
|
|
963
|
-
const diagramStyles = useMemo(() => ({
|
|
964
|
-
background: '#1a1a1a',
|
|
965
|
-
}), []);
|
|
966
|
-
|
|
967
|
-
const fitViewOptions = useMemo(() => ({
|
|
968
|
-
padding: 0.2,
|
|
969
|
-
minZoom: 0.5,
|
|
970
|
-
maxZoom: 2,
|
|
971
|
-
}), []);
|
|
972
|
-
|
|
973
|
-
const defaultViewport = useMemo(() => ({
|
|
974
|
-
x: 0,
|
|
975
|
-
y: 0,
|
|
976
|
-
zoom: 1
|
|
977
|
-
}), []);
|
|
978
|
-
|
|
979
|
-
return (
|
|
980
|
-
<Box sx={{ display: 'flex', height: '100vh' }}>
|
|
981
|
-
<Sidebar>
|
|
982
|
-
<NodeSelectionContext.Provider
|
|
983
|
-
value={{
|
|
984
|
-
selectedNodeType: null,
|
|
985
|
-
setSelectedNodeType: () => { },
|
|
986
|
-
addNodeAtCenter,
|
|
987
|
-
}}
|
|
988
|
-
>
|
|
989
|
-
<DiagramControls
|
|
990
|
-
onAddEntity={handleAddEntity}
|
|
991
|
-
onUndo={handleUndo}
|
|
992
|
-
onRedo={handleRedo}
|
|
993
|
-
canUndo={historyIndex > 0}
|
|
994
|
-
canRedo={historyIndex < history.length - 1}
|
|
995
|
-
onLoadTemplate={loadTemplateData}
|
|
996
|
-
edges={edges as SystemFlowEdge[]}
|
|
997
|
-
nodes={nodes as SystemFlowNode[]}
|
|
998
|
-
onEditEdge={(edge) => {
|
|
999
|
-
setEdgeSettings({ id: edge.id });
|
|
1000
|
-
setIsSettingsSidebarOpen(true);
|
|
1001
|
-
}}
|
|
1002
|
-
/>
|
|
1003
|
-
</NodeSelectionContext.Provider>
|
|
1004
|
-
</Sidebar>
|
|
1005
|
-
|
|
1006
|
-
<Box
|
|
1007
|
-
sx={{
|
|
1008
|
-
flexGrow: 1,
|
|
1009
|
-
'& .react-flow__edge': {
|
|
1010
|
-
zIndex: '5000 !important',
|
|
1011
|
-
},
|
|
1012
|
-
'& .react-flow__edge-path': {
|
|
1013
|
-
pointerEvents: 'all !important',
|
|
1014
|
-
},
|
|
1015
|
-
'& .edge-path-selector': {
|
|
1016
|
-
strokeWidth: 20,
|
|
1017
|
-
fill: 'none',
|
|
1018
|
-
stroke: 'transparent',
|
|
1019
|
-
cursor: 'pointer',
|
|
1020
|
-
},
|
|
1021
|
-
'& .react-flow__edges': {
|
|
1022
|
-
zIndex: '5000 !important',
|
|
1023
|
-
},
|
|
1024
|
-
'& .react-flow__node': {
|
|
1025
|
-
pointerEvents: 'all !important',
|
|
1026
|
-
cursor: 'grab',
|
|
1027
|
-
'&:active': {
|
|
1028
|
-
cursor: 'grabbing',
|
|
1029
|
-
},
|
|
1030
|
-
'& .react-flow__edge': {
|
|
1031
|
-
zIndex: '5000 !important',
|
|
1032
|
-
},
|
|
1033
|
-
},
|
|
1034
|
-
'& .react-flow__node.dragging': {
|
|
1035
|
-
cursor: 'grabbing !important',
|
|
1036
|
-
},
|
|
1037
|
-
'& .react-flow.dragging': {
|
|
1038
|
-
cursor: 'grabbing',
|
|
1039
|
-
},
|
|
1040
|
-
}}
|
|
1041
|
-
>
|
|
1042
|
-
<Box
|
|
1043
|
-
sx={{
|
|
1044
|
-
width: '100%',
|
|
1045
|
-
height: '100%',
|
|
1046
|
-
padding: '10px',
|
|
1047
|
-
bgcolor: '#1a1a1a',
|
|
1048
|
-
}}
|
|
1049
|
-
>
|
|
1050
|
-
<ReactFlow
|
|
1051
|
-
nodes={nodes}
|
|
1052
|
-
edges={edges}
|
|
1053
|
-
onNodesChange={customOnNodesChange}
|
|
1054
|
-
onEdgesChange={onEdgesChange}
|
|
1055
|
-
onConnect={onConnect}
|
|
1056
|
-
nodeTypes={baseSystemFlowNodeTypes}
|
|
1057
|
-
edgeTypes={systemFlowEdgeTypes}
|
|
1058
|
-
fitView
|
|
1059
|
-
fitViewOptions={fitViewOptions}
|
|
1060
|
-
minZoom={0.1}
|
|
1061
|
-
maxZoom={2}
|
|
1062
|
-
defaultViewport={defaultViewport}
|
|
1063
|
-
style={diagramStyles}
|
|
1064
|
-
proOptions={{ hideAttribution: true }}
|
|
1065
|
-
selectNodesOnDrag={false}
|
|
1066
|
-
connectOnClick={false}
|
|
1067
|
-
onNodeClick={onNodeClick}
|
|
1068
|
-
onNodeDoubleClick={onNodeDoubleClick}
|
|
1069
|
-
onEdgeDoubleClick={onEdgeDoubleClick}
|
|
1070
|
-
onPaneClick={handlePaneClick}
|
|
1071
|
-
>
|
|
1072
|
-
<Background
|
|
1073
|
-
color="#1a1a1a"
|
|
1074
|
-
variant={BackgroundVariant.Dots}
|
|
1075
|
-
gap={16}
|
|
1076
|
-
/>
|
|
1077
|
-
|
|
1078
|
-
{/* MiniMap positioned at bottom-left */}
|
|
1079
|
-
<MiniMapCommon />
|
|
1080
|
-
|
|
1081
|
-
{/* Diagram Panel with all controls */}
|
|
1082
|
-
<DiagramPanel
|
|
1083
|
-
historyIndex={historyIndex}
|
|
1084
|
-
historyLength={history.length}
|
|
1085
|
-
onUndo={handleUndo}
|
|
1086
|
-
onRedo={handleRedo}
|
|
1087
|
-
onClear={handleClear}
|
|
1088
|
-
onImport={(data) => {
|
|
1089
|
-
setNodes(data.nodes || []);
|
|
1090
|
-
setEdges(data.edges || []);
|
|
1091
|
-
// Add to history
|
|
1092
|
-
const newHistoryState = {
|
|
1093
|
-
nodes: data.nodes || [],
|
|
1094
|
-
edges: data.edges || [],
|
|
1095
|
-
};
|
|
1096
|
-
setHistory((prev) => [
|
|
1097
|
-
...prev.slice(0, historyIndex + 1),
|
|
1098
|
-
newHistoryState,
|
|
1099
|
-
]);
|
|
1100
|
-
setHistoryIndex((prev) => prev + 1);
|
|
1101
|
-
}}
|
|
1102
|
-
isSettingsOpen={isSettingsSidebarOpen}
|
|
1103
|
-
onToggleSettings={() => setIsSettingsSidebarOpen(true)}
|
|
1104
|
-
showCustomControls={true}
|
|
1105
|
-
onGridLayout={() => { }}
|
|
1106
|
-
onTreeLayout={() => { }}
|
|
1107
|
-
/>
|
|
1108
|
-
|
|
1109
|
-
{/* AI Button positioned at bottom-right */}
|
|
1110
|
-
<AiButton />
|
|
1111
|
-
|
|
1112
|
-
{/* Fullscreen button positioned at top-left */}
|
|
1113
|
-
</ReactFlow>
|
|
1114
|
-
</Box>
|
|
1115
|
-
</Box>
|
|
1116
|
-
|
|
1117
|
-
{/* Settings panels */}
|
|
1118
|
-
{systemFlowNodeSettings.id && (
|
|
1119
|
-
<SystemFlowNodeSettings
|
|
1120
|
-
nodeId={systemFlowNodeSettings.id}
|
|
1121
|
-
data={nodeMap.get(systemFlowNodeSettings.id)?.data || {}}
|
|
1122
|
-
onUpdate={updateSelectedSystemFlowNode}
|
|
1123
|
-
onClose={closeSystemFlowNodeSettings}
|
|
1124
|
-
edges={edges as SystemFlowEdge[]}
|
|
1125
|
-
setEdges={(updater) => {
|
|
1126
|
-
if (typeof updater === 'function') {
|
|
1127
|
-
setEdges((prev) => updater(prev as SystemFlowEdge[]) as Edge[]);
|
|
1128
|
-
} else {
|
|
1129
|
-
setEdges(updater as Edge[]);
|
|
1130
|
-
}
|
|
1131
|
-
}}
|
|
1132
|
-
nodes={nodes as SystemFlowNode[]}
|
|
1133
|
-
/>
|
|
1134
|
-
)}
|
|
1135
|
-
|
|
1136
|
-
{edgeSettings.id && (
|
|
1137
|
-
<EdgeSettings
|
|
1138
|
-
edge={edgeMap.get(edgeSettings.id) as SystemFlowEdge}
|
|
1139
|
-
nodes={nodes as SystemFlowNode[]}
|
|
1140
|
-
onUpdate={updateSelectedEdge}
|
|
1141
|
-
onClose={closeEdgeSettings}
|
|
1142
|
-
onDelete={() => {
|
|
1143
|
-
setEdges((eds: Edge[]) => {
|
|
1144
|
-
const currentEdge = eds.find(e => e.id === edgeSettings.id);
|
|
1145
|
-
if (!currentEdge) return eds;
|
|
1146
|
-
|
|
1147
|
-
// If it's a two-way edge, also remove the reverse edge
|
|
1148
|
-
const reverseEdgeId = currentEdge.data?.reverseEdgeId;
|
|
1149
|
-
if (reverseEdgeId) {
|
|
1150
|
-
return eds.filter((edge: Edge) =>
|
|
1151
|
-
edge.id !== edgeSettings.id && edge.id !== reverseEdgeId
|
|
1152
|
-
);
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
|
-
// Regular edge deletion
|
|
1156
|
-
return eds.filter((edge: Edge) => edge.id !== edgeSettings.id);
|
|
1157
|
-
});
|
|
1158
|
-
closeEdgeSettings();
|
|
1159
|
-
}}
|
|
1160
|
-
/>
|
|
1161
|
-
)}
|
|
1162
|
-
</Box>
|
|
1163
|
-
);
|
|
1164
|
-
});
|
|
1165
|
-
|
|
1166
|
-
SystemFlowDiagramFlowContent.displayName = 'SystemFlowDiagramFlowContent';
|
|
1167
|
-
|
|
1168
|
-
// Main wrapper component with ReactFlowProvider
|
|
1169
|
-
const SystemFlowDiagramFlow: React.FC<SystemFlowDiagramFlowProps> = (
|
|
1170
|
-
props,
|
|
1171
|
-
) => {
|
|
1172
|
-
return (
|
|
1173
|
-
<ReactFlowProvider>
|
|
1174
|
-
<SystemFlowDiagramFlowContent {...props} />
|
|
1175
|
-
</ReactFlowProvider>
|
|
1176
|
-
);
|
|
1177
|
-
};
|
|
1178
|
-
|
|
1179
|
-
export default SystemFlowDiagramFlow;
|
|
1
|
+
import React, {
|
|
2
|
+
useCallback,
|
|
3
|
+
useState,
|
|
4
|
+
useRef,
|
|
5
|
+
useEffect,
|
|
6
|
+
useMemo,
|
|
7
|
+
} from 'react';
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
ReactFlow,
|
|
11
|
+
Background,
|
|
12
|
+
useNodesState,
|
|
13
|
+
useEdgesState,
|
|
14
|
+
useReactFlow,
|
|
15
|
+
Panel,
|
|
16
|
+
BackgroundVariant,
|
|
17
|
+
Connection,
|
|
18
|
+
NodeChange,
|
|
19
|
+
applyNodeChanges,
|
|
20
|
+
ReactFlowProvider,
|
|
21
|
+
Node,
|
|
22
|
+
Edge,
|
|
23
|
+
NodeProps,
|
|
24
|
+
} from '@xyflow/react';
|
|
25
|
+
import '@xyflow/react/dist/style.css';
|
|
26
|
+
import {
|
|
27
|
+
SystemFlowNode,
|
|
28
|
+
SystemFlowEdge,
|
|
29
|
+
HistoryState,
|
|
30
|
+
EditingState,
|
|
31
|
+
SystemFlowNodeSettingsState,
|
|
32
|
+
SystemFlowEdgeSettingsState,
|
|
33
|
+
NodeSelectionContextType,
|
|
34
|
+
LayoutDirection,
|
|
35
|
+
UpdateFunction,
|
|
36
|
+
CloseFunction,
|
|
37
|
+
DeleteFunction
|
|
38
|
+
} from '../../../types/system-flow-types';
|
|
39
|
+
|
|
40
|
+
import {
|
|
41
|
+
Box,
|
|
42
|
+
Button,
|
|
43
|
+
Paper,
|
|
44
|
+
ToggleButton,
|
|
45
|
+
ToggleButtonGroup,
|
|
46
|
+
Snackbar,
|
|
47
|
+
Alert,
|
|
48
|
+
} from '@mui/material';
|
|
49
|
+
import DownloadIcon from '@mui/icons-material/Download';
|
|
50
|
+
import UploadIcon from '@mui/icons-material/Upload';
|
|
51
|
+
import FullscreenIcon from '@mui/icons-material/Fullscreen';
|
|
52
|
+
import FullscreenExitIcon from '@mui/icons-material/FullscreenExit';
|
|
53
|
+
import CloseIcon from '@mui/icons-material/Close';
|
|
54
|
+
import UndoIcon from '@mui/icons-material/Undo';
|
|
55
|
+
import RedoIcon from '@mui/icons-material/Redo';
|
|
56
|
+
import ViewWeekIcon from '@mui/icons-material/ViewWeek';
|
|
57
|
+
import ViewStreamIcon from '@mui/icons-material/ViewStream';
|
|
58
|
+
import {
|
|
59
|
+
systemFlowDefaultNodes,
|
|
60
|
+
systemFlowDefaultEdges,
|
|
61
|
+
treeStructureTemplate,
|
|
62
|
+
treeStructureTemplate1,
|
|
63
|
+
treeStructureTemplate2,
|
|
64
|
+
treeStructureTemplate3,
|
|
65
|
+
} from '../data/template-data';
|
|
66
|
+
import {
|
|
67
|
+
systemFlowEdgeTypes,
|
|
68
|
+
systemFlowNodeTypes as baseSystemFlowNodeTypes,
|
|
69
|
+
} from './SystemFlowComponents';
|
|
70
|
+
import DiagramControls from '../controls/SystemFlowControls';
|
|
71
|
+
import { NodeSelectionContext } from '../controls/SystemFlowControls';
|
|
72
|
+
import SystemFlowNodeSettings from './SystemFlowNodeSettings';
|
|
73
|
+
import EdgeSettings from './EdgeSettings';
|
|
74
|
+
import DiagramPanel from '../../../components/DiagramPanel';
|
|
75
|
+
import Sidebar from '../../../components/SideBar';
|
|
76
|
+
import AiButton from '../../../components/AiButton';
|
|
77
|
+
import MiniMapCommon from '../../../components/MiniMapCommon';
|
|
78
|
+
|
|
79
|
+
// Browser-specific fullscreen API types
|
|
80
|
+
interface WebkitElement extends Element {
|
|
81
|
+
webkitRequestFullscreen(): Promise<void>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
interface WebkitDocument extends Document {
|
|
85
|
+
webkitExitFullscreen(): Promise<void>;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
interface MSElement extends Element {
|
|
89
|
+
msRequestFullscreen(): Promise<void>;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
interface MSDocument extends Document {
|
|
93
|
+
msExitFullscreen(): Promise<void>;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
interface SystemFlowDiagramFlowProps {
|
|
97
|
+
nodes: SystemFlowNode[];
|
|
98
|
+
setNodes: (nodes: SystemFlowNode[] | ((prev: SystemFlowNode[]) => SystemFlowNode[])) => void;
|
|
99
|
+
edges: SystemFlowEdge[];
|
|
100
|
+
setEdges: (edges: SystemFlowEdge[] | ((prev: SystemFlowEdge[]) => SystemFlowEdge[])) => void;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Utility: Deep compare node arrays by id, type, data, width, height
|
|
104
|
+
const deepCompareNodes = (a: Node[], b: Node[]) => {
|
|
105
|
+
if (a.length !== b.length) return false;
|
|
106
|
+
for (let i = 0; i < a.length; i++) {
|
|
107
|
+
const nodeA = a[i];
|
|
108
|
+
const nodeB = b[i];
|
|
109
|
+
if (
|
|
110
|
+
nodeA.id !== nodeB.id ||
|
|
111
|
+
nodeA.type !== nodeB.type ||
|
|
112
|
+
JSON.stringify(nodeA.data) !== JSON.stringify(nodeB.data)
|
|
113
|
+
) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return true;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// Utility: Deep compare edge arrays by id, source, target, type, data
|
|
121
|
+
const deepCompareEdges = (a: Edge[], b: Edge[]) => {
|
|
122
|
+
if (a.length !== b.length) return false;
|
|
123
|
+
for (let i = 0; i < a.length; i++) {
|
|
124
|
+
const edgeA = a[i];
|
|
125
|
+
const edgeB = b[i];
|
|
126
|
+
if (
|
|
127
|
+
edgeA.id !== edgeB.id ||
|
|
128
|
+
edgeA.source !== edgeB.source ||
|
|
129
|
+
edgeA.target !== edgeB.target ||
|
|
130
|
+
edgeA.type !== edgeB.type ||
|
|
131
|
+
JSON.stringify(edgeA.data) !== JSON.stringify(edgeB.data)
|
|
132
|
+
) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return true;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// Debounce utility
|
|
140
|
+
const debounce = (fn: Function, delay: number) => {
|
|
141
|
+
let timer: NodeJS.Timeout | null = null;
|
|
142
|
+
return (...args: unknown[]) => {
|
|
143
|
+
if (timer) clearTimeout(timer);
|
|
144
|
+
timer = setTimeout(() => fn(...args), delay);
|
|
145
|
+
};
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
// Helper: get center position in diagram
|
|
149
|
+
const getCenterPosition = (width: number, height: number) => {
|
|
150
|
+
return { x: width / 2 - 75, y: height / 2 - 40 };
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const SystemFlowDiagramFlowContent: React.FC<
|
|
154
|
+
SystemFlowDiagramFlowProps
|
|
155
|
+
> = React.memo(({
|
|
156
|
+
nodes: initialNodes,
|
|
157
|
+
setNodes: parentSetNodes,
|
|
158
|
+
edges: initialEdges,
|
|
159
|
+
setEdges: parentSetEdges,
|
|
160
|
+
}) => {
|
|
161
|
+
// State declarations
|
|
162
|
+
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes as Node[]);
|
|
163
|
+
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges as Edge[]);
|
|
164
|
+
|
|
165
|
+
// Custom onNodesChange handler for synchronized tree structure movement
|
|
166
|
+
const customOnNodesChange = useCallback((changes: NodeChange[]) => {
|
|
167
|
+
// First apply the default changes
|
|
168
|
+
onNodesChange(changes);
|
|
169
|
+
|
|
170
|
+
// Then handle synchronized movement for tree structure nodes
|
|
171
|
+
changes.forEach((change: NodeChange) => {
|
|
172
|
+
if (change.type === 'position' && 'position' in change && change.position) {
|
|
173
|
+
const position = change.position as { x: number; y: number };
|
|
174
|
+
const node = nodes.find(n => n.id === change.id);
|
|
175
|
+
|
|
176
|
+
if (node && node.data.isTreeStructure && node.data.structureId) {
|
|
177
|
+
// This is a tree structure node being moved, move all nodes in the same structure
|
|
178
|
+
const currentNode = nodes.find(n => n.id === change.id);
|
|
179
|
+
if (!currentNode) return;
|
|
180
|
+
|
|
181
|
+
// Calculate the delta movement
|
|
182
|
+
const deltaX = position.x - currentNode.position.x;
|
|
183
|
+
const deltaY = position.y - currentNode.position.y;
|
|
184
|
+
|
|
185
|
+
// Move all nodes in the same structure by the same delta
|
|
186
|
+
const updatedNodes = nodes.map(n => {
|
|
187
|
+
if (n.data.isTreeStructure && n.data.structureId === node.data.structureId) {
|
|
188
|
+
return {
|
|
189
|
+
...n,
|
|
190
|
+
position: {
|
|
191
|
+
x: n.position.x + deltaX,
|
|
192
|
+
y: n.position.y + deltaY
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
return n;
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
setNodes(updatedNodes);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
}, [nodes, setNodes, onNodesChange]);
|
|
204
|
+
const [history, setHistory] = useState<HistoryState[]>([]);
|
|
205
|
+
const [historyIndex, setHistoryIndex] = useState<number>(-1);
|
|
206
|
+
const isUndoRedoAction = useRef(false);
|
|
207
|
+
const [isFullscreen, setIsFullscreen] = useState<boolean>(false);
|
|
208
|
+
const diagramContainerRef = useRef<HTMLDivElement>(null);
|
|
209
|
+
const [editing, setEditing] = useState<{
|
|
210
|
+
nodeId?: string | null;
|
|
211
|
+
edgeId?: string | null;
|
|
212
|
+
label?: string;
|
|
213
|
+
type?: 'node' | 'edge';
|
|
214
|
+
}>({});
|
|
215
|
+
const [systemFlowNodeSettings, setSystemFlowNodeSettings] = useState<{
|
|
216
|
+
id: string | null;
|
|
217
|
+
}>({ id: null });
|
|
218
|
+
const [edgeSettings, setEdgeSettings] = useState<{ id: string | null }>({
|
|
219
|
+
id: null,
|
|
220
|
+
});
|
|
221
|
+
const [isSettingsSidebarOpen, setIsSettingsSidebarOpen] = useState(false);
|
|
222
|
+
|
|
223
|
+
// Track if a child node has been edited and needs layout recalculation
|
|
224
|
+
const [pendingLayoutRecalculation, setPendingLayoutRecalculation] = useState<{
|
|
225
|
+
structureId: string;
|
|
226
|
+
rootNodeId: string;
|
|
227
|
+
} | null>(null);
|
|
228
|
+
|
|
229
|
+
// Function declarations in correct order
|
|
230
|
+
const saveLabel = useCallback(() => {
|
|
231
|
+
if (editing.nodeId && editing.type === 'node') {
|
|
232
|
+
setNodes((nds: Node[]) =>
|
|
233
|
+
nds.map((node: Node) => {
|
|
234
|
+
if (node.id === editing.nodeId) {
|
|
235
|
+
return {
|
|
236
|
+
...node,
|
|
237
|
+
data: {
|
|
238
|
+
...node.data,
|
|
239
|
+
label: editing.label,
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
return node;
|
|
244
|
+
}),
|
|
245
|
+
);
|
|
246
|
+
setEditing({
|
|
247
|
+
nodeId: undefined,
|
|
248
|
+
edgeId: undefined,
|
|
249
|
+
label: undefined,
|
|
250
|
+
type: undefined,
|
|
251
|
+
});
|
|
252
|
+
} else if (editing.edgeId && editing.type === 'edge') {
|
|
253
|
+
setEdges((eds: Edge[]) =>
|
|
254
|
+
eds.map((edge: Edge) => {
|
|
255
|
+
if (edge.id === editing.edgeId) {
|
|
256
|
+
return {
|
|
257
|
+
...edge,
|
|
258
|
+
data: {
|
|
259
|
+
...edge.data,
|
|
260
|
+
label: editing.label,
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
return edge;
|
|
265
|
+
}),
|
|
266
|
+
);
|
|
267
|
+
setEditing({
|
|
268
|
+
nodeId: undefined,
|
|
269
|
+
edgeId: undefined,
|
|
270
|
+
label: undefined,
|
|
271
|
+
type: undefined,
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}, [editing, setNodes, setEdges]);
|
|
275
|
+
|
|
276
|
+
const handleKeyDown = useCallback(
|
|
277
|
+
(e: React.KeyboardEvent) => {
|
|
278
|
+
if (e.key === 'Enter') {
|
|
279
|
+
saveLabel();
|
|
280
|
+
} else if (e.key === 'Escape') {
|
|
281
|
+
setEditing({
|
|
282
|
+
nodeId: undefined,
|
|
283
|
+
edgeId: undefined,
|
|
284
|
+
label: undefined,
|
|
285
|
+
type: undefined,
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
[saveLabel],
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
const loadTemplateData = useCallback(
|
|
293
|
+
(templateType: string) => {
|
|
294
|
+
|
|
295
|
+
if (templateType === 'tree-structure') {
|
|
296
|
+
setNodes(treeStructureTemplate.nodes as Node[]);
|
|
297
|
+
setEdges(treeStructureTemplate.edges as Edge[]);
|
|
298
|
+
} else if (templateType === 'structure1') {
|
|
299
|
+
setNodes(treeStructureTemplate1.nodes as Node[]);
|
|
300
|
+
setEdges(treeStructureTemplate1.edges as Edge[]);
|
|
301
|
+
} else if (templateType === 'structure2') {
|
|
302
|
+
setNodes(treeStructureTemplate2.nodes as Node[]);
|
|
303
|
+
setEdges(treeStructureTemplate2.edges as Edge[]);
|
|
304
|
+
} else if (templateType === 'structure3') {
|
|
305
|
+
setNodes(treeStructureTemplate3.nodes as Node[]);
|
|
306
|
+
setEdges(treeStructureTemplate3.edges as Edge[]);
|
|
307
|
+
} else {
|
|
308
|
+
// Default system flow nodes/edges
|
|
309
|
+
setNodes(systemFlowDefaultNodes as Node[]);
|
|
310
|
+
setEdges(systemFlowDefaultEdges as Edge[]);
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
[setNodes, setEdges],
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
// Initialize nodes and edges with our data
|
|
317
|
+
useEffect(() => {
|
|
318
|
+
// Only initialize if history is empty
|
|
319
|
+
if (history.length === 0) {
|
|
320
|
+
const initialState: HistoryState = {
|
|
321
|
+
nodes: nodes as SystemFlowNode[],
|
|
322
|
+
edges: edges as SystemFlowEdge[],
|
|
323
|
+
};
|
|
324
|
+
setHistory([initialState]);
|
|
325
|
+
setHistoryIndex(0);
|
|
326
|
+
}
|
|
327
|
+
}, []);
|
|
328
|
+
|
|
329
|
+
// Save current state to history when nodes or edges change (debounced)
|
|
330
|
+
const debouncedUpdateHistory = useRef(
|
|
331
|
+
debounce(
|
|
332
|
+
(
|
|
333
|
+
nodes: Node[],
|
|
334
|
+
edges: Edge[],
|
|
335
|
+
history: HistoryState[],
|
|
336
|
+
historyIndex: number,
|
|
337
|
+
setHistory: React.Dispatch<React.SetStateAction<HistoryState[]>>,
|
|
338
|
+
setHistoryIndex: React.Dispatch<React.SetStateAction<number>>,
|
|
339
|
+
) => {
|
|
340
|
+
const newHistoryEntry: HistoryState = {
|
|
341
|
+
nodes: [...nodes] as SystemFlowNode[],
|
|
342
|
+
edges: [...edges] as SystemFlowEdge[],
|
|
343
|
+
};
|
|
344
|
+
const currentState = history[historyIndex];
|
|
345
|
+
if (
|
|
346
|
+
currentState &&
|
|
347
|
+
deepCompareNodes(currentState.nodes, newHistoryEntry.nodes) &&
|
|
348
|
+
deepCompareEdges(currentState.edges, newHistoryEntry.edges)
|
|
349
|
+
) {
|
|
350
|
+
return; // No change, don't add to history
|
|
351
|
+
}
|
|
352
|
+
// Trim future history if we're in the middle of the history stack
|
|
353
|
+
let newHistory = history.slice(0, historyIndex + 1);
|
|
354
|
+
newHistory.push(newHistoryEntry);
|
|
355
|
+
// Limit to last 50 entries
|
|
356
|
+
if (newHistory.length > 50) {
|
|
357
|
+
newHistory = newHistory.slice(newHistory.length - 50);
|
|
358
|
+
}
|
|
359
|
+
setHistory(newHistory);
|
|
360
|
+
setHistoryIndex(newHistory.length - 1);
|
|
361
|
+
},
|
|
362
|
+
300,
|
|
363
|
+
),
|
|
364
|
+
).current;
|
|
365
|
+
|
|
366
|
+
useEffect(() => {
|
|
367
|
+
if (isUndoRedoAction.current || history.length === 0) {
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
debouncedUpdateHistory(
|
|
371
|
+
nodes,
|
|
372
|
+
edges,
|
|
373
|
+
history,
|
|
374
|
+
historyIndex,
|
|
375
|
+
setHistory,
|
|
376
|
+
setHistoryIndex,
|
|
377
|
+
);
|
|
378
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
379
|
+
}, [nodes, edges]);
|
|
380
|
+
|
|
381
|
+
// Function to perform undo operation
|
|
382
|
+
const handleUndo = useCallback(() => {
|
|
383
|
+
if (historyIndex > 0) {
|
|
384
|
+
isUndoRedoAction.current = true;
|
|
385
|
+
const prevState = history[historyIndex - 1];
|
|
386
|
+
setNodes(prevState.nodes);
|
|
387
|
+
setEdges(prevState.edges);
|
|
388
|
+
setHistoryIndex(historyIndex - 1);
|
|
389
|
+
setTimeout(() => {
|
|
390
|
+
isUndoRedoAction.current = false;
|
|
391
|
+
}, 0);
|
|
392
|
+
}
|
|
393
|
+
}, [history, historyIndex, setNodes, setEdges]);
|
|
394
|
+
|
|
395
|
+
// Function to perform redo operation
|
|
396
|
+
const handleRedo = useCallback(() => {
|
|
397
|
+
if (historyIndex < history.length - 1) {
|
|
398
|
+
isUndoRedoAction.current = true;
|
|
399
|
+
const nextState = history[historyIndex + 1];
|
|
400
|
+
setNodes(nextState.nodes);
|
|
401
|
+
setEdges(nextState.edges);
|
|
402
|
+
setHistoryIndex(historyIndex + 1);
|
|
403
|
+
setTimeout(() => {
|
|
404
|
+
isUndoRedoAction.current = false;
|
|
405
|
+
}, 0);
|
|
406
|
+
}
|
|
407
|
+
}, [history, historyIndex, setNodes, setEdges]);
|
|
408
|
+
|
|
409
|
+
// Clear handler
|
|
410
|
+
const handleClear = useCallback(() => {
|
|
411
|
+
const cleared = { nodes: [], edges: [] };
|
|
412
|
+
const newHistory = history.slice(0, historyIndex + 1);
|
|
413
|
+
newHistory.push(cleared);
|
|
414
|
+
setNodes([]);
|
|
415
|
+
setEdges([]);
|
|
416
|
+
setHistory(newHistory);
|
|
417
|
+
setHistoryIndex(newHistory.length - 1);
|
|
418
|
+
}, [history, historyIndex, setNodes, setEdges]);
|
|
419
|
+
|
|
420
|
+
// Listen for keyboard shortcuts
|
|
421
|
+
useEffect(() => {
|
|
422
|
+
const handleKeyDown = (e: KeyboardEvent) => {
|
|
423
|
+
// Check for Ctrl+Z or Cmd+Z (undo)
|
|
424
|
+
if ((e.ctrlKey || e.metaKey) && e.key === 'z' && !e.shiftKey) {
|
|
425
|
+
e.preventDefault();
|
|
426
|
+
handleUndo();
|
|
427
|
+
}
|
|
428
|
+
// Check for Ctrl+Y or Cmd+Shift+Z (redo)
|
|
429
|
+
if (
|
|
430
|
+
((e.ctrlKey || e.metaKey) && e.key === 'y') ||
|
|
431
|
+
((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'z')
|
|
432
|
+
) {
|
|
433
|
+
e.preventDefault();
|
|
434
|
+
handleRedo();
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
window.addEventListener('keydown', handleKeyDown);
|
|
439
|
+
return () => {
|
|
440
|
+
window.removeEventListener('keydown', handleKeyDown);
|
|
441
|
+
};
|
|
442
|
+
}, [handleUndo, handleRedo]);
|
|
443
|
+
|
|
444
|
+
// Node type map for system flow nodes
|
|
445
|
+
const nodeTypeMap: Record<string, { type: string; data?: Record<string, unknown> }> = {
|
|
446
|
+
SystemNode: { type: 'SystemNode', data: { label: 'Node', color: '#2196F3' } },
|
|
447
|
+
bendpoint: { type: 'bendpoint', data: {} },
|
|
448
|
+
Structure1: {
|
|
449
|
+
type: 'TreeSystemNode',
|
|
450
|
+
data: {
|
|
451
|
+
label: 'Structure 1',
|
|
452
|
+
color: '#2196F3',
|
|
453
|
+
isTreeStructure: true,
|
|
454
|
+
structureId: `structure-1-${Date.now()}`,
|
|
455
|
+
nodeType: 'root',
|
|
456
|
+
structureType: 'structure1'
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
Structure2: {
|
|
460
|
+
type: 'TreeSystemNode',
|
|
461
|
+
data: {
|
|
462
|
+
label: 'Structure 2',
|
|
463
|
+
color: '#2196F3',
|
|
464
|
+
isTreeStructure: true,
|
|
465
|
+
structureId: `structure-2-${Date.now()}`,
|
|
466
|
+
nodeType: 'root',
|
|
467
|
+
structureType: 'structure2'
|
|
468
|
+
}
|
|
469
|
+
},
|
|
470
|
+
Structure3: {
|
|
471
|
+
type: 'TreeSystemNode',
|
|
472
|
+
data: {
|
|
473
|
+
label: 'Structure 3',
|
|
474
|
+
color: '#2196F3',
|
|
475
|
+
isTreeStructure: true,
|
|
476
|
+
structureId: `structure-3-${Date.now()}`,
|
|
477
|
+
nodeType: 'root',
|
|
478
|
+
structureType: 'structure3'
|
|
479
|
+
}
|
|
480
|
+
},
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
// Add node at center (internal)
|
|
484
|
+
const addNodeAtCenter = useCallback(
|
|
485
|
+
(nodeTypeId: string) => {
|
|
486
|
+
const nodeInfo = nodeTypeMap[nodeTypeId];
|
|
487
|
+
if (!nodeInfo) return;
|
|
488
|
+
const { type, data } = nodeInfo;
|
|
489
|
+
const width = diagramContainerRef.current?.offsetWidth || 1200;
|
|
490
|
+
const height = diagramContainerRef.current?.offsetHeight || 800;
|
|
491
|
+
const center = getCenterPosition(width, height);
|
|
492
|
+
const newId = `${nodeTypeId}-${nodes.length + 1}`;
|
|
493
|
+
|
|
494
|
+
// Add onResize handler to node data
|
|
495
|
+
const onResize = (id: string, width: number, height: number) => {
|
|
496
|
+
setNodes((nds) =>
|
|
497
|
+
nds.map((node) =>
|
|
498
|
+
node.id === id
|
|
499
|
+
? {
|
|
500
|
+
...node,
|
|
501
|
+
measured: { width, height },
|
|
502
|
+
width: width,
|
|
503
|
+
height: height,
|
|
504
|
+
}
|
|
505
|
+
: node,
|
|
506
|
+
),
|
|
507
|
+
);
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
setNodes((nds: Node[]) => [
|
|
511
|
+
...nds,
|
|
512
|
+
{
|
|
513
|
+
id: newId,
|
|
514
|
+
type,
|
|
515
|
+
position: center,
|
|
516
|
+
data: { ...data, onResize },
|
|
517
|
+
draggable: true,
|
|
518
|
+
},
|
|
519
|
+
]);
|
|
520
|
+
},
|
|
521
|
+
[nodes, setNodes],
|
|
522
|
+
);
|
|
523
|
+
|
|
524
|
+
// Update onAddEntity to use internal addNodeAtCenter
|
|
525
|
+
const handleAddEntity = useCallback(
|
|
526
|
+
(nodeTypeId = 'SystemNode') => {
|
|
527
|
+
addNodeAtCenter(nodeTypeId);
|
|
528
|
+
},
|
|
529
|
+
[addNodeAtCenter],
|
|
530
|
+
);
|
|
531
|
+
|
|
532
|
+
// Function to export diagram as JSON
|
|
533
|
+
const exportDiagram = useCallback(() => {
|
|
534
|
+
const diagramData = {
|
|
535
|
+
nodes: nodes,
|
|
536
|
+
edges: edges,
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
const dataStr = JSON.stringify(diagramData, null, 2);
|
|
540
|
+
const dataUri =
|
|
541
|
+
'data:application/json;charset=utf-8,' + encodeURIComponent(dataStr);
|
|
542
|
+
|
|
543
|
+
const exportFileDefaultName = 'system-flow-diagram.json';
|
|
544
|
+
|
|
545
|
+
const linkElement = document.createElement('a');
|
|
546
|
+
linkElement.setAttribute('href', dataUri);
|
|
547
|
+
linkElement.setAttribute('download', exportFileDefaultName);
|
|
548
|
+
linkElement.click();
|
|
549
|
+
}, [nodes, edges]);
|
|
550
|
+
|
|
551
|
+
// Function to import diagram from JSON
|
|
552
|
+
const importDiagram = useCallback(
|
|
553
|
+
(event: React.ChangeEvent<HTMLInputElement>) => {
|
|
554
|
+
if (!event.target.files || event.target.files.length === 0) return;
|
|
555
|
+
|
|
556
|
+
const fileReader = new FileReader();
|
|
557
|
+
fileReader.readAsText(event.target.files[0], 'UTF-8');
|
|
558
|
+
fileReader.onload = (e) => {
|
|
559
|
+
try {
|
|
560
|
+
if (!e.target || typeof e.target.result !== 'string') return;
|
|
561
|
+
|
|
562
|
+
const imported = JSON.parse(e.target.result);
|
|
563
|
+
if (imported.nodes && imported.edges) {
|
|
564
|
+
setNodes(imported.nodes);
|
|
565
|
+
setEdges(imported.edges);
|
|
566
|
+
}
|
|
567
|
+
} catch (error) {
|
|
568
|
+
alert('Failed to import diagram. Invalid file format.');
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
},
|
|
572
|
+
[setNodes, setEdges],
|
|
573
|
+
);
|
|
574
|
+
|
|
575
|
+
// Toggle fullscreen mode
|
|
576
|
+
const toggleFullscreen = useCallback(() => {
|
|
577
|
+
if (!diagramContainerRef.current) return;
|
|
578
|
+
|
|
579
|
+
if (!isFullscreen) {
|
|
580
|
+
if (diagramContainerRef.current.requestFullscreen) {
|
|
581
|
+
diagramContainerRef.current.requestFullscreen();
|
|
582
|
+
} else if ((diagramContainerRef.current as unknown as WebkitElement).webkitRequestFullscreen) {
|
|
583
|
+
(diagramContainerRef.current as unknown as WebkitElement).webkitRequestFullscreen?.();
|
|
584
|
+
} else if ((diagramContainerRef.current as unknown as MSElement).msRequestFullscreen) {
|
|
585
|
+
(diagramContainerRef.current as unknown as MSElement).msRequestFullscreen?.();
|
|
586
|
+
}
|
|
587
|
+
} else {
|
|
588
|
+
if (document.exitFullscreen) {
|
|
589
|
+
document.exitFullscreen();
|
|
590
|
+
} else if ((document as unknown as WebkitDocument).webkitExitFullscreen) {
|
|
591
|
+
(document as unknown as WebkitDocument).webkitExitFullscreen?.();
|
|
592
|
+
} else if ((document as unknown as MSDocument).msExitFullscreen) {
|
|
593
|
+
(document as unknown as MSDocument).msExitFullscreen?.();
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
setIsFullscreen(!isFullscreen);
|
|
598
|
+
}, [isFullscreen]);
|
|
599
|
+
|
|
600
|
+
// Listen for fullscreen change events from browser
|
|
601
|
+
useEffect(() => {
|
|
602
|
+
const handleFullscreenChange = () => {
|
|
603
|
+
setIsFullscreen(!!document.fullscreenElement);
|
|
604
|
+
};
|
|
605
|
+
|
|
606
|
+
document.addEventListener('fullscreenchange', handleFullscreenChange);
|
|
607
|
+
document.addEventListener('webkitfullscreenchange', handleFullscreenChange);
|
|
608
|
+
document.addEventListener('mozfullscreenchange', handleFullscreenChange);
|
|
609
|
+
document.addEventListener('MSFullscreenChange', handleFullscreenChange);
|
|
610
|
+
|
|
611
|
+
return () => {
|
|
612
|
+
document.removeEventListener('fullscreenchange', handleFullscreenChange);
|
|
613
|
+
document.removeEventListener(
|
|
614
|
+
'webkitfullscreenchange',
|
|
615
|
+
handleFullscreenChange,
|
|
616
|
+
);
|
|
617
|
+
document.removeEventListener(
|
|
618
|
+
'mozfullscreenchange',
|
|
619
|
+
handleFullscreenChange,
|
|
620
|
+
);
|
|
621
|
+
document.removeEventListener(
|
|
622
|
+
'MSFullscreenChange',
|
|
623
|
+
handleFullscreenChange,
|
|
624
|
+
);
|
|
625
|
+
};
|
|
626
|
+
}, []);
|
|
627
|
+
|
|
628
|
+
// Modified onConnect to open EdgeSettings after edge is created
|
|
629
|
+
const onConnect = useCallback(
|
|
630
|
+
(params: Connection) => {
|
|
631
|
+
if (!params.source || !params.target) return;
|
|
632
|
+
const sourceNode = nodes.find((n) => n.id === params.source);
|
|
633
|
+
const targetNode = nodes.find((n) => n.id === params.target);
|
|
634
|
+
if (!sourceNode || !targetNode) return;
|
|
635
|
+
|
|
636
|
+
const newEdge = {
|
|
637
|
+
id: `edge-${edges.length + 1}`,
|
|
638
|
+
source: params.source,
|
|
639
|
+
target: params.target,
|
|
640
|
+
type: 'floatingEdge',
|
|
641
|
+
sourceHandle: params.sourceHandle,
|
|
642
|
+
targetHandle: params.targetHandle,
|
|
643
|
+
data: {
|
|
644
|
+
label: `Flow ${edges.length + 1}`,
|
|
645
|
+
type: 'controlFlow',
|
|
646
|
+
color: '#666',
|
|
647
|
+
},
|
|
648
|
+
animated: false,
|
|
649
|
+
};
|
|
650
|
+
setEdges((eds: Edge[]) => [...eds, newEdge]);
|
|
651
|
+
setEdgeSettings({ id: newEdge.id });
|
|
652
|
+
setIsSettingsSidebarOpen(true);
|
|
653
|
+
},
|
|
654
|
+
[nodes, edges, setEdges],
|
|
655
|
+
);
|
|
656
|
+
|
|
657
|
+
// Update onNodeClick function
|
|
658
|
+
const onNodeClick = useCallback((event: React.MouseEvent, node: Node) => {
|
|
659
|
+
setSystemFlowNodeSettings({ id: node.id });
|
|
660
|
+
setIsSettingsSidebarOpen(true);
|
|
661
|
+
}, []);
|
|
662
|
+
|
|
663
|
+
// Update onNodeDoubleClick function
|
|
664
|
+
const onNodeDoubleClick = useCallback(
|
|
665
|
+
(event: React.MouseEvent, node: Node) => {
|
|
666
|
+
event.preventDefault();
|
|
667
|
+
event.stopPropagation();
|
|
668
|
+
setEditing({
|
|
669
|
+
nodeId: node.id,
|
|
670
|
+
edgeId: null,
|
|
671
|
+
label: (node.data?.label as string) || '',
|
|
672
|
+
type: 'node',
|
|
673
|
+
});
|
|
674
|
+
},
|
|
675
|
+
[setEditing],
|
|
676
|
+
);
|
|
677
|
+
|
|
678
|
+
// Open EdgeSettings on double click
|
|
679
|
+
const onEdgeDoubleClick = useCallback(
|
|
680
|
+
(event: React.MouseEvent, edge: Edge) => {
|
|
681
|
+
event.preventDefault();
|
|
682
|
+
event.stopPropagation();
|
|
683
|
+
if (edge.type === 'floatingEdge') {
|
|
684
|
+
setEdgeSettings({ id: edge.id });
|
|
685
|
+
setIsSettingsSidebarOpen(true);
|
|
686
|
+
}
|
|
687
|
+
},
|
|
688
|
+
[],
|
|
689
|
+
);
|
|
690
|
+
|
|
691
|
+
// Function to update selected system flow node
|
|
692
|
+
const updateSelectedSystemFlowNode = useCallback(
|
|
693
|
+
(updates: Record<string, unknown>) => {
|
|
694
|
+
if (!systemFlowNodeSettings.id) return;
|
|
695
|
+
|
|
696
|
+
const currentNode = nodes.find(n => n.id === systemFlowNodeSettings.id);
|
|
697
|
+
const isChildNode = currentNode &&
|
|
698
|
+
currentNode.data.isTreeStructure &&
|
|
699
|
+
currentNode.data.nodeType === 'child' &&
|
|
700
|
+
currentNode.data.structureId;
|
|
701
|
+
|
|
702
|
+
setNodes((nds: Node[]) =>
|
|
703
|
+
nds.map((node: Node) => {
|
|
704
|
+
if (node.id === systemFlowNodeSettings.id) {
|
|
705
|
+
return {
|
|
706
|
+
...node,
|
|
707
|
+
data: {
|
|
708
|
+
...node.data,
|
|
709
|
+
...updates,
|
|
710
|
+
},
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
return node;
|
|
714
|
+
}),
|
|
715
|
+
);
|
|
716
|
+
|
|
717
|
+
// If editing a child node, mark for layout recalculation
|
|
718
|
+
if (isChildNode) {
|
|
719
|
+
const rootNode = nodes.find(n =>
|
|
720
|
+
n.data.isTreeStructure &&
|
|
721
|
+
n.data.structureId === currentNode.data.structureId &&
|
|
722
|
+
n.data.nodeType === 'root'
|
|
723
|
+
);
|
|
724
|
+
|
|
725
|
+
if (rootNode) {
|
|
726
|
+
setPendingLayoutRecalculation({
|
|
727
|
+
structureId: currentNode.data.structureId as string,
|
|
728
|
+
rootNodeId: rootNode.id
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
},
|
|
733
|
+
[systemFlowNodeSettings.id, setNodes, nodes],
|
|
734
|
+
);
|
|
735
|
+
|
|
736
|
+
// Close system flow node settings
|
|
737
|
+
const closeSystemFlowNodeSettings = useCallback(() => {
|
|
738
|
+
const currentNodeId = systemFlowNodeSettings.id;
|
|
739
|
+
setSystemFlowNodeSettings({ id: null });
|
|
740
|
+
setIsSettingsSidebarOpen(false);
|
|
741
|
+
|
|
742
|
+
// If we're closing settings for a tree structure node, handle accordingly
|
|
743
|
+
if (currentNodeId) {
|
|
744
|
+
const currentNode = nodes.find(n => n.id === currentNodeId);
|
|
745
|
+
if (currentNode && currentNode.data.isTreeStructure) {
|
|
746
|
+
|
|
747
|
+
// If it's a root node being edited, auto-center it
|
|
748
|
+
if (currentNode.data.nodeType === 'root' && currentNode.data.isRootBeingEdited) {
|
|
749
|
+
const autoCenterRootNode = currentNode.data?.autoCenterRootNode;
|
|
750
|
+
if (typeof autoCenterRootNode === 'function') {
|
|
751
|
+
autoCenterRootNode();
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// If it's a child node, trigger layout recalculation
|
|
756
|
+
else if (currentNode.data.nodeType === 'child' && currentNode.data.structureId) {
|
|
757
|
+
|
|
758
|
+
// Find the root node and trigger its layout recalculation
|
|
759
|
+
const rootNode = nodes.find(n =>
|
|
760
|
+
n.data.isTreeStructure &&
|
|
761
|
+
n.data.structureId === currentNode.data.structureId &&
|
|
762
|
+
n.data.nodeType === 'root'
|
|
763
|
+
);
|
|
764
|
+
|
|
765
|
+
if (rootNode) {
|
|
766
|
+
// Call the forceLayoutRecalculation function directly if available
|
|
767
|
+
const forceLayoutRecalculation = rootNode.data?.forceLayoutRecalculation;
|
|
768
|
+
if (typeof forceLayoutRecalculation === 'function') {
|
|
769
|
+
forceLayoutRecalculation();
|
|
770
|
+
} else {
|
|
771
|
+
// Fallback: Force a layout recalculation by updating the root node
|
|
772
|
+
setNodes((nds: Node[]) =>
|
|
773
|
+
nds.map((node: Node) => {
|
|
774
|
+
if (node.id === rootNode.id) {
|
|
775
|
+
return {
|
|
776
|
+
...node,
|
|
777
|
+
data: {
|
|
778
|
+
...node.data,
|
|
779
|
+
// Add a timestamp to force re-render and layout recalculation
|
|
780
|
+
lastLayoutUpdate: Date.now()
|
|
781
|
+
}
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
return node;
|
|
785
|
+
})
|
|
786
|
+
);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// Clear pending layout recalculation when settings close
|
|
794
|
+
setPendingLayoutRecalculation(null);
|
|
795
|
+
}, [systemFlowNodeSettings.id, nodes, setNodes]);
|
|
796
|
+
|
|
797
|
+
// Update edge from EdgeSettings
|
|
798
|
+
const updateSelectedEdge = useCallback(
|
|
799
|
+
(updates: Record<string, unknown>) => {
|
|
800
|
+
if (!edgeSettings.id) return;
|
|
801
|
+
|
|
802
|
+
setEdges((eds: Edge[]) => {
|
|
803
|
+
const currentEdge = eds.find(e => e.id === edgeSettings.id);
|
|
804
|
+
if (!currentEdge) return eds;
|
|
805
|
+
|
|
806
|
+
const newEdges = [...eds];
|
|
807
|
+
|
|
808
|
+
// Update the current edge
|
|
809
|
+
const edgeIndex = newEdges.findIndex(e => e.id === edgeSettings.id);
|
|
810
|
+
if (edgeIndex !== -1) {
|
|
811
|
+
newEdges[edgeIndex] = {
|
|
812
|
+
...newEdges[edgeIndex],
|
|
813
|
+
data: {
|
|
814
|
+
...newEdges[edgeIndex].data,
|
|
815
|
+
...updates,
|
|
816
|
+
},
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
// Handle two-way edge creation/removal
|
|
821
|
+
const isTwoWay = updates.isTwoWay as boolean;
|
|
822
|
+
const wasTwoWay = currentEdge.data?.isTwoWay as boolean;
|
|
823
|
+
|
|
824
|
+
if (isTwoWay && !wasTwoWay) {
|
|
825
|
+
// Create reverse edge for two-way connection
|
|
826
|
+
const reverseEdgeId = `reverse-${edgeSettings.id}`;
|
|
827
|
+
const reverseEdge: Edge = {
|
|
828
|
+
id: reverseEdgeId,
|
|
829
|
+
source: currentEdge.target,
|
|
830
|
+
target: currentEdge.source,
|
|
831
|
+
type: 'floatingEdge',
|
|
832
|
+
data: {
|
|
833
|
+
...currentEdge.data,
|
|
834
|
+
...updates,
|
|
835
|
+
isTwoWay: true,
|
|
836
|
+
reverseEdgeId: edgeSettings.id,
|
|
837
|
+
},
|
|
838
|
+
};
|
|
839
|
+
|
|
840
|
+
// Update current edge to reference reverse edge
|
|
841
|
+
newEdges[edgeIndex] = {
|
|
842
|
+
...newEdges[edgeIndex],
|
|
843
|
+
data: {
|
|
844
|
+
...newEdges[edgeIndex].data,
|
|
845
|
+
reverseEdgeId,
|
|
846
|
+
},
|
|
847
|
+
};
|
|
848
|
+
|
|
849
|
+
newEdges.push(reverseEdge);
|
|
850
|
+
} else if (!isTwoWay && wasTwoWay) {
|
|
851
|
+
// Remove reverse edge
|
|
852
|
+
const reverseEdgeId = currentEdge.data?.reverseEdgeId;
|
|
853
|
+
if (reverseEdgeId) {
|
|
854
|
+
// Remove reverse edge
|
|
855
|
+
const reverseEdgeIndex = newEdges.findIndex(e => e.id === reverseEdgeId);
|
|
856
|
+
if (reverseEdgeIndex !== -1) {
|
|
857
|
+
newEdges.splice(reverseEdgeIndex, 1);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
// Remove reverse edge reference from current edge
|
|
861
|
+
newEdges[edgeIndex] = {
|
|
862
|
+
...newEdges[edgeIndex],
|
|
863
|
+
data: {
|
|
864
|
+
...newEdges[edgeIndex].data,
|
|
865
|
+
reverseEdgeId: undefined,
|
|
866
|
+
},
|
|
867
|
+
};
|
|
868
|
+
}
|
|
869
|
+
} else if (isTwoWay && wasTwoWay) {
|
|
870
|
+
// Update both edges when two-way is already enabled
|
|
871
|
+
const reverseEdgeId = currentEdge.data?.reverseEdgeId;
|
|
872
|
+
if (reverseEdgeId) {
|
|
873
|
+
const reverseEdgeIndex = newEdges.findIndex(e => e.id === reverseEdgeId);
|
|
874
|
+
if (reverseEdgeIndex !== -1) {
|
|
875
|
+
newEdges[reverseEdgeIndex] = {
|
|
876
|
+
...newEdges[reverseEdgeIndex],
|
|
877
|
+
data: {
|
|
878
|
+
...newEdges[reverseEdgeIndex].data,
|
|
879
|
+
...updates,
|
|
880
|
+
},
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
return newEdges;
|
|
887
|
+
});
|
|
888
|
+
},
|
|
889
|
+
[edgeSettings.id, setEdges],
|
|
890
|
+
);
|
|
891
|
+
|
|
892
|
+
// Close EdgeSettings
|
|
893
|
+
const closeEdgeSettings = useCallback(() => {
|
|
894
|
+
setEdgeSettings({ id: null });
|
|
895
|
+
setIsSettingsSidebarOpen(false);
|
|
896
|
+
}, []);
|
|
897
|
+
|
|
898
|
+
// Collapse all nodes on pane click
|
|
899
|
+
const handlePaneClick = useCallback(() => {
|
|
900
|
+
setSystemFlowNodeSettings({ id: null });
|
|
901
|
+
|
|
902
|
+
// Check if any root node is being edited and auto-center it
|
|
903
|
+
const rootNodesBeingEdited = nodes.filter(n =>
|
|
904
|
+
n.data.isTreeStructure &&
|
|
905
|
+
n.data.nodeType === 'root' &&
|
|
906
|
+
n.data.isRootBeingEdited
|
|
907
|
+
);
|
|
908
|
+
|
|
909
|
+
rootNodesBeingEdited.forEach(rootNode => {
|
|
910
|
+
const autoCenterRootNode = rootNode.data?.autoCenterRootNode;
|
|
911
|
+
if (typeof autoCenterRootNode === 'function') {
|
|
912
|
+
autoCenterRootNode();
|
|
913
|
+
}
|
|
914
|
+
});
|
|
915
|
+
|
|
916
|
+
// If there's a pending layout recalculation, trigger it now
|
|
917
|
+
if (pendingLayoutRecalculation) {
|
|
918
|
+
|
|
919
|
+
const rootNode = nodes.find(n => n.id === pendingLayoutRecalculation.rootNodeId);
|
|
920
|
+
if (rootNode) {
|
|
921
|
+
// Call the forceLayoutRecalculation function directly if available
|
|
922
|
+
const forceLayoutRecalculation = rootNode.data?.forceLayoutRecalculation;
|
|
923
|
+
if (typeof forceLayoutRecalculation === 'function') {
|
|
924
|
+
forceLayoutRecalculation();
|
|
925
|
+
} else {
|
|
926
|
+
// Fallback: Force a layout recalculation by updating the root node
|
|
927
|
+
setNodes((nds: Node[]) =>
|
|
928
|
+
nds.map((node: Node) => {
|
|
929
|
+
if (node.id === rootNode.id) {
|
|
930
|
+
return {
|
|
931
|
+
...node,
|
|
932
|
+
data: {
|
|
933
|
+
...node.data,
|
|
934
|
+
// Add a timestamp to force re-render and layout recalculation
|
|
935
|
+
lastLayoutUpdate: Date.now()
|
|
936
|
+
}
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
return node;
|
|
940
|
+
})
|
|
941
|
+
);
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
// Clear the pending layout recalculation
|
|
946
|
+
setPendingLayoutRecalculation(null);
|
|
947
|
+
}
|
|
948
|
+
}, [pendingLayoutRecalculation, nodes, setNodes]);
|
|
949
|
+
|
|
950
|
+
// Memoize node and edge maps for O(1) lookup
|
|
951
|
+
const nodeMap = useMemo(() => {
|
|
952
|
+
const map = new Map<string, Node>();
|
|
953
|
+
nodes.forEach((node) => map.set(node.id, node));
|
|
954
|
+
return map;
|
|
955
|
+
}, [nodes]);
|
|
956
|
+
const edgeMap = useMemo(() => {
|
|
957
|
+
const map = new Map<string, Edge>();
|
|
958
|
+
edges.forEach((edge) => map.set(edge.id, edge));
|
|
959
|
+
return map;
|
|
960
|
+
}, [edges]);
|
|
961
|
+
|
|
962
|
+
// Memoize styles to prevent recreation on every render
|
|
963
|
+
const diagramStyles = useMemo(() => ({
|
|
964
|
+
background: '#1a1a1a',
|
|
965
|
+
}), []);
|
|
966
|
+
|
|
967
|
+
const fitViewOptions = useMemo(() => ({
|
|
968
|
+
padding: 0.2,
|
|
969
|
+
minZoom: 0.5,
|
|
970
|
+
maxZoom: 2,
|
|
971
|
+
}), []);
|
|
972
|
+
|
|
973
|
+
const defaultViewport = useMemo(() => ({
|
|
974
|
+
x: 0,
|
|
975
|
+
y: 0,
|
|
976
|
+
zoom: 1
|
|
977
|
+
}), []);
|
|
978
|
+
|
|
979
|
+
return (
|
|
980
|
+
<Box sx={{ display: 'flex', height: '100vh' }}>
|
|
981
|
+
<Sidebar>
|
|
982
|
+
<NodeSelectionContext.Provider
|
|
983
|
+
value={{
|
|
984
|
+
selectedNodeType: null,
|
|
985
|
+
setSelectedNodeType: () => { },
|
|
986
|
+
addNodeAtCenter,
|
|
987
|
+
}}
|
|
988
|
+
>
|
|
989
|
+
<DiagramControls
|
|
990
|
+
onAddEntity={handleAddEntity}
|
|
991
|
+
onUndo={handleUndo}
|
|
992
|
+
onRedo={handleRedo}
|
|
993
|
+
canUndo={historyIndex > 0}
|
|
994
|
+
canRedo={historyIndex < history.length - 1}
|
|
995
|
+
onLoadTemplate={loadTemplateData}
|
|
996
|
+
edges={edges as SystemFlowEdge[]}
|
|
997
|
+
nodes={nodes as SystemFlowNode[]}
|
|
998
|
+
onEditEdge={(edge) => {
|
|
999
|
+
setEdgeSettings({ id: edge.id });
|
|
1000
|
+
setIsSettingsSidebarOpen(true);
|
|
1001
|
+
}}
|
|
1002
|
+
/>
|
|
1003
|
+
</NodeSelectionContext.Provider>
|
|
1004
|
+
</Sidebar>
|
|
1005
|
+
|
|
1006
|
+
<Box
|
|
1007
|
+
sx={{
|
|
1008
|
+
flexGrow: 1,
|
|
1009
|
+
'& .react-flow__edge': {
|
|
1010
|
+
zIndex: '5000 !important',
|
|
1011
|
+
},
|
|
1012
|
+
'& .react-flow__edge-path': {
|
|
1013
|
+
pointerEvents: 'all !important',
|
|
1014
|
+
},
|
|
1015
|
+
'& .edge-path-selector': {
|
|
1016
|
+
strokeWidth: 20,
|
|
1017
|
+
fill: 'none',
|
|
1018
|
+
stroke: 'transparent',
|
|
1019
|
+
cursor: 'pointer',
|
|
1020
|
+
},
|
|
1021
|
+
'& .react-flow__edges': {
|
|
1022
|
+
zIndex: '5000 !important',
|
|
1023
|
+
},
|
|
1024
|
+
'& .react-flow__node': {
|
|
1025
|
+
pointerEvents: 'all !important',
|
|
1026
|
+
cursor: 'grab',
|
|
1027
|
+
'&:active': {
|
|
1028
|
+
cursor: 'grabbing',
|
|
1029
|
+
},
|
|
1030
|
+
'& .react-flow__edge': {
|
|
1031
|
+
zIndex: '5000 !important',
|
|
1032
|
+
},
|
|
1033
|
+
},
|
|
1034
|
+
'& .react-flow__node.dragging': {
|
|
1035
|
+
cursor: 'grabbing !important',
|
|
1036
|
+
},
|
|
1037
|
+
'& .react-flow.dragging': {
|
|
1038
|
+
cursor: 'grabbing',
|
|
1039
|
+
},
|
|
1040
|
+
}}
|
|
1041
|
+
>
|
|
1042
|
+
<Box
|
|
1043
|
+
sx={{
|
|
1044
|
+
width: '100%',
|
|
1045
|
+
height: '100%',
|
|
1046
|
+
padding: '10px',
|
|
1047
|
+
bgcolor: '#1a1a1a',
|
|
1048
|
+
}}
|
|
1049
|
+
>
|
|
1050
|
+
<ReactFlow
|
|
1051
|
+
nodes={nodes}
|
|
1052
|
+
edges={edges}
|
|
1053
|
+
onNodesChange={customOnNodesChange}
|
|
1054
|
+
onEdgesChange={onEdgesChange}
|
|
1055
|
+
onConnect={onConnect}
|
|
1056
|
+
nodeTypes={baseSystemFlowNodeTypes}
|
|
1057
|
+
edgeTypes={systemFlowEdgeTypes}
|
|
1058
|
+
fitView
|
|
1059
|
+
fitViewOptions={fitViewOptions}
|
|
1060
|
+
minZoom={0.1}
|
|
1061
|
+
maxZoom={2}
|
|
1062
|
+
defaultViewport={defaultViewport}
|
|
1063
|
+
style={diagramStyles}
|
|
1064
|
+
proOptions={{ hideAttribution: true }}
|
|
1065
|
+
selectNodesOnDrag={false}
|
|
1066
|
+
connectOnClick={false}
|
|
1067
|
+
onNodeClick={onNodeClick}
|
|
1068
|
+
onNodeDoubleClick={onNodeDoubleClick}
|
|
1069
|
+
onEdgeDoubleClick={onEdgeDoubleClick}
|
|
1070
|
+
onPaneClick={handlePaneClick}
|
|
1071
|
+
>
|
|
1072
|
+
<Background
|
|
1073
|
+
color="#1a1a1a"
|
|
1074
|
+
variant={BackgroundVariant.Dots}
|
|
1075
|
+
gap={16}
|
|
1076
|
+
/>
|
|
1077
|
+
|
|
1078
|
+
{/* MiniMap positioned at bottom-left */}
|
|
1079
|
+
<MiniMapCommon />
|
|
1080
|
+
|
|
1081
|
+
{/* Diagram Panel with all controls */}
|
|
1082
|
+
<DiagramPanel
|
|
1083
|
+
historyIndex={historyIndex}
|
|
1084
|
+
historyLength={history.length}
|
|
1085
|
+
onUndo={handleUndo}
|
|
1086
|
+
onRedo={handleRedo}
|
|
1087
|
+
onClear={handleClear}
|
|
1088
|
+
onImport={(data) => {
|
|
1089
|
+
setNodes(data.nodes || []);
|
|
1090
|
+
setEdges(data.edges || []);
|
|
1091
|
+
// Add to history
|
|
1092
|
+
const newHistoryState = {
|
|
1093
|
+
nodes: data.nodes || [],
|
|
1094
|
+
edges: data.edges || [],
|
|
1095
|
+
};
|
|
1096
|
+
setHistory((prev) => [
|
|
1097
|
+
...prev.slice(0, historyIndex + 1),
|
|
1098
|
+
newHistoryState,
|
|
1099
|
+
]);
|
|
1100
|
+
setHistoryIndex((prev) => prev + 1);
|
|
1101
|
+
}}
|
|
1102
|
+
isSettingsOpen={isSettingsSidebarOpen}
|
|
1103
|
+
onToggleSettings={() => setIsSettingsSidebarOpen(true)}
|
|
1104
|
+
showCustomControls={true}
|
|
1105
|
+
onGridLayout={() => { }}
|
|
1106
|
+
onTreeLayout={() => { }}
|
|
1107
|
+
/>
|
|
1108
|
+
|
|
1109
|
+
{/* AI Button positioned at bottom-right */}
|
|
1110
|
+
<AiButton />
|
|
1111
|
+
|
|
1112
|
+
{/* Fullscreen button positioned at top-left */}
|
|
1113
|
+
</ReactFlow>
|
|
1114
|
+
</Box>
|
|
1115
|
+
</Box>
|
|
1116
|
+
|
|
1117
|
+
{/* Settings panels */}
|
|
1118
|
+
{systemFlowNodeSettings.id && (
|
|
1119
|
+
<SystemFlowNodeSettings
|
|
1120
|
+
nodeId={systemFlowNodeSettings.id}
|
|
1121
|
+
data={nodeMap.get(systemFlowNodeSettings.id)?.data || {}}
|
|
1122
|
+
onUpdate={updateSelectedSystemFlowNode}
|
|
1123
|
+
onClose={closeSystemFlowNodeSettings}
|
|
1124
|
+
edges={edges as SystemFlowEdge[]}
|
|
1125
|
+
setEdges={(updater) => {
|
|
1126
|
+
if (typeof updater === 'function') {
|
|
1127
|
+
setEdges((prev) => updater(prev as SystemFlowEdge[]) as Edge[]);
|
|
1128
|
+
} else {
|
|
1129
|
+
setEdges(updater as Edge[]);
|
|
1130
|
+
}
|
|
1131
|
+
}}
|
|
1132
|
+
nodes={nodes as SystemFlowNode[]}
|
|
1133
|
+
/>
|
|
1134
|
+
)}
|
|
1135
|
+
|
|
1136
|
+
{edgeSettings.id && (
|
|
1137
|
+
<EdgeSettings
|
|
1138
|
+
edge={edgeMap.get(edgeSettings.id) as SystemFlowEdge}
|
|
1139
|
+
nodes={nodes as SystemFlowNode[]}
|
|
1140
|
+
onUpdate={updateSelectedEdge}
|
|
1141
|
+
onClose={closeEdgeSettings}
|
|
1142
|
+
onDelete={() => {
|
|
1143
|
+
setEdges((eds: Edge[]) => {
|
|
1144
|
+
const currentEdge = eds.find(e => e.id === edgeSettings.id);
|
|
1145
|
+
if (!currentEdge) return eds;
|
|
1146
|
+
|
|
1147
|
+
// If it's a two-way edge, also remove the reverse edge
|
|
1148
|
+
const reverseEdgeId = currentEdge.data?.reverseEdgeId;
|
|
1149
|
+
if (reverseEdgeId) {
|
|
1150
|
+
return eds.filter((edge: Edge) =>
|
|
1151
|
+
edge.id !== edgeSettings.id && edge.id !== reverseEdgeId
|
|
1152
|
+
);
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
// Regular edge deletion
|
|
1156
|
+
return eds.filter((edge: Edge) => edge.id !== edgeSettings.id);
|
|
1157
|
+
});
|
|
1158
|
+
closeEdgeSettings();
|
|
1159
|
+
}}
|
|
1160
|
+
/>
|
|
1161
|
+
)}
|
|
1162
|
+
</Box>
|
|
1163
|
+
);
|
|
1164
|
+
});
|
|
1165
|
+
|
|
1166
|
+
SystemFlowDiagramFlowContent.displayName = 'SystemFlowDiagramFlowContent';
|
|
1167
|
+
|
|
1168
|
+
// Main wrapper component with ReactFlowProvider
|
|
1169
|
+
const SystemFlowDiagramFlow: React.FC<SystemFlowDiagramFlowProps> = (
|
|
1170
|
+
props,
|
|
1171
|
+
) => {
|
|
1172
|
+
return (
|
|
1173
|
+
<ReactFlowProvider>
|
|
1174
|
+
<SystemFlowDiagramFlowContent {...props} />
|
|
1175
|
+
</ReactFlowProvider>
|
|
1176
|
+
);
|
|
1177
|
+
};
|
|
1178
|
+
|
|
1179
|
+
export default SystemFlowDiagramFlow;
|