@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.
- package/README.md +2 -0
- package/package.json +109 -0
- package/src/App.tsx +31 -0
- package/src/Router.tsx +115 -0
- package/src/__mocks__/defaultModuleMock.ts +1 -0
- package/src/__mocks__/fileMock.ts +1 -0
- package/src/__mocks__/styleMock.ts +1 -0
- package/src/assets/Clock-11.1s-18px.svg +16 -0
- package/src/assets/Clock-11.1s-28px.svg +16 -0
- package/src/assets/authentication.svg +1 -0
- package/src/assets/canvas-backdrop-0.png +0 -0
- package/src/assets/canvas-backdrop-1.png +0 -0
- package/src/assets/canvas-backdrop-2.png +0 -0
- package/src/assets/canvas-backdrop-3.png +0 -0
- package/src/assets/canvas-backdrop-4.png +0 -0
- package/src/assets/canvas-backdrop-5.png +0 -0
- package/src/assets/canvas-backdrop.png +0 -0
- package/src/assets/checkmark-animation.gif +0 -0
- package/src/assets/checkmark-animation.mp4 +0 -0
- package/src/assets/code-formatting/format-black.svg +6 -0
- package/src/assets/code-formatting/format-dark-grey.svg +6 -0
- package/src/assets/code-formatting/format-light-grey.svg +6 -0
- package/src/assets/code-formatting/format-white.svg +6 -0
- package/src/assets/code-formatting/inline-black.svg +5 -0
- package/src/assets/code-formatting/inline-dark-grey.svg +5 -0
- package/src/assets/code-formatting/inline-light-grey.svg +5 -0
- package/src/assets/code-formatting/inline-white.svg +5 -0
- package/src/assets/contained-logo-full-word.png +0 -0
- package/src/assets/cron-job-color.png +0 -0
- package/src/assets/cron-job.png +0 -0
- package/src/assets/database-table-color.png +0 -0
- package/src/assets/database-table.png +0 -0
- package/src/assets/datatype-icons/black/any.svg +1 -0
- package/src/assets/datatype-icons/black/binary.svg +1 -0
- package/src/assets/datatype-icons/black/boolean.svg +3 -0
- package/src/assets/datatype-icons/black/date-time.svg +3 -0
- package/src/assets/datatype-icons/black/definition-entity.svg +6 -0
- package/src/assets/datatype-icons/black/key-file.svg +1 -0
- package/src/assets/datatype-icons/black/list.svg +3 -0
- package/src/assets/datatype-icons/black/null.svg +3 -0
- package/src/assets/datatype-icons/black/number.svg +13 -0
- package/src/assets/datatype-icons/black/project.svg +12 -0
- package/src/assets/datatype-icons/black/sql-program.svg +2 -0
- package/src/assets/datatype-icons/black/text.svg +3 -0
- package/src/assets/datatype-icons/black/unknown.svg +3 -0
- package/src/assets/datatype-icons/black/uuid.svg +4 -0
- package/src/assets/datatype-icons/black/void.svg +1 -0
- package/src/assets/datatype-icons/dark-grey/any.svg +1 -0
- package/src/assets/datatype-icons/dark-grey/boolean.svg +3 -0
- package/src/assets/datatype-icons/dark-grey/date-time.svg +3 -0
- package/src/assets/datatype-icons/dark-grey/definition-entity.svg +6 -0
- package/src/assets/datatype-icons/dark-grey/list.svg +3 -0
- package/src/assets/datatype-icons/dark-grey/null.svg +3 -0
- package/src/assets/datatype-icons/dark-grey/number.svg +13 -0
- package/src/assets/datatype-icons/dark-grey/project.svg +12 -0
- package/src/assets/datatype-icons/dark-grey/sql-program.svg +2 -0
- package/src/assets/datatype-icons/dark-grey/text.svg +3 -0
- package/src/assets/datatype-icons/dark-grey/unknown.svg +3 -0
- package/src/assets/datatype-icons/dark-grey/uuid.svg +4 -0
- package/src/assets/datatype-icons/dark-grey/void.svg +1 -0
- package/src/assets/datatype-icons/light-grey/any.svg +1 -0
- package/src/assets/datatype-icons/light-grey/boolean.svg +3 -0
- package/src/assets/datatype-icons/light-grey/date-time.svg +3 -0
- package/src/assets/datatype-icons/light-grey/definition-entity.svg +6 -0
- package/src/assets/datatype-icons/light-grey/list.svg +3 -0
- package/src/assets/datatype-icons/light-grey/null.svg +3 -0
- package/src/assets/datatype-icons/light-grey/number.svg +13 -0
- package/src/assets/datatype-icons/light-grey/project.svg +12 -0
- package/src/assets/datatype-icons/light-grey/sql-program.svg +2 -0
- package/src/assets/datatype-icons/light-grey/text.svg +3 -0
- package/src/assets/datatype-icons/light-grey/unknown.svg +3 -0
- package/src/assets/datatype-icons/light-grey/uuid.svg +4 -0
- package/src/assets/datatype-icons/light-grey/void.svg +1 -0
- package/src/assets/edit.png +0 -0
- package/src/assets/execution.svg +13 -0
- package/src/assets/favicon.svg +14 -0
- package/src/assets/file-search.svg +1 -0
- package/src/assets/http-endpoint.png +0 -0
- package/src/assets/image-input-placeholder.png +0 -0
- package/src/assets/logo-full-word-white.png +0 -0
- package/src/assets/logo-full-word.png +0 -0
- package/src/assets/password.svg +85 -0
- package/src/assets/pencil.png +0 -0
- package/src/assets/publish-project-rich-icon-2.svg +1 -0
- package/src/assets/publish-project-rich-icon.svg +1 -0
- package/src/assets/relational-database.png +0 -0
- package/src/assets/resources.svg +3 -0
- package/src/assets/resume-icon-14px.png +0 -0
- package/src/assets/server.png +0 -0
- package/src/assets/small-status/checkmark.svg +4 -0
- package/src/assets/small-status/error.svg +4 -0
- package/src/assets/small-status/loading.svg +4 -0
- package/src/assets/small-status/skipped.svg +11 -0
- package/src/assets/sql-connection-config.svg +1 -0
- package/src/assets/sql-row-transformer.svg +1 -0
- package/src/assets/ssl-certificate-config.svg +1 -0
- package/src/assets/sync.svg +1 -0
- package/src/assets/testing-logic-icon.svg +1 -0
- package/src/assets/versions.svg +25 -0
- package/src/assets/visual-programming-icon.svg +1 -0
- package/src/assets/warning-sign-24px.png +0 -0
- package/src/auth/index.ts +318 -0
- package/src/components/DialogLoader.tsx +94 -0
- package/src/components/EntityDialogHeader.tsx +110 -0
- package/src/components/EntityDialogSectionHeader.tsx +214 -0
- package/src/components/GalleryAddExternalIntegrationInfoDialog.tsx +87 -0
- package/src/components/GenerateProjectStartingLogicPromptDialog.tsx +281 -0
- package/src/components/LegacyRouteRedirector.tsx +55 -0
- package/src/components/ProPlanChip.tsx +23 -0
- package/src/components/ReportBugDialog.tsx +412 -0
- package/src/components/RequestIntegrationAccessDialog.tsx +261 -0
- package/src/components/UseTemplateProjectDialog.tsx +193 -0
- package/src/components/WorkspaceLayout.tsx +152 -0
- package/src/components/animated-svg/AnimatedCheckmark.tsx +41 -0
- package/src/components/animated-svg/AnimatedCrossmark.tsx +51 -0
- package/src/components/animated-svg/AnimatedEmailSending.tsx +38 -0
- package/src/components/animated-svg/AnimatedLoading.tsx +72 -0
- package/src/components/animated-svg/animated-svg.css +239 -0
- package/src/components/canvas/Canvas.tsx +16 -0
- package/src/components/canvas/CreateEntityMenu.tsx +2020 -0
- package/src/components/canvas/canvas.css +10 -0
- package/src/components/canvas/create-entity-menu.css +579 -0
- package/src/components/canvas-search/CanvasSearch.tsx +501 -0
- package/src/components/canvas-search/canvas-search.css +126 -0
- package/src/components/canvas-settings-menu/CanvasSettingsMenuButton.tsx +515 -0
- package/src/components/canvas-settings-menu/canvas-settings-menu.css +96 -0
- package/src/components/circular-image-upload/CircularImageUpload.tsx +113 -0
- package/src/components/circular-image-upload/circular-image-upload.css +69 -0
- package/src/components/costs/CostsDialog.tsx +459 -0
- package/src/components/data-type/DataTypeBuilder.tsx +3127 -0
- package/src/components/data-type/data-type-builder.css +45 -0
- package/src/components/dialogs/BetaAcknowledgeDialog.tsx +43 -0
- package/src/components/dialogs/ComplexDataDialog.tsx +458 -0
- package/src/components/dialogs/CronBuilderDialog.tsx +2145 -0
- package/src/components/dialogs/ExternalIntegrationConnections.tsx +565 -0
- package/src/components/dialogs/JsonEditorDialog.tsx +1392 -0
- package/src/components/dialogs/StringEditorDialog.tsx +268 -0
- package/src/components/dialogs/argument-declaration/ArgumentDeclaration.tsx +1167 -0
- package/src/components/dialogs/argument-declaration/ArgumentDeclarationDialogContent.tsx +128 -0
- package/src/components/dialogs/beta-dialog.css +165 -0
- package/src/components/dialogs/condition/Condition.tsx +431 -0
- package/src/components/dialogs/condition/ConditionDialogContent.tsx +126 -0
- package/src/components/dialogs/definition-entity/DefinitionEntityDialogContent.tsx +973 -0
- package/src/components/dialogs/function-call/FunctionCall.tsx +442 -0
- package/src/components/dialogs/function-call/FunctionCallDialogContent.tsx +126 -0
- package/src/components/dialogs/function-declaration/FunctionDeclaration.tsx +926 -0
- package/src/components/dialogs/function-declaration/FunctionDeclarationDialogContent.tsx +124 -0
- package/src/components/dialogs/generating-project-starting-logic-overlay/GeneratingProjectStartingLogicOverlay.tsx +176 -0
- package/src/components/dialogs/generating-project-starting-logic-overlay/generating-project-starting-logic-overlay.css +13 -0
- package/src/components/dialogs/global-event/GlobalEvent.tsx +475 -0
- package/src/components/dialogs/global-event/GlobalEventDialogContent.tsx +126 -0
- package/src/components/dialogs/help/HelpDialog.tsx +217 -0
- package/src/components/dialogs/help/HelpDilalogHomeContent.tsx +178 -0
- package/src/components/dialogs/help/help-dialog.css +116 -0
- package/src/components/dialogs/help/help-icon/HelpIconButton.tsx +41 -0
- package/src/components/dialogs/help/help-icon/help-icon.css +9 -0
- package/src/components/dialogs/input-map/InputMap.tsx +635 -0
- package/src/components/dialogs/input-map/InputMapDialogContent.tsx +126 -0
- package/src/components/dialogs/json-editor-dialog.css +4 -0
- package/src/components/dialogs/loop/Loop.tsx +650 -0
- package/src/components/dialogs/loop/LoopDialogContent.tsx +122 -0
- package/src/components/dialogs/operation/Operation.tsx +440 -0
- package/src/components/dialogs/operation/OperationDialogContent.tsx +126 -0
- package/src/components/dialogs/output-map/OutputMap.tsx +536 -0
- package/src/components/dialogs/output-map/OutputMapDialogContent.tsx +126 -0
- package/src/components/dialogs/property/Property.tsx +1490 -0
- package/src/components/dialogs/property/PropertyDialogContent.tsx +106 -0
- package/src/components/dialogs/search-statement/ColumnSelector.tsx +334 -0
- package/src/components/dialogs/search-statement/ConditionBuilder.tsx +750 -0
- package/src/components/dialogs/search-statement/DataAggregationSection.tsx +621 -0
- package/src/components/dialogs/search-statement/DataSourceSelection.tsx +734 -0
- package/src/components/dialogs/search-statement/EntityMetadataSection.tsx +135 -0
- package/src/components/dialogs/search-statement/FilterConditionsSection.tsx +151 -0
- package/src/components/dialogs/search-statement/InlineInputMap.tsx +153 -0
- package/src/components/dialogs/search-statement/LiteralValue.tsx +616 -0
- package/src/components/dialogs/search-statement/MainSourceAndInputsSection.tsx +271 -0
- package/src/components/dialogs/search-statement/NestedSearchStatementBuilder.tsx +170 -0
- package/src/components/dialogs/search-statement/OutputFormatSection.tsx +1779 -0
- package/src/components/dialogs/search-statement/ResultsSection.tsx +344 -0
- package/src/components/dialogs/search-statement/SearchStatementBuilder.tsx +251 -0
- package/src/components/dialogs/search-statement/SearchStatementDialogContent.tsx +398 -0
- package/src/components/dialogs/search-statement/ValueSelector.tsx +766 -0
- package/src/components/dialogs/search-statement/search-statement-context.tsx +1630 -0
- package/src/components/dialogs/search-statement/search-statement-dialog.css +56 -0
- package/src/components/dialogs/search-statement/test.sql +111 -0
- package/src/components/dialogs/value-descriptor/ValueDescriptor.tsx +824 -0
- package/src/components/dialogs/value-descriptor/ValueDescriptorDialogContent.tsx +124 -0
- package/src/components/dialogs/variable-declaration/VariableDeclaration.tsx +836 -0
- package/src/components/dialogs/variable-declaration/VariableDeclarationDialogContent.tsx +106 -0
- package/src/components/dialogs/variable-instance/VariableInstance.tsx +443 -0
- package/src/components/dialogs/variable-instance/VariableInstanceDialogContent.tsx +124 -0
- package/src/components/draggable-entity-card/ArgumentDeclaration.tsx +736 -0
- package/src/components/draggable-entity-card/CollapseEntityButton.tsx +170 -0
- package/src/components/draggable-entity-card/ConditionCard.tsx +1062 -0
- package/src/components/draggable-entity-card/ConnectionDeleteButton.tsx +309 -0
- package/src/components/draggable-entity-card/DataTypeIcon.tsx +624 -0
- package/src/components/draggable-entity-card/DraggableEntityCard.tsx +617 -0
- package/src/components/draggable-entity-card/ErrorMapProperty.tsx +464 -0
- package/src/components/draggable-entity-card/EventCard.tsx +700 -0
- package/src/components/draggable-entity-card/ExecutionInProgressValue.tsx +327 -0
- package/src/components/draggable-entity-card/FunctionDeclarationCard.tsx +819 -0
- package/src/components/draggable-entity-card/InputMapProperty.tsx +1067 -0
- package/src/components/draggable-entity-card/InternalCall.tsx +978 -0
- package/src/components/draggable-entity-card/InternalCallExecutionNode.tsx +643 -0
- package/src/components/draggable-entity-card/LogicScopeCallerNode.tsx +262 -0
- package/src/components/draggable-entity-card/LoopCard.tsx +791 -0
- package/src/components/draggable-entity-card/MainValueInput.tsx +523 -0
- package/src/components/draggable-entity-card/MainValueOutput.tsx +458 -0
- package/src/components/draggable-entity-card/MethodDeclaration.tsx +1088 -0
- package/src/components/draggable-entity-card/NestedCondition.tsx +1025 -0
- package/src/components/draggable-entity-card/OutputMapProperty.tsx +843 -0
- package/src/components/draggable-entity-card/PassthroughEntityCard.tsx +1247 -0
- package/src/components/draggable-entity-card/ReturnedError.tsx +549 -0
- package/src/components/draggable-entity-card/SmallSuccessFailureNodes.tsx +523 -0
- package/src/components/draggable-entity-card/SuccessFailureNodes.tsx +509 -0
- package/src/components/draggable-entity-card/TestEntityButton.tsx +946 -0
- package/src/components/draggable-entity-card/TestMenu.tsx +523 -0
- package/src/components/draggable-entity-card/TestMenuValidationDropdown.tsx +84 -0
- package/src/components/draggable-entity-card/UnreachableMarker.tsx +114 -0
- package/src/components/draggable-entity-card/VariableCard.tsx +1577 -0
- package/src/components/draggable-entity-card/VariableScopeMarker.tsx +117 -0
- package/src/components/draggable-entity-card/collapse-entity-button.css +44 -0
- package/src/components/draggable-entity-card/definition-entity/DefinitionEntityCard.tsx +1181 -0
- package/src/components/draggable-entity-card/definition-entity/DefinitionEntityIcon.tsx +36 -0
- package/src/components/draggable-entity-card/definition-entity/DefinitionEntityProperty.tsx +478 -0
- package/src/components/draggable-entity-card/definition-entity/DynamicFooterActions.tsx +112 -0
- package/src/components/draggable-entity-card/definition-entity/actions/external-integration-connection/ExportCredentialsFooterAction.tsx +461 -0
- package/src/components/draggable-entity-card/definition-entity/actions/external-integration-connection/RestablishConnectionFooterAction.tsx +199 -0
- package/src/components/draggable-entity-card/definition-entity/actions/external-integration-connection/restablish-connection-footer-action.css +85 -0
- package/src/components/draggable-entity-card/definition-entity/actions/google-drive/GoogleDriveFilePickerAPIFooterAction.tsx +277 -0
- package/src/components/draggable-entity-card/definition-entity/actions/google-drive/google-drive-file-picker-api-footer-action.css +107 -0
- package/src/components/draggable-entity-card/definition-entity/actions/persisted-entity/DatabaseFooterAction.tsx +452 -0
- package/src/components/draggable-entity-card/definition-entity/actions/persisted-entity/database-footer-action.css +86 -0
- package/src/components/draggable-entity-card/definition-entity/definition-entity-card.css +17 -0
- package/src/components/draggable-entity-card/draggable-entity-card.css +1140 -0
- package/src/components/draggable-entity-card/entity-locked-icon/EntityLockedIcon.tsx +133 -0
- package/src/components/draggable-entity-card/entity-locked-icon/entity-locked.css +8 -0
- package/src/components/draggable-entity-card/expand-properties-icon-button/ExpandPropertiesIconButton.tsx +84 -0
- package/src/components/draggable-entity-card/expand-properties-icon-button/expand-properties-icon-button.css +21 -0
- package/src/components/draggable-entity-card/implement-entity-icon/ImplementEntityIcon.tsx +74 -0
- package/src/components/draggable-entity-card/implement-entity-icon/implement-entity-icon.css +13 -0
- package/src/components/draggable-entity-card/logic-error/LogicErrorIconMenu.tsx +424 -0
- package/src/components/draggable-entity-card/logic-error/logic-error.css +23 -0
- package/src/components/draggable-entity-card/new-card-input-button/NewCardInputButton.tsx +193 -0
- package/src/components/draggable-entity-card/new-card-input-button/NewDynamicInputButton.tsx +214 -0
- package/src/components/draggable-entity-card/new-card-input-button/new-card-input-button.css +71 -0
- package/src/components/draggable-entity-card/new-card-output-button/NewCardOutputButton.tsx +192 -0
- package/src/components/draggable-entity-card/new-card-output-button/new-card-output-button.css +71 -0
- package/src/components/draggable-entity-card/termination-statement/TerminationStatementCard.tsx +1543 -0
- package/src/components/draggable-entity-card/termination-statement/termination-statement-card.css +17 -0
- package/src/components/draggable-entity-card/test-entity-button.css +55 -0
- package/src/components/draggable-entity-card/test-menu.css +181 -0
- package/src/components/draggable-entity-card/unreachable-marker.css +43 -0
- package/src/components/draggable-entity-card/variable-scope-marker.css +22 -0
- package/src/components/dynamic-value/DynamicValue.tsx +2395 -0
- package/src/components/dynamic-value/DynamicValueEntry.tsx +1957 -0
- package/src/components/dynamic-value/dynamic-value.css +230 -0
- package/src/components/editor/ElyxMonacoEditor.tsx +38 -0
- package/src/components/entity-error/EntityErrorListItem.tsx +47 -0
- package/src/components/entity-error/entity-error.css +198 -0
- package/src/components/entity-icon/EntityIcon.tsx +292 -0
- package/src/components/entity-icon/entity-icon.css +39 -0
- package/src/components/gallery-card/CreateNewProject.tsx +222 -0
- package/src/components/gallery-card/GalleryCard.tsx +171 -0
- package/src/components/gallery-card/MarketplaceCard.tsx +87 -0
- package/src/components/gallery-card/ProjectDuplicationCard.tsx +575 -0
- package/src/components/gallery-card/gallery-card.css +25 -0
- package/src/components/notifications/NotificationsIconButton.tsx +124 -0
- package/src/components/notifications/NotificationsPanel.tsx +385 -0
- package/src/components/notifications/notifications.css +189 -0
- package/src/components/online-users/LocalOnlineUsers.tsx +175 -0
- package/src/components/online-users/PageOnlineUsers.tsx +297 -0
- package/src/components/online-users/online-users.css +72 -0
- package/src/components/page-backdrop/PageBackdrop.tsx +8 -0
- package/src/components/page-backdrop/page-backdrop.css +7 -0
- package/src/components/project-configuration/DeleteProjectConfirmationDialog.tsx +134 -0
- package/src/components/project-configuration/ProjectConfigurationDialog.tsx +972 -0
- package/src/components/project-configuration/ProjectDataForm.tsx +121 -0
- package/src/components/project-configuration/UnpublishProjectConfirmationDialog.tsx +162 -0
- package/src/components/project-configuration/project-configuration-content.css +209 -0
- package/src/components/project-name/ProjectName.tsx +2025 -0
- package/src/components/project-name/project-name.css +599 -0
- package/src/components/publishing/Publication.tsx +133 -0
- package/src/components/publishing/history/PublicationHistoryContent.tsx +414 -0
- package/src/components/publishing/history/PublicationHistoryDialog.tsx +234 -0
- package/src/components/publishing/preview/PublicationPreviewDialog.tsx +1158 -0
- package/src/components/publishing/preview/PublishingPriceForecast.tsx +160 -0
- package/src/components/publishing/preview/PublishingResourcesDetails.tsx +91 -0
- package/src/components/publishing/publication-sequence/PublishingSequenceContent.tsx +375 -0
- package/src/components/publishing/publication-sequence/PublishingSequenceDialog.tsx +344 -0
- package/src/components/publishing/publishing-dialog.css +142 -0
- package/src/components/publishing/utils.ts +227 -0
- package/src/components/resources/ResourcesDialog.tsx +591 -0
- package/src/components/resources/UpgradeBanner.tsx +102 -0
- package/src/components/resources/codebase/CodebaseDetails.tsx +156 -0
- package/src/components/resources/cron-job/CronJobsList.tsx +532 -0
- package/src/components/resources/functions/FunctionsList.tsx +454 -0
- package/src/components/resources/http-api/HttpAPI.tsx +566 -0
- package/src/components/resources/http-api/HttpAPIClientModule.tsx +37 -0
- package/src/components/resources/logs/LogsViewer.tsx +768 -0
- package/src/components/resources/query.ts +74 -0
- package/src/components/resources/relational-database/DatabaseTable.tsx +905 -0
- package/src/components/resources/relational-database/RelationalDatabase.tsx +83 -0
- package/src/components/resources/relational-database/RelationalDatabaseSecrets.tsx +361 -0
- package/src/components/resources/resources-dialog.css +74 -0
- package/src/components/test-relational-database/DatabaseTable.tsx +913 -0
- package/src/components/test-relational-database/TestDatabaseDialogContent.tsx +670 -0
- package/src/components/test-relational-database/query.ts +74 -0
- package/src/components/toolbar/ToolBar.tsx +236 -0
- package/src/components/toolbar/toolbar.css +78 -0
- package/src/components/transaction-history/TransactionHistoryDialog.tsx +268 -0
- package/src/components/user/CurrentUserAvatar.tsx +65 -0
- package/src/components/user/UserChip.tsx +62 -0
- package/src/components/user/user.css +39 -0
- package/src/components/user-profile/ChangePasswordForm.tsx +67 -0
- package/src/components/user-profile/OwnUserProfileContent.tsx +665 -0
- package/src/components/user-profile/PublicUserProfileContent.tsx +99 -0
- package/src/components/user-profile/UserDataForm.tsx +75 -0
- package/src/components/user-profile/UserProfileDialog.tsx +110 -0
- package/src/components/user-profile/user-profile-content.css +25 -0
- package/src/config.ts +130 -0
- package/src/globals.d.ts +13 -0
- package/src/index.html +27 -0
- package/src/index.tsx +23 -0
- package/src/lib/badge/Badge.tsx +35 -0
- package/src/lib/badge/badge.css +32 -0
- package/src/lib/button/Button.tsx +129 -0
- package/src/lib/button/button.css +145 -0
- package/src/lib/canvas/canvas-undo-redo.ts +263 -0
- package/src/lib/canvas/defs.ts +170 -0
- package/src/lib/canvas/index.test.ts +189 -0
- package/src/lib/canvas/index.ts +6999 -0
- package/src/lib/canvas/utils.ts +59 -0
- package/src/lib/card/Card.tsx +62 -0
- package/src/lib/card/LoadingCard.tsx +82 -0
- package/src/lib/card/card.css +259 -0
- package/src/lib/chip/Chip.tsx +79 -0
- package/src/lib/chip/chip.css +0 -0
- package/src/lib/dialog/Dialog.tsx +122 -0
- package/src/lib/dialog/SmallDialog.tsx +61 -0
- package/src/lib/dialog/dialog.css +40 -0
- package/src/lib/display-data-structure/index.tsx +21 -0
- package/src/lib/dropdown/CanvasDropdownMenuCard.tsx +68 -0
- package/src/lib/dropdown/CanvasDropdownMenuCardOption.tsx +136 -0
- package/src/lib/dropdown/DropdownButton.tsx +104 -0
- package/src/lib/dropdown/DropdownMenuCard.tsx +324 -0
- package/src/lib/dropdown/DropdownMenuPopup.tsx +27 -0
- package/src/lib/dropdown/dropdown-button.css +76 -0
- package/src/lib/dropdown/dropdown-menu.css +151 -0
- package/src/lib/json-editor/RawJsonEditor.tsx +137 -0
- package/src/lib/json-editor/json-editor.css +35 -0
- package/src/lib/loader/Loader.tsx +120 -0
- package/src/lib/loader/loader.css +38 -0
- package/src/lib/pagination/Pagination.tsx +64 -0
- package/src/lib/popup/CanvasPopupBaseComponent.tsx +103 -0
- package/src/lib/popup/Popup.tsx +243 -0
- package/src/lib/popup/popup.css +16 -0
- package/src/lib/table/RowForm.tsx +301 -0
- package/src/lib/table/Table.tsx +1069 -0
- package/src/lib/table/table.css +249 -0
- package/src/lib/table/types.ts +108 -0
- package/src/lib/text-area/TextArea.tsx +183 -0
- package/src/lib/text-area/text-area.css +156 -0
- package/src/lib/text-field/TextField.tsx +218 -0
- package/src/lib/text-field/index.ts +8 -0
- package/src/lib/text-field/text-field.css +201 -0
- package/src/lib/tooltip/Tooltip.tsx +24 -0
- package/src/lib/tooltip/tooltip.css +17 -0
- package/src/localization/index.ts +47 -0
- package/src/main.css +343 -0
- package/src/pages/Auth.tsx +848 -0
- package/src/pages/Editor.tsx +883 -0
- package/src/pages/ErrorPage.tsx +179 -0
- package/src/pages/Gallery.tsx +1693 -0
- package/src/pages/NewPaymentMethodCallback.tsx +53 -0
- package/src/pages/NotFoundPage.tsx +126 -0
- package/src/pages/PricingPlans.tsx +155 -0
- package/src/pages/auth.css +304 -0
- package/src/pages/gallery.css +421 -0
- package/src/payments/index.ts +187 -0
- package/src/popup-notification/index.ts +90 -0
- package/src/services/database/index.ts +1 -0
- package/src/services/database/utils.ts +1301 -0
- package/src/services/editor/CanvasElement.tsx +2934 -0
- package/src/services/editor/CanvasElementConnectionDeleteButton.ts +204 -0
- package/src/services/editor/CanvasPopup.tsx +749 -0
- package/src/services/editor/EditorService.ts +8157 -0
- package/src/services/editor/area.ts +1312 -0
- package/src/services/editor/connections.ts +1019 -0
- package/src/services/editor/create/condition.ts +25 -0
- package/src/services/editor/create/definition-entity.ts +29 -0
- package/src/services/editor/create/function-call.ts +25 -0
- package/src/services/editor/create/global-event.ts +33 -0
- package/src/services/editor/create/loop.ts +25 -0
- package/src/services/editor/create/operation.ts +30 -0
- package/src/services/editor/create/utils.ts +140 -0
- package/src/services/editor/create/variable-declaration.ts +135 -0
- package/src/services/editor/create/variable-instance.ts +100 -0
- package/src/services/editor/editor-ui-extensions-context.ts +43 -0
- package/src/services/editor/entities-metadata.json +9310 -0
- package/src/services/editor/icons.ts +1093 -0
- package/src/services/editor/index.ts +1 -0
- package/src/services/editor/layout.ts +102 -0
- package/src/services/editor/modules/built-in-function-implementations/base.ts +14 -0
- package/src/services/editor/modules/built-in-function-implementations/create-persisted-entity/index.ts +56 -0
- package/src/services/editor/modules/built-in-function-implementations/delete-persisted-entity/index.ts +55 -0
- package/src/services/editor/modules/built-in-function-implementations/index.ts +4 -0
- package/src/services/editor/modules/built-in-function-implementations/update-persisted-entity/index.ts +56 -0
- package/src/services/editor/modules/operations-implementations/external-integrations/google-drive/get-files.ts +183 -0
- package/src/services/editor/modules/operations-implementations/external-integrations/google-drive/list-drives.ts +124 -0
- package/src/services/editor/modules/operations-implementations/external-integrations/google-drive/list-root-folders.ts +125 -0
- package/src/services/editor/modules/operations-implementations/external-integrations/google-drive/smart-fetch-document.ts +702 -0
- package/src/services/editor/modules/operations-implementations/external-integrations/google-drive/upload-document.ts +535 -0
- package/src/services/editor/modules/operations-implementations/external-integrations/google-gemini/generate-content.ts +193 -0
- package/src/services/editor/modules/operations-implementations/external-integrations/google-mail/get-emails.ts +586 -0
- package/src/services/editor/modules/operations-implementations/external-integrations/google-mail/send-email.ts +386 -0
- package/src/services/editor/modules/operations-implementations/external-integrations/index.ts +12 -0
- package/src/services/editor/modules/operations-implementations/external-integrations/slack/channels.ts +240 -0
- package/src/services/editor/modules/operations-implementations/external-integrations/slack/messages.ts +210 -0
- package/src/services/editor/modules/operations-implementations/external-integrations/slack/replies.ts +200 -0
- package/src/services/editor/modules/operations-implementations/external-integrations/slack/send-message.ts +177 -0
- package/src/services/editor/modules/operations-implementations/index.ts +1 -0
- package/src/services/editor/modules/search-node-implementation/index.ts +42 -0
- package/src/services/editor/modules/sql-migrations-generation.tsx +1054 -0
- package/src/services/editor/publication/publication.ts +578 -0
- package/src/services/editor/ui.ts +1348 -0
- package/src/services/editor/utils.ts +5868 -0
- package/src/services/editor/value-store.ts +619 -0
- package/src/services/execution/built-in-function-implementations.ts +422 -0
- package/src/services/execution/index.ts +4747 -0
- package/src/services/execution/logic.ts +121 -0
- package/src/services/execution/test-instance.tsx +2296 -0
- package/src/services/execution/utils.ts +33 -0
- package/src/services/execution/value-resolution.test.ts +424 -0
- package/src/services/execution/value-resolution.ts +4087 -0
- package/src/services/integrations/ExternalIntegrationsService.ts +439 -0
- package/src/services/integrations/api.ts +175 -0
- package/src/services/local-relational-database/idb_helper.ts +66 -0
- package/src/services/local-relational-database/index.ts +3308 -0
- package/src/services/local-relational-database/utils.ts +403 -0
- package/src/services/notifications/index.ts +525 -0
- package/src/services/user/index.ts +144 -0
- package/src/setupTests.ts +1 -0
- package/src/socket/socket.ts +248 -0
- package/src/socket/utils.ts +10 -0
- package/src/store/workspace.ts +12 -0
- package/src/theme.ts +19 -0
- package/src/utils/DOM.ts +39 -0
- package/src/utils/date.ts +169 -0
- package/src/utils/index.ts +158 -0
- package/src/utils/react.tsx +679 -0
- 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
|
+
}
|