@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,1693 @@
1
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
2
+ import { Route, Routes, useNavigate } from 'react-router-dom';
3
+ import * as YAML from 'yaml';
4
+ import { AuthModes } from '@nangohq/types';
5
+ import CreateNewProject from '../components/gallery-card/CreateNewProject';
6
+ import GalleryCard from '../components/gallery-card/GalleryCard';
7
+ import MarketplaceCard from '../components/gallery-card/MarketplaceCard';
8
+ import LoadingCard from '../lib/card/LoadingCard';
9
+ import PageBackdrop from '../components/page-backdrop/PageBackdrop';
10
+ import './gallery.css';
11
+ import Logo from '../assets/logo-full-word.png';
12
+ import CurrentUserAvatar from '../components/user/CurrentUserAvatar';
13
+ import {
14
+ getAccessToken,
15
+ getCurrentUserOrLogoutRedirect,
16
+ getRefreshToken
17
+ } from '../auth';
18
+ import Dialog from '../lib/dialog/Dialog';
19
+ import UserProfileDialog from '../components/user-profile/UserProfileDialog';
20
+ import {
21
+ IProject_meta,
22
+ joinListWithLastSeparator,
23
+ lowercaseFirstLetter,
24
+ toSentenceCase
25
+ } from '@elyx-code/project-logic-tree';
26
+ import { Notification } from '../services/notifications';
27
+ import { popupNotification } from '../popup-notification';
28
+ import ProjectDuplicationCard from '../components/gallery-card/ProjectDuplicationCard';
29
+ import axios from 'axios';
30
+ import dayjs from 'dayjs';
31
+ import { Socket } from '../socket/socket';
32
+ import GalleryAddExternalIntegrationInfoDialog from '../components/GalleryAddExternalIntegrationInfoDialog';
33
+ import { Logger } from '@elyx-code/common-ts-utils';
34
+ import {
35
+ DTOAction,
36
+ ILiveMessageDTO,
37
+ LiveMessageEventType
38
+ } from '@elyx-code/definitions';
39
+ import { envConfig } from '../config';
40
+ import UseTemplateProjectDialog from '../components/UseTemplateProjectDialog';
41
+ import { useWorkspaceStore } from '../store/workspace';
42
+ import { CircularProgress } from '@mui/material';
43
+ import RequestIntegrationAccessDialog from '../components/RequestIntegrationAccessDialog';
44
+ import { uuid } from 'short-uuid';
45
+ import { IChannelConnections } from '../services/editor';
46
+
47
+ export type ProjectMetadatAPIResponse = IProject_meta & {
48
+ media: { url: string; type: 'cover' | 'icon' }[];
49
+ };
50
+
51
+ export type Project = ProjectMetadatAPIResponse & {
52
+ assignedFallbackColor: number | null;
53
+ };
54
+
55
+ const ALREADY_SUPPORTED_INTEGRATIONS = [
56
+ 'slack',
57
+ 'google-mail',
58
+ 'google-drive',
59
+ 'google-gemini'
60
+ ];
61
+
62
+ const PAID_INTEGRATIONS = [
63
+ '1password-scim',
64
+ 'accelo',
65
+ 'active-campaign',
66
+ 'acuity-scheduling',
67
+ 'adobe',
68
+ 'adobe-umapi',
69
+ 'adp',
70
+ 'adyen',
71
+ 'affinity',
72
+ 'aircall',
73
+ 'aircall-basic',
74
+ 'airtable',
75
+ 'airtable-pat',
76
+ 'autodesk',
77
+ 'algolia',
78
+ 'amazon-selling-partner',
79
+ 'amazon-selling-partner-beta',
80
+ 'anrok',
81
+ 'amplitude',
82
+ 'anthropic-admin',
83
+ 'apaleo',
84
+ 'apollo',
85
+ 'apollo-oauth',
86
+ 'appstle-subscriptions',
87
+ 'asana',
88
+ 'asana-scim',
89
+ 'ashby',
90
+ 'atlas-so',
91
+ 'atlassian',
92
+ 'atlassian-admin',
93
+ 'attio',
94
+ 'auth0',
95
+ 'auth0-cc',
96
+ 'avalara',
97
+ 'avalara-sandbox',
98
+ 'aws',
99
+ 'aws-iam',
100
+ 'aws-scim',
101
+ 'azure-devops',
102
+ 'bamboohr',
103
+ 'bamboohr-basic',
104
+ 'basecamp',
105
+ 'beehiiv',
106
+ 'bigcommerce',
107
+ 'bill-sandbox',
108
+ 'bill',
109
+ 'bitbucket',
110
+ 'bitdefender',
111
+ 'blackbaud',
112
+ 'blackbaud-basic',
113
+ 'blandai',
114
+ 'boldsign',
115
+ 'box',
116
+ 'braintree',
117
+ 'braintree-sandbox',
118
+ 'braze',
119
+ 'brevo-api-key',
120
+ 'brex',
121
+ 'brex-api-key',
122
+ 'brex-staging',
123
+ 'brightcrowd',
124
+ 'builder-io-private',
125
+ 'builder-io-public',
126
+ 'buildium',
127
+ 'builtwith',
128
+ 'callrail',
129
+ 'canny',
130
+ 'canva-scim',
131
+ 'certn',
132
+ 'certn-partner',
133
+ 'chargebee',
134
+ 'chattermill',
135
+ 'checkhq',
136
+ 'checkr-partner',
137
+ 'checkr-partner-staging',
138
+ 'checkout-com',
139
+ 'checkout-com-sandbox',
140
+ 'chorus',
141
+ 'circle-so',
142
+ 'clari-copilot',
143
+ 'clicksend',
144
+ 'clickup',
145
+ 'cloudentity',
146
+ 'close',
147
+ 'codeclimate',
148
+ 'codegen',
149
+ 'commercetools',
150
+ 'companycam',
151
+ 'copper',
152
+ 'copper-api-key',
153
+ 'connectwise-psa',
154
+ 'connectwise-psa-staging',
155
+ 'confluence',
156
+ 'confluence-basic',
157
+ 'confluence-data-center',
158
+ 'contentful',
159
+ 'contentstack',
160
+ 'coupa-compass',
161
+ 'cyberimpact',
162
+ 'databricks-account',
163
+ 'databricks-workspace',
164
+ 'datev',
165
+ 'datadog',
166
+ 'deel',
167
+ 'deel-sandbox',
168
+ 'devin',
169
+ 'dialpad',
170
+ 'dialpad-sandbox',
171
+ 'digitalocean',
172
+ 'dixa',
173
+ 'document360',
174
+ 'docusign',
175
+ 'docusign-sandbox',
176
+ 'docuware',
177
+ 'dropbox-sign',
178
+ 'emarsys',
179
+ 'emarsys-oauth',
180
+ 'employment-hero',
181
+ 'e-conomic',
182
+ 'egnyte',
183
+ 'elevenlabs',
184
+ 'elevio',
185
+ 'entrata',
186
+ 'envoy',
187
+ 'evaluagent',
188
+ 'exa',
189
+ 'exact-online',
190
+ 'expensify',
191
+ 'factorial',
192
+ 'fathom',
193
+ 'figjam',
194
+ 'figma-scim',
195
+ 'falai',
196
+ 'findymail',
197
+ 'firefish',
198
+ 'fireflies',
199
+ 'fiserv',
200
+ 'fiserv-api-key',
201
+ 'fortnox',
202
+ 'freshbooks',
203
+ 'freshdesk',
204
+ 'freshsales',
205
+ 'freshservice',
206
+ 'freshteam',
207
+ 'front',
208
+ 'gainsight-cc',
209
+ 'gebruder-weiss',
210
+ 'gem',
211
+ 'grammarly-scim',
212
+ 'guru',
213
+ 'guru-scim',
214
+ 'gong',
215
+ 'gong-oauth',
216
+ 'google-ads',
217
+ 'google-cloud-storage',
218
+ 'gorgias',
219
+ 'gorgias-basic',
220
+ 'grafana',
221
+ 'grain',
222
+ 'grain-api-key',
223
+ 'greenhouse',
224
+ 'greenhouse-basic',
225
+ 'greenhouse-harvest',
226
+ 'greenhouse-job-board',
227
+ 'greenhouse-assessment',
228
+ 'greenhouse-ingestion',
229
+ 'greenhouse-onboarding',
230
+ 'gusto',
231
+ 'gusto-demo',
232
+ 'hackerrank-work',
233
+ 'harvest',
234
+ 'health-gorilla',
235
+ 'hibob-service-user',
236
+ 'highlevel',
237
+ 'highlevel-white-label',
238
+ 'holded',
239
+ 'hubspot',
240
+ 'incident-io',
241
+ 'insightly',
242
+ 'instantly',
243
+ 'intercom',
244
+ 'intuit',
245
+ 'jamf',
246
+ 'jamf-basic',
247
+ 'jazzhr',
248
+ 'jira',
249
+ 'jira-basic',
250
+ 'jira-data-center',
251
+ 'jira-data-center-api-key',
252
+ 'jira-data-center-basic',
253
+ 'jobadder',
254
+ 'jobvite',
255
+ 'helpscout-docs',
256
+ 'helpscout-mailbox',
257
+ 'kandji',
258
+ 'keap',
259
+ 'keeper-scim',
260
+ 'klipfolio',
261
+ 'klaviyo',
262
+ 'klaviyo-oauth',
263
+ 'kustomer',
264
+ 'lagrowthmachine',
265
+ 'lattice',
266
+ 'lessonly',
267
+ 'lemlist',
268
+ 'lever',
269
+ 'lever-basic',
270
+ 'lever-sandbox',
271
+ 'lever-basic-sandbox',
272
+ 'linear',
273
+ 'loom-scim',
274
+ 'loops-so',
275
+ 'lucid-scim',
276
+ 'make',
277
+ 'mailgun',
278
+ 'mailchimp',
279
+ 'manatal',
280
+ 'marketo',
281
+ 'malwarebytes',
282
+ 'medallia',
283
+ 'metabase',
284
+ 'microsoft-oauth2-cc',
285
+ 'microsoft-teams',
286
+ 'microsoft-tenant-specific',
287
+ 'microsoft-business-central',
288
+ 'microsoft-ads',
289
+ 'microsoft-entra-id',
290
+ 'microsoft-power-bi',
291
+ 'mindbody',
292
+ 'mip-cloud',
293
+ 'mip-on-premise',
294
+ 'mixpanel',
295
+ 'miro-scim',
296
+ 'missive',
297
+ 'monday',
298
+ 'mural',
299
+ 'nationbuilder',
300
+ 'namely',
301
+ 'namely-pat',
302
+ 'netsuite',
303
+ 'netsuite-tba',
304
+ 'notion-scim',
305
+ 'odoo',
306
+ 'odoo-cc',
307
+ 'okta',
308
+ 'okta-preview',
309
+ 'openai-admin',
310
+ 'oracle-hcm',
311
+ 'ory',
312
+ 'outreach',
313
+ 'pagerduty',
314
+ 'pandadoc',
315
+ 'pandadoc-api-key',
316
+ 'paychex',
317
+ 'payfit',
318
+ 'paylocity',
319
+ 'pendo',
320
+ 'pennylane',
321
+ 'peopledatalabs',
322
+ 'perplexity',
323
+ 'perimeter81',
324
+ 'personio',
325
+ 'personio-v2',
326
+ 'personio-recruiting',
327
+ 'pingboard',
328
+ 'pipedrive',
329
+ 'pivotaltracker',
330
+ 'plain',
331
+ 'podium',
332
+ 'posthog',
333
+ 'prive',
334
+ 'precisefp',
335
+ 'productboard',
336
+ 'qualtrics',
337
+ 'quickbase',
338
+ 'quickbooks',
339
+ 'quickbooks-sandbox',
340
+ 'ragieai',
341
+ 'ramp',
342
+ 'ramp-sandbox',
343
+ 'razorpay',
344
+ 'recharge',
345
+ 'recruitcrm',
346
+ 'recruiterflow',
347
+ 'redtail-crm-sandbox',
348
+ 'refiner',
349
+ 'replicate',
350
+ 'retell-ai',
351
+ 'ring-central',
352
+ 'ring-central-sandbox',
353
+ 'rippling',
354
+ 'rippling-shop-app',
355
+ 'roam-scim',
356
+ 'rock-gym-pro',
357
+ 'rootly',
358
+ 'segment',
359
+ 'sage',
360
+ 'sage-hr',
361
+ 'sage-intacct-oauth',
362
+ 'sage-intacct',
363
+ 'salesforce',
364
+ 'salesforce-sandbox',
365
+ 'salesforce-experience-cloud',
366
+ 'salesforce-cdp',
367
+ 'sap-concur',
368
+ 'sap-success-factors',
369
+ 'scrapedo',
370
+ 'salesloft',
371
+ 'sendgrid',
372
+ 'sentry',
373
+ 'sentry-oauth',
374
+ 'sedna',
375
+ 'sedna-basic',
376
+ 'servicem8',
377
+ 'signnow',
378
+ 'signnow-sandbox',
379
+ 'servicenow',
380
+ 'sharepoint-online',
381
+ 'sharepoint-online-oauth2-cc',
382
+ 'sharepoint-online-v1',
383
+ 'shipstation',
384
+ 'shopify',
385
+ 'shopify-api-key',
386
+ 'shopify-partner',
387
+ 'shopify-scim',
388
+ 'shortcut',
389
+ 'slack',
390
+ 'smartlead-ai',
391
+ 'smartrecruiters-api-key',
392
+ 'smartsheet',
393
+ 'snowflake',
394
+ 'snowflake-jwt',
395
+ 'spotify-oauth2-cc',
396
+ 'squarespace',
397
+ 'squareup',
398
+ 'squareup-sandbox',
399
+ 'stripe',
400
+ 'stripe-express',
401
+ 'stripe-app',
402
+ 'stripe-app-sandbox',
403
+ 'supabase',
404
+ 'tapclicks',
405
+ 'tableau',
406
+ 'teamtailor',
407
+ 'teamwork',
408
+ 'terraform',
409
+ 'tiktok-ads',
410
+ 'timely',
411
+ 'thrivecart-oauth',
412
+ 'thrivecart-api-key',
413
+ 'trakstar-hire',
414
+ 'trafft',
415
+ 'tremendous',
416
+ 'tremendous-sandbox',
417
+ 'trello-scim',
418
+ 'tldv',
419
+ 'tsheetsteam',
420
+ 'twitter-oauth2-cc',
421
+ 'twinfield',
422
+ 'twenty-crm',
423
+ 'twenty-crm-self-hosted',
424
+ 'twilio',
425
+ 'ukg-pro-wfm',
426
+ 'ukg-pro',
427
+ 'ukg-ready',
428
+ 'unanet',
429
+ 'unipile',
430
+ 'vercel',
431
+ 'wave-accounting',
432
+ 'wealthbox',
433
+ 'webflow',
434
+ 'whatsapp-business',
435
+ 'wildix-pbx',
436
+ 'woocommerce',
437
+ 'workable',
438
+ 'workable-oauth',
439
+ 'workday',
440
+ 'workday-oauth',
441
+ 'wrike',
442
+ 'xai',
443
+ 'xero',
444
+ 'xero-oauth2-cc',
445
+ 'zapier',
446
+ 'zapier-nla',
447
+ 'zapier-scim',
448
+ 'zendesk',
449
+ 'zenefits',
450
+ 'zoho',
451
+ 'zoho-books',
452
+ 'zoho-crm',
453
+ 'zoho-desk',
454
+ 'zoho-inventory',
455
+ 'zoho-invoice',
456
+ 'zoho-mail',
457
+ 'zoho-bigin',
458
+ 'zoho-people',
459
+ 'zoominfo',
460
+ 'zuora'
461
+ ];
462
+
463
+ export interface IProxyConfig {
464
+ base_url: string;
465
+ headers?: Record<string, string>;
466
+ verification?: { method: string; endpoints: string[] };
467
+ retry?: {
468
+ after?: string;
469
+ in_body?: { path: string; value: string; strategy: string };
470
+ };
471
+ paginate?:
472
+ | {
473
+ type: 'link';
474
+ link_rel_in_response_header: string;
475
+ limit_name_in_request: string;
476
+ response_path: string;
477
+ link_path_in_response_body: string;
478
+ }
479
+ | {
480
+ type: 'cursor';
481
+ cursor_path_in_response: string;
482
+ limit_name_in_request: string;
483
+ cursor_name_in_request: string;
484
+ response_path: string;
485
+ };
486
+ connection_config?: Record<string, string>;
487
+ }
488
+
489
+ export interface IConnectionConfigProperty {
490
+ type: string;
491
+ title?: string;
492
+ description?: string;
493
+ example?: string;
494
+ pattern?: string;
495
+ prefix?: string;
496
+ suffix?: string;
497
+ doc_section?: string;
498
+ optional?: boolean;
499
+ order?: number;
500
+ }
501
+
502
+ export interface ICredentialProperty {
503
+ type: string;
504
+ title?: string;
505
+ description?: string;
506
+ secret?: boolean;
507
+ format?: string;
508
+ example?: string;
509
+ pattern?: string;
510
+ doc_section?: string;
511
+ }
512
+
513
+ export interface IFullIntegrationProvider {
514
+ display_name: string;
515
+ alias?: string;
516
+ categories: string[];
517
+ docs: string;
518
+ docs_connect?: string;
519
+ auth_mode?: AuthModes;
520
+ credentials?: Record<string, ICredentialProperty>;
521
+ authorization_url?: string;
522
+ token_url?: string;
523
+ default_scopes?: string[];
524
+ scope_separator?: string;
525
+ authorization_params?: Record<string, string>;
526
+ token_params?: Record<string, string>;
527
+ refresh_params?: Record<string, string>;
528
+ token_request_auth_method?: string;
529
+ authorization_method?: string;
530
+ connection_configuration?: string[];
531
+ proxy?: IProxyConfig;
532
+ post_connection_script?: string;
533
+ webhook_routing_script?: string;
534
+ connection_config?: Record<string, IConnectionConfigProperty>;
535
+ }
536
+
537
+ export type FullProviderMap = Record<string, IFullIntegrationProvider>;
538
+
539
+ const convertToPattern = (num: number) => {
540
+ const remainder = num % 5;
541
+ return remainder === 0 ? 5 : remainder;
542
+ };
543
+
544
+ let sessionId: string | null = null;
545
+ let pastSessionIds: Set<string> = new Set();
546
+ let peerConnections: Record<string, IChannelConnections> = {};
547
+
548
+ const Gallery: React.FC<{ socket: Socket }> = ({ socket }) => {
549
+ const [projects, setProjects] = useState<Project[]>([]);
550
+ const [totalProjectCount, setTotalProjectCount] = useState<number>(-1);
551
+ const [templates, setTemplates] = useState<Project[]>([]);
552
+ const [cloning, setCloning] = useState<Project[]>([]);
553
+ const [loadingOwnProjects, setLoadingOwnProjects] =
554
+ useState<boolean>(false);
555
+ const [loadingTemplates, setLoadingTemplates] = useState<boolean>(false);
556
+ const [openTemplate, setOpenTemplate] = useState<Project | null>(null);
557
+ const [loadingExternalIntegrations, setLoadingExternalIntegrations] =
558
+ useState<boolean>(false);
559
+ const [externalIntegrations, setExternalIntegrations] =
560
+ useState<FullProviderMap>({});
561
+ const [offset, setOffset] = useState<number>(0);
562
+
563
+ // marketplace search UI state
564
+ const [showMarketplaceSearch, setShowMarketplaceSearch] = useState(false);
565
+ const [marketplaceQuery, setMarketplaceQuery] = useState('');
566
+ const [requestingIntegration, setRequestingIntegration] = useState<{
567
+ key: string;
568
+ name: string;
569
+ } | null>(null);
570
+ const [requestedIntegrations, setRequestedIntegrations] = useState<
571
+ Set<string>
572
+ >(new Set());
573
+
574
+ // project search and view layout state
575
+ const [userId, setUserId] = useState<string | null>(null);
576
+ const [viewMode, setViewMode] = useState<'grid' | 'rows'>('grid');
577
+ const [projectQuery, setProjectQuery] = useState('');
578
+ const [showProjectSearch, setShowProjectSearch] = useState(false);
579
+ const [debouncedQuery, setDebouncedQuery] = useState('');
580
+
581
+ const activeWorkspace = useWorkspaceStore((state) => state.activeWorkspace);
582
+
583
+ const navigate = useNavigate();
584
+ Notification.navigate = navigate;
585
+
586
+ const handleNotificationChannelsMessage = useCallback(
587
+ (message: ILiveMessageDTO): void => {
588
+ Logger.log('detected subscribed-channels: ', message.payload);
589
+ const data: { channels: IChannelConnections[] } =
590
+ message.payload as {
591
+ channels: IChannelConnections[];
592
+ };
593
+
594
+ if (
595
+ message.action === DTOAction.SubscribeChannelsV1 &&
596
+ message.event === 'subscribed-channels'
597
+ ) {
598
+ if (message.sessionId && sessionId !== message.sessionId) {
599
+ if (sessionId) {
600
+ pastSessionIds.add(sessionId);
601
+ }
602
+ sessionId = message.sessionId;
603
+ }
604
+ }
605
+
606
+ if (!!data?.channels && Array.isArray(data.channels)) {
607
+ peerConnections = data.channels.reduce(
608
+ (acc: { [key: string]: IChannelConnections }, channel) => {
609
+ acc[channel.channel] = channel;
610
+ return acc;
611
+ },
612
+ {}
613
+ );
614
+
615
+ // this.emit('peer-connections-updated', peerConnections);
616
+ }
617
+
618
+ // Add the payload to the state
619
+ // if (message.event === 'subscribed-channels') {
620
+ // } else if (message.event === 'new-connection') {
621
+ // peerConnections = data.channels.reduce(
622
+ // (acc: { [key: string]: IChannelConnections }, channel) => {
623
+ // acc[channel.channel] = channel;
624
+ // return acc;
625
+ // },
626
+ // {}
627
+ // );
628
+
629
+ // this.emit(
630
+ // 'peer-connections-updated',
631
+ // peerConnections
632
+ // );
633
+ // }
634
+
635
+ Logger.log('Updated peerConnections: ', peerConnections);
636
+
637
+ return;
638
+ },
639
+ []
640
+ );
641
+
642
+ const handleIncommingWebsocketMessage = useCallback(
643
+ (message: ILiveMessageDTO) => {
644
+ // Logger.log('Generic editor message callback: ', message);
645
+
646
+ let action: string = message.action || message.event;
647
+
648
+ switch (action) {
649
+ case DTOAction.PeerDisconnectedV1:
650
+ case DTOAction.ReconnectSessionV1:
651
+ case DTOAction.SubscribeChannelsV1: {
652
+ handleNotificationChannelsMessage(message);
653
+ return;
654
+ }
655
+ }
656
+ },
657
+ [handleNotificationChannelsMessage]
658
+ );
659
+
660
+ const subscribeToProjectNotificationsChannel = useCallback(async () => {
661
+ const userId = (await getCurrentUserOrLogoutRedirect())?.id;
662
+
663
+ const [accessToken, refreshToken] = await Promise.all([
664
+ getAccessToken(),
665
+ getRefreshToken()
666
+ ]);
667
+
668
+ await socket.send({
669
+ action: DTOAction.SubscribeChannelsV1,
670
+ actionId: uuid(),
671
+ userAuthor: userId,
672
+ agentAuthor: null,
673
+ emittedAt: new Date().toISOString(),
674
+ channel: `gallery--${userId}`,
675
+ sessionId: sessionId as string,
676
+ authorization: 'Bearer ' + accessToken,
677
+ refreshToken: refreshToken,
678
+ type: LiveMessageEventType.Post,
679
+ workspaceId: activeWorkspace?.id,
680
+ event: null,
681
+ message: null,
682
+ payload: {
683
+ channels: [`gallery--${userId}`]
684
+ }
685
+ });
686
+ }, [socket]);
687
+
688
+ const handleReconnectingWebsocket = useCallback(async () => {
689
+ Logger.log('Reconnecting websocket...');
690
+
691
+ // // Show notification
692
+ // popupNotification({
693
+ // color: 'warning',
694
+ // text: 'Reconnecting session...',
695
+ // });
696
+
697
+ await subscribeToProjectNotificationsChannel();
698
+
699
+ // Send message to reconnect
700
+ // this.socket.send({
701
+ // action: DTOAction.ReconnectSessionV1,
702
+ // actionId: ProjectState.UUID.uuid(),
703
+ // userAuthor: ProjectState.sessionAuthor,
704
+ // agentAuthor: null,
705
+ // emittedAt: new Date().toISOString(),
706
+ // channel: this.PROJECT_NOTIFICATIONS_CHANNEL,
707
+ // sessionId: this.sessionId as string,
708
+ // authorization: 'Bearer ' + (await this.getAccessToken()),
709
+ // type: LiveMessageEventType.Post,
710
+ // event: null,
711
+ // message: null,
712
+ // payload: null,
713
+ // });
714
+ }, [subscribeToProjectNotificationsChannel]);
715
+
716
+ useEffect(() => {
717
+ const timer = setTimeout(() => {
718
+ setDebouncedQuery(projectQuery);
719
+ }, 300);
720
+ return () => clearTimeout(timer);
721
+ }, [projectQuery]);
722
+
723
+ useEffect(() => {
724
+ setOffset(0);
725
+ }, [debouncedQuery]);
726
+
727
+ const fetchProjectsData = useCallback(
728
+ async (currentOffset: number, query: string, append: boolean) => {
729
+ setLoadingOwnProjects(true);
730
+ if (!append) {
731
+ setProjects([]);
732
+ }
733
+ try {
734
+ const token = await getAccessToken();
735
+ const response = await axios.get(
736
+ `${envConfig.API_BASE_URL}/editor-service/v1/projects?limit=15&offset=${currentOffset}&search=${encodeURIComponent(query)}`,
737
+ {
738
+ headers: {
739
+ Authorization: 'Bearer ' + token
740
+ }
741
+ }
742
+ );
743
+
744
+ const fetched = (response?.data?.items || []).map(
745
+ (project: ProjectMetadatAPIResponse, i: number) => ({
746
+ ...project,
747
+ assignedFallbackColor: !(project.media || []).length
748
+ ? convertToPattern(currentOffset + i + 1)
749
+ : null
750
+ })
751
+ ) as Project[];
752
+
753
+ setProjects((prev) => {
754
+ if (append) {
755
+ const existingIds = new Set(prev.map((p) => p.id));
756
+ const filteredNew = fetched.filter(
757
+ (p) => !existingIds.has(p.id)
758
+ );
759
+ return [...prev, ...filteredNew];
760
+ }
761
+ return fetched;
762
+ });
763
+ setTotalProjectCount(response?.data?.total ?? -1);
764
+ } catch (error) {
765
+ Logger.error('error', error);
766
+ popupNotification({
767
+ text: 'Error loading projects. Please try again.',
768
+ color: 'error'
769
+ });
770
+ }
771
+
772
+ setLoadingOwnProjects(false);
773
+ },
774
+ []
775
+ );
776
+
777
+ useEffect(() => {
778
+ fetchProjectsData(offset, debouncedQuery, offset > 0);
779
+ }, [offset, debouncedQuery, fetchProjectsData]);
780
+
781
+ useEffect(() => {
782
+ if (userId && activeWorkspace?.id) {
783
+ const key = `gallery-view-preference:${userId}:${activeWorkspace.id}`;
784
+ const stored = localStorage.getItem(key);
785
+ if (stored === 'rows' || stored === 'grid') {
786
+ setViewMode(stored as 'grid' | 'rows');
787
+ }
788
+ }
789
+ }, [userId, activeWorkspace?.id]);
790
+
791
+ const handleViewModeChange = (mode: 'grid' | 'rows') => {
792
+ setViewMode(mode);
793
+ if (userId && activeWorkspace?.id) {
794
+ const key = `gallery-view-preference:${userId}:${activeWorkspace.id}`;
795
+ localStorage.setItem(key, mode);
796
+ }
797
+ };
798
+
799
+ useEffect(() => {
800
+ const fetchUser = async () => {
801
+ try {
802
+ const u = await getCurrentUserOrLogoutRedirect();
803
+ if (u?.id) {
804
+ setUserId(u.id);
805
+ }
806
+ } catch (err) {
807
+ Logger.error('Failed to fetch user', err);
808
+ }
809
+ };
810
+
811
+ const fetchExternalIntegrationsData = async () => {
812
+ setLoadingExternalIntegrations(true);
813
+ try {
814
+ const response = await axios.get(
815
+ `${envConfig.PUBLIC_EXTERNAL_INTEGRATIONS_URL}/providers.yaml`,
816
+ { responseType: 'text' }
817
+ );
818
+ const parsed = YAML.parse(response.data);
819
+ setExternalIntegrations(parsed as FullProviderMap);
820
+ } catch (error) {
821
+ Logger.error('error', error);
822
+ }
823
+
824
+ setLoadingExternalIntegrations(false);
825
+ };
826
+
827
+ const fetchRequestedIntegrations = async () => {
828
+ if (!activeWorkspace?.id) return;
829
+ try {
830
+ const token = await getAccessToken();
831
+ const res = await axios.get(
832
+ `${envConfig.API_BASE_URL}/support-service/v1/cases?type=access-request&workspaceId=${activeWorkspace.id}`,
833
+ {
834
+ headers: { Authorization: 'Bearer ' + token }
835
+ }
836
+ );
837
+ if (res.data?.data) {
838
+ const integrations = new Set<string>();
839
+ res.data.data.forEach((item: any) => {
840
+ if (item.metadata?.integration) {
841
+ integrations.add(item.metadata.integration);
842
+ }
843
+ });
844
+ setRequestedIntegrations(integrations);
845
+ }
846
+ } catch (err) {
847
+ Logger.error('Failed to fetch requested integrations', err);
848
+ }
849
+ };
850
+
851
+ const fetchTemplateProjectsData = async () => {
852
+ try {
853
+ setLoadingTemplates(true);
854
+ const token = await getAccessToken();
855
+ const response = await axios.get(
856
+ `${envConfig.API_BASE_URL}/editor-service/v1/template-projects`,
857
+ {
858
+ headers: {
859
+ Authorization: 'Bearer ' + token
860
+ }
861
+ }
862
+ );
863
+ // Handle template projects data if needed
864
+ const projects = (response?.data?.items || []).map(
865
+ (project: ProjectMetadatAPIResponse, i: number) => ({
866
+ ...project,
867
+ assignedFallbackColor: !(project.media || []).length
868
+ ? convertToPattern(i + 1)
869
+ : null
870
+ })
871
+ ) as Project[];
872
+ setTemplates(projects);
873
+
874
+ const foundTemplateId = window.location.pathname.split(
875
+ `/ws/${activeWorkspace?.slug}/gallery/use-template-project/`
876
+ )[1];
877
+
878
+ // Hydrate active template if there is one in the URL
879
+ if (foundTemplateId) {
880
+ const activeTemplate = projects.find(
881
+ (p) => p.id === foundTemplateId
882
+ );
883
+ if (activeTemplate) {
884
+ setOpenTemplate(activeTemplate);
885
+ navigate(
886
+ `/ws/${activeWorkspace?.slug}/gallery/use-template-project/${foundTemplateId}`
887
+ );
888
+ }
889
+ }
890
+ } catch (error) {
891
+ Logger.error('error', error);
892
+ }
893
+
894
+ setLoadingTemplates(false);
895
+ };
896
+
897
+ fetchUser();
898
+ fetchExternalIntegrationsData();
899
+ fetchRequestedIntegrations();
900
+ fetchTemplateProjectsData();
901
+ }, [activeWorkspace?.id]);
902
+
903
+ useEffect(() => {
904
+ // socket.on('notification-channels', handleNotificationChannelsMessage);
905
+ socket.off('message', handleIncommingWebsocketMessage);
906
+ socket.off('reconnecting', handleReconnectingWebsocket);
907
+ // socket.off('closed', handleClosedWebsocket);
908
+
909
+ socket.on('message', handleIncommingWebsocketMessage);
910
+ socket.on('reconnecting', handleReconnectingWebsocket);
911
+ // socket.on('closed', handleClosedWebsocket);
912
+
913
+ subscribeToProjectNotificationsChannel();
914
+
915
+ return () => {
916
+ peerConnections = {};
917
+ pastSessionIds.clear();
918
+ sessionId = null;
919
+ socket.off('message', handleIncommingWebsocketMessage);
920
+ socket.off('reconnecting', handleReconnectingWebsocket);
921
+ };
922
+ }, [handleIncommingWebsocketMessage]);
923
+
924
+ // local filtering (name matches first, then category matches; alphabetical)
925
+ const filteredIntegrationEntries = useMemo(() => {
926
+ const entries = Object.entries(externalIntegrations) as [
927
+ string,
928
+ IFullIntegrationProvider
929
+ ][];
930
+
931
+ const q = marketplaceQuery.trim().toLowerCase();
932
+ if (!q) return entries;
933
+
934
+ const byName: typeof entries = [];
935
+ const byCategory: typeof entries = [];
936
+
937
+ for (const [key, value] of entries) {
938
+ const name = (value.display_name || '').toLowerCase();
939
+ const cats = (value.categories || []).map((c) => c.toLowerCase());
940
+ const isName = name.includes(q);
941
+ const isCat = !isName && cats.some((c) => c.includes(q));
942
+ if (isName) byName.push([key, value]);
943
+ else if (isCat) byCategory.push([key, value]);
944
+ }
945
+
946
+ const sortFn = (
947
+ a: (typeof entries)[number],
948
+ b: (typeof entries)[number]
949
+ ) =>
950
+ (a[1].display_name || '').localeCompare(
951
+ b[1].display_name || '',
952
+ undefined,
953
+ {
954
+ sensitivity: 'base'
955
+ }
956
+ );
957
+
958
+ byName.sort(sortFn);
959
+ byCategory.sort(sortFn);
960
+ return [...byName, ...byCategory];
961
+ }, [externalIntegrations, marketplaceQuery]);
962
+
963
+ const onDeleteProject = async (projectId: string) => {
964
+ const token = await getAccessToken();
965
+ let projectIndex = projects.findIndex((p) => p.id === projectId);
966
+ let updatedProjects = [...projects].filter((p) => p.id !== projectId);
967
+
968
+ try {
969
+ setProjects(updatedProjects);
970
+ const response = await axios.delete(
971
+ `${envConfig.API_BASE_URL}/editor-service/v1/project/${projectId}`,
972
+ { headers: { Authorization: 'Bearer ' + token } }
973
+ );
974
+ Logger.log('HERE: Project deleted: ', response);
975
+ } catch (error) {
976
+ Logger.log('HERE: Error deleting project: ', error);
977
+ popupNotification({
978
+ text: 'Error deleting project',
979
+ color: 'error'
980
+ });
981
+ if (!updatedProjects.find((p) => p.id === projectId)) {
982
+ const newProjects = [...updatedProjects];
983
+ newProjects.splice(projectIndex, 0, projects[projectIndex]);
984
+ setProjects(newProjects);
985
+ }
986
+ }
987
+ };
988
+
989
+ const onCloneProject = async (projectId: string) => {
990
+ // const token = await getAccessToken();
991
+ try {
992
+ const project = [...projects, ...templates].find(
993
+ (p) => p.id === projectId
994
+ )!;
995
+ if (!!project) {
996
+ setCloning([...cloning, project]);
997
+ }
998
+ } catch (error) {
999
+ popupNotification({
1000
+ text: 'Error duplicate project',
1001
+ color: 'error'
1002
+ });
1003
+ Logger.error('Error cloning project from the gallery: ', error);
1004
+ }
1005
+ };
1006
+
1007
+ // Helper to produce the description string (unchanged logic)
1008
+ const describeIntegration = (
1009
+ value: IFullIntegrationProvider
1010
+ ): {
1011
+ description: string;
1012
+ popular: boolean;
1013
+ } => {
1014
+ const relevantCategories = (value.categories || [])?.filter(
1015
+ (category) => category !== 'other' && category !== 'popular'
1016
+ );
1017
+
1018
+ const popular = (value.categories || [])?.includes('popular');
1019
+
1020
+ if (relevantCategories.length === 0) {
1021
+ return {
1022
+ description: `External integration with the services of ${value.display_name}`,
1023
+ popular
1024
+ };
1025
+ }
1026
+
1027
+ return {
1028
+ description: joinListWithLastSeparator(
1029
+ relevantCategories.map((cat, i) => {
1030
+ if (i !== 0)
1031
+ return lowercaseFirstLetter(toSentenceCase(cat));
1032
+ return toSentenceCase(cat);
1033
+ }),
1034
+ ', ',
1035
+ ' and '
1036
+ ),
1037
+ popular
1038
+ };
1039
+ };
1040
+
1041
+ const integrationEntriesToRender =
1042
+ marketplaceQuery.trim() === ''
1043
+ ? (
1044
+ Object.entries(externalIntegrations) as [
1045
+ string,
1046
+ IFullIntegrationProvider
1047
+ ][]
1048
+ ).sort((a, b) => {
1049
+ // If there is no query, we render first the already supported integrations
1050
+ const aSupported = ALREADY_SUPPORTED_INTEGRATIONS.includes(
1051
+ a[0]
1052
+ );
1053
+ const bSupported = ALREADY_SUPPORTED_INTEGRATIONS.includes(
1054
+ b[0]
1055
+ );
1056
+
1057
+ if (aSupported && !bSupported) return -1;
1058
+ if (!aSupported && bSupported) return 1;
1059
+
1060
+ // Otherwise we leave them as they are
1061
+ return (a[1].display_name || '').localeCompare(
1062
+ b[1].display_name || '',
1063
+ undefined,
1064
+ {
1065
+ sensitivity: 'base'
1066
+ }
1067
+ );
1068
+ })
1069
+ : filteredIntegrationEntries;
1070
+
1071
+ return (
1072
+ <div>
1073
+ <PageBackdrop />
1074
+ <div className="gallery-page">
1075
+ <div className="gallery-content-column">
1076
+ <h1 className="gallery-page-title">Gallery</h1>
1077
+
1078
+ <section className="gallery-section">
1079
+ <span className="gallery-section-header-container">
1080
+ <h2 className="gallery-section-title">
1081
+ Your projects
1082
+ </h2>
1083
+
1084
+ {/* Search by project name */}
1085
+ <div
1086
+ className={`marketplace-search ${
1087
+ showProjectSearch ? 'open' : ''
1088
+ }`}
1089
+ >
1090
+ <button
1091
+ type="button"
1092
+ className="marketplace-search__icon"
1093
+ aria-label={
1094
+ showProjectSearch
1095
+ ? 'Close search'
1096
+ : 'Open search'
1097
+ }
1098
+ onClick={() => {
1099
+ setShowProjectSearch((s) => !s);
1100
+ }}
1101
+ >
1102
+ <i
1103
+ className={`fa-solid ${
1104
+ showProjectSearch
1105
+ ? 'fa-xmark'
1106
+ : 'fa-magnifying-glass'
1107
+ }`}
1108
+ ></i>
1109
+ </button>
1110
+
1111
+ <input
1112
+ type="text"
1113
+ value={projectQuery}
1114
+ onChange={(e) =>
1115
+ setProjectQuery(e.target.value)
1116
+ }
1117
+ onKeyDown={(e) => {
1118
+ if (e.key === 'Escape') {
1119
+ setShowProjectSearch(false);
1120
+ }
1121
+ }}
1122
+ placeholder="Search projects..."
1123
+ className="marketplace-search__input"
1124
+ />
1125
+ </div>
1126
+
1127
+ {/* Layout View Mode Toggle */}
1128
+ <div className="gallery-layout-toggle">
1129
+ <button
1130
+ type="button"
1131
+ className={`gallery-layout-toggle__btn ${viewMode === 'grid' ? 'active' : ''}`}
1132
+ onClick={() => handleViewModeChange('grid')}
1133
+ title="Grid view"
1134
+ >
1135
+ <i className="fa-solid fa-table-cells"></i>
1136
+ </button>
1137
+ <button
1138
+ type="button"
1139
+ className={`gallery-layout-toggle__btn ${viewMode === 'rows' ? 'active' : ''}`}
1140
+ onClick={() => handleViewModeChange('rows')}
1141
+ title="List view"
1142
+ >
1143
+ <i className="fa-solid fa-list"></i>
1144
+ </button>
1145
+ </div>
1146
+ </span>
1147
+
1148
+ <div
1149
+ className={
1150
+ viewMode === 'grid'
1151
+ ? 'gallery-projects-grid'
1152
+ : 'gallery-projects-rows'
1153
+ }
1154
+ >
1155
+ <CreateNewProject
1156
+ onCreated={(proj) => {
1157
+ const enrichedProj: Project = {
1158
+ ...proj,
1159
+ assignedFallbackColor:
1160
+ convertToPattern(5),
1161
+ media: []
1162
+ };
1163
+ setProjects([enrichedProj, ...projects]);
1164
+ setTotalProjectCount(
1165
+ (prevCount) => prevCount + 1
1166
+ );
1167
+ }}
1168
+ totalProjectCount={totalProjectCount}
1169
+ viewMode={viewMode}
1170
+ />
1171
+ {cloning.map((project) => (
1172
+ <ProjectDuplicationCard
1173
+ key={project.id}
1174
+ project={project}
1175
+ socket={socket}
1176
+ onCloningComplete={(newProject) => {
1177
+ setCloning((oldCloning) =>
1178
+ oldCloning.filter(
1179
+ (p) => p.id !== project.id
1180
+ )
1181
+ );
1182
+ setProjects((oldProjects) => [
1183
+ newProject,
1184
+ ...oldProjects
1185
+ ]);
1186
+ }}
1187
+ onCloningFailed={() => {
1188
+ setCloning((oldCloning) =>
1189
+ oldCloning.filter(
1190
+ (p) => p.id !== project.id
1191
+ )
1192
+ );
1193
+ }}
1194
+ viewMode={viewMode}
1195
+ />
1196
+ ))}
1197
+ {loadingOwnProjects && projects.length === 0 ? (
1198
+ <LoadingCard viewMode={viewMode} />
1199
+ ) : projects.length === 0 &&
1200
+ debouncedQuery.trim() ? (
1201
+ <p className="gallery-no-results">
1202
+ No projects match “{projectQuery}”.
1203
+ </p>
1204
+ ) : (
1205
+ projects
1206
+ .sort((p1, p2) =>
1207
+ dayjs(p2.createdAt).diff(
1208
+ dayjs(p1.createdAt)
1209
+ )
1210
+ )
1211
+ .map((projectData: Project) => (
1212
+ <GalleryCard
1213
+ key={projectData.id}
1214
+ project={projectData}
1215
+ viewMode={viewMode}
1216
+ coverPictureUrl={
1217
+ projectData.media?.find(
1218
+ (media) =>
1219
+ media.type === 'cover'
1220
+ )?.url
1221
+ }
1222
+ onClick={(e) => {
1223
+ // Check if new tab
1224
+ if (e.metaKey || e.ctrlKey) {
1225
+ // Open same target in new tab
1226
+ window.open(
1227
+ `/ws/${activeWorkspace?.slug}/editor/${projectData.id}/main/latest`,
1228
+ '_blank'
1229
+ );
1230
+ return;
1231
+ }
1232
+
1233
+ navigate(
1234
+ `/ws/${activeWorkspace?.slug}/editor/${projectData.id}/main/latest`
1235
+ );
1236
+ }}
1237
+ options={[
1238
+ {
1239
+ // navigateTo: profilePath,
1240
+ onClick: async () => {
1241
+ Logger.log(
1242
+ 'Delete project clicked'
1243
+ );
1244
+ onDeleteProject(
1245
+ projectData.id
1246
+ );
1247
+ },
1248
+ iconEnd:
1249
+ 'fa-regular fa-trash-can',
1250
+ color: 'error',
1251
+ label: 'Delete'
1252
+ },
1253
+ {
1254
+ onClick: async () => {
1255
+ Logger.log(
1256
+ 'Copy project clicked'
1257
+ );
1258
+ onCloneProject(
1259
+ projectData.id
1260
+ );
1261
+ },
1262
+ iconEnd:
1263
+ 'fa-regular fa-copy',
1264
+ label: 'Copy'
1265
+ }
1266
+ ]}
1267
+ popup={
1268
+ <div className="tooltip gallery-card-tooltip">
1269
+ {!!projectData.name && (
1270
+ <>
1271
+ <h3 className="gallery-card-tooltip__project-name">
1272
+ {
1273
+ projectData.name
1274
+ }
1275
+ </h3>
1276
+ <br />
1277
+ </>
1278
+ )}
1279
+ {!!projectData.description && (
1280
+ <>
1281
+ <p className="gallery-card-tooltip__project-description">
1282
+ {
1283
+ projectData.description
1284
+ }
1285
+ </p>
1286
+ <br />
1287
+ </>
1288
+ )}
1289
+ <p className="gallery-card-tooltip__helper-text">
1290
+ Click on the card to
1291
+ open project
1292
+ </p>
1293
+ </div>
1294
+ }
1295
+ />
1296
+ ))
1297
+ )}
1298
+ </div>
1299
+ {projects.length < totalProjectCount && (
1300
+ <div className="gallery-load-more-container">
1301
+ <button
1302
+ type="button"
1303
+ className="gallery-load-more-btn"
1304
+ onClick={() =>
1305
+ setOffset((prev) => prev + 15)
1306
+ }
1307
+ disabled={loadingOwnProjects}
1308
+ >
1309
+ {loadingOwnProjects ? (
1310
+ <CircularProgress
1311
+ size={16}
1312
+ color="inherit"
1313
+ />
1314
+ ) : (
1315
+ 'Load more'
1316
+ )}
1317
+ </button>
1318
+ </div>
1319
+ )}
1320
+ </section>
1321
+
1322
+ {!!templates.length && (
1323
+ <section className="gallery-section">
1324
+ <h2 className="gallery-section-title">Templates</h2>
1325
+ <div className="gallery-projects-grid">
1326
+ {loadingTemplates ? (
1327
+ <LoadingCard />
1328
+ ) : (
1329
+ templates.map((projectData: Project) => (
1330
+ <GalleryCard
1331
+ key={projectData.id}
1332
+ project={projectData}
1333
+ coverPictureUrl={
1334
+ projectData.media?.find(
1335
+ (media) =>
1336
+ media.type === 'cover'
1337
+ )?.url
1338
+ }
1339
+ onClick={() => {
1340
+ setOpenTemplate(projectData);
1341
+ navigate(
1342
+ `/ws/${activeWorkspace?.slug}/gallery/use-template-project/${projectData.id}`
1343
+ );
1344
+ }}
1345
+ popup={
1346
+ <div className="tooltip gallery-card-tooltip">
1347
+ {!!projectData.name && (
1348
+ <>
1349
+ <h3 className="gallery-card-tooltip__project-name">
1350
+ {
1351
+ projectData.name
1352
+ }
1353
+ </h3>
1354
+ <br />
1355
+ </>
1356
+ )}
1357
+ {!!projectData.description && (
1358
+ <>
1359
+ <p className="gallery-card-tooltip__project-description">
1360
+ {
1361
+ projectData.description
1362
+ }
1363
+ </p>
1364
+ <br />
1365
+ </>
1366
+ )}
1367
+ <p className="gallery-card-tooltip__helper-text">
1368
+ Click to use as template
1369
+ for a new project
1370
+ </p>
1371
+ </div>
1372
+ }
1373
+ />
1374
+ ))
1375
+ )}
1376
+ </div>
1377
+ </section>
1378
+ )}
1379
+
1380
+ <section className="gallery-section">
1381
+ <span className="gallery-section-header-container">
1382
+ <i className="gallery-section-header-icon fa-solid fa-store"></i>
1383
+ <h2 className="gallery-section-title">
1384
+ Marketplace
1385
+ </h2>
1386
+ {/* <p className='gallery-section-description'>Coming soon</p> */}
1387
+
1388
+ {/* Search */}
1389
+ <div
1390
+ className={`marketplace-search ${
1391
+ showMarketplaceSearch ? 'open' : ''
1392
+ }`}
1393
+ >
1394
+ <button
1395
+ type="button"
1396
+ className="marketplace-search__icon"
1397
+ aria-label={
1398
+ showMarketplaceSearch
1399
+ ? 'Close search'
1400
+ : 'Open search'
1401
+ }
1402
+ onClick={() => {
1403
+ // Clicking the icon toggles input visibility.
1404
+ setShowMarketplaceSearch((s) => !s);
1405
+ if (
1406
+ showMarketplaceSearch &&
1407
+ marketplaceQuery
1408
+ ) {
1409
+ setMarketplaceQuery('');
1410
+ }
1411
+ }}
1412
+ >
1413
+ <i
1414
+ className={`fa-solid ${
1415
+ showMarketplaceSearch
1416
+ ? 'fa-xmark'
1417
+ : 'fa-magnifying-glass'
1418
+ }`}
1419
+ ></i>
1420
+ </button>
1421
+
1422
+ <input
1423
+ type="text"
1424
+ value={marketplaceQuery}
1425
+ onChange={(e) =>
1426
+ setMarketplaceQuery(e.target.value)
1427
+ }
1428
+ onKeyDown={(e) => {
1429
+ if (e.key === 'Escape') {
1430
+ setShowMarketplaceSearch(false);
1431
+ }
1432
+ }}
1433
+ placeholder="Search integrations..."
1434
+ className="marketplace-search__input"
1435
+ />
1436
+ </div>
1437
+ </span>
1438
+
1439
+ <div className="gallery-projects-grid">
1440
+ {/* <MarketplaceCard
1441
+ disabled
1442
+ project={
1443
+ {
1444
+ name: 'Payments',
1445
+ description: 'Add payments to your project',
1446
+ id: 'payments-feature',
1447
+ media: [],
1448
+ assignedFallbackColor: 0,
1449
+ } as any as Project
1450
+ }
1451
+ />
1452
+ <MarketplaceCard
1453
+ disabled
1454
+ project={
1455
+ {
1456
+ name: 'User auth',
1457
+ description: 'Add signup and login to your project',
1458
+ id: 'user-auth-feature',
1459
+ media: [],
1460
+ assignedFallbackColor: 1,
1461
+ } as any as Project
1462
+ }
1463
+ /> */}
1464
+
1465
+ {loadingExternalIntegrations ? (
1466
+ <LoadingCard />
1467
+ ) : integrationEntriesToRender.length === 0 &&
1468
+ marketplaceQuery.trim() ? (
1469
+ <p className="gallery-no-results">
1470
+ No integrations match “{marketplaceQuery}”.
1471
+ </p>
1472
+ ) : (
1473
+ integrationEntriesToRender.map(
1474
+ ([key, value], i) => {
1475
+ const description =
1476
+ describeIntegration(value);
1477
+ return (
1478
+ <MarketplaceCard
1479
+ isPaid={PAID_INTEGRATIONS.includes(
1480
+ key
1481
+ )}
1482
+ disabled={
1483
+ !ALREADY_SUPPORTED_INTEGRATIONS.includes(
1484
+ key
1485
+ )
1486
+ }
1487
+ onClick={() => {
1488
+ if (
1489
+ ALREADY_SUPPORTED_INTEGRATIONS.includes(
1490
+ key
1491
+ )
1492
+ ) {
1493
+ // Handle click for supported integrations
1494
+ // Open small dialog to explain next steps
1495
+ navigate(
1496
+ `/ws/${activeWorkspace?.slug}/gallery/add-external-integration-to-project/${key}`,
1497
+ {
1498
+ state: {
1499
+ providerName:
1500
+ value.display_name
1501
+ }
1502
+ }
1503
+ );
1504
+ } else {
1505
+ setRequestingIntegration(
1506
+ {
1507
+ key,
1508
+ name: value.display_name
1509
+ }
1510
+ );
1511
+ }
1512
+ }}
1513
+ tags={
1514
+ ALREADY_SUPPORTED_INTEGRATIONS.includes(
1515
+ key
1516
+ )
1517
+ ? [
1518
+ {
1519
+ label: (
1520
+ <span>
1521
+ <i className="fa-solid fa-check"></i>
1522
+ &nbsp;available
1523
+ </span>
1524
+ )
1525
+ },
1526
+ ...(description.popular
1527
+ ? [
1528
+ {
1529
+ label: 'popular',
1530
+ color: 'secondary' as const
1531
+ }
1532
+ ]
1533
+ : [])
1534
+ ]
1535
+ : [
1536
+ ...(requestedIntegrations.has(
1537
+ key
1538
+ )
1539
+ ? [
1540
+ {
1541
+ label: (
1542
+ <span>
1543
+ <i className="fa-solid fa-check"></i>
1544
+ &nbsp;Requested
1545
+ </span>
1546
+ ),
1547
+ color: 'success' as const
1548
+ }
1549
+ ]
1550
+ : []),
1551
+ ...(description.popular
1552
+ ? [
1553
+ {
1554
+ label: 'popular',
1555
+ color: 'secondary' as const
1556
+ }
1557
+ ]
1558
+ : [])
1559
+ ]
1560
+ }
1561
+ key={key}
1562
+ disableTitleCapitalize
1563
+ project={
1564
+ {
1565
+ name: value.display_name,
1566
+ description:
1567
+ description.description,
1568
+ id: key,
1569
+ media: [
1570
+ {
1571
+ url: `${envConfig.EXTERNAL_INTEGRATIONS_LOGOS_URL}/${key}.svg`,
1572
+ type: 'icon'
1573
+ }
1574
+ ],
1575
+ assignedFallbackColor:
1576
+ convertToPattern(
1577
+ i + 1
1578
+ )
1579
+ } as any as Project
1580
+ }
1581
+ />
1582
+ );
1583
+ }
1584
+ )
1585
+ )}
1586
+ </div>
1587
+ </section>
1588
+ </div>
1589
+ </div>
1590
+
1591
+ <a
1592
+ href={`/ws/${activeWorkspace?.slug}/gallery`}
1593
+ onClick={(e) => {
1594
+ e.preventDefault();
1595
+ if (activeWorkspace) {
1596
+ navigate(`/ws/${activeWorkspace.id}/gallery`);
1597
+ }
1598
+ }}
1599
+ >
1600
+ <img className="gallery-page-logo" src={Logo} alt="Logo" />
1601
+ </a>
1602
+
1603
+ {/* Workspace Badge + User Avatar Wrapper */}
1604
+ <div className="gallery-top-controls">
1605
+ {activeWorkspace && (
1606
+ <div
1607
+ // <a
1608
+ className="workspace-badge"
1609
+ title="Current Workspace"
1610
+ // // @ts-ignore
1611
+ // href={envConfig.stripe_personal_sub_mngmt_url}
1612
+ // target='_blank'
1613
+ >
1614
+ <div className="workspace-badge__icon">
1615
+ {activeWorkspace.name?.charAt(0)?.toUpperCase() ||
1616
+ 'W'}
1617
+ </div>
1618
+ <div className="workspace-badge__info">
1619
+ <span className="workspace-badge__name">
1620
+ {activeWorkspace.name}
1621
+ </span>
1622
+ <span className="workspace-badge__tier">
1623
+ {activeWorkspace.planTier} plan
1624
+ </span>
1625
+ </div>
1626
+ {/* </a> */}
1627
+ </div>
1628
+ )}
1629
+ <CurrentUserAvatar
1630
+ profilePagePath={`/ws/${activeWorkspace?.slug}/gallery/profile/{id}`}
1631
+ />
1632
+ </div>
1633
+
1634
+ <Routes>
1635
+ <Route
1636
+ path="profile/:userId"
1637
+ element={
1638
+ <Dialog
1639
+ onClose={() =>
1640
+ navigate(`/ws/${activeWorkspace?.slug}/gallery`)
1641
+ }
1642
+ >
1643
+ <UserProfileDialog
1644
+ onClose={() =>
1645
+ navigate(
1646
+ `/ws/${activeWorkspace?.slug}/gallery`
1647
+ )
1648
+ }
1649
+ />
1650
+ </Dialog>
1651
+ }
1652
+ />
1653
+ <Route
1654
+ path="add-external-integration-to-project/:providerKey"
1655
+ element={<GalleryAddExternalIntegrationInfoDialog />}
1656
+ />
1657
+ <Route
1658
+ path="use-template-project/:templateId"
1659
+ element={
1660
+ <UseTemplateProjectDialog
1661
+ project={openTemplate}
1662
+ onProjectCreate={(newProjectId) =>
1663
+ onCloneProject(newProjectId)
1664
+ }
1665
+ />
1666
+ }
1667
+ />
1668
+ </Routes>
1669
+
1670
+ {requestingIntegration && (
1671
+ <RequestIntegrationAccessDialog
1672
+ integrationKey={requestingIntegration.key}
1673
+ integrationName={requestingIntegration.name}
1674
+ isAlreadyRequested={requestedIntegrations.has(
1675
+ requestingIntegration.key
1676
+ )}
1677
+ onClose={(requested) => {
1678
+ setRequestingIntegration(null);
1679
+ if (requested) {
1680
+ setRequestedIntegrations((prev) => {
1681
+ const next = new Set(prev);
1682
+ next.add(requestingIntegration.key);
1683
+ return next;
1684
+ });
1685
+ }
1686
+ }}
1687
+ />
1688
+ )}
1689
+ </div>
1690
+ );
1691
+ };
1692
+
1693
+ export default Gallery;