@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,1392 @@
1
+ import React, {
2
+ useCallback,
3
+ useEffect,
4
+ useMemo,
5
+ useRef,
6
+ useState,
7
+ } from 'react';
8
+ import Button from '../../lib/button/Button';
9
+ import {
10
+ DataTypeState,
11
+ PrimitiveTypes,
12
+ LiteralValueState,
13
+ toCamelCase,
14
+ DefinitionEntityState,
15
+ ChangeSet,
16
+ ProjectState,
17
+ resolveDataTypeLabel,
18
+ EntityType,
19
+ resolveEntityDataTypeLabel,
20
+ resolveEntityName,
21
+ getParentCanvasEntity,
22
+ CANVAS_CARD_WIDTH,
23
+ calculateCardSize,
24
+ CANVAS_VERTICAL_BUFFER_BETWEEN_CARDS,
25
+ createDefinitionEntityFromJSONObject,
26
+ findEntityFromKeys,
27
+ EntityWithValueState,
28
+ READABLE_ENTITY_TYPES,
29
+ TERMINATION_TYPES,
30
+ lowercaseFirstLetter,
31
+ resolveEntityCodeName,
32
+ isObject,
33
+ StateMutationAction,
34
+ flattenDataTypeAndGroup,
35
+ flattenDataTypesInOrGroup,
36
+ } from '@elyx-code/project-logic-tree';
37
+ import FormatIconBlack from '../../assets/code-formatting/format-black.svg';
38
+ import FormatIconWhite from '../../assets/code-formatting/format-white.svg';
39
+ import InlineIconBlack from '../../assets/code-formatting/inline-black.svg';
40
+ import InlineIconWhite from '../../assets/code-formatting/inline-white.svg';
41
+ import './json-editor-dialog.css';
42
+ import { DraggableObject } from '../../lib/canvas';
43
+ import { getCanvasEntityDraggableContainerDOMId } from '../../services/editor/ui';
44
+ import {
45
+ DynamicValueTypes,
46
+ IValueStoreClient,
47
+ } from '../../services/editor/value-store';
48
+ import { EditorService } from '../../services/editor';
49
+ import { popupNotification } from '../../popup-notification';
50
+ import RawJsonEditor from '../../lib/json-editor/RawJsonEditor';
51
+ import {
52
+ Checkbox,
53
+ FormControl,
54
+ FormControlLabel,
55
+ IconButton,
56
+ InputLabel,
57
+ MenuItem,
58
+ OutlinedInput,
59
+ Select,
60
+ } from '@mui/material';
61
+ import {
62
+ castHTMLInputValueToType,
63
+ resolveInputTypeFromDataType,
64
+ } from '../../services/editor/utils';
65
+ import DropdownMenuPopup from '../../lib/dropdown/DropdownMenuPopup';
66
+ import JSONEditor, {
67
+ ExpandOptions,
68
+ ParseError,
69
+ SchemaValidationError,
70
+ } from 'jsoneditor';
71
+ import { JSONSchema7 } from 'json-schema';
72
+ import { handleLiteralValueChange } from '../../services/execution/value-resolution';
73
+ import { entitiesToUniqueCanvasEntities } from '../../services/editor/utils';
74
+ import { Logger } from '@elyx-code/common-ts-utils';
75
+ import DataTypeIcon, {
76
+ ExplicitDataTypeIcon,
77
+ } from '../draggable-entity-card/DataTypeIcon';
78
+ import DefinitionEntityIcon from '../draggable-entity-card/definition-entity/DefinitionEntityIcon';
79
+ import { resolveCardSubheader } from '../../services/editor/ui';
80
+ import {
81
+ fromLiteralValueTypeToFontColor,
82
+ fromLiteralValueTypeToExplicitIconName,
83
+ fromLiteralValueTypeToReadableLabel,
84
+ resolveLiteralValueSubheader,
85
+ } from '../data-type/DataTypeBuilder';
86
+
87
+ interface IJsonEditorDialogProps {
88
+ onClose: (event: React.MouseEvent) => void;
89
+ valueOwner: EntityWithValueState;
90
+ value?: LiteralValueState;
91
+ valueType?: DynamicValueTypes;
92
+ draggableObject: DraggableObject;
93
+ project: EditorService;
94
+ onlyDefault?: boolean;
95
+ }
96
+
97
+ function toJSONSchema(dataType: DataTypeState, title?: string): JSONSchema7 {
98
+ let jsonSchema: JSONSchema7 = {
99
+ // "$schema": "https://json-schema.org/draft-07/schema#",
100
+ title: title || resolveDataTypeLabel(dataType) || 'Unspecified data type',
101
+ };
102
+
103
+ if (!dataType) {
104
+ return jsonSchema;
105
+ }
106
+
107
+ let nestedSchemaUnderList = false;
108
+
109
+ if (dataType.isList) {
110
+ jsonSchema.type = 'array';
111
+ nestedSchemaUnderList = true;
112
+ }
113
+
114
+ if (
115
+ !dataType.entity &&
116
+ !dataType.andChildrenGroup?.length &&
117
+ !dataType.orChildrenGroup?.length
118
+ ) {
119
+ return jsonSchema;
120
+ }
121
+
122
+ let remainingSchema: JSONSchema7 = {};
123
+
124
+ if (dataType.entity) {
125
+ if (dataType.entity.type === EntityType.PrimitiveEntity) {
126
+ switch (dataType.entity.name) {
127
+ case PrimitiveTypes.Boolean:
128
+ remainingSchema.type = 'boolean';
129
+ break;
130
+ case PrimitiveTypes.Number:
131
+ remainingSchema.type = 'number';
132
+ break;
133
+ case PrimitiveTypes.String:
134
+ remainingSchema.type = 'string';
135
+ break;
136
+ case PrimitiveTypes.KeyValue:
137
+ remainingSchema.type = 'object';
138
+ break;
139
+ case PrimitiveTypes.Untyped:
140
+ delete remainingSchema.type;
141
+ break;
142
+ case PrimitiveTypes.Null:
143
+ remainingSchema.type = 'null';
144
+ break;
145
+ case PrimitiveTypes.Date:
146
+ remainingSchema.type = 'string';
147
+ remainingSchema.format = 'date-time';
148
+ break;
149
+ case PrimitiveTypes.Enum:
150
+ remainingSchema.type = 'string';
151
+ remainingSchema.enum = dataType.options;
152
+ break;
153
+ case PrimitiveTypes.UUID:
154
+ remainingSchema.type = 'string';
155
+ remainingSchema.format = 'uuid';
156
+ break;
157
+ case PrimitiveTypes.File:
158
+ remainingSchema.type = 'string';
159
+ remainingSchema.format = 'file';
160
+ break;
161
+ }
162
+ } else if (dataType.entity.type === EntityType.DefinitionEntity) {
163
+ if (dataType.asType) {
164
+ remainingSchema.type = 'object';
165
+ // Allow any other properties for now
166
+ remainingSchema.properties = {
167
+ id: { type: 'string' },
168
+ name: { type: 'string' },
169
+ // Literal string value
170
+ type: {
171
+ type: 'string',
172
+ enum: [EntityType.DefinitionEntity],
173
+ },
174
+ };
175
+ remainingSchema.additionalProperties = true;
176
+ remainingSchema.required = ['id', 'name', 'type'];
177
+ } else {
178
+ remainingSchema.type = 'object';
179
+ remainingSchema.properties = {};
180
+ remainingSchema.additionalProperties = false;
181
+ dataType.entity.properties.forEach((property) => {
182
+ const propertyDataType = property.getDataType(null);
183
+ const entityName = resolveEntityName(property, dataType.project);
184
+
185
+ const resolveCodeName =
186
+ property.codeName ||
187
+ (resolveEntityCodeName(property, dataType.project) as string) ||
188
+ lowercaseFirstLetter(toCamelCase(entityName));
189
+
190
+ remainingSchema.properties[resolveCodeName] =
191
+ toJSONSchema(propertyDataType);
192
+
193
+ // Because of how the sytem works, if the property is not required, we allow null values
194
+ if (!property.required) {
195
+ const existingPropertySchema = remainingSchema.properties[
196
+ resolveCodeName
197
+ ] as JSONSchema7;
198
+
199
+ if (existingPropertySchema) {
200
+ if (Array.isArray(existingPropertySchema.type)) {
201
+ // If it is already an array, we add null if not present
202
+ if (!existingPropertySchema.type.includes('null')) {
203
+ existingPropertySchema.type.push('null');
204
+ }
205
+ } else if (typeof existingPropertySchema.type === 'string') {
206
+ // If it is a string, we convert to array
207
+ if (existingPropertySchema.type !== 'null') {
208
+ existingPropertySchema.type = [
209
+ existingPropertySchema.type,
210
+ 'null',
211
+ ];
212
+ }
213
+ }
214
+ }
215
+ }
216
+ });
217
+
218
+ // Add required properties
219
+ remainingSchema.required = [];
220
+ dataType.entity.properties.forEach((property) => {
221
+ if (property.required) {
222
+ const entityName = resolveEntityName(property, dataType.project);
223
+
224
+ const resolveCodeName =
225
+ property.codeName ||
226
+ (resolveEntityCodeName(property, dataType.project) as string) ||
227
+ lowercaseFirstLetter(toCamelCase(entityName));
228
+
229
+ remainingSchema.required.push(resolveCodeName);
230
+ }
231
+ });
232
+ }
233
+ } else if (dataType.entity.type === EntityType.ActionDescriptor) {
234
+ remainingSchema.type = 'object';
235
+ // Allow any other properties for now
236
+ remainingSchema.properties = {
237
+ id: { type: 'string' },
238
+ name: { type: 'string' },
239
+ // Literal string value
240
+ type: {
241
+ type: 'string',
242
+ enum: [EntityType.ActionDescriptor],
243
+ },
244
+ };
245
+ remainingSchema.additionalProperties = true;
246
+ remainingSchema.required = ['id', 'name', 'type'];
247
+ }
248
+ } else if (!!dataType.andChildrenGroup?.length) {
249
+ remainingSchema.allOf = dataType.andChildrenGroup.map((child) =>
250
+ toJSONSchema(child),
251
+ );
252
+ } else if (!!dataType.orChildrenGroup?.length) {
253
+ remainingSchema.anyOf = dataType.orChildrenGroup.map((child) =>
254
+ toJSONSchema(child),
255
+ );
256
+ }
257
+
258
+ if (nestedSchemaUnderList) {
259
+ jsonSchema.items = remainingSchema;
260
+ } else {
261
+ jsonSchema = {
262
+ ...jsonSchema,
263
+ ...remainingSchema,
264
+ };
265
+ }
266
+
267
+ return jsonSchema;
268
+ }
269
+
270
+ const deducePrimitiveType = (literalValue?: LiteralValueState): PrimitiveTypes | null => {
271
+ if (!literalValue) return null;
272
+
273
+ const name = literalValue.name;
274
+ if (name && Object.values(PrimitiveTypes).includes(name)) {
275
+ if (name === PrimitiveTypes.KeyValue) {
276
+ return null;
277
+ }
278
+ return name;
279
+ }
280
+
281
+ const val = literalValue.value;
282
+ if (typeof val === 'string') {
283
+ return PrimitiveTypes.String;
284
+ }
285
+ if (typeof val === 'number') {
286
+ return PrimitiveTypes.Number;
287
+ }
288
+ if (typeof val === 'boolean') {
289
+ return PrimitiveTypes.Boolean;
290
+ }
291
+ if (val === null) {
292
+ return PrimitiveTypes.Null;
293
+ }
294
+ return null;
295
+ };
296
+
297
+ const getPrimitiveNameOfDataType = (dt: DataTypeState): PrimitiveTypes | null => {
298
+ let effective = dt;
299
+ if (dt.foreignKeyRef && !dt.entity) {
300
+ const refDataType = dt.foreignKeyRef.getDataType?.(null);
301
+ if (refDataType) {
302
+ const refResolved = flattenDataTypesInOrGroup(
303
+ flattenDataTypeAndGroup(refDataType),
304
+ { removeDuplicates: true, removeNulls: true },
305
+ ).filter((d) => !!d.isResolved);
306
+
307
+ if (refResolved.length === 1) {
308
+ effective = refResolved[0];
309
+ }
310
+ }
311
+ }
312
+ if (effective.entity?.type === EntityType.PrimitiveEntity) {
313
+ return effective.entity.name as PrimitiveTypes;
314
+ }
315
+ return null;
316
+ };
317
+
318
+ const JsonEditorDialog: React.FC<IJsonEditorDialogProps> = (props) => {
319
+ const onlyDefault = props.onlyDefault || false;
320
+ Logger.log(
321
+ 'Selected on mount before: ',
322
+ props.project.canvas?.selectedObjects,
323
+ );
324
+ props.project.canvas?.unselectAll();
325
+ Logger.log(
326
+ 'Selected on mount after: ',
327
+ props.project.canvas?.selectedObjects,
328
+ );
329
+
330
+ const valueOwnerCanvasParentEntity = getParentCanvasEntity(props.valueOwner);
331
+
332
+ const resolveSubHeaderText = () => {
333
+ let entityTypeDescription = '';
334
+
335
+ const parentEntityName = resolveEntityName(
336
+ valueOwnerCanvasParentEntity,
337
+ props.valueOwner.project,
338
+ );
339
+
340
+ const parentEntityDescriptor =
341
+ props.valueOwner.id !== valueOwnerCanvasParentEntity.id
342
+ ? ' of ' +
343
+ parentEntityName +
344
+ ' ' +
345
+ lowercaseFirstLetter(
346
+ READABLE_ENTITY_TYPES[valueOwnerCanvasParentEntity.type].singular,
347
+ )
348
+ : '';
349
+
350
+ switch (props.valueOwner.type) {
351
+ case EntityType.VariableDeclaration:
352
+ entityTypeDescription = 'Variable';
353
+ break;
354
+ case EntityType.ArgumentDeclaration:
355
+ entityTypeDescription = 'Input';
356
+ break;
357
+ case EntityType.InputMap: {
358
+ entityTypeDescription = 'Input';
359
+
360
+ if (TERMINATION_TYPES.includes(valueOwnerCanvasParentEntity.type)) {
361
+ entityTypeDescription = 'Output';
362
+ }
363
+ break;
364
+ }
365
+ case EntityType.OutputMap:
366
+ entityTypeDescription = 'Output';
367
+ break;
368
+ }
369
+
370
+ return entityTypeDescription + parentEntityDescriptor;
371
+ };
372
+
373
+ const valueOwnerDataType = props.valueOwner.getDataType(null);
374
+ const schema = toJSONSchema(valueOwnerDataType, resolveSubHeaderText());
375
+
376
+ const initialValue = JSON.stringify(props.value?.value || null, null, 2);
377
+
378
+ const [rawValue, setRawValue] = useState<string>(initialValue);
379
+ // ref of the editor
380
+ const editorRef = useRef<JSONEditor>(null);
381
+ const [editorErrors, setEditorErrors] = useState<
382
+ ReadonlyArray<SchemaValidationError | ParseError>
383
+ >([]);
384
+
385
+ // === Cast-to dropdown ====================================================
386
+ // For owners whose data-type is an `or`-group (e.g. `text | number`), we
387
+ // surface a small dropdown that lets the user pick a concrete subtype to
388
+ // edit as. The pick is local-only — it doesn't mutate the entity's
389
+ // data-type — it just swaps the JSON editor for the matching primitive
390
+ // input (like `DynamicValueEntry` does inline).
391
+ const castOptions = useMemo<DataTypeState[]>(() => {
392
+ const flat = flattenDataTypesInOrGroup(
393
+ flattenDataTypeAndGroup(valueOwnerDataType),
394
+ { removeDuplicates: true, removeNulls: false },
395
+ ).filter((dt) => !!dt.isResolved);
396
+
397
+ // Drop the trivial wrapping case where the owner is already a single
398
+ // resolved type (the cast dropdown would offer that same type only).
399
+ if (flat.length < 2) return [];
400
+
401
+ return flat;
402
+ }, [valueOwnerDataType]);
403
+
404
+ const initialCastDataType = useMemo<DataTypeState | null>(() => {
405
+ if (!props.value) return null;
406
+
407
+ const deducedType = deducePrimitiveType(props.value);
408
+ if (!deducedType) return null;
409
+
410
+ return castOptions.find((opt) => {
411
+ return getPrimitiveNameOfDataType(opt) === deducedType;
412
+ }) || null;
413
+ }, [props.value, castOptions]);
414
+
415
+ const [castDataType, setCastDataType] = useState<DataTypeState | null>(initialCastDataType);
416
+ const [castedValue, setCastedValue] = useState<
417
+ string | number | boolean | null
418
+ >(null);
419
+
420
+ const renderCastOption = (option: DataTypeState) => {
421
+ if (option.isList) {
422
+ return (
423
+ <span style={{ display: 'flex', flexDirection: 'column', gap: 2, padding: '4px 0' }}>
424
+ <span style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: '14px', fontWeight: 500 }}>
425
+ <ExplicitDataTypeIcon icon="list" size="small" id={option.id} />
426
+ {resolveCastOptionLabel(option)}
427
+ </span>
428
+ <p style={{ margin: 0, marginLeft: 24, fontSize: '11px', color: 'rgba(0,0,0,0.54)' }}>
429
+ List of values
430
+ </p>
431
+ </span>
432
+ );
433
+ }
434
+
435
+ if (option.foreignKeyRef) {
436
+ const foreignEntityName = resolveEntityName(option.foreignKeyRef, props.project.logic);
437
+ const foreignKeyParentName = resolveEntityName(option.foreignKeyRef.parent, props.project.logic);
438
+ const subLabel = `Reference to ${foreignEntityName} from ${foreignKeyParentName}`;
439
+
440
+ return (
441
+ <span style={{ display: 'flex', flexDirection: 'column', gap: 2, padding: '4px 0' }}>
442
+ <span style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: '14px', fontWeight: 500 }}>
443
+ <DataTypeIcon entity={option.foreignKeyRef} size="small" project={props.project} />
444
+ {resolveEntityName(option.foreignKeyRef, props.project.logic) || '-'}
445
+ </span>
446
+ <p style={{ margin: 0, marginLeft: 24, fontSize: '11px', color: 'rgba(0,0,0,0.54)' }}>
447
+ {subLabel}
448
+ </p>
449
+ </span>
450
+ );
451
+ }
452
+
453
+ if (option.entity) {
454
+ if (option.entity.type === EntityType.PrimitiveEntity) {
455
+ const primName = option.entity.name as PrimitiveTypes;
456
+ return (
457
+ <span style={{ display: 'flex', flexDirection: 'column', gap: 2, padding: '4px 0' }}>
458
+ <span
459
+ style={{
460
+ display: 'flex',
461
+ alignItems: 'center',
462
+ gap: 8,
463
+ color: fromLiteralValueTypeToFontColor(primName),
464
+ fontSize: '14px',
465
+ fontWeight: 500,
466
+ }}
467
+ >
468
+ <ExplicitDataTypeIcon
469
+ icon={fromLiteralValueTypeToExplicitIconName(primName)}
470
+ size="small"
471
+ id={option.entity.id}
472
+ />
473
+ {fromLiteralValueTypeToReadableLabel(primName)}
474
+ </span>
475
+ <p style={{ margin: 0, marginLeft: 24, fontSize: '11px', color: 'rgba(0,0,0,0.54)' }}>
476
+ {resolveLiteralValueSubheader(primName)}
477
+ </p>
478
+ </span>
479
+ );
480
+ }
481
+
482
+ if (
483
+ [
484
+ EntityType.ActionDescriptor,
485
+ EntityType.DefinitionEntity,
486
+ EntityType.BuiltInBaseEntity,
487
+ ].includes(option.entity.type as EntityType)
488
+ ) {
489
+ return (
490
+ <span style={{ display: 'flex', flexDirection: 'column', gap: 2, padding: '4px 0' }}>
491
+ <span style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: '14px', fontWeight: 500 }}>
492
+ <DefinitionEntityIcon
493
+ entity={option.entity as DefinitionEntityState}
494
+ size="small"
495
+ />
496
+ {resolveEntityName(option.entity, props.project.logic) || '-'}
497
+ </span>
498
+ <p style={{ margin: 0, marginLeft: 24, fontSize: '11px', color: 'rgba(0,0,0,0.54)' }}>
499
+ {resolveCardSubheader(option.entity as DefinitionEntityState) || 'Definition entity'}
500
+ </p>
501
+ </span>
502
+ );
503
+ }
504
+ }
505
+
506
+ return <span style={{ fontSize: '14px', fontWeight: 500 }}>{resolveCastOptionLabel(option)}</span>;
507
+ };
508
+
509
+ const renderSelectedCastOption = (option: DataTypeState) => {
510
+ if (option.isList) {
511
+ return (
512
+ <span style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: '14px', fontWeight: 500 }}>
513
+ <ExplicitDataTypeIcon icon="list" size="small" id={option.id} />
514
+ {resolveCastOptionLabel(option)}
515
+ </span>
516
+ );
517
+ }
518
+
519
+ if (option.foreignKeyRef) {
520
+ return (
521
+ <span style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: '14px', fontWeight: 500 }}>
522
+ <DataTypeIcon entity={option.foreignKeyRef} size="small" project={props.project} />
523
+ {resolveEntityName(option.foreignKeyRef, props.project.logic) || '-'}
524
+ </span>
525
+ );
526
+ }
527
+
528
+ if (option.entity) {
529
+ if (option.entity.type === EntityType.PrimitiveEntity) {
530
+ const primName = option.entity.name as PrimitiveTypes;
531
+ return (
532
+ <span
533
+ style={{
534
+ display: 'flex',
535
+ alignItems: 'center',
536
+ gap: 8,
537
+ color: fromLiteralValueTypeToFontColor(primName),
538
+ fontSize: '14px',
539
+ fontWeight: 500,
540
+ }}
541
+ >
542
+ <ExplicitDataTypeIcon
543
+ icon={fromLiteralValueTypeToExplicitIconName(primName)}
544
+ size="small"
545
+ id={option.entity.id}
546
+ />
547
+ {fromLiteralValueTypeToReadableLabel(primName)}
548
+ </span>
549
+ );
550
+ }
551
+
552
+ if (
553
+ [
554
+ EntityType.ActionDescriptor,
555
+ EntityType.DefinitionEntity,
556
+ EntityType.BuiltInBaseEntity,
557
+ ].includes(option.entity.type as EntityType)
558
+ ) {
559
+ return (
560
+ <span style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: '14px', fontWeight: 500 }}>
561
+ <DefinitionEntityIcon
562
+ entity={option.entity as DefinitionEntityState}
563
+ size="small"
564
+ />
565
+ {resolveEntityName(option.entity, props.project.logic) || '-'}
566
+ </span>
567
+ );
568
+ }
569
+ }
570
+
571
+ return <span style={{ fontSize: '14px', fontWeight: 500 }}>{resolveCastOptionLabel(option)}</span>;
572
+ };
573
+
574
+ // When the cast type changes, seed the local edited value from the current
575
+ // raw JSON, falling back to a sensible default (false / '' / null) when
576
+ // the existing value can't be coerced into the chosen primitive.
577
+ useEffect(() => {
578
+ if (!castDataType) return;
579
+
580
+ let parsed: unknown = null;
581
+ try {
582
+ parsed = JSON.parse(rawValue);
583
+ } catch (_) {
584
+ parsed = null;
585
+ }
586
+
587
+ const primitiveName =
588
+ castDataType.entity?.type === EntityType.PrimitiveEntity
589
+ ? (castDataType.entity.name as PrimitiveTypes)
590
+ : null;
591
+
592
+ const isCompatibleType = (() => {
593
+ switch (primitiveName) {
594
+ case PrimitiveTypes.Boolean:
595
+ return typeof parsed === 'boolean';
596
+ case PrimitiveTypes.Number:
597
+ return typeof parsed === 'number';
598
+ case PrimitiveTypes.Null:
599
+ return parsed === null;
600
+ case PrimitiveTypes.String:
601
+ case PrimitiveTypes.UUID:
602
+ case PrimitiveTypes.Date:
603
+ case PrimitiveTypes.Enum:
604
+ return typeof parsed === 'string';
605
+ default:
606
+ return false;
607
+ }
608
+ })();
609
+
610
+ if (isCompatibleType) {
611
+ setCastedValue(parsed as string | number | boolean | null);
612
+ } else {
613
+ switch (primitiveName) {
614
+ case PrimitiveTypes.Boolean:
615
+ setCastedValue(false);
616
+ break;
617
+ case PrimitiveTypes.Number:
618
+ setCastedValue(0);
619
+ break;
620
+ case PrimitiveTypes.Null:
621
+ setCastedValue(null);
622
+ break;
623
+ default:
624
+ setCastedValue('');
625
+ }
626
+ }
627
+ }, [castDataType]);
628
+
629
+ const resolveCastOptionLabel = (dt: DataTypeState): string => {
630
+ const label = resolveDataTypeLabel(dt);
631
+ return label || 'Unspecified data type';
632
+ };
633
+
634
+ const renderCastInput = () => {
635
+ if (!castDataType) return null;
636
+
637
+ // Same trick as `DynamicValueEntry`: if the cast target is a foreign-key
638
+ // reference, render the input that matches the referenced property's
639
+ // primitive entity (a UUID input, a number input, …).
640
+ let effectiveDataType: DataTypeState = castDataType;
641
+ if (castDataType.foreignKeyRef && !castDataType.entity) {
642
+ const refDataType = castDataType.foreignKeyRef.getDataType?.(null);
643
+ if (refDataType) {
644
+ const refResolved = flattenDataTypesInOrGroup(
645
+ flattenDataTypeAndGroup(refDataType),
646
+ { removeDuplicates: true, removeNulls: true },
647
+ ).filter((dt) => !!dt.isResolved);
648
+
649
+ if (refResolved.length === 1) {
650
+ effectiveDataType = refResolved[0];
651
+ }
652
+ }
653
+ }
654
+
655
+ const primitiveName =
656
+ effectiveDataType.entity?.type === EntityType.PrimitiveEntity
657
+ ? (effectiveDataType.entity.name as PrimitiveTypes)
658
+ : null;
659
+
660
+ if (primitiveName === PrimitiveTypes.Boolean) {
661
+ return (
662
+ <FormControlLabel
663
+ control={
664
+ <Checkbox
665
+ checked={castedValue === true}
666
+ onChange={(e) => setCastedValue(e.target.checked)}
667
+ />
668
+ }
669
+ label={castedValue ? 'true' : 'false'}
670
+ />
671
+ );
672
+ }
673
+
674
+ if (primitiveName === PrimitiveTypes.Null) {
675
+ return (
676
+ <p style={{ margin: 0, color: 'rgba(0,0,0,0.54)' }}>
677
+ This value will be saved as <code>null</code>.
678
+ </p>
679
+ );
680
+ }
681
+
682
+ if (
683
+ primitiveName === PrimitiveTypes.Enum &&
684
+ Array.isArray(effectiveDataType.options) &&
685
+ effectiveDataType.options.length
686
+ ) {
687
+ return (
688
+ <FormControl fullWidth>
689
+ <InputLabel id='cast-enum-label'>Value</InputLabel>
690
+ <Select
691
+ size='small'
692
+ labelId='cast-enum-label'
693
+ label='Value'
694
+ value={(castedValue as string) || ''}
695
+ onChange={(e) => setCastedValue(e.target.value as string)}
696
+ >
697
+ {effectiveDataType.options.map((option) => (
698
+ <MenuItem key={option} value={option}>
699
+ {option}
700
+ </MenuItem>
701
+ ))}
702
+ </Select>
703
+ </FormControl>
704
+ );
705
+ }
706
+
707
+ return (
708
+ <FormControl fullWidth>
709
+ <InputLabel htmlFor='cast-input'>Value</InputLabel>
710
+ <OutlinedInput
711
+ id='cast-input'
712
+ fullWidth
713
+ autoFocus
714
+ size='small'
715
+ label='Value'
716
+ type={resolveInputTypeFromDataType(effectiveDataType)}
717
+ value={castedValue ?? ''}
718
+ onChange={(e) => {
719
+ const sanitized = castHTMLInputValueToType(
720
+ e.target.value,
721
+ effectiveDataType,
722
+ );
723
+ setCastedValue(sanitized as string | number | boolean | null);
724
+ }}
725
+ />
726
+ </FormControl>
727
+ );
728
+ };
729
+
730
+ const handleOnNodeName = useCallback(
731
+ (nodeNameParams: any) => {
732
+ Logger.log('onNodeName', nodeNameParams);
733
+ const valueAsKnownValueAsType: any = nodeNameParams.value;
734
+
735
+ if (
736
+ !!valueAsKnownValueAsType &&
737
+ !!valueAsKnownValueAsType.type &&
738
+ [
739
+ EntityType.DefinitionEntity,
740
+ EntityType.FunctionDeclaration,
741
+ EntityType.Operation,
742
+ EntityType.FunctionCall,
743
+ EntityType.ActionDescriptor,
744
+ EntityType.BuiltInBaseEntity,
745
+ ].includes(valueAsKnownValueAsType.type)
746
+ ) {
747
+ // Note: We need to be careful with dependencies here.
748
+ // If props.project.logic changes, this function updates.
749
+ // The "Ref Proxy" in RawJsonEditor handles the update gracefully.
750
+ const resolvedEntityName = resolveEntityName(
751
+ valueAsKnownValueAsType,
752
+ props.project.logic,
753
+ );
754
+ if (!!resolvedEntityName) {
755
+ return 'Template of ' + resolvedEntityName;
756
+ } else {
757
+ return 'Template';
758
+ }
759
+ }
760
+ return undefined;
761
+ },
762
+ [props.project.logic],
763
+ ); // Dependency ensures it updates if logic changes
764
+
765
+ const handleOnChangeText = useCallback((value: string) => {
766
+ Logger.log('onChangeText', value);
767
+ setRawValue(value);
768
+ }, []);
769
+
770
+ // Based on the entity type, we resolve the header text
771
+ const resolveHeaderText = () => {
772
+ return resolveEntityName(props.valueOwner, props.valueOwner.project);
773
+ };
774
+
775
+ const isStrictObjectStructure =
776
+ valueOwnerDataType?.hasStrictObjectStructure();
777
+ const defaultValue = isStrictObjectStructure
778
+ ? (valueOwnerDataType.entity as DefinitionEntityState).getRawDefaultValue()
779
+ : null;
780
+
781
+ const isObjectStructure = valueOwnerDataType?.isObject();
782
+
783
+ const isUntyped =
784
+ !valueOwnerDataType ||
785
+ !valueOwnerDataType?.entity ||
786
+ valueOwnerDataType?.entity.name === PrimitiveTypes.Untyped;
787
+
788
+ const hasStrictObjectStructure =
789
+ valueOwnerDataType?.hasStrictObjectStructure();
790
+
791
+ const hasInlineDeclaredObjectDataTypeEntity =
792
+ !!valueOwnerDataType?.entity &&
793
+ valueOwnerDataType?.entity.type === EntityType.DefinitionEntity &&
794
+ valueOwnerDataType?.entity.parent?.id === valueOwnerDataType?.id;
795
+
796
+ const canInlineDeclaredObjectDataTypeEntityBeExplicit =
797
+ hasInlineDeclaredObjectDataTypeEntity &&
798
+ ![EntityType.Search, EntityType.Loop].includes(
799
+ props.valueOwner.parent?.type,
800
+ );
801
+
802
+ const keys =
803
+ !!props.value?.value &&
804
+ isObject(props.value?.value) &&
805
+ Object.keys(props.value?.value);
806
+
807
+ const existingGloballyDeclaredDefinitionEntity =
808
+ !!props.value?.value &&
809
+ isObject(props.value?.value) &&
810
+ findEntityFromKeys(keys, props.project.logic);
811
+
812
+ const showGoToDefinitionButton = !!existingGloballyDeclaredDefinitionEntity;
813
+
814
+ const showMakeDefinitionExplicitButton =
815
+ !existingGloballyDeclaredDefinitionEntity &&
816
+ canInlineDeclaredObjectDataTypeEntityBeExplicit &&
817
+ hasInlineDeclaredObjectDataTypeEntity;
818
+
819
+ const showCreateDefinitionEntityButton =
820
+ !showMakeDefinitionExplicitButton &&
821
+ (!valueOwnerDataType ||
822
+ (isObjectStructure && !hasStrictObjectStructure) ||
823
+ (isUntyped && isObject(props.value?.value)));
824
+
825
+ return (
826
+ <div
827
+ style={{
828
+ display: 'flex',
829
+ flexDirection: 'column',
830
+ height: '100%',
831
+ gap: '4px',
832
+ padding: '40px',
833
+ }}
834
+ >
835
+ {/* Header */}
836
+ <span>
837
+ <div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
838
+ <button
839
+ className='dialog_back_button'
840
+ onClick={(e) => {
841
+ props.onClose?.(e);
842
+ }}
843
+ >
844
+ <i className='fa-solid fa-arrow-left'></i>
845
+ </button>
846
+ <h1 style={{ margin: '0px', fontWeight: 500, fontSize: '28px' }}>
847
+ {resolveHeaderText()}
848
+ </h1>
849
+ </div>
850
+ <span style={{ display: 'flex', gap: '6px', marginLeft: '42px' }}>
851
+ <p style={{ margin: '0px', color: 'rgba(0,0,0,0.7)' }}>
852
+ {resolveSubHeaderText()}
853
+ </p>
854
+ </span>
855
+ </span>
856
+
857
+ <div
858
+ style={{
859
+ flex: 1,
860
+ margin: '16px 0',
861
+ // margin: '16px 42px',
862
+ overflow: 'scroll',
863
+ }}
864
+ >
865
+ <section
866
+ style={{
867
+ display: 'flex',
868
+ flexDirection: 'column',
869
+ height: '100%',
870
+ }}
871
+ >
872
+ <div
873
+ style={{
874
+ margin: '0 42px',
875
+ display: 'flex',
876
+ justifyContent: 'space-between',
877
+ alignItems: 'flex-end',
878
+ }}
879
+ >
880
+ <span
881
+ style={{
882
+ display: 'flex',
883
+ paddingTop: 6,
884
+ gap: 12,
885
+ }}
886
+ >
887
+ <span>
888
+ <span
889
+ style={{ display: 'flex', gap: '10px', alignItems: 'center' }}
890
+ >
891
+ <h3
892
+ style={{
893
+ display: 'flex',
894
+ gap: '6px',
895
+ fontWeight: 'normal',
896
+ margin: '0px',
897
+ }}
898
+ >
899
+ Value
900
+ </h3>
901
+ </span>
902
+ <p
903
+ style={{
904
+ margin: '0px',
905
+ fontSize: '14px',
906
+ marginTop: '6px',
907
+ color: 'rgba(0,0,0,0.54)',
908
+ marginBottom: '16px',
909
+ }}
910
+ >
911
+ {resolveEntityDataTypeLabel(props.valueOwner)}
912
+ </p>
913
+ </span>
914
+
915
+ {castOptions.length > 0 && (
916
+ <FormControl
917
+ size='small'
918
+ sx={{ minWidth: 180, marginRight: 1 }}
919
+ >
920
+ <InputLabel id='cast-data-type-label'>Edit as</InputLabel>
921
+ <Select
922
+ size='small'
923
+ labelId='cast-data-type-label'
924
+ label='Edit as'
925
+ value={castDataType?.id || ''}
926
+ renderValue={(value) => {
927
+ if (!value) {
928
+ return <em>Raw JSON</em>;
929
+ }
930
+ const picked = castOptions.find((opt) => opt.id === value);
931
+ if (!picked) return <em>Raw JSON</em>;
932
+ return renderSelectedCastOption(picked);
933
+ }}
934
+ onChange={(e) => {
935
+ const id = e.target.value as string;
936
+ if (!id) {
937
+ setCastDataType(null);
938
+ return;
939
+ }
940
+ const picked = castOptions.find((opt) => opt.id === id);
941
+ setCastDataType(picked || null);
942
+ }}
943
+ >
944
+ <MenuItem value=''>
945
+ <em>Raw JSON</em>
946
+ </MenuItem>
947
+ {castOptions.map((option) => (
948
+ <MenuItem key={option.id} value={option.id}>
949
+ {renderCastOption(option)}
950
+ </MenuItem>
951
+ ))}
952
+ </Select>
953
+ </FormControl>
954
+ )}
955
+ </span>
956
+
957
+ <IconButton
958
+ style={{ width: 30, height: 30 }}
959
+ onClick={() => {
960
+ Logger.log('clicked');
961
+ }}
962
+ size='small'
963
+ id='json-editor-options-menu'
964
+ >
965
+ <i className='fa-solid fa-bars'></i>
966
+ </IconButton>
967
+
968
+ {/* Menu dropdown */}
969
+ <DropdownMenuPopup
970
+ popupOptions={{
971
+ anchorQuerySelector: '#json-editor-options-menu',
972
+ placement: 'bottom-end',
973
+ }}
974
+ // Options for formatting the json and one of making it a single line
975
+ options={[
976
+ ...(isStrictObjectStructure
977
+ ? [
978
+ {
979
+ label: 'Regenerate initial value',
980
+ iconStartSrc: FormatIconBlack,
981
+ iconStartSrcHover: FormatIconWhite,
982
+ iconStartClasses:
983
+ 'json-editor-dialog-format-code-icons',
984
+ onClick: () => {
985
+ try {
986
+ const parsedExistingValue = JSON.parse(rawValue);
987
+
988
+ const objectExistingValue = isObject(
989
+ parsedExistingValue,
990
+ )
991
+ ? parsedExistingValue
992
+ : {};
993
+
994
+ // On the existing object, delete any keys that are not in the default value
995
+ Object.keys(objectExistingValue).forEach((key) => {
996
+ if (
997
+ !(
998
+ key in
999
+ (defaultValue as {
1000
+ [key: string]: any;
1001
+ })
1002
+ )
1003
+ ) {
1004
+ delete objectExistingValue[key];
1005
+ }
1006
+ });
1007
+
1008
+ setRawValue(
1009
+ JSON.stringify(
1010
+ {
1011
+ ...defaultValue,
1012
+ // Preserve existing values
1013
+ ...objectExistingValue,
1014
+ },
1015
+ null,
1016
+ 2,
1017
+ ),
1018
+ );
1019
+ } catch (e) {
1020
+ Logger.log('Invalid JSON');
1021
+ popupNotification({
1022
+ text: 'Invalid JSON',
1023
+ color: 'error',
1024
+ });
1025
+ }
1026
+ },
1027
+ },
1028
+ ]
1029
+ : []),
1030
+ {
1031
+ label: 'Format',
1032
+ iconStartSrc: FormatIconBlack,
1033
+ iconStartSrcHover: FormatIconWhite,
1034
+ iconStartClasses: 'json-editor-dialog-format-code-icons',
1035
+ onClick: () => {
1036
+ try {
1037
+ const parsed = JSON.parse(rawValue);
1038
+ setRawValue(JSON.stringify(parsed, null, 2));
1039
+ } catch (e) {
1040
+ Logger.log('Invalid JSON');
1041
+ popupNotification({
1042
+ text: 'Invalid JSON',
1043
+ color: 'error',
1044
+ });
1045
+ }
1046
+ },
1047
+ },
1048
+ {
1049
+ label: 'Single line',
1050
+ iconStartSrc: InlineIconBlack,
1051
+ iconStartSrcHover: InlineIconWhite,
1052
+ iconStartClasses: 'json-editor-dialog-format-code-icons',
1053
+ onClick: () => {
1054
+ try {
1055
+ const parsed = JSON.parse(rawValue);
1056
+ setRawValue(JSON.stringify(parsed));
1057
+ } catch (e) {
1058
+ Logger.log('Invalid JSON');
1059
+ popupNotification({
1060
+ text: 'Invalid JSON',
1061
+ color: 'error',
1062
+ });
1063
+ }
1064
+ },
1065
+ },
1066
+ {
1067
+ label: 'Copy',
1068
+ iconStart: 'fa-solid fa-clipboard',
1069
+ onClick: () => {
1070
+ navigator.clipboard.writeText(rawValue);
1071
+ popupNotification({
1072
+ text: 'Copied to clipboard',
1073
+ // color: 'success',
1074
+ });
1075
+ },
1076
+ },
1077
+ {
1078
+ label: 'Paste',
1079
+ iconStart: 'fa-solid fa-paste',
1080
+ onClick: () => {
1081
+ navigator.clipboard
1082
+ .readText()
1083
+ .then((text) => {
1084
+ Logger.log('Pasted text', text);
1085
+ setRawValue(text);
1086
+ })
1087
+ .catch((err) => {
1088
+ Logger.error('Failed to read clipboard', err);
1089
+ popupNotification({
1090
+ text: 'Failed to read clipboard',
1091
+ color: 'error',
1092
+ });
1093
+ });
1094
+ },
1095
+ },
1096
+ ]}
1097
+ />
1098
+ </div>
1099
+
1100
+ {castDataType ? (
1101
+ <div
1102
+ style={{
1103
+ margin: '0 42px',
1104
+ marginTop: 6,
1105
+ display: 'flex',
1106
+ flexDirection: 'column',
1107
+ gap: 12,
1108
+ }}
1109
+ >
1110
+ {renderCastInput()}
1111
+ </div>
1112
+ ) : (
1113
+ <RawJsonEditor
1114
+ schema={schema}
1115
+ text={rawValue}
1116
+ onExpand={(expandParams: ExpandOptions) => {
1117
+ Logger.log('onExpand', expandParams);
1118
+ }}
1119
+ onNodeName={handleOnNodeName}
1120
+ onReady={(editor: JSONEditor) => {
1121
+ editorRef.current = editor;
1122
+ }}
1123
+ onChangeText={handleOnChangeText}
1124
+ onValidationError={(
1125
+ errors: ReadonlyArray<SchemaValidationError | ParseError>,
1126
+ ) => {
1127
+ Logger.log(errors);
1128
+ setEditorErrors(errors);
1129
+ }}
1130
+ />
1131
+ )}
1132
+ </section>
1133
+ </div>
1134
+
1135
+ <section
1136
+ style={{
1137
+ alignSelf: 'flex-start',
1138
+ display: 'flex',
1139
+ flexDirection: 'row',
1140
+ justifyContent: 'flex-end',
1141
+ width: '100%',
1142
+ gap: '16px',
1143
+ }}
1144
+ >
1145
+ <Button
1146
+ onClick={(e: any) => {
1147
+ props.onClose?.(e);
1148
+ }}
1149
+ variant='text'
1150
+ >
1151
+ Back
1152
+ </Button>
1153
+ {showCreateDefinitionEntityButton && (
1154
+ <Button
1155
+ variant='outlined'
1156
+ onClick={async () => {
1157
+ const changeSet = props.project.logic.addChangeSet(
1158
+ new ChangeSet(
1159
+ props.project.logic,
1160
+ ProjectState.sessionAuthor,
1161
+ new Date().toISOString(),
1162
+ props.project.logic,
1163
+ false,
1164
+ StateMutationAction.CreateDefFromValue,
1165
+ ),
1166
+ );
1167
+
1168
+ const result = createDefinitionEntityFromJSONObject(
1169
+ props.value?.value as {
1170
+ [key: string]: any;
1171
+ },
1172
+ props.project.logic,
1173
+ {
1174
+ name:
1175
+ resolveEntityName(props.valueOwner, props.project.logic) +
1176
+ ' definition',
1177
+ },
1178
+ changeSet,
1179
+ );
1180
+
1181
+ const resolvedDefinitionEntity = result.changeSet.self;
1182
+
1183
+ if (result.hasCreated) {
1184
+ let newX = valueOwnerCanvasParentEntity.x;
1185
+ const newY =
1186
+ valueOwnerCanvasParentEntity.y -
1187
+ calculateCardSize(resolvedDefinitionEntity).height -
1188
+ CANVAS_VERTICAL_BUFFER_BETWEEN_CARDS;
1189
+
1190
+ const newCanvasEntities = entitiesToUniqueCanvasEntities(
1191
+ result.changeSet.added,
1192
+ );
1193
+
1194
+ // Give them a valid x and y coordinates
1195
+ newCanvasEntities.forEach((entity) => {
1196
+ newX += CANVAS_CARD_WIDTH * 2;
1197
+
1198
+ // @ts-ignore
1199
+ entity.metaSync(
1200
+ {
1201
+ x: newX,
1202
+ y: newY,
1203
+ },
1204
+ changeSet,
1205
+ );
1206
+ });
1207
+
1208
+ const objectId = getCanvasEntityDraggableContainerDOMId(
1209
+ resolvedDefinitionEntity,
1210
+ );
1211
+
1212
+ props.project.canvas?.scrollToObjectById(objectId, () => {
1213
+ props.onClose?.(null);
1214
+ });
1215
+ } else {
1216
+ // Create notification that the entity already exists
1217
+ // Then scroll to the entity
1218
+ popupNotification({
1219
+ text: 'Compatible entity already exists',
1220
+ color: 'warning',
1221
+ });
1222
+
1223
+ const canvasEntity = getParentCanvasEntity(
1224
+ resolvedDefinitionEntity,
1225
+ );
1226
+
1227
+ const objectId =
1228
+ getCanvasEntityDraggableContainerDOMId(canvasEntity);
1229
+
1230
+ props.project.canvas?.scrollToObjectById(objectId, () => {
1231
+ props.onClose?.(null);
1232
+ });
1233
+ }
1234
+
1235
+ props.project.renderAndCloseChangeSet(changeSet);
1236
+ }}
1237
+ >
1238
+ Create entity definition
1239
+ </Button>
1240
+ )}
1241
+ {showMakeDefinitionExplicitButton && (
1242
+ <Button
1243
+ variant='outlined'
1244
+ onClick={async () => {
1245
+ const changeSet = props.project.logic.addChangeSet(
1246
+ new ChangeSet(
1247
+ props.project.logic,
1248
+ ProjectState.sessionAuthor,
1249
+ new Date().toISOString(),
1250
+ props.project.logic,
1251
+ false,
1252
+ StateMutationAction.MoveInlineDefToCanvas,
1253
+ ),
1254
+ );
1255
+
1256
+ const existingInlineEntity =
1257
+ valueOwnerDataType?.entity as DefinitionEntityState;
1258
+
1259
+ existingInlineEntity.setParent(props.project.logic, changeSet);
1260
+ valueOwnerDataType.metaSync(
1261
+ {
1262
+ inferred: false,
1263
+ },
1264
+ changeSet,
1265
+ );
1266
+
1267
+ // if (result.hasCreated) {
1268
+ let newX = valueOwnerCanvasParentEntity.x;
1269
+ const newY =
1270
+ valueOwnerCanvasParentEntity.y -
1271
+ calculateCardSize(existingInlineEntity).height -
1272
+ CANVAS_VERTICAL_BUFFER_BETWEEN_CARDS;
1273
+
1274
+ const newCanvasEntities = entitiesToUniqueCanvasEntities([
1275
+ existingInlineEntity,
1276
+ ]);
1277
+
1278
+ // Give them a valid x and y coordinates
1279
+ newCanvasEntities.forEach((entity) => {
1280
+ newX += CANVAS_CARD_WIDTH * 2;
1281
+
1282
+ // @ts-ignore
1283
+ entity.metaSync(
1284
+ {
1285
+ x: newX,
1286
+ y: newY,
1287
+ },
1288
+ changeSet,
1289
+ );
1290
+ });
1291
+
1292
+ const objectId =
1293
+ getCanvasEntityDraggableContainerDOMId(existingInlineEntity);
1294
+
1295
+ props.project.canvas?.scrollToObjectById(objectId, () => {
1296
+ props.onClose?.(null);
1297
+ });
1298
+
1299
+ props.project.renderAndCloseChangeSet(changeSet);
1300
+ }}
1301
+ >
1302
+ Create entity definition
1303
+ </Button>
1304
+ )}
1305
+ {showGoToDefinitionButton && (
1306
+ <Button
1307
+ variant='outlined'
1308
+ onClick={(e: any) => {
1309
+ const canvasEntity = getParentCanvasEntity(
1310
+ valueOwnerDataType.entity,
1311
+ );
1312
+
1313
+ const objectId =
1314
+ getCanvasEntityDraggableContainerDOMId(canvasEntity);
1315
+
1316
+ props.project.canvas?.scrollToObjectById(objectId, () => {
1317
+ props.onClose?.(e);
1318
+ });
1319
+ }}
1320
+ >
1321
+ Go to definition
1322
+ </Button>
1323
+ )}
1324
+ <Button
1325
+ // Disabled if there are errors (the cast-input path produces
1326
+ // values pre-typed by the matching input field so it can't
1327
+ // have JSON validation errors).
1328
+ disabled={!castDataType && !!editorErrors.length}
1329
+ onClick={(e: any) => {
1330
+ let valueToSave: unknown;
1331
+
1332
+ if (castDataType) {
1333
+ valueToSave = castedValue;
1334
+ } else {
1335
+ Logger.log('Save value', rawValue);
1336
+ try {
1337
+ valueToSave = JSON.parse(rawValue);
1338
+ } catch (_) {
1339
+ valueToSave = null;
1340
+ }
1341
+ }
1342
+
1343
+ let storage: ChangeSet | IValueStoreClient =
1344
+ props.project.localTestValues;
1345
+
1346
+ if (onlyDefault) {
1347
+ storage = props.project.logic.addChangeSet(
1348
+ new ChangeSet(
1349
+ props.project.logic,
1350
+ ProjectState.sessionAuthor,
1351
+ new Date().toISOString(),
1352
+ props.valueOwner,
1353
+ false,
1354
+ StateMutationAction.SetPrimitiveDefaultValue,
1355
+ ),
1356
+ );
1357
+ }
1358
+
1359
+ const asCastedType = castDataType ? (getPrimitiveNameOfDataType(castDataType) || undefined) : undefined;
1360
+
1361
+ const changeSet = handleLiteralValueChange(
1362
+ valueToSave as any,
1363
+ props.valueOwner,
1364
+ props.project.logic,
1365
+ storage,
1366
+ asCastedType,
1367
+ );
1368
+
1369
+ if (!!changeSet) {
1370
+ props.project.renderAndCloseChangeSet(changeSet);
1371
+ }
1372
+
1373
+ // Update the owner of the value in the canvas
1374
+ props.project.emit(valueOwnerCanvasParentEntity.id, {});
1375
+
1376
+ // If there is a test ongoing, notify the test
1377
+ props.project.test?.validate();
1378
+
1379
+ // Close the dialog
1380
+ props.onClose?.(e);
1381
+ }}
1382
+ variant='contained'
1383
+ color='primary'
1384
+ >
1385
+ Save value
1386
+ </Button>
1387
+ </section>
1388
+ </div>
1389
+ );
1390
+ };
1391
+
1392
+ export default JsonEditorDialog;