@elyx-code/editor-ui 0.0.2

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 (452) hide show
  1. package/README.md +2 -0
  2. package/package.json +109 -0
  3. package/src/App.tsx +31 -0
  4. package/src/Router.tsx +115 -0
  5. package/src/__mocks__/defaultModuleMock.ts +1 -0
  6. package/src/__mocks__/fileMock.ts +1 -0
  7. package/src/__mocks__/styleMock.ts +1 -0
  8. package/src/assets/Clock-11.1s-18px.svg +16 -0
  9. package/src/assets/Clock-11.1s-28px.svg +16 -0
  10. package/src/assets/authentication.svg +1 -0
  11. package/src/assets/canvas-backdrop-0.png +0 -0
  12. package/src/assets/canvas-backdrop-1.png +0 -0
  13. package/src/assets/canvas-backdrop-2.png +0 -0
  14. package/src/assets/canvas-backdrop-3.png +0 -0
  15. package/src/assets/canvas-backdrop-4.png +0 -0
  16. package/src/assets/canvas-backdrop-5.png +0 -0
  17. package/src/assets/canvas-backdrop.png +0 -0
  18. package/src/assets/checkmark-animation.gif +0 -0
  19. package/src/assets/checkmark-animation.mp4 +0 -0
  20. package/src/assets/code-formatting/format-black.svg +6 -0
  21. package/src/assets/code-formatting/format-dark-grey.svg +6 -0
  22. package/src/assets/code-formatting/format-light-grey.svg +6 -0
  23. package/src/assets/code-formatting/format-white.svg +6 -0
  24. package/src/assets/code-formatting/inline-black.svg +5 -0
  25. package/src/assets/code-formatting/inline-dark-grey.svg +5 -0
  26. package/src/assets/code-formatting/inline-light-grey.svg +5 -0
  27. package/src/assets/code-formatting/inline-white.svg +5 -0
  28. package/src/assets/contained-logo-full-word.png +0 -0
  29. package/src/assets/cron-job-color.png +0 -0
  30. package/src/assets/cron-job.png +0 -0
  31. package/src/assets/database-table-color.png +0 -0
  32. package/src/assets/database-table.png +0 -0
  33. package/src/assets/datatype-icons/black/any.svg +1 -0
  34. package/src/assets/datatype-icons/black/binary.svg +1 -0
  35. package/src/assets/datatype-icons/black/boolean.svg +3 -0
  36. package/src/assets/datatype-icons/black/date-time.svg +3 -0
  37. package/src/assets/datatype-icons/black/definition-entity.svg +6 -0
  38. package/src/assets/datatype-icons/black/key-file.svg +1 -0
  39. package/src/assets/datatype-icons/black/list.svg +3 -0
  40. package/src/assets/datatype-icons/black/null.svg +3 -0
  41. package/src/assets/datatype-icons/black/number.svg +13 -0
  42. package/src/assets/datatype-icons/black/project.svg +12 -0
  43. package/src/assets/datatype-icons/black/sql-program.svg +2 -0
  44. package/src/assets/datatype-icons/black/text.svg +3 -0
  45. package/src/assets/datatype-icons/black/unknown.svg +3 -0
  46. package/src/assets/datatype-icons/black/uuid.svg +4 -0
  47. package/src/assets/datatype-icons/black/void.svg +1 -0
  48. package/src/assets/datatype-icons/dark-grey/any.svg +1 -0
  49. package/src/assets/datatype-icons/dark-grey/boolean.svg +3 -0
  50. package/src/assets/datatype-icons/dark-grey/date-time.svg +3 -0
  51. package/src/assets/datatype-icons/dark-grey/definition-entity.svg +6 -0
  52. package/src/assets/datatype-icons/dark-grey/list.svg +3 -0
  53. package/src/assets/datatype-icons/dark-grey/null.svg +3 -0
  54. package/src/assets/datatype-icons/dark-grey/number.svg +13 -0
  55. package/src/assets/datatype-icons/dark-grey/project.svg +12 -0
  56. package/src/assets/datatype-icons/dark-grey/sql-program.svg +2 -0
  57. package/src/assets/datatype-icons/dark-grey/text.svg +3 -0
  58. package/src/assets/datatype-icons/dark-grey/unknown.svg +3 -0
  59. package/src/assets/datatype-icons/dark-grey/uuid.svg +4 -0
  60. package/src/assets/datatype-icons/dark-grey/void.svg +1 -0
  61. package/src/assets/datatype-icons/light-grey/any.svg +1 -0
  62. package/src/assets/datatype-icons/light-grey/boolean.svg +3 -0
  63. package/src/assets/datatype-icons/light-grey/date-time.svg +3 -0
  64. package/src/assets/datatype-icons/light-grey/definition-entity.svg +6 -0
  65. package/src/assets/datatype-icons/light-grey/list.svg +3 -0
  66. package/src/assets/datatype-icons/light-grey/null.svg +3 -0
  67. package/src/assets/datatype-icons/light-grey/number.svg +13 -0
  68. package/src/assets/datatype-icons/light-grey/project.svg +12 -0
  69. package/src/assets/datatype-icons/light-grey/sql-program.svg +2 -0
  70. package/src/assets/datatype-icons/light-grey/text.svg +3 -0
  71. package/src/assets/datatype-icons/light-grey/unknown.svg +3 -0
  72. package/src/assets/datatype-icons/light-grey/uuid.svg +4 -0
  73. package/src/assets/datatype-icons/light-grey/void.svg +1 -0
  74. package/src/assets/edit.png +0 -0
  75. package/src/assets/execution.svg +13 -0
  76. package/src/assets/favicon.svg +14 -0
  77. package/src/assets/file-search.svg +1 -0
  78. package/src/assets/http-endpoint.png +0 -0
  79. package/src/assets/image-input-placeholder.png +0 -0
  80. package/src/assets/logo-full-word-white.png +0 -0
  81. package/src/assets/logo-full-word.png +0 -0
  82. package/src/assets/password.svg +85 -0
  83. package/src/assets/pencil.png +0 -0
  84. package/src/assets/publish-project-rich-icon-2.svg +1 -0
  85. package/src/assets/publish-project-rich-icon.svg +1 -0
  86. package/src/assets/relational-database.png +0 -0
  87. package/src/assets/resources.svg +3 -0
  88. package/src/assets/resume-icon-14px.png +0 -0
  89. package/src/assets/server.png +0 -0
  90. package/src/assets/small-status/checkmark.svg +4 -0
  91. package/src/assets/small-status/error.svg +4 -0
  92. package/src/assets/small-status/loading.svg +4 -0
  93. package/src/assets/small-status/skipped.svg +11 -0
  94. package/src/assets/sql-connection-config.svg +1 -0
  95. package/src/assets/sql-row-transformer.svg +1 -0
  96. package/src/assets/ssl-certificate-config.svg +1 -0
  97. package/src/assets/sync.svg +1 -0
  98. package/src/assets/testing-logic-icon.svg +1 -0
  99. package/src/assets/versions.svg +25 -0
  100. package/src/assets/visual-programming-icon.svg +1 -0
  101. package/src/assets/warning-sign-24px.png +0 -0
  102. package/src/auth/index.ts +318 -0
  103. package/src/components/DialogLoader.tsx +94 -0
  104. package/src/components/EntityDialogHeader.tsx +110 -0
  105. package/src/components/EntityDialogSectionHeader.tsx +214 -0
  106. package/src/components/GalleryAddExternalIntegrationInfoDialog.tsx +87 -0
  107. package/src/components/GenerateProjectStartingLogicPromptDialog.tsx +281 -0
  108. package/src/components/LegacyRouteRedirector.tsx +55 -0
  109. package/src/components/ProPlanChip.tsx +23 -0
  110. package/src/components/ReportBugDialog.tsx +412 -0
  111. package/src/components/RequestIntegrationAccessDialog.tsx +261 -0
  112. package/src/components/UseTemplateProjectDialog.tsx +193 -0
  113. package/src/components/WorkspaceLayout.tsx +152 -0
  114. package/src/components/animated-svg/AnimatedCheckmark.tsx +41 -0
  115. package/src/components/animated-svg/AnimatedCrossmark.tsx +51 -0
  116. package/src/components/animated-svg/AnimatedEmailSending.tsx +38 -0
  117. package/src/components/animated-svg/AnimatedLoading.tsx +72 -0
  118. package/src/components/animated-svg/animated-svg.css +239 -0
  119. package/src/components/canvas/Canvas.tsx +16 -0
  120. package/src/components/canvas/CreateEntityMenu.tsx +2020 -0
  121. package/src/components/canvas/canvas.css +10 -0
  122. package/src/components/canvas/create-entity-menu.css +579 -0
  123. package/src/components/canvas-search/CanvasSearch.tsx +501 -0
  124. package/src/components/canvas-search/canvas-search.css +126 -0
  125. package/src/components/canvas-settings-menu/CanvasSettingsMenuButton.tsx +515 -0
  126. package/src/components/canvas-settings-menu/canvas-settings-menu.css +96 -0
  127. package/src/components/circular-image-upload/CircularImageUpload.tsx +113 -0
  128. package/src/components/circular-image-upload/circular-image-upload.css +69 -0
  129. package/src/components/costs/CostsDialog.tsx +459 -0
  130. package/src/components/data-type/DataTypeBuilder.tsx +3127 -0
  131. package/src/components/data-type/data-type-builder.css +45 -0
  132. package/src/components/dialogs/BetaAcknowledgeDialog.tsx +43 -0
  133. package/src/components/dialogs/ComplexDataDialog.tsx +458 -0
  134. package/src/components/dialogs/CronBuilderDialog.tsx +2145 -0
  135. package/src/components/dialogs/ExternalIntegrationConnections.tsx +565 -0
  136. package/src/components/dialogs/JsonEditorDialog.tsx +1392 -0
  137. package/src/components/dialogs/StringEditorDialog.tsx +268 -0
  138. package/src/components/dialogs/argument-declaration/ArgumentDeclaration.tsx +1167 -0
  139. package/src/components/dialogs/argument-declaration/ArgumentDeclarationDialogContent.tsx +128 -0
  140. package/src/components/dialogs/beta-dialog.css +165 -0
  141. package/src/components/dialogs/condition/Condition.tsx +431 -0
  142. package/src/components/dialogs/condition/ConditionDialogContent.tsx +126 -0
  143. package/src/components/dialogs/definition-entity/DefinitionEntityDialogContent.tsx +973 -0
  144. package/src/components/dialogs/function-call/FunctionCall.tsx +442 -0
  145. package/src/components/dialogs/function-call/FunctionCallDialogContent.tsx +126 -0
  146. package/src/components/dialogs/function-declaration/FunctionDeclaration.tsx +926 -0
  147. package/src/components/dialogs/function-declaration/FunctionDeclarationDialogContent.tsx +124 -0
  148. package/src/components/dialogs/generating-project-starting-logic-overlay/GeneratingProjectStartingLogicOverlay.tsx +176 -0
  149. package/src/components/dialogs/generating-project-starting-logic-overlay/generating-project-starting-logic-overlay.css +13 -0
  150. package/src/components/dialogs/global-event/GlobalEvent.tsx +475 -0
  151. package/src/components/dialogs/global-event/GlobalEventDialogContent.tsx +126 -0
  152. package/src/components/dialogs/help/HelpDialog.tsx +217 -0
  153. package/src/components/dialogs/help/HelpDilalogHomeContent.tsx +178 -0
  154. package/src/components/dialogs/help/help-dialog.css +116 -0
  155. package/src/components/dialogs/help/help-icon/HelpIconButton.tsx +41 -0
  156. package/src/components/dialogs/help/help-icon/help-icon.css +9 -0
  157. package/src/components/dialogs/input-map/InputMap.tsx +635 -0
  158. package/src/components/dialogs/input-map/InputMapDialogContent.tsx +126 -0
  159. package/src/components/dialogs/json-editor-dialog.css +4 -0
  160. package/src/components/dialogs/loop/Loop.tsx +650 -0
  161. package/src/components/dialogs/loop/LoopDialogContent.tsx +122 -0
  162. package/src/components/dialogs/operation/Operation.tsx +440 -0
  163. package/src/components/dialogs/operation/OperationDialogContent.tsx +126 -0
  164. package/src/components/dialogs/output-map/OutputMap.tsx +536 -0
  165. package/src/components/dialogs/output-map/OutputMapDialogContent.tsx +126 -0
  166. package/src/components/dialogs/property/Property.tsx +1490 -0
  167. package/src/components/dialogs/property/PropertyDialogContent.tsx +106 -0
  168. package/src/components/dialogs/search-statement/ColumnSelector.tsx +334 -0
  169. package/src/components/dialogs/search-statement/ConditionBuilder.tsx +750 -0
  170. package/src/components/dialogs/search-statement/DataAggregationSection.tsx +621 -0
  171. package/src/components/dialogs/search-statement/DataSourceSelection.tsx +734 -0
  172. package/src/components/dialogs/search-statement/EntityMetadataSection.tsx +135 -0
  173. package/src/components/dialogs/search-statement/FilterConditionsSection.tsx +151 -0
  174. package/src/components/dialogs/search-statement/InlineInputMap.tsx +153 -0
  175. package/src/components/dialogs/search-statement/LiteralValue.tsx +616 -0
  176. package/src/components/dialogs/search-statement/MainSourceAndInputsSection.tsx +271 -0
  177. package/src/components/dialogs/search-statement/NestedSearchStatementBuilder.tsx +170 -0
  178. package/src/components/dialogs/search-statement/OutputFormatSection.tsx +1779 -0
  179. package/src/components/dialogs/search-statement/ResultsSection.tsx +344 -0
  180. package/src/components/dialogs/search-statement/SearchStatementBuilder.tsx +251 -0
  181. package/src/components/dialogs/search-statement/SearchStatementDialogContent.tsx +398 -0
  182. package/src/components/dialogs/search-statement/ValueSelector.tsx +766 -0
  183. package/src/components/dialogs/search-statement/search-statement-context.tsx +1630 -0
  184. package/src/components/dialogs/search-statement/search-statement-dialog.css +56 -0
  185. package/src/components/dialogs/search-statement/test.sql +111 -0
  186. package/src/components/dialogs/value-descriptor/ValueDescriptor.tsx +824 -0
  187. package/src/components/dialogs/value-descriptor/ValueDescriptorDialogContent.tsx +124 -0
  188. package/src/components/dialogs/variable-declaration/VariableDeclaration.tsx +836 -0
  189. package/src/components/dialogs/variable-declaration/VariableDeclarationDialogContent.tsx +106 -0
  190. package/src/components/dialogs/variable-instance/VariableInstance.tsx +443 -0
  191. package/src/components/dialogs/variable-instance/VariableInstanceDialogContent.tsx +124 -0
  192. package/src/components/draggable-entity-card/ArgumentDeclaration.tsx +736 -0
  193. package/src/components/draggable-entity-card/CollapseEntityButton.tsx +170 -0
  194. package/src/components/draggable-entity-card/ConditionCard.tsx +1062 -0
  195. package/src/components/draggable-entity-card/ConnectionDeleteButton.tsx +309 -0
  196. package/src/components/draggable-entity-card/DataTypeIcon.tsx +624 -0
  197. package/src/components/draggable-entity-card/DraggableEntityCard.tsx +617 -0
  198. package/src/components/draggable-entity-card/ErrorMapProperty.tsx +464 -0
  199. package/src/components/draggable-entity-card/EventCard.tsx +700 -0
  200. package/src/components/draggable-entity-card/ExecutionInProgressValue.tsx +327 -0
  201. package/src/components/draggable-entity-card/FunctionDeclarationCard.tsx +819 -0
  202. package/src/components/draggable-entity-card/InputMapProperty.tsx +1067 -0
  203. package/src/components/draggable-entity-card/InternalCall.tsx +978 -0
  204. package/src/components/draggable-entity-card/InternalCallExecutionNode.tsx +643 -0
  205. package/src/components/draggable-entity-card/LogicScopeCallerNode.tsx +262 -0
  206. package/src/components/draggable-entity-card/LoopCard.tsx +791 -0
  207. package/src/components/draggable-entity-card/MainValueInput.tsx +523 -0
  208. package/src/components/draggable-entity-card/MainValueOutput.tsx +458 -0
  209. package/src/components/draggable-entity-card/MethodDeclaration.tsx +1088 -0
  210. package/src/components/draggable-entity-card/NestedCondition.tsx +1025 -0
  211. package/src/components/draggable-entity-card/OutputMapProperty.tsx +843 -0
  212. package/src/components/draggable-entity-card/PassthroughEntityCard.tsx +1247 -0
  213. package/src/components/draggable-entity-card/ReturnedError.tsx +549 -0
  214. package/src/components/draggable-entity-card/SmallSuccessFailureNodes.tsx +523 -0
  215. package/src/components/draggable-entity-card/SuccessFailureNodes.tsx +509 -0
  216. package/src/components/draggable-entity-card/TestEntityButton.tsx +946 -0
  217. package/src/components/draggable-entity-card/TestMenu.tsx +523 -0
  218. package/src/components/draggable-entity-card/TestMenuValidationDropdown.tsx +84 -0
  219. package/src/components/draggable-entity-card/UnreachableMarker.tsx +114 -0
  220. package/src/components/draggable-entity-card/VariableCard.tsx +1577 -0
  221. package/src/components/draggable-entity-card/VariableScopeMarker.tsx +117 -0
  222. package/src/components/draggable-entity-card/collapse-entity-button.css +44 -0
  223. package/src/components/draggable-entity-card/definition-entity/DefinitionEntityCard.tsx +1181 -0
  224. package/src/components/draggable-entity-card/definition-entity/DefinitionEntityIcon.tsx +36 -0
  225. package/src/components/draggable-entity-card/definition-entity/DefinitionEntityProperty.tsx +478 -0
  226. package/src/components/draggable-entity-card/definition-entity/DynamicFooterActions.tsx +112 -0
  227. package/src/components/draggable-entity-card/definition-entity/actions/external-integration-connection/ExportCredentialsFooterAction.tsx +461 -0
  228. package/src/components/draggable-entity-card/definition-entity/actions/external-integration-connection/RestablishConnectionFooterAction.tsx +199 -0
  229. package/src/components/draggable-entity-card/definition-entity/actions/external-integration-connection/restablish-connection-footer-action.css +85 -0
  230. package/src/components/draggable-entity-card/definition-entity/actions/google-drive/GoogleDriveFilePickerAPIFooterAction.tsx +277 -0
  231. package/src/components/draggable-entity-card/definition-entity/actions/google-drive/google-drive-file-picker-api-footer-action.css +107 -0
  232. package/src/components/draggable-entity-card/definition-entity/actions/persisted-entity/DatabaseFooterAction.tsx +452 -0
  233. package/src/components/draggable-entity-card/definition-entity/actions/persisted-entity/database-footer-action.css +86 -0
  234. package/src/components/draggable-entity-card/definition-entity/definition-entity-card.css +17 -0
  235. package/src/components/draggable-entity-card/draggable-entity-card.css +1140 -0
  236. package/src/components/draggable-entity-card/entity-locked-icon/EntityLockedIcon.tsx +133 -0
  237. package/src/components/draggable-entity-card/entity-locked-icon/entity-locked.css +8 -0
  238. package/src/components/draggable-entity-card/expand-properties-icon-button/ExpandPropertiesIconButton.tsx +84 -0
  239. package/src/components/draggable-entity-card/expand-properties-icon-button/expand-properties-icon-button.css +21 -0
  240. package/src/components/draggable-entity-card/implement-entity-icon/ImplementEntityIcon.tsx +74 -0
  241. package/src/components/draggable-entity-card/implement-entity-icon/implement-entity-icon.css +13 -0
  242. package/src/components/draggable-entity-card/logic-error/LogicErrorIconMenu.tsx +424 -0
  243. package/src/components/draggable-entity-card/logic-error/logic-error.css +23 -0
  244. package/src/components/draggable-entity-card/new-card-input-button/NewCardInputButton.tsx +193 -0
  245. package/src/components/draggable-entity-card/new-card-input-button/NewDynamicInputButton.tsx +214 -0
  246. package/src/components/draggable-entity-card/new-card-input-button/new-card-input-button.css +71 -0
  247. package/src/components/draggable-entity-card/new-card-output-button/NewCardOutputButton.tsx +192 -0
  248. package/src/components/draggable-entity-card/new-card-output-button/new-card-output-button.css +71 -0
  249. package/src/components/draggable-entity-card/termination-statement/TerminationStatementCard.tsx +1543 -0
  250. package/src/components/draggable-entity-card/termination-statement/termination-statement-card.css +17 -0
  251. package/src/components/draggable-entity-card/test-entity-button.css +55 -0
  252. package/src/components/draggable-entity-card/test-menu.css +181 -0
  253. package/src/components/draggable-entity-card/unreachable-marker.css +43 -0
  254. package/src/components/draggable-entity-card/variable-scope-marker.css +22 -0
  255. package/src/components/dynamic-value/DynamicValue.tsx +2395 -0
  256. package/src/components/dynamic-value/DynamicValueEntry.tsx +1957 -0
  257. package/src/components/dynamic-value/dynamic-value.css +230 -0
  258. package/src/components/editor/ElyxMonacoEditor.tsx +38 -0
  259. package/src/components/entity-error/EntityErrorListItem.tsx +47 -0
  260. package/src/components/entity-error/entity-error.css +198 -0
  261. package/src/components/entity-icon/EntityIcon.tsx +292 -0
  262. package/src/components/entity-icon/entity-icon.css +39 -0
  263. package/src/components/gallery-card/CreateNewProject.tsx +222 -0
  264. package/src/components/gallery-card/GalleryCard.tsx +171 -0
  265. package/src/components/gallery-card/MarketplaceCard.tsx +87 -0
  266. package/src/components/gallery-card/ProjectDuplicationCard.tsx +575 -0
  267. package/src/components/gallery-card/gallery-card.css +25 -0
  268. package/src/components/notifications/NotificationsIconButton.tsx +124 -0
  269. package/src/components/notifications/NotificationsPanel.tsx +385 -0
  270. package/src/components/notifications/notifications.css +189 -0
  271. package/src/components/online-users/LocalOnlineUsers.tsx +175 -0
  272. package/src/components/online-users/PageOnlineUsers.tsx +297 -0
  273. package/src/components/online-users/online-users.css +72 -0
  274. package/src/components/page-backdrop/PageBackdrop.tsx +8 -0
  275. package/src/components/page-backdrop/page-backdrop.css +7 -0
  276. package/src/components/project-configuration/DeleteProjectConfirmationDialog.tsx +134 -0
  277. package/src/components/project-configuration/ProjectConfigurationDialog.tsx +972 -0
  278. package/src/components/project-configuration/ProjectDataForm.tsx +121 -0
  279. package/src/components/project-configuration/UnpublishProjectConfirmationDialog.tsx +162 -0
  280. package/src/components/project-configuration/project-configuration-content.css +209 -0
  281. package/src/components/project-name/ProjectName.tsx +2025 -0
  282. package/src/components/project-name/project-name.css +599 -0
  283. package/src/components/publishing/Publication.tsx +133 -0
  284. package/src/components/publishing/history/PublicationHistoryContent.tsx +414 -0
  285. package/src/components/publishing/history/PublicationHistoryDialog.tsx +234 -0
  286. package/src/components/publishing/preview/PublicationPreviewDialog.tsx +1158 -0
  287. package/src/components/publishing/preview/PublishingPriceForecast.tsx +160 -0
  288. package/src/components/publishing/preview/PublishingResourcesDetails.tsx +91 -0
  289. package/src/components/publishing/publication-sequence/PublishingSequenceContent.tsx +375 -0
  290. package/src/components/publishing/publication-sequence/PublishingSequenceDialog.tsx +344 -0
  291. package/src/components/publishing/publishing-dialog.css +142 -0
  292. package/src/components/publishing/utils.ts +227 -0
  293. package/src/components/resources/ResourcesDialog.tsx +591 -0
  294. package/src/components/resources/UpgradeBanner.tsx +102 -0
  295. package/src/components/resources/codebase/CodebaseDetails.tsx +156 -0
  296. package/src/components/resources/cron-job/CronJobsList.tsx +532 -0
  297. package/src/components/resources/functions/FunctionsList.tsx +454 -0
  298. package/src/components/resources/http-api/HttpAPI.tsx +566 -0
  299. package/src/components/resources/http-api/HttpAPIClientModule.tsx +37 -0
  300. package/src/components/resources/logs/LogsViewer.tsx +768 -0
  301. package/src/components/resources/query.ts +74 -0
  302. package/src/components/resources/relational-database/DatabaseTable.tsx +905 -0
  303. package/src/components/resources/relational-database/RelationalDatabase.tsx +83 -0
  304. package/src/components/resources/relational-database/RelationalDatabaseSecrets.tsx +361 -0
  305. package/src/components/resources/resources-dialog.css +74 -0
  306. package/src/components/test-relational-database/DatabaseTable.tsx +913 -0
  307. package/src/components/test-relational-database/TestDatabaseDialogContent.tsx +670 -0
  308. package/src/components/test-relational-database/query.ts +74 -0
  309. package/src/components/toolbar/ToolBar.tsx +236 -0
  310. package/src/components/toolbar/toolbar.css +78 -0
  311. package/src/components/transaction-history/TransactionHistoryDialog.tsx +268 -0
  312. package/src/components/user/CurrentUserAvatar.tsx +65 -0
  313. package/src/components/user/UserChip.tsx +62 -0
  314. package/src/components/user/user.css +39 -0
  315. package/src/components/user-profile/ChangePasswordForm.tsx +67 -0
  316. package/src/components/user-profile/OwnUserProfileContent.tsx +665 -0
  317. package/src/components/user-profile/PublicUserProfileContent.tsx +99 -0
  318. package/src/components/user-profile/UserDataForm.tsx +75 -0
  319. package/src/components/user-profile/UserProfileDialog.tsx +110 -0
  320. package/src/components/user-profile/user-profile-content.css +25 -0
  321. package/src/config.ts +130 -0
  322. package/src/globals.d.ts +13 -0
  323. package/src/index.html +27 -0
  324. package/src/index.tsx +23 -0
  325. package/src/lib/badge/Badge.tsx +35 -0
  326. package/src/lib/badge/badge.css +32 -0
  327. package/src/lib/button/Button.tsx +129 -0
  328. package/src/lib/button/button.css +145 -0
  329. package/src/lib/canvas/canvas-undo-redo.ts +263 -0
  330. package/src/lib/canvas/defs.ts +170 -0
  331. package/src/lib/canvas/index.test.ts +189 -0
  332. package/src/lib/canvas/index.ts +6999 -0
  333. package/src/lib/canvas/utils.ts +59 -0
  334. package/src/lib/card/Card.tsx +62 -0
  335. package/src/lib/card/LoadingCard.tsx +82 -0
  336. package/src/lib/card/card.css +259 -0
  337. package/src/lib/chip/Chip.tsx +79 -0
  338. package/src/lib/chip/chip.css +0 -0
  339. package/src/lib/dialog/Dialog.tsx +122 -0
  340. package/src/lib/dialog/SmallDialog.tsx +61 -0
  341. package/src/lib/dialog/dialog.css +40 -0
  342. package/src/lib/display-data-structure/index.tsx +21 -0
  343. package/src/lib/dropdown/CanvasDropdownMenuCard.tsx +68 -0
  344. package/src/lib/dropdown/CanvasDropdownMenuCardOption.tsx +136 -0
  345. package/src/lib/dropdown/DropdownButton.tsx +104 -0
  346. package/src/lib/dropdown/DropdownMenuCard.tsx +324 -0
  347. package/src/lib/dropdown/DropdownMenuPopup.tsx +27 -0
  348. package/src/lib/dropdown/dropdown-button.css +76 -0
  349. package/src/lib/dropdown/dropdown-menu.css +151 -0
  350. package/src/lib/json-editor/RawJsonEditor.tsx +137 -0
  351. package/src/lib/json-editor/json-editor.css +35 -0
  352. package/src/lib/loader/Loader.tsx +120 -0
  353. package/src/lib/loader/loader.css +38 -0
  354. package/src/lib/pagination/Pagination.tsx +64 -0
  355. package/src/lib/popup/CanvasPopupBaseComponent.tsx +103 -0
  356. package/src/lib/popup/Popup.tsx +243 -0
  357. package/src/lib/popup/popup.css +16 -0
  358. package/src/lib/table/RowForm.tsx +301 -0
  359. package/src/lib/table/Table.tsx +1069 -0
  360. package/src/lib/table/table.css +249 -0
  361. package/src/lib/table/types.ts +108 -0
  362. package/src/lib/text-area/TextArea.tsx +183 -0
  363. package/src/lib/text-area/text-area.css +156 -0
  364. package/src/lib/text-field/TextField.tsx +218 -0
  365. package/src/lib/text-field/index.ts +8 -0
  366. package/src/lib/text-field/text-field.css +201 -0
  367. package/src/lib/tooltip/Tooltip.tsx +24 -0
  368. package/src/lib/tooltip/tooltip.css +17 -0
  369. package/src/localization/index.ts +47 -0
  370. package/src/main.css +343 -0
  371. package/src/pages/Auth.tsx +848 -0
  372. package/src/pages/Editor.tsx +883 -0
  373. package/src/pages/ErrorPage.tsx +179 -0
  374. package/src/pages/Gallery.tsx +1693 -0
  375. package/src/pages/NewPaymentMethodCallback.tsx +53 -0
  376. package/src/pages/NotFoundPage.tsx +126 -0
  377. package/src/pages/PricingPlans.tsx +155 -0
  378. package/src/pages/auth.css +304 -0
  379. package/src/pages/gallery.css +421 -0
  380. package/src/payments/index.ts +187 -0
  381. package/src/popup-notification/index.ts +90 -0
  382. package/src/services/database/index.ts +1 -0
  383. package/src/services/database/utils.ts +1301 -0
  384. package/src/services/editor/CanvasElement.tsx +2934 -0
  385. package/src/services/editor/CanvasElementConnectionDeleteButton.ts +204 -0
  386. package/src/services/editor/CanvasPopup.tsx +749 -0
  387. package/src/services/editor/EditorService.ts +8157 -0
  388. package/src/services/editor/area.ts +1312 -0
  389. package/src/services/editor/connections.ts +1019 -0
  390. package/src/services/editor/create/condition.ts +25 -0
  391. package/src/services/editor/create/definition-entity.ts +29 -0
  392. package/src/services/editor/create/function-call.ts +25 -0
  393. package/src/services/editor/create/global-event.ts +33 -0
  394. package/src/services/editor/create/loop.ts +25 -0
  395. package/src/services/editor/create/operation.ts +30 -0
  396. package/src/services/editor/create/utils.ts +140 -0
  397. package/src/services/editor/create/variable-declaration.ts +135 -0
  398. package/src/services/editor/create/variable-instance.ts +100 -0
  399. package/src/services/editor/editor-ui-extensions-context.ts +43 -0
  400. package/src/services/editor/entities-metadata.json +9310 -0
  401. package/src/services/editor/icons.ts +1093 -0
  402. package/src/services/editor/index.ts +1 -0
  403. package/src/services/editor/layout.ts +102 -0
  404. package/src/services/editor/modules/built-in-function-implementations/base.ts +14 -0
  405. package/src/services/editor/modules/built-in-function-implementations/create-persisted-entity/index.ts +56 -0
  406. package/src/services/editor/modules/built-in-function-implementations/delete-persisted-entity/index.ts +55 -0
  407. package/src/services/editor/modules/built-in-function-implementations/index.ts +4 -0
  408. package/src/services/editor/modules/built-in-function-implementations/update-persisted-entity/index.ts +56 -0
  409. package/src/services/editor/modules/operations-implementations/external-integrations/google-drive/get-files.ts +183 -0
  410. package/src/services/editor/modules/operations-implementations/external-integrations/google-drive/list-drives.ts +124 -0
  411. package/src/services/editor/modules/operations-implementations/external-integrations/google-drive/list-root-folders.ts +125 -0
  412. package/src/services/editor/modules/operations-implementations/external-integrations/google-drive/smart-fetch-document.ts +702 -0
  413. package/src/services/editor/modules/operations-implementations/external-integrations/google-drive/upload-document.ts +535 -0
  414. package/src/services/editor/modules/operations-implementations/external-integrations/google-gemini/generate-content.ts +193 -0
  415. package/src/services/editor/modules/operations-implementations/external-integrations/google-mail/get-emails.ts +586 -0
  416. package/src/services/editor/modules/operations-implementations/external-integrations/google-mail/send-email.ts +386 -0
  417. package/src/services/editor/modules/operations-implementations/external-integrations/index.ts +12 -0
  418. package/src/services/editor/modules/operations-implementations/external-integrations/slack/channels.ts +240 -0
  419. package/src/services/editor/modules/operations-implementations/external-integrations/slack/messages.ts +210 -0
  420. package/src/services/editor/modules/operations-implementations/external-integrations/slack/replies.ts +200 -0
  421. package/src/services/editor/modules/operations-implementations/external-integrations/slack/send-message.ts +177 -0
  422. package/src/services/editor/modules/operations-implementations/index.ts +1 -0
  423. package/src/services/editor/modules/search-node-implementation/index.ts +42 -0
  424. package/src/services/editor/modules/sql-migrations-generation.tsx +1054 -0
  425. package/src/services/editor/publication/publication.ts +578 -0
  426. package/src/services/editor/ui.ts +1348 -0
  427. package/src/services/editor/utils.ts +5868 -0
  428. package/src/services/editor/value-store.ts +619 -0
  429. package/src/services/execution/built-in-function-implementations.ts +422 -0
  430. package/src/services/execution/index.ts +4747 -0
  431. package/src/services/execution/logic.ts +121 -0
  432. package/src/services/execution/test-instance.tsx +2296 -0
  433. package/src/services/execution/utils.ts +33 -0
  434. package/src/services/execution/value-resolution.test.ts +424 -0
  435. package/src/services/execution/value-resolution.ts +4087 -0
  436. package/src/services/integrations/ExternalIntegrationsService.ts +439 -0
  437. package/src/services/integrations/api.ts +175 -0
  438. package/src/services/local-relational-database/idb_helper.ts +66 -0
  439. package/src/services/local-relational-database/index.ts +3308 -0
  440. package/src/services/local-relational-database/utils.ts +403 -0
  441. package/src/services/notifications/index.ts +525 -0
  442. package/src/services/user/index.ts +144 -0
  443. package/src/setupTests.ts +1 -0
  444. package/src/socket/socket.ts +248 -0
  445. package/src/socket/utils.ts +10 -0
  446. package/src/store/workspace.ts +12 -0
  447. package/src/theme.ts +19 -0
  448. package/src/utils/DOM.ts +39 -0
  449. package/src/utils/date.ts +169 -0
  450. package/src/utils/index.ts +158 -0
  451. package/src/utils/react.tsx +679 -0
  452. package/src/utils/testing.ts +103 -0
