@rebasepro/admin 0.4.0 → 0.6.0

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 (353) hide show
  1. package/README.md +135 -0
  2. package/dist/CollectionEditorDialog-jA-PLh6N.js +3549 -0
  3. package/dist/CollectionEditorDialog-jA-PLh6N.js.map +1 -0
  4. package/dist/CollectionsStudioView-UKouBPOm.js +170 -0
  5. package/dist/CollectionsStudioView-UKouBPOm.js.map +1 -0
  6. package/dist/PropertyEditView-DEUddmg_.js +3660 -0
  7. package/dist/PropertyEditView-DEUddmg_.js.map +1 -0
  8. package/dist/collection_editor/ConfigControllerProvider.d.ts +2 -2
  9. package/dist/collection_editor/ui/AddKanbanColumnAction.d.ts +2 -1
  10. package/dist/collection_editor/ui/CollectionViewHeaderAction.d.ts +2 -1
  11. package/dist/collection_editor/ui/EditorCollectionAction.d.ts +1 -1
  12. package/dist/collection_editor/ui/EditorCollectionActionStart.d.ts +1 -1
  13. package/dist/collection_editor/ui/EditorEntityAction.d.ts +1 -1
  14. package/dist/collection_editor/ui/HomePageEditorCollectionAction.d.ts +1 -1
  15. package/dist/collection_editor/ui/KanbanSetupAction.d.ts +2 -1
  16. package/dist/collection_editor/ui/MissingReferenceWidget.d.ts +1 -1
  17. package/dist/collection_editor/ui/NewCollectionButton.d.ts +1 -1
  18. package/dist/collection_editor/ui/NewCollectionCard.d.ts +1 -1
  19. package/dist/collection_editor/ui/PropertyAddColumnComponent.d.ts +1 -1
  20. package/dist/collection_editor/ui/collection_editor/AICollectionGeneratorPopover.d.ts +1 -1
  21. package/dist/collection_editor/ui/collection_editor/AIModifiedPathsContext.d.ts +1 -1
  22. package/dist/collection_editor/ui/collection_editor/CollectionDetailsForm.d.ts +2 -1
  23. package/dist/collection_editor/ui/collection_editor/CollectionEditorDialog.d.ts +2 -2
  24. package/dist/collection_editor/ui/collection_editor/CollectionEditorWelcomeView.d.ts +2 -2
  25. package/dist/collection_editor/ui/collection_editor/CollectionJsonImportDialog.d.ts +2 -1
  26. package/dist/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +1 -1
  27. package/dist/collection_editor/ui/collection_editor/CollectionRLSTab.d.ts +2 -1
  28. package/dist/collection_editor/ui/collection_editor/CollectionRelationsTab.d.ts +2 -1
  29. package/dist/collection_editor/ui/collection_editor/CollectionStudioView.d.ts +2 -1
  30. package/dist/collection_editor/ui/collection_editor/CollectionYupValidation.d.ts +1 -9
  31. package/dist/collection_editor/ui/collection_editor/CollectionsStudioView.d.ts +2 -1
  32. package/dist/collection_editor/ui/collection_editor/DisplaySettingsForm.d.ts +2 -1
  33. package/dist/collection_editor/ui/collection_editor/EntityActionsEditTab.d.ts +2 -1
  34. package/dist/collection_editor/ui/collection_editor/EntityActionsSelectDialog.d.ts +2 -1
  35. package/dist/collection_editor/ui/collection_editor/EntityCustomViewsSelectDialog.d.ts +2 -1
  36. package/dist/collection_editor/ui/collection_editor/EnumForm.d.ts +2 -1
  37. package/dist/collection_editor/ui/collection_editor/GeneralSettingsForm.d.ts +2 -1
  38. package/dist/collection_editor/ui/collection_editor/GetCodeDialog.d.ts +2 -1
  39. package/dist/collection_editor/ui/collection_editor/KanbanConfigSection.d.ts +2 -1
  40. package/dist/collection_editor/ui/collection_editor/LayoutModeSwitch.d.ts +1 -1
  41. package/dist/collection_editor/ui/collection_editor/PropertyEditView.d.ts +4 -3
  42. package/dist/collection_editor/ui/collection_editor/PropertyFieldPreview.d.ts +2 -2
  43. package/dist/collection_editor/ui/collection_editor/PropertyTree.d.ts +2 -2
  44. package/dist/collection_editor/ui/collection_editor/SubcollectionsEditTab.d.ts +2 -1
  45. package/dist/collection_editor/ui/collection_editor/SwitchControl.d.ts +2 -1
  46. package/dist/collection_editor/ui/collection_editor/ViewModeSwitch.d.ts +1 -1
  47. package/dist/collection_editor/ui/collection_editor/import/CollectionEditorImportDataPreview.d.ts +1 -1
  48. package/dist/collection_editor/ui/collection_editor/import/CollectionEditorImportMapping.d.ts +3 -2
  49. package/dist/collection_editor/ui/collection_editor/properties/BlockPropertyField.d.ts +2 -1
  50. package/dist/collection_editor/ui/collection_editor/properties/BooleanPropertyField.d.ts +2 -1
  51. package/dist/collection_editor/ui/collection_editor/properties/DateTimePropertyField.d.ts +2 -1
  52. package/dist/collection_editor/ui/collection_editor/properties/EnumPropertyField.d.ts +2 -1
  53. package/dist/collection_editor/ui/collection_editor/properties/KeyValuePropertyField.d.ts +2 -1
  54. package/dist/collection_editor/ui/collection_editor/properties/MapPropertyField.d.ts +2 -1
  55. package/dist/collection_editor/ui/collection_editor/properties/MarkdownPropertyField.d.ts +2 -1
  56. package/dist/collection_editor/ui/collection_editor/properties/NumberPropertyField.d.ts +2 -1
  57. package/dist/collection_editor/ui/collection_editor/properties/ReferencePropertyField.d.ts +3 -2
  58. package/dist/collection_editor/ui/collection_editor/properties/RelationPropertyField.d.ts +2 -1
  59. package/dist/collection_editor/ui/collection_editor/properties/RepeatPropertyField.d.ts +2 -1
  60. package/dist/collection_editor/ui/collection_editor/properties/StoragePropertyField.d.ts +2 -1
  61. package/dist/collection_editor/ui/collection_editor/properties/StringPropertyField.d.ts +2 -1
  62. package/dist/collection_editor/ui/collection_editor/properties/UrlPropertyField.d.ts +2 -1
  63. package/dist/collection_editor/ui/collection_editor/properties/VectorPropertyField.d.ts +2 -1
  64. package/dist/collection_editor/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.d.ts +2 -1
  65. package/dist/collection_editor/ui/collection_editor/properties/conditions/ConditionsEditor.d.ts +2 -1
  66. package/dist/collection_editor/ui/collection_editor/properties/conditions/ConditionsPanel.d.ts +1 -1
  67. package/dist/collection_editor/ui/collection_editor/properties/conditions/EnumConditionsEditor.d.ts +2 -1
  68. package/dist/collection_editor/ui/collection_editor/properties/validation/ArrayPropertyValidation.d.ts +2 -1
  69. package/dist/collection_editor/ui/collection_editor/properties/validation/GeneralPropertyValidation.d.ts +2 -1
  70. package/dist/collection_editor/ui/collection_editor/properties/validation/NumberPropertyValidation.d.ts +2 -1
  71. package/dist/collection_editor/ui/collection_editor/properties/validation/StringPropertyValidation.d.ts +2 -1
  72. package/dist/collection_editor/ui/collection_editor/properties/validation/ValidationPanel.d.ts +1 -1
  73. package/dist/collection_editor/ui/collection_editor/templates/blog_template.d.ts +1 -1
  74. package/dist/collection_editor/ui/collection_editor/templates/pages_template.d.ts +1 -1
  75. package/dist/collection_editor/ui/collection_editor/templates/products_template.d.ts +1 -1
  76. package/dist/collection_editor/ui/collection_editor/templates/users_template.d.ts +1 -1
  77. package/dist/collection_editor_ui.js +4 -11
  78. package/dist/components/ArrayContainer.d.ts +3 -3
  79. package/dist/components/ClearFilterSortButton.d.ts +1 -1
  80. package/dist/components/CollectionEditorDialogs.d.ts +2 -1
  81. package/dist/components/CollectionPanel.d.ts +2 -27
  82. package/dist/components/DefaultAppBar.d.ts +1 -1
  83. package/dist/components/DefaultDrawer.d.ts +4 -4
  84. package/dist/components/DeleteEntityDialog.d.ts +2 -1
  85. package/dist/components/DrawerNavigationGroup.d.ts +1 -1
  86. package/dist/components/DrawerNavigationItem.d.ts +1 -1
  87. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +1 -1
  88. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +2 -1
  89. package/dist/components/EntityCollectionTable/fields/TableMultipleRelationField.d.ts +3 -3
  90. package/dist/components/EntityCollectionTable/fields/TableReferenceField.d.ts +3 -3
  91. package/dist/components/EntityCollectionTable/fields/TableRelationField.d.ts +3 -3
  92. package/dist/components/EntityCollectionTable/fields/TableRelationSelectorField.d.ts +2 -1
  93. package/dist/components/EntityCollectionTable/fields/TableStorageUpload.d.ts +2 -2
  94. package/dist/components/EntityCollectionTable/fields/VirtualTableDateField.d.ts +1 -1
  95. package/dist/components/EntityCollectionTable/fields/VirtualTableInput.d.ts +2 -1
  96. package/dist/components/EntityCollectionTable/fields/VirtualTableNumberInput.d.ts +2 -1
  97. package/dist/components/EntityCollectionTable/fields/VirtualTableSelect.d.ts +1 -1
  98. package/dist/components/EntityCollectionTable/fields/VirtualTableSwitch.d.ts +2 -1
  99. package/dist/components/EntityCollectionTable/fields/VirtualTableUserSelect.d.ts +1 -1
  100. package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +1 -1
  101. package/dist/components/EntityCollectionTable/internal/EntityTableCellActions.d.ts +1 -1
  102. package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +4 -3
  103. package/dist/components/EntityCollectionView/Board.d.ts +2 -1
  104. package/dist/components/EntityCollectionView/BoardColumnTitle.d.ts +1 -1
  105. package/dist/components/EntityCollectionView/BoardSortableList.d.ts +1 -1
  106. package/dist/components/EntityCollectionView/EntityBoardCard.d.ts +1 -1
  107. package/dist/components/EntityCollectionView/EntityCard.d.ts +2 -1
  108. package/dist/components/EntityCollectionView/EntityCollectionBoardView.d.ts +1 -1
  109. package/dist/components/EntityCollectionView/EntityCollectionCardView.d.ts +1 -1
  110. package/dist/components/EntityCollectionView/EntityCollectionListView.d.ts +1 -1
  111. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +0 -24
  112. package/dist/components/EntityCollectionView/EntityCollectionViewActions.d.ts +1 -1
  113. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +2 -1
  114. package/dist/components/EntityCollectionView/FilterPresetsButton.d.ts +2 -1
  115. package/dist/components/EntityCollectionView/FiltersDialog.d.ts +2 -1
  116. package/dist/components/EntityCollectionView/SplitListView.d.ts +1 -1
  117. package/dist/components/EntityCollectionView/ViewModeToggle.d.ts +2 -1
  118. package/dist/components/EntityDetailView.d.ts +1 -1
  119. package/dist/components/EntityEditView.d.ts +2 -2
  120. package/dist/components/EntityEditViewFormActions.d.ts +2 -1
  121. package/dist/components/EntityJsonPreview.d.ts +2 -1
  122. package/dist/components/EntityPreview.d.ts +3 -3
  123. package/dist/components/EntitySidePanel.d.ts +2 -1
  124. package/dist/components/EntityView.d.ts +2 -1
  125. package/dist/components/FieldCaption.d.ts +1 -1
  126. package/dist/components/HomePage/ContentHomePage.d.ts +1 -1
  127. package/dist/components/HomePage/FavouritesView.d.ts +1 -1
  128. package/dist/components/HomePage/HomePageDnD.d.ts +4 -4
  129. package/dist/components/HomePage/NavigationCard.d.ts +1 -1
  130. package/dist/components/HomePage/NavigationCardBinding.d.ts +2 -1
  131. package/dist/components/HomePage/NavigationGroup.d.ts +2 -2
  132. package/dist/components/HomePage/RenameGroupDialog.d.ts +2 -1
  133. package/dist/components/HomePage/SmallNavigationCard.d.ts +1 -1
  134. package/dist/components/PropertyCollectionView.d.ts +2 -1
  135. package/dist/components/PropertyIdCopyTooltip.d.ts +2 -2
  136. package/dist/components/RebaseAuthGate.d.ts +1 -1
  137. package/dist/components/RebaseLayout.d.ts +1 -1
  138. package/dist/components/RebaseNavigation.d.ts +1 -1
  139. package/dist/components/RebaseRouteDefs.d.ts +1 -1
  140. package/dist/components/RebaseShell.d.ts +1 -1
  141. package/dist/components/ReferenceTable/EntitySelectionTable.d.ts +1 -1
  142. package/dist/components/ReferenceWidget.d.ts +2 -1
  143. package/dist/components/SearchIconsView.d.ts +2 -1
  144. package/dist/components/SelectableTable/SelectableTable.d.ts +2 -2
  145. package/dist/components/SelectableTable/filters/BooleanFilterField.d.ts +2 -1
  146. package/dist/components/SelectableTable/filters/DateTimeFilterField.d.ts +2 -1
  147. package/dist/components/SelectableTable/filters/ReferenceFilterField.d.ts +2 -1
  148. package/dist/components/SelectableTable/filters/RelationFilterField.d.ts +2 -1
  149. package/dist/components/SelectableTable/filters/StringNumberFilterField.d.ts +2 -1
  150. package/dist/components/SideDialogs.d.ts +1 -1
  151. package/dist/components/SideEntityProvider.d.ts +1 -1
  152. package/dist/components/admin/CreationResultDialog.d.ts +2 -1
  153. package/dist/components/app/AppBar.d.ts +1 -1
  154. package/dist/components/app/Drawer.d.ts +1 -1
  155. package/dist/components/common/default_entity_actions.d.ts +2 -1
  156. package/dist/components/history/EntityHistoryEntry.d.ts +1 -1
  157. package/dist/components/history/EntityHistoryView.d.ts +1 -1
  158. package/dist/components/history/LastEditedByFormAction.d.ts +2 -1
  159. package/dist/components/history/LastEditedByIndicator.d.ts +2 -1
  160. package/dist/components/history/UserChip.d.ts +1 -1
  161. package/dist/data_export/export/BasicExportAction.d.ts +2 -1
  162. package/dist/data_export/export/ExportCollectionAction.d.ts +1 -1
  163. package/dist/data_import/components/DataNewPropertiesMapping.d.ts +1 -1
  164. package/dist/data_import/components/ImportFileUpload.d.ts +1 -1
  165. package/dist/data_import/components/ImportNewPropertyFieldPreview.d.ts +2 -1
  166. package/dist/data_import/components/ImportSaveInProgress.d.ts +1 -1
  167. package/dist/data_import/import/ImportCollectionAction.d.ts +4 -3
  168. package/dist/editor/components/SlashCommandMenu.d.ts +2 -1
  169. package/dist/editor/editor.d.ts +1 -1
  170. package/dist/editor/selectors/color-selector.d.ts +1 -1
  171. package/dist/editor/selectors/link-selector.d.ts +1 -1
  172. package/dist/editor/selectors/node-selector.d.ts +1 -1
  173. package/dist/editor/selectors/text-buttons.d.ts +1 -1
  174. package/dist/editor.js +2621 -3574
  175. package/dist/editor.js.map +1 -1
  176. package/dist/form/EntityForm.d.ts +2 -1
  177. package/dist/form/EntityFormActions.d.ts +2 -1
  178. package/dist/form/components/FieldHelperText.d.ts +1 -1
  179. package/dist/form/components/FormEntry.d.ts +1 -1
  180. package/dist/form/components/FormLayout.d.ts +1 -1
  181. package/dist/form/components/LabelWithIconAndTooltip.d.ts +1 -1
  182. package/dist/form/components/LocalChangesMenu.d.ts +2 -1
  183. package/dist/form/components/StorageItemPreview.d.ts +2 -1
  184. package/dist/form/components/StorageUploadProgress.d.ts +2 -1
  185. package/dist/form/field_bindings/ArrayCustomShapedFieldBinding.d.ts +2 -1
  186. package/dist/form/field_bindings/ArrayOfReferencesFieldBinding.d.ts +2 -1
  187. package/dist/form/field_bindings/BlockFieldBinding.d.ts +2 -1
  188. package/dist/form/field_bindings/DateTimeFieldBinding.d.ts +2 -1
  189. package/dist/form/field_bindings/KeyValueFieldBinding.d.ts +2 -1
  190. package/dist/form/field_bindings/MapFieldBinding.d.ts +2 -1
  191. package/dist/form/field_bindings/MarkdownEditorFieldBinding.d.ts +2 -1
  192. package/dist/form/field_bindings/MultiSelectFieldBinding.d.ts +2 -1
  193. package/dist/form/field_bindings/MultipleRelationFieldBinding.d.ts +2 -1
  194. package/dist/form/field_bindings/ReadOnlyFieldBinding.d.ts +2 -1
  195. package/dist/form/field_bindings/ReferenceAsStringFieldBinding.d.ts +2 -1
  196. package/dist/form/field_bindings/ReferenceFieldBinding.d.ts +2 -1
  197. package/dist/form/field_bindings/RelationFieldBinding.d.ts +2 -1
  198. package/dist/form/field_bindings/RepeatFieldBinding.d.ts +2 -1
  199. package/dist/form/field_bindings/SelectFieldBinding.d.ts +2 -1
  200. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +3 -2
  201. package/dist/form/field_bindings/SwitchFieldBinding.d.ts +2 -1
  202. package/dist/form/field_bindings/TextFieldBinding.d.ts +2 -1
  203. package/dist/form/field_bindings/UserSelectFieldBinding.d.ts +2 -1
  204. package/dist/form/field_bindings/VectorFieldBinding.d.ts +2 -1
  205. package/dist/history-BL49TIDb.js +311 -0
  206. package/dist/history-BL49TIDb.js.map +1 -0
  207. package/dist/hooks/navigation/useBuildNavigationStateController.d.ts +0 -2
  208. package/dist/hooks/navigation/useNavigationResolution.d.ts +5 -6
  209. package/dist/hooks/navigation/useResolvedCollections.d.ts +0 -2
  210. package/dist/hooks/useBreadcrumbsController.d.ts +2 -32
  211. package/dist/index.js +2 -3393
  212. package/dist/markdown-CklalUUk.js +526 -0
  213. package/dist/markdown-CklalUUk.js.map +1 -0
  214. package/dist/preview/components/ArrayEnumPreview.d.ts +2 -1
  215. package/dist/preview/components/EmptyValue.d.ts +2 -1
  216. package/dist/preview/components/EnumValuesChip.d.ts +1 -1
  217. package/dist/preview/components/ImagePreview.d.ts +2 -1
  218. package/dist/preview/components/ReferencePreview.d.ts +2 -1
  219. package/dist/preview/components/RelationPreview.d.ts +2 -1
  220. package/dist/preview/components/StorageThumbnail.d.ts +1 -1
  221. package/dist/preview/components/UserPreview.d.ts +6 -3
  222. package/dist/preview/property_previews/ArrayOfMapsPreview.d.ts +2 -1
  223. package/dist/preview/property_previews/ArrayOfReferencesPreview.d.ts +1 -1
  224. package/dist/preview/property_previews/ArrayOfRelationsPreview.d.ts +1 -1
  225. package/dist/preview/property_previews/ArrayOfStorageComponentsPreview.d.ts +2 -1
  226. package/dist/preview/property_previews/ArrayOfStringsPreview.d.ts +2 -1
  227. package/dist/preview/property_previews/ArrayOneOfPreview.d.ts +2 -1
  228. package/dist/preview/property_previews/ArrayPropertyEnumPreview.d.ts +1 -1
  229. package/dist/preview/property_previews/ArrayPropertyPreview.d.ts +2 -1
  230. package/dist/preview/property_previews/MapPropertyPreview.d.ts +3 -2
  231. package/dist/preview/property_previews/SkeletonPropertyComponent.d.ts +5 -4
  232. package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
  233. package/dist/routes/RebaseRoute.d.ts +1 -1
  234. package/dist/src-BJ8fkM8y.js +24010 -0
  235. package/dist/src-BJ8fkM8y.js.map +1 -0
  236. package/dist/types/components/PropertyPreviewProps.d.ts +4 -0
  237. package/dist/types/components/formex.d.ts +1 -40
  238. package/dist/types/fields.d.ts +9 -1
  239. package/dist/util/navigation_utils.d.ts +2 -1
  240. package/dist/util/previews.d.ts +5 -0
  241. package/dist/util/property_utils.d.ts +1 -1
  242. package/package.json +29 -27
  243. package/src/collection_editor/ConfigControllerProvider.tsx +10 -7
  244. package/src/collection_editor/ui/CollectionViewHeaderAction.tsx +2 -1
  245. package/src/collection_editor/ui/EditorCollectionAction.tsx +2 -1
  246. package/src/collection_editor/ui/EditorCollectionActionStart.tsx +2 -1
  247. package/src/collection_editor/ui/EditorEntityAction.tsx +2 -1
  248. package/src/collection_editor/ui/KanbanSetupAction.tsx +2 -1
  249. package/src/collection_editor/ui/MissingReferenceWidget.tsx +2 -1
  250. package/src/collection_editor/ui/PropertyAddColumnComponent.tsx +2 -1
  251. package/src/collection_editor/ui/collection_editor/CollectionDetailsForm.tsx +2 -3
  252. package/src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx +0 -1
  253. package/src/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.tsx +8 -4
  254. package/src/collection_editor/ui/collection_editor/CollectionRelationsTab.tsx +2 -2
  255. package/src/collection_editor/ui/collection_editor/DisplaySettingsForm.tsx +2 -1
  256. package/src/collection_editor/ui/collection_editor/PropertyEditView.tsx +2 -1
  257. package/src/collection_editor/ui/collection_editor/PropertyFieldPreview.tsx +2 -2
  258. package/src/collection_editor/ui/collection_editor/properties/RelationPropertyField.tsx +5 -2
  259. package/src/collection_editor/ui/collection_editor/properties/conditions/ConditionsEditor.tsx +2 -1
  260. package/src/collection_editor/ui/collection_editor/properties/conditions/EnumConditionsEditor.tsx +1 -1
  261. package/src/collection_editor/ui/collection_editor/templates/blog_template.ts +1 -1
  262. package/src/collection_editor/ui/collection_editor/templates/pages_template.ts +1 -1
  263. package/src/collection_editor/ui/collection_editor/templates/products_template.ts +1 -1
  264. package/src/collection_editor/ui/collection_editor/templates/users_template.ts +1 -1
  265. package/src/collection_editor/useLocalCollectionsConfigController.tsx +7 -2
  266. package/src/collection_editor/validateCollectionJson.ts +2 -2
  267. package/src/components/CollectionPanel.tsx +51 -25
  268. package/src/components/DefaultAppBar.tsx +1 -2
  269. package/src/components/DefaultDrawer.tsx +3 -2
  270. package/src/components/DrawerNavigationGroup.tsx +3 -2
  271. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +30 -9
  272. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +1 -1
  273. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +1 -0
  274. package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +5 -2
  275. package/src/components/EntityCollectionView/Board.tsx +10 -8
  276. package/src/components/EntityCollectionView/BoardSortableList.tsx +2 -2
  277. package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +4 -2
  278. package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +14 -4
  279. package/src/components/EntityCollectionView/EntityCollectionListView.tsx +48 -26
  280. package/src/components/EntityCollectionView/EntityCollectionView.tsx +146 -73
  281. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +2 -1
  282. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +3 -2
  283. package/src/components/EntityCollectionView/FilterPresetsButton.tsx +4 -2
  284. package/src/components/EntityCollectionView/ViewModeToggle.tsx +0 -1
  285. package/src/components/EntityCollectionView/useBoardDataController.tsx +17 -15
  286. package/src/components/EntityCollectionView/useEntityPreviewSlots.ts +32 -23
  287. package/src/components/EntityDetailView.tsx +72 -39
  288. package/src/components/EntityEditView.tsx +79 -47
  289. package/src/components/EntitySidePanel.tsx +9 -3
  290. package/src/components/HomePage/ContentHomePage.tsx +3 -3
  291. package/src/components/HomePage/NavigationCard.tsx +5 -5
  292. package/src/components/HomePage/NavigationCardBinding.tsx +1 -1
  293. package/src/components/RebaseLayout.tsx +5 -2
  294. package/src/components/RebaseNavigation.tsx +1 -4
  295. package/src/components/RebaseRouteDefs.tsx +5 -3
  296. package/src/components/SearchIconsView.tsx +1 -1
  297. package/src/components/SelectableTable/SelectableTable.tsx +2 -3
  298. package/src/components/SelectableTable/SelectionStore.ts +9 -3
  299. package/src/components/UserSelector.tsx +92 -2
  300. package/src/components/common/default_entity_actions.tsx +23 -6
  301. package/src/components/field_configs.tsx +6 -3
  302. package/src/editor/editor.tsx +1 -1
  303. package/src/editor/extensions/Image/index.ts +2 -2
  304. package/src/editor/extensions/Image.ts +2 -2
  305. package/src/editor/extensions/clipboard.ts +2 -2
  306. package/src/editor/markdown-it-plugins.d.ts +24 -0
  307. package/src/editor/markdown.ts +2 -3
  308. package/src/form/EntityForm.tsx +21 -15
  309. package/src/form/PropertyFieldBinding.tsx +1 -1
  310. package/src/form/field_bindings/KeyValueFieldBinding.tsx +1 -1
  311. package/src/form/field_bindings/MapFieldBinding.tsx +5 -47
  312. package/src/form/field_bindings/VectorFieldBinding.tsx +3 -3
  313. package/src/form/validation.ts +17 -15
  314. package/src/hooks/navigation/useBuildNavigationStateController.tsx +3 -6
  315. package/src/hooks/navigation/useNavigationResolution.ts +143 -19
  316. package/src/hooks/navigation/useResolvedCollections.ts +4 -6
  317. package/src/hooks/useBreadcrumbsController.tsx +2 -34
  318. package/src/hooks/useBuildSideEntityController.tsx +25 -3
  319. package/src/preview/PropertyPreview.tsx +6 -2
  320. package/src/preview/components/ReferencePreview.tsx +64 -13
  321. package/src/preview/components/RelationPreview.tsx +101 -13
  322. package/src/preview/components/UserPreview.tsx +5 -14
  323. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +1 -1
  324. package/src/routes/RebaseRoute.tsx +5 -4
  325. package/src/types/components/PropertyPreviewProps.tsx +5 -0
  326. package/src/types/components/formex.tsx +1 -45
  327. package/src/types/fields.tsx +10 -1
  328. package/src/util/navigation_utils.ts +14 -4
  329. package/src/util/previews.ts +101 -4
  330. package/dist/CollectionEditorDialog-Bo86h-d-.js +0 -4574
  331. package/dist/CollectionEditorDialog-Bo86h-d-.js.map +0 -1
  332. package/dist/CollectionsStudioView-bsg4AT_Z.js +0 -217
  333. package/dist/CollectionsStudioView-bsg4AT_Z.js.map +0 -1
  334. package/dist/ExportCollectionAction-Cf-Id5uO.js +0 -446
  335. package/dist/ExportCollectionAction-Cf-Id5uO.js.map +0 -1
  336. package/dist/ImportCollectionAction-LN5sreK9.js +0 -685
  337. package/dist/ImportCollectionAction-LN5sreK9.js.map +0 -1
  338. package/dist/PropertyEditView-jCWCxmCz.js +0 -8197
  339. package/dist/PropertyEditView-jCWCxmCz.js.map +0 -1
  340. package/dist/collection_editor_ui.js.map +0 -1
  341. package/dist/index-BrqSvMG0.js +0 -8
  342. package/dist/index-BrqSvMG0.js.map +0 -1
  343. package/dist/index-Cb0bPnzZ.js +0 -12
  344. package/dist/index-Cb0bPnzZ.js.map +0 -1
  345. package/dist/index-z3H8iqsj.js +0 -462
  346. package/dist/index-z3H8iqsj.js.map +0 -1
  347. package/dist/index.js.map +0 -1
  348. package/dist/markdown-DD2JDU1X.js +0 -618
  349. package/dist/markdown-DD2JDU1X.js.map +0 -1
  350. package/dist/useEntityHistory-UVsSclfZ.js +0 -123
  351. package/dist/useEntityHistory-UVsSclfZ.js.map +0 -1
  352. package/dist/util-CvNp6A-r.js +0 -30505
  353. package/dist/util-CvNp6A-r.js.map +0 -1
