@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.
Files changed (677) hide show
  1. package/.editorconfig +13 -13
  2. package/.eslintignore +1 -1
  3. package/.eslintrc.json +35 -35
  4. package/.prettierignore +3 -3
  5. package/.prettierrc +3 -3
  6. package/.vscode/settings.json +6 -6
  7. package/README.md +95 -95
  8. package/apps/authentication/tsconfig.app.json +23 -23
  9. package/apps/authentication/tsconfig.json +21 -21
  10. package/apps/authentication/tsconfig.spec.json +28 -28
  11. package/apps/diagramming/.eslintrc.json +18 -18
  12. package/apps/diagramming/index.html +16 -16
  13. package/apps/diagramming/project.json +53 -53
  14. package/apps/diagramming/public/aws-icons/compute/App Runner.svg +17 -17
  15. package/apps/diagramming/public/aws-icons/compute/Application Auto Scaling.svg +17 -17
  16. package/apps/diagramming/public/aws-icons/compute/Batch.svg +17 -17
  17. package/apps/diagramming/public/aws-icons/compute/Bottlerocket.svg +19 -19
  18. package/apps/diagramming/public/aws-icons/compute/Compute Optimizer.svg +17 -17
  19. package/apps/diagramming/public/aws-icons/compute/EC2 Auto Scaling.svg +17 -17
  20. package/apps/diagramming/public/aws-icons/compute/EC2 Image Builder.svg +17 -17
  21. package/apps/diagramming/public/aws-icons/compute/EC2.svg +17 -17
  22. package/apps/diagramming/public/aws-icons/compute/Elastic Beanstalk.svg +17 -17
  23. package/apps/diagramming/public/aws-icons/compute/Elastic Fabric Adapter.svg +17 -17
  24. package/apps/diagramming/public/aws-icons/compute/Fargate.svg +19 -19
  25. package/apps/diagramming/public/aws-icons/compute/Genomics CLI.svg +17 -17
  26. package/apps/diagramming/public/aws-icons/compute/Lambda.svg +17 -17
  27. package/apps/diagramming/public/aws-icons/compute/Local Zones.svg +17 -17
  28. package/apps/diagramming/public/aws-icons/compute/NICE DCV.svg +17 -17
  29. package/apps/diagramming/public/aws-icons/compute/NICE EnginFrame.svg +17 -17
  30. package/apps/diagramming/public/aws-icons/compute/Nitro Enclaves.svg +17 -17
  31. package/apps/diagramming/public/aws-icons/compute/Outposts family.svg +17 -17
  32. package/apps/diagramming/public/aws-icons/compute/Outposts rack.svg +17 -17
  33. package/apps/diagramming/public/aws-icons/compute/Outposts servers.svg +17 -17
  34. package/apps/diagramming/public/aws-icons/compute/ParallelCluster.svg +17 -17
  35. package/apps/diagramming/public/aws-icons/compute/Serverless Application Repository.svg +17 -17
  36. package/apps/diagramming/public/aws-icons/compute/SimSpace Weaver.svg +17 -17
  37. package/apps/diagramming/public/aws-icons/compute/Thinkbox Deadline.svg +17 -17
  38. package/apps/diagramming/public/aws-icons/compute/Thinkbox Frost.svg +17 -17
  39. package/apps/diagramming/public/aws-icons/compute/Thinkbox Sequoia.svg +17 -17
  40. package/apps/diagramming/public/aws-icons/compute/Thinkbox Stoke.svg +17 -17
  41. package/apps/diagramming/public/aws-icons/compute/Thinkbox XMesh.svg +17 -17
  42. package/apps/diagramming/public/aws-icons/compute/VMware Cloud on AWS.svg +17 -17
  43. package/apps/diagramming/public/aws-icons/compute/Wavelength.svg +17 -17
  44. package/apps/diagramming/public/aws-icons/container/ECS Anywhere.svg +17 -17
  45. package/apps/diagramming/public/aws-icons/container/EKS Anywhere.svg +17 -17
  46. package/apps/diagramming/public/aws-icons/container/EKS Cloud.svg +17 -17
  47. package/apps/diagramming/public/aws-icons/container/EKS Distro.svg +17 -17
  48. package/apps/diagramming/public/aws-icons/container/Elastic Container Registry.svg +17 -17
  49. package/apps/diagramming/public/aws-icons/container/Elastic Container Service.svg +17 -17
  50. package/apps/diagramming/public/aws-icons/container/Elastic Kubernetes Service.svg +17 -17
  51. package/apps/diagramming/public/aws-icons/container/Fargate.svg +19 -19
  52. package/apps/diagramming/public/aws-icons/container/Red Hat OpenShift Service on AWS.svg +17 -17
  53. package/apps/diagramming/public/aws-icons/database/Aurora.svg +17 -17
  54. package/apps/diagramming/public/aws-icons/database/Database Migration Service.svg +17 -17
  55. package/apps/diagramming/public/aws-icons/database/DocumentDB.svg +17 -17
  56. package/apps/diagramming/public/aws-icons/database/ElastiCache.svg +17 -17
  57. package/apps/diagramming/public/aws-icons/database/Keyspaces.svg +15 -15
  58. package/apps/diagramming/public/aws-icons/database/MemoryDB for Redis.svg +17 -17
  59. package/apps/diagramming/public/aws-icons/database/Neptune.svg +17 -17
  60. package/apps/diagramming/public/aws-icons/database/RDS on VMware.svg +17 -17
  61. package/apps/diagramming/public/aws-icons/database/RDS.svg +17 -17
  62. package/apps/diagramming/public/aws-icons/database/Timestream.svg +17 -17
  63. package/apps/diagramming/public/aws-icons/networking/App Mesh.svg +17 -17
  64. package/apps/diagramming/public/aws-icons/networking/Client VPN.svg +17 -17
  65. package/apps/diagramming/public/aws-icons/networking/Cloud Directory.svg +17 -17
  66. package/apps/diagramming/public/aws-icons/networking/Cloud Map.svg +17 -17
  67. package/apps/diagramming/public/aws-icons/networking/Cloud WAN.svg +17 -17
  68. package/apps/diagramming/public/aws-icons/networking/CloudFront.svg +17 -17
  69. package/apps/diagramming/public/aws-icons/networking/Direct Connect.svg +17 -17
  70. package/apps/diagramming/public/aws-icons/networking/Elastic Load Balancing.svg +17 -17
  71. package/apps/diagramming/public/aws-icons/networking/Global Accelerator.svg +17 -17
  72. package/apps/diagramming/public/aws-icons/networking/Private 5G.svg +17 -17
  73. package/apps/diagramming/public/aws-icons/networking/PrivateLink.svg +17 -17
  74. package/apps/diagramming/public/aws-icons/networking/Route 53.svg +17 -17
  75. package/apps/diagramming/public/aws-icons/networking/Site to Site VPN.svg +17 -17
  76. package/apps/diagramming/public/aws-icons/networking/Transit Gateway.svg +17 -17
  77. package/apps/diagramming/public/aws-icons/networking/VPC Lattice.svg +17 -17
  78. package/apps/diagramming/public/aws-icons/networking/Verified Access.svg +17 -17
  79. package/apps/diagramming/public/aws-icons/networking/Virtual Private Cloud.svg +17 -17
  80. package/apps/diagramming/public/aws-icons/security/Artifact.svg +17 -17
  81. package/apps/diagramming/public/aws-icons/security/Audit Manager.svg +17 -17
  82. package/apps/diagramming/public/aws-icons/security/Certificate Manager.svg +17 -17
  83. package/apps/diagramming/public/aws-icons/security/CloudHSM.svg +17 -17
  84. package/apps/diagramming/public/aws-icons/security/Cognito.svg +17 -17
  85. package/apps/diagramming/public/aws-icons/security/Detective.svg +17 -17
  86. package/apps/diagramming/public/aws-icons/security/Directory Service.svg +17 -17
  87. package/apps/diagramming/public/aws-icons/security/Firewall Manager.svg +17 -17
  88. package/apps/diagramming/public/aws-icons/security/GuardDuty.svg +17 -17
  89. package/apps/diagramming/public/aws-icons/security/IAM Identity Center.svg +17 -17
  90. package/apps/diagramming/public/aws-icons/security/Identity and Access Management.svg +17 -17
  91. package/apps/diagramming/public/aws-icons/security/Inspector.svg +17 -17
  92. package/apps/diagramming/public/aws-icons/security/Key Management Service.svg +17 -17
  93. package/apps/diagramming/public/aws-icons/security/Macie.svg +17 -17
  94. package/apps/diagramming/public/aws-icons/security/Network Firewall.svg +17 -17
  95. package/apps/diagramming/public/aws-icons/security/Resource Access Manager.svg +17 -17
  96. package/apps/diagramming/public/aws-icons/security/Secrets Manager.svg +17 -17
  97. package/apps/diagramming/public/aws-icons/security/Security Hub.svg +17 -17
  98. package/apps/diagramming/public/aws-icons/security/Security Lake.svg +17 -17
  99. package/apps/diagramming/public/aws-icons/security/Shield.svg +17 -17
  100. package/apps/diagramming/public/aws-icons/security/Signer.svg +17 -17
  101. package/apps/diagramming/public/aws-icons/security/Verified Permissions.svg +17 -17
  102. package/apps/diagramming/public/aws-icons/security/WAF.svg +17 -17
  103. package/apps/diagramming/public/aws-icons/storage/Backup.svg +17 -17
  104. package/apps/diagramming/public/aws-icons/storage/EFS.svg +17 -17
  105. package/apps/diagramming/public/aws-icons/storage/Elastic Block Store.svg +17 -17
  106. package/apps/diagramming/public/aws-icons/storage/Elastic Disaster Recovery.svg +15 -15
  107. package/apps/diagramming/public/aws-icons/storage/FSx for Lustre.svg +17 -17
  108. package/apps/diagramming/public/aws-icons/storage/FSx for NetApp ONTAP.svg +17 -17
  109. package/apps/diagramming/public/aws-icons/storage/FSx for OpenZFS.svg +17 -17
  110. package/apps/diagramming/public/aws-icons/storage/FSx for WFS.svg +17 -17
  111. package/apps/diagramming/public/aws-icons/storage/FSx.svg +17 -17
  112. package/apps/diagramming/public/aws-icons/storage/File Cache.svg +17 -17
  113. package/apps/diagramming/public/aws-icons/storage/S3 on Outposts.svg +17 -17
  114. package/apps/diagramming/public/aws-icons/storage/Simple Storage Service Glacier.svg +17 -17
  115. package/apps/diagramming/public/aws-icons/storage/Simple Storage Service.svg +17 -17
  116. package/apps/diagramming/public/aws-icons/storage/Snowball Edge.svg +17 -17
  117. package/apps/diagramming/public/aws-icons/storage/Snowball.svg +17 -17
  118. package/apps/diagramming/public/aws-icons/storage/Snowcone.svg +17 -17
  119. package/apps/diagramming/public/aws-icons/storage/Snowmobile.svg +17 -17
  120. package/apps/diagramming/public/aws-icons/storage/Storage Gateway.svg +17 -17
  121. package/apps/diagramming/public/azure-icons/compute/02112-icon-service-Automanaged-VM.svg +1 -1
  122. package/apps/diagramming/public/azure-icons/databases/02390-icon-service-Azure-SQL.svg +1 -1
  123. package/apps/diagramming/public/azure-icons/databases/02392-icon-service-SSIS-Lift-And-Shift-IR.svg +1 -1
  124. package/apps/diagramming/public/azure-icons/networking/02145-icon-service-Resource-Management-Private-Link.svg +1 -1
  125. package/apps/diagramming/public/azure-icons/security/02247-icon-service-Microsoft-Defender-for-IoT.svg +1 -1
  126. package/apps/diagramming/public/sample-node-complete.json +63 -63
  127. package/apps/diagramming/public/sample-node-data.json +63 -63
  128. package/apps/diagramming/src/AutomationDiagramData.ts +147 -480
  129. package/apps/diagramming/src/CollaborationDiagramData.ts +127 -127
  130. package/apps/diagramming/src/CustomIconExamples.ts +233 -233
  131. package/apps/diagramming/src/DiagramTabs.tsx +205 -205
  132. package/apps/diagramming/src/Pages/DevPlayground.tsx +3 -3
  133. package/apps/diagramming/src/Pages/Home.tsx +111 -111
  134. package/apps/diagramming/src/SequenceDiagramData.ts +215 -215
  135. package/apps/diagramming/src/StateMachineDiagramData.ts +64 -64
  136. package/apps/diagramming/src/UseCaseDiagramData.ts +52 -52
  137. package/apps/diagramming/src/cloud-data.ts +371 -371
  138. package/apps/diagramming/src/components/AddNodeView.tsx +252 -252
  139. package/apps/diagramming/src/createSelecors.tsx +17 -17
  140. package/apps/diagramming/src/index.scss +12 -12
  141. package/apps/diagramming/src/main.tsx +463 -463
  142. package/apps/diagramming/src/node-data.ts +664 -664
  143. package/apps/diagramming/src/sample-workflow-content.ts +55 -55
  144. package/apps/diagramming/src/stencil-items.ts +31 -31
  145. package/apps/diagramming/src/style.css +13 -13
  146. package/apps/diagramming/src/tabsStore.tsx +152 -152
  147. package/apps/diagramming/src/vite-env.d.ts +1 -1
  148. package/apps/diagramming/tsconfig.app.json +23 -23
  149. package/apps/diagramming/tsconfig.json +21 -21
  150. package/apps/diagramming/tsconfig.spec.json +28 -28
  151. package/apps/diagramming/vite.config.ts +34 -34
  152. package/apps/diagramming/webpack.config.js +13 -13
  153. package/apps/workflow/.eslintrc.json +18 -18
  154. package/apps/workflow/group/group-form-hooks/index.ts +3 -3
  155. package/apps/workflow/group/group-form-hooks/useFormValidation.ts +20 -20
  156. package/apps/workflow/group/group-form-schema/SettingsTabFormSchema.ts +7 -7
  157. package/apps/workflow/group/group-form-schema/index.ts +3 -3
  158. package/apps/workflow/i18n.ts +19 -19
  159. package/apps/workflow/index.html +16 -16
  160. package/apps/workflow/locales/en/translation.json +713 -713
  161. package/apps/workflow/project.json +8 -8
  162. package/apps/workflow/src/app/app.module.css +1 -1
  163. package/apps/workflow/src/app/app.spec.tsx +15 -15
  164. package/apps/workflow/src/app/app.tsx +370 -370
  165. package/apps/workflow/src/main.tsx +13 -13
  166. package/apps/workflow/src/styles.css +1 -1
  167. package/apps/workflow/src/theme/index.ts +546 -546
  168. package/apps/workflow/tsconfig.app.json +23 -23
  169. package/apps/workflow/tsconfig.json +21 -21
  170. package/apps/workflow/tsconfig.spec.json +28 -28
  171. package/apps/workflow/vite.config.ts +51 -51
  172. package/nx.json +58 -58
  173. package/package.json +1 -1
  174. package/packages/api/.babelrc +12 -12
  175. package/packages/api/.eslintrc.json +18 -18
  176. package/packages/api/README.md +7 -7
  177. package/packages/api/project.json +8 -8
  178. package/packages/api/src/index.ts +3 -3
  179. package/packages/api/src/lib/jsonPlaceholderService/endpoints.ts +3 -3
  180. package/packages/api/src/lib/jsonPlaceholderService/service.ts +13 -13
  181. package/packages/api/tsconfig.json +17 -17
  182. package/packages/api/tsconfig.lib.json +24 -24
  183. package/packages/atoms/.babelrc +12 -12
  184. package/packages/atoms/.eslintrc.json +18 -18
  185. package/packages/atoms/README.md +7 -7
  186. package/packages/atoms/forms/AuthenticationTabForm/authenticationTabForm.json +224 -224
  187. package/packages/atoms/forms/AuthenticationTabForm/index.tsx +255 -255
  188. package/packages/atoms/forms/SettingsTabForm/index.tsx +85 -85
  189. package/packages/atoms/forms/SettingsTabForm/settingTabForm.json +27 -27
  190. package/packages/atoms/forms/index.ts +4 -4
  191. package/packages/atoms/project.json +8 -8
  192. package/packages/atoms/src/index.ts +33 -33
  193. package/packages/atoms/src/lib/Accordion/Accordion.module.css +7 -7
  194. package/packages/atoms/src/lib/Accordion/Accordion.spec.tsx +13 -13
  195. package/packages/atoms/src/lib/Accordion/Accordion.tsx +29 -29
  196. package/packages/atoms/src/lib/Alert/Alert.module.css +7 -7
  197. package/packages/atoms/src/lib/Alert/Alert.spec.tsx +10 -10
  198. package/packages/atoms/src/lib/Alert/Alert.tsx +19 -19
  199. package/packages/atoms/src/lib/Avatar/Avatar.module.css +7 -7
  200. package/packages/atoms/src/lib/Avatar/Avatar.spec.tsx +10 -10
  201. package/packages/atoms/src/lib/Avatar/Avatar.tsx +22 -22
  202. package/packages/atoms/src/lib/Box/Box.module.css +7 -7
  203. package/packages/atoms/src/lib/Box/Box.spec.tsx +10 -10
  204. package/packages/atoms/src/lib/Box/Box.tsx +19 -19
  205. package/packages/atoms/src/lib/BulkEdit/BulkEdit.module.css +7 -7
  206. package/packages/atoms/src/lib/BulkEdit/BulkEdit.spec.tsx +10 -10
  207. package/packages/atoms/src/lib/BulkEdit/BulkEdit.tsx +15 -15
  208. package/packages/atoms/src/lib/Button/Button.module.css +7 -7
  209. package/packages/atoms/src/lib/Button/Button.spec.tsx +10 -10
  210. package/packages/atoms/src/lib/Button/Button.tsx +78 -78
  211. package/packages/atoms/src/lib/Card/Card.module.css +7 -7
  212. package/packages/atoms/src/lib/Card/Card.spec.tsx +10 -10
  213. package/packages/atoms/src/lib/Card/Card.tsx +19 -19
  214. package/packages/atoms/src/lib/CardContent/CardContent.module.css +7 -7
  215. package/packages/atoms/src/lib/CardContent/CardContent.spec.tsx +10 -10
  216. package/packages/atoms/src/lib/CardContent/CardContent.tsx +22 -22
  217. package/packages/atoms/src/lib/FormTextField/FormTextField.module.css +7 -7
  218. package/packages/atoms/src/lib/FormTextField/FormTextField.spec.tsx +10 -10
  219. package/packages/atoms/src/lib/FormTextField/FormTextField.tsx +35 -35
  220. package/packages/atoms/src/lib/Grid/Grid.module.css +7 -7
  221. package/packages/atoms/src/lib/Grid/Grid.spec.tsx +10 -10
  222. package/packages/atoms/src/lib/Grid/Grid.tsx +19 -19
  223. package/packages/atoms/src/lib/Stack/Stack.module.css +7 -7
  224. package/packages/atoms/src/lib/Stack/Stack.spec.tsx +10 -10
  225. package/packages/atoms/src/lib/Stack/Stack.tsx +19 -19
  226. package/packages/atoms/src/lib/Switch/Switch.module.css +7 -7
  227. package/packages/atoms/src/lib/Switch/Switch.spec.tsx +10 -10
  228. package/packages/atoms/src/lib/Switch/Switch.tsx +46 -46
  229. package/packages/atoms/src/lib/TableView/TableView.module.css +7 -7
  230. package/packages/atoms/src/lib/TableView/TableView.spec.tsx +10 -10
  231. package/packages/atoms/src/lib/TableView/TableView.tsx +88 -88
  232. package/packages/atoms/src/lib/TextField/TextField.module.css +7 -7
  233. package/packages/atoms/src/lib/TextField/TextField.spec.tsx +10 -10
  234. package/packages/atoms/src/lib/TextField/TextField.tsx +17 -17
  235. package/packages/atoms/src/lib/Typography/Typography.module.css +7 -7
  236. package/packages/atoms/src/lib/Typography/Typography.spec.tsx +10 -10
  237. package/packages/atoms/src/lib/Typography/Typography.tsx +22 -22
  238. package/packages/atoms/tsconfig.json +17 -17
  239. package/packages/atoms/tsconfig.lib.json +30 -30
  240. package/packages/common/.babelrc +12 -12
  241. package/packages/common/.eslintrc.json +18 -18
  242. package/packages/common/README.md +7 -7
  243. package/packages/common/project.json +8 -8
  244. package/packages/common/src/index.ts +4 -4
  245. package/packages/common/src/lib/generateRandomProfilePic.ts +3 -3
  246. package/packages/common/src/lib/generateValidationSchema.ts +46 -46
  247. package/packages/common/tsconfig.json +17 -17
  248. package/packages/common/tsconfig.lib.json +24 -24
  249. package/packages/contexts/.babelrc +12 -12
  250. package/packages/contexts/.eslintrc.json +18 -18
  251. package/packages/contexts/README.md +7 -7
  252. package/packages/contexts/project.json +8 -8
  253. package/packages/contexts/src/index.ts +2 -2
  254. package/packages/contexts/tsconfig.json +17 -17
  255. package/packages/contexts/tsconfig.lib.json +24 -24
  256. package/packages/diagrams/.babelrc +12 -12
  257. package/packages/diagrams/.ctirc +208 -208
  258. package/packages/diagrams/.eslintrc.json +17 -17
  259. package/packages/diagrams/CUSTOM_ICONS.md +232 -232
  260. package/packages/diagrams/GOOGLE_SHEETS_IMPLEMENTATION.md +233 -233
  261. package/packages/diagrams/NODE_DATA_UPDATE_API.md +430 -430
  262. package/packages/diagrams/README.md +7 -7
  263. package/packages/diagrams/UNDO_REDO_API.md +306 -306
  264. package/packages/diagrams/locales/en/translation.json +713 -713
  265. package/packages/diagrams/package.json +27 -27
  266. package/packages/diagrams/pnpm-lock.yaml +2606 -2606
  267. package/packages/diagrams/project.json +42 -42
  268. package/packages/diagrams/rollup.config.js +26 -26
  269. package/packages/diagrams/src/DiagramFlow.tsx +7 -7
  270. package/packages/diagrams/src/declarations.d.ts +7 -7
  271. package/packages/diagrams/src/index.ts +8 -1
  272. package/packages/diagrams/src/index.ts.bak +99 -99
  273. package/packages/diagrams/src/lib/assets/markers/markers.param.tsx +101 -101
  274. package/packages/diagrams/src/lib/assets/markers/markers.type.ts +10 -10
  275. package/packages/diagrams/src/lib/atoms/ActorNode.tsx +123 -123
  276. package/packages/diagrams/src/lib/atoms/AddParallelColButton.tsx +26 -26
  277. package/packages/diagrams/src/lib/atoms/BendpointNode.tsx +71 -71
  278. package/packages/diagrams/src/lib/atoms/CardBlockTypeSelector.tsx +35 -35
  279. package/packages/diagrams/src/lib/atoms/CardEditableTitle.tsx +76 -76
  280. package/packages/diagrams/src/lib/atoms/CardMainContent.tsx +19 -19
  281. package/packages/diagrams/src/lib/atoms/ConnectionPoints.tsx +149 -149
  282. package/packages/diagrams/src/lib/atoms/ContentAssist.tsx +341 -341
  283. package/packages/diagrams/src/lib/atoms/DiagramControls.tsx +56 -56
  284. package/packages/diagrams/src/lib/atoms/ExpressionInput.tsx +437 -437
  285. package/packages/diagrams/src/lib/atoms/FloatingConnectionLine.tsx +73 -73
  286. package/packages/diagrams/src/lib/atoms/LazyIcon.tsx +31 -31
  287. package/packages/diagrams/src/lib/atoms/MarkerSelector.tsx +106 -106
  288. package/packages/diagrams/src/lib/atoms/MultiSelectInput.tsx +87 -87
  289. package/packages/diagrams/src/lib/atoms/ParameterInput.tsx +199 -199
  290. package/packages/diagrams/src/lib/atoms/PropertyInput.tsx +114 -114
  291. package/packages/diagrams/src/lib/atoms/StyledBox.tsx +69 -69
  292. package/packages/diagrams/src/lib/atoms/ValidationError.tsx +37 -37
  293. package/packages/diagrams/src/lib/atoms/ValidationMessage.tsx +63 -63
  294. package/packages/diagrams/src/lib/components/AiButton.tsx +52 -52
  295. package/packages/diagrams/src/lib/components/ControlEdgeList.tsx +303 -303
  296. package/packages/diagrams/src/lib/components/CreateFunctionModal.tsx +264 -264
  297. package/packages/diagrams/src/lib/components/CustomCodeModal.tsx +287 -287
  298. package/packages/diagrams/src/lib/components/DiagramPanel.tsx +331 -331
  299. package/packages/diagrams/src/lib/components/FunctionModalTooltip.tsx +30 -30
  300. package/packages/diagrams/src/lib/components/GraphQLCustomCodeModal.tsx +210 -210
  301. package/packages/diagrams/src/lib/components/Header.tsx +143 -143
  302. package/packages/diagrams/src/lib/components/MiniMapCommon.tsx +24 -24
  303. package/packages/diagrams/src/lib/components/ResizeIcon.tsx +81 -81
  304. package/packages/diagrams/src/lib/components/SideBar.tsx +40 -40
  305. package/packages/diagrams/src/lib/components/automation/AISuggestionsModal.tsx +269 -269
  306. package/packages/diagrams/src/lib/components/automation/AISuggestionsPanel.tsx +28 -175
  307. package/packages/diagrams/src/lib/components/automation/AutomationApiNode.tsx +1 -1
  308. package/packages/diagrams/src/lib/components/automation/AutomationDecisionNode.tsx +94 -0
  309. package/packages/diagrams/src/lib/components/automation/AutomationEndNode.tsx +1 -1
  310. package/packages/diagrams/src/lib/components/automation/AutomationExecutionPanel.tsx +439 -439
  311. package/packages/diagrams/src/lib/components/automation/AutomationFormattingNode.tsx +1 -1
  312. package/packages/diagrams/src/lib/components/automation/AutomationInteractionNode.tsx +693 -693
  313. package/packages/diagrams/src/lib/components/automation/AutomationMonitoringNode.tsx +399 -399
  314. package/packages/diagrams/src/lib/components/automation/AutomationNavigationNode.tsx +1 -1
  315. package/packages/diagrams/src/lib/components/automation/AutomationNodeCard.tsx +414 -0
  316. package/packages/diagrams/src/lib/components/automation/AutomationSlackNode.tsx +694 -694
  317. package/packages/diagrams/src/lib/components/automation/AutomationSmsNode.tsx +62 -0
  318. package/packages/diagrams/src/lib/components/automation/AutomationStartNode.tsx +1 -1
  319. package/packages/diagrams/src/lib/components/automation/AutomationTelegramNode.tsx +664 -664
  320. package/packages/diagrams/src/lib/components/automation/AutomationVoiceCallNode.tsx +65 -0
  321. package/packages/diagrams/src/lib/components/automation/AutomationWorkflowNode.tsx +85 -0
  322. package/packages/diagrams/src/lib/components/automation/NodeAIAssistantPopup.tsx +504 -504
  323. package/packages/diagrams/src/lib/components/automation/index.ts +29 -19
  324. package/packages/diagrams/src/lib/components/automation/statusColors.ts +124 -124
  325. package/packages/diagrams/src/lib/contexts/CardDataProvider.tsx +111 -111
  326. package/packages/diagrams/src/lib/contexts/DiagramProvider.tsx +392 -391
  327. package/packages/diagrams/src/lib/contexts/diagramStoreTypes.tsx +134 -134
  328. package/packages/diagrams/src/lib/contexts/onConnect.ts +39 -39
  329. package/packages/diagrams/src/lib/contexts/onDragStart.ts +45 -45
  330. package/packages/diagrams/src/lib/contexts/onNodeDragEnd.ts +179 -179
  331. package/packages/diagrams/src/lib/contexts/onNodesChange.ts +406 -406
  332. package/packages/diagrams/src/lib/contexts/onReconnect.ts +59 -59
  333. package/packages/diagrams/src/lib/contexts/onWorkflowNodeDelete.ts +65 -65
  334. package/packages/diagrams/src/lib/contexts/setContentHeight.ts +14 -14
  335. package/packages/diagrams/src/lib/contexts/setDiagramType.ts +10 -10
  336. package/packages/diagrams/src/lib/contexts/setEdgeShapeType.ts +7 -7
  337. package/packages/diagrams/src/lib/contexts/setEdges.ts +9 -9
  338. package/packages/diagrams/src/lib/contexts/setLayoutDirection.ts +9 -9
  339. package/packages/diagrams/src/lib/contexts/setNodeSetting.ts +17 -17
  340. package/packages/diagrams/src/lib/contexts/setNodes.ts +10 -10
  341. package/packages/diagrams/src/lib/contexts/setPannable.ts +7 -7
  342. package/packages/diagrams/src/lib/contexts/setSelectedEdge.ts +7 -7
  343. package/packages/diagrams/src/lib/contexts/setSelectedNode.ts +7 -7
  344. package/packages/diagrams/src/lib/contexts/undo.ts +163 -163
  345. package/packages/diagrams/src/lib/contexts/updateNodeSetting.ts +17 -17
  346. package/packages/diagrams/src/lib/examples/TwilioWhatsAppConfigExample.ts +128 -128
  347. package/packages/diagrams/src/lib/externals.ts +4 -4
  348. package/packages/diagrams/src/lib/hooks/customUseReactFlow.tsx +90 -90
  349. package/packages/diagrams/src/lib/hooks/updateNodes.ts +45 -45
  350. package/packages/diagrams/src/lib/hooks/useAddChildButton.tsx +61 -61
  351. package/packages/diagrams/src/lib/hooks/useAddSwitchCase.ts +75 -75
  352. package/packages/diagrams/src/lib/hooks/useAutoRegisterFunctions.ts +135 -135
  353. package/packages/diagrams/src/lib/hooks/useAutoRegisterVariables.ts +286 -286
  354. package/packages/diagrams/src/lib/hooks/useDeleteNodeByEvent.ts +64 -64
  355. package/packages/diagrams/src/lib/hooks/useDragCallbacks.tsx +122 -122
  356. package/packages/diagrams/src/lib/hooks/useFormValidation.ts +349 -349
  357. package/packages/diagrams/src/lib/hooks/useFunctionFormCallbacks.ts +136 -136
  358. package/packages/diagrams/src/lib/hooks/useIsSelectedNode.ts +11 -11
  359. package/packages/diagrams/src/lib/hooks/useModalControls.ts +13 -13
  360. package/packages/diagrams/src/lib/hooks/useNodeDragHandlers.ts +43 -43
  361. package/packages/diagrams/src/lib/hooks/useNodeSelection.ts +55 -55
  362. package/packages/diagrams/src/lib/hooks/useRenderDividers.tsx +19 -19
  363. package/packages/diagrams/src/lib/hooks/useRenderPins.tsx +74 -74
  364. package/packages/diagrams/src/lib/hooks/useResizeObserver.ts +21 -21
  365. package/packages/diagrams/src/lib/hooks/useTreeChildNode.ts +536 -536
  366. package/packages/diagrams/src/lib/i18n.ts +42 -42
  367. package/packages/diagrams/src/lib/icons/icons.tsx +324 -0
  368. package/packages/diagrams/src/lib/icons/index.ts +29 -0
  369. package/packages/diagrams/src/lib/icons/types.ts +7 -0
  370. package/packages/diagrams/src/lib/molecules/AddingBlock.tsx +147 -147
  371. package/packages/diagrams/src/lib/molecules/AvailableVariablesDisplay.tsx +57 -57
  372. package/packages/diagrams/src/lib/molecules/Block.tsx +143 -143
  373. package/packages/diagrams/src/lib/molecules/BlockProvider.tsx +28 -28
  374. package/packages/diagrams/src/lib/molecules/BlockWrapper.tsx +14 -14
  375. package/packages/diagrams/src/lib/molecules/ConditionRule.tsx +131 -131
  376. package/packages/diagrams/src/lib/molecules/DraggablePane.tsx +198 -198
  377. package/packages/diagrams/src/lib/molecules/EntityNodeBlocks.tsx +66 -66
  378. package/packages/diagrams/src/lib/molecules/SideHandles.tsx +215 -215
  379. package/packages/diagrams/src/lib/molecules/StencilItem.tsx +85 -85
  380. package/packages/diagrams/src/lib/molecules/WorkflowNodeActionButtons.tsx +62 -62
  381. package/packages/diagrams/src/lib/molecules/animated-add-button.tsx +83 -83
  382. package/packages/diagrams/src/lib/molecules/json-viewer.tsx +107 -107
  383. package/packages/diagrams/src/lib/organisms/AddNodeView.tsx +102 -102
  384. package/packages/diagrams/src/lib/organisms/Card/EntityNode.tsx +259 -259
  385. package/packages/diagrams/src/lib/organisms/Card/card.params.ts +29 -29
  386. package/packages/diagrams/src/lib/organisms/Card/card.types.ts +5 -5
  387. package/packages/diagrams/src/lib/organisms/CodeModal.tsx +105 -105
  388. package/packages/diagrams/src/lib/organisms/ConditionRuleGroup.tsx +138 -138
  389. package/packages/diagrams/src/lib/organisms/CustomEdge/EdgeMarkers.tsx +51 -51
  390. package/packages/diagrams/src/lib/organisms/CustomEdge/custom-edge-generator.tsx +135 -135
  391. package/packages/diagrams/src/lib/organisms/CustomEdge/custom-edge.params.ts +6 -6
  392. package/packages/diagrams/src/lib/organisms/CustomEdge/custom-edge.type.ts +15 -15
  393. package/packages/diagrams/src/lib/organisms/CustomEdge/useCreateBendPoint.tsx +121 -121
  394. package/packages/diagrams/src/lib/organisms/CustomEdge/useEdgeModal.ts +37 -37
  395. package/packages/diagrams/src/lib/organisms/CustomEdge/useEdgePath.tsx +99 -99
  396. package/packages/diagrams/src/lib/organisms/DownloadPanel.tsx +345 -345
  397. package/packages/diagrams/src/lib/organisms/EdgeModal.tsx +243 -243
  398. package/packages/diagrams/src/lib/organisms/HistoryPane.tsx +118 -118
  399. package/packages/diagrams/src/lib/organisms/NodeContextMenu.tsx +259 -259
  400. package/packages/diagrams/src/lib/organisms/PropertiesPane.tsx +276 -276
  401. package/packages/diagrams/src/lib/organisms/SmartDynamicForm.tsx +226 -226
  402. package/packages/diagrams/src/lib/organisms/Stencil.tsx +60 -60
  403. package/packages/diagrams/src/lib/organisms/UseDiagramStore.tsx +4 -4
  404. package/packages/diagrams/src/lib/organisms/WorkFlowNode/NodeActionButtons.tsx +45 -45
  405. package/packages/diagrams/src/lib/organisms/WorkFlowNode/NodeTypeDisplay.tsx +114 -114
  406. package/packages/diagrams/src/lib/organisms/WorkFlowNode/WorkflowNodeIcons.tsx +21 -23
  407. package/packages/diagrams/src/lib/organisms/WorkflowNode.tsx +484 -484
  408. package/packages/diagrams/src/lib/services/GoogleSheetsService.ts +961 -961
  409. package/packages/diagrams/src/lib/services/SlackService.ts +134 -134
  410. package/packages/diagrams/src/lib/services/TwilioWhatsAppService.ts +273 -273
  411. package/packages/diagrams/src/lib/styles.css +55 -55
  412. package/packages/diagrams/src/lib/templates/PageLinks.tsx +13 -13
  413. package/packages/diagrams/src/lib/templates/arch/ArchDiagram.tsx +793 -793
  414. package/packages/diagrams/src/lib/templates/arch/components/EdgeDialog.tsx +82 -82
  415. package/packages/diagrams/src/lib/templates/arch/components/EdgeSettings.tsx +81 -81
  416. package/packages/diagrams/src/lib/templates/arch/components/GroupControls.tsx +59 -59
  417. package/packages/diagrams/src/lib/templates/arch/components/GroupSizeDialog.tsx +81 -81
  418. package/packages/diagrams/src/lib/templates/arch/components/NodeDialog.tsx +214 -214
  419. package/packages/diagrams/src/lib/templates/arch/components/nodeTypes.ts +91 -91
  420. package/packages/diagrams/src/lib/templates/arch/controls/ArchDiagramControls.tsx +349 -349
  421. package/packages/diagrams/src/lib/templates/arch/data/templatee-data.ts +212 -212
  422. package/packages/diagrams/src/lib/templates/cloud-arch/components/CloudArchitectureDiagram.tsx +3912 -3912
  423. package/packages/diagrams/src/lib/templates/cloud-arch/components/FormatConverter.tsx +809 -809
  424. package/packages/diagrams/src/lib/templates/cloud-arch/components/FragmentImporter.tsx +276 -276
  425. package/packages/diagrams/src/lib/templates/cloud-arch/components/PropertiesPanel.tsx +1063 -1063
  426. package/packages/diagrams/src/lib/templates/cloud-arch/components/ServiceIconPicker.tsx +138 -138
  427. package/packages/diagrams/src/lib/templates/cloud-arch/components/SettingsSidebar.tsx +656 -656
  428. package/packages/diagrams/src/lib/templates/cloud-arch/components/SubnetSelector.tsx +468 -468
  429. package/packages/diagrams/src/lib/templates/cloud-arch/components/nodes/ServiceNode.tsx +310 -310
  430. package/packages/diagrams/src/lib/templates/cloud-arch/components/nodes/SubnetNode.tsx +475 -475
  431. package/packages/diagrams/src/lib/templates/cloud-arch/components/nodes/UsersNode.tsx +277 -277
  432. package/packages/diagrams/src/lib/templates/cloud-arch/data/diagramManager.ts +364 -364
  433. package/packages/diagrams/src/lib/templates/cloud-arch/data/types.ts +183 -183
  434. package/packages/diagrams/src/lib/templates/cloud-arch/integration/diagramValidator.ts +379 -379
  435. package/packages/diagrams/src/lib/templates/cloud-arch/messages/errorMessages.json +95 -95
  436. package/packages/diagrams/src/lib/templates/cloud-arch/types/localization.ts +368 -368
  437. package/packages/diagrams/src/lib/templates/cloud-arch/types/validation.ts +72 -72
  438. package/packages/diagrams/src/lib/templates/cloud-arch/utils/aws-icons.ts +557 -557
  439. package/packages/diagrams/src/lib/templates/cloud-arch/utils/awsValidation.ts +446 -446
  440. package/packages/diagrams/src/lib/templates/cloud-arch/utils/azure-icons.ts +802 -802
  441. package/packages/diagrams/src/lib/templates/cloud-arch/utils/azureValidation.ts +495 -495
  442. package/packages/diagrams/src/lib/templates/cloud-arch/utils/cloudValidation.ts +929 -929
  443. package/packages/diagrams/src/lib/templates/cloud-arch/utils/errorMessages.ts +283 -283
  444. package/packages/diagrams/src/lib/templates/cloud-arch/utils/gcp-icons.ts +186 -186
  445. package/packages/diagrams/src/lib/templates/cloud-arch/utils/gcpValidation.ts +312 -312
  446. package/packages/diagrams/src/lib/templates/cloud-arch/utils/genericValidation.ts +689 -689
  447. package/packages/diagrams/src/lib/templates/cloud-arch/utils/iconMapping.ts +383 -383
  448. package/packages/diagrams/src/lib/templates/cloud-arch/utils/idGenerator.ts +220 -220
  449. package/packages/diagrams/src/lib/templates/cloud-arch/utils/localizationManager.ts +300 -300
  450. package/packages/diagrams/src/lib/templates/cloud-arch/utils/restrictionEngine.ts +550 -550
  451. package/packages/diagrams/src/lib/templates/cloud-arch/utils/restrictionValidator.ts +400 -400
  452. package/packages/diagrams/src/lib/templates/cloud-arch/utils/serviceIcons.tsx +129 -129
  453. package/packages/diagrams/src/lib/templates/cloud-arch/utils/serviceMapping.ts +330 -330
  454. package/packages/diagrams/src/lib/templates/cloud-arch/utils/translations.ts +54 -54
  455. package/packages/diagrams/src/lib/templates/cloud-arch/utils/validationExtractor.ts +342 -342
  456. package/packages/diagrams/src/lib/templates/collaborationDiagram/CollaborationDiagram.tsx +15 -15
  457. package/packages/diagrams/src/lib/templates/collaborationDiagram/components/AddCollabEdgeDialog.tsx +181 -181
  458. package/packages/diagrams/src/lib/templates/collaborationDiagram/components/CollabLayout.ts +182 -182
  459. package/packages/diagrams/src/lib/templates/collaborationDiagram/components/CollabObjectNodeSettings.tsx +86 -86
  460. package/packages/diagrams/src/lib/templates/collaborationDiagram/components/CollaborationDiagramFlow.tsx +731 -731
  461. package/packages/diagrams/src/lib/templates/collaborationDiagram/components/DraggableEdgeLabel.tsx +123 -123
  462. package/packages/diagrams/src/lib/templates/collaborationDiagram/controls/CollaborationControls.tsx +131 -131
  463. package/packages/diagrams/src/lib/templates/collaborationDiagram/nodes/CollabEdge.tsx +170 -170
  464. package/packages/diagrams/src/lib/templates/collaborationDiagram/nodes/CollabObjectNode.tsx +178 -178
  465. package/packages/diagrams/src/lib/templates/home.style.css +16 -16
  466. package/packages/diagrams/src/lib/templates/node-forms/ApiForm.tsx +416 -416
  467. package/packages/diagrams/src/lib/templates/node-forms/CallForm.tsx +370 -370
  468. package/packages/diagrams/src/lib/templates/node-forms/ForLoopNode.tsx +313 -313
  469. package/packages/diagrams/src/lib/templates/node-forms/FunctionForm.tsx +211 -211
  470. package/packages/diagrams/src/lib/templates/node-forms/GraphQLForm.tsx +679 -679
  471. package/packages/diagrams/src/lib/templates/node-forms/IfNodeForm.tsx +97 -97
  472. package/packages/diagrams/src/lib/templates/node-forms/LetNodeForm.tsx +533 -533
  473. package/packages/diagrams/src/lib/templates/node-forms/LoopNode.tsx +149 -149
  474. package/packages/diagrams/src/lib/templates/node-forms/NodeForm.tsx +383 -383
  475. package/packages/diagrams/src/lib/templates/node-forms/ReturnNodeForm.tsx +96 -96
  476. package/packages/diagrams/src/lib/templates/node-forms/SetNodeForm.tsx +141 -141
  477. package/packages/diagrams/src/lib/templates/node-forms/SwitchNodeForm.tsx +249 -249
  478. package/packages/diagrams/src/lib/templates/node-forms/TryCatchForm.tsx +167 -167
  479. package/packages/diagrams/src/lib/templates/nodeFormSchema.json +84 -84
  480. package/packages/diagrams/src/lib/templates/sequence/SequenceDiagram.tsx +22 -22
  481. package/packages/diagrams/src/lib/templates/sequence/components/ActivationBarNode.tsx +33 -33
  482. package/packages/diagrams/src/lib/templates/sequence/components/AddMessageDialog.tsx +302 -302
  483. package/packages/diagrams/src/lib/templates/sequence/components/CombinedFragmentNode.tsx +65 -65
  484. package/packages/diagrams/src/lib/templates/sequence/components/EntitySettings.tsx +559 -559
  485. package/packages/diagrams/src/lib/templates/sequence/components/FragmentSettings.tsx +116 -116
  486. package/packages/diagrams/src/lib/templates/sequence/components/SequenceComponents.tsx +14 -14
  487. package/packages/diagrams/src/lib/templates/sequence/components/SequenceDiagramFlow.tsx +1361 -1361
  488. package/packages/diagrams/src/lib/templates/sequence/components/SequenceEntityNode.tsx +394 -394
  489. package/packages/diagrams/src/lib/templates/sequence/components/SequenceMessageEdge.tsx +272 -272
  490. package/packages/diagrams/src/lib/templates/sequence/components/SimpleEntitySettings.tsx +89 -89
  491. package/packages/diagrams/src/lib/templates/sequence/controls/DiagramControls.tsx +707 -707
  492. package/packages/diagrams/src/lib/templates/sequence/data/template-data.ts +635 -635
  493. package/packages/diagrams/src/lib/templates/stateMachine/StateMachineDiagram.tsx +66 -66
  494. package/packages/diagrams/src/lib/templates/stateMachine/components/CompositeStateNodeSettings.tsx +638 -638
  495. package/packages/diagrams/src/lib/templates/stateMachine/components/CustomEdge.tsx +220 -220
  496. package/packages/diagrams/src/lib/templates/stateMachine/components/EdgeSettings.tsx +193 -193
  497. package/packages/diagrams/src/lib/templates/stateMachine/components/SelfConnectingEdge.tsx +41 -41
  498. package/packages/diagrams/src/lib/templates/stateMachine/components/StateMachineComponents.tsx +49 -49
  499. package/packages/diagrams/src/lib/templates/stateMachine/components/StateMachineDiagramFlow.tsx +1238 -1238
  500. package/packages/diagrams/src/lib/templates/stateMachine/components/StateMachineLayout.ts +350 -350
  501. package/packages/diagrams/src/lib/templates/stateMachine/components/StateNodeSettings.tsx +188 -188
  502. package/packages/diagrams/src/lib/templates/stateMachine/components/useSelfTransition.ts +114 -114
  503. package/packages/diagrams/src/lib/templates/stateMachine/controls/StateDiagramControls.tsx +488 -488
  504. package/packages/diagrams/src/lib/templates/stateMachine/data/template-data.ts +4 -4
  505. package/packages/diagrams/src/lib/templates/stateMachine/nodes/ChoicePointNode.tsx +54 -54
  506. package/packages/diagrams/src/lib/templates/stateMachine/nodes/CompositeStateNode.tsx +225 -225
  507. package/packages/diagrams/src/lib/templates/stateMachine/nodes/EntryPointNode.tsx +31 -31
  508. package/packages/diagrams/src/lib/templates/stateMachine/nodes/ExitPointNode.tsx +44 -44
  509. package/packages/diagrams/src/lib/templates/stateMachine/nodes/FinalStateNode.tsx +41 -41
  510. package/packages/diagrams/src/lib/templates/stateMachine/nodes/ForkJoinNode.tsx +53 -53
  511. package/packages/diagrams/src/lib/templates/stateMachine/nodes/HistoryStateNode.tsx +36 -36
  512. package/packages/diagrams/src/lib/templates/stateMachine/nodes/InitialStateNode.tsx +29 -29
  513. package/packages/diagrams/src/lib/templates/stateMachine/nodes/JunctionPointNode.tsx +33 -33
  514. package/packages/diagrams/src/lib/templates/stateMachine/nodes/PinPointNode.tsx +111 -111
  515. package/packages/diagrams/src/lib/templates/stateMachine/nodes/StateNode.tsx +124 -124
  516. package/packages/diagrams/src/lib/templates/stateMachine/nodes/bendPoint.tsx +71 -71
  517. package/packages/diagrams/src/lib/templates/systemFlow/SystemFlowDiagram.tsx +67 -67
  518. package/packages/diagrams/src/lib/templates/systemFlow/components/EdgeSettings.tsx +330 -330
  519. package/packages/diagrams/src/lib/templates/systemFlow/components/FloatingEdge.tsx +219 -219
  520. package/packages/diagrams/src/lib/templates/systemFlow/components/SystemFlowComponents.tsx +28 -28
  521. package/packages/diagrams/src/lib/templates/systemFlow/components/SystemFlowDiagramFlow.tsx +1179 -1179
  522. package/packages/diagrams/src/lib/templates/systemFlow/components/SystemFlowNodeSettings.tsx +151 -151
  523. package/packages/diagrams/src/lib/templates/systemFlow/controls/SystemFlowControls.tsx +435 -435
  524. package/packages/diagrams/src/lib/templates/systemFlow/data/template-data.ts +308 -308
  525. package/packages/diagrams/src/lib/templates/systemFlow/demo.tsx +91 -91
  526. package/packages/diagrams/src/lib/templates/systemFlow/index.ts +5 -5
  527. package/packages/diagrams/src/lib/templates/systemFlow/nodes/BendpointNode.tsx +80 -80
  528. package/packages/diagrams/src/lib/templates/systemFlow/nodes/SystemNode.tsx +92 -92
  529. package/packages/diagrams/src/lib/templates/systemFlow/nodes/TreeSystemNode.tsx +755 -755
  530. package/packages/diagrams/src/lib/templates/useCaseDiagram/UseCaseDiagram.tsx +16 -16
  531. package/packages/diagrams/src/lib/templates/useCaseDiagram/components/ActorNodeSettings.tsx +103 -103
  532. package/packages/diagrams/src/lib/templates/useCaseDiagram/components/AddRelationshipDialog.tsx +186 -186
  533. package/packages/diagrams/src/lib/templates/useCaseDiagram/components/PackageNodeSettings.tsx +205 -205
  534. package/packages/diagrams/src/lib/templates/useCaseDiagram/components/UseCaseDiagramFlow.tsx +637 -637
  535. package/packages/diagrams/src/lib/templates/useCaseDiagram/components/UseCaseNodeSettings.tsx +120 -120
  536. package/packages/diagrams/src/lib/templates/useCaseDiagram/controls/UseCaseControls.tsx +289 -289
  537. package/packages/diagrams/src/lib/templates/useCaseDiagram/nodes/PackageNode.tsx +83 -83
  538. package/packages/diagrams/src/lib/templates/useCaseDiagram/nodes/UseCaseEdge.tsx +115 -115
  539. package/packages/diagrams/src/lib/templates/useCaseDiagram/nodes/UseCaseNode.tsx +230 -230
  540. package/packages/diagrams/src/lib/templates/validationSchema.json +277 -277
  541. package/packages/diagrams/src/lib/theme.ts +439 -439
  542. package/packages/diagrams/src/lib/types/FunctionSignature.ts +11 -11
  543. package/packages/diagrams/src/lib/types/SmartDynamicFormField.ts +37 -37
  544. package/packages/diagrams/src/lib/types/automation-node-data-types.ts +45 -131
  545. package/packages/diagrams/src/lib/types/available-variables.ts +18 -18
  546. package/packages/diagrams/src/lib/types/card-node.ts +68 -68
  547. package/packages/diagrams/src/lib/types/collaboration-types.ts +114 -114
  548. package/packages/diagrams/src/lib/types/colors.ts +25 -25
  549. package/packages/diagrams/src/lib/types/condition-builder.ts +18 -18
  550. package/packages/diagrams/src/lib/types/diagram-types.ts +14 -14
  551. package/packages/diagrams/src/lib/types/edge-types.ts +39 -39
  552. package/packages/diagrams/src/lib/types/function-execution.ts +35 -35
  553. package/packages/diagrams/src/lib/types/hooks.types.ts +6 -6
  554. package/packages/diagrams/src/lib/types/ndoe-form-types.ts +139 -139
  555. package/packages/diagrams/src/lib/types/node-types.ts +13 -23
  556. package/packages/diagrams/src/lib/types/sequence-types.ts +178 -178
  557. package/packages/diagrams/src/lib/types/shared-node-types.ts +21 -21
  558. package/packages/diagrams/src/lib/types/state-machine-types.ts +225 -225
  559. package/packages/diagrams/src/lib/types/stencil-item.ts +7 -7
  560. package/packages/diagrams/src/lib/types/structures.ts +80 -80
  561. package/packages/diagrams/src/lib/types/system-flow-types.ts +129 -129
  562. package/packages/diagrams/src/lib/types/usecase-types.ts +84 -84
  563. package/packages/diagrams/src/lib/types/validation-types.ts +134 -134
  564. package/packages/diagrams/src/lib/types/workflow-content-dynamic-form-type.ts +23 -23
  565. package/packages/diagrams/src/lib/types/workflow-node-data-types.ts +172 -172
  566. package/packages/diagrams/src/lib/utils/AutomationExecutionEngine.ts +658 -1179
  567. package/packages/diagrams/src/lib/utils/add-new-block.ts +34 -34
  568. package/packages/diagrams/src/lib/utils/add-new-node.ts +52 -52
  569. package/packages/diagrams/src/lib/utils/addToHistory.ts +15 -15
  570. package/packages/diagrams/src/lib/utils/automation-flow-processor.ts +556 -619
  571. package/packages/diagrams/src/lib/utils/closestPoint.ts +45 -45
  572. package/packages/diagrams/src/lib/utils/color-options.tsx +26 -26
  573. package/packages/diagrams/src/lib/utils/compress-img.ts +59 -59
  574. package/packages/diagrams/src/lib/utils/configLoader.ts +329 -329
  575. package/packages/diagrams/src/lib/utils/constant-lengths.ts +8 -8
  576. package/packages/diagrams/src/lib/utils/create-updated.tsx +40 -40
  577. package/packages/diagrams/src/lib/utils/createHistoryChange.ts +3 -3
  578. package/packages/diagrams/src/lib/utils/dividerUtils.tsx +59 -59
  579. package/packages/diagrams/src/lib/utils/edge-hooks.ts +53 -53
  580. package/packages/diagrams/src/lib/utils/elkLayout.ts +297 -297
  581. package/packages/diagrams/src/lib/utils/event-hooks.ts +69 -69
  582. package/packages/diagrams/src/lib/utils/event-store.ts +58 -58
  583. package/packages/diagrams/src/lib/utils/flow-node-hooks.ts +28 -28
  584. package/packages/diagrams/src/lib/utils/flow-to-js.ts +1465 -1465
  585. package/packages/diagrams/src/lib/utils/functionGenerator.ts +38 -38
  586. package/packages/diagrams/src/lib/utils/generateEdgesFromNodeOrder.ts +113 -113
  587. package/packages/diagrams/src/lib/utils/helpers.types.ts +10 -10
  588. package/packages/diagrams/src/lib/utils/highlightText.tsx +93 -93
  589. package/packages/diagrams/src/lib/utils/iconMapper.tsx +76 -76
  590. package/packages/diagrams/src/lib/utils/logger.ts +5 -5
  591. package/packages/diagrams/src/lib/utils/model-hooks.ts +129 -129
  592. package/packages/diagrams/src/lib/utils/node-hooks.ts +78 -78
  593. package/packages/diagrams/src/lib/utils/nodeAIAssistantConfig.ts +54 -54
  594. package/packages/diagrams/src/lib/utils/nodeOrderByEdges.ts +437 -437
  595. package/packages/diagrams/src/lib/utils/nodeutils.ts +242 -242
  596. package/packages/diagrams/src/lib/utils/object.ts +13 -13
  597. package/packages/diagrams/src/lib/utils/useDebounce.ts +19 -19
  598. package/packages/diagrams/src/lib/utils/utilities.ts +105 -105
  599. package/packages/diagrams/src/lib/utils/validationEngine.ts +610 -610
  600. package/packages/diagrams/src/lib/utils/vhToPixels.ts +9 -9
  601. package/packages/diagrams/tsconfig.json +21 -21
  602. package/packages/diagrams/tsconfig.lib.json +26 -25
  603. package/packages/diagrams/webpack.config.js +17 -17
  604. package/packages/interfaces/.babelrc +12 -12
  605. package/packages/interfaces/.eslintrc.json +18 -18
  606. package/packages/interfaces/README.md +7 -7
  607. package/packages/interfaces/project.json +8 -8
  608. package/packages/interfaces/src/index.ts +21 -21
  609. package/packages/interfaces/src/lib/Button.tsx +1 -1
  610. package/packages/interfaces/src/lib/DataGrid.ts +14 -14
  611. package/packages/interfaces/src/lib/StyledBox.tsx +1 -1
  612. package/packages/interfaces/src/lib/ToolbarItem.ts +7 -7
  613. package/packages/interfaces/src/lib/UserCard.ts +8 -8
  614. package/packages/interfaces/src/lib/yup.ts +3 -3
  615. package/packages/interfaces/tsconfig.json +17 -17
  616. package/packages/interfaces/tsconfig.lib.json +24 -24
  617. package/packages/molecules/.babelrc +12 -12
  618. package/packages/molecules/.eslintrc.json +18 -18
  619. package/packages/molecules/README.md +7 -7
  620. package/packages/molecules/project.json +8 -8
  621. package/packages/molecules/src/index.ts +47 -41
  622. package/packages/molecules/src/lib/ActionTextField/ActionTextField.module.css +7 -7
  623. package/packages/molecules/src/lib/ActionTextField/ActionTextField.spec.tsx +10 -10
  624. package/packages/molecules/src/lib/ActionTextField/ActionTextField.tsx +33 -33
  625. package/packages/molecules/src/lib/ClosableButton/CloseableButton.module.css +7 -7
  626. package/packages/molecules/src/lib/ClosableButton/CloseableButton.spec.tsx +11 -11
  627. package/packages/molecules/src/lib/ClosableButton/CloseableButton.tsx +69 -69
  628. package/packages/molecules/src/lib/EditorTab/EditorTab.module.css +7 -7
  629. package/packages/molecules/src/lib/EditorTab/EditorTab.spec.tsx +10 -10
  630. package/packages/molecules/src/lib/EditorTab/EditorTab.tsx +42 -42
  631. package/packages/molecules/src/lib/EditorTab/TabPanel.tsx +25 -25
  632. package/packages/molecules/src/lib/ParamsActionField/ParamsActionField.module.css +7 -7
  633. package/packages/molecules/src/lib/ParamsActionField/ParamsActionField.spec.tsx +10 -10
  634. package/packages/molecules/src/lib/ParamsActionField/ParamsActionField.tsx +24 -24
  635. package/packages/molecules/src/lib/SvgIcons/icons.tsx +323 -291
  636. package/packages/molecules/src/lib/SvgIcons/index.ts +31 -25
  637. package/packages/molecules/src/lib/SvgIcons/types.ts +7 -7
  638. package/packages/molecules/src/lib/TableWithInlineView/TableWithInlineView.module.css +7 -7
  639. package/packages/molecules/src/lib/TableWithInlineView/TableWithInlineView.spec.tsx +10 -10
  640. package/packages/molecules/src/lib/TableWithInlineView/TableWithInlineView.tsx +47 -47
  641. package/packages/molecules/src/lib/UserCard/UserCard.module.css +7 -7
  642. package/packages/molecules/src/lib/UserCard/UserCard.spec.tsx +11 -11
  643. package/packages/molecules/src/lib/UserCard/UserCard.tsx +22 -22
  644. package/packages/molecules/src/lib/VerbSelection/HTTPVerbSelection.module.css +7 -7
  645. package/packages/molecules/src/lib/VerbSelection/HTTPVerbSelection.spec.tsx +10 -10
  646. package/packages/molecules/src/lib/VerbSelection/HTTPVerbSelection.tsx +72 -72
  647. package/packages/molecules/tsconfig.json +17 -17
  648. package/packages/molecules/tsconfig.lib.json +30 -30
  649. package/packages/organisms/.babelrc +12 -12
  650. package/packages/organisms/.eslintrc.json +18 -18
  651. package/packages/organisms/README.md +7 -7
  652. package/packages/organisms/project.json +8 -8
  653. package/packages/organisms/src/index.ts +4 -4
  654. package/packages/organisms/src/lib/EditorToolbar/EditorToolbar.module.css +7 -7
  655. package/packages/organisms/src/lib/EditorToolbar/EditorToolbar.spec.tsx +10 -10
  656. package/packages/organisms/src/lib/EditorToolbar/EditorToolbar.tsx +117 -117
  657. package/packages/organisms/src/lib/EditorToolbar/SortableItem.tsx +51 -51
  658. package/packages/organisms/src/lib/UserList/UserList.module.css +7 -7
  659. package/packages/organisms/src/lib/UserList/UserList.spec.tsx +11 -11
  660. package/packages/organisms/src/lib/UserList/UserList.tsx +48 -48
  661. package/packages/organisms/src/lib/UserList/store.ts +49 -49
  662. package/packages/organisms/tsconfig.json +17 -17
  663. package/packages/organisms/tsconfig.lib.json +24 -24
  664. package/packages/zustand/.babelrc +12 -12
  665. package/packages/zustand/.eslintrc.json +18 -18
  666. package/packages/zustand/README.md +7 -7
  667. package/packages/zustand/project.json +8 -8
  668. package/packages/zustand/src/index.ts +4 -4
  669. package/packages/zustand/tsconfig.json +17 -17
  670. package/packages/zustand/tsconfig.lib.json +24 -24
  671. package/tsconfig.base.json +29 -29
  672. package/packages/diagrams/src/lib/components/automation/AutomationAISuggestionNode.tsx +0 -304
  673. package/packages/diagrams/src/lib/components/automation/AutomationEmailNode.tsx +0 -773
  674. package/packages/diagrams/src/lib/components/automation/AutomationGoogleServicesNode.tsx +0 -779
  675. package/packages/diagrams/src/lib/components/automation/AutomationNoteNode.tsx +0 -422
  676. package/packages/diagrams/src/lib/components/automation/AutomationSheetsNode.tsx +0 -1135
  677. package/packages/diagrams/src/lib/examples/GoogleSheetsConfigurationExamples.ts +0 -306