@@ -0,0 +1,1312 @@
1
+ import {
2
+ CALLABLE_TYPES,
3
+ CALLER_TYPES,
4
+ ChangeSet,
5
+ DraggablePassThroughCallableEntity,
6
+ ENTITY_WITH_LOGIC_SCOPE_TYPES,
7
+ ENTRY_POINT_TYPES,
8
+ EntityType,
9
+ VARIABLE_TYPES,
10
+ getRelatedCanvasElementsOnTheLeft,
11
+ } from '@elyx-code/project-logic-tree';
12
+ import {
13
+ DraggableCallableEntityState,
14
+ DraggableCallerEntityState,
15
+ CanvasEntityState,
16
+ DefinitionEntityState,
17
+ EntryPointEntityState,
18
+ ProjectState,
19
+ VariableDeclarationState,
20
+ } from '@elyx-code/project-logic-tree';
21
+ import {
22
+ checkIsBranchDependentButNotDirectlyOnBranch,
23
+ checkIsBranchDependentOnBranch,
24
+ filterOutDuplicateEntities,
25
+ getCalls,
26
+ getCommonChildren,
27
+ getParentCanvasEntity,
28
+ getRelatedCanvasElementsOnTheRight,
29
+ } from '@elyx-code/project-logic-tree';
30
+ import {
31
+ EntityWithLogicScopeState,
32
+ VariableState,
33
+ } from '@elyx-code/project-logic-tree';
34
+ import {
35
+ calculateCardSize,
36
+ CANVAS_BASE_X,
37
+ CANVAS_BASE_Y,
38
+ CANVAS_CARD_HEADER_CENTER_HEIGHT,
39
+ CANVAS_CARD_WIDTH,
40
+ CANVAS_HORIZONTAL_BUFFER_BETWEEN_CARDS,
41
+ CANVAS_SIMPLE_CARD_HEIGHT,
42
+ CANVAS_VERTICAL_BUFFER_BETWEEN_CARDS,
43
+ } from './ui';
44
+
45
+ // Quick test function to check if an area is in the given list of areas
46
+ // Based on the provided entity id
47
+ function isAreaInList(areas: Area[], entityId: string): Area | null {
48
+ return areas.find((area) => area.entity.id === entityId) || null;
49
+ }
50
+
51
+ // filter out repeated areas
52
+ function filterOutRepeatedAreas(areas: Area[]): Area[] {
53
+ return areas.filter((area, index) => {
54
+ return areas.indexOf(area) === index;
55
+ });
56
+ }
57
+
58
+ export interface ICoordinates {
59
+ top: number;
60
+ left: number;
61
+ bottom: number;
62
+ right: number;
63
+ }
64
+
65
+ // This represents an area in the canvas made of 4 coordinates: top, left, bottom, right.
66
+ // Areas are nested, so an area is the total size of itself and all its children.
67
+ export class Area {
68
+ // The id of this area which represents its place on the tree of areas
69
+ // For example: "1-2-3" means this area is the 3rd child of the 2nd child of the 1st child of the root area
70
+ // Since an area can have multiple parents, it can have multiple ids
71
+ ids: string[] = [];
72
+ // The main entity of this area. Contains x and y coordinates.
73
+ entity: CanvasEntityState | ProjectState;
74
+ // Calculated UI card size for this entity in pixels
75
+ // This is an approximation and the actual height of the card
76
+ // The size is calculated based on the entity type and data
77
+ entityCardHeight!: number;
78
+ entityCardWidth!: number;
79
+ // The areas index as a child of its parent area
80
+ index: number;
81
+ // Uninitialized ordered children
82
+ childEntities: CanvasEntityState[] = [];
83
+ // All areas that collectively make up this area
84
+ children: Area[] = [];
85
+ // The areas that contains this area
86
+ // Areas can have multiple parents because they might have a common ancestor in the tree
87
+ // For example a return statement that takes in two values are the end of a logic chain
88
+ parents: Area[] = [];
89
+
90
+ // The root area of the calculation,
91
+ // Useful when we want to go the root of the areas' tree
92
+ calculationEntryPoint: Area;
93
+ _onlyEntities: CanvasEntityState[] | null = null;
94
+
95
+ private _changeSet: ChangeSet | null = null;
96
+
97
+ constructor(
98
+ entity: CanvasEntityState | ProjectState,
99
+ index: number,
100
+ calculationEntryPoint: Area | null = null,
101
+ changeSet?: ChangeSet | null
102
+ ) {
103
+ this.index = index;
104
+ this.entity = entity;
105
+ this.calculationEntryPoint = calculationEntryPoint || this;
106
+ this._changeSet = changeSet || null;
107
+
108
+ if (this === this.calculationEntryPoint && !changeSet) {
109
+ throw new Error(
110
+ 'Change-set must be provided for the calculation entry point'
111
+ );
112
+ }
113
+
114
+ this.calculateCardSize();
115
+ this.getSortedChildren();
116
+ }
117
+
118
+ static autoGenerateLayout(
119
+ entryPointEntity: CanvasEntityState | ProjectState,
120
+ changeSet: ChangeSet | null,
121
+ onlyEntities?: CanvasEntityState[]
122
+ ): CanvasEntityState[] {
123
+ const startingX =
124
+ CANVAS_BASE_X -
125
+ CANVAS_HORIZONTAL_BUFFER_BETWEEN_CARDS -
126
+ CANVAS_CARD_WIDTH;
127
+ const startingY =
128
+ CANVAS_BASE_Y -
129
+ CANVAS_VERTICAL_BUFFER_BETWEEN_CARDS -
130
+ CANVAS_SIMPLE_CARD_HEIGHT;
131
+
132
+ // TODO: Here, instead add them close to other entities if they exist in the canvas
133
+ if (entryPointEntity.type === EntityType.Project) {
134
+ (entryPointEntity as ProjectState).x = startingX;
135
+ (entryPointEntity as ProjectState).y = startingY;
136
+ } else {
137
+ // @ts-ignore
138
+ entryPointEntity.metaSync(
139
+ {
140
+ x: entryPointEntity.x || startingX,
141
+ y: entryPointEntity.y || startingY,
142
+ },
143
+ changeSet
144
+ );
145
+ }
146
+
147
+ const rootArea = new Area(entryPointEntity, 0, null, changeSet);
148
+ rootArea.calculationEntryPoint = rootArea;
149
+ rootArea._onlyEntities = onlyEntities || [];
150
+
151
+ rootArea.ids = ['0'];
152
+
153
+ const topLevelRenderedChildren: Area[] = [];
154
+
155
+ rootArea.next((renderedLevelTopLevel) => {
156
+ topLevelRenderedChildren.push(...renderedLevelTopLevel);
157
+ });
158
+
159
+ Area.recursivelyAssembleChildrenAreas(topLevelRenderedChildren);
160
+
161
+ rootArea.resolveChildrenOverlaps();
162
+
163
+ const results = rootArea.flattenChildEntities();
164
+
165
+ if (rootArea._onlyEntities) {
166
+ return results.filter((result) =>
167
+ rootArea._onlyEntities?.includes(result)
168
+ );
169
+ }
170
+
171
+ return results;
172
+ }
173
+
174
+ static recursivelyAssembleChildrenAreas(renderedParents: Area[]) {
175
+ const renderedChildren: Area[] = [];
176
+
177
+ renderedParents.forEach((area) => {
178
+ // Assemble the children of the already rendered area
179
+ area.next((renderedLevel) => {
180
+ // Gather the rendered children
181
+ renderedChildren.push(...renderedLevel);
182
+ });
183
+ });
184
+
185
+ // Do the next pass
186
+ if (renderedChildren.length > 0) {
187
+ Area.recursivelyAssembleChildrenAreas(renderedChildren);
188
+ }
189
+ }
190
+
191
+ get onlyEntities(): CanvasEntityState[] {
192
+ return this.calculationEntryPoint._onlyEntities || [];
193
+ }
194
+
195
+ get changeSet(): ChangeSet {
196
+ return this.calculationEntryPoint._changeSet as ChangeSet;
197
+ }
198
+
199
+ set changeSet(changeSet: ChangeSet | null) {
200
+ this.calculationEntryPoint._changeSet = changeSet;
201
+ }
202
+
203
+ findAreaInChildrenFromEntity(entity: CanvasEntityState): Area | null {
204
+ if (this.entity === entity) {
205
+ return this;
206
+ }
207
+
208
+ const foundChild = this.children.find((child) => child.entity === entity);
209
+
210
+ if (foundChild) {
211
+ return foundChild;
212
+ }
213
+
214
+ const foundArea = this.children.reduce((acc, child) => {
215
+ return acc || child.findAreaInChildrenFromEntity(entity);
216
+ }, null as Area | null);
217
+
218
+ return foundArea;
219
+ }
220
+
221
+ findAreaFromEntity(entity: CanvasEntityState): Area | null {
222
+ if (this.entity === entity) {
223
+ return this;
224
+ }
225
+
226
+ const children = this.calculationEntryPoint.children;
227
+
228
+ const foundChild = children.find((child) => child.entity === entity);
229
+
230
+ if (foundChild) {
231
+ return foundChild;
232
+ }
233
+
234
+ const foundArea = children.reduce((acc, child) => {
235
+ return acc || child.findAreaInChildrenFromEntity(entity);
236
+ }, null as Area | null);
237
+
238
+ return foundArea;
239
+ }
240
+
241
+ addParent(parent: Area) {
242
+ // Add the parent to the list of parents if it's not already there
243
+ if (!this.parents.includes(parent)) {
244
+ // Create the new id and add it to the list of ids
245
+ const newIds = Area.resolveIds(parent, this.index);
246
+ this.ids.push(...newIds);
247
+
248
+ // Add the parent to the list of parents
249
+ this.parents.push(parent);
250
+ }
251
+ }
252
+
253
+ static resolveIds(parent: Area, index: number): string[] {
254
+ if (!parent) {
255
+ return [`${index}`];
256
+ }
257
+
258
+ return parent.ids.map((parentId) => `${parentId}-${index}`);
259
+ }
260
+
261
+ // Sort children based on the vertical order they should be rendered in
262
+ getSortedChildren() {
263
+ /*
264
+ Child entities executed by the current entity should go on top,
265
+ so they are closer to the execution node in the header of the cards.
266
+
267
+ Children might already be rendered because they were also a child of an ancestor or sibling of the current entity.
268
+ In that case, we should not render them again.
269
+ We should shift them right if they were rendered before the right end of the current entity, so they can be rendered next to the current entity.
270
+ Or leave them as they are if they were rendered after the right end of the current entity.
271
+ After that, we should replace the area of this child with a Connection object in any of the parents that don't inmediatly boarder the child.
272
+ The child might be rendered further right after many entities, so there is potential for a horizontal gap between some of the parents and the child.
273
+ The connection takes that place and is rendered as a line between the parent and the child that spans multiple tree levels horizontally.
274
+ This way when the parent updates, it knows what happened to the entity that was shifted right.
275
+ */
276
+ if (!!(this.entity as EntryPointEntityState).collapsed) {
277
+ this.childEntities = [];
278
+ return;
279
+ }
280
+
281
+ const allUnsortedChildren = getRelatedCanvasElementsOnTheRight(
282
+ this.entity,
283
+ true
284
+ );
285
+
286
+ if (this.entity.type === EntityType.Project) {
287
+ const globalScopeEntities: DraggablePassThroughCallableEntity[] = [];
288
+ const definitionEntities: DefinitionEntityState[] = [];
289
+ const entryPoints: EntryPointEntityState[] = [];
290
+
291
+ // Filter out calls from the all unsorted children list
292
+ allUnsortedChildren.forEach((child) => {
293
+ if (EntityType.DefinitionEntity === child.type) {
294
+ definitionEntities.push(child as DefinitionEntityState);
295
+ return;
296
+ } else if (ENTRY_POINT_TYPES.includes(child.type)) {
297
+ entryPoints.push(child as EntryPointEntityState);
298
+ return;
299
+ }
300
+
301
+ globalScopeEntities.push(child as DraggablePassThroughCallableEntity);
302
+ });
303
+
304
+ // Order the variables based on whether they are part of the same global branch
305
+ // The goal is to avoid rendering other elements in between the variables
306
+ const sortedRootEntities = globalScopeEntities
307
+ .sort((a, b) => {
308
+ // If both entities are callable, check if they both eventually lead into a common child
309
+ const haveCommonChildren = !!getCommonChildren(
310
+ a as CanvasEntityState,
311
+ b as CanvasEntityState
312
+ ).length;
313
+ const relatedOfAOnTheRight = getRelatedCanvasElementsOnTheRight(
314
+ a as CanvasEntityState
315
+ );
316
+ const relatedOfBOnTheRight = getRelatedCanvasElementsOnTheRight(
317
+ b as CanvasEntityState
318
+ );
319
+
320
+ if (haveCommonChildren) {
321
+ return 0;
322
+ } else if (
323
+ !!relatedOfAOnTheRight.length &&
324
+ !relatedOfBOnTheRight.length
325
+ ) {
326
+ return -1;
327
+ } else if (
328
+ !relatedOfAOnTheRight.length &&
329
+ !!relatedOfBOnTheRight.length
330
+ ) {
331
+ return 1;
332
+ }
333
+
334
+ return 0;
335
+ // Remove any element which has ancestors (entities on the left)
336
+ })
337
+ .filter(
338
+ (entity) =>
339
+ !getRelatedCanvasElementsOnTheLeft(entity as CanvasEntityState)
340
+ .length
341
+ );
342
+
343
+ this.childEntities = [
344
+ ...(definitionEntities as CanvasEntityState[]),
345
+ ...(entryPoints as CanvasEntityState[]),
346
+ ...(sortedRootEntities as CanvasEntityState[]),
347
+ ];
348
+ } else {
349
+ const calls: DraggableCallableEntityState[] = [];
350
+ const detachedBranchesHeads: CanvasEntityState[] = [];
351
+ const variables: VariableState[] = [];
352
+ const callables: DraggableCallableEntityState[] = [];
353
+ const definitionEntities: DefinitionEntityState[] = [];
354
+
355
+ if (CALLER_TYPES.includes(this.entity.type)) {
356
+ const extractedCalls = getCalls(
357
+ this.entity as DraggableCallerEntityState
358
+ );
359
+
360
+ // Move variables to it sown array, push the rest to 'calls'
361
+ extractedCalls.forEach((call) => {
362
+ if (VARIABLE_TYPES.includes(call.type)) {
363
+ variables.push(call as VariableState);
364
+ return;
365
+ }
366
+
367
+ const callCanvasParentEntity = getParentCanvasEntity(call);
368
+
369
+ calls.push(callCanvasParentEntity as DraggableCallableEntityState);
370
+ });
371
+ }
372
+
373
+ if (ENTITY_WITH_LOGIC_SCOPE_TYPES.includes(this.entity.type)) {
374
+ detachedBranchesHeads.push(
375
+ ...(this.entity as EntityWithLogicScopeState).detachedChildren
376
+ );
377
+ }
378
+
379
+ // Filter out calls from the all unsorted children list
380
+ const otherEntities = allUnsortedChildren.filter((child) => {
381
+ const isInCall = calls.includes(child as DraggableCallableEntityState);
382
+
383
+ if (isInCall) {
384
+ return false;
385
+ }
386
+
387
+ const isInVars = variables.includes(child as VariableState);
388
+
389
+ if (isInVars) {
390
+ return false;
391
+ }
392
+
393
+ const isInDetachedBranch = detachedBranchesHeads.includes(child);
394
+
395
+ if (isInDetachedBranch) {
396
+ return false;
397
+ }
398
+
399
+ if (VARIABLE_TYPES.includes(child.type)) {
400
+ variables.push(child as VariableDeclarationState);
401
+ return false;
402
+ }
403
+
404
+ if (CALLABLE_TYPES.includes(child.type) && !isInCall) {
405
+ callables.push(child as DraggableCallableEntityState);
406
+ return false;
407
+ }
408
+
409
+ if (child.type === EntityType.DefinitionEntity) {
410
+ definitionEntities.push(child as DefinitionEntityState);
411
+ return false;
412
+ }
413
+
414
+ return true;
415
+ });
416
+
417
+ /*
418
+ Sort children based on the vertical order they should be rendered in
419
+ Children under the 'calls' or 'successCalls' property should be rendered on top
420
+ Children under the 'errorCalls' property should be rendered next
421
+ */
422
+ calls.sort((a, b) => {
423
+ // If both entities are callable, check if any of them, eventually leads into the other
424
+ // Place the dependent branch before the independent one
425
+ if (
426
+ checkIsBranchDependentButNotDirectlyOnBranch(
427
+ a as CanvasEntityState,
428
+ b as CanvasEntityState
429
+ )
430
+ ) {
431
+ return -1;
432
+ }
433
+
434
+ return 0;
435
+ });
436
+
437
+ callables.sort((a, b) => {
438
+ // If both entities are callable, check if any of them, eventually leads into the other
439
+ // Place the dependent branch before the independent one
440
+ if (
441
+ checkIsBranchDependentButNotDirectlyOnBranch(
442
+ a as CanvasEntityState,
443
+ b as CanvasEntityState
444
+ )
445
+ ) {
446
+ return -1;
447
+ }
448
+
449
+ return 0;
450
+ });
451
+
452
+ variables.sort((a, b) => {
453
+ // If both entities are callable, check if any of them, eventually leads into the other
454
+ // Place the dependent branch before the independent one
455
+ if (
456
+ checkIsBranchDependentOnBranch(a as VariableState, b as VariableState)
457
+ ) {
458
+ return 1;
459
+ } else if (
460
+ checkIsBranchDependentOnBranch(b as VariableState, a as VariableState)
461
+ ) {
462
+ return -1;
463
+ }
464
+
465
+ return 0;
466
+ });
467
+
468
+ this.childEntities = [
469
+ ...definitionEntities,
470
+ ...(calls as CanvasEntityState[]),
471
+ ...(callables as CanvasEntityState[]),
472
+ ...otherEntities,
473
+ ...variables,
474
+ ...detachedBranchesHeads,
475
+ ];
476
+ }
477
+ }
478
+
479
+ // This is an approximation and the actual height of the card
480
+ // Calculated based on the entity type and data
481
+ calculateCardSize() {
482
+ const size = calculateCardSize(this.entity as CanvasEntityState);
483
+
484
+ this.entityCardWidth = size.width;
485
+ this.entityCardHeight = size.height;
486
+ }
487
+
488
+ // It takes the biggest top, left, bottom, right coordinates of two areas
489
+ // and returns the top, left, bottom, right coordinates of the area that contains both
490
+ static getBoundriesOfTwoAreas(
491
+ area1: ICoordinates,
492
+ area2: ICoordinates
493
+ ): ICoordinates {
494
+ return {
495
+ top: Math.min(area1.top, area2.top),
496
+ left: Math.min(area1.left, area2.left),
497
+ bottom: Math.max(area1.bottom, area2.bottom),
498
+ right: Math.max(area1.right, area2.right),
499
+ };
500
+ }
501
+
502
+ // Get the combined boundries area of all given areas
503
+ static getBoundriedOfCombinedAreas(
504
+ areas: Area[],
505
+ until: Area[]
506
+ ): ICoordinates {
507
+ const areasToCombine = areas.filter((area) => !until.includes(area));
508
+
509
+ const combinedArea = areasToCombine.reduce((acc, area) => {
510
+ if (until.includes(area)) {
511
+ return acc;
512
+ }
513
+
514
+ return Area.getBoundriesOfTwoAreas(acc, area.fullBranchArea);
515
+ }, areasToCombine[0].fullBranchArea);
516
+
517
+ return combinedArea;
518
+ }
519
+
520
+ // Returns the full area of the current entity and all its children until we find any of the given areas
521
+ getFullAreaUntilAny(areas: Area[]): ICoordinates {
522
+ const ownArea = this.ownEntityPlusBufferArea;
523
+
524
+ const otherChildren = this.children.filter(
525
+ (child) => !areas.includes(child)
526
+ );
527
+
528
+ const childrenAreas = otherChildren.map((child) =>
529
+ child.getFullAreaUntilAny(areas)
530
+ );
531
+
532
+ const fullArea: ICoordinates = childrenAreas.reduce((acc, childArea) => {
533
+ return Area.getBoundriesOfTwoAreas(acc, childArea);
534
+ }, ownArea);
535
+
536
+ return fullArea;
537
+ }
538
+
539
+ // Returns the full area of children until the given child area is found
540
+ // Useful when a child is shared by another entity
541
+ getFullAreaUntilAreaOrAnyChildren(childArea: Area): ICoordinates {
542
+ const untilChildren = [childArea, ...childArea.flattenChildren()];
543
+
544
+ const ownArea = this.ownEntityPlusBufferArea;
545
+
546
+ const childrenAreas = this.children
547
+ .filter((child) => untilChildren.includes(child))
548
+ .map((child) => child.getFullAreaUntil(childArea));
549
+
550
+ const fullArea: ICoordinates = childrenAreas.reduce((acc, childArea) => {
551
+ return Area.getBoundriesOfTwoAreas(acc, childArea);
552
+ }, ownArea);
553
+
554
+ return fullArea;
555
+ }
556
+
557
+ // Returns the full area of children until the given child area is found
558
+ // Useful when a child is shared by another entity
559
+ getFullAreaUntil(childArea: Area): ICoordinates {
560
+ const ownArea = this.ownEntityPlusBufferArea;
561
+
562
+ const childrenAreas = this.children
563
+ .filter((child) => child !== childArea)
564
+ .map((child) => child.getFullAreaUntil(childArea));
565
+
566
+ const fullArea: ICoordinates = childrenAreas.reduce((acc, childArea) => {
567
+ return Area.getBoundriesOfTwoAreas(acc, childArea);
568
+ }, ownArea);
569
+
570
+ return fullArea;
571
+ }
572
+
573
+ // Calculates and returns the top, left, bottom, right coordinates of this area with all of its children
574
+ get fullBranchArea(): ICoordinates {
575
+ const ownArea = this.ownEntityPlusBufferArea;
576
+ const childrenAreas = this.children.map((child) => child.fullBranchArea);
577
+
578
+ const fullArea: ICoordinates = childrenAreas.reduce((acc, childArea) => {
579
+ const childAreaBoundry = Area.getBoundriesOfTwoAreas(acc, childArea);
580
+
581
+ return childAreaBoundry;
582
+ }, ownArea);
583
+ return fullArea;
584
+ }
585
+
586
+ // Calculates and returns the top, left, bottom, right coordinates of this area without its children
587
+ // Only the size of the entity itself
588
+ get ownEntityArea(): ICoordinates {
589
+ const ownArea = {
590
+ top: this.entity.y,
591
+ left: this.entity.x,
592
+ bottom: this.entity.y + this.entityCardHeight,
593
+ right: this.entity.x + this.entityCardWidth,
594
+ };
595
+
596
+ return ownArea;
597
+ }
598
+
599
+ // Calculates and returns the top, left, bottom, right coordinates of this area with its buffer area
600
+ // The buffer area is a space added to the right and bottom of the entity to separate cards on the canvas
601
+ get ownEntityPlusBufferArea(): ICoordinates {
602
+ const entityArea = this.ownEntityArea;
603
+ const bufferedArea = {
604
+ top: entityArea.top,
605
+ left: entityArea.left,
606
+ bottom: entityArea.bottom + CANVAS_VERTICAL_BUFFER_BETWEEN_CARDS,
607
+ right: entityArea.right + CANVAS_HORIZONTAL_BUFFER_BETWEEN_CARDS,
608
+ };
609
+
610
+ return bufferedArea;
611
+ }
612
+
613
+ static filterOutRepeatedAreas(areas: Area[]): Area[] {
614
+ return areas.filter((area, index) => {
615
+ return areas.indexOf(area) === index;
616
+ });
617
+ }
618
+
619
+ getEarliestId(idA: string, idB: string): string {
620
+ const idASplit = idA.split('-');
621
+ const idBSplit = idB.split('-');
622
+
623
+ if (idASplit.length < idBSplit.length) {
624
+ return idA;
625
+ } else if (idASplit.length > idBSplit.length) {
626
+ return idB;
627
+ }
628
+
629
+ // If both ids has the same levels, check which one has the smallest number earlier on
630
+ const earliestId = idASplit.reduce((_, id, index) => {
631
+ if (id < idBSplit[index]) {
632
+ return idA;
633
+ }
634
+
635
+ return idB;
636
+ }, idA);
637
+
638
+ return earliestId;
639
+ }
640
+
641
+ // Returns the number of levels deep in the tree of areas that the current area is first seen at
642
+ getEarliestLevel(): number {
643
+ // Get the id with the least levels
644
+ const earliestId = this.ids.reduce((acc, id) => {
645
+ return this.getEarliestId(acc, id);
646
+ }, this.ids[0]);
647
+
648
+ const earliestLevel = earliestId.split('-').length;
649
+
650
+ return earliestLevel;
651
+ }
652
+
653
+ // Returns the column number,
654
+ // every time an area is a children of another, it is shifted right to be on the right of the parent
655
+ // The column number is the number of times the area has been shifted right
656
+ // To find the column number, we need to count the number of parents, taking the longest route, until the root of the calculation
657
+ countColumns(): number {
658
+ // Start counting itself as the first column
659
+ let count: number = 0;
660
+
661
+ if (this !== this.calculationEntryPoint) {
662
+ count++;
663
+ } else {
664
+ return count;
665
+ }
666
+
667
+ if (!this.parents.length) {
668
+ return count;
669
+ }
670
+
671
+ // Find the parent with the most levels
672
+ const parentWithMostLevels = this.parents.reduce((acc, parent) => {
673
+ const parentLevel = parent.getEarliestLevel();
674
+
675
+ if (parentLevel > acc.getEarliestLevel()) {
676
+ return parent;
677
+ }
678
+
679
+ return acc;
680
+ }, this.parents[0]);
681
+
682
+ // Recursively find the column number
683
+ const parentColumnNumber = parentWithMostLevels.countColumns();
684
+
685
+ count += parentColumnNumber;
686
+
687
+ return count;
688
+ }
689
+
690
+ getLatestId(idA: string, idB: string): string {
691
+ if (idA === idB) {
692
+ return idA;
693
+ }
694
+
695
+ const idASplit = idA.split('-');
696
+ const idBSplit = idB.split('-');
697
+
698
+ if (idASplit.length < idBSplit.length) {
699
+ return idB;
700
+ } else if (idASplit.length > idBSplit.length) {
701
+ return idA;
702
+ }
703
+
704
+ // If both ids has the same levels, check which one has the smallest number earlier on
705
+ const latestId = idASplit.reduce((_, id, index) => {
706
+ if (id > idBSplit[index]) {
707
+ return idA;
708
+ }
709
+
710
+ return idB;
711
+ }, idA);
712
+
713
+ return latestId;
714
+ }
715
+
716
+ // Returns the number of levels deep in the tree of areas that the current area is last seen at
717
+ getLatestLevel(): number {
718
+ if (this.ids.length === 1) {
719
+ return this.ids[0].split('-').length;
720
+ }
721
+
722
+ // Get the id with the most levels
723
+ const latestId = this.ids.reduce((acc, id) => {
724
+ return this.getLatestId(acc, id);
725
+ }, this.ids[0]);
726
+
727
+ const latestLevel = latestId.split('-').length;
728
+
729
+ return latestLevel;
730
+ }
731
+
732
+ // Decides how much to shift an element down to make it look more organic
733
+ smoothPosition() {
734
+ const siblings = this.flattenSiblings();
735
+
736
+ if (
737
+ !siblings.length &&
738
+ this.parents.length <= 1 &&
739
+ !!this.children.length
740
+ ) {
741
+ const amountShifted =
742
+ this.centerHeaderVerticallyOverCombinedAllChildrenHeaderHeight();
743
+
744
+ // Shift parents down too
745
+ this.parents.forEach((parent) => {
746
+ if (parent === this.calculationEntryPoint) {
747
+ return;
748
+ }
749
+
750
+ parent.shiftDownAlone(amountShifted);
751
+ });
752
+
753
+ // Final little cleanup to make the layout more human-like by centering the starting entities over their first children
754
+ } else if (
755
+ [...ENTRY_POINT_TYPES].includes(this.entity.type) &&
756
+ !!this.children.length
757
+ ) {
758
+ this.centerHeaderVerticallyOverCombinedAllChildrenHeaderHeight();
759
+ } else if (!this.children.length && this.parents.length > 1) {
760
+ // Remove any siblings that are also parents
761
+ const sanitizedSiblings = siblings.filter(
762
+ (sibling) => !this.parents.includes(sibling)
763
+ );
764
+
765
+ // Parents shouldn't have more children at the same level
766
+ // Center current entity, only if the children are rendered higher up the tree.
767
+ // A sibling is rendered further left if their longest id is shorter
768
+ if (!!sanitizedSiblings.length) {
769
+ const itIsRenderedAfterSiblings = sanitizedSiblings.every((sibling) => {
770
+ const ownNumberOfColumns = this.countColumns();
771
+
772
+ const siblingNumberOfColumns = sibling.countColumns();
773
+
774
+ const isRenderedAfter = ownNumberOfColumns > siblingNumberOfColumns;
775
+
776
+ return isRenderedAfter;
777
+ });
778
+
779
+ if (itIsRenderedAfterSiblings) {
780
+ this.centerHeaderVerticallyOverCombinedAllParentsHeaderHeight();
781
+ }
782
+ } else if (!sanitizedSiblings.length) {
783
+ this.centerHeaderVerticallyOverCombinedAllParentsHeaderHeight();
784
+ }
785
+ }
786
+ }
787
+
788
+ // Shift the entity down recursively with all its children, until we find any of the given areas, then stop
789
+ // Returns the areas that have been shifted, recursively, so the children shifted by the children are also returned
790
+ shiftDownUntilAny(areas: Area[], amount: number): Area[] {
791
+ // Just to test, check if the 'areas' list contains a null or undefined value
792
+ if (areas.includes(this)) {
793
+ return areas;
794
+ }
795
+
796
+ this.move(this.entity as CanvasEntityState, {
797
+ y: this.entity.y + amount,
798
+ });
799
+
800
+ let alreadyShiftedAreas: Area[] = [...areas, this];
801
+
802
+ this.children.forEach((child) => {
803
+ // We only want to shift the children once, therefore, if the child has multiple parents,
804
+ // we assume that it has already been shifted by the earliest parent
805
+ // So if this isn't the earliest parent, we skip shifting the child
806
+ const earliestParent = Area.getEarliestParentInChain(child);
807
+
808
+ if (earliestParent !== this) {
809
+ return;
810
+ }
811
+
812
+ const wasPreviouslyInList = isAreaInList(
813
+ alreadyShiftedAreas,
814
+ child.entity.id
815
+ );
816
+
817
+ alreadyShiftedAreas = Area.filterOutRepeatedAreas([
818
+ ...alreadyShiftedAreas,
819
+ ]);
820
+
821
+ if (!wasPreviouslyInList) {
822
+ // Remove itself from the already shifted areas list if it is present
823
+ alreadyShiftedAreas = alreadyShiftedAreas.filter(
824
+ (area) => area !== child
825
+ );
826
+ }
827
+
828
+ const newAreasShifted = child.shiftDownUntilAny(
829
+ alreadyShiftedAreas,
830
+ amount
831
+ );
832
+
833
+ alreadyShiftedAreas.push(...newAreasShifted);
834
+ });
835
+
836
+ return alreadyShiftedAreas;
837
+ }
838
+
839
+ shiftRightUntilAny(areas: Area[], amount: number) {
840
+ if (areas.includes(this)) {
841
+ return;
842
+ }
843
+
844
+ this.move(this.entity as CanvasEntityState, {
845
+ x: this.entity.x + amount,
846
+ });
847
+
848
+ this.children.forEach((child) => {
849
+ const flattSiblingAreas = Area.filterOutRepeatedAreas([
850
+ ...this.flattenSiblings(),
851
+ ...areas,
852
+ ]);
853
+
854
+ const earliestParent = Area.getEarliestParentInChain(child);
855
+
856
+ // This is done to make sure that the child is only shifted once
857
+ // Only the earliest parent has the responsibility to shift the child
858
+ if (earliestParent !== this) {
859
+ return;
860
+ }
861
+
862
+ child.shiftRightUntilAny(flattSiblingAreas, amount);
863
+ });
864
+ }
865
+
866
+ // Shifts the entity to the right
867
+ shiftRight(amount: number) {
868
+ this.move(this.entity as CanvasEntityState, {
869
+ x: this.entity.x + amount,
870
+ });
871
+
872
+ // Shift all children to the right as well
873
+ this.children.forEach((child) => {
874
+ /*
875
+ We have two avoid siblings shifting eachother. For example:
876
+ The current entity shifts all of its children, but they are shifted recursively.
877
+ Meaning, all children shift their children by the same amount, and so on
878
+ Imagine that one of the children is a also the parent of a sibling.
879
+ Meaning that the sibling is also a child of the current entity. In that case it will be shifted twice
880
+
881
+ We need to avoid children from being shiften more than ones in the "shift chain" so we keep track of the areas that have been shifted
882
+ */
883
+ const flattSiblingAreas = child.flattenSiblings();
884
+
885
+ // Remove current child from list of siblings if it is present
886
+ const siblings = flattSiblingAreas.filter((sibling) => sibling !== child);
887
+
888
+ child.shiftRightUntilAny(siblings, amount);
889
+ });
890
+ }
891
+
892
+ // Translates the y axis of the entity without side effects
893
+ shiftDownAlone(amount: number) {
894
+ this.move(this.entity as CanvasEntityState, {
895
+ y: this.entity.y + amount,
896
+ });
897
+ }
898
+
899
+ centerHeaderVerticallyOverCombinedAllParentsHeaderHeight() {
900
+ const fullParentsHeadersHeightArea: ICoordinates = this.parents.reduce(
901
+ (acc, parent) => {
902
+ const parentArea = parent.ownEntityArea;
903
+
904
+ const parentHeaderCenter =
905
+ parentArea.top + CANVAS_CARD_HEADER_CENTER_HEIGHT;
906
+
907
+ const parentHeaderCenterArea: ICoordinates = {
908
+ top: parentHeaderCenter,
909
+ left: parentArea.left,
910
+ bottom: parentHeaderCenter,
911
+ right: parentArea.right,
912
+ };
913
+
914
+ return Area.getBoundriesOfTwoAreas(acc, parentHeaderCenterArea);
915
+ },
916
+ { top: Infinity, left: Infinity, bottom: -Infinity, right: -Infinity }
917
+ );
918
+
919
+ const fullParentsHeadersHeight =
920
+ fullParentsHeadersHeightArea.bottom - fullParentsHeadersHeightArea.top;
921
+
922
+ const shiftAmount =
923
+ fullParentsHeadersHeight / 2 - CANVAS_CARD_HEADER_CENTER_HEIGHT;
924
+
925
+ this.shiftDownAlone(shiftAmount);
926
+ }
927
+
928
+ // Returns amount shifted
929
+ centerHeaderVerticallyOverCombinedAllChildrenHeaderHeight(): number {
930
+ const fullChildrenHeadersHeightArea: ICoordinates = this.children.reduce(
931
+ (acc, child) => {
932
+ const childArea = child.ownEntityArea;
933
+ const childHeaderCenter =
934
+ childArea.top + CANVAS_CARD_HEADER_CENTER_HEIGHT;
935
+
936
+ const childHeaderCenterArea: ICoordinates = {
937
+ top: childHeaderCenter,
938
+ left: childArea.left,
939
+ bottom: childHeaderCenter,
940
+ right: childArea.right,
941
+ };
942
+
943
+ return Area.getBoundriesOfTwoAreas(acc, childHeaderCenterArea);
944
+ },
945
+ {
946
+ top: Infinity,
947
+ left: Infinity,
948
+ bottom: -Infinity,
949
+ right: -Infinity,
950
+ }
951
+ );
952
+
953
+ const fullChildrenHeadersHeight =
954
+ fullChildrenHeadersHeightArea.bottom - fullChildrenHeadersHeightArea.top;
955
+
956
+ const shiftAmount =
957
+ fullChildrenHeadersHeight / 2 - CANVAS_CARD_HEADER_CENTER_HEIGHT;
958
+
959
+ this.shiftDownAlone(shiftAmount);
960
+
961
+ return shiftAmount;
962
+ }
963
+
964
+ // Recursively resolves overlaps among its children
965
+ resolveChildrenOverlaps() {
966
+ // Loop through all the children and resolve overlaps
967
+ const children = this.flattenChildren();
968
+
969
+ let alreadyShiftedAreasVertically: Area[] = [];
970
+
971
+ children.forEach((child) => {
972
+ const newlyShiftedAreas = child.adjustVerticallyToAvoidOverlaps();
973
+
974
+ alreadyShiftedAreasVertically.push(...newlyShiftedAreas);
975
+ });
976
+
977
+ children.forEach((child) => {
978
+ child.smoothPosition();
979
+ });
980
+ }
981
+
982
+ static getEarliestParentInChain(area: Area): Area {
983
+ // Find the parent that is rendered the earliest in the areas tree
984
+ let earliestParentInChain = area.parents[0];
985
+
986
+ if (area.parents.length) {
987
+ earliestParentInChain = area.parents.sort((parentA, parentB) => {
988
+ // This is the root area
989
+ if (!parentA.ids.length) {
990
+ return -1;
991
+ }
992
+
993
+ // This is the root area
994
+ if (!parentB.ids.length) {
995
+ return 1;
996
+ }
997
+
998
+ // Return the one with the smallest ids
999
+ const parentASortedIds = parentA.ids.sort((a, b) => {
1000
+ // Shortest string length first
1001
+ if (a.length < b.length) {
1002
+ return -1;
1003
+ }
1004
+
1005
+ // If the lengths are the same, return any
1006
+ return 0;
1007
+ });
1008
+
1009
+ // Return the one with the smallest ids
1010
+ const parentBSortedIds = parentB.ids.sort((a, b) => {
1011
+ // Shortest string length first
1012
+ if (a.length < b.length) {
1013
+ return -1;
1014
+ }
1015
+
1016
+ // If the lengths are the same, return any
1017
+ return 0;
1018
+ });
1019
+
1020
+ // Sort the parents based on the length of their shortest id
1021
+ return parentASortedIds[0].length - parentBSortedIds[0].length;
1022
+ })[0];
1023
+ }
1024
+
1025
+ return earliestParentInChain;
1026
+ }
1027
+
1028
+ // Access the parent, remove itself and flatten the siblings that come before it
1029
+ // in the parents children array
1030
+ // If it find itself as a child of another entity, stop there
1031
+ flattenEarlierSiblings(seenSiblings: Set<string> = new Set()): Area[] {
1032
+ seenSiblings.add(this.entity.id);
1033
+
1034
+ const result = this.parents.reduce((acc, parent) => {
1035
+ if (seenSiblings.has(parent.entity.id)) {
1036
+ return acc;
1037
+ }
1038
+
1039
+ seenSiblings.add(parent.entity.id);
1040
+
1041
+ const siblings = parent.children.slice(0, parent.children.indexOf(this));
1042
+
1043
+ const siblingAreas = siblings.reduce((acc, sibling) => {
1044
+ return [...acc, sibling, ...sibling.flattenChildren(seenSiblings)];
1045
+ }, [] as Area[]);
1046
+
1047
+ return [...acc, ...siblingAreas];
1048
+ }, [] as Area[]);
1049
+
1050
+ return result;
1051
+ }
1052
+
1053
+ // Access the parent, remove itself and flatten the remaining children of its parent
1054
+ // If it find itself as a child of another entity, stop there
1055
+ flattenSiblings(seenSiblings: Set<string> = new Set()): Area[] {
1056
+ seenSiblings.add(this.entity.id);
1057
+
1058
+ const result = this.parents.reduce((acc, parent) => {
1059
+ if (seenSiblings.has(parent.entity.id)) {
1060
+ return acc;
1061
+ }
1062
+
1063
+ seenSiblings.add(parent.entity.id);
1064
+
1065
+ const siblings = parent.children.filter((sibling) => sibling !== this);
1066
+
1067
+ const siblingAreas = siblings.reduce((acc, sibling) => {
1068
+ return [...acc, sibling, ...sibling.flattenChildren(seenSiblings)];
1069
+ }, [] as Area[]);
1070
+
1071
+ return [...acc, ...siblingAreas];
1072
+ }, [] as Area[]);
1073
+
1074
+ return result;
1075
+ }
1076
+
1077
+ flattenChildren(seenChildren: Set<string> = new Set()): Area[] {
1078
+ return this.children.reduce((acc, child) => {
1079
+ if (seenChildren.has(child.entity.id)) {
1080
+ return acc;
1081
+ }
1082
+
1083
+ seenChildren.add(child.entity.id);
1084
+
1085
+ return [...acc, child, ...child.flattenChildren(seenChildren)];
1086
+ }, [] as Area[]);
1087
+ }
1088
+
1089
+ flattenParents(seenParents: Set<string> = new Set()): Area[] {
1090
+ const result = this.parents.reduce((acc, parent) => {
1091
+ if (seenParents.has(parent.entity.id)) {
1092
+ return acc;
1093
+ }
1094
+
1095
+ seenParents.add(parent.entity.id);
1096
+
1097
+ return [...acc, parent, ...parent.flattenParents(seenParents)];
1098
+ }, [] as Area[]);
1099
+
1100
+ return result;
1101
+ }
1102
+
1103
+ // Explore the tree of areas to find the entity
1104
+ // If the entity is already rendered, return its area
1105
+ // Otherwise, return null
1106
+ getAreaIfRendered(entity: CanvasEntityState): Area | null {
1107
+ // TODO: this search can be optimised a lot
1108
+ const allAreas: Area[] = this.calculationEntryPoint.flattenChildren();
1109
+
1110
+ const area = allAreas.find((area) => area.entity.id === entity.id);
1111
+
1112
+ return area || null;
1113
+ }
1114
+
1115
+ // Loop over parents, find own index in their children array and return all the siblings after itself
1116
+ getLowerSiblings(): Area[] {
1117
+ const siblings = this.parents.reduce((acc, parent) => {
1118
+ const index = parent.children.indexOf(this);
1119
+
1120
+ const lowerSiblings = parent.children.slice(index + 1);
1121
+ return [...acc, ...lowerSiblings];
1122
+ }, [] as Area[]);
1123
+
1124
+ return filterOutRepeatedAreas(siblings);
1125
+ }
1126
+
1127
+ // It returns all areas that are rendered after the current area, below in the canvas
1128
+ // Not direct children, but subsequent own siblings and subsequent siblings of the parents
1129
+ getLowerAreas(): Area[] {
1130
+ const lowerSiblings = this.getLowerSiblings();
1131
+
1132
+ // Select its parents, then select its lower siblings
1133
+ const lowerParents = this.parents.reduce((acc, parent) => {
1134
+ return [...acc, ...parent.getLowerAreas()];
1135
+ }, [] as Area[]);
1136
+
1137
+ return filterOutRepeatedAreas([...lowerSiblings, ...lowerParents]);
1138
+ }
1139
+
1140
+ // It checks its own area against the area of earlier siblings
1141
+ // and moves itself down if it overlaps with any of them by the overlap amount
1142
+ adjustVerticallyToAvoidOverlaps(alreadyShiftedAreas: Area[] = []): Area[] {
1143
+ // Get previous sibling
1144
+ const earliestParent = Area.getEarliestParentInChain(this);
1145
+
1146
+ const previousSibling = earliestParent.children[this.index - 1];
1147
+
1148
+ if (!previousSibling) {
1149
+ return alreadyShiftedAreas;
1150
+ }
1151
+
1152
+ const flatPreviousSiblingAreas = this.flattenEarlierSiblings();
1153
+ const flatParents = this.flattenParents();
1154
+ const allToAvoid = [
1155
+ ...flatPreviousSiblingAreas,
1156
+ ...flatParents,
1157
+ previousSibling,
1158
+ ];
1159
+
1160
+ const commonChildren = filterOutDuplicateEntities(
1161
+ allToAvoid.flatMap((relatedArea) => {
1162
+ const commonChildren = getCommonChildren(
1163
+ this.entity as CanvasEntityState,
1164
+ relatedArea.entity as CanvasEntityState
1165
+ );
1166
+
1167
+ return commonChildren;
1168
+ })
1169
+ ) as CanvasEntityState[];
1170
+
1171
+ // Remove itself from the list if it is present
1172
+ const filteredCommonChildren = commonChildren.filter(
1173
+ (child) => child.id !== this.entity.id
1174
+ );
1175
+
1176
+ const commonChildrenAreas = filteredCommonChildren
1177
+ .map((commonChild) => this.findAreaFromEntity(commonChild))
1178
+ .filter((area) => !!area);
1179
+
1180
+ const ownFullArea = this.getFullAreaUntilAny(commonChildrenAreas);
1181
+
1182
+ const previousSiblingFullArea =
1183
+ previousSibling.getFullAreaUntilAny(commonChildrenAreas);
1184
+
1185
+ const maxBottom = allToAvoid.reduce((acc, area) => {
1186
+ if (area === this) {
1187
+ return acc;
1188
+ }
1189
+
1190
+ // Skip any areas that are not vertically aligned with the current one
1191
+ // We don't want to move areas that are not on the same vertical line
1192
+ if (area.fullBranchArea.left !== ownFullArea.left) {
1193
+ return acc;
1194
+ }
1195
+
1196
+ return Math.max(acc, area.fullBranchArea.bottom);
1197
+
1198
+ // This is so every entity is at least lower than the previous sibling
1199
+ // Even if they aren't overlapping
1200
+ }, previousSiblingFullArea.bottom);
1201
+
1202
+ // Shift down if the top of the current area is less than the bottom of the previous sibling
1203
+ if (ownFullArea.top < maxBottom) {
1204
+ const shiftAmount =
1205
+ maxBottom - ownFullArea.top + CANVAS_VERTICAL_BUFFER_BETWEEN_CARDS;
1206
+
1207
+ const newlyShiftedAreas = this.shiftDownUntilAny(
1208
+ alreadyShiftedAreas,
1209
+ shiftAmount
1210
+ );
1211
+
1212
+ return newlyShiftedAreas;
1213
+ }
1214
+
1215
+ return alreadyShiftedAreas;
1216
+ }
1217
+
1218
+ move(
1219
+ entity: CanvasEntityState,
1220
+ coordinates: { x: number; y: number } | { y: number } | { x: number }
1221
+ ) {
1222
+ if (!!this.onlyEntities.includes(entity)) {
1223
+ // @ts-ignore
1224
+ entity.metaSync(coordinates, this.changeSet);
1225
+ }
1226
+ }
1227
+
1228
+ // Create new areas for the children of this area
1229
+ addChild(index: number): Area | null {
1230
+ const childEntity = this.childEntities[index];
1231
+
1232
+ let childArea: Area | null = null;
1233
+
1234
+ // If the child entity has coordinates 0, 0 it means it hasn't been initialized
1235
+ // But if both coordinates exist, it means it has necessarily been rendered
1236
+ if (!!childEntity.x && !!childEntity.y) {
1237
+ childArea = this.getAreaIfRendered(childEntity) as Area;
1238
+ } else if (!childEntity.x && !childEntity.y) {
1239
+ // Initialize the child entity with the parent coordinates to start with
1240
+ this.move(childEntity, {
1241
+ x: this.entity.x,
1242
+ y: this.entity.y,
1243
+ });
1244
+ }
1245
+
1246
+ if (!childArea) {
1247
+ // Create new area instance
1248
+ childArea = new Area(childEntity, index, this.calculationEntryPoint);
1249
+ }
1250
+
1251
+ const ownBufferArea = this.ownEntityPlusBufferArea;
1252
+
1253
+ // If the child area instance is not already in the state as a children, add it
1254
+ if (!this.children.includes(childArea)) {
1255
+ // Add to the state own state even if it was already rendered
1256
+ this.children.push(childArea);
1257
+
1258
+ // Subscribe itself as a parent of the child area
1259
+ childArea.addParent(this);
1260
+ }
1261
+
1262
+ // Move the new child area to the right of the current area if it isn't already there
1263
+ const newChildFullArea = childArea.fullBranchArea;
1264
+
1265
+ // If the child area is not already to the right of the current area, shift it to the right
1266
+ if (newChildFullArea.left < ownBufferArea.right) {
1267
+ const shiftAmount = ownBufferArea.right - newChildFullArea.left;
1268
+
1269
+ childArea.shiftRight(shiftAmount);
1270
+ }
1271
+
1272
+ return childArea;
1273
+ }
1274
+
1275
+ // Flatten the tree of areas into an array of entities
1276
+ // This is useful at the end of the calculation to return all entities with the final coordinates
1277
+ flattenChildEntities(
1278
+ seenEntities: Set<string> = new Set()
1279
+ ): CanvasEntityState[] {
1280
+ return this.children.reduce((acc, child) => {
1281
+ if (seenEntities.has(child.entity.id)) {
1282
+ return acc;
1283
+ }
1284
+
1285
+ seenEntities.add(child.entity.id);
1286
+
1287
+ return [
1288
+ ...acc,
1289
+ child.entity as CanvasEntityState,
1290
+ ...child.flattenChildEntities(seenEntities),
1291
+ ];
1292
+ }, [] as CanvasEntityState[]);
1293
+ }
1294
+
1295
+ // When we render children, we render them in a shallow way without their respective children
1296
+ // Once all the first level children are rendered, we go back to the first one and render its children in the same way
1297
+ // This way we can resolve overlaps and shifts in a more efficient way
1298
+ // We use recursion on the side of the caller
1299
+ next(onLevelComplete: (renderedLevel: Area[]) => void) {
1300
+ const proccessedChildren: Area[] = [];
1301
+
1302
+ this.childEntities.forEach((_, index) => {
1303
+ const proccessedChild = this.addChild(index);
1304
+
1305
+ if (proccessedChild) {
1306
+ proccessedChildren.push(proccessedChild);
1307
+ }
1308
+ });
1309
+
1310
+ onLevelComplete(proccessedChildren);
1311
+ }
1312
+ }