@@ -1,4574 +0,0 @@
1
- import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
- import { c } from "react-compiler-runtime";
3
- import { useAuthController, useCustomizationController, IconForView, useSnackbarController, useLargeLayout, AIIcon, useRebaseContext, ErrorView, ConfirmationDialog, useUnsavedChangesDialog, UnsavedChangesDialog } from "@rebasepro/core";
4
- import { bm as useCollectionsConfigController, N as FieldCaption, ag as SearchIconsView, aO as getFieldConfig, a4 as PropertyConfigBadge, aQ as getFullId, aY as idToPropertiesPath, b0 as namespaceToPropertiesOrderPath, by as validateCollectionJson, bl as useCollectionRegistryController, l as CollectionGenerationApiError, bk as useCollectionEditorController, S as ImportFileUpload, aU as getInferenceType, T as ImportNewPropertyFieldPreview, p as DataNewPropertiesMapping, aP as getFieldId, bt as useSelectionController, aB as convertDataToEntity, y as EntityCollectionTable, bq as useNavigationStateController, bo as useImportConfig, bx as useUrlController, U as ImportSaveInProgress, aR as getFullIdPath } from "./util-CvNp6A-r.js";
5
- import * as React from "react";
6
- import React__default, { useState, useRef, useMemo, useEffect } from "react";
7
- import { Chip, Typography, cls, Tooltip, IconButton, TextField, DebouncedTextField, Dialog, Container, ColumnsIcon, SquareIcon, PanelLeftIcon, AppWindow, ToggleButtonGroup, ListIcon, TableIcon, LayoutGridIcon, KanbanIcon, Select, SelectItem, XIcon, iconSize, Button, BooleanSwitchWithLabel, DialogTitle, DialogContent, CopyIcon, DialogActions, CircularProgress, FileSearchIcon, PlusIcon, ErrorBoundary, defaultBorderMixin, CodeIcon, Alert, Menu, ShoppingCartIcon, UserIcon, FileTextIcon, FileIcon, Card, CircularProgressCenter, Paper, KeyIcon, Trash2Icon, MultiSelect, MultiSelectItem, coolIconKeys, Tabs, Tab, LoadingButton, ArrowLeftIcon, CheckIcon } from "@rebasepro/ui";
8
- import { isPropertyBuilder, getSubcollections, getTableName, removeInitialAndTrailingSlashes } from "@rebasepro/common";
9
- import "fast-equals";
10
- import { useFormex, getIn, Field, clone, useCreateFormex, Formex } from "@rebasepro/formex";
11
- import { z } from "zod";
12
- import { toSnakeCase, singular, unslugify, camelCase, isEmptyObject, prettifyIdentifier, slugify, randomString, removeUndefined, mergeDeep } from "@rebasepro/utils";
13
- import "react-dropzone";
14
- import "@dnd-kit/core";
15
- import "@dnd-kit/sortable";
16
- import "@dnd-kit/utilities";
17
- import { getDataSourceCapabilities } from "@rebasepro/types";
18
- import "@dnd-kit/modifiers";
19
- import "react-router-dom";
20
- import "exceljs";
21
- import { buildPropertyFromData, buildEntityPropertiesFromData } from "@rebasepro/schema-inference";
22
- import "date-fns";
23
- import "date-fns/locale";
24
- import "fuse.js";
25
- import { b as PropertyFormDialog, d as useAIModifiedPaths, c as PropertyTree, a as PropertyForm, s as supportedFields, u as updatePropertyFromWidget, A as AIModifiedPathsProvider } from "./PropertyEditView-jCWCxmCz.js";
26
- import JSON5 from "json5";
27
- import { Highlight, themes } from "prism-react-renderer";
28
- const CollectionEditorSchema = z.object({
29
- slug: z.string().min(1, "Required"),
30
- name: z.string().min(1, "Required"),
31
- table: z.string().min(1, "Required")
32
- });
33
- function GeneralSettingsForm(t0) {
34
- const $ = c(111);
35
- const {
36
- isNewCollection,
37
- parentCollection
38
- } = t0;
39
- const {
40
- values,
41
- setFieldValue,
42
- handleChange,
43
- touched,
44
- errors,
45
- setFieldTouched,
46
- submitCount
47
- } = useFormex();
48
- const [iconDialogOpen, setIconDialogOpen] = useState(false);
49
- useAuthController();
50
- useCustomizationController();
51
- const configController = useCollectionsConfigController();
52
- let t1;
53
- if ($[0] !== setFieldValue) {
54
- t1 = (databaseId) => {
55
- setFieldValue("databaseId", databaseId ?? void 0);
56
- };
57
- $[0] = setFieldValue;
58
- $[1] = t1;
59
- } else {
60
- t1 = $[1];
61
- }
62
- const updateDatabaseId = t1;
63
- let t2;
64
- if ($[2] !== isNewCollection || $[3] !== setFieldValue || $[4] !== touched) {
65
- t2 = (name) => {
66
- setFieldValue("name", name);
67
- const pathTouched = getIn(touched, "table");
68
- if (!pathTouched && isNewCollection && name) {
69
- setFieldValue("table", toSnakeCase(name));
70
- }
71
- const idTouched = getIn(touched, "slug");
72
- if (!idTouched && isNewCollection && name) {
73
- setFieldValue("slug", toSnakeCase(name));
74
- }
75
- const singularNameTouched = getIn(touched, "singularName");
76
- if (!singularNameTouched && isNewCollection && name) {
77
- setFieldValue("singularName", singular(name));
78
- }
79
- };
80
- $[2] = isNewCollection;
81
- $[3] = setFieldValue;
82
- $[4] = touched;
83
- $[5] = t2;
84
- } else {
85
- t2 = $[5];
86
- }
87
- const updateName = t2;
88
- let t3;
89
- if ($[6] !== values) {
90
- t3 = /* @__PURE__ */ jsx(IconForView, { collectionOrView: values });
91
- $[6] = values;
92
- $[7] = t3;
93
- } else {
94
- t3 = $[7];
95
- }
96
- const collectionIcon = t3;
97
- const isSubcollection = !!parentCollection;
98
- const showErrors = submitCount > 0;
99
- const t4 = !isNewCollection ? "h5" : "h4";
100
- const t5 = isNewCollection ? "New collection" : `${values?.name} collection`;
101
- let t6;
102
- if ($[8] !== t4 || $[9] !== t5) {
103
- t6 = /* @__PURE__ */ jsx(Typography, { variant: t4, className: "flex-grow", children: t5 });
104
- $[8] = t4;
105
- $[9] = t5;
106
- $[10] = t6;
107
- } else {
108
- t6 = $[10];
109
- }
110
- const t7 = configController?.readOnly;
111
- let t8;
112
- if ($[11] !== t7 || $[12] !== updateDatabaseId || $[13] !== values.databaseId) {
113
- t8 = /* @__PURE__ */ jsx(DefaultDatabaseField, { databaseId: values.databaseId, disabled: t7, onDatabaseIdUpdate: updateDatabaseId });
114
- $[11] = t7;
115
- $[12] = updateDatabaseId;
116
- $[13] = values.databaseId;
117
- $[14] = t8;
118
- } else {
119
- t8 = $[14];
120
- }
121
- const t9 = configController?.readOnly;
122
- let t10;
123
- if ($[15] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
124
- t10 = () => setIconDialogOpen(true);
125
- $[15] = t10;
126
- } else {
127
- t10 = $[15];
128
- }
129
- let t11;
130
- if ($[16] !== collectionIcon || $[17] !== t9) {
131
- t11 = /* @__PURE__ */ jsx(Tooltip, { title: "Change icon", asChild: true, children: /* @__PURE__ */ jsx(IconButton, { shape: "square", disabled: t9, onClick: t10, children: collectionIcon }) });
132
- $[16] = collectionIcon;
133
- $[17] = t9;
134
- $[18] = t11;
135
- } else {
136
- t11 = $[18];
137
- }
138
- let t12;
139
- if ($[19] !== t11 || $[20] !== t6 || $[21] !== t8) {
140
- t12 = /* @__PURE__ */ jsxs("div", { className: "flex flex-row gap-2 items-center", children: [
141
- t6,
142
- t8,
143
- t11
144
- ] });
145
- $[19] = t11;
146
- $[20] = t6;
147
- $[21] = t8;
148
- $[22] = t12;
149
- } else {
150
- t12 = $[22];
151
- }
152
- let t13;
153
- if ($[23] !== parentCollection) {
154
- t13 = parentCollection && /* @__PURE__ */ jsx(Chip, { colorScheme: "teal", children: /* @__PURE__ */ jsxs(Typography, { variant: "caption", children: [
155
- "This is a subcollection of ",
156
- /* @__PURE__ */ jsx("b", { children: parentCollection.name })
157
- ] }) });
158
- $[23] = parentCollection;
159
- $[24] = t13;
160
- } else {
161
- t13 = $[24];
162
- }
163
- let t14;
164
- if ($[25] !== t12 || $[26] !== t13) {
165
- t14 = /* @__PURE__ */ jsxs("div", { children: [
166
- t12,
167
- t13
168
- ] });
169
- $[25] = t12;
170
- $[26] = t13;
171
- $[27] = t14;
172
- } else {
173
- t14 = $[27];
174
- }
175
- const t15 = configController?.readOnly;
176
- const t16 = values.name ?? "";
177
- let t17;
178
- if ($[28] !== updateName) {
179
- t17 = (e) => updateName(e.target.value);
180
- $[28] = updateName;
181
- $[29] = t17;
182
- } else {
183
- t17 = $[29];
184
- }
185
- const t18 = showErrors && Boolean(errors.name);
186
- let t19;
187
- if ($[30] !== t16 || $[31] !== t17 || $[32] !== t18) {
188
- t19 = /* @__PURE__ */ jsx(TextField, { value: t16, onChange: t17, label: "Name", autoFocus: true, required: true, error: t18 });
189
- $[30] = t16;
190
- $[31] = t17;
191
- $[32] = t18;
192
- $[33] = t19;
193
- } else {
194
- t19 = $[33];
195
- }
196
- const t20 = touched.name && Boolean(errors.name);
197
- const t21 = touched.name && Boolean(errors.name) ? errors.name : "Name of this collection, usually a plural name (e.g. Products)";
198
- let t22;
199
- if ($[34] !== t20 || $[35] !== t21) {
200
- t22 = /* @__PURE__ */ jsx(FieldCaption, { error: t20, children: t21 });
201
- $[34] = t20;
202
- $[35] = t21;
203
- $[36] = t22;
204
- } else {
205
- t22 = $[36];
206
- }
207
- let t23;
208
- if ($[37] !== t19 || $[38] !== t22) {
209
- t23 = /* @__PURE__ */ jsxs("div", { className: "col-span-12", children: [
210
- t19,
211
- t22
212
- ] });
213
- $[37] = t19;
214
- $[38] = t22;
215
- $[39] = t23;
216
- } else {
217
- t23 = $[39];
218
- }
219
- let t24;
220
- if ($[40] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
221
- t24 = cls("col-span-12");
222
- $[40] = t24;
223
- } else {
224
- t24 = $[40];
225
- }
226
- const t25 = showErrors && Boolean(errors.table);
227
- let t26;
228
- if ($[41] !== t25) {
229
- t26 = /* @__PURE__ */ jsx(Field, { name: "table", as: DebouncedTextField, label: "Table name", required: true, error: t25 });
230
- $[41] = t25;
231
- $[42] = t26;
232
- } else {
233
- t26 = $[42];
234
- }
235
- const t27 = touched.table && Boolean(errors.table);
236
- const t28 = touched.table && Boolean(errors.table) ? errors.table : isSubcollection ? "Relative path to the parent (no need to include the parent path)" : "PostgreSQL table name for this collection";
237
- let t29;
238
- if ($[43] !== t27 || $[44] !== t28) {
239
- t29 = /* @__PURE__ */ jsx(FieldCaption, { error: t27, children: t28 });
240
- $[43] = t27;
241
- $[44] = t28;
242
- $[45] = t29;
243
- } else {
244
- t29 = $[45];
245
- }
246
- let t30;
247
- if ($[46] !== t26 || $[47] !== t29) {
248
- t30 = /* @__PURE__ */ jsxs("div", { className: t24, children: [
249
- t26,
250
- t29
251
- ] });
252
- $[46] = t26;
253
- $[47] = t29;
254
- $[48] = t30;
255
- } else {
256
- t30 = $[48];
257
- }
258
- const t31 = showErrors && Boolean(errors.singularName);
259
- let t32;
260
- if ($[49] !== handleChange || $[50] !== setFieldTouched) {
261
- t32 = (e_0) => {
262
- setFieldTouched("singularName", true);
263
- return handleChange(e_0);
264
- };
265
- $[49] = handleChange;
266
- $[50] = setFieldTouched;
267
- $[51] = t32;
268
- } else {
269
- t32 = $[51];
270
- }
271
- const t33 = values.singularName ?? "";
272
- let t34;
273
- if ($[52] !== t31 || $[53] !== t32 || $[54] !== t33) {
274
- t34 = /* @__PURE__ */ jsx(TextField, { error: t31, name: "singularName", "aria-describedby": "singularName-helper", onChange: t32, value: t33, label: "Singular name" });
275
- $[52] = t31;
276
- $[53] = t32;
277
- $[54] = t33;
278
- $[55] = t34;
279
- } else {
280
- t34 = $[55];
281
- }
282
- const t35 = showErrors && Boolean(errors.singularName);
283
- const t36 = showErrors && Boolean(errors.singularName) ? errors.singularName : "Optionally define a singular name for your entities";
284
- let t37;
285
- if ($[56] !== t35 || $[57] !== t36) {
286
- t37 = /* @__PURE__ */ jsx(FieldCaption, { error: t35, children: t36 });
287
- $[56] = t35;
288
- $[57] = t36;
289
- $[58] = t37;
290
- } else {
291
- t37 = $[58];
292
- }
293
- let t38;
294
- if ($[59] !== t34 || $[60] !== t37) {
295
- t38 = /* @__PURE__ */ jsxs("div", { className: "col-span-12", children: [
296
- t34,
297
- t37
298
- ] });
299
- $[59] = t34;
300
- $[60] = t37;
301
- $[61] = t38;
302
- } else {
303
- t38 = $[61];
304
- }
305
- const t39 = showErrors && Boolean(errors.description);
306
- const t40 = values.description ?? "";
307
- let t41;
308
- if ($[62] !== handleChange || $[63] !== t39 || $[64] !== t40) {
309
- t41 = /* @__PURE__ */ jsx(TextField, { error: t39, name: "description", value: t40, onChange: handleChange, multiline: true, minRows: 2, "aria-describedby": "description-helper-text", label: "Description" });
310
- $[62] = handleChange;
311
- $[63] = t39;
312
- $[64] = t40;
313
- $[65] = t41;
314
- } else {
315
- t41 = $[65];
316
- }
317
- const t42 = showErrors && Boolean(errors.description);
318
- const t43 = showErrors && Boolean(errors.description) ? errors.description : "Description of the collection, you can use markdown";
319
- let t44;
320
- if ($[66] !== t42 || $[67] !== t43) {
321
- t44 = /* @__PURE__ */ jsx(FieldCaption, { error: t42, children: t43 });
322
- $[66] = t42;
323
- $[67] = t43;
324
- $[68] = t44;
325
- } else {
326
- t44 = $[68];
327
- }
328
- let t45;
329
- if ($[69] !== t41 || $[70] !== t44) {
330
- t45 = /* @__PURE__ */ jsxs("div", { className: "col-span-12", children: [
331
- t41,
332
- t44
333
- ] });
334
- $[69] = t41;
335
- $[70] = t44;
336
- $[71] = t45;
337
- } else {
338
- t45 = $[71];
339
- }
340
- const t46 = values.slug ?? "";
341
- let t47;
342
- if ($[72] !== setFieldValue) {
343
- t47 = (e_1) => setFieldValue("slug", e_1.target.value);
344
- $[72] = setFieldValue;
345
- $[73] = t47;
346
- } else {
347
- t47 = $[73];
348
- }
349
- const t48 = !isNewCollection;
350
- const t49 = showErrors && Boolean(errors.slug);
351
- let t50;
352
- if ($[74] !== t46 || $[75] !== t47 || $[76] !== t48 || $[77] !== t49) {
353
- t50 = /* @__PURE__ */ jsx(DebouncedTextField, { name: "slug", value: t46, onChange: t47, disabled: t48, label: "Collection ID", error: t49 });
354
- $[74] = t46;
355
- $[75] = t47;
356
- $[76] = t48;
357
- $[77] = t49;
358
- $[78] = t50;
359
- } else {
360
- t50 = $[78];
361
- }
362
- const t51 = touched.slug && Boolean(errors.slug);
363
- const t52 = touched.slug && Boolean(errors.slug) ? errors.slug : "This ID identifies this collection. Typically the same as the path.";
364
- let t53;
365
- if ($[79] !== t51 || $[80] !== t52) {
366
- t53 = /* @__PURE__ */ jsx(FieldCaption, { error: t51, children: t52 });
367
- $[79] = t51;
368
- $[80] = t52;
369
- $[81] = t53;
370
- } else {
371
- t53 = $[81];
372
- }
373
- let t54;
374
- if ($[82] !== t50 || $[83] !== t53) {
375
- t54 = /* @__PURE__ */ jsxs("div", { className: "col-span-12", children: [
376
- t50,
377
- t53
378
- ] });
379
- $[82] = t50;
380
- $[83] = t53;
381
- $[84] = t54;
382
- } else {
383
- t54 = $[84];
384
- }
385
- let t55;
386
- if ($[85] !== t23 || $[86] !== t30 || $[87] !== t38 || $[88] !== t45 || $[89] !== t54) {
387
- t55 = /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-12 gap-4", children: [
388
- t23,
389
- t30,
390
- t38,
391
- t45,
392
- t54
393
- ] });
394
- $[85] = t23;
395
- $[86] = t30;
396
- $[87] = t38;
397
- $[88] = t45;
398
- $[89] = t54;
399
- $[90] = t55;
400
- } else {
401
- t55 = $[90];
402
- }
403
- let t56;
404
- if ($[91] !== setFieldValue || $[92] !== values.history) {
405
- t56 = null;
406
- $[91] = setFieldValue;
407
- $[92] = values.history;
408
- $[93] = t56;
409
- } else {
410
- t56 = $[93];
411
- }
412
- let t57;
413
- if ($[94] !== t15 || $[95] !== t55 || $[96] !== t56) {
414
- t57 = /* @__PURE__ */ jsxs("fieldset", { disabled: t15, className: "contents", children: [
415
- t55,
416
- t56
417
- ] });
418
- $[94] = t15;
419
- $[95] = t55;
420
- $[96] = t56;
421
- $[97] = t57;
422
- } else {
423
- t57 = $[97];
424
- }
425
- let t58;
426
- if ($[98] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
427
- t58 = /* @__PURE__ */ jsx("div", { style: {
428
- height: "52px"
429
- } });
430
- $[98] = t58;
431
- } else {
432
- t58 = $[98];
433
- }
434
- const t59 = typeof values.icon === "string" ? values.icon : void 0;
435
- let t60;
436
- if ($[99] !== setFieldValue) {
437
- t60 = (icon) => {
438
- setIconDialogOpen(false);
439
- setFieldValue("icon", icon);
440
- };
441
- $[99] = setFieldValue;
442
- $[100] = t60;
443
- } else {
444
- t60 = $[100];
445
- }
446
- let t61;
447
- if ($[101] !== t59 || $[102] !== t60) {
448
- t61 = /* @__PURE__ */ jsx("div", { className: "p-4 overflow-auto min-h-[200px]", children: /* @__PURE__ */ jsx(SearchIconsView, { selectedIcon: t59, onIconSelected: t60 }) });
449
- $[101] = t59;
450
- $[102] = t60;
451
- $[103] = t61;
452
- } else {
453
- t61 = $[103];
454
- }
455
- let t62;
456
- if ($[104] !== iconDialogOpen || $[105] !== t61) {
457
- t62 = /* @__PURE__ */ jsx(Dialog, { open: iconDialogOpen, onOpenChange: setIconDialogOpen, maxWidth: "xl", fullWidth: true, children: t61 });
458
- $[104] = iconDialogOpen;
459
- $[105] = t61;
460
- $[106] = t62;
461
- } else {
462
- t62 = $[106];
463
- }
464
- let t63;
465
- if ($[107] !== t14 || $[108] !== t57 || $[109] !== t62) {
466
- t63 = /* @__PURE__ */ jsx("div", { className: "overflow-auto my-auto", children: /* @__PURE__ */ jsxs(Container, { maxWidth: "4xl", className: "flex flex-col gap-4 p-8 m-auto", children: [
467
- t14,
468
- t57,
469
- t58,
470
- t62
471
- ] }) });
472
- $[107] = t14;
473
- $[108] = t57;
474
- $[109] = t62;
475
- $[110] = t63;
476
- } else {
477
- t63 = $[110];
478
- }
479
- return t63;
480
- }
481
- function DefaultDatabaseField(t0) {
482
- const $ = c(6);
483
- const {
484
- databaseId,
485
- disabled: t1,
486
- onDatabaseIdUpdate
487
- } = t0;
488
- const disabled = t1 === void 0 ? false : t1;
489
- const t2 = databaseId ?? "";
490
- let t3;
491
- if ($[0] !== onDatabaseIdUpdate) {
492
- t3 = (e) => onDatabaseIdUpdate(e.target.value);
493
- $[0] = onDatabaseIdUpdate;
494
- $[1] = t3;
495
- } else {
496
- t3 = $[1];
497
- }
498
- let t4;
499
- if ($[2] !== disabled || $[3] !== t2 || $[4] !== t3) {
500
- t4 = /* @__PURE__ */ jsx(Tooltip, { title: "Database ID", side: "top", align: "start", children: /* @__PURE__ */ jsx(TextField, { size: "small", invisible: true, inputClassName: "text-end", disabled, value: t2, onChange: t3, placeholder: "(default)" }) });
501
- $[2] = disabled;
502
- $[3] = t2;
503
- $[4] = t3;
504
- $[5] = t4;
505
- } else {
506
- t4 = $[5];
507
- }
508
- return t4;
509
- }
510
- function LayoutModeSwitch(t0) {
511
- const $ = c(14);
512
- const {
513
- value,
514
- onChange,
515
- className
516
- } = t0;
517
- let t1;
518
- if ($[0] !== className) {
519
- t1 = cls(className);
520
- $[0] = className;
521
- $[1] = t1;
522
- } else {
523
- t1 = $[1];
524
- }
525
- let t2;
526
- if ($[2] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
527
- t2 = /* @__PURE__ */ jsx(Typography, { variant: "label", color: "secondary", className: "ml-3.5", children: "Document view" });
528
- $[2] = t2;
529
- } else {
530
- t2 = $[2];
531
- }
532
- let t3;
533
- if ($[3] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
534
- t3 = {
535
- value: "side_panel",
536
- label: "Side panel",
537
- icon: /* @__PURE__ */ jsx(ColumnsIcon, {})
538
- };
539
- $[3] = t3;
540
- } else {
541
- t3 = $[3];
542
- }
543
- let t4;
544
- if ($[4] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
545
- t4 = {
546
- value: "full_screen",
547
- label: "Full screen",
548
- icon: /* @__PURE__ */ jsx(SquareIcon, {})
549
- };
550
- $[4] = t4;
551
- } else {
552
- t4 = $[4];
553
- }
554
- let t5;
555
- if ($[5] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
556
- t5 = {
557
- value: "split",
558
- label: "Split view",
559
- icon: /* @__PURE__ */ jsx(PanelLeftIcon, {})
560
- };
561
- $[5] = t5;
562
- } else {
563
- t5 = $[5];
564
- }
565
- let t6;
566
- if ($[6] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
567
- t6 = [t3, t4, t5, {
568
- value: "dialog",
569
- label: "Centered dialog",
570
- icon: /* @__PURE__ */ jsx(AppWindow, {})
571
- }];
572
- $[6] = t6;
573
- } else {
574
- t6 = $[6];
575
- }
576
- let t7;
577
- if ($[7] !== onChange || $[8] !== value) {
578
- t7 = /* @__PURE__ */ jsx("div", { className: "my-2", children: /* @__PURE__ */ jsx(ToggleButtonGroup, { value, onValueChange: onChange, options: t6 }) });
579
- $[7] = onChange;
580
- $[8] = value;
581
- $[9] = t7;
582
- } else {
583
- t7 = $[9];
584
- }
585
- let t8;
586
- if ($[10] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
587
- t8 = /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "ml-3.5", children: "Should documents be opened full screen, inline side dialog, or centered dialog" });
588
- $[10] = t8;
589
- } else {
590
- t8 = $[10];
591
- }
592
- let t9;
593
- if ($[11] !== t1 || $[12] !== t7) {
594
- t9 = /* @__PURE__ */ jsxs("div", { className: t1, children: [
595
- t2,
596
- t7,
597
- t8
598
- ] });
599
- $[11] = t1;
600
- $[12] = t7;
601
- $[13] = t9;
602
- } else {
603
- t9 = $[13];
604
- }
605
- return t9;
606
- }
607
- function ViewModeSwitch(t0) {
608
- const $ = c(14);
609
- const {
610
- value,
611
- onChange,
612
- className
613
- } = t0;
614
- let t1;
615
- if ($[0] !== className) {
616
- t1 = cls(className);
617
- $[0] = className;
618
- $[1] = t1;
619
- } else {
620
- t1 = $[1];
621
- }
622
- let t2;
623
- if ($[2] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
624
- t2 = /* @__PURE__ */ jsx(Typography, { variant: "label", color: "secondary", className: "ml-3.5", children: "Default collection view" });
625
- $[2] = t2;
626
- } else {
627
- t2 = $[2];
628
- }
629
- let t3;
630
- if ($[3] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
631
- t3 = {
632
- value: "list",
633
- label: "List",
634
- icon: /* @__PURE__ */ jsx(ListIcon, {})
635
- };
636
- $[3] = t3;
637
- } else {
638
- t3 = $[3];
639
- }
640
- let t4;
641
- if ($[4] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
642
- t4 = {
643
- value: "table",
644
- label: "Table",
645
- icon: /* @__PURE__ */ jsx(TableIcon, {})
646
- };
647
- $[4] = t4;
648
- } else {
649
- t4 = $[4];
650
- }
651
- let t5;
652
- if ($[5] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
653
- t5 = {
654
- value: "cards",
655
- label: "Cards",
656
- icon: /* @__PURE__ */ jsx(LayoutGridIcon, {})
657
- };
658
- $[5] = t5;
659
- } else {
660
- t5 = $[5];
661
- }
662
- let t6;
663
- if ($[6] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
664
- t6 = [t3, t4, t5, {
665
- value: "kanban",
666
- label: "Kanban",
667
- icon: /* @__PURE__ */ jsx(KanbanIcon, {})
668
- }];
669
- $[6] = t6;
670
- } else {
671
- t6 = $[6];
672
- }
673
- let t7;
674
- if ($[7] !== onChange || $[8] !== value) {
675
- t7 = /* @__PURE__ */ jsx("div", { className: "my-2", children: /* @__PURE__ */ jsx(ToggleButtonGroup, { value, onValueChange: onChange, options: t6 }) });
676
- $[7] = onChange;
677
- $[8] = value;
678
- $[9] = t7;
679
- } else {
680
- t7 = $[9];
681
- }
682
- let t8;
683
- if ($[10] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
684
- t8 = /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "ml-3.5", children: "Choose how entities should be displayed by default" });
685
- $[10] = t8;
686
- } else {
687
- t8 = $[10];
688
- }
689
- let t9;
690
- if ($[11] !== t1 || $[12] !== t7) {
691
- t9 = /* @__PURE__ */ jsxs("div", { className: t1, children: [
692
- t2,
693
- t7,
694
- t8
695
- ] });
696
- $[11] = t1;
697
- $[12] = t7;
698
- $[13] = t9;
699
- } else {
700
- t9 = $[13];
701
- }
702
- return t9;
703
- }
704
- function KanbanConfigSection({
705
- className,
706
- forceExpanded
707
- }) {
708
- useAuthController();
709
- const customizationController = useCustomizationController();
710
- const {
711
- values,
712
- setFieldValue
713
- } = useFormex();
714
- const panelRef = useRef(null);
715
- const [columnPropertyDialogOpen, setColumnPropertyDialogOpen] = useState(false);
716
- const enumStringProperties = useMemo(() => {
717
- const result = [];
718
- if (!values.properties) return result;
719
- Object.entries(values.properties).forEach(([key, prop]) => {
720
- if (prop && "type" in prop && prop.type === "string" && prop.enum) {
721
- result.push({
722
- key,
723
- label: prop.name || key,
724
- property: prop
725
- });
726
- }
727
- });
728
- return result;
729
- }, [values.properties]);
730
- const kanbanConfig = values.kanban;
731
- const columnPropertyMissing = Boolean(kanbanConfig?.columnProperty) && !enumStringProperties.some((p) => p.key === kanbanConfig?.columnProperty);
732
- React__default.useEffect(() => {
733
- if (forceExpanded && panelRef.current) {
734
- setTimeout(() => {
735
- panelRef.current?.scrollIntoView({
736
- behavior: "smooth",
737
- block: "center"
738
- });
739
- }, 100);
740
- }
741
- }, [forceExpanded]);
742
- const showCreateButton = !kanbanConfig?.columnProperty || columnPropertyMissing;
743
- const dialogPropertyKey = columnPropertyMissing && kanbanConfig?.columnProperty ? kanbanConfig.columnProperty : "status";
744
- const dialogPropertyName = columnPropertyMissing && kanbanConfig?.columnProperty ? unslugify(kanbanConfig.columnProperty) : "Status";
745
- return /* @__PURE__ */ jsxs("div", { className, ref: panelRef, children: [
746
- /* @__PURE__ */ jsx(Select, { name: "kanban.columnProperty", label: "Kanban Column Property", fullWidth: true, position: "item-aligned", disabled: enumStringProperties.length === 0, error: columnPropertyMissing, value: kanbanConfig?.columnProperty ?? "", onValueChange: (v) => {
747
- if (v) {
748
- setFieldValue("kanban", {
749
- ...kanbanConfig,
750
- columnProperty: v
751
- });
752
- } else {
753
- setFieldValue("kanban", void 0);
754
- }
755
- }, renderValue: (value) => {
756
- if (columnPropertyMissing) {
757
- return /* @__PURE__ */ jsxs("span", { className: "text-red-500", children: [
758
- value,
759
- " (not found)"
760
- ] });
761
- }
762
- const prop_0 = enumStringProperties.find((p_0) => p_0.key === value);
763
- if (!prop_0) return "Select a property";
764
- const fieldConfig = getFieldConfig(prop_0.property, customizationController.propertyConfigs);
765
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
766
- /* @__PURE__ */ jsx(PropertyConfigBadge, { propertyConfig: fieldConfig }),
767
- /* @__PURE__ */ jsx("span", { children: prop_0.label })
768
- ] });
769
- }, endAdornment: kanbanConfig?.columnProperty ? /* @__PURE__ */ jsx(IconButton, { size: "small", onClick: (e) => {
770
- e.stopPropagation();
771
- setFieldValue("kanban", void 0);
772
- }, children: /* @__PURE__ */ jsx(XIcon, { size: iconSize.smallest }) }) : void 0, children: enumStringProperties.map((prop_1) => {
773
- const fieldConfig_0 = getFieldConfig(prop_1.property, customizationController.propertyConfigs);
774
- return /* @__PURE__ */ jsx(SelectItem, { value: prop_1.key, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
775
- /* @__PURE__ */ jsx(PropertyConfigBadge, { propertyConfig: fieldConfig_0 }),
776
- /* @__PURE__ */ jsxs("div", { children: [
777
- /* @__PURE__ */ jsx("div", { children: prop_1.label }),
778
- /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: fieldConfig_0?.name || "Enum" })
779
- ] })
780
- ] }) }, prop_1.key);
781
- }) }, `column-select-${enumStringProperties.length}`),
782
- /* @__PURE__ */ jsx(FieldCaption, { error: columnPropertyMissing, children: columnPropertyMissing ? `Property "${kanbanConfig?.columnProperty}" does not exist or is not an enum string property. Please select a valid property or clear the selection.` : enumStringProperties.length === 0 ? "No enum string properties found. Add a string property with enum to use Kanban view." : "Select a string property with enum values to group entities into columns" }),
783
- showCreateButton && /* @__PURE__ */ jsxs(Fragment, { children: [
784
- /* @__PURE__ */ jsxs(Button, { variant: "text", size: "small", className: "ml-3.5 mt-2", onClick: () => setColumnPropertyDialogOpen(true), children: [
785
- '+ Create "',
786
- dialogPropertyKey,
787
- '" property'
788
- ] }),
789
- /* @__PURE__ */ jsx(PropertyFormDialog, { open: columnPropertyDialogOpen, onCancel: () => setColumnPropertyDialogOpen(false), property: {
790
- type: "string",
791
- name: dialogPropertyName,
792
- enum: [{
793
- id: "todo",
794
- label: "To Do"
795
- }, {
796
- id: "in_progress",
797
- label: "In Progress"
798
- }, {
799
- id: "done",
800
- label: "Done"
801
- }]
802
- }, propertyKey: dialogPropertyKey, existingProperty: false, autoOpenTypeSelect: false, autoUpdateId: false, inArray: false, allowDataInference: false, propertyConfigs: customizationController.propertyConfigs, existingPropertyKeys: Object.keys(values.properties ?? {}), onPropertyChanged: ({
803
- id,
804
- property
805
- }) => {
806
- const newProperties = {
807
- ...values.properties,
808
- [id]: property
809
- };
810
- const newPropertiesOrder = [...values.propertiesOrder ?? Object.keys(values.properties ?? {}), id];
811
- setFieldValue("properties", newProperties);
812
- setFieldValue("propertiesOrder", newPropertiesOrder);
813
- setFieldValue("kanban", {
814
- ...kanbanConfig,
815
- columnProperty: id
816
- });
817
- setColumnPropertyDialogOpen(false);
818
- } })
819
- ] })
820
- ] });
821
- }
822
- function DisplaySettingsForm({
823
- expandKanban
824
- }) {
825
- const {
826
- values,
827
- setFieldValue,
828
- handleChange,
829
- submitCount
830
- } = useFormex();
831
- const [orderPropertyDialogOpen, setOrderPropertyDialogOpen] = useState(false);
832
- useAuthController();
833
- const customizationController = useCustomizationController();
834
- const configController = useCollectionsConfigController();
835
- const textProperties = useMemo(() => {
836
- const result = [];
837
- if (!values.properties) return result;
838
- Object.entries(values.properties).forEach(([key, prop]) => {
839
- if (prop && "type" in prop && prop.type === "string") {
840
- result.push({
841
- key,
842
- label: prop.name || key,
843
- property: prop
844
- });
845
- }
846
- });
847
- return result;
848
- }, [values.properties]);
849
- return /* @__PURE__ */ jsx("div", { className: "overflow-auto my-auto", children: /* @__PURE__ */ jsxs(Container, { maxWidth: "4xl", className: "flex flex-col gap-4 p-8 m-auto", children: [
850
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "flex-grow", children: "Display settings" }) }),
851
- /* @__PURE__ */ jsx("fieldset", { disabled: configController?.readOnly, className: "contents", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-12 gap-4", children: [
852
- /* @__PURE__ */ jsx(LayoutModeSwitch, { className: "col-span-12", value: values.openEntityMode ?? "side_panel", onChange: (value) => setFieldValue("openEntityMode", value) }),
853
- /* @__PURE__ */ jsx(ViewModeSwitch, { className: "col-span-12", value: values.defaultViewMode ?? "table", onChange: (value_0) => setFieldValue("defaultViewMode", value_0) }),
854
- /* @__PURE__ */ jsx(KanbanConfigSection, { className: "col-span-12", forceExpanded: expandKanban }),
855
- /* @__PURE__ */ jsxs("div", { className: "col-span-12 mt-4", children: [
856
- (() => {
857
- const orderPropertyMissing = Boolean(values.orderProperty) && !textProperties.some((p) => p.key === values.orderProperty);
858
- return /* @__PURE__ */ jsxs(Fragment, { children: [
859
- /* @__PURE__ */ jsx(Select, { name: "orderProperty", label: "Order Property", fullWidth: true, position: "item-aligned", disabled: textProperties.length === 0, error: orderPropertyMissing, value: values.orderProperty ?? "", onValueChange: (v) => {
860
- setFieldValue("orderProperty", v || void 0);
861
- }, renderValue: (value_1) => {
862
- if (orderPropertyMissing) {
863
- return /* @__PURE__ */ jsxs("span", { className: "text-red-500", children: [
864
- value_1,
865
- " (not found)"
866
- ] });
867
- }
868
- const prop_0 = textProperties.find((p_0) => p_0.key === value_1);
869
- if (!prop_0) return "Select a property";
870
- const fieldConfig = getFieldConfig(prop_0.property, customizationController.propertyConfigs);
871
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
872
- /* @__PURE__ */ jsx(PropertyConfigBadge, { propertyConfig: fieldConfig }),
873
- /* @__PURE__ */ jsx("span", { children: prop_0.label })
874
- ] });
875
- }, endAdornment: values.orderProperty ? /* @__PURE__ */ jsx(IconButton, { size: "small", onClick: (e) => {
876
- e.stopPropagation();
877
- setFieldValue("orderProperty", void 0);
878
- }, children: /* @__PURE__ */ jsx(XIcon, { size: iconSize.smallest }) }) : void 0, children: textProperties.map((prop_1) => {
879
- const fieldConfig_0 = getFieldConfig(prop_1.property, customizationController.propertyConfigs);
880
- return /* @__PURE__ */ jsx(SelectItem, { value: prop_1.key, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
881
- /* @__PURE__ */ jsx(PropertyConfigBadge, { propertyConfig: fieldConfig_0 }),
882
- /* @__PURE__ */ jsxs("div", { children: [
883
- /* @__PURE__ */ jsx("div", { children: prop_1.label }),
884
- /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: fieldConfig_0?.name || "Text" })
885
- ] })
886
- ] }) }, prop_1.key);
887
- }) }, `order-select-${textProperties.length}`),
888
- /* @__PURE__ */ jsx(FieldCaption, { error: orderPropertyMissing, children: orderPropertyMissing ? `Property "${values.orderProperty}" does not exist or is not a text property. Please select a valid property or clear the selection.` : textProperties.length === 0 ? "No text properties found. Add a text property to enable ordering." : "Select a text property to persist the order of items" })
889
- ] });
890
- })(),
891
- (() => {
892
- const orderPropertyMissing_0 = Boolean(values.orderProperty) && !textProperties.some((p_1) => p_1.key === values.orderProperty);
893
- const showCreateButton = !values.orderProperty || orderPropertyMissing_0;
894
- const dialogPropertyKey = orderPropertyMissing_0 && values.orderProperty ? values.orderProperty : "__order";
895
- const dialogPropertyName = orderPropertyMissing_0 && values.orderProperty ? unslugify(values.orderProperty) : "Order";
896
- if (!showCreateButton) return null;
897
- return /* @__PURE__ */ jsxs(Fragment, { children: [
898
- /* @__PURE__ */ jsxs(Button, { variant: "text", size: "small", className: "ml-3.5 mt-2", onClick: () => setOrderPropertyDialogOpen(true), children: [
899
- '+ Create "',
900
- dialogPropertyKey,
901
- '" property'
902
- ] }),
903
- /* @__PURE__ */ jsx(PropertyFormDialog, { open: orderPropertyDialogOpen, onCancel: () => setOrderPropertyDialogOpen(false), property: {
904
- type: "string",
905
- name: dialogPropertyName,
906
- ui: {
907
- disabled: true,
908
- hideFromCollection: true
909
- }
910
- }, propertyKey: dialogPropertyKey, existingProperty: false, autoOpenTypeSelect: false, autoUpdateId: false, inArray: false, allowDataInference: false, propertyConfigs: customizationController.propertyConfigs, existingPropertyKeys: Object.keys(values.properties ?? {}), onPropertyChanged: ({
911
- id,
912
- property
913
- }) => {
914
- const newProperties = {
915
- ...values.properties,
916
- [id]: property
917
- };
918
- const newPropertiesOrder = [...values.propertiesOrder ?? Object.keys(values.properties ?? {}), id];
919
- setFieldValue("properties", newProperties);
920
- setFieldValue("propertiesOrder", newPropertiesOrder);
921
- setFieldValue("orderProperty", id);
922
- setOrderPropertyDialogOpen(false);
923
- } })
924
- ] });
925
- })()
926
- ] }),
927
- /* @__PURE__ */ jsx("div", { className: "col-span-12", children: /* @__PURE__ */ jsx(Select, { name: "defaultSize", fullWidth: true, label: "Default row size", position: "item-aligned", onChange: handleChange, value: values.defaultSize ?? "", renderValue: (value_2) => value_2.toUpperCase(), children: ["xs", "s", "m", "l", "xl"].map((value_3) => /* @__PURE__ */ jsx(SelectItem, { value: value_3, children: value_3.toUpperCase() }, `size-select-${value_3}`)) }) }),
928
- /* @__PURE__ */ jsxs("div", { className: "col-span-12", children: [
929
- /* @__PURE__ */ jsx(TextField, { name: "sideDialogWidth", type: "number", "aria-describedby": "sideDialogWidth-helper", onChange: (e_0) => {
930
- const value_4 = e_0.target.value;
931
- if (!value_4) {
932
- setFieldValue("sideDialogWidth", null);
933
- } else if (!isNaN(Number(value_4))) {
934
- setFieldValue("sideDialogWidth", Number(value_4));
935
- }
936
- }, endAdornment: /* @__PURE__ */ jsx(IconButton, { size: "small", onClick: () => {
937
- setFieldValue("sideDialogWidth", null);
938
- }, disabled: !values.sideDialogWidth, children: /* @__PURE__ */ jsx(XIcon, { size: iconSize.small }) }), value: values.sideDialogWidth ?? "", label: "Side dialog width" }),
939
- /* @__PURE__ */ jsx(FieldCaption, { children: "Optionally define the width (in pixels) of entities side dialog. Default is 768px" })
940
- ] }),
941
- /* @__PURE__ */ jsxs("div", { className: "col-span-12", children: [
942
- /* @__PURE__ */ jsx(BooleanSwitchWithLabel, { position: "start", label: values.inlineEditing === void 0 || values.inlineEditing ? "Data can be edited directly in the table view" : "Data can be edited only in the form view", onValueChange: (v_0) => setFieldValue("inlineEditing", v_0), value: values.inlineEditing === void 0 ? true : values.inlineEditing }),
943
- /* @__PURE__ */ jsx(FieldCaption, { children: "Allow editing data directly in the table view, without opening the form view." })
944
- ] }),
945
- /* @__PURE__ */ jsxs("div", { className: "col-span-12", children: [
946
- /* @__PURE__ */ jsx(BooleanSwitchWithLabel, { position: "start", label: values.includeJsonView === void 0 || values.includeJsonView ? "Include JSON view" : "Do not include JSON view", onValueChange: (v_1) => setFieldValue("includeJsonView", v_1), value: values.includeJsonView === void 0 ? true : values.includeJsonView }),
947
- /* @__PURE__ */ jsx(FieldCaption, { children: "Allows removing the form view JSON tab if you think it is confusing for your users." })
948
- ] })
949
- ] }) }),
950
- /* @__PURE__ */ jsx("div", { style: {
951
- height: "52px"
952
- } })
953
- ] }) });
954
- }
955
- function GetCodeDialog(t0) {
956
- const $ = c(22);
957
- const {
958
- collection,
959
- onOpenChange,
960
- open
961
- } = t0;
962
- const snackbarController = useSnackbarController();
963
- const code = collection ? 'import { EntityCollection } from "@rebasepro/core";\n\nconst ' + (collection?.name ? camelCase(collection.name) : "my") + "Collection:EntityCollection = " + JSON5.stringify(collectionToCode({
964
- ...collection
965
- }), null, " ") : "No collection selected";
966
- let t1;
967
- if ($[0] !== collection.name) {
968
- t1 = /* @__PURE__ */ jsxs(DialogTitle, { variant: "h6", children: [
969
- "Code for ",
970
- collection.name
971
- ] });
972
- $[0] = collection.name;
973
- $[1] = t1;
974
- } else {
975
- t1 = $[1];
976
- }
977
- let t2;
978
- if ($[2] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
979
- t2 = /* @__PURE__ */ jsxs(Typography, { variant: "body2", className: "my-4 mb-8", children: [
980
- "If you want to customise the collection in code, you can add this collection code to your CMS app configuration. More info in the ",
981
- /* @__PURE__ */ jsx("a", { rel: "noopener noreferrer", href: "https://rebase.pro/docs/cloud/quickstart", children: "docs" }),
982
- "."
983
- ] });
984
- $[2] = t2;
985
- } else {
986
- t2 = $[2];
987
- }
988
- let t3;
989
- if ($[3] !== code) {
990
- t3 = /* @__PURE__ */ jsxs(DialogContent, { children: [
991
- t2,
992
- /* @__PURE__ */ jsx(Highlight, { theme: themes.vsDark, code, language: "typescript", children: _temp$4 })
993
- ] });
994
- $[3] = code;
995
- $[4] = t3;
996
- } else {
997
- t3 = $[4];
998
- }
999
- let t4;
1000
- if ($[5] !== code || $[6] !== snackbarController) {
1001
- t4 = (e) => {
1002
- e.stopPropagation();
1003
- e.preventDefault();
1004
- snackbarController.open({
1005
- type: "success",
1006
- message: "Copied"
1007
- });
1008
- return navigator.clipboard.writeText(code);
1009
- };
1010
- $[5] = code;
1011
- $[6] = snackbarController;
1012
- $[7] = t4;
1013
- } else {
1014
- t4 = $[7];
1015
- }
1016
- let t5;
1017
- if ($[8] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
1018
- t5 = /* @__PURE__ */ jsx(CopyIcon, {});
1019
- $[8] = t5;
1020
- } else {
1021
- t5 = $[8];
1022
- }
1023
- let t6;
1024
- if ($[9] !== t4) {
1025
- t6 = /* @__PURE__ */ jsxs(Button, { variant: "text", size: "small", onClick: t4, children: [
1026
- t5,
1027
- "CopyIcon to clipboard"
1028
- ] });
1029
- $[9] = t4;
1030
- $[10] = t6;
1031
- } else {
1032
- t6 = $[10];
1033
- }
1034
- let t7;
1035
- if ($[11] !== onOpenChange) {
1036
- t7 = /* @__PURE__ */ jsx(Button, { onClick: () => onOpenChange(false), children: "Close" });
1037
- $[11] = onOpenChange;
1038
- $[12] = t7;
1039
- } else {
1040
- t7 = $[12];
1041
- }
1042
- let t8;
1043
- if ($[13] !== t6 || $[14] !== t7) {
1044
- t8 = /* @__PURE__ */ jsxs(DialogActions, { children: [
1045
- t6,
1046
- t7
1047
- ] });
1048
- $[13] = t6;
1049
- $[14] = t7;
1050
- $[15] = t8;
1051
- } else {
1052
- t8 = $[15];
1053
- }
1054
- let t9;
1055
- if ($[16] !== onOpenChange || $[17] !== open || $[18] !== t1 || $[19] !== t3 || $[20] !== t8) {
1056
- t9 = /* @__PURE__ */ jsxs(Dialog, { open, onOpenChange, maxWidth: "4xl", children: [
1057
- t1,
1058
- t3,
1059
- t8
1060
- ] });
1061
- $[16] = onOpenChange;
1062
- $[17] = open;
1063
- $[18] = t1;
1064
- $[19] = t3;
1065
- $[20] = t8;
1066
- $[21] = t9;
1067
- } else {
1068
- t9 = $[21];
1069
- }
1070
- return t9;
1071
- }
1072
- function _temp$4(t0) {
1073
- const {
1074
- style,
1075
- tokens,
1076
- getLineProps,
1077
- getTokenProps
1078
- } = t0;
1079
- return /* @__PURE__ */ jsx("pre", { style, className: "p-4 rounded-xs text-sm", children: tokens.map((line, i) => /* @__PURE__ */ jsx("div", { ...getLineProps({
1080
- line
1081
- }), children: line.map((token, key) => /* @__PURE__ */ jsx("span", { ...getTokenProps({
1082
- token
1083
- }) }, key)) }, i)) });
1084
- }
1085
- function collectionToCode(collection) {
1086
- const propertyCleanup = (value) => {
1087
- if (value === void 0 || value === null) {
1088
- return value;
1089
- }
1090
- const valueCopy = clone(value);
1091
- if (typeof valueCopy === "function") {
1092
- return valueCopy;
1093
- }
1094
- if (Array.isArray(valueCopy)) {
1095
- return valueCopy.map((v) => propertyCleanup(v));
1096
- }
1097
- if (typeof valueCopy === "object") {
1098
- if (valueCopy === null) return valueCopy;
1099
- const obj = valueCopy;
1100
- Object.keys(obj).forEach((key) => {
1101
- if (!isEmptyObject(obj)) {
1102
- const childRes = propertyCleanup(obj[key]);
1103
- if (childRes !== null && childRes !== void 0 && childRes !== false && !isEmptyObject(childRes)) {
1104
- obj[key] = childRes;
1105
- } else {
1106
- delete obj[key];
1107
- }
1108
- }
1109
- });
1110
- delete obj.resolved;
1111
- delete obj.propertiesOrder;
1112
- delete obj.propertyConfig;
1113
- }
1114
- return valueCopy;
1115
- };
1116
- return {
1117
- id: collection.slug,
1118
- name: collection.name,
1119
- singularName: collection.singularName,
1120
- path: collection.slug,
1121
- description: collection.description,
1122
- icon: collection.icon,
1123
- defaultFilter: collection.defaultFilter,
1124
- sort: collection.sort,
1125
- properties: Object.entries({
1126
- ...collection.properties ?? {}
1127
- }).map(([key, value]) => ({
1128
- [key]: propertyCleanup(value)
1129
- })).reduce((a, b) => ({
1130
- ...a,
1131
- ...b
1132
- }), {})
1133
- // subcollections: (collection.subcollections ?? []).map(collectionToCode)
1134
- };
1135
- }
1136
- function CollectionPropertiesEditorForm({
1137
- showErrors,
1138
- isNewCollection,
1139
- propertyErrorsRef,
1140
- onPropertyError,
1141
- setDirty,
1142
- extraIcon,
1143
- getUser,
1144
- getData,
1145
- doCollectionInference,
1146
- propertyConfigs
1147
- }) {
1148
- const {
1149
- values,
1150
- setFieldValue,
1151
- setFieldError,
1152
- setFieldTouched,
1153
- errors,
1154
- dirty
1155
- } = useFormex();
1156
- const snackbarController = useSnackbarController();
1157
- const configController = useCollectionsConfigController();
1158
- const largeLayout = useLargeLayout();
1159
- const asDialog = !largeLayout;
1160
- const [selectedPropertyIndex, setSelectedPropertyIndex] = useState();
1161
- const [selectedPropertyKey, setSelectedPropertyKey] = useState();
1162
- const [selectedPropertyNamespace, setSelectedPropertyNamespace] = useState();
1163
- const selectedPropertyFullId = selectedPropertyKey ? getFullId(selectedPropertyKey, selectedPropertyNamespace) : void 0;
1164
- const selectedProperty = selectedPropertyFullId ? getIn(values.properties, selectedPropertyFullId.replaceAll(".", ".properties.")) : void 0;
1165
- const [codeDialogOpen, setCodeDialogOpen] = useState(false);
1166
- const [inferringProperties, setInferringProperties] = useState(false);
1167
- const [newPropertyDialogOpen, setNewPropertyDialogOpen] = useState(false);
1168
- const [inferredPropertyKeys, setInferredPropertyKeys] = useState([]);
1169
- const currentPropertiesOrderRef = React__default.useRef(values.propertiesOrder ? {
1170
- "": values.propertiesOrder
1171
- } : {});
1172
- useEffect(() => {
1173
- if (setDirty) setDirty(dirty);
1174
- }, [dirty]);
1175
- const inferPropertiesFromData = doCollectionInference ? () => {
1176
- if (!doCollectionInference || configController?.readOnly) return;
1177
- setInferringProperties(true);
1178
- console.debug("CollectionEditor: inferring properties from data", values);
1179
- doCollectionInference(values).then((newCollection) => {
1180
- if (!newCollection) {
1181
- snackbarController.open({
1182
- type: "error",
1183
- message: "Could not infer properties from data"
1184
- });
1185
- return;
1186
- }
1187
- const findNewPropertyKeys = (existingProps, newProps, namespace) => {
1188
- if (!newProps) return [];
1189
- const keys = [];
1190
- for (const key of Object.keys(newProps)) {
1191
- const fullKey = namespace ? `${namespace}.${key}` : key;
1192
- const existingProp = existingProps?.[key];
1193
- const newProp = newProps[key];
1194
- if (!existingProp) {
1195
- keys.push(fullKey);
1196
- } else if (typeof newProp === "object" && "type" in newProp && newProp.type === "map" && newProp.properties) {
1197
- const existingMapProps = typeof existingProp === "object" && "type" in existingProp && existingProp.type === "map" ? existingProp.properties : void 0;
1198
- keys.push(...findNewPropertyKeys(existingMapProps, newProp.properties, fullKey));
1199
- }
1200
- }
1201
- return keys;
1202
- };
1203
- const addNewPropertiesOnly = (existingProps_0, newProps_0) => {
1204
- if (!newProps_0) return existingProps_0 ?? {};
1205
- if (!existingProps_0) return newProps_0;
1206
- const result = {
1207
- ...existingProps_0
1208
- };
1209
- for (const key_0 of Object.keys(newProps_0)) {
1210
- const existingProp_0 = existingProps_0[key_0];
1211
- const newProp_0 = newProps_0[key_0];
1212
- if (!existingProp_0) {
1213
- result[key_0] = newProp_0;
1214
- } else if (typeof existingProp_0 === "object" && "type" in existingProp_0 && existingProp_0.type === "map" && typeof newProp_0 === "object" && "type" in newProp_0 && newProp_0.type === "map" && newProp_0.properties) {
1215
- const existingMapProps_0 = existingProp_0.properties;
1216
- if (existingMapProps_0) {
1217
- result[key_0] = {
1218
- ...existingProp_0,
1219
- properties: addNewPropertiesOnly(existingMapProps_0, newProp_0.properties)
1220
- };
1221
- }
1222
- }
1223
- }
1224
- return result;
1225
- };
1226
- const updatedProperties = addNewPropertiesOnly(values.properties ?? {}, newCollection.properties);
1227
- const allNewPropertyKeys = findNewPropertyKeys(values.properties, newCollection.properties);
1228
- const newTopLevelPropertyKeys = (newCollection.properties ? Object.keys(newCollection.properties) : []).filter((propertyKey) => !values.properties[propertyKey]);
1229
- if (allNewPropertyKeys.length === 0) {
1230
- snackbarController.open({
1231
- type: "info",
1232
- message: "No new properties found in existing data"
1233
- });
1234
- return;
1235
- }
1236
- const allExistingKeys = values.propertiesOrder ?? Object.keys(values.properties ?? {});
1237
- const updatedPropertiesOrder = [...newTopLevelPropertyKeys, ...allExistingKeys.filter((key_1) => !newTopLevelPropertyKeys.includes(key_1))];
1238
- setFieldValue("properties", updatedProperties, false);
1239
- updatePropertiesOrder(updatedPropertiesOrder);
1240
- setInferredPropertyKeys(allNewPropertyKeys);
1241
- snackbarController.open({
1242
- type: "success",
1243
- message: `Added ${allNewPropertyKeys.length} new ${allNewPropertyKeys.length === 1 ? "property" : "properties"}`
1244
- });
1245
- }).finally(() => {
1246
- setInferringProperties(false);
1247
- });
1248
- } : void 0;
1249
- const getCurrentPropertiesOrder = (namespace_0) => {
1250
- if (!namespace_0) return currentPropertiesOrderRef.current[""] ?? getIn(values, namespaceToPropertiesOrderPath());
1251
- return currentPropertiesOrderRef.current[namespace_0] ?? getIn(values, namespaceToPropertiesOrderPath(namespace_0));
1252
- };
1253
- const updatePropertiesOrder = (newPropertiesOrder, namespace_1) => {
1254
- const propertiesOrderPath = namespaceToPropertiesOrderPath(namespace_1);
1255
- setFieldValue(propertiesOrderPath, newPropertiesOrder, false);
1256
- currentPropertiesOrderRef.current[namespace_1 ?? ""] = newPropertiesOrder;
1257
- };
1258
- const deleteProperty = (propertyKey_0, namespace_2) => {
1259
- if (configController?.readOnly) return;
1260
- const fullId = propertyKey_0 ? getFullId(propertyKey_0, namespace_2) : void 0;
1261
- if (!fullId) throw Error("collection editor miss config");
1262
- setFieldValue(idToPropertiesPath(fullId), void 0, false);
1263
- const currentPropertiesOrder = getCurrentPropertiesOrder(namespace_2);
1264
- if (currentPropertiesOrder) {
1265
- const newPropertiesOrder_0 = currentPropertiesOrder.filter((p) => p !== propertyKey_0);
1266
- updatePropertiesOrder(newPropertiesOrder_0, namespace_2);
1267
- }
1268
- setNewPropertyDialogOpen(false);
1269
- setSelectedPropertyIndex(void 0);
1270
- setSelectedPropertyKey(void 0);
1271
- setSelectedPropertyNamespace(void 0);
1272
- };
1273
- const onPropertyMove = (propertiesOrder, namespace_3) => {
1274
- if (configController?.readOnly) return;
1275
- setFieldValue(namespaceToPropertiesOrderPath(namespace_3), propertiesOrder, false);
1276
- };
1277
- const onPropertyCreated = ({
1278
- id,
1279
- property
1280
- }) => {
1281
- if (configController?.readOnly) return;
1282
- if (!id) {
1283
- throw Error("Need to include an ID when creating a new property");
1284
- }
1285
- setFieldValue("properties", {
1286
- ...values.properties ?? {},
1287
- [id]: property
1288
- }, false);
1289
- const newPropertiesOrder_1 = [...values.propertiesOrder ?? Object.keys(values.properties), id];
1290
- updatePropertiesOrder(newPropertiesOrder_1);
1291
- setNewPropertyDialogOpen(false);
1292
- if (largeLayout) {
1293
- setSelectedPropertyIndex(newPropertiesOrder_1.indexOf(id));
1294
- setSelectedPropertyKey(id);
1295
- }
1296
- setSelectedPropertyNamespace(void 0);
1297
- };
1298
- const onPropertyChanged = ({
1299
- id: id_0,
1300
- property: property_0,
1301
- previousId,
1302
- namespace: namespace_4
1303
- }) => {
1304
- const fullId_0 = id_0 ? getFullId(id_0, namespace_4) : void 0;
1305
- const propertyPath = fullId_0 ? idToPropertiesPath(fullId_0) : void 0;
1306
- if (previousId && previousId !== id_0) {
1307
- const previousFullId = getFullId(previousId, namespace_4);
1308
- const previousPropertyPath = idToPropertiesPath(previousFullId);
1309
- const currentPropertiesOrder_0 = getCurrentPropertiesOrder(namespace_4);
1310
- const newPropertiesOrder_2 = currentPropertiesOrder_0.map((p_0) => p_0 === previousId ? id_0 : p_0).filter((p_1) => p_1 !== void 0);
1311
- updatePropertiesOrder(newPropertiesOrder_2, namespace_4);
1312
- if (id_0) {
1313
- setSelectedPropertyIndex(newPropertiesOrder_2.indexOf(id_0));
1314
- setSelectedPropertyKey(id_0);
1315
- }
1316
- setFieldValue(previousPropertyPath, void 0, false);
1317
- setFieldTouched(previousPropertyPath, false, false);
1318
- }
1319
- if (propertyPath) {
1320
- setFieldValue(propertyPath, property_0, false);
1321
- setFieldTouched(propertyPath, true, false);
1322
- }
1323
- };
1324
- const onPropertyErrorInternal = (id_1, namespace_5, error) => {
1325
- const propertyPath_0 = id_1 ? getFullId(id_1, namespace_5) : void 0;
1326
- console.debug("onPropertyErrorInternal", {
1327
- id: id_1,
1328
- namespace: namespace_5,
1329
- error,
1330
- propertyPath: propertyPath_0
1331
- });
1332
- if (propertyPath_0) {
1333
- const hasError = error && Object.keys(error).length > 0;
1334
- onPropertyError(id_1, namespace_5, hasError ? error : void 0);
1335
- setFieldError(idToPropertiesPath(propertyPath_0), hasError ? "Property error" : void 0);
1336
- }
1337
- };
1338
- const closePropertyDialog = () => {
1339
- setSelectedPropertyIndex(void 0);
1340
- setSelectedPropertyKey(void 0);
1341
- };
1342
- const initialErrors = selectedPropertyKey && propertyErrorsRef?.current?.properties ? propertyErrorsRef.current.properties[selectedPropertyKey] : void 0;
1343
- const emptyCollection = (values?.propertiesOrder === void 0 || values.propertiesOrder.length === 0) && (!values?.properties || Object.keys(values.properties).length === 0);
1344
- const usedPropertiesOrder = values.propertiesOrder ? values.propertiesOrder : Object.keys(values.properties);
1345
- const owner = useMemo(() => values.ownerId && getUser ? getUser(values.ownerId) : null, [getUser, values.ownerId]);
1346
- const aiModifiedPaths = useAIModifiedPaths();
1347
- const generationCounter = aiModifiedPaths?.generationCounter ?? 0;
1348
- const onPropertyClick = (propertyKey_1, namespace_6) => {
1349
- console.debug("CollectionEditor: onPropertyClick", {
1350
- propertyKey: propertyKey_1,
1351
- namespace: namespace_6
1352
- });
1353
- setSelectedPropertyIndex(usedPropertiesOrder.indexOf(propertyKey_1));
1354
- setSelectedPropertyKey(propertyKey_1);
1355
- setSelectedPropertyNamespace(namespace_6);
1356
- };
1357
- const body = /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-12 gap-2 h-full bg-white dark:bg-surface-950", children: [
1358
- /* @__PURE__ */ jsxs("div", { className: cls("bg-surface-50 dark:bg-surface-900", "p-4 md:p-8", "col-span-12 lg:col-span-5 h-full overflow-auto", !asDialog && "border-r " + defaultBorderMixin), children: [
1359
- /* @__PURE__ */ jsxs("div", { className: "flex my-2", children: [
1360
- /* @__PURE__ */ jsxs("div", { className: "grow mb-4", children: [
1361
- /* @__PURE__ */ jsx(Field, { name: "name", as: DebouncedTextField, invisible: true, className: "-ml-1", inputClassName: "text-2xl font-headers", placeholder: "Collection name", size: "small", required: true, error: Boolean(errors?.name) }),
1362
- owner && /* @__PURE__ */ jsxs(Typography, { variant: "body2", className: "ml-2", color: "secondary", children: [
1363
- "Created by ",
1364
- owner.displayName
1365
- ] })
1366
- ] }),
1367
- extraIcon && /* @__PURE__ */ jsx("div", { className: "ml-4", children: extraIcon }),
1368
- /* @__PURE__ */ jsxs("div", { className: "ml-4 flex flex-row gap-2 items-center flex-shrink-0", children: [
1369
- inferPropertiesFromData && /* @__PURE__ */ jsx(Tooltip, { title: "Add new properties based on data", asChild: true, children: /* @__PURE__ */ jsx(IconButton, { variant: "filled", disabled: inferringProperties, onClick: inferPropertiesFromData, children: inferringProperties ? /* @__PURE__ */ jsx(CircularProgress, { size: "small" }) : /* @__PURE__ */ jsx(FileSearchIcon, {}) }) }),
1370
- /* @__PURE__ */ jsx(Tooltip, { title: "Add new property", asChild: true, children: /* @__PURE__ */ jsx(Button, { disabled: configController?.readOnly, onClick: () => setNewPropertyDialogOpen(true), children: /* @__PURE__ */ jsx(PlusIcon, {}) }) })
1371
- ] })
1372
- ] }),
1373
- /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(PropertyTree, { className: "mt-2", inferredPropertyKeys, selectedPropertyKey: selectedPropertyKey ? getFullId(selectedPropertyKey, selectedPropertyNamespace) : void 0, properties: values.properties, additionalFields: values.additionalFields, propertiesOrder: usedPropertiesOrder, onPropertyClick, onPropertyMove, onPropertyRemove: (isNewCollection || inferredPropertyKeys && inferredPropertyKeys.length > 0) && !configController?.readOnly ? deleteProperty : void 0, errors }) }),
1374
- /* @__PURE__ */ jsx(Button, { className: "mt-4 xl:mt-8 w-full", variant: "filled", color: "neutral", disabled: configController?.readOnly, onClick: () => setNewPropertyDialogOpen(true), startIcon: /* @__PURE__ */ jsx(PlusIcon, {}), children: "Add new property" })
1375
- ] }),
1376
- !asDialog && /* @__PURE__ */ jsx("div", { className: "col-span-12 lg:col-span-7 p-4 md:py-8 md:px-4 h-full overflow-auto", children: /* @__PURE__ */ jsxs("div", { className: "sticky top-8 min-h-full w-full flex flex-col justify-center", children: [
1377
- selectedPropertyFullId && !!selectedProperty && !isPropertyBuilder(selectedProperty) && /* @__PURE__ */ jsx(PropertyForm, { inArray: false, existingProperty: !isNewCollection, autoUpdateId: false, allowDataInference: !isNewCollection, autoOpenTypeSelect: false, propertyKey: selectedPropertyKey, propertyNamespace: selectedPropertyNamespace, property: selectedProperty, onPropertyChanged, onDelete: deleteProperty, onError: onPropertyErrorInternal, forceShowErrors: showErrors, initialErrors, getData, propertyConfigs }, `edit_view_${selectedPropertyIndex}_${generationCounter}`),
1378
- !selectedProperty && /* @__PURE__ */ jsxs("div", { className: "w-full flex flex-col items-center justify-center h-full gap-4", children: [
1379
- /* @__PURE__ */ jsx(Typography, { variant: "label", className: "", children: emptyCollection ? "Now you can add your first property" : "Select a property to edit it" }),
1380
- /* @__PURE__ */ jsxs(Button, { disabled: configController?.readOnly, onClick: () => setNewPropertyDialogOpen(true), children: [
1381
- /* @__PURE__ */ jsx(PlusIcon, {}),
1382
- "Add new property"
1383
- ] })
1384
- ] }),
1385
- !!selectedProperty && isPropertyBuilder(selectedProperty) && /* @__PURE__ */ jsx(Typography, { variant: "label", className: "flex items-center justify-center", children: "This property is defined as a property builder in code" })
1386
- ] }) }),
1387
- asDialog && /* @__PURE__ */ jsx(PropertyFormDialog, { inArray: false, open: selectedPropertyIndex !== void 0, autoUpdateId: !selectedProperty, allowDataInference: !isNewCollection, existingProperty: true, autoOpenTypeSelect: false, propertyKey: selectedPropertyKey, propertyNamespace: selectedPropertyNamespace, property: selectedProperty, onPropertyChanged, onDelete: deleteProperty, onError: onPropertyErrorInternal, forceShowErrors: showErrors, initialErrors, getData, propertyConfigs, onCancel: closePropertyDialog, onOkClicked: asDialog ? closePropertyDialog : void 0 }, `edit_view_${selectedPropertyIndex}_${generationCounter}`)
1388
- ] });
1389
- return /* @__PURE__ */ jsxs(Fragment, { children: [
1390
- body,
1391
- /* @__PURE__ */ jsx(PropertyFormDialog, { inArray: false, existingProperty: false, autoOpenTypeSelect: true, autoUpdateId: true, forceShowErrors: showErrors, open: newPropertyDialogOpen, onCancel: () => setNewPropertyDialogOpen(false), onPropertyChanged: onPropertyCreated, getData, allowDataInference: !isNewCollection, propertyConfigs, existingPropertyKeys: values.propertiesOrder }),
1392
- /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(GetCodeDialog, { collection: values, open: codeDialogOpen, onOpenChange: setCodeDialogOpen }) })
1393
- ] });
1394
- }
1395
- const EXAMPLE_JSON = `{
1396
- "id": "products",
1397
- "name": "Products",
1398
- "path": "products",
1399
- "icon": "shopping_cart",
1400
- "properties": {
1401
- "name": {
1402
- "type": "string",
1403
- "name": "Name",
1404
- "validation": { "required": true }
1405
- },
1406
- "price": {
1407
- "type": "number",
1408
- "name": "Price"
1409
- },
1410
- "available": {
1411
- "type": "boolean",
1412
- "name": "Available"
1413
- }
1414
- }
1415
- }`;
1416
- function CollectionJsonImportDialog(t0) {
1417
- const $ = c(44);
1418
- const {
1419
- open,
1420
- onClose,
1421
- onImport
1422
- } = t0;
1423
- const [jsonValue, setJsonValue] = useState("");
1424
- let t1;
1425
- if ($[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
1426
- t1 = [];
1427
- $[0] = t1;
1428
- } else {
1429
- t1 = $[0];
1430
- }
1431
- const [errors, setErrors] = useState(t1);
1432
- const [touched, setTouched] = useState(false);
1433
- let t2;
1434
- if ($[1] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
1435
- t2 = (e) => {
1436
- const value = e.target.value;
1437
- setJsonValue(value);
1438
- setTouched(true);
1439
- if (!value.trim()) {
1440
- setErrors([]);
1441
- return;
1442
- }
1443
- const result = validateCollectionJson(value);
1444
- setErrors(result.errors);
1445
- };
1446
- $[1] = t2;
1447
- } else {
1448
- t2 = $[1];
1449
- }
1450
- const handleJsonChange = t2;
1451
- let t3;
1452
- if ($[2] !== jsonValue || $[3] !== onClose || $[4] !== onImport) {
1453
- t3 = () => {
1454
- const result_0 = validateCollectionJson(jsonValue);
1455
- if (result_0.valid && result_0.collection) {
1456
- onImport(result_0.collection);
1457
- setJsonValue("");
1458
- setErrors([]);
1459
- setTouched(false);
1460
- onClose();
1461
- }
1462
- };
1463
- $[2] = jsonValue;
1464
- $[3] = onClose;
1465
- $[4] = onImport;
1466
- $[5] = t3;
1467
- } else {
1468
- t3 = $[5];
1469
- }
1470
- const handleImport = t3;
1471
- let t4;
1472
- if ($[6] !== onClose) {
1473
- t4 = () => {
1474
- setJsonValue("");
1475
- setErrors([]);
1476
- setTouched(false);
1477
- onClose();
1478
- };
1479
- $[6] = onClose;
1480
- $[7] = t4;
1481
- } else {
1482
- t4 = $[7];
1483
- }
1484
- const handleClose = t4;
1485
- let t5;
1486
- if ($[8] !== errors.length || $[9] !== jsonValue || $[10] !== touched) {
1487
- t5 = touched && jsonValue.trim() && errors.length === 0;
1488
- $[8] = errors.length;
1489
- $[9] = jsonValue;
1490
- $[10] = touched;
1491
- $[11] = t5;
1492
- } else {
1493
- t5 = $[11];
1494
- }
1495
- const isValid = t5;
1496
- let t6;
1497
- if ($[12] !== handleClose) {
1498
- t6 = (open_0) => !open_0 && handleClose();
1499
- $[12] = handleClose;
1500
- $[13] = t6;
1501
- } else {
1502
- t6 = $[13];
1503
- }
1504
- let t7;
1505
- if ($[14] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
1506
- t7 = /* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center gap-2", children: [
1507
- /* @__PURE__ */ jsx(CodeIcon, { size: iconSize.smallest }),
1508
- "Import Collection from JSON"
1509
- ] });
1510
- $[14] = t7;
1511
- } else {
1512
- t7 = $[14];
1513
- }
1514
- let t8;
1515
- if ($[15] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
1516
- t8 = /* @__PURE__ */ jsx("code", { className: "bg-surface-200 dark:bg-surface-700 px-1 rounded", children: "id" });
1517
- $[15] = t8;
1518
- } else {
1519
- t8 = $[15];
1520
- }
1521
- let t9;
1522
- if ($[16] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
1523
- t9 = /* @__PURE__ */ jsx("code", { className: "bg-surface-200 dark:bg-surface-700 px-1 rounded", children: "name" });
1524
- $[16] = t9;
1525
- } else {
1526
- t9 = $[16];
1527
- }
1528
- let t10;
1529
- if ($[17] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
1530
- t10 = /* @__PURE__ */ jsx("code", { className: "bg-surface-200 dark:bg-surface-700 px-1 rounded", children: "path" });
1531
- $[17] = t10;
1532
- } else {
1533
- t10 = $[17];
1534
- }
1535
- let t11;
1536
- if ($[18] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
1537
- t11 = /* @__PURE__ */ jsxs(Typography, { variant: "body2", color: "secondary", children: [
1538
- "Paste a JSON object representing your collection configuration. The JSON must include ",
1539
- t8,
1540
- ",",
1541
- t9,
1542
- ",",
1543
- t10,
1544
- ", and",
1545
- /* @__PURE__ */ jsx("code", { className: "bg-surface-200 dark:bg-surface-700 px-1 rounded", children: "properties" }),
1546
- "."
1547
- ] });
1548
- $[18] = t11;
1549
- } else {
1550
- t11 = $[18];
1551
- }
1552
- const t12 = errors.length > 0 && touched;
1553
- let t13;
1554
- if ($[19] !== jsonValue || $[20] !== t12) {
1555
- t13 = /* @__PURE__ */ jsx(TextField, { multiline: true, minRows: 12, value: jsonValue, onChange: handleJsonChange, placeholder: EXAMPLE_JSON, error: t12, className: "w-full", inputClassName: "font-mono text-sm resize-none overflow-y-auto h-[300px]" });
1556
- $[19] = jsonValue;
1557
- $[20] = t12;
1558
- $[21] = t13;
1559
- } else {
1560
- t13 = $[21];
1561
- }
1562
- let t14;
1563
- if ($[22] !== errors || $[23] !== touched) {
1564
- t14 = errors.length > 0 && touched && /* @__PURE__ */ jsxs(Alert, { color: "error", children: [
1565
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "font-medium mb-2", children: "Validation errors:" }),
1566
- /* @__PURE__ */ jsx("ul", { className: "list-disc list-inside space-y-1", children: errors.map(_temp$3) })
1567
- ] });
1568
- $[22] = errors;
1569
- $[23] = touched;
1570
- $[24] = t14;
1571
- } else {
1572
- t14 = $[24];
1573
- }
1574
- let t15;
1575
- if ($[25] !== isValid) {
1576
- t15 = isValid && /* @__PURE__ */ jsx(Alert, { color: "success", children: /* @__PURE__ */ jsx(Typography, { variant: "body2", children: "✓ JSON is valid and ready to import" }) });
1577
- $[25] = isValid;
1578
- $[26] = t15;
1579
- } else {
1580
- t15 = $[26];
1581
- }
1582
- let t16;
1583
- if ($[27] !== t13 || $[28] !== t14 || $[29] !== t15) {
1584
- t16 = /* @__PURE__ */ jsxs(DialogContent, { className: "flex flex-col gap-4", children: [
1585
- t11,
1586
- t13,
1587
- t14,
1588
- t15
1589
- ] });
1590
- $[27] = t13;
1591
- $[28] = t14;
1592
- $[29] = t15;
1593
- $[30] = t16;
1594
- } else {
1595
- t16 = $[30];
1596
- }
1597
- let t17;
1598
- if ($[31] !== handleClose) {
1599
- t17 = /* @__PURE__ */ jsx(Button, { variant: "text", onClick: handleClose, children: "Cancel" });
1600
- $[31] = handleClose;
1601
- $[32] = t17;
1602
- } else {
1603
- t17 = $[32];
1604
- }
1605
- const t18 = !isValid;
1606
- let t19;
1607
- if ($[33] !== handleImport || $[34] !== t18) {
1608
- t19 = /* @__PURE__ */ jsx(Button, { variant: "filled", color: "primary", onClick: handleImport, disabled: t18, children: "Import Collection" });
1609
- $[33] = handleImport;
1610
- $[34] = t18;
1611
- $[35] = t19;
1612
- } else {
1613
- t19 = $[35];
1614
- }
1615
- let t20;
1616
- if ($[36] !== t17 || $[37] !== t19) {
1617
- t20 = /* @__PURE__ */ jsxs(DialogActions, { children: [
1618
- t17,
1619
- t19
1620
- ] });
1621
- $[36] = t17;
1622
- $[37] = t19;
1623
- $[38] = t20;
1624
- } else {
1625
- t20 = $[38];
1626
- }
1627
- let t21;
1628
- if ($[39] !== open || $[40] !== t16 || $[41] !== t20 || $[42] !== t6) {
1629
- t21 = /* @__PURE__ */ jsxs(Dialog, { open, onOpenChange: t6, maxWidth: "2xl", children: [
1630
- t7,
1631
- t16,
1632
- t20
1633
- ] });
1634
- $[39] = open;
1635
- $[40] = t16;
1636
- $[41] = t20;
1637
- $[42] = t6;
1638
- $[43] = t21;
1639
- } else {
1640
- t21 = $[43];
1641
- }
1642
- return t21;
1643
- }
1644
- function _temp$3(error, index) {
1645
- return /* @__PURE__ */ jsx("li", { className: "text-sm", children: error.path ? /* @__PURE__ */ jsxs(Fragment, { children: [
1646
- /* @__PURE__ */ jsx("code", { className: "bg-red-100 dark:bg-red-900/40 px-1 rounded", children: error.path }),
1647
- ": ",
1648
- error.message
1649
- ] }) : error.message }, index);
1650
- }
1651
- const productsCollectionTemplate = {
1652
- slug: "products",
1653
- table: "products",
1654
- name: "Products",
1655
- singularName: "Product",
1656
- icon: "ShoppingCart",
1657
- description: "List of the products currently sold in your shop",
1658
- properties: {
1659
- name: {
1660
- type: "string",
1661
- name: "Name",
1662
- description: "Name of this product",
1663
- validation: {
1664
- required: true
1665
- }
1666
- },
1667
- brand: {
1668
- type: "string",
1669
- name: "Brand",
1670
- validation: {
1671
- required: true
1672
- }
1673
- },
1674
- description: {
1675
- type: "string",
1676
- name: "Description",
1677
- description: "Description of this product, supports markdown",
1678
- markdown: true
1679
- },
1680
- main_image: {
1681
- type: "string",
1682
- name: "Image",
1683
- storage: {
1684
- storagePath: "images",
1685
- acceptedFiles: ["image/*"]
1686
- },
1687
- description: "Upload field for images"
1688
- },
1689
- available: {
1690
- type: "boolean",
1691
- name: "Available",
1692
- ui: {
1693
- columnWidth: 100
1694
- },
1695
- description: "Is this product available in the website"
1696
- },
1697
- price: {
1698
- type: "number",
1699
- name: "Price",
1700
- validation: {
1701
- requiredMessage: "You must set a positive price",
1702
- min: 0
1703
- }
1704
- },
1705
- images: {
1706
- type: "array",
1707
- name: "Images",
1708
- ui: {
1709
- hideFromCollection: true
1710
- },
1711
- of: {
1712
- type: "string",
1713
- storage: {
1714
- storagePath: "images",
1715
- acceptedFiles: ["image/*"]
1716
- }
1717
- }
1718
- },
1719
- related_products: {
1720
- type: "array",
1721
- name: "Related products",
1722
- description: "Products related to this one",
1723
- of: {
1724
- type: "reference",
1725
- path: "products"
1726
- }
1727
- },
1728
- metadata: {
1729
- name: "Metadata",
1730
- description: "This is an example of a map property",
1731
- type: "map",
1732
- keyValue: true
1733
- },
1734
- added_on: {
1735
- type: "date",
1736
- name: "Added on",
1737
- autoValue: "on_create"
1738
- }
1739
- }
1740
- };
1741
- const blogCollectionTemplate = {
1742
- slug: "blog",
1743
- table: "blog",
1744
- name: "Blog",
1745
- singularName: "Blog entry",
1746
- icon: "FileText",
1747
- description: "A collection of blog entries",
1748
- defaultSize: "l",
1749
- properties: {
1750
- name: {
1751
- name: "Name",
1752
- validation: {
1753
- required: true
1754
- },
1755
- type: "string"
1756
- },
1757
- header_image: {
1758
- name: "Header image",
1759
- type: "string",
1760
- storage: {
1761
- storagePath: "images",
1762
- acceptedFiles: ["image/*"],
1763
- metadata: {
1764
- cacheControl: "max-age=1000000"
1765
- }
1766
- }
1767
- },
1768
- content: {
1769
- name: "Content",
1770
- description: "Content blocks for the blog entry",
1771
- validation: {
1772
- required: true
1773
- },
1774
- type: "array",
1775
- oneOf: {
1776
- typeField: "type",
1777
- valueField: "value",
1778
- properties: {
1779
- text: {
1780
- type: "string",
1781
- name: "Text",
1782
- markdown: true
1783
- },
1784
- quote: {
1785
- type: "string",
1786
- name: "Quote",
1787
- multiline: true
1788
- },
1789
- images: {
1790
- name: "Images",
1791
- type: "array",
1792
- of: {
1793
- type: "string",
1794
- storage: {
1795
- storagePath: "images",
1796
- acceptedFiles: ["image/*"],
1797
- metadata: {
1798
- cacheControl: "max-age=1000000"
1799
- }
1800
- }
1801
- },
1802
- description: "This fields allows uploading multiple images at once and reordering"
1803
- },
1804
- products: {
1805
- name: "Products",
1806
- type: "array",
1807
- of: {
1808
- type: "reference",
1809
- path: "products",
1810
- previewProperties: ["name", "main_image"]
1811
- }
1812
- }
1813
- },
1814
- propertiesOrder: ["text", "quote", "images", "products"]
1815
- }
1816
- },
1817
- created_on: {
1818
- name: "Created on",
1819
- type: "date",
1820
- autoValue: "on_create"
1821
- },
1822
- status: {
1823
- name: "Status",
1824
- validation: {
1825
- required: true
1826
- },
1827
- type: "string",
1828
- enum: {
1829
- published: {
1830
- id: "published",
1831
- label: "Published"
1832
- },
1833
- draft: "Draft"
1834
- },
1835
- defaultValue: "draft"
1836
- },
1837
- publish_date: {
1838
- name: "Publish date",
1839
- type: "date",
1840
- clearable: true
1841
- },
1842
- reviewed: {
1843
- name: "Reviewed",
1844
- type: "boolean"
1845
- },
1846
- tags: {
1847
- name: "Tags",
1848
- description: "Example of generic array",
1849
- type: "array",
1850
- of: {
1851
- type: "string",
1852
- previewAsTag: true
1853
- }
1854
- }
1855
- }
1856
- };
1857
- const usersCollectionTemplate = {
1858
- slug: "users",
1859
- table: "users",
1860
- name: "Users",
1861
- singularName: "User",
1862
- description: "Registered users in the app/web",
1863
- icon: "User",
1864
- properties: {
1865
- displayName: {
1866
- name: "Display name",
1867
- type: "string"
1868
- },
1869
- email: {
1870
- name: "Email",
1871
- type: "string",
1872
- email: true
1873
- },
1874
- emailVerified: {
1875
- name: "Email verified",
1876
- type: "boolean"
1877
- },
1878
- phone: {
1879
- name: "Phone",
1880
- type: "string"
1881
- },
1882
- favourite_products: {
1883
- name: "Favourite products",
1884
- type: "array",
1885
- of: {
1886
- type: "reference",
1887
- path: "products"
1888
- }
1889
- },
1890
- photoURL: {
1891
- name: "Photo URL",
1892
- type: "string",
1893
- url: "image"
1894
- }
1895
- }
1896
- };
1897
- const pagesCollectionTemplate = {
1898
- slug: "pages",
1899
- table: "pages",
1900
- name: "Pages",
1901
- singularName: "Page",
1902
- icon: "File",
1903
- description: "List of website pages that can be edited here",
1904
- properties: {
1905
- title: {
1906
- type: "string",
1907
- name: "Page Title",
1908
- validation: {
1909
- required: true
1910
- }
1911
- },
1912
- slug: {
1913
- type: "string",
1914
- name: "URL Slug",
1915
- validation: {
1916
- required: true,
1917
- unique: true,
1918
- matches: "^[a-z0-9]+(?:-[a-z0-9]+)*$",
1919
- matchesMessage: "Must be lowercase, alphanumeric, and hyphenated"
1920
- }
1921
- },
1922
- hero_section: {
1923
- type: "map",
1924
- name: "Hero Section",
1925
- properties: {
1926
- headline: {
1927
- type: "string",
1928
- name: "Headline",
1929
- validation: {
1930
- required: true
1931
- }
1932
- },
1933
- subhead: {
1934
- type: "string",
1935
- name: "Subheadline"
1936
- },
1937
- background_image: {
1938
- type: "string",
1939
- name: "Background Image",
1940
- storage: {
1941
- storagePath: "page_hero/images",
1942
- acceptedFiles: ["image/*"]
1943
- }
1944
- },
1945
- call_to_action: {
1946
- type: "string",
1947
- name: "Call to Action"
1948
- },
1949
- call_to_action_link: {
1950
- type: "string",
1951
- name: "CTA Link",
1952
- url: true
1953
- }
1954
- }
1955
- },
1956
- content: {
1957
- type: "array",
1958
- name: "Content",
1959
- oneOf: {
1960
- properties: {
1961
- section: {
1962
- type: "map",
1963
- name: "Section",
1964
- properties: {
1965
- title: {
1966
- type: "string",
1967
- name: "Section Title",
1968
- validation: {
1969
- required: true
1970
- }
1971
- },
1972
- content: {
1973
- type: "string",
1974
- name: "Section Content",
1975
- markdown: true
1976
- },
1977
- image: {
1978
- type: "string",
1979
- name: "Section Image",
1980
- storage: {
1981
- storagePath: "page_sections/images",
1982
- acceptedFiles: ["image/*"]
1983
- }
1984
- },
1985
- link: {
1986
- type: "string",
1987
- name: "Section Link",
1988
- url: true
1989
- }
1990
- }
1991
- },
1992
- image: {
1993
- type: "string",
1994
- name: "Image",
1995
- storage: {
1996
- storagePath: "page_sections/images",
1997
- acceptedFiles: ["image/*"]
1998
- }
1999
- },
2000
- slider: {
2001
- type: "array",
2002
- name: "Slider",
2003
- of: {
2004
- type: "map",
2005
- properties: {
2006
- title: {
2007
- type: "string",
2008
- name: "Title",
2009
- validation: {
2010
- required: true
2011
- }
2012
- },
2013
- image: {
2014
- type: "string",
2015
- storage: {
2016
- storagePath: "page_sections/images",
2017
- acceptedFiles: ["image/*"]
2018
- }
2019
- }
2020
- }
2021
- }
2022
- }
2023
- }
2024
- }
2025
- },
2026
- sidebar: {
2027
- type: "map",
2028
- name: "Sidebar",
2029
- properties: {
2030
- title: {
2031
- type: "string",
2032
- name: "Sidebar Title",
2033
- validation: {
2034
- required: false
2035
- }
2036
- },
2037
- content: {
2038
- type: "string",
2039
- name: "Sidebar Content",
2040
- markdown: true
2041
- }
2042
- }
2043
- },
2044
- seo_metadata: {
2045
- type: "map",
2046
- name: "SEO Metadata",
2047
- properties: {
2048
- meta_title: {
2049
- type: "string",
2050
- name: "Meta Title"
2051
- },
2052
- meta_description: {
2053
- type: "string",
2054
- name: "Meta Description"
2055
- },
2056
- focus_keywords: {
2057
- type: "array",
2058
- name: "Focus Keywords",
2059
- of: {
2060
- type: "string"
2061
- }
2062
- }
2063
- }
2064
- },
2065
- footer_override: {
2066
- type: "string",
2067
- name: "Footer Override",
2068
- markdown: true
2069
- },
2070
- publish_date: {
2071
- type: "date",
2072
- name: "Publish Date",
2073
- validation: {
2074
- required: true
2075
- }
2076
- },
2077
- last_updated: {
2078
- type: "date",
2079
- name: "Last Updated",
2080
- autoValue: "on_update"
2081
- },
2082
- is_published: {
2083
- type: "boolean",
2084
- name: "Is Published",
2085
- ui: {
2086
- columnWidth: 100
2087
- },
2088
- description: "Should this page be live on the site?"
2089
- }
2090
- }
2091
- };
2092
- function AICollectionGeneratorPopover({
2093
- existingCollection,
2094
- onGenerated,
2095
- generateCollection,
2096
- trigger,
2097
- size = "small",
2098
- showLabel = true,
2099
- onAnalyticsEvent
2100
- }) {
2101
- const [menuOpen, setMenuOpen] = useState(false);
2102
- const [prompt, setPrompt] = useState("");
2103
- const [loading, setLoading] = useState(false);
2104
- const [error, setError] = useState(null);
2105
- const collectionRegistry = useCollectionRegistryController();
2106
- const configController = useCollectionsConfigController();
2107
- const snackbarController = useSnackbarController();
2108
- const existingCollections = collectionRegistry.collections ?? [];
2109
- const handleGenerate = async () => {
2110
- if (!prompt.trim()) return;
2111
- setLoading(true);
2112
- setError(null);
2113
- const mode = existingCollection ? "modify" : "create";
2114
- onAnalyticsEvent?.("ai_collection_generate_start", {
2115
- mode
2116
- });
2117
- try {
2118
- const collectionsContext = existingCollections.map((c2) => ({
2119
- slug: c2.slug,
2120
- name: c2.name,
2121
- properties: c2.properties,
2122
- propertiesOrder: c2.propertiesOrder
2123
- }));
2124
- const result = await generateCollection({
2125
- prompt: prompt.trim(),
2126
- existingCollections: collectionsContext.slice(0, 30),
2127
- ...existingCollection && {
2128
- existingCollection: {
2129
- slug: existingCollection.slug,
2130
- name: existingCollection.name,
2131
- properties: existingCollection.properties,
2132
- propertiesOrder: existingCollection.propertiesOrder
2133
- }
2134
- }
2135
- });
2136
- onGenerated(result.collection, result.operations);
2137
- setMenuOpen(false);
2138
- setPrompt("");
2139
- onAnalyticsEvent?.("ai_collection_generate_success", {
2140
- mode,
2141
- operationsCount: result.operations?.length
2142
- });
2143
- snackbarController.open({
2144
- type: "success",
2145
- message: existingCollection ? "Collection updated with AI suggestions" : "Collection generated successfully"
2146
- });
2147
- } catch (e) {
2148
- console.error("Error generating collection:", e);
2149
- const errorMessage = e instanceof CollectionGenerationApiError ? e.message : "Failed to generate collection. Please try again.";
2150
- setError(errorMessage);
2151
- onAnalyticsEvent?.("ai_collection_generate_error", {
2152
- mode,
2153
- error: errorMessage
2154
- });
2155
- snackbarController.open({
2156
- type: "error",
2157
- message: errorMessage
2158
- });
2159
- } finally {
2160
- setLoading(false);
2161
- }
2162
- };
2163
- const handleKeyDown = (e_0) => {
2164
- if (e_0.key === "Enter" && !e_0.shiftKey) {
2165
- e_0.preventDefault();
2166
- handleGenerate();
2167
- }
2168
- };
2169
- const tooltipTitle = configController?.readOnly ? configController.readOnlyReason || "Collection generation is disabled" : void 0;
2170
- const defaultTrigger = showLabel ? /* @__PURE__ */ jsx(Tooltip, { title: tooltipTitle, asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "text", size, disabled: loading || configController?.readOnly, startIcon: loading ? /* @__PURE__ */ jsx(CircularProgress, { size: "smallest" }) : /* @__PURE__ */ jsx(AIIcon, { size: "small" }), children: "AI Assist" }) }) : /* @__PURE__ */ jsx(Tooltip, { title: tooltipTitle, asChild: true, children: /* @__PURE__ */ jsx(IconButton, { size, disabled: loading || configController?.readOnly, "aria-label": "AI Assist", children: loading ? /* @__PURE__ */ jsx(CircularProgress, { size: "smallest" }) : /* @__PURE__ */ jsx(AIIcon, { size: "small" }) }) });
2171
- return /* @__PURE__ */ jsx(Menu, { open: menuOpen, onOpenChange: (open) => {
2172
- setMenuOpen(open);
2173
- if (!open) {
2174
- setError(null);
2175
- }
2176
- }, trigger: trigger ?? defaultTrigger, children: /* @__PURE__ */ jsxs("div", { className: "p-4 flex flex-col gap-3 min-w-[360px] max-w-[480px]", children: [
2177
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2178
- /* @__PURE__ */ jsx(AIIcon, { size: "small" }),
2179
- /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", children: existingCollection ? "Modify Collection with AI" : "Generate Collection with AI" })
2180
- ] }),
2181
- /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: existingCollection ? "Describe the changes you want to make to this collection." : "Describe the collection you want to create." }),
2182
- /* @__PURE__ */ jsx(TextField, { size: "small", multiline: true, autoFocus: true, className: "w-full text-text-primary dark:text-text-primary-dark", value: prompt, onChange: (e_1) => setPrompt(e_1.target.value), onKeyDown: handleKeyDown, placeholder: existingCollection ? "e.g., Add a thumbnail image field with storage, make price required..." : "e.g., Create a products collection with name, price, description, and category...", disabled: loading }),
2183
- error && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-red-500", children: error }),
2184
- /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
2185
- /* @__PURE__ */ jsx(Button, { variant: "text", size: "small", onClick: () => setMenuOpen(false), disabled: loading, children: "Cancel" }),
2186
- /* @__PURE__ */ jsx(Button, { variant: "filled", size: "small", onClick: handleGenerate, disabled: !prompt.trim() || loading, startIcon: loading ? /* @__PURE__ */ jsx(CircularProgress, { size: "smallest" }) : void 0, children: loading ? "Generating..." : "Generate" })
2187
- ] })
2188
- ] }) });
2189
- }
2190
- function CollectionEditorWelcomeView(t0) {
2191
- const $ = c(90);
2192
- const {
2193
- parentCollection,
2194
- onContinue,
2195
- existingCollectionPaths,
2196
- generateCollection,
2197
- onAnalyticsEvent,
2198
- unmappedTables,
2199
- onImportFromTable
2200
- } = t0;
2201
- const {
2202
- pathSuggestions
2203
- } = useCollectionEditorController();
2204
- let t1;
2205
- if ($[0] !== pathSuggestions) {
2206
- t1 = pathSuggestions ?? [];
2207
- $[0] = pathSuggestions;
2208
- $[1] = t1;
2209
- } else {
2210
- t1 = $[1];
2211
- }
2212
- let t2;
2213
- if ($[2] !== existingCollectionPaths) {
2214
- t2 = (s) => !(existingCollectionPaths ?? []).find((c2) => c2.trim().toLowerCase() === s.trim().toLowerCase());
2215
- $[2] = existingCollectionPaths;
2216
- $[3] = t2;
2217
- } else {
2218
- t2 = $[3];
2219
- }
2220
- const filteredSuggestions = t1.filter(t2);
2221
- const {
2222
- setFieldValue,
2223
- setValues
2224
- } = useFormex();
2225
- const [jsonImportOpen, setJsonImportOpen] = useState(false);
2226
- const [importingTable, setImportingTable] = useState(null);
2227
- let t3;
2228
- if ($[4] !== unmappedTables) {
2229
- t3 = unmappedTables ?? [];
2230
- $[4] = unmappedTables;
2231
- $[5] = t3;
2232
- } else {
2233
- t3 = $[5];
2234
- }
2235
- let T0;
2236
- let t4;
2237
- let t5;
2238
- let t6;
2239
- let t7;
2240
- let t8;
2241
- let t9;
2242
- if ($[6] !== existingCollectionPaths || $[7] !== importingTable || $[8] !== onContinue || $[9] !== onImportFromTable || $[10] !== parentCollection || $[11] !== setFieldValue || $[12] !== t3) {
2243
- let t102;
2244
- if ($[20] !== existingCollectionPaths) {
2245
- t102 = (t) => !(existingCollectionPaths ?? []).find((c_0) => c_0.trim().toLowerCase() === t.trim().toLowerCase());
2246
- $[20] = existingCollectionPaths;
2247
- $[21] = t102;
2248
- } else {
2249
- t102 = $[21];
2250
- }
2251
- const filteredUnmappedTables = t3.filter(t102);
2252
- t9 = "overflow-auto my-auto";
2253
- T0 = Container;
2254
- t4 = "4xl";
2255
- t5 = "flex flex-col gap-4 p-8 m-auto";
2256
- if ($[22] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
2257
- t6 = /* @__PURE__ */ jsx("div", { className: "flex flex-row py-2 pt-3 items-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "grow", children: "New collection" }) });
2258
- $[22] = t6;
2259
- } else {
2260
- t6 = $[22];
2261
- }
2262
- if ($[23] !== parentCollection) {
2263
- t7 = parentCollection && /* @__PURE__ */ jsx(Chip, { colorScheme: "teal", children: /* @__PURE__ */ jsxs(Typography, { variant: "caption", children: [
2264
- "This is a subcollection of ",
2265
- /* @__PURE__ */ jsx("b", { children: parentCollection.name })
2266
- ] }) });
2267
- $[23] = parentCollection;
2268
- $[24] = t7;
2269
- } else {
2270
- t7 = $[24];
2271
- }
2272
- t8 = filteredUnmappedTables.length > 0 && /* @__PURE__ */ jsxs("div", { className: "my-2", children: [
2273
- /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: "● Import from an existing database table:" }),
2274
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-x-2 gap-y-1 items-center my-2 min-h-7", children: filteredUnmappedTables.map((tableName) => /* @__PURE__ */ jsxs(Chip, { colorScheme: "purple", onClick: () => {
2275
- if (onImportFromTable) {
2276
- setImportingTable(tableName);
2277
- onImportFromTable(tableName);
2278
- } else {
2279
- setFieldValue("name", prettifyIdentifier(tableName));
2280
- setFieldValue("id", tableName);
2281
- setFieldValue("path", tableName);
2282
- onContinue();
2283
- }
2284
- }, size: "small", children: [
2285
- /* @__PURE__ */ jsx(TableIcon, { size: iconSize.smallest }),
2286
- importingTable === tableName ? "Loading..." : tableName
2287
- ] }, tableName)) })
2288
- ] });
2289
- $[6] = existingCollectionPaths;
2290
- $[7] = importingTable;
2291
- $[8] = onContinue;
2292
- $[9] = onImportFromTable;
2293
- $[10] = parentCollection;
2294
- $[11] = setFieldValue;
2295
- $[12] = t3;
2296
- $[13] = T0;
2297
- $[14] = t4;
2298
- $[15] = t5;
2299
- $[16] = t6;
2300
- $[17] = t7;
2301
- $[18] = t8;
2302
- $[19] = t9;
2303
- } else {
2304
- T0 = $[13];
2305
- t4 = $[14];
2306
- t5 = $[15];
2307
- t6 = $[16];
2308
- t7 = $[17];
2309
- t8 = $[18];
2310
- t9 = $[19];
2311
- }
2312
- const t10 = (filteredSuggestions ?? []).length > 0 && /* @__PURE__ */ jsxs("div", { className: "my-2", children: [
2313
- /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: "● Use one of the existing paths in your database:" }),
2314
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-x-2 gap-y-1 items-center my-2 min-h-7", children: filteredSuggestions?.map((suggestion, index) => /* @__PURE__ */ jsx(Chip, { colorScheme: "cyan", onClick: () => {
2315
- setFieldValue("name", prettifyIdentifier(suggestion));
2316
- setFieldValue("id", suggestion);
2317
- setFieldValue("path", suggestion);
2318
- setFieldValue("properties", void 0);
2319
- onContinue();
2320
- }, size: "small", children: suggestion }, suggestion)) })
2321
- ] });
2322
- let t11;
2323
- if ($[25] !== generateCollection || $[26] !== onAnalyticsEvent || $[27] !== onContinue || $[28] !== setValues) {
2324
- t11 = generateCollection && /* @__PURE__ */ jsxs("div", { className: "my-2", children: [
2325
- /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "mb-2", children: "● Describe your collection to AI:" }),
2326
- /* @__PURE__ */ jsx(AICollectionGeneratorPopover, { onGenerated: (generatedCollection) => {
2327
- setValues(generatedCollection);
2328
- onContinue();
2329
- }, generateCollection, onAnalyticsEvent, trigger: /* @__PURE__ */ jsx(Button, { variant: "filled", color: "neutral", startIcon: /* @__PURE__ */ jsx(AIIcon, { size: "small" }), children: "Generate with AI" }) })
2330
- ] });
2331
- $[25] = generateCollection;
2332
- $[26] = onAnalyticsEvent;
2333
- $[27] = onContinue;
2334
- $[28] = setValues;
2335
- $[29] = t11;
2336
- } else {
2337
- t11 = $[29];
2338
- }
2339
- let t12;
2340
- if ($[30] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
2341
- t12 = /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "mb-2", children: "● Create from JSON configuration:" });
2342
- $[30] = t12;
2343
- } else {
2344
- t12 = $[30];
2345
- }
2346
- let t13;
2347
- if ($[31] !== setJsonImportOpen) {
2348
- t13 = () => setJsonImportOpen(true);
2349
- $[31] = setJsonImportOpen;
2350
- $[32] = t13;
2351
- } else {
2352
- t13 = $[32];
2353
- }
2354
- let t14;
2355
- if ($[33] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
2356
- t14 = /* @__PURE__ */ jsx(CodeIcon, { size: iconSize.small });
2357
- $[33] = t14;
2358
- } else {
2359
- t14 = $[33];
2360
- }
2361
- let t15;
2362
- if ($[34] !== t13) {
2363
- t15 = /* @__PURE__ */ jsx(Button, { variant: "filled", color: "neutral", onClick: t13, startIcon: t14, children: "Paste JSON Configuration" });
2364
- $[34] = t13;
2365
- $[35] = t15;
2366
- } else {
2367
- t15 = $[35];
2368
- }
2369
- let t16;
2370
- if ($[36] !== setJsonImportOpen) {
2371
- t16 = () => setJsonImportOpen(false);
2372
- $[36] = setJsonImportOpen;
2373
- $[37] = t16;
2374
- } else {
2375
- t16 = $[37];
2376
- }
2377
- let t17;
2378
- if ($[38] !== onContinue || $[39] !== setValues) {
2379
- t17 = (collection) => {
2380
- setValues(collection);
2381
- onContinue();
2382
- };
2383
- $[38] = onContinue;
2384
- $[39] = setValues;
2385
- $[40] = t17;
2386
- } else {
2387
- t17 = $[40];
2388
- }
2389
- let t18;
2390
- if ($[41] !== jsonImportOpen || $[42] !== t16 || $[43] !== t17) {
2391
- t18 = /* @__PURE__ */ jsx(CollectionJsonImportDialog, { open: jsonImportOpen, onClose: t16, onImport: t17 });
2392
- $[41] = jsonImportOpen;
2393
- $[42] = t16;
2394
- $[43] = t17;
2395
- $[44] = t18;
2396
- } else {
2397
- t18 = $[44];
2398
- }
2399
- let t19;
2400
- if ($[45] !== t15 || $[46] !== t18) {
2401
- t19 = /* @__PURE__ */ jsxs("div", { className: "my-2", children: [
2402
- t12,
2403
- t15,
2404
- t18
2405
- ] });
2406
- $[45] = t15;
2407
- $[46] = t18;
2408
- $[47] = t19;
2409
- } else {
2410
- t19 = $[47];
2411
- }
2412
- let t20;
2413
- if ($[48] !== t11 || $[49] !== t19) {
2414
- t20 = /* @__PURE__ */ jsxs("div", { className: "flex flex-row gap-8", children: [
2415
- t11,
2416
- t19
2417
- ] });
2418
- $[48] = t11;
2419
- $[49] = t19;
2420
- $[50] = t20;
2421
- } else {
2422
- t20 = $[50];
2423
- }
2424
- let t21;
2425
- if ($[51] !== onContinue || $[52] !== parentCollection) {
2426
- t21 = !parentCollection && /* @__PURE__ */ jsxs("div", { children: [
2427
- /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "mb-2", children: "● Create a collection from a file (csv, json, xls, xslx...)" }),
2428
- /* @__PURE__ */ jsx(ImportFileUpload, { onDataAdded: (data, propertiesOrder) => onContinue(data, propertiesOrder) })
2429
- ] });
2430
- $[51] = onContinue;
2431
- $[52] = parentCollection;
2432
- $[53] = t21;
2433
- } else {
2434
- t21 = $[53];
2435
- }
2436
- let t22;
2437
- if ($[54] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
2438
- t22 = /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: "● Select a template:" });
2439
- $[54] = t22;
2440
- } else {
2441
- t22 = $[54];
2442
- }
2443
- let t23;
2444
- if ($[55] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
2445
- t23 = /* @__PURE__ */ jsx(ShoppingCartIcon, { size: iconSize.small });
2446
- $[55] = t23;
2447
- } else {
2448
- t23 = $[55];
2449
- }
2450
- let t24;
2451
- if ($[56] !== onContinue || $[57] !== setValues) {
2452
- t24 = /* @__PURE__ */ jsx(TemplateButton, { title: "Products", subtitle: "A collection of products with images, prices and stock", icon: t23, onClick: () => {
2453
- setValues(productsCollectionTemplate);
2454
- onContinue();
2455
- } });
2456
- $[56] = onContinue;
2457
- $[57] = setValues;
2458
- $[58] = t24;
2459
- } else {
2460
- t24 = $[58];
2461
- }
2462
- let t25;
2463
- if ($[59] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
2464
- t25 = /* @__PURE__ */ jsx(UserIcon, { size: iconSize.small });
2465
- $[59] = t25;
2466
- } else {
2467
- t25 = $[59];
2468
- }
2469
- let t26;
2470
- if ($[60] !== onContinue || $[61] !== setValues) {
2471
- t26 = /* @__PURE__ */ jsx(TemplateButton, { title: "Users", subtitle: "A collection of users with emails, names and roles", icon: t25, onClick: () => {
2472
- setValues(usersCollectionTemplate);
2473
- onContinue();
2474
- } });
2475
- $[60] = onContinue;
2476
- $[61] = setValues;
2477
- $[62] = t26;
2478
- } else {
2479
- t26 = $[62];
2480
- }
2481
- let t27;
2482
- if ($[63] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
2483
- t27 = /* @__PURE__ */ jsx(FileTextIcon, { size: iconSize.small });
2484
- $[63] = t27;
2485
- } else {
2486
- t27 = $[63];
2487
- }
2488
- let t28;
2489
- if ($[64] !== onContinue || $[65] !== setValues) {
2490
- t28 = /* @__PURE__ */ jsx(TemplateButton, { title: "Blog posts", subtitle: "A collection of blog posts with images, authors and complex content", icon: t27, onClick: () => {
2491
- setValues(blogCollectionTemplate);
2492
- onContinue();
2493
- } });
2494
- $[64] = onContinue;
2495
- $[65] = setValues;
2496
- $[66] = t28;
2497
- } else {
2498
- t28 = $[66];
2499
- }
2500
- let t29;
2501
- if ($[67] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
2502
- t29 = /* @__PURE__ */ jsx(FileIcon, { size: iconSize.small });
2503
- $[67] = t29;
2504
- } else {
2505
- t29 = $[67];
2506
- }
2507
- let t30;
2508
- if ($[68] !== onContinue || $[69] !== setValues) {
2509
- t30 = /* @__PURE__ */ jsx(TemplateButton, { title: "Pages", subtitle: "A collection of pages with images, authors and complex content", icon: t29, onClick: () => {
2510
- setValues(pagesCollectionTemplate);
2511
- onContinue();
2512
- } });
2513
- $[68] = onContinue;
2514
- $[69] = setValues;
2515
- $[70] = t30;
2516
- } else {
2517
- t30 = $[70];
2518
- }
2519
- let t31;
2520
- if ($[71] !== t24 || $[72] !== t26 || $[73] !== t28 || $[74] !== t30) {
2521
- t31 = /* @__PURE__ */ jsxs("div", { className: "my-2", children: [
2522
- t22,
2523
- /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
2524
- t24,
2525
- t26,
2526
- t28,
2527
- t30
2528
- ] })
2529
- ] });
2530
- $[71] = t24;
2531
- $[72] = t26;
2532
- $[73] = t28;
2533
- $[74] = t30;
2534
- $[75] = t31;
2535
- } else {
2536
- t31 = $[75];
2537
- }
2538
- let t32;
2539
- if ($[76] !== T0 || $[77] !== t10 || $[78] !== t20 || $[79] !== t21 || $[80] !== t31 || $[81] !== t4 || $[82] !== t5 || $[83] !== t6 || $[84] !== t7 || $[85] !== t8) {
2540
- t32 = /* @__PURE__ */ jsxs(T0, { maxWidth: t4, className: t5, children: [
2541
- t6,
2542
- t7,
2543
- t8,
2544
- t10,
2545
- t20,
2546
- t21,
2547
- t31
2548
- ] });
2549
- $[76] = T0;
2550
- $[77] = t10;
2551
- $[78] = t20;
2552
- $[79] = t21;
2553
- $[80] = t31;
2554
- $[81] = t4;
2555
- $[82] = t5;
2556
- $[83] = t6;
2557
- $[84] = t7;
2558
- $[85] = t8;
2559
- $[86] = t32;
2560
- } else {
2561
- t32 = $[86];
2562
- }
2563
- let t33;
2564
- if ($[87] !== t32 || $[88] !== t9) {
2565
- t33 = /* @__PURE__ */ jsx("div", { className: t9, children: t32 });
2566
- $[87] = t32;
2567
- $[88] = t9;
2568
- $[89] = t33;
2569
- } else {
2570
- t33 = $[89];
2571
- }
2572
- return t33;
2573
- }
2574
- function TemplateButton(t0) {
2575
- const $ = c(10);
2576
- const {
2577
- title,
2578
- subtitle,
2579
- icon,
2580
- onClick
2581
- } = t0;
2582
- let t1;
2583
- if ($[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
2584
- t1 = cls("my-2 rounded-md border px-4 py-3 focus:outline-none transition ease-in-out duration-150 flex flex-row gap-4 items-center", "text-text-secondary dark:text-text-secondary-dark", "hover:border-primary-dark hover:text-primary-dark dark:hover:text-primary focus:ring-primary hover:ring-1 hover:ring-primary", "border-surface-400 dark:border-surface-600 ");
2585
- $[0] = t1;
2586
- } else {
2587
- t1 = $[0];
2588
- }
2589
- let t2;
2590
- if ($[1] !== title) {
2591
- t2 = /* @__PURE__ */ jsx("div", { className: "flex flex-col items-start", children: /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", children: title }) });
2592
- $[1] = title;
2593
- $[2] = t2;
2594
- } else {
2595
- t2 = $[2];
2596
- }
2597
- let t3;
2598
- if ($[3] !== icon || $[4] !== onClick || $[5] !== t2) {
2599
- t3 = /* @__PURE__ */ jsxs(Card, { onClick, className: t1, children: [
2600
- icon,
2601
- t2
2602
- ] });
2603
- $[3] = icon;
2604
- $[4] = onClick;
2605
- $[5] = t2;
2606
- $[6] = t3;
2607
- } else {
2608
- t3 = $[6];
2609
- }
2610
- let t4;
2611
- if ($[7] !== subtitle || $[8] !== t3) {
2612
- t4 = /* @__PURE__ */ jsx(Tooltip, { title: subtitle, asChild: true, children: t3 });
2613
- $[7] = subtitle;
2614
- $[8] = t3;
2615
- $[9] = t4;
2616
- } else {
2617
- t4 = $[9];
2618
- }
2619
- return t4;
2620
- }
2621
- function CollectionEditorImportMapping(t0) {
2622
- const $ = c(32);
2623
- const {
2624
- importConfig,
2625
- propertyConfigs
2626
- } = t0;
2627
- const {
2628
- setFieldValue,
2629
- setFieldTouched,
2630
- values
2631
- } = useFormex();
2632
- const [selectedProperty, setSelectedProperty] = useState(void 0);
2633
- let t1;
2634
- if ($[0] !== values.propertiesOrder) {
2635
- t1 = values.propertiesOrder ? {
2636
- "": values.propertiesOrder
2637
- } : {};
2638
- $[0] = values.propertiesOrder;
2639
- $[1] = t1;
2640
- } else {
2641
- t1 = $[1];
2642
- }
2643
- const currentPropertiesOrderRef = React__default.useRef(t1);
2644
- const propertyKey = selectedProperty ? selectedProperty.id : void 0;
2645
- const property = selectedProperty || void 0;
2646
- let t2;
2647
- if ($[2] !== importConfig || $[3] !== setFieldTouched || $[4] !== setFieldValue || $[5] !== values) {
2648
- t2 = (t32) => {
2649
- const {
2650
- id,
2651
- property: property_0,
2652
- previousId,
2653
- namespace
2654
- } = t32;
2655
- const fullId = id ? getFullId(id, namespace) : void 0;
2656
- const propertyPath = fullId ? idToPropertiesPath(fullId) : void 0;
2657
- const getCurrentPropertiesOrder = (namespace_0) => {
2658
- if (!namespace_0) {
2659
- return currentPropertiesOrderRef.current[""];
2660
- }
2661
- return currentPropertiesOrderRef.current[namespace_0] ?? getIn(values, namespaceToPropertiesOrderPath(namespace_0));
2662
- };
2663
- const updatePropertiesOrder = (newPropertiesOrder, namespace_1) => {
2664
- const propertiesOrderPath = namespaceToPropertiesOrderPath(namespace_1);
2665
- setFieldValue(propertiesOrderPath, newPropertiesOrder, false);
2666
- currentPropertiesOrderRef.current[namespace_1 ?? ""] = newPropertiesOrder;
2667
- };
2668
- if (previousId && previousId !== id) {
2669
- const previousFullId = getFullId(previousId, namespace);
2670
- const previousPropertyPath = idToPropertiesPath(previousFullId);
2671
- const currentPropertiesOrder = getCurrentPropertiesOrder(namespace);
2672
- const newPropertiesOrder_0 = currentPropertiesOrder.map((p) => p === previousId ? id : p).filter(_temp$2);
2673
- updatePropertiesOrder(newPropertiesOrder_0, namespace);
2674
- const newHeadersMapping = {
2675
- ...importConfig.headersMapping
2676
- };
2677
- Object.keys(newHeadersMapping).forEach((key) => {
2678
- if (newHeadersMapping[key] === previousId) {
2679
- newHeadersMapping[key] = id ?? "";
2680
- }
2681
- });
2682
- importConfig.setHeadersMapping(newHeadersMapping);
2683
- setFieldValue(previousPropertyPath, void 0, false);
2684
- setFieldTouched(previousPropertyPath, false, false);
2685
- }
2686
- if (propertyPath) {
2687
- setFieldValue(propertyPath, property_0, false);
2688
- setFieldTouched(propertyPath, true, false);
2689
- }
2690
- };
2691
- $[2] = importConfig;
2692
- $[3] = setFieldTouched;
2693
- $[4] = setFieldValue;
2694
- $[5] = values;
2695
- $[6] = t2;
2696
- } else {
2697
- t2 = $[6];
2698
- }
2699
- const onPropertyChanged = t2;
2700
- let t3;
2701
- if ($[7] !== importConfig.importData || $[8] !== setFieldTouched || $[9] !== setFieldValue) {
2702
- t3 = async (t42) => {
2703
- const {
2704
- id: id_0,
2705
- importKey,
2706
- property: property_1,
2707
- namespace: namespace_2
2708
- } = t42;
2709
- const fullId_0 = id_0 ? getFullId(id_0, namespace_2) : void 0;
2710
- const propertyPath_0 = fullId_0 ? idToPropertiesPath(fullId_0) : void 0;
2711
- const propertyData = importConfig.importData.map((d) => getIn(d, importKey));
2712
- const inferredNewProperty = {
2713
- ...buildPropertyFromData(propertyData, property_1, getInferenceType)
2714
- };
2715
- if (propertyPath_0) {
2716
- if (inferredNewProperty) {
2717
- setFieldValue(propertyPath_0, inferredNewProperty, false);
2718
- } else {
2719
- setFieldValue(propertyPath_0, property_1, false);
2720
- }
2721
- setFieldTouched(propertyPath_0, true, false);
2722
- }
2723
- };
2724
- $[7] = importConfig.importData;
2725
- $[8] = setFieldTouched;
2726
- $[9] = setFieldValue;
2727
- $[10] = t3;
2728
- } else {
2729
- t3 = $[10];
2730
- }
2731
- const onPropertyTypeChanged = t3;
2732
- let t4;
2733
- if ($[11] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
2734
- t4 = /* @__PURE__ */ jsx(Typography, { variant: "h6", className: "my-4 ml-3.5", children: "Data property mapping" });
2735
- $[11] = t4;
2736
- } else {
2737
- t4 = $[11];
2738
- }
2739
- const t5 = values.properties;
2740
- let t6;
2741
- if ($[12] !== onPropertyTypeChanged || $[13] !== propertyConfigs || $[14] !== setFieldValue) {
2742
- t6 = (t72) => {
2743
- const {
2744
- property: property_2,
2745
- propertyKey: propertyKey_0,
2746
- importKey: importKey_0,
2747
- isIdColumn
2748
- } = t72;
2749
- if (isIdColumn) {
2750
- return /* @__PURE__ */ jsx(Typography, { children: " This column will be used as ID" });
2751
- }
2752
- return /* @__PURE__ */ jsx(ImportNewPropertyFieldPreview, { property: property_2, propertyKey: propertyKey_0, onPropertyNameChanged: (propertyKey_1, value) => setFieldValue(`properties.${propertyKey_1}.name`, value, false), onEditClick: () => {
2753
- if (!propertyKey_0 || !property_2) {
2754
- return;
2755
- }
2756
- setSelectedProperty({
2757
- ...property_2,
2758
- id: propertyKey_0
2759
- });
2760
- }, propertyTypeView: /* @__PURE__ */ jsx(PropertySelect, { property: property_2, disabled: false, onPropertyChanged: (props) => onPropertyTypeChanged({
2761
- ...props,
2762
- importKey: importKey_0
2763
- }), propertyKey: propertyKey_0, propertyConfigs }) });
2764
- };
2765
- $[12] = onPropertyTypeChanged;
2766
- $[13] = propertyConfigs;
2767
- $[14] = setFieldValue;
2768
- $[15] = t6;
2769
- } else {
2770
- t6 = $[15];
2771
- }
2772
- let t7;
2773
- if ($[16] !== importConfig || $[17] !== t5 || $[18] !== t6) {
2774
- t7 = /* @__PURE__ */ jsxs(Container, { maxWidth: "6xl", className: "flex flex-col gap-4 p-8 m-auto", children: [
2775
- t4,
2776
- /* @__PURE__ */ jsx(DataNewPropertiesMapping, { importConfig, destinationProperties: t5, buildPropertyView: t6 })
2777
- ] });
2778
- $[16] = importConfig;
2779
- $[17] = t5;
2780
- $[18] = t6;
2781
- $[19] = t7;
2782
- } else {
2783
- t7 = $[19];
2784
- }
2785
- const t8 = selectedProperty !== void 0;
2786
- let t10;
2787
- let t9;
2788
- if ($[20] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
2789
- t9 = () => {
2790
- setSelectedProperty(void 0);
2791
- };
2792
- t10 = () => {
2793
- setSelectedProperty(void 0);
2794
- };
2795
- $[20] = t10;
2796
- $[21] = t9;
2797
- } else {
2798
- t10 = $[20];
2799
- t9 = $[21];
2800
- }
2801
- let t11;
2802
- if ($[22] !== onPropertyChanged || $[23] !== property || $[24] !== propertyConfigs || $[25] !== propertyKey || $[26] !== t8) {
2803
- t11 = /* @__PURE__ */ jsx(PropertyFormDialog, { open: t8, propertyKey, property, inArray: false, autoUpdateId: false, onPropertyChanged, allowDataInference: false, onOkClicked: t9, onCancel: t10, autoOpenTypeSelect: false, existingProperty: false, propertyConfigs });
2804
- $[22] = onPropertyChanged;
2805
- $[23] = property;
2806
- $[24] = propertyConfigs;
2807
- $[25] = propertyKey;
2808
- $[26] = t8;
2809
- $[27] = t11;
2810
- } else {
2811
- t11 = $[27];
2812
- }
2813
- let t12;
2814
- if ($[28] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
2815
- t12 = /* @__PURE__ */ jsx("div", { style: {
2816
- height: "52px"
2817
- } });
2818
- $[28] = t12;
2819
- } else {
2820
- t12 = $[28];
2821
- }
2822
- let t13;
2823
- if ($[29] !== t11 || $[30] !== t7) {
2824
- t13 = /* @__PURE__ */ jsxs("div", { className: "overflow-auto my-auto", children: [
2825
- t7,
2826
- t11,
2827
- t12
2828
- ] });
2829
- $[29] = t11;
2830
- $[30] = t7;
2831
- $[31] = t13;
2832
- } else {
2833
- t13 = $[31];
2834
- }
2835
- return t13;
2836
- }
2837
- function _temp$2(p_0) {
2838
- return p_0 !== void 0;
2839
- }
2840
- function PropertySelect(t0) {
2841
- const $ = c(24);
2842
- const {
2843
- property,
2844
- onPropertyChanged,
2845
- propertyKey,
2846
- propertyConfigs,
2847
- disabled
2848
- } = t0;
2849
- let t1;
2850
- if ($[0] !== property) {
2851
- t1 = property ? getFieldId(property) : null;
2852
- $[0] = property;
2853
- $[1] = t1;
2854
- } else {
2855
- t1 = $[1];
2856
- }
2857
- const fieldId = t1;
2858
- let t2;
2859
- if ($[2] !== property || $[3] !== propertyConfigs) {
2860
- t2 = property ? getFieldConfig(property, propertyConfigs) : null;
2861
- $[2] = property;
2862
- $[3] = propertyConfigs;
2863
- $[4] = t2;
2864
- } else {
2865
- t2 = $[4];
2866
- }
2867
- const widget = t2;
2868
- const [selectOpen, setSelectOpen] = useState(false);
2869
- const t3 = property && widget ? `${widget?.name} - ${property.type}` : void 0;
2870
- const t4 = selectOpen ? false : void 0;
2871
- const t5 = !widget;
2872
- const t6 = fieldId ?? "";
2873
- let t7;
2874
- if ($[5] !== widget) {
2875
- t7 = (value) => {
2876
- if (!widget) {
2877
- return null;
2878
- }
2879
- return /* @__PURE__ */ jsx(PropertyConfigBadge, { propertyConfig: widget });
2880
- };
2881
- $[5] = widget;
2882
- $[6] = t7;
2883
- } else {
2884
- t7 = $[6];
2885
- }
2886
- let t8;
2887
- if ($[7] !== onPropertyChanged || $[8] !== property || $[9] !== propertyConfigs || $[10] !== propertyKey) {
2888
- t8 = (newSelectedWidgetId) => {
2889
- const newProperty = updatePropertyFromWidget(property, newSelectedWidgetId, propertyConfigs);
2890
- if (!propertyKey) {
2891
- return;
2892
- }
2893
- onPropertyChanged({
2894
- id: propertyKey,
2895
- property: newProperty,
2896
- previousId: propertyKey,
2897
- namespace: void 0
2898
- });
2899
- };
2900
- $[7] = onPropertyChanged;
2901
- $[8] = property;
2902
- $[9] = propertyConfigs;
2903
- $[10] = propertyKey;
2904
- $[11] = t8;
2905
- } else {
2906
- t8 = $[11];
2907
- }
2908
- let t9;
2909
- if ($[12] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
2910
- t9 = Object.entries(supportedFields).map(_temp2);
2911
- $[12] = t9;
2912
- } else {
2913
- t9 = $[12];
2914
- }
2915
- let t10;
2916
- if ($[13] !== disabled || $[14] !== selectOpen || $[15] !== t5 || $[16] !== t6 || $[17] !== t7 || $[18] !== t8) {
2917
- t10 = /* @__PURE__ */ jsx(Select, { open: selectOpen, onOpenChange: setSelectOpen, invisible: true, className: "w-full", disabled, error: t5, fullWidth: true, value: t6, placeholder: "Select a property widget", position: "item-aligned", renderValue: t7, onValueChange: t8, children: t9 });
2918
- $[13] = disabled;
2919
- $[14] = selectOpen;
2920
- $[15] = t5;
2921
- $[16] = t6;
2922
- $[17] = t7;
2923
- $[18] = t8;
2924
- $[19] = t10;
2925
- } else {
2926
- t10 = $[19];
2927
- }
2928
- let t11;
2929
- if ($[20] !== t10 || $[21] !== t3 || $[22] !== t4) {
2930
- t11 = /* @__PURE__ */ jsx(Tooltip, { title: t3, open: t4, children: t10 });
2931
- $[20] = t10;
2932
- $[21] = t3;
2933
- $[22] = t4;
2934
- $[23] = t11;
2935
- } else {
2936
- t11 = $[23];
2937
- }
2938
- return t11;
2939
- }
2940
- function _temp2(t0) {
2941
- const [key, widget_0] = t0;
2942
- return /* @__PURE__ */ jsx(ImportPropertySelectItem, { value: key, optionDisabled: false, propertyConfig: widget_0, existing: false }, key);
2943
- }
2944
- function ImportPropertySelectItem(t0) {
2945
- const $ = c(19);
2946
- const {
2947
- value,
2948
- optionDisabled,
2949
- propertyConfig,
2950
- existing
2951
- } = t0;
2952
- const t1 = optionDisabled ? "w-full" : "";
2953
- let t2;
2954
- if ($[0] !== t1) {
2955
- t2 = cls("flex flex-row items-center text-base min-h-[48px]", t1);
2956
- $[0] = t1;
2957
- $[1] = t2;
2958
- } else {
2959
- t2 = $[1];
2960
- }
2961
- let t3;
2962
- if ($[2] !== propertyConfig) {
2963
- t3 = /* @__PURE__ */ jsx("div", { className: "mr-8", children: /* @__PURE__ */ jsx(PropertyConfigBadge, { propertyConfig }) });
2964
- $[2] = propertyConfig;
2965
- $[3] = t3;
2966
- } else {
2967
- t3 = $[3];
2968
- }
2969
- let t4;
2970
- if ($[4] !== propertyConfig.name) {
2971
- t4 = /* @__PURE__ */ jsx("div", { children: propertyConfig.name });
2972
- $[4] = propertyConfig.name;
2973
- $[5] = t4;
2974
- } else {
2975
- t4 = $[5];
2976
- }
2977
- const t5 = existing && optionDisabled ? "You can only switch to widgets that use the same data type" : propertyConfig.description;
2978
- let t6;
2979
- if ($[6] !== t5) {
2980
- t6 = /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "disabled", className: "max-w-sm", children: t5 });
2981
- $[6] = t5;
2982
- $[7] = t6;
2983
- } else {
2984
- t6 = $[7];
2985
- }
2986
- let t7;
2987
- if ($[8] !== t4 || $[9] !== t6) {
2988
- t7 = /* @__PURE__ */ jsxs("div", { children: [
2989
- t4,
2990
- t6
2991
- ] });
2992
- $[8] = t4;
2993
- $[9] = t6;
2994
- $[10] = t7;
2995
- } else {
2996
- t7 = $[10];
2997
- }
2998
- let t8;
2999
- if ($[11] !== t2 || $[12] !== t3 || $[13] !== t7) {
3000
- t8 = /* @__PURE__ */ jsxs("div", { className: t2, children: [
3001
- t3,
3002
- t7
3003
- ] });
3004
- $[11] = t2;
3005
- $[12] = t3;
3006
- $[13] = t7;
3007
- $[14] = t8;
3008
- } else {
3009
- t8 = $[14];
3010
- }
3011
- let t9;
3012
- if ($[15] !== optionDisabled || $[16] !== t8 || $[17] !== value) {
3013
- t9 = /* @__PURE__ */ jsx(SelectItem, { value, disabled: optionDisabled, className: "flex flex-row items-center", children: t8 });
3014
- $[15] = optionDisabled;
3015
- $[16] = t8;
3016
- $[17] = value;
3017
- $[18] = t9;
3018
- } else {
3019
- t9 = $[18];
3020
- }
3021
- return t9;
3022
- }
3023
- function CollectionEditorImportDataPreview(t0) {
3024
- const $ = c(20);
3025
- const {
3026
- importConfig,
3027
- properties,
3028
- propertiesOrder
3029
- } = t0;
3030
- const authController = useAuthController();
3031
- const registry = useCollectionRegistryController();
3032
- const [loading, setLoading] = useState(false);
3033
- let t1;
3034
- if ($[0] !== authController || $[1] !== importConfig || $[2] !== properties || $[3] !== registry) {
3035
- t1 = async function loadEntities2() {
3036
- const mappedData = importConfig.importData.map((d) => convertDataToEntity(authController, registry, d, importConfig.idColumn, importConfig.headersMapping, properties, "TEMP_PATH", importConfig.defaultValues));
3037
- importConfig.setEntities(mappedData);
3038
- };
3039
- $[0] = authController;
3040
- $[1] = importConfig;
3041
- $[2] = properties;
3042
- $[3] = registry;
3043
- $[4] = t1;
3044
- } else {
3045
- t1 = $[4];
3046
- }
3047
- const loadEntities = t1;
3048
- let t2;
3049
- if ($[5] !== loadEntities) {
3050
- t2 = () => {
3051
- loadEntities().finally(() => setLoading(false));
3052
- };
3053
- $[5] = loadEntities;
3054
- $[6] = t2;
3055
- } else {
3056
- t2 = $[6];
3057
- }
3058
- let t3;
3059
- if ($[7] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
3060
- t3 = [];
3061
- $[7] = t3;
3062
- } else {
3063
- t3 = $[7];
3064
- }
3065
- useEffect(t2, t3);
3066
- const selectionController = useSelectionController();
3067
- if (loading) {
3068
- let t42;
3069
- if ($[8] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
3070
- t42 = /* @__PURE__ */ jsx(CircularProgressCenter, {});
3071
- $[8] = t42;
3072
- } else {
3073
- t42 = $[8];
3074
- }
3075
- return t42;
3076
- }
3077
- let t4;
3078
- if ($[9] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
3079
- t4 = /* @__PURE__ */ jsxs("div", { children: [
3080
- /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", children: "Imported data preview" }),
3081
- /* @__PURE__ */ jsx(Typography, { variant: "caption", children: "Entities with the same id will be overwritten" })
3082
- ] });
3083
- $[9] = t4;
3084
- } else {
3085
- t4 = $[9];
3086
- }
3087
- let t5;
3088
- if ($[10] !== importConfig.entities) {
3089
- t5 = {
3090
- data: importConfig.entities,
3091
- dataLoading: false,
3092
- noMoreToLoad: false
3093
- };
3094
- $[10] = importConfig.entities;
3095
- $[11] = t5;
3096
- } else {
3097
- t5 = $[11];
3098
- }
3099
- let t6;
3100
- if ($[12] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
3101
- t6 = /* @__PURE__ */ jsx("div", { className: "h-12" });
3102
- $[12] = t6;
3103
- } else {
3104
- t6 = $[12];
3105
- }
3106
- let t7;
3107
- if ($[13] !== propertiesOrder) {
3108
- t7 = propertiesOrder.map(_temp$1);
3109
- $[13] = propertiesOrder;
3110
- $[14] = t7;
3111
- } else {
3112
- t7 = $[14];
3113
- }
3114
- let t8;
3115
- if ($[15] !== properties || $[16] !== selectionController || $[17] !== t5 || $[18] !== t7) {
3116
- t8 = /* @__PURE__ */ jsx(EntityCollectionTable, { title: t4, tableController: t5, endAdornment: t6, filterable: false, sortable: false, selectionController, displayedColumnIds: t7, openEntityMode: "side_panel", properties, enablePopupIcon: false });
3117
- $[15] = properties;
3118
- $[16] = selectionController;
3119
- $[17] = t5;
3120
- $[18] = t7;
3121
- $[19] = t8;
3122
- } else {
3123
- t8 = $[19];
3124
- }
3125
- return t8;
3126
- }
3127
- function _temp$1(p) {
3128
- return {
3129
- key: p,
3130
- disabled: false
3131
- };
3132
- }
3133
- function cleanPropertiesFromImport(properties, parentSlug = "") {
3134
- const result = Object.keys(properties).reduce((acc, key) => {
3135
- const property = properties[key];
3136
- const slug = slugify(key);
3137
- const fullSlug = parentSlug ? `${parentSlug}.${slug}` : slug;
3138
- if (property.type === "map" && property.properties) {
3139
- const slugifiedResult = cleanPropertiesFromImport(property.properties, fullSlug);
3140
- return {
3141
- headersMapping: {
3142
- ...acc.headersMapping,
3143
- [key]: fullSlug
3144
- },
3145
- properties: {
3146
- ...acc.properties,
3147
- [slug]: {
3148
- ...property,
3149
- properties: slugifiedResult.properties,
3150
- propertiesOrder: Object.keys(slugifiedResult.properties)
3151
- }
3152
- }
3153
- };
3154
- }
3155
- const updatedProperties = {
3156
- ...acc.properties,
3157
- [slug]: property
3158
- };
3159
- const headersMapping = {
3160
- ...acc.headersMapping,
3161
- [key]: fullSlug
3162
- };
3163
- return {
3164
- headersMapping,
3165
- properties: updatedProperties
3166
- };
3167
- }, {
3168
- headersMapping: {},
3169
- properties: {}
3170
- });
3171
- const firstKey = Object.keys(result.headersMapping)?.[0];
3172
- let idColumn;
3173
- if (firstKey?.includes("id") || firstKey?.includes("key")) {
3174
- idColumn = firstKey;
3175
- }
3176
- return {
3177
- ...result,
3178
- idColumn
3179
- };
3180
- }
3181
- function sanitizeSqlIdentifier(name) {
3182
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
3183
- throw new Error(`Invalid SQL identifier: "${name}". Only letters, digits, and underscores are allowed.`);
3184
- }
3185
- return `"${name}"`;
3186
- }
3187
- function CollectionRLSTab() {
3188
- const {
3189
- values,
3190
- setFieldValue
3191
- } = useFormex();
3192
- const [editingPolicy, setEditingPolicy] = useState(null);
3193
- const rules = values.securityRules || [];
3194
- const {
3195
- databaseAdmin
3196
- } = useRebaseContext();
3197
- const [dbPolicies, setDbPolicies] = useState([]);
3198
- const [isLoadingDb, setIsLoadingDb] = useState(false);
3199
- useEffect(() => {
3200
- const fetchLivePolicies = async () => {
3201
- const tableName = values.id || values.table || values.alias;
3202
- if (!tableName || !databaseAdmin?.executeSql) return;
3203
- setIsLoadingDb(true);
3204
- try {
3205
- const safeTableName = sanitizeSqlIdentifier(tableName);
3206
- const quotedName = safeTableName.slice(1, -1);
3207
- const sql = `
3208
- SELECT policyname, permissive, roles, cmd, qual, with_check
3209
- FROM pg_policies
3210
- WHERE tablename = '${quotedName}' AND schemaname NOT IN ('information_schema', 'pg_catalog');
3211
- `;
3212
- const result = await databaseAdmin.executeSql(sql);
3213
- const extractRows = (res) => {
3214
- if (res && typeof res === "object" && "rows" in res && Array.isArray(res.rows)) {
3215
- return res.rows;
3216
- }
3217
- if (Array.isArray(res)) return res;
3218
- return [];
3219
- };
3220
- const pRows = extractRows(result);
3221
- const policies = pRows.map((p) => {
3222
- let parsedRoles = [];
3223
- const r = p.roles || p.ROLES;
3224
- if (Array.isArray(r)) {
3225
- parsedRoles = r;
3226
- } else if (typeof r === "string") {
3227
- parsedRoles = r.replace(/^{|}$/g, "").split(",").map((s) => s.trim());
3228
- }
3229
- return {
3230
- policyname: p.policyname || p.POLICYNAME || "",
3231
- tablename: tableName,
3232
- permissive: p.permissive || p.PERMISSIVE || "PERMISSIVE",
3233
- roles: parsedRoles,
3234
- cmd: p.cmd || p.CMD || "ALL",
3235
- qual: p.qual || p.QUAL || null,
3236
- with_check: p.with_check || p.WITH_CHECK || null
3237
- };
3238
- });
3239
- setDbPolicies(policies);
3240
- } catch (e) {
3241
- console.error("Failed to fetch DB policies", e);
3242
- } finally {
3243
- setIsLoadingDb(false);
3244
- }
3245
- };
3246
- fetchLivePolicies();
3247
- }, [databaseAdmin, values.id, values.table, values.alias]);
3248
- const unmappedPolicies = dbPolicies.filter((dp) => !rules.some((r_0) => r_0.name === dp.policyname));
3249
- const handleSave = async (newPolicy) => {
3250
- const rule = {
3251
- name: newPolicy.policyname ?? "",
3252
- operation: newPolicy.cmd?.toLowerCase(),
3253
- mode: newPolicy.permissive?.toLowerCase(),
3254
- using: newPolicy.qual || void 0,
3255
- withCheck: newPolicy.with_check || void 0,
3256
- roles: newPolicy.roles
3257
- };
3258
- let newRules;
3259
- if (editingPolicy === "new") {
3260
- newRules = [...rules, rule];
3261
- } else {
3262
- newRules = rules.map((r_1) => r_1.name === editingPolicy.policyname ? rule : r_1);
3263
- }
3264
- setFieldValue("securityRules", newRules);
3265
- setEditingPolicy(null);
3266
- };
3267
- return /* @__PURE__ */ jsx("div", { className: "overflow-auto my-auto", children: /* @__PURE__ */ jsxs(Container, { maxWidth: "4xl", className: "flex flex-col gap-4 p-8 m-auto", children: [
3268
- /* @__PURE__ */ jsxs("div", { className: "w-full flex flex-col", children: [
3269
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-8", children: [
3270
- /* @__PURE__ */ jsx(Typography, { variant: "h5", children: "Row Level Security" }),
3271
- /* @__PURE__ */ jsx(Button, { variant: "filled", color: "neutral", onClick: () => setEditingPolicy("new"), children: "CREATE POLICY" })
3272
- ] }),
3273
- rules.length === 0 ? /* @__PURE__ */ jsx("div", { className: "flex-grow flex items-center justify-center text-text-disabled py-12", children: /* @__PURE__ */ jsx(Typography, { variant: "body2", children: "No RLS policies defined for this collection." }) }) : /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-3", children: rules.map((rule_0) => /* @__PURE__ */ jsxs(Paper, { className: "p-4 border border-transparent hover:border-surface-200 dark:hover:border-surface-700 rounded-lg flex flex-col sm:flex-row sm:items-center justify-between gap-4 transition-colors bg-white dark:bg-surface-800 shadow-sm", children: [
3274
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 min-w-0", children: [
3275
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
3276
- /* @__PURE__ */ jsx(KeyIcon, { size: iconSize.smallest, className: "text-text-disabled dark:text-text-disabled-dark shrink-0" }),
3277
- /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", className: "truncate", children: rule_0.name })
3278
- ] }),
3279
- /* @__PURE__ */ jsxs("div", { className: "flex gap-2 text-xs pl-6 overflow-x-auto hide-scrollbar", children: [
3280
- /* @__PURE__ */ jsxs(Chip, { size: "small", className: "bg-surface-100 dark:bg-surface-900 text-text-secondary border-none", children: [
3281
- "Action: ",
3282
- rule_0.operation || "ALL"
3283
- ] }),
3284
- /* @__PURE__ */ jsxs(Chip, { size: "small", className: "bg-surface-100 dark:bg-surface-900 text-text-secondary border-none", children: [
3285
- "Roles: ",
3286
- Array.isArray(rule_0.roles) ? rule_0.roles.join(", ") : rule_0.roles
3287
- ] })
3288
- ] })
3289
- ] }),
3290
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 sm:gap-2 shrink-0", children: [
3291
- /* @__PURE__ */ jsx(Button, { size: "small", variant: "text", onClick: () => setEditingPolicy({
3292
- policyname: rule_0.name,
3293
- tablename: values.id || values.table || values.alias || "your_table",
3294
- permissive: (rule_0.mode || "permissive").toUpperCase(),
3295
- cmd: (rule_0.operation || "ALL").toUpperCase(),
3296
- roles: rule_0.roles || ["public"],
3297
- qual: rule_0.using || null,
3298
- with_check: rule_0.withCheck || null
3299
- }), children: "EDIT" }),
3300
- /* @__PURE__ */ jsx(IconButton, { size: "small", onClick: () => {
3301
- setFieldValue("securityRules", rules.filter((r_2) => r_2.name !== rule_0.name));
3302
- }, children: /* @__PURE__ */ jsx(Trash2Icon, { size: iconSize.smallest, className: "text-text-secondary dark:text-text-secondary-dark hover:text-red-500 dark:hover:text-red-500 transition-colors" }) })
3303
- ] })
3304
- ] }, rule_0.name)) }),
3305
- isLoadingDb && unmappedPolicies.length === 0 && /* @__PURE__ */ jsx("div", { className: "flex justify-center mt-8", children: /* @__PURE__ */ jsx(CircularProgress, { size: "small" }) }),
3306
- !isLoadingDb && unmappedPolicies.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-12 flex flex-col gap-4", children: [
3307
- /* @__PURE__ */ jsx(Typography, { variant: "h6", className: "text-text-secondary", children: "Unmapped Database Policies" }),
3308
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-text-secondary opacity-80 -mt-2", children: "These policies exist in your Postgres database but are not mapped to this collection's codebase configuration." }),
3309
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-3", children: unmappedPolicies.map((dp_0) => /* @__PURE__ */ jsxs(Paper, { className: "p-4 border border-orange-200 dark:border-orange-900/50 bg-orange-50/50 dark:bg-orange-900/10 rounded-lg flex flex-col sm:flex-row sm:items-center justify-between gap-4 transition-colors", children: [
3310
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 min-w-0", children: [
3311
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
3312
- /* @__PURE__ */ jsx(KeyIcon, { size: iconSize.smallest, className: "text-orange-500 shrink-0" }),
3313
- /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", className: "truncate", children: dp_0.policyname }),
3314
- /* @__PURE__ */ jsx(Tooltip, { title: "This policy is live in the database but missing from your codebase schema.", children: /* @__PURE__ */ jsx("div", { className: "px-1.5 py-0.5 rounded text-[10px] uppercase bg-orange-500/10 text-orange-600 border border-orange-500/20 shrink-0", children: "DB Only" }) })
3315
- ] }),
3316
- /* @__PURE__ */ jsxs("div", { className: "flex gap-2 text-xs pl-6 overflow-x-auto hide-scrollbar", children: [
3317
- /* @__PURE__ */ jsxs(Chip, { size: "small", className: "bg-white dark:bg-surface-900 text-text-secondary border-none", children: [
3318
- "Action: ",
3319
- dp_0.cmd || "ALL"
3320
- ] }),
3321
- /* @__PURE__ */ jsxs(Chip, { size: "small", className: "bg-white dark:bg-surface-900 text-text-secondary border-none", children: [
3322
- "Roles: ",
3323
- Array.isArray(dp_0.roles) ? dp_0.roles.join(", ") : dp_0.roles
3324
- ] })
3325
- ] })
3326
- ] }),
3327
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 sm:gap-2 shrink-0", children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "outlined", color: "primary", onClick: () => {
3328
- const rule_1 = {
3329
- name: dp_0.policyname,
3330
- operation: dp_0.cmd?.toLowerCase(),
3331
- mode: dp_0.permissive?.toLowerCase(),
3332
- using: dp_0.qual || void 0,
3333
- withCheck: dp_0.with_check || void 0,
3334
- roles: dp_0.roles
3335
- };
3336
- setFieldValue("securityRules", [...rules, rule_1]);
3337
- }, children: "Import to codebase" }) })
3338
- ] }, dp_0.policyname)) })
3339
- ] })
3340
- ] }),
3341
- /* @__PURE__ */ jsx(Dialog, { open: !!editingPolicy, onOpenChange: (open) => !open && setEditingPolicy(null), maxWidth: "4xl", children: editingPolicy && /* @__PURE__ */ jsx(InlinePolicyEditor, { policy: editingPolicy === "new" ? void 0 : editingPolicy, table: values.id || values.table || values.alias || "your_table", onSave: handleSave, onCancel: () => setEditingPolicy(null) }) })
3342
- ] }) });
3343
- }
3344
- const COMMAND_OPTIONS = ["ALL", "SELECT", "INSERT", "UPDATE", "DELETE"];
3345
- const ROLE_OPTIONS = ["public", "authenticated", "anon", "admin"];
3346
- function InlinePolicyEditor(t0) {
3347
- const $ = c(63);
3348
- const {
3349
- policy,
3350
- table,
3351
- onSave,
3352
- onCancel
3353
- } = t0;
3354
- const [name, setName] = useState(policy?.policyname || "");
3355
- const [behavior, setBehavior] = useState(policy?.permissive || "PERMISSIVE");
3356
- const [command, setCommand] = useState(policy?.cmd || "ALL");
3357
- let t1;
3358
- if ($[0] !== policy) {
3359
- t1 = policy?.roles ? Array.isArray(policy.roles) ? policy.roles : [policy.roles] : ["public"];
3360
- $[0] = policy;
3361
- $[1] = t1;
3362
- } else {
3363
- t1 = $[1];
3364
- }
3365
- const [roles, setRoles] = useState(t1);
3366
- const [usingExpr, setUsingExpr] = useState(policy?.qual || "");
3367
- const [checkExpr, setCheckExpr] = useState(policy?.with_check || "");
3368
- const showCheck = command === "ALL" || command === "INSERT" || command === "UPDATE";
3369
- const t2 = policy ? "Edit Policy" : "Create Policy";
3370
- let t3;
3371
- if ($[2] !== table) {
3372
- t3 = /* @__PURE__ */ jsxs("div", { className: "text-sm font-normal text-text-secondary dark:text-text-secondary-dark tracking-wide mt-1", children: [
3373
- "Define RLS rules for ",
3374
- /* @__PURE__ */ jsxs("span", { className: "font-mono text-primary bg-primary-bg dark:bg-primary-bg-dark px-1 py-0.5 rounded", children: [
3375
- "public.",
3376
- table
3377
- ] })
3378
- ] });
3379
- $[2] = table;
3380
- $[3] = t3;
3381
- } else {
3382
- t3 = $[3];
3383
- }
3384
- let t4;
3385
- if ($[4] !== t2 || $[5] !== t3) {
3386
- t4 = /* @__PURE__ */ jsxs(DialogTitle, { variant: "h6", children: [
3387
- t2,
3388
- t3
3389
- ] });
3390
- $[4] = t2;
3391
- $[5] = t3;
3392
- $[6] = t4;
3393
- } else {
3394
- t4 = $[6];
3395
- }
3396
- let t5;
3397
- if ($[7] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
3398
- t5 = cls("p-4 md:p-6 flex flex-col gap-6 bg-white dark:bg-surface-800 border-none sm:border-solid rounded-none sm:rounded-xl", defaultBorderMixin);
3399
- $[7] = t5;
3400
- } else {
3401
- t5 = $[7];
3402
- }
3403
- let t6;
3404
- if ($[8] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
3405
- t6 = /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "uppercase tracking-wider text-text-secondary", children: "Policy Name" });
3406
- $[8] = t6;
3407
- } else {
3408
- t6 = $[8];
3409
- }
3410
- let t7;
3411
- if ($[9] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
3412
- t7 = (e) => setName(e.target.value);
3413
- $[9] = t7;
3414
- } else {
3415
- t7 = $[9];
3416
- }
3417
- let t8;
3418
- if ($[10] !== name) {
3419
- t8 = /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
3420
- t6,
3421
- /* @__PURE__ */ jsx(TextField, { value: name, onChange: t7, placeholder: "e.g. allow_read_all" })
3422
- ] });
3423
- $[10] = name;
3424
- $[11] = t8;
3425
- } else {
3426
- t8 = $[11];
3427
- }
3428
- let t9;
3429
- if ($[12] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
3430
- t9 = /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "uppercase tracking-wider text-text-secondary", children: "Behavior" });
3431
- $[12] = t9;
3432
- } else {
3433
- t9 = $[12];
3434
- }
3435
- let t10;
3436
- if ($[13] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
3437
- t10 = (val) => setBehavior(val);
3438
- $[13] = t10;
3439
- } else {
3440
- t10 = $[13];
3441
- }
3442
- let t11;
3443
- let t12;
3444
- if ($[14] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
3445
- t11 = /* @__PURE__ */ jsx(SelectItem, { value: "PERMISSIVE", children: "Permissive" });
3446
- t12 = /* @__PURE__ */ jsx(SelectItem, { value: "RESTRICTIVE", children: "Restrictive" });
3447
- $[14] = t11;
3448
- $[15] = t12;
3449
- } else {
3450
- t11 = $[14];
3451
- t12 = $[15];
3452
- }
3453
- let t13;
3454
- if ($[16] !== behavior) {
3455
- t13 = /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
3456
- t9,
3457
- /* @__PURE__ */ jsxs(Select, { value: behavior, onValueChange: t10, position: "item-aligned", children: [
3458
- t11,
3459
- t12
3460
- ] })
3461
- ] });
3462
- $[16] = behavior;
3463
- $[17] = t13;
3464
- } else {
3465
- t13 = $[17];
3466
- }
3467
- let t14;
3468
- if ($[18] !== t13 || $[19] !== t8) {
3469
- t14 = /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
3470
- t8,
3471
- t13
3472
- ] });
3473
- $[18] = t13;
3474
- $[19] = t8;
3475
- $[20] = t14;
3476
- } else {
3477
- t14 = $[20];
3478
- }
3479
- let t15;
3480
- if ($[21] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
3481
- t15 = /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "uppercase tracking-wider text-text-secondary", children: "Command" });
3482
- $[21] = t15;
3483
- } else {
3484
- t15 = $[21];
3485
- }
3486
- let t16;
3487
- if ($[22] !== command) {
3488
- t16 = COMMAND_OPTIONS.map((cmd) => /* @__PURE__ */ jsx(Button, { size: "small", variant: command === cmd ? "filled" : "text", color: "neutral", onClick: () => setCommand(cmd), children: cmd }, cmd));
3489
- $[22] = command;
3490
- $[23] = t16;
3491
- } else {
3492
- t16 = $[23];
3493
- }
3494
- let t17;
3495
- if ($[24] !== t16) {
3496
- t17 = /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
3497
- t15,
3498
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: t16 })
3499
- ] });
3500
- $[24] = t16;
3501
- $[25] = t17;
3502
- } else {
3503
- t17 = $[25];
3504
- }
3505
- let t18;
3506
- if ($[26] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
3507
- t18 = /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "uppercase tracking-wider text-text-secondary", children: "Target Roles" });
3508
- $[26] = t18;
3509
- } else {
3510
- t18 = $[26];
3511
- }
3512
- let t19;
3513
- if ($[27] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
3514
- t19 = ROLE_OPTIONS.map(_temp);
3515
- $[27] = t19;
3516
- } else {
3517
- t19 = $[27];
3518
- }
3519
- let t20;
3520
- if ($[28] !== roles) {
3521
- t20 = /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
3522
- t18,
3523
- /* @__PURE__ */ jsx(MultiSelect, { size: "small", value: roles, onValueChange: setRoles, placeholder: "Select roles", children: t19 })
3524
- ] });
3525
- $[28] = roles;
3526
- $[29] = t20;
3527
- } else {
3528
- t20 = $[29];
3529
- }
3530
- let t21;
3531
- if ($[30] !== command || $[31] !== usingExpr) {
3532
- t21 = command !== "INSERT" && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
3533
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "uppercase tracking-wider text-text-secondary", children: "USING expression" }),
3534
- /* @__PURE__ */ jsx(TextField, { value: usingExpr, onChange: (e_0) => setUsingExpr(e_0.target.value), placeholder: "e.g. auth.uid() = user_id" })
3535
- ] });
3536
- $[30] = command;
3537
- $[31] = usingExpr;
3538
- $[32] = t21;
3539
- } else {
3540
- t21 = $[32];
3541
- }
3542
- let t22;
3543
- if ($[33] !== checkExpr || $[34] !== showCheck) {
3544
- t22 = showCheck && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
3545
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "uppercase tracking-wider text-text-secondary", children: "WITH CHECK expression" }),
3546
- /* @__PURE__ */ jsx(TextField, { value: checkExpr, onChange: (e_1) => setCheckExpr(e_1.target.value), placeholder: "e.g. auth.uid() = user_id" })
3547
- ] });
3548
- $[33] = checkExpr;
3549
- $[34] = showCheck;
3550
- $[35] = t22;
3551
- } else {
3552
- t22 = $[35];
3553
- }
3554
- let t23;
3555
- if ($[36] !== t14 || $[37] !== t17 || $[38] !== t20 || $[39] !== t21 || $[40] !== t22) {
3556
- t23 = /* @__PURE__ */ jsx(DialogContent, { className: "p-4 md:p-6 border-t dark:border-surface-700 bg-surface-50 dark:bg-surface-800", includeMargin: false, children: /* @__PURE__ */ jsxs(Paper, { className: t5, children: [
3557
- t14,
3558
- t17,
3559
- t20,
3560
- t21,
3561
- t22
3562
- ] }) });
3563
- $[36] = t14;
3564
- $[37] = t17;
3565
- $[38] = t20;
3566
- $[39] = t21;
3567
- $[40] = t22;
3568
- $[41] = t23;
3569
- } else {
3570
- t23 = $[41];
3571
- }
3572
- let t24;
3573
- if ($[42] !== onCancel) {
3574
- t24 = /* @__PURE__ */ jsx(Button, { size: "small", variant: "text", color: "neutral", onClick: onCancel, children: "Cancel" });
3575
- $[42] = onCancel;
3576
- $[43] = t24;
3577
- } else {
3578
- t24 = $[43];
3579
- }
3580
- const t25 = !name;
3581
- let t26;
3582
- if ($[44] !== behavior || $[45] !== checkExpr || $[46] !== command || $[47] !== name || $[48] !== onSave || $[49] !== roles || $[50] !== showCheck || $[51] !== usingExpr) {
3583
- t26 = () => onSave({
3584
- policyname: name,
3585
- permissive: behavior,
3586
- cmd: command,
3587
- roles,
3588
- qual: usingExpr,
3589
- with_check: showCheck ? checkExpr : null
3590
- });
3591
- $[44] = behavior;
3592
- $[45] = checkExpr;
3593
- $[46] = command;
3594
- $[47] = name;
3595
- $[48] = onSave;
3596
- $[49] = roles;
3597
- $[50] = showCheck;
3598
- $[51] = usingExpr;
3599
- $[52] = t26;
3600
- } else {
3601
- t26 = $[52];
3602
- }
3603
- let t27;
3604
- if ($[53] !== t25 || $[54] !== t26) {
3605
- t27 = /* @__PURE__ */ jsx(Button, { size: "small", variant: "filled", color: "primary", disabled: t25, onClick: t26, children: "Save" });
3606
- $[53] = t25;
3607
- $[54] = t26;
3608
- $[55] = t27;
3609
- } else {
3610
- t27 = $[55];
3611
- }
3612
- let t28;
3613
- if ($[56] !== t24 || $[57] !== t27) {
3614
- t28 = /* @__PURE__ */ jsxs(DialogActions, { children: [
3615
- t24,
3616
- t27
3617
- ] });
3618
- $[56] = t24;
3619
- $[57] = t27;
3620
- $[58] = t28;
3621
- } else {
3622
- t28 = $[58];
3623
- }
3624
- let t29;
3625
- if ($[59] !== t23 || $[60] !== t28 || $[61] !== t4) {
3626
- t29 = /* @__PURE__ */ jsxs(Fragment, { children: [
3627
- t4,
3628
- t23,
3629
- t28
3630
- ] });
3631
- $[59] = t23;
3632
- $[60] = t28;
3633
- $[61] = t4;
3634
- $[62] = t29;
3635
- } else {
3636
- t29 = $[62];
3637
- }
3638
- return t29;
3639
- }
3640
- function _temp(r) {
3641
- return /* @__PURE__ */ jsx(MultiSelectItem, { value: r, children: r }, r);
3642
- }
3643
- function pgTypeToRebaseProperty(column) {
3644
- const {
3645
- column_name,
3646
- data_type,
3647
- udt_name,
3648
- is_nullable,
3649
- column_default,
3650
- enum_values
3651
- } = column;
3652
- const required = is_nullable === "NO";
3653
- const prettifiedName = prettifyIdentifier(column_name);
3654
- const isAutoId = column_default != null && (column_default.includes("nextval") || column_default.includes("gen_random_uuid") || column_default.includes("uuid_generate") || column_default.includes("identity"));
3655
- if (data_type === "USER-DEFINED" && enum_values && enum_values.length > 0) {
3656
- return {
3657
- type: "string",
3658
- name: prettifiedName,
3659
- enum: enum_values.map((v) => ({
3660
- id: v,
3661
- label: prettifyIdentifier(v)
3662
- })),
3663
- validation: required ? {
3664
- required: true
3665
- } : void 0
3666
- };
3667
- }
3668
- const dt = data_type.toLowerCase();
3669
- switch (dt) {
3670
- case "character varying":
3671
- case "varchar":
3672
- case "text":
3673
- case "char":
3674
- case "character":
3675
- case "citext": {
3676
- let colType = "varchar";
3677
- if (dt === "text" || dt === "citext") colType = "text";
3678
- if (dt === "char" || dt === "character") colType = "char";
3679
- const prop = {
3680
- type: "string",
3681
- name: prettifiedName,
3682
- columnType: colType,
3683
- validation: required ? {
3684
- required: true
3685
- } : void 0
3686
- };
3687
- if (isAutoId) {
3688
- prop.isId = "manual";
3689
- }
3690
- return prop;
3691
- }
3692
- case "uuid": {
3693
- const prop = {
3694
- type: "string",
3695
- name: prettifiedName,
3696
- validation: required ? {
3697
- required: true
3698
- } : void 0
3699
- };
3700
- if (isAutoId) {
3701
- prop.isId = "uuid";
3702
- }
3703
- return prop;
3704
- }
3705
- case "integer":
3706
- case "bigint":
3707
- case "smallint": {
3708
- const colType = dt === "bigint" ? "bigint" : "integer";
3709
- const prop = {
3710
- type: "number",
3711
- name: prettifiedName,
3712
- columnType: colType,
3713
- validation: {
3714
- ...required ? {
3715
- required: true
3716
- } : {},
3717
- integer: true
3718
- }
3719
- };
3720
- if (isAutoId) {
3721
- prop.isId = "increment";
3722
- }
3723
- return prop;
3724
- }
3725
- case "serial":
3726
- case "bigserial":
3727
- case "smallserial": {
3728
- const colType = dt === "bigserial" ? "bigserial" : "serial";
3729
- return {
3730
- type: "number",
3731
- name: prettifiedName,
3732
- columnType: colType,
3733
- isId: "increment",
3734
- validation: {
3735
- ...required ? {
3736
- required: true
3737
- } : {},
3738
- integer: true
3739
- }
3740
- };
3741
- }
3742
- case "numeric":
3743
- case "decimal":
3744
- case "real":
3745
- case "double precision": {
3746
- let colType = "numeric";
3747
- if (dt === "real") colType = "real";
3748
- if (dt === "double precision") colType = "double precision";
3749
- return {
3750
- type: "number",
3751
- name: prettifiedName,
3752
- columnType: colType,
3753
- validation: required ? {
3754
- required: true
3755
- } : void 0
3756
- };
3757
- }
3758
- case "boolean":
3759
- return {
3760
- type: "boolean",
3761
- name: prettifiedName,
3762
- validation: required ? {
3763
- required: true
3764
- } : void 0
3765
- };
3766
- case "timestamp with time zone":
3767
- case "timestamp without time zone":
3768
- case "timestamp":
3769
- case "timestamptz":
3770
- case "date":
3771
- case "time with time zone":
3772
- case "time without time zone":
3773
- case "time": {
3774
- let colType = "timestamp";
3775
- if (dt.startsWith("date")) colType = "date";
3776
- if (dt.startsWith("time ") || dt === "time") colType = "time";
3777
- return {
3778
- type: "date",
3779
- name: prettifiedName,
3780
- columnType: colType,
3781
- validation: required ? {
3782
- required: true
3783
- } : void 0
3784
- };
3785
- }
3786
- case "jsonb":
3787
- case "json":
3788
- return {
3789
- type: "map",
3790
- name: prettifiedName,
3791
- columnType: dt === "jsonb" ? "jsonb" : "json",
3792
- keyValue: true,
3793
- properties: {}
3794
- };
3795
- case "array":
3796
- case "ARRAY": {
3797
- let innerType = "string";
3798
- let colType = void 0;
3799
- if (udt_name === "_text" || udt_name === "_varchar") {
3800
- innerType = "string";
3801
- colType = "text[]";
3802
- } else if (udt_name === "_int4" || udt_name === "_int2" || udt_name === "_int8") {
3803
- innerType = "number";
3804
- colType = "integer[]";
3805
- } else if (udt_name === "_bool") {
3806
- innerType = "boolean";
3807
- colType = "boolean[]";
3808
- } else if (udt_name === "_numeric") {
3809
- innerType = "number";
3810
- colType = "numeric[]";
3811
- }
3812
- return {
3813
- type: "array",
3814
- name: prettifiedName,
3815
- columnType: colType,
3816
- of: {
3817
- type: innerType
3818
- }
3819
- };
3820
- }
3821
- default:
3822
- return {
3823
- type: "string",
3824
- name: prettifiedName,
3825
- validation: required ? {
3826
- required: true
3827
- } : void 0
3828
- };
3829
- }
3830
- }
3831
- function buildCollectionFromTableMetadata(tableName, metadata) {
3832
- const properties = {};
3833
- const propertiesOrder = [];
3834
- const relations = [];
3835
- const securityRules = [];
3836
- for (const column of metadata.columns) {
3837
- const property = pgTypeToRebaseProperty(column);
3838
- if (property) {
3839
- const propRecord = property;
3840
- Object.keys(propRecord).forEach((key) => propRecord[key] === void 0 && delete propRecord[key]);
3841
- properties[column.column_name] = property;
3842
- propertiesOrder.push(column.column_name);
3843
- }
3844
- }
3845
- if (metadata.foreignKeys) {
3846
- for (const fk of metadata.foreignKeys) {
3847
- const relName = fk.column_name.endsWith("_id") ? fk.column_name.substring(0, fk.column_name.length - 3) : fk.column_name;
3848
- relations.push({
3849
- id: fk.column_name,
3850
- relationName: relName,
3851
- target: fk.foreign_table_name,
3852
- // Will be hydrated later
3853
- cardinality: "one",
3854
- direction: "owning",
3855
- localKey: fk.column_name
3856
- });
3857
- }
3858
- }
3859
- if (metadata.junctions) {
3860
- for (const junction of metadata.junctions) {
3861
- const relName = junction.target_table_name;
3862
- relations.push({
3863
- id: junction.target_table_name + "_relation",
3864
- relationName: relName,
3865
- target: junction.target_table_name,
3866
- // Will be hydrated later
3867
- cardinality: "many",
3868
- direction: "owning",
3869
- through: {
3870
- table: junction.junction_table_name,
3871
- sourceColumn: junction.source_column_name,
3872
- targetColumn: junction.target_column_name
3873
- }
3874
- });
3875
- }
3876
- }
3877
- if (metadata.policies) {
3878
- for (const policy of metadata.policies) {
3879
- let operations = [];
3880
- switch (policy.cmd) {
3881
- case "ALL":
3882
- operations = ["read", "create", "update", "delete"];
3883
- break;
3884
- case "SELECT":
3885
- operations = ["read"];
3886
- break;
3887
- case "INSERT":
3888
- operations = ["create"];
3889
- break;
3890
- case "UPDATE":
3891
- operations = ["update"];
3892
- break;
3893
- case "DELETE":
3894
- operations = ["delete"];
3895
- break;
3896
- }
3897
- securityRules.push({
3898
- name: policy.policy_name,
3899
- operations,
3900
- // roles is string[] e.g., ["public", "authenticated"]
3901
- roles: policy.roles ?? [],
3902
- qual: policy.qual,
3903
- with_check: policy.with_check
3904
- });
3905
- }
3906
- }
3907
- const prettifiedName = prettifyIdentifier(tableName);
3908
- return {
3909
- name: prettifiedName,
3910
- slug: tableName,
3911
- table: tableName,
3912
- properties,
3913
- propertiesOrder,
3914
- ...relations.length > 0 ? {
3915
- relations
3916
- } : {},
3917
- ...securityRules.length > 0 ? {
3918
- securityRules
3919
- } : {}
3920
- };
3921
- }
3922
- function CollectionEditorDialog(props) {
3923
- const $ = c(25);
3924
- const open = props.open;
3925
- const [formDirty, setFormDirty] = React.useState(false);
3926
- let t0;
3927
- if ($[0] !== props) {
3928
- t0 = () => props.handleClose(void 0);
3929
- $[0] = props;
3930
- $[1] = t0;
3931
- } else {
3932
- t0 = $[1];
3933
- }
3934
- const {
3935
- dialogProps,
3936
- triggerDialog
3937
- } = useUnsavedChangesDialog(open && formDirty, t0);
3938
- let t1;
3939
- if ($[2] !== formDirty || $[3] !== props || $[4] !== triggerDialog) {
3940
- t1 = () => {
3941
- if (!formDirty) {
3942
- props.handleClose(void 0);
3943
- } else {
3944
- triggerDialog();
3945
- }
3946
- };
3947
- $[2] = formDirty;
3948
- $[3] = props;
3949
- $[4] = triggerDialog;
3950
- $[5] = t1;
3951
- } else {
3952
- t1 = $[5];
3953
- }
3954
- const handleCancel = t1;
3955
- let t2;
3956
- let t3;
3957
- if ($[6] !== open) {
3958
- t2 = () => {
3959
- if (!open) {
3960
- setFormDirty(false);
3961
- }
3962
- };
3963
- t3 = [open];
3964
- $[6] = open;
3965
- $[7] = t2;
3966
- $[8] = t3;
3967
- } else {
3968
- t2 = $[7];
3969
- t3 = $[8];
3970
- }
3971
- useEffect(t2, t3);
3972
- let t4;
3973
- if ($[9] !== handleCancel) {
3974
- t4 = (open_0) => !open_0 ? handleCancel() : void 0;
3975
- $[9] = handleCancel;
3976
- $[10] = t4;
3977
- } else {
3978
- t4 = $[10];
3979
- }
3980
- let t5;
3981
- if ($[11] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
3982
- t5 = /* @__PURE__ */ jsx(DialogTitle, { hidden: true, children: "Collection editor" });
3983
- $[11] = t5;
3984
- } else {
3985
- t5 = $[11];
3986
- }
3987
- let t6;
3988
- if ($[12] !== handleCancel || $[13] !== open || $[14] !== props) {
3989
- t6 = open && /* @__PURE__ */ jsx(CollectionEditor, { ...props, handleCancel, setFormDirty });
3990
- $[12] = handleCancel;
3991
- $[13] = open;
3992
- $[14] = props;
3993
- $[15] = t6;
3994
- } else {
3995
- t6 = $[15];
3996
- }
3997
- let t7;
3998
- if ($[16] !== dialogProps) {
3999
- t7 = /* @__PURE__ */ jsx(UnsavedChangesDialog, { ...dialogProps });
4000
- $[16] = dialogProps;
4001
- $[17] = t7;
4002
- } else {
4003
- t7 = $[17];
4004
- }
4005
- let t8;
4006
- if ($[18] !== t6 || $[19] !== t7) {
4007
- t8 = /* @__PURE__ */ jsxs(AIModifiedPathsProvider, { children: [
4008
- t6,
4009
- t7
4010
- ] });
4011
- $[18] = t6;
4012
- $[19] = t7;
4013
- $[20] = t8;
4014
- } else {
4015
- t8 = $[20];
4016
- }
4017
- let t9;
4018
- if ($[21] !== open || $[22] !== t4 || $[23] !== t8) {
4019
- t9 = /* @__PURE__ */ jsxs(Dialog, { open, fullWidth: true, fullHeight: true, scrollable: false, maxWidth: "7xl", onOpenChange: t4, children: [
4020
- t5,
4021
- t8
4022
- ] });
4023
- $[21] = open;
4024
- $[22] = t4;
4025
- $[23] = t8;
4026
- $[24] = t9;
4027
- } else {
4028
- t9 = $[24];
4029
- }
4030
- return t9;
4031
- }
4032
- function CollectionEditor(props) {
4033
- const {
4034
- propertyConfigs
4035
- } = useCustomizationController();
4036
- const navigationState = useNavigationStateController();
4037
- const collectionRegistry = useCollectionRegistryController();
4038
- const authController = useAuthController();
4039
- const {
4040
- topLevelNavigation
4041
- } = navigationState;
4042
- const {
4043
- collections
4044
- } = collectionRegistry;
4045
- const initialValuesProp = props.initialValues;
4046
- const copyFromProp = props.copyFrom;
4047
- const includeTemplates = !copyFromProp && !initialValuesProp?.slug && (props.parentCollectionSlugs ?? []).length === 0;
4048
- const collectionsInThisLevel = (props.parentCollection ? getSubcollections(props.parentCollection) : collections) ?? [];
4049
- const existingPaths = collectionsInThisLevel.map((col) => getTableName(col)?.trim().toLowerCase()).filter(Boolean);
4050
- const existingIds = collectionsInThisLevel.map((col_0) => col_0.slug?.trim().toLowerCase()).filter(Boolean);
4051
- const [collection, setCollection] = React.useState();
4052
- const [initialLoadingCompleted, setInitialLoadingCompleted] = React.useState(false);
4053
- useEffect(() => {
4054
- try {
4055
- if (collectionRegistry.initialised) {
4056
- if (props.editedCollectionId) {
4057
- const collectionPath = [...props.parentCollectionSlugs ?? [], props.editedCollectionId].reduce((acc, segment, i) => i === 0 ? segment : `${acc}/fake_id/${segment}`, "");
4058
- setCollection(collectionRegistry.getRawCollection(collectionPath));
4059
- } else {
4060
- setCollection(void 0);
4061
- }
4062
- setInitialLoadingCompleted(true);
4063
- }
4064
- } catch (e) {
4065
- console.error(e);
4066
- }
4067
- }, [props.editedCollectionId, props.parentCollectionSlugs, props.parentEntityIds, collectionRegistry.initialised, collectionRegistry.getRawCollection]);
4068
- const initialCollection = collection ? {
4069
- ...collection,
4070
- slug: collection.slug ?? randomString(16)
4071
- } : void 0;
4072
- const initialValues = initialCollection ? applyPropertyConfigs(initialCollection, propertyConfigs) : copyFromProp ? (() => {
4073
- const {
4074
- subcollections: _sub,
4075
- ...rest
4076
- } = copyFromProp;
4077
- return {
4078
- ...rest,
4079
- name: "",
4080
- ownerId: authController.user?.uid ?? ""
4081
- };
4082
- })() : {
4083
- slug: initialValuesProp?.slug ?? randomString(16),
4084
- table: initialValuesProp?.slug ?? "",
4085
- name: initialValuesProp?.name ?? "",
4086
- properties: {},
4087
- propertiesOrder: [],
4088
- icon: coolIconKeys[Math.floor(Math.random() * coolIconKeys.length)],
4089
- ownerId: authController.user?.uid ?? ""
4090
- };
4091
- if (!initialLoadingCompleted) {
4092
- return /* @__PURE__ */ jsx(CircularProgressCenter, {});
4093
- }
4094
- if (!props.isNewCollection && (!collectionRegistry.initialised || !initialLoadingCompleted)) {
4095
- return /* @__PURE__ */ jsx(CircularProgressCenter, {});
4096
- }
4097
- return /* @__PURE__ */ jsx(CollectionEditorInternal, { ...props, initialValues, existingPaths, existingIds, includeTemplates, collection, setCollection, propertyConfigs });
4098
- }
4099
- function CollectionEditorInternal({
4100
- isNewCollection,
4101
- configController,
4102
- editedCollectionId,
4103
- parentCollectionSlugs,
4104
- parentEntityIds,
4105
- path,
4106
- collectionInference,
4107
- handleClose,
4108
- extraView,
4109
- handleCancel,
4110
- setFormDirty,
4111
- getUser,
4112
- parentCollection,
4113
- getData,
4114
- existingPaths,
4115
- existingIds,
4116
- includeTemplates,
4117
- collection,
4118
- setCollection,
4119
- initialValues,
4120
- propertyConfigs,
4121
- existingEntities,
4122
- initialView: initialViewProp,
4123
- expandKanban,
4124
- generateCollection,
4125
- onAnalyticsEvent,
4126
- fullScreen,
4127
- unmappedTables,
4128
- onFetchTableMetadata
4129
- }) {
4130
- const importConfig = useImportConfig();
4131
- const urlController = useUrlController();
4132
- const collectionRegistry = useCollectionRegistryController();
4133
- const snackbarController = useSnackbarController();
4134
- const propertyErrorsRef = useRef({});
4135
- const initialView = isNewCollection ? includeTemplates ? "welcome" : "general" : initialViewProp ?? "properties";
4136
- const [currentView, setCurrentView] = useState(initialView);
4137
- const [error, setError] = React.useState();
4138
- const saveCollection = (updatedCollection) => {
4139
- const id = updatedCollection.slug;
4140
- return configController.saveCollection({
4141
- id,
4142
- collectionData: updatedCollection,
4143
- previousId: editedCollectionId,
4144
- parentCollectionSlugs
4145
- }).then(() => {
4146
- setError(void 0);
4147
- return true;
4148
- }).catch((e) => {
4149
- setError(e);
4150
- console.error(e);
4151
- snackbarController.open({
4152
- type: "error",
4153
- message: "Error persisting collection: " + (e.message ?? "Details in the console")
4154
- });
4155
- return false;
4156
- });
4157
- };
4158
- const setNextMode = () => {
4159
- if (currentView === "general") {
4160
- if (importConfig.inUse) {
4161
- setCurrentView("import_data_saving");
4162
- } else if (extraView) {
4163
- setCurrentView("extra_view");
4164
- } else {
4165
- setCurrentView("properties");
4166
- }
4167
- } else if (currentView === "welcome") {
4168
- setCurrentView("general");
4169
- } else if (currentView === "import_data_mapping") {
4170
- setCurrentView("import_data_preview");
4171
- } else if (currentView === "import_data_preview") {
4172
- setCurrentView("general");
4173
- } else if (currentView === "extra_view") {
4174
- setCurrentView("properties");
4175
- } else {
4176
- setCurrentView("general");
4177
- }
4178
- };
4179
- const doCollectionInference = collectionInference ? (collection_0) => {
4180
- if (!collectionInference) return void 0;
4181
- return collectionInference?.(collection_0.slug, parentPaths ?? [], collection_0.databaseId);
4182
- } : void 0;
4183
- const inferCollectionFromData = async (newCollection) => {
4184
- try {
4185
- if (!doCollectionInference) {
4186
- setCollection(newCollection);
4187
- return Promise.resolve(newCollection);
4188
- }
4189
- setCurrentView("loading");
4190
- const inferredCollection = await doCollectionInference?.(newCollection);
4191
- if (!inferredCollection) {
4192
- setCollection(newCollection);
4193
- return Promise.resolve(newCollection);
4194
- }
4195
- const values = {
4196
- ...newCollection ?? {}
4197
- };
4198
- if (Object.keys(inferredCollection.properties ?? {}).length > 0) {
4199
- values.properties = inferredCollection.properties;
4200
- values.propertiesOrder = inferredCollection.propertiesOrder;
4201
- }
4202
- if (!values.propertiesOrder) {
4203
- values.propertiesOrder = Object.keys(values.properties);
4204
- return values;
4205
- }
4206
- setCollection(values);
4207
- console.debug("Inferred collection", {
4208
- newCollection: newCollection ?? {},
4209
- values
4210
- });
4211
- return values;
4212
- } catch (e_0) {
4213
- console.error(e_0);
4214
- snackbarController.open({
4215
- type: "error",
4216
- message: "Error inferring collection: " + (e_0 instanceof Error ? e_0.message : "Details in the console")
4217
- });
4218
- return newCollection;
4219
- }
4220
- };
4221
- const onSubmit = async (newCollectionState, formexController) => {
4222
- console.debug("Submitting collection", newCollectionState);
4223
- try {
4224
- if (!isNewCollection) {
4225
- const success = await saveCollection(newCollectionState);
4226
- if (success) {
4227
- aiModifiedPaths?.clearAllPaths();
4228
- formexController.resetForm({
4229
- values: newCollectionState
4230
- });
4231
- handleClose(newCollectionState);
4232
- }
4233
- return;
4234
- }
4235
- if (currentView === "welcome") {
4236
- setNextMode();
4237
- formexController.resetForm({
4238
- values: newCollectionState
4239
- });
4240
- } else if (currentView === "general") {
4241
- if (extraView || importConfig.inUse) {
4242
- formexController.resetForm({
4243
- values: newCollectionState
4244
- });
4245
- setNextMode();
4246
- } else if (isNewCollection) {
4247
- const values_0 = await inferCollectionFromData(newCollectionState);
4248
- formexController.resetForm({
4249
- values: values_0 ?? newCollectionState,
4250
- touched: {
4251
- path: true,
4252
- name: true
4253
- }
4254
- });
4255
- setNextMode();
4256
- } else {
4257
- formexController.resetForm({
4258
- values: newCollectionState
4259
- });
4260
- setNextMode();
4261
- }
4262
- } else if (currentView === "extra_view") {
4263
- setNextMode();
4264
- formexController.resetForm({
4265
- values: newCollectionState
4266
- });
4267
- } else if (currentView === "import_data_mapping") {
4268
- setNextMode();
4269
- } else if (currentView === "import_data_preview") {
4270
- setNextMode();
4271
- } else if (currentView === "properties") {
4272
- const success_0 = await saveCollection(newCollectionState);
4273
- if (success_0) {
4274
- formexController.resetForm({
4275
- values: initialValues
4276
- });
4277
- setNextMode();
4278
- handleClose(newCollectionState);
4279
- }
4280
- } else {
4281
- setNextMode();
4282
- formexController.resetForm({
4283
- values: newCollectionState
4284
- });
4285
- }
4286
- } catch (e_1) {
4287
- snackbarController.open({
4288
- type: "error",
4289
- message: "Error persisting collection: " + (e_1 instanceof Error ? e_1.message : "Details in the console")
4290
- });
4291
- console.error(e_1);
4292
- formexController.resetForm({
4293
- values: newCollectionState
4294
- });
4295
- }
4296
- };
4297
- const validation = (col) => {
4298
- let errors = {};
4299
- const schema = (currentView === "properties" || currentView === "general") && CollectionEditorSchema;
4300
- if (schema) {
4301
- const result = schema.safeParse(col);
4302
- if (!result.success) {
4303
- result.error.issues.forEach((issue) => {
4304
- const path_0 = issue.path.join(".");
4305
- if (path_0) {
4306
- errors[path_0] = issue.message;
4307
- }
4308
- });
4309
- }
4310
- }
4311
- if (currentView === "properties") {
4312
- errors = {
4313
- ...errors,
4314
- ...propertyErrorsRef.current
4315
- };
4316
- }
4317
- if (currentView === "general") {
4318
- const pathError = validatePath(getTableName(col), isNewCollection, existingPaths, col.slug);
4319
- if (pathError) {
4320
- errors.slug = pathError;
4321
- }
4322
- const idError = validateId(col.slug, isNewCollection, existingPaths, existingIds);
4323
- if (idError) {
4324
- errors.id = idError;
4325
- }
4326
- }
4327
- if (Object.keys(errors).length > 0) {
4328
- console.error("Formex validation blocked save:", errors, "Current view:", currentView);
4329
- }
4330
- return errors;
4331
- };
4332
- const formController = useCreateFormex({
4333
- initialValues,
4334
- onSubmit,
4335
- validation,
4336
- debugId: "COLLECTION_EDITOR"
4337
- });
4338
- const {
4339
- values: values_1,
4340
- setFieldValue,
4341
- isSubmitting,
4342
- dirty,
4343
- submitCount
4344
- } = formController;
4345
- const usedPath = getTableName(values_1);
4346
- const pathError_0 = validatePath(usedPath, isNewCollection, existingPaths, values_1.slug);
4347
- const parentPaths = !pathError_0 && parentCollectionSlugs ? collectionRegistry.convertIdsToPaths(parentCollectionSlugs) : void 0;
4348
- const updatedFullPath = parentPaths && parentPaths.length > 0 ? [...parentPaths, usedPath].join("/fake_id/") : path?.includes("/") ? path.split("/").slice(0, -1).join("/") + "/" + usedPath : usedPath;
4349
- const resolvedPath = !pathError_0 ? urlController.resolveDatabasePathsFrom(updatedFullPath) : void 0;
4350
- const getDataWithPath = resolvedPath && getData ? async () => {
4351
- const data = await getData(resolvedPath, parentPaths ?? []);
4352
- if (existingEntities) {
4353
- const existingData = existingEntities.map((e_2) => e_2.values);
4354
- data.push(...existingData);
4355
- }
4356
- return data;
4357
- } : void 0;
4358
- useEffect(() => {
4359
- setFormDirty(dirty);
4360
- }, [dirty]);
4361
- function onImportDataSet(data_0, propertiesOrder) {
4362
- importConfig.setInUse(true);
4363
- buildEntityPropertiesFromData(data_0, getInferenceType).then((properties) => {
4364
- const res = cleanPropertiesFromImport(properties);
4365
- importConfig.setIdColumn(res.idColumn);
4366
- importConfig.setImportData(data_0);
4367
- importConfig.setHeadersMapping(res.headersMapping);
4368
- const filteredHeadingsOrder = (propertiesOrder ?? []).filter((key) => res.headersMapping[key]) ?? Object.keys(res.properties);
4369
- importConfig.setHeadingsOrder(filteredHeadingsOrder);
4370
- importConfig.setOriginProperties(res.properties);
4371
- const mappedHeadings = (propertiesOrder ?? []).map((key_0) => res.headersMapping[key_0]).filter(Boolean) ?? Object.keys(res.properties);
4372
- setFieldValue("properties", res.properties);
4373
- setFieldValue("propertiesOrder", mappedHeadings);
4374
- });
4375
- }
4376
- const validValues = Boolean(values_1.name) && Boolean(values_1.slug);
4377
- const onImportMappingComplete = () => {
4378
- const updatedProperties = {
4379
- ...values_1.properties
4380
- };
4381
- if (importConfig.idColumn) delete updatedProperties[importConfig.idColumn];
4382
- setFieldValue("properties", updatedProperties);
4383
- setNextMode();
4384
- };
4385
- const [deleteRequested, setDeleteRequested] = useState(false);
4386
- const deleteCollection = () => {
4387
- if (!collection) return;
4388
- configController?.deleteCollection({
4389
- id: collection.slug
4390
- }).then(() => {
4391
- setDeleteRequested(false);
4392
- handleCancel();
4393
- snackbarController.open({
4394
- message: "Collection deleted",
4395
- type: "success"
4396
- });
4397
- });
4398
- };
4399
- const onWelcomeScreenContinue = (importData, propertiesOrder_0) => {
4400
- if (importData) {
4401
- onImportDataSet(importData, propertiesOrder_0);
4402
- setCurrentView("import_data_mapping");
4403
- } else {
4404
- setCurrentView("general");
4405
- }
4406
- };
4407
- const aiModifiedPaths = useAIModifiedPaths();
4408
- const handleAIGenerated = (generatedCollection, operations) => {
4409
- formController.setValues(generatedCollection);
4410
- if (operations && aiModifiedPaths) {
4411
- aiModifiedPaths.addModifiedPaths(operations);
4412
- }
4413
- };
4414
- return /* @__PURE__ */ jsxs("div", { className: "h-full w-full flex flex-col bg-white dark:bg-surface-950", children: [
4415
- /* @__PURE__ */ jsx(Formex, { value: formController, children: /* @__PURE__ */ jsxs(Fragment, { children: [
4416
- !isNewCollection && /* @__PURE__ */ jsxs("div", { className: cls("px-4 py-2 w-full flex shrink-0 items-center justify-between gap-4 bg-surface-50 dark:bg-surface-950 border-b", defaultBorderMixin), children: [
4417
- /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-end gap-4 min-w-0", children: /* @__PURE__ */ jsxs(Tabs, { value: currentView, className: "bg-transparent !w-fit max-w-full", onValueChange: (v) => setCurrentView(v), children: [
4418
- /* @__PURE__ */ jsx(Tab, { value: "general", children: "General" }),
4419
- /* @__PURE__ */ jsx(Tab, { value: "display", children: "Display" }),
4420
- /* @__PURE__ */ jsx(Tab, { value: "properties", children: "Properties" }),
4421
- getDataSourceCapabilities(values_1.driver).supportsRLS && /* @__PURE__ */ jsx(Tab, { value: "rls", children: "RLS" })
4422
- ] }) }),
4423
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
4424
- generateCollection && /* @__PURE__ */ jsx(AICollectionGeneratorPopover, { existingCollection: values_1, onGenerated: handleAIGenerated, generateCollection, onAnalyticsEvent }),
4425
- fullScreen && !isNewCollection && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsx(LoadingButton, { variant: "filled", color: "primary", type: "submit", onClick: () => formController.handleSubmit(), disabled: !dirty || isSubmitting || configController?.readOnly, loading: isSubmitting, children: configController?.readOnly ? "Update (Read-only)" : "Update" }) })
4426
- ] })
4427
- ] }),
4428
- /* @__PURE__ */ jsxs("form", { noValidate: true, onSubmit: formController.handleSubmit, className: "flex-grow flex flex-col min-h-0 relative", children: [
4429
- /* @__PURE__ */ jsxs("div", { className: "flex-grow flex flex-col min-h-0 overflow-y-auto no-scrollbar relative w-full h-full", children: [
4430
- currentView === "loading" && /* @__PURE__ */ jsx(CircularProgressCenter, {}),
4431
- currentView === "extra_view" && usedPath && extraView?.View && /* @__PURE__ */ jsx(extraView.View, { path: usedPath }),
4432
- currentView === "welcome" && /* @__PURE__ */ jsx(CollectionEditorWelcomeView, { path: usedPath, onContinue: onWelcomeScreenContinue, existingCollectionPaths: existingPaths, parentCollection, generateCollection, onAnalyticsEvent, unmappedTables, onImportFromTable: onFetchTableMetadata ? async (tableName) => {
4433
- try {
4434
- const columns = await onFetchTableMetadata(tableName);
4435
- if (!columns) return;
4436
- const collectionData = buildCollectionFromTableMetadata(tableName, columns);
4437
- formController.setValues({
4438
- ...formController.values,
4439
- ...collectionData
4440
- });
4441
- onWelcomeScreenContinue();
4442
- } catch (e_3) {
4443
- console.error("Error importing table:", e_3);
4444
- snackbarController.open({
4445
- type: "error",
4446
- message: "Error importing table: " + (e_3 instanceof Error ? e_3.message : "Unknown error")
4447
- });
4448
- }
4449
- } : void 0 }),
4450
- currentView === "import_data_mapping" && importConfig && /* @__PURE__ */ jsx(CollectionEditorImportMapping, { importConfig, propertyConfigs }),
4451
- currentView === "import_data_preview" && importConfig && /* @__PURE__ */ jsx(CollectionEditorImportDataPreview, { importConfig, properties: values_1.properties, propertiesOrder: values_1.propertiesOrder }),
4452
- currentView === "import_data_saving" && importConfig && /* @__PURE__ */ jsx(ImportSaveInProgress, { importConfig, collection: values_1, path: usedPath, onImportSuccess: async (importedCollection) => {
4453
- snackbarController.open({
4454
- type: "info",
4455
- message: "Data imported successfully"
4456
- });
4457
- await saveCollection(values_1);
4458
- handleClose(importedCollection);
4459
- } }),
4460
- currentView === "general" && /* @__PURE__ */ jsx(GeneralSettingsForm, { existingPaths, existingIds, parentCollection, isNewCollection }),
4461
- currentView === "display" && /* @__PURE__ */ jsx(DisplaySettingsForm, { expandKanban }),
4462
- currentView === "rls" && getDataSourceCapabilities(values_1.driver).supportsRLS && /* @__PURE__ */ jsx(CollectionRLSTab, {}),
4463
- currentView === "properties" && /* @__PURE__ */ jsx(CollectionPropertiesEditorForm, { showErrors: submitCount > 0, isNewCollection, onPropertyError: (propertyKey, namespace, error_0) => {
4464
- const current = removeUndefined({
4465
- ...propertyErrorsRef.current,
4466
- [getFullIdPath(propertyKey, namespace)]: removeUndefined(error_0, true)
4467
- }, true);
4468
- propertyErrorsRef.current = current;
4469
- formController.validate();
4470
- }, getUser, getData: getDataWithPath, doCollectionInference, propertyConfigs, extraIcon: extraView?.icon && /* @__PURE__ */ jsx(IconButton, { color: "primary", onClick: () => setCurrentView("extra_view"), children: extraView.icon }) })
4471
- ] }),
4472
- (!fullScreen || isNewCollection || !!error) && /* @__PURE__ */ jsxs("div", { className: "shrink-0 w-full p-4 sm:px-6 sm:py-4 border-t border-surface-200 dark:border-surface-900 flex items-center justify-between gap-4 bg-white dark:bg-surface-950", children: [
4473
- error && /* @__PURE__ */ jsx(ErrorView, { error }),
4474
- isNewCollection && includeTemplates && currentView === "import_data_mapping" && /* @__PURE__ */ jsx(Button, { variant: "text", type: "button", onClick: () => {
4475
- importConfig.setInUse(false);
4476
- return setCurrentView("welcome");
4477
- }, children: "Back" }),
4478
- isNewCollection && includeTemplates && currentView === "import_data_preview" && /* @__PURE__ */ jsx(Button, { variant: "text", type: "button", onClick: () => {
4479
- setCurrentView("import_data_mapping");
4480
- }, children: "Back" }),
4481
- isNewCollection && includeTemplates && currentView === "general" && /* @__PURE__ */ jsx(Button, { variant: "text", type: "button", onClick: () => setCurrentView("welcome"), children: "Back" }),
4482
- isNewCollection && currentView === "properties" && /* @__PURE__ */ jsxs(Button, { variant: "text", type: "button", color: "neutral", onClick: () => setCurrentView("general"), children: [
4483
- /* @__PURE__ */ jsx(ArrowLeftIcon, {}),
4484
- "Back"
4485
- ] }),
4486
- (!fullScreen || isNewCollection) && /* @__PURE__ */ jsx(Button, { variant: "text", color: "neutral", onClick: () => {
4487
- handleCancel();
4488
- }, children: "Cancel" }),
4489
- currentView === "welcome" && /* @__PURE__ */ jsx(Button, { variant: "text", onClick: () => onWelcomeScreenContinue(), children: "Continue from scratch" }),
4490
- isNewCollection && currentView === "import_data_mapping" && /* @__PURE__ */ jsx(Button, { variant: "filled", color: "primary", onClick: onImportMappingComplete, children: "Next" }),
4491
- isNewCollection && currentView === "import_data_preview" && /* @__PURE__ */ jsx(Button, { variant: "filled", color: "primary", onClick: () => {
4492
- setNextMode();
4493
- }, children: "Next" }),
4494
- isNewCollection && (currentView === "general" || currentView === "properties") && /* @__PURE__ */ jsxs(LoadingButton, { variant: "filled", color: "primary", type: "submit", loading: isSubmitting, disabled: isSubmitting || currentView === "general" && !validValues || configController?.readOnly, startIcon: currentView === "properties" ? /* @__PURE__ */ jsx(CheckIcon, {}) : void 0, children: [
4495
- currentView === "general" && "Next",
4496
- currentView === "properties" && "Create collection"
4497
- ] }),
4498
- !isNewCollection && !fullScreen && /* @__PURE__ */ jsx(LoadingButton, { variant: "filled", color: "primary", type: "submit", disabled: isSubmitting || configController?.readOnly, loading: isSubmitting, children: configController?.readOnly ? "Update collection (Read-only)" : "Update collection" })
4499
- ] })
4500
- ] })
4501
- ] }) }),
4502
- /* @__PURE__ */ jsx(ConfirmationDialog, { open: deleteRequested, onAccept: deleteCollection, onCancel: () => setDeleteRequested(false), title: /* @__PURE__ */ jsx(Fragment, { children: "Delete the stored config?" }), body: /* @__PURE__ */ jsxs(Fragment, { children: [
4503
- " This will ",
4504
- /* @__PURE__ */ jsx("b", { children: "not delete any data" }),
4505
- ", only the stored config, and reset to the code state."
4506
- ] }) })
4507
- ] });
4508
- }
4509
- function applyPropertyConfigs(collection, propertyConfigs) {
4510
- const {
4511
- properties,
4512
- ...rest
4513
- } = collection;
4514
- const propertiesResult = {};
4515
- if (properties) {
4516
- Object.keys(properties).forEach((key) => {
4517
- const prop = properties[key];
4518
- if (prop == null) return;
4519
- propertiesResult[key] = applyPropertiesConfig(prop, propertyConfigs);
4520
- });
4521
- }
4522
- return {
4523
- ...rest,
4524
- properties: propertiesResult
4525
- };
4526
- }
4527
- function applyPropertiesConfig(property, propertyConfigs) {
4528
- let internalProperty = property;
4529
- if (propertyConfigs && internalProperty && typeof internalProperty === "object" && internalProperty.propertyConfig) {
4530
- const propertyConfig = propertyConfigs[internalProperty.propertyConfig];
4531
- if (propertyConfig && isPropertyBuilder(propertyConfig.property)) {
4532
- internalProperty = propertyConfig.property;
4533
- } else {
4534
- if (propertyConfig) {
4535
- internalProperty = mergeDeep(propertyConfig.property, internalProperty);
4536
- }
4537
- if (!isPropertyBuilder(internalProperty) && internalProperty.type === "map" && internalProperty.properties) {
4538
- const properties = {};
4539
- Object.keys(internalProperty.properties).forEach((key) => {
4540
- properties[key] = applyPropertiesConfig(internalProperty.properties[key], propertyConfigs);
4541
- });
4542
- internalProperty = {
4543
- ...internalProperty,
4544
- properties
4545
- };
4546
- }
4547
- }
4548
- }
4549
- return internalProperty;
4550
- }
4551
- const validatePath = (value, isNewCollection, existingPaths, idValue) => {
4552
- let error;
4553
- if (!value) {
4554
- error = "You must specify a path in the database for this collection";
4555
- }
4556
- if (isNewCollection && existingPaths?.includes(value.trim().toLowerCase()) && !idValue) error = "There is already a collection with the specified path. If you want to have multiple collections referring to the same database path, make sure the have different ids";
4557
- const subpaths = removeInitialAndTrailingSlashes(value).split("/");
4558
- if (subpaths.length % 2 === 0) {
4559
- error = `Collection paths must have an odd number of segments: ${value}`;
4560
- }
4561
- return error;
4562
- };
4563
- const validateId = (value, isNewCollection, existingPaths, existingIds) => {
4564
- if (!value) return void 0;
4565
- let error;
4566
- if (isNewCollection && existingPaths?.includes(value.trim().toLowerCase())) error = "There is already a collection that uses this value as a path";
4567
- if (isNewCollection && existingIds?.includes(value.trim().toLowerCase())) error = "There is already a collection which uses this id";
4568
- return error;
4569
- };
4570
- export {
4571
- CollectionEditor,
4572
- CollectionEditorDialog
4573
- };
4574
- //# sourceMappingURL=CollectionEditorDialog-Bo86h-d-.js.map