@@ -1,1361 +1,1361 @@
1
- import React, { useCallback, useState, useRef, useEffect } from 'react';
2
- import {
3
- ReactFlow,
4
- Background,
5
- useNodesState,
6
- useEdgesState,
7
- Panel,
8
- BackgroundVariant,
9
- Connection,
10
- NodeChange,
11
- Node,
12
- Edge,
13
- MiniMap,
14
- NodeMouseHandler,
15
- EdgeMouseHandler,
16
- } from '@xyflow/react';
17
- import '@xyflow/react/dist/style.css';
18
-
19
- import {
20
- Box,
21
- Button,
22
- TextField,
23
- Typography,
24
- IconButton,
25
- Paper,
26
- } from '@mui/material';
27
- import DownloadIcon from '@mui/icons-material/Download';
28
- import UploadIcon from '@mui/icons-material/Upload';
29
- import FullscreenIcon from '@mui/icons-material/Fullscreen';
30
- import FullscreenExitIcon from '@mui/icons-material/FullscreenExit';
31
- import CloseIcon from '@mui/icons-material/Close';
32
- import UndoIcon from '@mui/icons-material/Undo';
33
- import RedoIcon from '@mui/icons-material/Redo';
34
- import { useTranslation } from 'react-i18next';
35
- import {
36
- SequenceDiagramProps,
37
- ThemeData,
38
- SequenceNode,
39
- SequenceEdge,
40
- SequenceHistoryEntry,
41
- SequenceEntityShape,
42
- CombinedFragmentType,
43
- SequenceMessageType,
44
- SequenceEntityNode,
45
- SequenceEntityData,
46
- FragmentSettingsUpdateData,
47
- EntitySettingsUpdateData,
48
- ActivationBarNode,
49
- CombinedFragmentNode,
50
- SequenceMessageData,
51
- ActivationBarData,
52
- CombinedFragmentData
53
- } from '../../../types/sequence-types';
54
- import { getTemplateData } from '../data/template-data';
55
- import { sequenceEdgeTypes, sequenceNodeTypes } from './SequenceComponents';
56
- import DiagramControls from '../controls/DiagramControls';
57
- import FragmentSettings from './FragmentSettings';
58
- import EntitySettings from './EntitySettings';
59
- import AddMessageDialog from './AddMessageDialog';
60
- import Sidebar from '../../../components/SideBar';
61
- import AiButton from '../../../components/AiButton';
62
- import MiniMapCommon from '../../../components/MiniMapCommon';
63
- import DiagramPanel from '../../../components/DiagramPanel';
64
-
65
- // Types for browser fullscreen API extensions
66
- interface HTMLElementWithFullscreen extends HTMLElement {
67
- webkitRequestFullscreen?: () => Promise<void>;
68
- msRequestFullscreen?: () => Promise<void>;
69
- }
70
-
71
- interface DocumentWithFullscreen extends Document {
72
- webkitExitFullscreen?: () => Promise<void>;
73
- msExitFullscreen?: () => Promise<void>;
74
- }
75
-
76
- // Main component that manages the diagram state
77
-
78
- const SequenceDiagramFlow: React.FC<SequenceDiagramProps> = ({
79
- sequenceNodes,
80
- sequenceEdges,
81
- }) => {
82
- const { t } = useTranslation();
83
-
84
- // Initialize nodes and edges with our data - use xy/flow base types with proper generics
85
- const [nodes, setNodes, onNodesChange] = useNodesState(sequenceNodes);
86
-
87
- const [edges, setEdges, onEdgesChange] = useEdgesState(sequenceEdges);
88
-
89
- // History state for undo/redo functionality
90
- const [history, setHistory] = useState<SequenceHistoryEntry[]>([]);
91
- const [historyIndex, setHistoryIndex] = useState<number>(-1);
92
- const isUndoRedoAction = useRef(false);
93
-
94
- // Initialize history with initial state
95
- useEffect(() => {
96
- // Only initialize if history is empty
97
- if (history.length === 0) {
98
- const initialState: SequenceHistoryEntry = {
99
- nodes: [...nodes] as SequenceNode[],
100
- edges: [...edges] as SequenceEdge[],
101
- };
102
- setHistory([initialState]);
103
- setHistoryIndex(0);
104
- }
105
- }, []);
106
-
107
- // Save current state to history when nodes or edges change
108
- useEffect(() => {
109
- // Don't record history when performing undo/redo actions or when we're still initializing
110
- if (isUndoRedoAction.current || history.length === 0) {
111
- return;
112
- }
113
-
114
- // Debounce: Only update history if nodes/edges actually changed (deep compare)
115
- const newHistoryEntry: SequenceHistoryEntry = {
116
- nodes: [...nodes] as SequenceNode[],
117
- edges: [...edges] as SequenceEdge[],
118
- };
119
- const currentState = history[historyIndex];
120
- if (
121
- JSON.stringify(currentState.nodes) ===
122
- JSON.stringify(newHistoryEntry.nodes) &&
123
- JSON.stringify(currentState.edges) ===
124
- JSON.stringify(newHistoryEntry.edges)
125
- ) {
126
- return; // No change, don't add to history
127
- }
128
-
129
- // Trim future history if we're in the middle of the history stack
130
- const newHistory = history.slice(0, historyIndex + 1);
131
- newHistory.push(newHistoryEntry);
132
- setHistory(newHistory);
133
- setHistoryIndex(newHistory.length - 1);
134
- }, [nodes, edges, history, historyIndex]);
135
-
136
- // Function to perform undo operation
137
- const handleUndo = useCallback(() => {
138
- if (historyIndex > 0) {
139
- isUndoRedoAction.current = true;
140
- const prevState = history[historyIndex - 1];
141
- setNodes(prevState.nodes);
142
- setEdges(prevState.edges);
143
- setHistoryIndex(historyIndex - 1);
144
- setTimeout(() => {
145
- isUndoRedoAction.current = false;
146
- }, 0);
147
- }
148
- }, [history, historyIndex, setNodes, setEdges]);
149
-
150
- // Function to perform redo operation
151
- const handleRedo = useCallback(() => {
152
- if (historyIndex < history.length - 1) {
153
- isUndoRedoAction.current = true;
154
- const nextState = history[historyIndex + 1];
155
- setNodes(nextState.nodes);
156
- setEdges(nextState.edges);
157
- setHistoryIndex(historyIndex + 1);
158
- setTimeout(() => {
159
- isUndoRedoAction.current = false;
160
- }, 0);
161
- }
162
- }, [history, historyIndex, setNodes, setEdges]);
163
-
164
- // Listen for keyboard shortcuts
165
- useEffect(() => {
166
- const handleKeyDown = (e: KeyboardEvent) => {
167
- // Check for Ctrl+Z or Cmd+Z (undo)
168
- if ((e.ctrlKey || e.metaKey) && e.key === 'z' && !e.shiftKey) {
169
- e.preventDefault();
170
- handleUndo();
171
- }
172
- // Check for Ctrl+Y or Cmd+Shift+Z (redo)
173
- if (
174
- ((e.ctrlKey || e.metaKey) && e.key === 'y') ||
175
- ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'z')
176
- ) {
177
- e.preventDefault();
178
- handleRedo();
179
- }
180
- };
181
-
182
- window.addEventListener('keydown', handleKeyDown);
183
- return () => {
184
- window.removeEventListener('keydown', handleKeyDown);
185
- };
186
- }, [handleUndo, handleRedo]);
187
-
188
- const [theme, setTheme] = useState<ThemeData>({
189
- primary: '#61dafb',
190
- secondary: '#2a2a2a',
191
- });
192
- const [isFullscreen, setIsFullscreen] = useState<boolean>(false);
193
- const [selectedFragmentId, setSelectedFragmentId] = useState<string | null>(
194
- null,
195
- );
196
- const [fragmentSettings, setFragmentSettings] = useState({
197
- width: 400,
198
- height: 150,
199
- });
200
- const [showFragmentSettings, setShowFragmentSettings] =
201
- useState<boolean>(false);
202
- const diagramContainerRef = useRef<HTMLDivElement>(null);
203
- const [editingNode, setEditingNode] = useState<string | null>(null);
204
- const [editingEdge, setEditingEdge] = useState<string | null>(null);
205
- const [editingLabel, setEditingLabel] = useState<string>('');
206
- const [editingConditions, setEditingConditions] = useState<string[]>([]);
207
- const [editingType, setEditingType] = useState<'node' | 'edge' | 'fragment'>(
208
- 'node',
209
- );
210
- const [selectedEntityId, setSelectedEntityId] = useState<string | null>(null);
211
- const [showEntitySettings, setShowEntitySettings] = useState<boolean>(false);
212
- const [showMessageDialog, setShowMessageDialog] = useState<boolean>(false);
213
- const ENTITY_FIXED_Y = 50; // Fixed y position for all entities
214
-
215
- // Type-safe node access helpers
216
- const getSequenceEntityNodes = useCallback(() => {
217
- return nodes.filter((node): node is Node<SequenceEntityData> =>
218
- node.type === 'sequenceEntity'
219
- );
220
- }, [nodes]);
221
-
222
- const getCombinedFragmentNodes = useCallback(() => {
223
- return nodes.filter((node): node is Node<CombinedFragmentData> =>
224
- node.type === 'combinedFragment'
225
- );
226
- }, [nodes]);
227
-
228
- // Intercept node position changes to lock y for sequenceEntity nodes
229
- const onNodesChangeLockedY = useCallback(
230
- (changes: NodeChange[]) => {
231
- let hasPositionChange = false;
232
- const updatedNodes = nodes.map((node) => {
233
- // Find if there's a position change for this node
234
- const change = changes.find(
235
- (c: NodeChange) => c.type === 'position' && c.id === node.id,
236
- );
237
- if (
238
- change &&
239
- change.type === 'position' &&
240
- node.type === 'sequenceEntity' &&
241
- change.position
242
- ) {
243
- hasPositionChange = true;
244
- // Lock y position
245
- return {
246
- ...node,
247
- position: {
248
- x: change.position.x,
249
- y: ENTITY_FIXED_Y, // always fixed
250
- },
251
- };
252
- }
253
- return node;
254
- });
255
- if (hasPositionChange) {
256
- setNodes(updatedNodes);
257
- } else {
258
- onNodesChange(changes);
259
- }
260
- },
261
- [nodes, setNodes, onNodesChange],
262
- );
263
-
264
- // Handler to add a new entity
265
- const handleAddEntity = useCallback(
266
- (shape: SequenceEntityShape = 'rectangle') => {
267
- console.log('Adding new entity with shape:', shape);
268
- console.log('Current nodes:', nodes);
269
-
270
- // Find all entity nodes
271
- const entityNodes = getSequenceEntityNodes();
272
- const entityCount = entityNodes.length;
273
- const newEntityId = `entity-${entityCount + 1}`;
274
-
275
- // Find the rightmost x position among entities
276
- const rightmostX =
277
- entityNodes.length > 0
278
- ? Math.max(...entityNodes.map((node) => node.position.x))
279
- : 100; // Default starting x
280
-
281
- const xOffset = 150; // Space between entities
282
- const xPosition =
283
- entityNodes.length > 0 ? rightmostX + xOffset : rightmostX;
284
-
285
- // Create a new entity node with extended properties
286
- const newEntity: Node<SequenceEntityData> = {
287
- id: newEntityId,
288
- type: 'sequenceEntity',
289
- position: { x: xPosition, y: 50 },
290
- data: {
291
- label: `Entity ${entityCount + 1}`,
292
- color: theme.primary,
293
- backgroundColor: theme.secondary,
294
- lifelineLength: 500, // Use same height as others
295
- shape: shape, // Use the provided shape
296
- fontSize: 12,
297
- borderWidth: 2,
298
- description: '',
299
- collapsed: false,
300
- },
301
- draggable: true,
302
- zIndex: 5, // Higher z-index to appear above other elements
303
- };
304
-
305
- // Adjust position based on entity shape
306
- let offsetX = 55;
307
- switch (shape) {
308
- case 'circle':
309
- offsetX = 40;
310
- break;
311
- case 'database':
312
- offsetX = 45;
313
- break;
314
- case 'actor':
315
- offsetX = 60;
316
- break;
317
- default:
318
- offsetX = 55;
319
- break;
320
- }
321
-
322
- const activationBar: Node<ActivationBarData> = {
323
- id: `${newEntityId}-activation`,
324
- type: 'activationBar',
325
- position: { x: xPosition + offsetX, y: 180 }, // Position below the entity
326
- data: {
327
- entityId: newEntityId,
328
- color: theme.secondary,
329
- borderColor: theme.primary,
330
- length: 150,
331
- },
332
- draggable: true,
333
- zIndex: 1, // Lower z-index to appear behind entity boxes but above combined fragments
334
- };
335
-
336
- setNodes((nds) => [...nds, newEntity, activationBar]);
337
- },
338
- [nodes, setNodes, theme, getSequenceEntityNodes],
339
- );
340
-
341
- // Filter entities for Add Message Dialog
342
- const sequenceEntities = useCallback((): SequenceEntityNode[] => {
343
- return getSequenceEntityNodes().map((node) => ({
344
- id: node.id,
345
- type: 'sequenceEntity',
346
- data: node.data,
347
- position: node.position,
348
- draggable: node.draggable,
349
- zIndex: node.zIndex,
350
- }));
351
- }, [getSequenceEntityNodes]);
352
-
353
- // Handler to open add message dialog
354
- const handleOpenAddMessageDialog = useCallback(() => {
355
- // Filter to get only entity nodes
356
- const entityNodes = getSequenceEntityNodes();
357
-
358
- if (entityNodes.length < 1) {
359
- alert(t('sequenceDiagram.errors.needEntitiesForMessage'));
360
- return;
361
- }
362
-
363
- setShowMessageDialog(true);
364
- }, [getSequenceEntityNodes]);
365
-
366
- // Handler to create a new message with specified source, target, and type
367
- const handleAddCustomMessage = useCallback(
368
- (
369
- sourceId: string,
370
- targetId: string,
371
- messageType: SequenceMessageType,
372
- label: string,
373
- ) => {
374
- // Find the source and target nodes
375
- const sourceNode = nodes.find((n) => n.id === sourceId);
376
- const targetNode = nodes.find((n) => n.id === targetId);
377
-
378
- if (!sourceNode || !targetNode) {
379
- console.error(t('sequenceDiagram.errors.sourceTargetNotFound'));
380
- return;
381
- }
382
-
383
- // Calculate a reasonable Y position for the new message
384
- const messageY =
385
- Math.max(
386
- ...edges.map((edge) => (edge.data as SequenceMessageData)?.y || 0),
387
- 180, // Default minimum Y position
388
- ) + 60; // Add some spacing
389
-
390
- // Calculate handle positions based on nodes
391
- const sourceX = sourceNode.position?.x || 0;
392
- const targetX = targetNode.position?.x || 0;
393
-
394
- // Calculate source and target handles
395
- let sourceHandle = 'right';
396
- let targetHandle = 'left';
397
-
398
- if (messageType === 'self') {
399
- // For self messages, always use the right side
400
- sourceHandle = 'right';
401
- targetHandle = 'right';
402
- } else if (sourceX > targetX) {
403
- // If source is to the right of target (server-to-client)
404
- sourceHandle = 'left';
405
- targetHandle = 'right';
406
- } else {
407
- // If source is to the left of target (client-to-server)
408
- sourceHandle = 'right';
409
- targetHandle = 'left';
410
- }
411
-
412
- // Create a message from the source to the target entity
413
- const newEdge: Edge<SequenceMessageData> = {
414
- id: `seq-edge-${edges.length + 1}`,
415
- source: sourceId,
416
- target: targetId,
417
- type: 'sequenceMessage',
418
- sourceHandle: sourceHandle,
419
- targetHandle: targetHandle,
420
- data: {
421
- label: label,
422
- type: messageType,
423
- y: messageY,
424
- },
425
- animated: messageType === 'async',
426
- };
427
-
428
- setEdges((eds) => [...eds, newEdge]);
429
-
430
- setNodes((nds) => {
431
- return nds.map((node) => {
432
- if (
433
- node.type === 'sequenceEntity' &&
434
- (node.id === sourceId || node.id === targetId)
435
- ) {
436
- const nodeData = node.data as SequenceEntityData;
437
- // Find all messages (edges) connected to this node, including the new one
438
- const connectedMessages = [...edges, newEdge].filter(
439
- (edge) => edge.source === node.id || edge.target === node.id,
440
- );
441
- // Find the max Y position among these messages
442
- const maxY = Math.max(
443
- ...connectedMessages.map((edge) => (edge.data as SequenceMessageData)?.y || 0),
444
- nodeData.lifelineLength || 0, // at least current length
445
- );
446
- const newLength = Math.max(maxY + 40, nodeData.lifelineLength || 0);
447
- // Only update if needed
448
- if (newLength > (nodeData.lifelineLength || 0)) {
449
- return {
450
- ...node,
451
- data: {
452
- ...nodeData,
453
- lifelineLength: newLength,
454
- },
455
- };
456
- }
457
- }
458
- return node;
459
- });
460
- });
461
- },
462
- [nodes, edges, setEdges, setNodes],
463
- );
464
-
465
- // Handler for the original add message button (now opens the dialog)
466
- const handleAddMessage = useCallback(() => {
467
- handleOpenAddMessageDialog();
468
- }, [handleOpenAddMessageDialog]);
469
-
470
- // Function to export diagram as JSON
471
- const exportDiagram = useCallback(() => {
472
- const diagramData = {
473
- nodes: nodes,
474
- edges: edges,
475
- };
476
-
477
- const dataStr = JSON.stringify(diagramData, null, 2);
478
- const dataUri =
479
- 'data:application/json;charset=utf-8,' + encodeURIComponent(dataStr);
480
-
481
- const exportFileDefaultName = t('sequenceDiagram.export.filename');
482
-
483
- const linkElement = document.createElement('a');
484
- linkElement.setAttribute('href', dataUri);
485
- linkElement.setAttribute('download', exportFileDefaultName);
486
- linkElement.click();
487
- }, [nodes, edges]);
488
-
489
- // Function to import diagram from JSON
490
- const importDiagram = useCallback(
491
- (event: React.ChangeEvent<HTMLInputElement>) => {
492
- if (!event.target.files || event.target.files.length === 0) return;
493
-
494
- const fileReader = new FileReader();
495
- fileReader.readAsText(event.target.files[0], 'UTF-8');
496
- fileReader.onload = (e) => {
497
- try {
498
- if (!e.target || typeof e.target.result !== 'string') return;
499
-
500
- const imported = JSON.parse(e.target.result);
501
- if (imported.nodes && imported.edges) {
502
- setNodes(imported.nodes);
503
- setEdges(imported.edges);
504
- }
505
- } catch (error) {
506
- console.error('Error importing diagram:', error);
507
- alert(t('sequenceDiagram.errors.importFailed'));
508
- }
509
- };
510
- },
511
- [setNodes, setEdges],
512
- );
513
-
514
- // Function to handle theme changes
515
- const handleThemeChange = useCallback(
516
- (newTheme: ThemeData) => {
517
- setTheme(newTheme);
518
-
519
- // Update nodes with new theme colors
520
- setNodes((nds) =>
521
- nds.map((node) => {
522
- if (node.type === 'sequenceEntity') {
523
- const nodeData = node.data;
524
- return {
525
- ...node,
526
- data: {
527
- ...nodeData,
528
- color: newTheme.primary,
529
- backgroundColor: newTheme.secondary,
530
- },
531
- };
532
- } else if (node.type === 'activationBar') {
533
- const nodeData = node.data;
534
- return {
535
- ...node,
536
- data: {
537
- ...nodeData,
538
- color: newTheme.secondary,
539
- borderColor: newTheme.primary,
540
- },
541
- };
542
- }
543
- return node;
544
- }),
545
- );
546
- },
547
- [setNodes],
548
- );
549
-
550
- // Toggle fullscreen mode
551
- const toggleFullscreen = useCallback(() => {
552
- if (!diagramContainerRef.current) return;
553
-
554
- const element = diagramContainerRef.current as HTMLElementWithFullscreen;
555
- const doc = document as DocumentWithFullscreen;
556
-
557
- if (!isFullscreen) {
558
- if (element.requestFullscreen) {
559
- element.requestFullscreen();
560
- } else if (element.webkitRequestFullscreen) {
561
- element.webkitRequestFullscreen();
562
- } else if (element.msRequestFullscreen) {
563
- element.msRequestFullscreen();
564
- }
565
- } else {
566
- if (doc.exitFullscreen) {
567
- doc.exitFullscreen();
568
- } else if (doc.webkitExitFullscreen) {
569
- doc.webkitExitFullscreen();
570
- } else if (doc.msExitFullscreen) {
571
- doc.msExitFullscreen();
572
- }
573
- }
574
-
575
- setIsFullscreen(!isFullscreen);
576
- }, [isFullscreen]);
577
-
578
- // Listen for fullscreen change events from browser
579
- React.useEffect(() => {
580
- const handleFullscreenChange = () => {
581
- setIsFullscreen(!!document.fullscreenElement);
582
- };
583
-
584
- document.addEventListener('fullscreenchange', handleFullscreenChange);
585
- document.addEventListener('webkitfullscreenchange', handleFullscreenChange);
586
- document.addEventListener('mozfullscreenchange', handleFullscreenChange);
587
- document.addEventListener('MSFullscreenChange', handleFullscreenChange);
588
-
589
- return () => {
590
- document.removeEventListener('fullscreenchange', handleFullscreenChange);
591
- document.removeEventListener(
592
- 'webkitfullscreenchange',
593
- handleFullscreenChange,
594
- );
595
- document.removeEventListener(
596
- 'mozfullscreenchange',
597
- handleFullscreenChange,
598
- );
599
- document.removeEventListener(
600
- 'MSFullscreenChange',
601
- handleFullscreenChange,
602
- );
603
- };
604
- }, []);
605
-
606
- // Properly handle connections between nodes
607
- const onConnect = useCallback(
608
- (params: Connection) => {
609
- console.log('Connection params:', params);
610
- if (!params.source || !params.target) return;
611
-
612
- // Find the source and target nodes
613
- const sourceNode = nodes.find((n) => n.id === params.source);
614
- const targetNode = nodes.find((n) => n.id === params.target);
615
-
616
- if (!sourceNode || !targetNode) return;
617
-
618
- // Only allow connections between sequence entities
619
- if (
620
- sourceNode.type !== 'sequenceEntity' ||
621
- targetNode.type !== 'sequenceEntity'
622
- ) {
623
- alert(t('sequenceDiagram.errors.onlyConnectEntities'));
624
- return;
625
- }
626
-
627
- // Calculate a Y position for the new message
628
- const messageY =
629
- Math.max(
630
- ...edges.map((edge) => (edge.data as SequenceMessageData)?.y || 0),
631
- 180, // Default minimum Y position
632
- ) + 60; // Add some spacing
633
-
634
- // Calculate handle positions based on nodes
635
- const sourceX = sourceNode.position?.x || 0;
636
- const targetX = targetNode.position?.x || 0;
637
-
638
- // Determine correct handles based on relative positions
639
- let sourceHandle = params.sourceHandle;
640
- let targetHandle = params.targetHandle;
641
-
642
- // If handles aren't explicitly provided by the connection event,
643
- // calculate them based on node positions
644
- if (!sourceHandle || !targetHandle) {
645
- if (sourceX > targetX) {
646
- // Source is to the right of target (server-to-client)
647
- sourceHandle = 'left';
648
- targetHandle = 'right';
649
- } else {
650
- // Source is to the left of target (client-to-server)
651
- sourceHandle = 'right';
652
- targetHandle = 'left';
653
- }
654
- }
655
-
656
- // Create a new edge for the message
657
- const newEdge: Edge<SequenceMessageData> = {
658
- id: `seq-edge-${edges.length + 1}`,
659
- source: params.source,
660
- target: params.target,
661
- type: 'sequenceMessage',
662
- sourceHandle: sourceHandle,
663
- targetHandle: targetHandle,
664
- data: {
665
- label: `Message ${edges.length + 1}`,
666
- type: 'sync', // Default to sync message
667
- y: messageY,
668
- },
669
- animated: false,
670
- };
671
-
672
- setEdges((eds) => [...eds, newEdge]);
673
-
674
- setNodes((nds) => {
675
- return nds.map((node) => {
676
- if (
677
- node.type === 'sequenceEntity' &&
678
- (node.id === params.source || node.id === params.target)
679
- ) {
680
- const nodeData = node.data as SequenceEntityData;
681
- // Find all messages (edges) connected to this node, including the new one
682
- const connectedMessages = [...edges, newEdge].filter(
683
- (edge) => edge.source === node.id || edge.target === node.id,
684
- );
685
- // Find the max Y position among these messages
686
- const maxY = Math.max(
687
- ...connectedMessages.map((edge) => (edge.data as SequenceMessageData)?.y || 0),
688
- nodeData.lifelineLength || 0, // at least current length
689
- );
690
- const newLength = Math.max(maxY + 40, nodeData.lifelineLength || 0);
691
- // Only update if needed
692
- if (newLength > (nodeData.lifelineLength || 0)) {
693
- return {
694
- ...node,
695
- data: {
696
- ...nodeData,
697
- lifelineLength: newLength,
698
- },
699
- };
700
- }
701
- }
702
- return node;
703
- });
704
- });
705
- },
706
- [nodes, edges, setEdges, setNodes],
707
- );
708
-
709
- // Handle node click events - use ReactFlow's NodeMouseHandler type
710
- const onNodeClick: NodeMouseHandler = useCallback(
711
- (event, node) => {
712
- // If the node is a combined fragment, select it for editing
713
- if (node.type === 'combinedFragment') {
714
- setSelectedFragmentId(node.id);
715
-
716
- // Set current fragment dimensions
717
- const width = node.style?.width || 400;
718
- const height = node.style?.height || 150;
719
- setFragmentSettings({ width: Number(width), height: Number(height) });
720
-
721
- // Show the settings panel
722
- setShowFragmentSettings(true);
723
- setShowEntitySettings(false);
724
- }
725
- // If the node is an entity, select it for settings
726
- else if (node.type === 'sequenceEntity') {
727
- setSelectedEntityId(node.id);
728
- setShowEntitySettings(true);
729
- setShowFragmentSettings(false);
730
- } else {
731
- // If clicking on a non-fragment node while settings are open, close them
732
- if (showFragmentSettings) {
733
- setShowFragmentSettings(false);
734
- setSelectedFragmentId(null);
735
- }
736
- if (showEntitySettings) {
737
- setShowEntitySettings(false);
738
- setSelectedEntityId(null);
739
- }
740
- }
741
- },
742
- [showFragmentSettings, showEntitySettings],
743
- );
744
-
745
- // Handle node double-click for label editing - use ReactFlow's NodeMouseHandler type
746
- const onNodeDoubleClick: NodeMouseHandler = useCallback(
747
- (event, node) => {
748
- event.preventDefault();
749
- event.stopPropagation();
750
-
751
- if (node.type === 'sequenceEntity') {
752
- const nodeData = node.data as SequenceEntityData;
753
- setEditingNode(node.id);
754
- setEditingEdge(null);
755
- setEditingLabel(nodeData.label || '');
756
- setEditingType('node');
757
- } else if (node.type === 'combinedFragment') {
758
- const nodeData = node.data as CombinedFragmentData;
759
- setEditingNode(node.id);
760
- setEditingEdge(null);
761
- setEditingLabel(nodeData.label || '');
762
- setEditingType('fragment');
763
- setEditingConditions(nodeData.conditions || []);
764
- }
765
- },
766
- [],
767
- );
768
-
769
- // Handle edge double-click for label editing - use ReactFlow's EdgeMouseHandler type
770
- const onEdgeDoubleClick: EdgeMouseHandler = useCallback(
771
- (event, edge) => {
772
- event.preventDefault();
773
- event.stopPropagation();
774
-
775
- if (edge.type === 'sequenceMessage') {
776
- const edgeData = edge.data as SequenceMessageData;
777
- setEditingEdge(edge.id);
778
- setEditingNode(null);
779
- setEditingLabel(edgeData?.label || '');
780
- setEditingType('edge');
781
- }
782
- },
783
- [],
784
- );
785
-
786
- // Handle label input change
787
- const handleLabelChange = useCallback(
788
- (e: React.ChangeEvent<HTMLInputElement>) => {
789
- setEditingLabel(e.target.value);
790
- },
791
- [],
792
- );
793
-
794
- // Handle condition change
795
- const handleConditionChange = (idx: number, value: string) => {
796
- const updated = [...editingConditions];
797
- updated[idx] = value;
798
- setEditingConditions(updated);
799
- };
800
-
801
- // Handle add condition
802
- const handleAddCondition = () => {
803
- setEditingConditions([...editingConditions, '']);
804
- };
805
-
806
- // Handle remove condition
807
- const handleRemoveCondition = (idx: number) => {
808
- setEditingConditions(editingConditions.filter((_, i) => i !== idx));
809
- };
810
-
811
- // Save the edited label
812
- const saveLabel = useCallback(() => {
813
- if (editingNode && editingType === 'node') {
814
- setNodes((nds) =>
815
- nds.map((node) => {
816
- if (node.id === editingNode) {
817
- return {
818
- ...node,
819
- data: {
820
- ...node.data,
821
- label: editingLabel,
822
- },
823
- };
824
- }
825
- return node;
826
- }),
827
- );
828
- setEditingNode(null);
829
- } else if (editingNode && editingType === 'fragment') {
830
- setNodes((nds) =>
831
- nds.map((node) => {
832
- if (node.id === editingNode) {
833
- return {
834
- ...node,
835
- data: {
836
- ...node.data,
837
- label: editingLabel,
838
- conditions: editingConditions,
839
- },
840
- };
841
- }
842
- return node;
843
- }),
844
- );
845
- setEditingNode(null);
846
- setEditingType('node');
847
- } else if (editingEdge && editingType === 'edge') {
848
- setEdges((eds) =>
849
- eds.map((edge) => {
850
- if (edge.id === editingEdge) {
851
- return {
852
- ...edge,
853
- data: {
854
- ...edge.data,
855
- label: editingLabel,
856
- },
857
- };
858
- }
859
- return edge;
860
- }),
861
- );
862
- setEditingEdge(null);
863
- }
864
-
865
- // Reset editing state
866
- setEditingType('node');
867
- }, [
868
- editingNode,
869
- editingEdge,
870
- editingType,
871
- editingLabel,
872
- editingConditions,
873
- setNodes,
874
- setEdges,
875
- ]);
876
-
877
- // Handle keyboard events for the input field
878
- const handleKeyDown = useCallback(
879
- (e: React.KeyboardEvent) => {
880
- if (e.key === 'Enter') {
881
- saveLabel();
882
- } else if (e.key === 'Escape') {
883
- setEditingNode(null);
884
- setEditingEdge(null);
885
- }
886
- },
887
- [saveLabel],
888
- );
889
-
890
- // Cancel editing
891
- const cancelEditing = useCallback(() => {
892
- setEditingNode(null);
893
- setEditingEdge(null);
894
- setEditingType('node');
895
- }, []);
896
-
897
- // Handler to add a new alt fragment
898
- const handleAddAltFragment = useCallback(
899
- (fragmentType: CombinedFragmentType = 'alt') => {
900
- console.log(`Adding new ${fragmentType} fragment...`);
901
-
902
- // Find all fragment nodes
903
- const fragmentNodes = getCombinedFragmentNodes();
904
- const fragmentCount = fragmentNodes.length;
905
- const newFragmentId = `${fragmentType}-fragment-${fragmentCount + 1}`;
906
-
907
- // Find the lowest y position among fragments
908
- const defaultX = 250; // Fixed x position for all fragments
909
- const defaultY = 300; // Default starting y for fragments
910
-
911
- const lowestY =
912
- fragmentNodes.length > 0
913
- ? Math.max(...fragmentNodes.map((node) => node.position.y))
914
- : defaultY;
915
-
916
- const yOffset = 200; // Space between fragments vertically
917
- const centerX = defaultX;
918
- const centerY = fragmentNodes.length > 0 ? lowestY + yOffset : lowestY;
919
-
920
- // Set up conditions based on fragment type
921
- let conditions: string[] = [];
922
- switch (fragmentType) {
923
- case 'alt':
924
- conditions = ['[condition]', '[else]'];
925
- break;
926
- case 'opt':
927
- conditions = ['[condition]'];
928
- break;
929
- case 'loop':
930
- conditions = ['[loop condition]'];
931
- break;
932
- case 'par':
933
- conditions = ['[parallel 1]', '[parallel 2]'];
934
- break;
935
- default:
936
- conditions = ['[condition]'];
937
- }
938
-
939
- // Create a new fragment node
940
- const newFragment: Node<CombinedFragmentData> = {
941
- id: newFragmentId,
942
- type: 'combinedFragment',
943
- position: { x: centerX, y: centerY },
944
- style: {
945
- width: fragmentSettings.width,
946
- height: fragmentSettings.height,
947
- },
948
- data: {
949
- label: fragmentType,
950
- conditions: conditions,
951
- style: {
952
- width: fragmentSettings.width,
953
- height: fragmentSettings.height,
954
- },
955
- color: '#000000',
956
- backgroundColor: '#ffffff',
957
- lifelineLength: 0,
958
- },
959
- draggable: true,
960
- zIndex: 0, // Lower z-index to appear behind other elements
961
- };
962
-
963
- setNodes((nds) => [...nds, newFragment]);
964
- setSelectedFragmentId(newFragmentId);
965
- setShowFragmentSettings(true);
966
- },
967
- [fragmentSettings, getCombinedFragmentNodes, setNodes],
968
- );
969
-
970
- // Function to update selected fragment
971
- const updateSelectedFragment = useCallback(
972
- (fragmentId: string, updates: FragmentSettingsUpdateData) => {
973
- setNodes((nds) =>
974
- nds.map((node) => {
975
- if (node.id === fragmentId) {
976
- // Safely handle the style spread by ensuring the fragment data has a style property
977
- const fragmentData = node.data;
978
- const currentStyle = fragmentData.style || {};
979
- // Apply updates to both style and data.style to ensure consistency
980
- const updatedNode = {
981
- ...node,
982
- style: { ...node.style, ...updates },
983
- data: {
984
- ...fragmentData,
985
- style: { ...currentStyle, ...updates },
986
- },
987
- };
988
- return updatedNode;
989
- }
990
- return node;
991
- }),
992
- );
993
- },
994
- [setNodes],
995
- );
996
-
997
- const handleFragmentWidthChange = useCallback(
998
- (width: number) => {
999
- setFragmentSettings((prev) => ({ ...prev, width }));
1000
-
1001
- if (selectedFragmentId) {
1002
- updateSelectedFragment(selectedFragmentId, { width });
1003
- }
1004
- },
1005
- [selectedFragmentId, updateSelectedFragment],
1006
- );
1007
-
1008
- const handleFragmentHeightChange = useCallback(
1009
- (height: number) => {
1010
- setFragmentSettings((prev) => ({ ...prev, height }));
1011
-
1012
- if (selectedFragmentId) {
1013
- updateSelectedFragment(selectedFragmentId, { height });
1014
- }
1015
- },
1016
- [selectedFragmentId, updateSelectedFragment],
1017
- );
1018
-
1019
- const closeFragmentSettings = useCallback(() => {
1020
- setShowFragmentSettings(false);
1021
- setSelectedFragmentId(null);
1022
- }, []);
1023
-
1024
- // Function to update selected entity
1025
- const updateSelectedEntity = useCallback(
1026
- (updates: EntitySettingsUpdateData) => {
1027
- if (!selectedEntityId) return;
1028
-
1029
- setNodes((nds) =>
1030
- nds.map((node) => {
1031
- if (node.id === selectedEntityId) {
1032
- return {
1033
- ...node,
1034
- data: {
1035
- ...node.data,
1036
- ...updates,
1037
- },
1038
- };
1039
- }
1040
- return node;
1041
- }),
1042
- );
1043
- },
1044
- [selectedEntityId, setNodes],
1045
- );
1046
-
1047
- // Close entity settings
1048
- const closeEntitySettings = useCallback(() => {
1049
- setShowEntitySettings(false);
1050
- setSelectedEntityId(null);
1051
- }, []);
1052
-
1053
- // Handler to load a template diagram
1054
- const loadTemplateData = useCallback(
1055
- (templateType: string) => {
1056
- console.log(`Loading template: ${templateType}`);
1057
-
1058
- const template = getTemplateData(templateType);
1059
-
1060
- if (template.nodes.length > 0) {
1061
- setNodes(template.nodes);
1062
- setEdges(template.edges);
1063
- }
1064
- },
1065
- [setNodes, setEdges],
1066
- );
1067
-
1068
- return (
1069
- <>
1070
- <Box sx={{ display: 'flex', width: '100%', height: '100vh' }}>
1071
- <Sidebar>
1072
- <DiagramControls
1073
- onAddEntity={handleAddEntity}
1074
- onAddMessage={handleAddMessage}
1075
- onAddAltFragment={handleAddAltFragment}
1076
- onUndo={handleUndo}
1077
- onRedo={handleRedo}
1078
- canUndo={historyIndex > 0}
1079
- canRedo={historyIndex < history.length - 1}
1080
- onLoadTemplate={loadTemplateData}
1081
- />
1082
- </Sidebar>
1083
- <Box sx={{ flex: 1, height: '100%', position: 'relative' }}>
1084
- <div
1085
- ref={diagramContainerRef}
1086
- className={`diagram-container ${isFullscreen ? 'fullscreen' : ''}`}
1087
- style={{
1088
- width: '100%',
1089
- height: '100%',
1090
- border: '1px solid #333',
1091
- position: 'relative',
1092
- backgroundColor: '#1a1a1a',
1093
- color: '#ffffff',
1094
- }}
1095
- >
1096
- <ReactFlow<Node, Edge>
1097
- nodes={nodes}
1098
- edges={edges}
1099
- onNodesChange={onNodesChangeLockedY}
1100
- onEdgesChange={onEdgesChange}
1101
- onConnect={onConnect}
1102
- nodeTypes={sequenceNodeTypes}
1103
- edgeTypes={sequenceEdgeTypes}
1104
- fitView
1105
- attributionPosition="bottom-left"
1106
- connectOnClick={false}
1107
- onNodeClick={onNodeClick}
1108
- onNodeDoubleClick={onNodeDoubleClick}
1109
- onEdgeDoubleClick={onEdgeDoubleClick}
1110
- style={{
1111
- backgroundColor: '#1a1a1a',
1112
- }}
1113
- >
1114
- <Background
1115
- color="#333"
1116
- variant={BackgroundVariant.Dots}
1117
- gap={16}
1118
- />
1119
- </ReactFlow>
1120
-
1121
- {/* Components outside ReactFlow */}
1122
- <DiagramPanel
1123
- historyIndex={historyIndex}
1124
- historyLength={history.length}
1125
- onUndo={handleUndo}
1126
- onRedo={handleRedo}
1127
- onClear={() => {
1128
- const clearedState: SequenceHistoryEntry = { nodes: [], edges: [] };
1129
- const newHistory = history.slice(0, historyIndex + 1);
1130
- newHistory.push(clearedState);
1131
- setNodes([]);
1132
- setEdges([]);
1133
- setHistory(newHistory);
1134
- setHistoryIndex(newHistory.length - 1);
1135
- }}
1136
- onImport={() => { }}
1137
- isSettingsOpen={false}
1138
- onToggleSettings={() => { }}
1139
- />
1140
-
1141
- <AiButton />
1142
-
1143
- <MiniMapCommon />
1144
-
1145
- {/* Fragment settings panel */}
1146
- {showFragmentSettings && (
1147
- <FragmentSettings
1148
- fragmentId={selectedFragmentId}
1149
- width={fragmentSettings.width}
1150
- height={fragmentSettings.height}
1151
- onWidthChange={handleFragmentWidthChange}
1152
- onHeightChange={handleFragmentHeightChange}
1153
- onClose={closeFragmentSettings}
1154
- />
1155
- )}
1156
-
1157
- {/* Entity settings panel */}
1158
- {showEntitySettings && selectedEntityId && (
1159
- <EntitySettings
1160
- entityId={selectedEntityId}
1161
- data={
1162
- (nodes.find((node) =>
1163
- node.id === selectedEntityId && node.type === 'sequenceEntity'
1164
- )?.data as SequenceEntityData) || {
1165
- label: '',
1166
- color: '#61dafb',
1167
- backgroundColor: '#2a2a2a',
1168
- lifelineLength: 500
1169
- }
1170
- }
1171
- onUpdate={updateSelectedEntity}
1172
- onClose={closeEntitySettings}
1173
- />
1174
- )}
1175
-
1176
- {/* Label editing overlay */}
1177
- {(editingNode || editingEdge) && (
1178
- <Box
1179
- sx={{
1180
- position: 'absolute',
1181
- zIndex: 10,
1182
- top: 10,
1183
- left: '50%',
1184
- transform: 'translateX(-50%)',
1185
- bgcolor: '#242424',
1186
- border: '1px solid #333',
1187
- color: '#fff',
1188
- p: 2,
1189
- borderRadius: 1,
1190
- boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)',
1191
- minWidth: 320,
1192
- '& .MuiTextField-root': {
1193
- '& .MuiInputLabel-root': {
1194
- color: '#999',
1195
- },
1196
- '& .MuiOutlinedInput-root': {
1197
- color: '#fff',
1198
- '& fieldset': {
1199
- borderColor: '#444',
1200
- },
1201
- '&:hover fieldset': {
1202
- borderColor: '#61dafb',
1203
- },
1204
- '&.Mui-focused fieldset': {
1205
- borderColor: '#61dafb',
1206
- },
1207
- },
1208
- },
1209
- '& .MuiButton-contained': {
1210
- bgcolor: '#61dafb',
1211
- color: '#000',
1212
- '&:hover': {
1213
- bgcolor: '#4db6d6',
1214
- },
1215
- },
1216
- '& .MuiButton-outlined': {
1217
- borderColor: '#333',
1218
- color: '#fff',
1219
- '&:hover': {
1220
- borderColor: '#61dafb',
1221
- bgcolor: 'rgba(97, 218, 251, 0.1)',
1222
- },
1223
- },
1224
- '& .MuiIconButton-root': {
1225
- color: '#999',
1226
- '&:hover': {
1227
- color: '#fff',
1228
- bgcolor: 'rgba(255, 255, 255, 0.1)',
1229
- },
1230
- },
1231
- }}
1232
- >
1233
- <Typography sx={{ mb: 1, fontWeight: 'bold', color: '#fff' }}>
1234
- {editingType === 'node'
1235
- ? t('sequenceFlow.editLabels.entityLabel')
1236
- : editingType === 'edge'
1237
- ? t('sequenceFlow.editLabels.messageLabel')
1238
- : t('sequenceFlow.editLabels.editFragment')}
1239
- </Typography>
1240
- {editingType === 'fragment' ? (
1241
- <>
1242
- <Box display="flex" alignItems="center" gap={2} mb={2}>
1243
- <TextField
1244
- type="text"
1245
- value={editingLabel}
1246
- onChange={handleLabelChange}
1247
- onKeyDown={handleKeyDown}
1248
- autoFocus
1249
- size="small"
1250
- sx={{ width: 200 }}
1251
- label={t('fragmentSettings.fragmentName')}
1252
- />
1253
- </Box>
1254
- {/* Conditions editing */}
1255
- <Box mb={2}>
1256
- <Typography
1257
- variant="body2"
1258
- fontWeight="bold"
1259
- mb={0.5}
1260
- sx={{ color: '#61dafb' }}
1261
- >
1262
- {t('fragmentSettings.conditions')}
1263
- </Typography>
1264
- {editingConditions.map((cond, idx) => (
1265
- <Box
1266
- key={idx}
1267
- display="flex"
1268
- alignItems="center"
1269
- mb={1}
1270
- >
1271
- <TextField
1272
- value={cond}
1273
- onChange={(e) =>
1274
- handleConditionChange(idx, e.target.value)
1275
- }
1276
- size="small"
1277
- fullWidth
1278
- sx={{ mr: 1 }}
1279
- />
1280
- <IconButton
1281
- onClick={() => handleRemoveCondition(idx)}
1282
- size="small"
1283
- >
1284
- <CloseIcon fontSize="small" />
1285
- </IconButton>
1286
- </Box>
1287
- ))}
1288
- <Button
1289
- onClick={handleAddCondition}
1290
- size="small"
1291
- variant="outlined"
1292
- >
1293
- {t('fragmentSettings.addCondition')}
1294
- </Button>
1295
- </Box>
1296
- <Box display="flex" gap={2}>
1297
- <Button
1298
- variant="contained"
1299
- size="small"
1300
- onClick={saveLabel}
1301
- sx={{ textTransform: 'none' }}
1302
- >
1303
- {t('common.save')}
1304
- </Button>
1305
- <Button
1306
- variant="outlined"
1307
- size="small"
1308
- onClick={cancelEditing}
1309
- sx={{ textTransform: 'none' }}
1310
- >
1311
- {t('common.cancel')}
1312
- </Button>
1313
- </Box>
1314
- </>
1315
- ) : (
1316
- <Box display="flex" alignItems="center" gap={2}>
1317
- <TextField
1318
- type="text"
1319
- value={editingLabel}
1320
- onChange={handleLabelChange}
1321
- onKeyDown={handleKeyDown}
1322
- autoFocus
1323
- size="small"
1324
- sx={{ width: 200 }}
1325
- />
1326
- <Button
1327
- variant="contained"
1328
- size="small"
1329
- onClick={saveLabel}
1330
- sx={{ textTransform: 'none' }}
1331
- >
1332
- {t('common.save')}
1333
- </Button>
1334
- <Button
1335
- variant="outlined"
1336
- size="small"
1337
- onClick={cancelEditing}
1338
- sx={{ textTransform: 'none' }}
1339
- >
1340
- {t('common.cancel')}
1341
- </Button>
1342
- </Box>
1343
- )}
1344
- </Box>
1345
- )}
1346
-
1347
- {/* Add Message Dialog */}
1348
- <AddMessageDialog
1349
- open={showMessageDialog}
1350
- onClose={() => setShowMessageDialog(false)}
1351
- onAddMessage={handleAddCustomMessage}
1352
- entities={sequenceEntities()}
1353
- />
1354
- </div>
1355
- </Box>
1356
- </Box>
1357
- </>
1358
- );
1359
- };
1360
-
1361
- export default SequenceDiagramFlow;
1
+ import React, { useCallback, useState, useRef, useEffect } from 'react';
2
+ import {
3
+ ReactFlow,
4
+ Background,
5
+ useNodesState,
6
+ useEdgesState,
7
+ Panel,
8
+ BackgroundVariant,
9
+ Connection,
10
+ NodeChange,
11
+ Node,
12
+ Edge,
13
+ MiniMap,
14
+ NodeMouseHandler,
15
+ EdgeMouseHandler,
16
+ } from '@xyflow/react';
17
+ import '@xyflow/react/dist/style.css';
18
+
19
+ import {
20
+ Box,
21
+ Button,
22
+ TextField,
23
+ Typography,
24
+ IconButton,
25
+ Paper,
26
+ } from '@mui/material';
27
+ import DownloadIcon from '@mui/icons-material/Download';
28
+ import UploadIcon from '@mui/icons-material/Upload';
29
+ import FullscreenIcon from '@mui/icons-material/Fullscreen';
30
+ import FullscreenExitIcon from '@mui/icons-material/FullscreenExit';
31
+ import CloseIcon from '@mui/icons-material/Close';
32
+ import UndoIcon from '@mui/icons-material/Undo';
33
+ import RedoIcon from '@mui/icons-material/Redo';
34
+ import { useTranslation } from 'react-i18next';
35
+ import {
36
+ SequenceDiagramProps,
37
+ ThemeData,
38
+ SequenceNode,
39
+ SequenceEdge,
40
+ SequenceHistoryEntry,
41
+ SequenceEntityShape,
42
+ CombinedFragmentType,
43
+ SequenceMessageType,
44
+ SequenceEntityNode,
45
+ SequenceEntityData,
46
+ FragmentSettingsUpdateData,
47
+ EntitySettingsUpdateData,
48
+ ActivationBarNode,
49
+ CombinedFragmentNode,
50
+ SequenceMessageData,
51
+ ActivationBarData,
52
+ CombinedFragmentData
53
+ } from '../../../types/sequence-types';
54
+ import { getTemplateData } from '../data/template-data';
55
+ import { sequenceEdgeTypes, sequenceNodeTypes } from './SequenceComponents';
56
+ import DiagramControls from '../controls/DiagramControls';
57
+ import FragmentSettings from './FragmentSettings';
58
+ import EntitySettings from './EntitySettings';
59
+ import AddMessageDialog from './AddMessageDialog';
60
+ import Sidebar from '../../../components/SideBar';
61
+ import AiButton from '../../../components/AiButton';
62
+ import MiniMapCommon from '../../../components/MiniMapCommon';
63
+ import DiagramPanel from '../../../components/DiagramPanel';
64
+
65
+ // Types for browser fullscreen API extensions
66
+ interface HTMLElementWithFullscreen extends HTMLElement {
67
+ webkitRequestFullscreen?: () => Promise<void>;
68
+ msRequestFullscreen?: () => Promise<void>;
69
+ }
70
+
71
+ interface DocumentWithFullscreen extends Document {
72
+ webkitExitFullscreen?: () => Promise<void>;
73
+ msExitFullscreen?: () => Promise<void>;
74
+ }
75
+
76
+ // Main component that manages the diagram state
77
+
78
+ const SequenceDiagramFlow: React.FC<SequenceDiagramProps> = ({
79
+ sequenceNodes,
80
+ sequenceEdges,
81
+ }) => {
82
+ const { t } = useTranslation();
83
+
84
+ // Initialize nodes and edges with our data - use xy/flow base types with proper generics
85
+ const [nodes, setNodes, onNodesChange] = useNodesState(sequenceNodes);
86
+
87
+ const [edges, setEdges, onEdgesChange] = useEdgesState(sequenceEdges);
88
+
89
+ // History state for undo/redo functionality
90
+ const [history, setHistory] = useState<SequenceHistoryEntry[]>([]);
91
+ const [historyIndex, setHistoryIndex] = useState<number>(-1);
92
+ const isUndoRedoAction = useRef(false);
93
+
94
+ // Initialize history with initial state
95
+ useEffect(() => {
96
+ // Only initialize if history is empty
97
+ if (history.length === 0) {
98
+ const initialState: SequenceHistoryEntry = {
99
+ nodes: [...nodes] as SequenceNode[],
100
+ edges: [...edges] as SequenceEdge[],
101
+ };
102
+ setHistory([initialState]);
103
+ setHistoryIndex(0);
104
+ }
105
+ }, []);
106
+
107
+ // Save current state to history when nodes or edges change
108
+ useEffect(() => {
109
+ // Don't record history when performing undo/redo actions or when we're still initializing
110
+ if (isUndoRedoAction.current || history.length === 0) {
111
+ return;
112
+ }
113
+
114
+ // Debounce: Only update history if nodes/edges actually changed (deep compare)
115
+ const newHistoryEntry: SequenceHistoryEntry = {
116
+ nodes: [...nodes] as SequenceNode[],
117
+ edges: [...edges] as SequenceEdge[],
118
+ };
119
+ const currentState = history[historyIndex];
120
+ if (
121
+ JSON.stringify(currentState.nodes) ===
122
+ JSON.stringify(newHistoryEntry.nodes) &&
123
+ JSON.stringify(currentState.edges) ===
124
+ JSON.stringify(newHistoryEntry.edges)
125
+ ) {
126
+ return; // No change, don't add to history
127
+ }
128
+
129
+ // Trim future history if we're in the middle of the history stack
130
+ const newHistory = history.slice(0, historyIndex + 1);
131
+ newHistory.push(newHistoryEntry);
132
+ setHistory(newHistory);
133
+ setHistoryIndex(newHistory.length - 1);
134
+ }, [nodes, edges, history, historyIndex]);
135
+
136
+ // Function to perform undo operation
137
+ const handleUndo = useCallback(() => {
138
+ if (historyIndex > 0) {
139
+ isUndoRedoAction.current = true;
140
+ const prevState = history[historyIndex - 1];
141
+ setNodes(prevState.nodes);
142
+ setEdges(prevState.edges);
143
+ setHistoryIndex(historyIndex - 1);
144
+ setTimeout(() => {
145
+ isUndoRedoAction.current = false;
146
+ }, 0);
147
+ }
148
+ }, [history, historyIndex, setNodes, setEdges]);
149
+
150
+ // Function to perform redo operation
151
+ const handleRedo = useCallback(() => {
152
+ if (historyIndex < history.length - 1) {
153
+ isUndoRedoAction.current = true;
154
+ const nextState = history[historyIndex + 1];
155
+ setNodes(nextState.nodes);
156
+ setEdges(nextState.edges);
157
+ setHistoryIndex(historyIndex + 1);
158
+ setTimeout(() => {
159
+ isUndoRedoAction.current = false;
160
+ }, 0);
161
+ }
162
+ }, [history, historyIndex, setNodes, setEdges]);
163
+
164
+ // Listen for keyboard shortcuts
165
+ useEffect(() => {
166
+ const handleKeyDown = (e: KeyboardEvent) => {
167
+ // Check for Ctrl+Z or Cmd+Z (undo)
168
+ if ((e.ctrlKey || e.metaKey) && e.key === 'z' && !e.shiftKey) {
169
+ e.preventDefault();
170
+ handleUndo();
171
+ }
172
+ // Check for Ctrl+Y or Cmd+Shift+Z (redo)
173
+ if (
174
+ ((e.ctrlKey || e.metaKey) && e.key === 'y') ||
175
+ ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'z')
176
+ ) {
177
+ e.preventDefault();
178
+ handleRedo();
179
+ }
180
+ };
181
+
182
+ window.addEventListener('keydown', handleKeyDown);
183
+ return () => {
184
+ window.removeEventListener('keydown', handleKeyDown);
185
+ };
186
+ }, [handleUndo, handleRedo]);
187
+
188
+ const [theme, setTheme] = useState<ThemeData>({
189
+ primary: '#61dafb',
190
+ secondary: '#2a2a2a',
191
+ });
192
+ const [isFullscreen, setIsFullscreen] = useState<boolean>(false);
193
+ const [selectedFragmentId, setSelectedFragmentId] = useState<string | null>(
194
+ null,
195
+ );
196
+ const [fragmentSettings, setFragmentSettings] = useState({
197
+ width: 400,
198
+ height: 150,
199
+ });
200
+ const [showFragmentSettings, setShowFragmentSettings] =
201
+ useState<boolean>(false);
202
+ const diagramContainerRef = useRef<HTMLDivElement>(null);
203
+ const [editingNode, setEditingNode] = useState<string | null>(null);
204
+ const [editingEdge, setEditingEdge] = useState<string | null>(null);
205
+ const [editingLabel, setEditingLabel] = useState<string>('');
206
+ const [editingConditions, setEditingConditions] = useState<string[]>([]);
207
+ const [editingType, setEditingType] = useState<'node' | 'edge' | 'fragment'>(
208
+ 'node',
209
+ );
210
+ const [selectedEntityId, setSelectedEntityId] = useState<string | null>(null);
211
+ const [showEntitySettings, setShowEntitySettings] = useState<boolean>(false);
212
+ const [showMessageDialog, setShowMessageDialog] = useState<boolean>(false);
213
+ const ENTITY_FIXED_Y = 50; // Fixed y position for all entities
214
+
215
+ // Type-safe node access helpers
216
+ const getSequenceEntityNodes = useCallback(() => {
217
+ return nodes.filter((node): node is Node<SequenceEntityData> =>
218
+ node.type === 'sequenceEntity'
219
+ );
220
+ }, [nodes]);
221
+
222
+ const getCombinedFragmentNodes = useCallback(() => {
223
+ return nodes.filter((node): node is Node<CombinedFragmentData> =>
224
+ node.type === 'combinedFragment'
225
+ );
226
+ }, [nodes]);
227
+
228
+ // Intercept node position changes to lock y for sequenceEntity nodes
229
+ const onNodesChangeLockedY = useCallback(
230
+ (changes: NodeChange[]) => {
231
+ let hasPositionChange = false;
232
+ const updatedNodes = nodes.map((node) => {
233
+ // Find if there's a position change for this node
234
+ const change = changes.find(
235
+ (c: NodeChange) => c.type === 'position' && c.id === node.id,
236
+ );
237
+ if (
238
+ change &&
239
+ change.type === 'position' &&
240
+ node.type === 'sequenceEntity' &&
241
+ change.position
242
+ ) {
243
+ hasPositionChange = true;
244
+ // Lock y position
245
+ return {
246
+ ...node,
247
+ position: {
248
+ x: change.position.x,
249
+ y: ENTITY_FIXED_Y, // always fixed
250
+ },
251
+ };
252
+ }
253
+ return node;
254
+ });
255
+ if (hasPositionChange) {
256
+ setNodes(updatedNodes);
257
+ } else {
258
+ onNodesChange(changes);
259
+ }
260
+ },
261
+ [nodes, setNodes, onNodesChange],
262
+ );
263
+
264
+ // Handler to add a new entity
265
+ const handleAddEntity = useCallback(
266
+ (shape: SequenceEntityShape = 'rectangle') => {
267
+ console.log('Adding new entity with shape:', shape);
268
+ console.log('Current nodes:', nodes);
269
+
270
+ // Find all entity nodes
271
+ const entityNodes = getSequenceEntityNodes();
272
+ const entityCount = entityNodes.length;
273
+ const newEntityId = `entity-${entityCount + 1}`;
274
+
275
+ // Find the rightmost x position among entities
276
+ const rightmostX =
277
+ entityNodes.length > 0
278
+ ? Math.max(...entityNodes.map((node) => node.position.x))
279
+ : 100; // Default starting x
280
+
281
+ const xOffset = 150; // Space between entities
282
+ const xPosition =
283
+ entityNodes.length > 0 ? rightmostX + xOffset : rightmostX;
284
+
285
+ // Create a new entity node with extended properties
286
+ const newEntity: Node<SequenceEntityData> = {
287
+ id: newEntityId,
288
+ type: 'sequenceEntity',
289
+ position: { x: xPosition, y: 50 },
290
+ data: {
291
+ label: `Entity ${entityCount + 1}`,
292
+ color: theme.primary,
293
+ backgroundColor: theme.secondary,
294
+ lifelineLength: 500, // Use same height as others
295
+ shape: shape, // Use the provided shape
296
+ fontSize: 12,
297
+ borderWidth: 2,
298
+ description: '',
299
+ collapsed: false,
300
+ },
301
+ draggable: true,
302
+ zIndex: 5, // Higher z-index to appear above other elements
303
+ };
304
+
305
+ // Adjust position based on entity shape
306
+ let offsetX = 55;
307
+ switch (shape) {
308
+ case 'circle':
309
+ offsetX = 40;
310
+ break;
311
+ case 'database':
312
+ offsetX = 45;
313
+ break;
314
+ case 'actor':
315
+ offsetX = 60;
316
+ break;
317
+ default:
318
+ offsetX = 55;
319
+ break;
320
+ }
321
+
322
+ const activationBar: Node<ActivationBarData> = {
323
+ id: `${newEntityId}-activation`,
324
+ type: 'activationBar',
325
+ position: { x: xPosition + offsetX, y: 180 }, // Position below the entity
326
+ data: {
327
+ entityId: newEntityId,
328
+ color: theme.secondary,
329
+ borderColor: theme.primary,
330
+ length: 150,
331
+ },
332
+ draggable: true,
333
+ zIndex: 1, // Lower z-index to appear behind entity boxes but above combined fragments
334
+ };
335
+
336
+ setNodes((nds) => [...nds, newEntity, activationBar]);
337
+ },
338
+ [nodes, setNodes, theme, getSequenceEntityNodes],
339
+ );
340
+
341
+ // Filter entities for Add Message Dialog
342
+ const sequenceEntities = useCallback((): SequenceEntityNode[] => {
343
+ return getSequenceEntityNodes().map((node) => ({
344
+ id: node.id,
345
+ type: 'sequenceEntity',
346
+ data: node.data,
347
+ position: node.position,
348
+ draggable: node.draggable,
349
+ zIndex: node.zIndex,
350
+ }));
351
+ }, [getSequenceEntityNodes]);
352
+
353
+ // Handler to open add message dialog
354
+ const handleOpenAddMessageDialog = useCallback(() => {
355
+ // Filter to get only entity nodes
356
+ const entityNodes = getSequenceEntityNodes();
357
+
358
+ if (entityNodes.length < 1) {
359
+ alert(t('sequenceDiagram.errors.needEntitiesForMessage'));
360
+ return;
361
+ }
362
+
363
+ setShowMessageDialog(true);
364
+ }, [getSequenceEntityNodes]);
365
+
366
+ // Handler to create a new message with specified source, target, and type
367
+ const handleAddCustomMessage = useCallback(
368
+ (
369
+ sourceId: string,
370
+ targetId: string,
371
+ messageType: SequenceMessageType,
372
+ label: string,
373
+ ) => {
374
+ // Find the source and target nodes
375
+ const sourceNode = nodes.find((n) => n.id === sourceId);
376
+ const targetNode = nodes.find((n) => n.id === targetId);
377
+
378
+ if (!sourceNode || !targetNode) {
379
+ console.error(t('sequenceDiagram.errors.sourceTargetNotFound'));
380
+ return;
381
+ }
382
+
383
+ // Calculate a reasonable Y position for the new message
384
+ const messageY =
385
+ Math.max(
386
+ ...edges.map((edge) => (edge.data as SequenceMessageData)?.y || 0),
387
+ 180, // Default minimum Y position
388
+ ) + 60; // Add some spacing
389
+
390
+ // Calculate handle positions based on nodes
391
+ const sourceX = sourceNode.position?.x || 0;
392
+ const targetX = targetNode.position?.x || 0;
393
+
394
+ // Calculate source and target handles
395
+ let sourceHandle = 'right';
396
+ let targetHandle = 'left';
397
+
398
+ if (messageType === 'self') {
399
+ // For self messages, always use the right side
400
+ sourceHandle = 'right';
401
+ targetHandle = 'right';
402
+ } else if (sourceX > targetX) {
403
+ // If source is to the right of target (server-to-client)
404
+ sourceHandle = 'left';
405
+ targetHandle = 'right';
406
+ } else {
407
+ // If source is to the left of target (client-to-server)
408
+ sourceHandle = 'right';
409
+ targetHandle = 'left';
410
+ }
411
+
412
+ // Create a message from the source to the target entity
413
+ const newEdge: Edge<SequenceMessageData> = {
414
+ id: `seq-edge-${edges.length + 1}`,
415
+ source: sourceId,
416
+ target: targetId,
417
+ type: 'sequenceMessage',
418
+ sourceHandle: sourceHandle,
419
+ targetHandle: targetHandle,
420
+ data: {
421
+ label: label,
422
+ type: messageType,
423
+ y: messageY,
424
+ },
425
+ animated: messageType === 'async',
426
+ };
427
+
428
+ setEdges((eds) => [...eds, newEdge]);
429
+
430
+ setNodes((nds) => {
431
+ return nds.map((node) => {
432
+ if (
433
+ node.type === 'sequenceEntity' &&
434
+ (node.id === sourceId || node.id === targetId)
435
+ ) {
436
+ const nodeData = node.data as SequenceEntityData;
437
+ // Find all messages (edges) connected to this node, including the new one
438
+ const connectedMessages = [...edges, newEdge].filter(
439
+ (edge) => edge.source === node.id || edge.target === node.id,
440
+ );
441
+ // Find the max Y position among these messages
442
+ const maxY = Math.max(
443
+ ...connectedMessages.map((edge) => (edge.data as SequenceMessageData)?.y || 0),
444
+ nodeData.lifelineLength || 0, // at least current length
445
+ );
446
+ const newLength = Math.max(maxY + 40, nodeData.lifelineLength || 0);
447
+ // Only update if needed
448
+ if (newLength > (nodeData.lifelineLength || 0)) {
449
+ return {
450
+ ...node,
451
+ data: {
452
+ ...nodeData,
453
+ lifelineLength: newLength,
454
+ },
455
+ };
456
+ }
457
+ }
458
+ return node;
459
+ });
460
+ });
461
+ },
462
+ [nodes, edges, setEdges, setNodes],
463
+ );
464
+
465
+ // Handler for the original add message button (now opens the dialog)
466
+ const handleAddMessage = useCallback(() => {
467
+ handleOpenAddMessageDialog();
468
+ }, [handleOpenAddMessageDialog]);
469
+
470
+ // Function to export diagram as JSON
471
+ const exportDiagram = useCallback(() => {
472
+ const diagramData = {
473
+ nodes: nodes,
474
+ edges: edges,
475
+ };
476
+
477
+ const dataStr = JSON.stringify(diagramData, null, 2);
478
+ const dataUri =
479
+ 'data:application/json;charset=utf-8,' + encodeURIComponent(dataStr);
480
+
481
+ const exportFileDefaultName = t('sequenceDiagram.export.filename');
482
+
483
+ const linkElement = document.createElement('a');
484
+ linkElement.setAttribute('href', dataUri);
485
+ linkElement.setAttribute('download', exportFileDefaultName);
486
+ linkElement.click();
487
+ }, [nodes, edges]);
488
+
489
+ // Function to import diagram from JSON
490
+ const importDiagram = useCallback(
491
+ (event: React.ChangeEvent<HTMLInputElement>) => {
492
+ if (!event.target.files || event.target.files.length === 0) return;
493
+
494
+ const fileReader = new FileReader();
495
+ fileReader.readAsText(event.target.files[0], 'UTF-8');
496
+ fileReader.onload = (e) => {
497
+ try {
498
+ if (!e.target || typeof e.target.result !== 'string') return;
499
+
500
+ const imported = JSON.parse(e.target.result);
501
+ if (imported.nodes && imported.edges) {
502
+ setNodes(imported.nodes);
503
+ setEdges(imported.edges);
504
+ }
505
+ } catch (error) {
506
+ console.error('Error importing diagram:', error);
507
+ alert(t('sequenceDiagram.errors.importFailed'));
508
+ }
509
+ };
510
+ },
511
+ [setNodes, setEdges],
512
+ );
513
+
514
+ // Function to handle theme changes
515
+ const handleThemeChange = useCallback(
516
+ (newTheme: ThemeData) => {
517
+ setTheme(newTheme);
518
+
519
+ // Update nodes with new theme colors
520
+ setNodes((nds) =>
521
+ nds.map((node) => {
522
+ if (node.type === 'sequenceEntity') {
523
+ const nodeData = node.data;
524
+ return {
525
+ ...node,
526
+ data: {
527
+ ...nodeData,
528
+ color: newTheme.primary,
529
+ backgroundColor: newTheme.secondary,
530
+ },
531
+ };
532
+ } else if (node.type === 'activationBar') {
533
+ const nodeData = node.data;
534
+ return {
535
+ ...node,
536
+ data: {
537
+ ...nodeData,
538
+ color: newTheme.secondary,
539
+ borderColor: newTheme.primary,
540
+ },
541
+ };
542
+ }
543
+ return node;
544
+ }),
545
+ );
546
+ },
547
+ [setNodes],
548
+ );
549
+
550
+ // Toggle fullscreen mode
551
+ const toggleFullscreen = useCallback(() => {
552
+ if (!diagramContainerRef.current) return;
553
+
554
+ const element = diagramContainerRef.current as HTMLElementWithFullscreen;
555
+ const doc = document as DocumentWithFullscreen;
556
+
557
+ if (!isFullscreen) {
558
+ if (element.requestFullscreen) {
559
+ element.requestFullscreen();
560
+ } else if (element.webkitRequestFullscreen) {
561
+ element.webkitRequestFullscreen();
562
+ } else if (element.msRequestFullscreen) {
563
+ element.msRequestFullscreen();
564
+ }
565
+ } else {
566
+ if (doc.exitFullscreen) {
567
+ doc.exitFullscreen();
568
+ } else if (doc.webkitExitFullscreen) {
569
+ doc.webkitExitFullscreen();
570
+ } else if (doc.msExitFullscreen) {
571
+ doc.msExitFullscreen();
572
+ }
573
+ }
574
+
575
+ setIsFullscreen(!isFullscreen);
576
+ }, [isFullscreen]);
577
+
578
+ // Listen for fullscreen change events from browser
579
+ React.useEffect(() => {
580
+ const handleFullscreenChange = () => {
581
+ setIsFullscreen(!!document.fullscreenElement);
582
+ };
583
+
584
+ document.addEventListener('fullscreenchange', handleFullscreenChange);
585
+ document.addEventListener('webkitfullscreenchange', handleFullscreenChange);
586
+ document.addEventListener('mozfullscreenchange', handleFullscreenChange);
587
+ document.addEventListener('MSFullscreenChange', handleFullscreenChange);
588
+
589
+ return () => {
590
+ document.removeEventListener('fullscreenchange', handleFullscreenChange);
591
+ document.removeEventListener(
592
+ 'webkitfullscreenchange',
593
+ handleFullscreenChange,
594
+ );
595
+ document.removeEventListener(
596
+ 'mozfullscreenchange',
597
+ handleFullscreenChange,
598
+ );
599
+ document.removeEventListener(
600
+ 'MSFullscreenChange',
601
+ handleFullscreenChange,
602
+ );
603
+ };
604
+ }, []);
605
+
606
+ // Properly handle connections between nodes
607
+ const onConnect = useCallback(
608
+ (params: Connection) => {
609
+ console.log('Connection params:', params);
610
+ if (!params.source || !params.target) return;
611
+
612
+ // Find the source and target nodes
613
+ const sourceNode = nodes.find((n) => n.id === params.source);
614
+ const targetNode = nodes.find((n) => n.id === params.target);
615
+
616
+ if (!sourceNode || !targetNode) return;
617
+
618
+ // Only allow connections between sequence entities
619
+ if (
620
+ sourceNode.type !== 'sequenceEntity' ||
621
+ targetNode.type !== 'sequenceEntity'
622
+ ) {
623
+ alert(t('sequenceDiagram.errors.onlyConnectEntities'));
624
+ return;
625
+ }
626
+
627
+ // Calculate a Y position for the new message
628
+ const messageY =
629
+ Math.max(
630
+ ...edges.map((edge) => (edge.data as SequenceMessageData)?.y || 0),
631
+ 180, // Default minimum Y position
632
+ ) + 60; // Add some spacing
633
+
634
+ // Calculate handle positions based on nodes
635
+ const sourceX = sourceNode.position?.x || 0;
636
+ const targetX = targetNode.position?.x || 0;
637
+
638
+ // Determine correct handles based on relative positions
639
+ let sourceHandle = params.sourceHandle;
640
+ let targetHandle = params.targetHandle;
641
+
642
+ // If handles aren't explicitly provided by the connection event,
643
+ // calculate them based on node positions
644
+ if (!sourceHandle || !targetHandle) {
645
+ if (sourceX > targetX) {
646
+ // Source is to the right of target (server-to-client)
647
+ sourceHandle = 'left';
648
+ targetHandle = 'right';
649
+ } else {
650
+ // Source is to the left of target (client-to-server)
651
+ sourceHandle = 'right';
652
+ targetHandle = 'left';
653
+ }
654
+ }
655
+
656
+ // Create a new edge for the message
657
+ const newEdge: Edge<SequenceMessageData> = {
658
+ id: `seq-edge-${edges.length + 1}`,
659
+ source: params.source,
660
+ target: params.target,
661
+ type: 'sequenceMessage',
662
+ sourceHandle: sourceHandle,
663
+ targetHandle: targetHandle,
664
+ data: {
665
+ label: `Message ${edges.length + 1}`,
666
+ type: 'sync', // Default to sync message
667
+ y: messageY,
668
+ },
669
+ animated: false,
670
+ };
671
+
672
+ setEdges((eds) => [...eds, newEdge]);
673
+
674
+ setNodes((nds) => {
675
+ return nds.map((node) => {
676
+ if (
677
+ node.type === 'sequenceEntity' &&
678
+ (node.id === params.source || node.id === params.target)
679
+ ) {
680
+ const nodeData = node.data as SequenceEntityData;
681
+ // Find all messages (edges) connected to this node, including the new one
682
+ const connectedMessages = [...edges, newEdge].filter(
683
+ (edge) => edge.source === node.id || edge.target === node.id,
684
+ );
685
+ // Find the max Y position among these messages
686
+ const maxY = Math.max(
687
+ ...connectedMessages.map((edge) => (edge.data as SequenceMessageData)?.y || 0),
688
+ nodeData.lifelineLength || 0, // at least current length
689
+ );
690
+ const newLength = Math.max(maxY + 40, nodeData.lifelineLength || 0);
691
+ // Only update if needed
692
+ if (newLength > (nodeData.lifelineLength || 0)) {
693
+ return {
694
+ ...node,
695
+ data: {
696
+ ...nodeData,
697
+ lifelineLength: newLength,
698
+ },
699
+ };
700
+ }
701
+ }
702
+ return node;
703
+ });
704
+ });
705
+ },
706
+ [nodes, edges, setEdges, setNodes],
707
+ );
708
+
709
+ // Handle node click events - use ReactFlow's NodeMouseHandler type
710
+ const onNodeClick: NodeMouseHandler = useCallback(
711
+ (event, node) => {
712
+ // If the node is a combined fragment, select it for editing
713
+ if (node.type === 'combinedFragment') {
714
+ setSelectedFragmentId(node.id);
715
+
716
+ // Set current fragment dimensions
717
+ const width = node.style?.width || 400;
718
+ const height = node.style?.height || 150;
719
+ setFragmentSettings({ width: Number(width), height: Number(height) });
720
+
721
+ // Show the settings panel
722
+ setShowFragmentSettings(true);
723
+ setShowEntitySettings(false);
724
+ }
725
+ // If the node is an entity, select it for settings
726
+ else if (node.type === 'sequenceEntity') {
727
+ setSelectedEntityId(node.id);
728
+ setShowEntitySettings(true);
729
+ setShowFragmentSettings(false);
730
+ } else {
731
+ // If clicking on a non-fragment node while settings are open, close them
732
+ if (showFragmentSettings) {
733
+ setShowFragmentSettings(false);
734
+ setSelectedFragmentId(null);
735
+ }
736
+ if (showEntitySettings) {
737
+ setShowEntitySettings(false);
738
+ setSelectedEntityId(null);
739
+ }
740
+ }
741
+ },
742
+ [showFragmentSettings, showEntitySettings],
743
+ );
744
+
745
+ // Handle node double-click for label editing - use ReactFlow's NodeMouseHandler type
746
+ const onNodeDoubleClick: NodeMouseHandler = useCallback(
747
+ (event, node) => {
748
+ event.preventDefault();
749
+ event.stopPropagation();
750
+
751
+ if (node.type === 'sequenceEntity') {
752
+ const nodeData = node.data as SequenceEntityData;
753
+ setEditingNode(node.id);
754
+ setEditingEdge(null);
755
+ setEditingLabel(nodeData.label || '');
756
+ setEditingType('node');
757
+ } else if (node.type === 'combinedFragment') {
758
+ const nodeData = node.data as CombinedFragmentData;
759
+ setEditingNode(node.id);
760
+ setEditingEdge(null);
761
+ setEditingLabel(nodeData.label || '');
762
+ setEditingType('fragment');
763
+ setEditingConditions(nodeData.conditions || []);
764
+ }
765
+ },
766
+ [],
767
+ );
768
+
769
+ // Handle edge double-click for label editing - use ReactFlow's EdgeMouseHandler type
770
+ const onEdgeDoubleClick: EdgeMouseHandler = useCallback(
771
+ (event, edge) => {
772
+ event.preventDefault();
773
+ event.stopPropagation();
774
+
775
+ if (edge.type === 'sequenceMessage') {
776
+ const edgeData = edge.data as SequenceMessageData;
777
+ setEditingEdge(edge.id);
778
+ setEditingNode(null);
779
+ setEditingLabel(edgeData?.label || '');
780
+ setEditingType('edge');
781
+ }
782
+ },
783
+ [],
784
+ );
785
+
786
+ // Handle label input change
787
+ const handleLabelChange = useCallback(
788
+ (e: React.ChangeEvent<HTMLInputElement>) => {
789
+ setEditingLabel(e.target.value);
790
+ },
791
+ [],
792
+ );
793
+
794
+ // Handle condition change
795
+ const handleConditionChange = (idx: number, value: string) => {
796
+ const updated = [...editingConditions];
797
+ updated[idx] = value;
798
+ setEditingConditions(updated);
799
+ };
800
+
801
+ // Handle add condition
802
+ const handleAddCondition = () => {
803
+ setEditingConditions([...editingConditions, '']);
804
+ };
805
+
806
+ // Handle remove condition
807
+ const handleRemoveCondition = (idx: number) => {
808
+ setEditingConditions(editingConditions.filter((_, i) => i !== idx));
809
+ };
810
+
811
+ // Save the edited label
812
+ const saveLabel = useCallback(() => {
813
+ if (editingNode && editingType === 'node') {
814
+ setNodes((nds) =>
815
+ nds.map((node) => {
816
+ if (node.id === editingNode) {
817
+ return {
818
+ ...node,
819
+ data: {
820
+ ...node.data,
821
+ label: editingLabel,
822
+ },
823
+ };
824
+ }
825
+ return node;
826
+ }),
827
+ );
828
+ setEditingNode(null);
829
+ } else if (editingNode && editingType === 'fragment') {
830
+ setNodes((nds) =>
831
+ nds.map((node) => {
832
+ if (node.id === editingNode) {
833
+ return {
834
+ ...node,
835
+ data: {
836
+ ...node.data,
837
+ label: editingLabel,
838
+ conditions: editingConditions,
839
+ },
840
+ };
841
+ }
842
+ return node;
843
+ }),
844
+ );
845
+ setEditingNode(null);
846
+ setEditingType('node');
847
+ } else if (editingEdge && editingType === 'edge') {
848
+ setEdges((eds) =>
849
+ eds.map((edge) => {
850
+ if (edge.id === editingEdge) {
851
+ return {
852
+ ...edge,
853
+ data: {
854
+ ...edge.data,
855
+ label: editingLabel,
856
+ },
857
+ };
858
+ }
859
+ return edge;
860
+ }),
861
+ );
862
+ setEditingEdge(null);
863
+ }
864
+
865
+ // Reset editing state
866
+ setEditingType('node');
867
+ }, [
868
+ editingNode,
869
+ editingEdge,
870
+ editingType,
871
+ editingLabel,
872
+ editingConditions,
873
+ setNodes,
874
+ setEdges,
875
+ ]);
876
+
877
+ // Handle keyboard events for the input field
878
+ const handleKeyDown = useCallback(
879
+ (e: React.KeyboardEvent) => {
880
+ if (e.key === 'Enter') {
881
+ saveLabel();
882
+ } else if (e.key === 'Escape') {
883
+ setEditingNode(null);
884
+ setEditingEdge(null);
885
+ }
886
+ },
887
+ [saveLabel],
888
+ );
889
+
890
+ // Cancel editing
891
+ const cancelEditing = useCallback(() => {
892
+ setEditingNode(null);
893
+ setEditingEdge(null);
894
+ setEditingType('node');
895
+ }, []);
896
+
897
+ // Handler to add a new alt fragment
898
+ const handleAddAltFragment = useCallback(
899
+ (fragmentType: CombinedFragmentType = 'alt') => {
900
+ console.log(`Adding new ${fragmentType} fragment...`);
901
+
902
+ // Find all fragment nodes
903
+ const fragmentNodes = getCombinedFragmentNodes();
904
+ const fragmentCount = fragmentNodes.length;
905
+ const newFragmentId = `${fragmentType}-fragment-${fragmentCount + 1}`;
906
+
907
+ // Find the lowest y position among fragments
908
+ const defaultX = 250; // Fixed x position for all fragments
909
+ const defaultY = 300; // Default starting y for fragments
910
+
911
+ const lowestY =
912
+ fragmentNodes.length > 0
913
+ ? Math.max(...fragmentNodes.map((node) => node.position.y))
914
+ : defaultY;
915
+
916
+ const yOffset = 200; // Space between fragments vertically
917
+ const centerX = defaultX;
918
+ const centerY = fragmentNodes.length > 0 ? lowestY + yOffset : lowestY;
919
+
920
+ // Set up conditions based on fragment type
921
+ let conditions: string[] = [];
922
+ switch (fragmentType) {
923
+ case 'alt':
924
+ conditions = ['[condition]', '[else]'];
925
+ break;
926
+ case 'opt':
927
+ conditions = ['[condition]'];
928
+ break;
929
+ case 'loop':
930
+ conditions = ['[loop condition]'];
931
+ break;
932
+ case 'par':
933
+ conditions = ['[parallel 1]', '[parallel 2]'];
934
+ break;
935
+ default:
936
+ conditions = ['[condition]'];
937
+ }
938
+
939
+ // Create a new fragment node
940
+ const newFragment: Node<CombinedFragmentData> = {
941
+ id: newFragmentId,
942
+ type: 'combinedFragment',
943
+ position: { x: centerX, y: centerY },
944
+ style: {
945
+ width: fragmentSettings.width,
946
+ height: fragmentSettings.height,
947
+ },
948
+ data: {
949
+ label: fragmentType,
950
+ conditions: conditions,
951
+ style: {
952
+ width: fragmentSettings.width,
953
+ height: fragmentSettings.height,
954
+ },
955
+ color: '#000000',
956
+ backgroundColor: '#ffffff',
957
+ lifelineLength: 0,
958
+ },
959
+ draggable: true,
960
+ zIndex: 0, // Lower z-index to appear behind other elements
961
+ };
962
+
963
+ setNodes((nds) => [...nds, newFragment]);
964
+ setSelectedFragmentId(newFragmentId);
965
+ setShowFragmentSettings(true);
966
+ },
967
+ [fragmentSettings, getCombinedFragmentNodes, setNodes],
968
+ );
969
+
970
+ // Function to update selected fragment
971
+ const updateSelectedFragment = useCallback(
972
+ (fragmentId: string, updates: FragmentSettingsUpdateData) => {
973
+ setNodes((nds) =>
974
+ nds.map((node) => {
975
+ if (node.id === fragmentId) {
976
+ // Safely handle the style spread by ensuring the fragment data has a style property
977
+ const fragmentData = node.data;
978
+ const currentStyle = fragmentData.style || {};
979
+ // Apply updates to both style and data.style to ensure consistency
980
+ const updatedNode = {
981
+ ...node,
982
+ style: { ...node.style, ...updates },
983
+ data: {
984
+ ...fragmentData,
985
+ style: { ...currentStyle, ...updates },
986
+ },
987
+ };
988
+ return updatedNode;
989
+ }
990
+ return node;
991
+ }),
992
+ );
993
+ },
994
+ [setNodes],
995
+ );
996
+
997
+ const handleFragmentWidthChange = useCallback(
998
+ (width: number) => {
999
+ setFragmentSettings((prev) => ({ ...prev, width }));
1000
+
1001
+ if (selectedFragmentId) {
1002
+ updateSelectedFragment(selectedFragmentId, { width });
1003
+ }
1004
+ },
1005
+ [selectedFragmentId, updateSelectedFragment],
1006
+ );
1007
+
1008
+ const handleFragmentHeightChange = useCallback(
1009
+ (height: number) => {
1010
+ setFragmentSettings((prev) => ({ ...prev, height }));
1011
+
1012
+ if (selectedFragmentId) {
1013
+ updateSelectedFragment(selectedFragmentId, { height });
1014
+ }
1015
+ },
1016
+ [selectedFragmentId, updateSelectedFragment],
1017
+ );
1018
+
1019
+ const closeFragmentSettings = useCallback(() => {
1020
+ setShowFragmentSettings(false);
1021
+ setSelectedFragmentId(null);
1022
+ }, []);
1023
+
1024
+ // Function to update selected entity
1025
+ const updateSelectedEntity = useCallback(
1026
+ (updates: EntitySettingsUpdateData) => {
1027
+ if (!selectedEntityId) return;
1028
+
1029
+ setNodes((nds) =>
1030
+ nds.map((node) => {
1031
+ if (node.id === selectedEntityId) {
1032
+ return {
1033
+ ...node,
1034
+ data: {
1035
+ ...node.data,
1036
+ ...updates,
1037
+ },
1038
+ };
1039
+ }
1040
+ return node;
1041
+ }),
1042
+ );
1043
+ },
1044
+ [selectedEntityId, setNodes],
1045
+ );
1046
+
1047
+ // Close entity settings
1048
+ const closeEntitySettings = useCallback(() => {
1049
+ setShowEntitySettings(false);
1050
+ setSelectedEntityId(null);
1051
+ }, []);
1052
+
1053
+ // Handler to load a template diagram
1054
+ const loadTemplateData = useCallback(
1055
+ (templateType: string) => {
1056
+ console.log(`Loading template: ${templateType}`);
1057
+
1058
+ const template = getTemplateData(templateType);
1059
+
1060
+ if (template.nodes.length > 0) {
1061
+ setNodes(template.nodes);
1062
+ setEdges(template.edges);
1063
+ }
1064
+ },
1065
+ [setNodes, setEdges],
1066
+ );
1067
+
1068
+ return (
1069
+ <>
1070
+ <Box sx={{ display: 'flex', width: '100%', height: '100vh' }}>
1071
+ <Sidebar>
1072
+ <DiagramControls
1073
+ onAddEntity={handleAddEntity}
1074
+ onAddMessage={handleAddMessage}
1075
+ onAddAltFragment={handleAddAltFragment}
1076
+ onUndo={handleUndo}
1077
+ onRedo={handleRedo}
1078
+ canUndo={historyIndex > 0}
1079
+ canRedo={historyIndex < history.length - 1}
1080
+ onLoadTemplate={loadTemplateData}
1081
+ />
1082
+ </Sidebar>
1083
+ <Box sx={{ flex: 1, height: '100%', position: 'relative' }}>
1084
+ <div
1085
+ ref={diagramContainerRef}
1086
+ className={`diagram-container ${isFullscreen ? 'fullscreen' : ''}`}
1087
+ style={{
1088
+ width: '100%',
1089
+ height: '100%',
1090
+ border: '1px solid #333',
1091
+ position: 'relative',
1092
+ backgroundColor: '#1a1a1a',
1093
+ color: '#ffffff',
1094
+ }}
1095
+ >
1096
+ <ReactFlow<Node, Edge>
1097
+ nodes={nodes}
1098
+ edges={edges}
1099
+ onNodesChange={onNodesChangeLockedY}
1100
+ onEdgesChange={onEdgesChange}
1101
+ onConnect={onConnect}
1102
+ nodeTypes={sequenceNodeTypes}
1103
+ edgeTypes={sequenceEdgeTypes}
1104
+ fitView
1105
+ attributionPosition="bottom-left"
1106
+ connectOnClick={false}
1107
+ onNodeClick={onNodeClick}
1108
+ onNodeDoubleClick={onNodeDoubleClick}
1109
+ onEdgeDoubleClick={onEdgeDoubleClick}
1110
+ style={{
1111
+ backgroundColor: '#1a1a1a',
1112
+ }}
1113
+ >
1114
+ <Background
1115
+ color="#333"
1116
+ variant={BackgroundVariant.Dots}
1117
+ gap={16}
1118
+ />
1119
+ </ReactFlow>
1120
+
1121
+ {/* Components outside ReactFlow */}
1122
+ <DiagramPanel
1123
+ historyIndex={historyIndex}
1124
+ historyLength={history.length}
1125
+ onUndo={handleUndo}
1126
+ onRedo={handleRedo}
1127
+ onClear={() => {
1128
+ const clearedState: SequenceHistoryEntry = { nodes: [], edges: [] };
1129
+ const newHistory = history.slice(0, historyIndex + 1);
1130
+ newHistory.push(clearedState);
1131
+ setNodes([]);
1132
+ setEdges([]);
1133
+ setHistory(newHistory);
1134
+ setHistoryIndex(newHistory.length - 1);
1135
+ }}
1136
+ onImport={() => { }}
1137
+ isSettingsOpen={false}
1138
+ onToggleSettings={() => { }}
1139
+ />
1140
+
1141
+ <AiButton />
1142
+
1143
+ <MiniMapCommon />
1144
+
1145
+ {/* Fragment settings panel */}
1146
+ {showFragmentSettings && (
1147
+ <FragmentSettings
1148
+ fragmentId={selectedFragmentId}
1149
+ width={fragmentSettings.width}
1150
+ height={fragmentSettings.height}
1151
+ onWidthChange={handleFragmentWidthChange}
1152
+ onHeightChange={handleFragmentHeightChange}
1153
+ onClose={closeFragmentSettings}
1154
+ />
1155
+ )}
1156
+
1157
+ {/* Entity settings panel */}
1158
+ {showEntitySettings && selectedEntityId && (
1159
+ <EntitySettings
1160
+ entityId={selectedEntityId}
1161
+ data={
1162
+ (nodes.find((node) =>
1163
+ node.id === selectedEntityId && node.type === 'sequenceEntity'
1164
+ )?.data as SequenceEntityData) || {
1165
+ label: '',
1166
+ color: '#61dafb',
1167
+ backgroundColor: '#2a2a2a',
1168
+ lifelineLength: 500
1169
+ }
1170
+ }
1171
+ onUpdate={updateSelectedEntity}
1172
+ onClose={closeEntitySettings}
1173
+ />
1174
+ )}
1175
+
1176
+ {/* Label editing overlay */}
1177
+ {(editingNode || editingEdge) && (
1178
+ <Box
1179
+ sx={{
1180
+ position: 'absolute',
1181
+ zIndex: 10,
1182
+ top: 10,
1183
+ left: '50%',
1184
+ transform: 'translateX(-50%)',
1185
+ bgcolor: '#242424',
1186
+ border: '1px solid #333',
1187
+ color: '#fff',
1188
+ p: 2,
1189
+ borderRadius: 1,
1190
+ boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)',
1191
+ minWidth: 320,
1192
+ '& .MuiTextField-root': {
1193
+ '& .MuiInputLabel-root': {
1194
+ color: '#999',
1195
+ },
1196
+ '& .MuiOutlinedInput-root': {
1197
+ color: '#fff',
1198
+ '& fieldset': {
1199
+ borderColor: '#444',
1200
+ },
1201
+ '&:hover fieldset': {
1202
+ borderColor: '#61dafb',
1203
+ },
1204
+ '&.Mui-focused fieldset': {
1205
+ borderColor: '#61dafb',
1206
+ },
1207
+ },
1208
+ },
1209
+ '& .MuiButton-contained': {
1210
+ bgcolor: '#61dafb',
1211
+ color: '#000',
1212
+ '&:hover': {
1213
+ bgcolor: '#4db6d6',
1214
+ },
1215
+ },
1216
+ '& .MuiButton-outlined': {
1217
+ borderColor: '#333',
1218
+ color: '#fff',
1219
+ '&:hover': {
1220
+ borderColor: '#61dafb',
1221
+ bgcolor: 'rgba(97, 218, 251, 0.1)',
1222
+ },
1223
+ },
1224
+ '& .MuiIconButton-root': {
1225
+ color: '#999',
1226
+ '&:hover': {
1227
+ color: '#fff',
1228
+ bgcolor: 'rgba(255, 255, 255, 0.1)',
1229
+ },
1230
+ },
1231
+ }}
1232
+ >
1233
+ <Typography sx={{ mb: 1, fontWeight: 'bold', color: '#fff' }}>
1234
+ {editingType === 'node'
1235
+ ? t('sequenceFlow.editLabels.entityLabel')
1236
+ : editingType === 'edge'
1237
+ ? t('sequenceFlow.editLabels.messageLabel')
1238
+ : t('sequenceFlow.editLabels.editFragment')}
1239
+ </Typography>
1240
+ {editingType === 'fragment' ? (
1241
+ <>
1242
+ <Box display="flex" alignItems="center" gap={2} mb={2}>
1243
+ <TextField
1244
+ type="text"
1245
+ value={editingLabel}
1246
+ onChange={handleLabelChange}
1247
+ onKeyDown={handleKeyDown}
1248
+ autoFocus
1249
+ size="small"
1250
+ sx={{ width: 200 }}
1251
+ label={t('fragmentSettings.fragmentName')}
1252
+ />
1253
+ </Box>
1254
+ {/* Conditions editing */}
1255
+ <Box mb={2}>
1256
+ <Typography
1257
+ variant="body2"
1258
+ fontWeight="bold"
1259
+ mb={0.5}
1260
+ sx={{ color: '#61dafb' }}
1261
+ >
1262
+ {t('fragmentSettings.conditions')}
1263
+ </Typography>
1264
+ {editingConditions.map((cond, idx) => (
1265
+ <Box
1266
+ key={idx}
1267
+ display="flex"
1268
+ alignItems="center"
1269
+ mb={1}
1270
+ >
1271
+ <TextField
1272
+ value={cond}
1273
+ onChange={(e) =>
1274
+ handleConditionChange(idx, e.target.value)
1275
+ }
1276
+ size="small"
1277
+ fullWidth
1278
+ sx={{ mr: 1 }}
1279
+ />
1280
+ <IconButton
1281
+ onClick={() => handleRemoveCondition(idx)}
1282
+ size="small"
1283
+ >
1284
+ <CloseIcon fontSize="small" />
1285
+ </IconButton>
1286
+ </Box>
1287
+ ))}
1288
+ <Button
1289
+ onClick={handleAddCondition}
1290
+ size="small"
1291
+ variant="outlined"
1292
+ >
1293
+ {t('fragmentSettings.addCondition')}
1294
+ </Button>
1295
+ </Box>
1296
+ <Box display="flex" gap={2}>
1297
+ <Button
1298
+ variant="contained"
1299
+ size="small"
1300
+ onClick={saveLabel}
1301
+ sx={{ textTransform: 'none' }}
1302
+ >
1303
+ {t('common.save')}
1304
+ </Button>
1305
+ <Button
1306
+ variant="outlined"
1307
+ size="small"
1308
+ onClick={cancelEditing}
1309
+ sx={{ textTransform: 'none' }}
1310
+ >
1311
+ {t('common.cancel')}
1312
+ </Button>
1313
+ </Box>
1314
+ </>
1315
+ ) : (
1316
+ <Box display="flex" alignItems="center" gap={2}>
1317
+ <TextField
1318
+ type="text"
1319
+ value={editingLabel}
1320
+ onChange={handleLabelChange}
1321
+ onKeyDown={handleKeyDown}
1322
+ autoFocus
1323
+ size="small"
1324
+ sx={{ width: 200 }}
1325
+ />
1326
+ <Button
1327
+ variant="contained"
1328
+ size="small"
1329
+ onClick={saveLabel}
1330
+ sx={{ textTransform: 'none' }}
1331
+ >
1332
+ {t('common.save')}
1333
+ </Button>
1334
+ <Button
1335
+ variant="outlined"
1336
+ size="small"
1337
+ onClick={cancelEditing}
1338
+ sx={{ textTransform: 'none' }}
1339
+ >
1340
+ {t('common.cancel')}
1341
+ </Button>
1342
+ </Box>
1343
+ )}
1344
+ </Box>
1345
+ )}
1346
+
1347
+ {/* Add Message Dialog */}
1348
+ <AddMessageDialog
1349
+ open={showMessageDialog}
1350
+ onClose={() => setShowMessageDialog(false)}
1351
+ onAddMessage={handleAddCustomMessage}
1352
+ entities={sequenceEntities()}
1353
+ />
1354
+ </div>
1355
+ </Box>
1356
+ </Box>
1357
+ </>
1358
+ );
1359
+ };
1360
+
1361
+ export default SequenceDiagramFlow;