@rebasepro/core 0.0.1-canary.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 (570) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +174 -0
  3. package/dist/app/AppBar.d.ts +12 -0
  4. package/dist/app/Drawer.d.ts +19 -0
  5. package/dist/app/Scaffold.d.ts +34 -0
  6. package/dist/app/index.d.ts +4 -0
  7. package/dist/app/useApp.d.ts +17 -0
  8. package/dist/components/AIIcon.d.ts +16 -0
  9. package/dist/components/AdminModeSyncer.d.ts +17 -0
  10. package/dist/components/ArrayContainer.d.ts +59 -0
  11. package/dist/components/CircularProgressCenter.d.ts +11 -0
  12. package/dist/components/ClearFilterSortButton.d.ts +5 -0
  13. package/dist/components/ConfirmationDialog.d.ts +9 -0
  14. package/dist/components/Debug/UIReferenceView.d.ts +1 -0
  15. package/dist/components/Debug/UIStyleGuide.d.ts +1 -0
  16. package/dist/components/DeleteEntityDialog.d.ts +12 -0
  17. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +37 -0
  18. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +27 -0
  19. package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +128 -0
  20. package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +25 -0
  21. package/dist/components/EntityCollectionTable/column_utils.d.ts +15 -0
  22. package/dist/components/EntityCollectionTable/fields/TableMultipleRelationField.d.ts +20 -0
  23. package/dist/components/EntityCollectionTable/fields/TableReferenceField.d.ts +21 -0
  24. package/dist/components/EntityCollectionTable/fields/TableRelationField.d.ts +21 -0
  25. package/dist/components/EntityCollectionTable/fields/TableRelationSelectorField.d.ts +20 -0
  26. package/dist/components/EntityCollectionTable/fields/TableStorageUpload.d.ts +32 -0
  27. package/dist/components/EntityCollectionTable/index.d.ts +6 -0
  28. package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +16 -0
  29. package/dist/components/EntityCollectionTable/internal/EntityTableCell.d.ts +32 -0
  30. package/dist/components/EntityCollectionTable/internal/EntityTableCellActions.d.ts +9 -0
  31. package/dist/components/EntityCollectionTable/internal/common.d.ts +4 -0
  32. package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +26 -0
  33. package/dist/components/EntityCollectionTable/internal/popup_field/useDraggable.d.ts +13 -0
  34. package/dist/components/EntityCollectionTable/internal/popup_field/useWindowSize.d.ts +6 -0
  35. package/dist/components/EntityCollectionView/Board.d.ts +2 -0
  36. package/dist/components/EntityCollectionView/BoardColumn.d.ts +42 -0
  37. package/dist/components/EntityCollectionView/BoardColumnTitle.d.ts +9 -0
  38. package/dist/components/EntityCollectionView/BoardSortableList.d.ts +14 -0
  39. package/dist/components/EntityCollectionView/EntityBoardCard.d.ts +26 -0
  40. package/dist/components/EntityCollectionView/EntityCard.d.ts +19 -0
  41. package/dist/components/EntityCollectionView/EntityCollectionBoardView.d.ts +20 -0
  42. package/dist/components/EntityCollectionView/EntityCollectionCardView.d.ts +31 -0
  43. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +54 -0
  44. package/dist/components/EntityCollectionView/EntityCollectionViewActions.d.ts +14 -0
  45. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +15 -0
  46. package/dist/components/EntityCollectionView/FiltersDialog.d.ts +14 -0
  47. package/dist/components/EntityCollectionView/ViewModeToggle.d.ts +44 -0
  48. package/dist/components/EntityCollectionView/board_types.d.ts +105 -0
  49. package/dist/components/EntityCollectionView/useBoardDataController.d.ts +60 -0
  50. package/dist/components/EntityCollectionView/useSelectionController.d.ts +2 -0
  51. package/dist/components/EntityCollectionView/utils.d.ts +3 -0
  52. package/dist/components/EntityJsonPreview.d.ts +3 -0
  53. package/dist/components/EntityPreview.d.ts +54 -0
  54. package/dist/components/EntityView.d.ts +11 -0
  55. package/dist/components/ErrorBoundary.d.ts +11 -0
  56. package/dist/components/ErrorTooltip.d.ts +2 -0
  57. package/dist/components/ErrorView.d.ts +21 -0
  58. package/dist/components/FieldCaption.d.ts +5 -0
  59. package/dist/components/HomePage/ContentHomePage.d.ts +11 -0
  60. package/dist/components/HomePage/FavouritesView.d.ts +3 -0
  61. package/dist/components/HomePage/HomePageDnD.d.ts +77 -0
  62. package/dist/components/HomePage/NavigationCard.d.ts +10 -0
  63. package/dist/components/HomePage/NavigationCardBinding.d.ts +18 -0
  64. package/dist/components/HomePage/NavigationGroup.d.ts +11 -0
  65. package/dist/components/HomePage/RenameGroupDialog.d.ts +9 -0
  66. package/dist/components/HomePage/SmallNavigationCard.d.ts +6 -0
  67. package/dist/components/HomePage/StudioHomePage.d.ts +9 -0
  68. package/dist/components/HomePage/index.d.ts +5 -0
  69. package/dist/components/NotFoundPage.d.ts +1 -0
  70. package/dist/components/PropertyCollectionView.d.ts +22 -0
  71. package/dist/components/PropertyConfigBadge.d.ts +6 -0
  72. package/dist/components/PropertyIdCopyTooltip.d.ts +8 -0
  73. package/dist/components/RebaseLogo.d.ts +7 -0
  74. package/dist/components/ReferenceTable/EntitySelectionTable.d.ts +58 -0
  75. package/dist/components/ReferenceWidget.d.ts +29 -0
  76. package/dist/components/RelationSelector.d.ts +32 -0
  77. package/dist/components/SearchIconsView.d.ts +5 -0
  78. package/dist/components/SelectableTable/SelectableTable.d.ts +89 -0
  79. package/dist/components/SelectableTable/SelectableTableContext.d.ts +4 -0
  80. package/dist/components/SelectableTable/filters/BooleanFilterField.d.ts +9 -0
  81. package/dist/components/SelectableTable/filters/DateTimeFilterField.d.ts +12 -0
  82. package/dist/components/SelectableTable/filters/ReferenceFilterField.d.ts +15 -0
  83. package/dist/components/SelectableTable/filters/RelationFilterField.d.ts +12 -0
  84. package/dist/components/SelectableTable/filters/StringNumberFilterField.d.ts +13 -0
  85. package/dist/components/UnsavedChangesDialog.d.ts +9 -0
  86. package/dist/components/UserDisplay.d.ts +7 -0
  87. package/dist/components/UserSettingsView.d.ts +1 -0
  88. package/dist/components/VirtualTable/VirtualTable.d.ts +11 -0
  89. package/dist/components/VirtualTable/VirtualTableCell.d.ts +20 -0
  90. package/dist/components/VirtualTable/VirtualTableHeader.d.ts +29 -0
  91. package/dist/components/VirtualTable/VirtualTableHeaderRow.d.ts +2 -0
  92. package/dist/components/VirtualTable/VirtualTableProps.d.ts +239 -0
  93. package/dist/components/VirtualTable/VirtualTableRow.d.ts +3 -0
  94. package/dist/components/VirtualTable/fields/VirtualTableDateField.d.ts +12 -0
  95. package/dist/components/VirtualTable/fields/VirtualTableInput.d.ts +9 -0
  96. package/dist/components/VirtualTable/fields/VirtualTableNumberInput.d.ts +8 -0
  97. package/dist/components/VirtualTable/fields/VirtualTableSelect.d.ts +15 -0
  98. package/dist/components/VirtualTable/fields/VirtualTableSwitch.d.ts +7 -0
  99. package/dist/components/VirtualTable/fields/VirtualTableUserSelect.d.ts +12 -0
  100. package/dist/components/VirtualTable/index.d.ts +3 -0
  101. package/dist/components/VirtualTable/types.d.ts +37 -0
  102. package/dist/components/admin/RoleChip.d.ts +4 -0
  103. package/dist/components/admin/RolesView.d.ts +4 -0
  104. package/dist/components/admin/UsersView.d.ts +4 -0
  105. package/dist/components/admin/index.d.ts +3 -0
  106. package/dist/components/common/default_entity_actions.d.ts +4 -0
  107. package/dist/components/common/index.d.ts +6 -0
  108. package/dist/components/common/table_height.d.ts +5 -0
  109. package/dist/components/common/types.d.ts +58 -0
  110. package/dist/components/common/useColumnsIds.d.ts +6 -0
  111. package/dist/components/common/useDataSourceTableController.d.ts +44 -0
  112. package/dist/components/common/useDebouncedCallback.d.ts +1 -0
  113. package/dist/components/common/useDebouncedData.d.ts +9 -0
  114. package/dist/components/common/useScrollRestoration.d.ts +14 -0
  115. package/dist/components/common/useTableSearchHelper.d.ts +11 -0
  116. package/dist/components/index.d.ts +35 -0
  117. package/dist/contexts/AdminModeController.d.ts +4 -0
  118. package/dist/contexts/AnalyticsContext.d.ts +3 -0
  119. package/dist/contexts/AuthControllerContext.d.ts +3 -0
  120. package/dist/contexts/BreacrumbsContext.d.ts +8 -0
  121. package/dist/contexts/CustomizationControllerContext.d.ts +3 -0
  122. package/dist/contexts/DataSourceContext.d.ts +3 -0
  123. package/dist/contexts/DialogsProvider.d.ts +4 -0
  124. package/dist/contexts/EffectiveRoleController.d.ts +4 -0
  125. package/dist/contexts/InternalUserManagementContext.d.ts +3 -0
  126. package/dist/contexts/ModeController.d.ts +4 -0
  127. package/dist/contexts/NavigationContext.d.ts +3 -0
  128. package/dist/contexts/SideDialogsControllerContext.d.ts +3 -0
  129. package/dist/contexts/SideEntityControllerContext.d.ts +3 -0
  130. package/dist/contexts/SnackbarProvider.d.ts +2 -0
  131. package/dist/contexts/StorageSourceContext.d.ts +3 -0
  132. package/dist/contexts/UserConfigurationPersistenceContext.d.ts +3 -0
  133. package/dist/contexts/index.d.ts +15 -0
  134. package/dist/core/DefaultAppBar.d.ts +29 -0
  135. package/dist/core/DefaultDrawer.d.ts +29 -0
  136. package/dist/core/DrawerNavigationGroup.d.ts +45 -0
  137. package/dist/core/DrawerNavigationItem.d.ts +10 -0
  138. package/dist/core/EntityEditView.d.ts +47 -0
  139. package/dist/core/EntityEditViewFormActions.d.ts +2 -0
  140. package/dist/core/EntitySidePanel.d.ts +10 -0
  141. package/dist/core/Rebase.d.ts +13 -0
  142. package/dist/core/RebaseRouter.d.ts +4 -0
  143. package/dist/core/RebaseRoutes.d.ts +17 -0
  144. package/dist/core/SideDialogs.d.ts +25 -0
  145. package/dist/core/field_configs.d.ts +6 -0
  146. package/dist/core/index.d.ts +9 -0
  147. package/dist/form/EntityForm.d.ts +7 -0
  148. package/dist/form/EntityFormActions.d.ts +2 -0
  149. package/dist/form/PropertyFieldBinding.d.ts +30 -0
  150. package/dist/form/components/ErrorFocus.d.ts +4 -0
  151. package/dist/form/components/FieldHelperText.d.ts +12 -0
  152. package/dist/form/components/FormEntry.d.ts +6 -0
  153. package/dist/form/components/FormLayout.d.ts +5 -0
  154. package/dist/form/components/LabelWithIcon.d.ts +14 -0
  155. package/dist/form/components/LabelWithIconAndTooltip.d.ts +15 -0
  156. package/dist/form/components/LocalChangesMenu.d.ts +11 -0
  157. package/dist/form/components/StorageItemPreview.d.ts +13 -0
  158. package/dist/form/components/StorageUploadProgress.d.ts +10 -0
  159. package/dist/form/components/index.d.ts +5 -0
  160. package/dist/form/field_bindings/ArrayCustomShapedFieldBinding.d.ts +9 -0
  161. package/dist/form/field_bindings/ArrayOfReferencesFieldBinding.d.ts +11 -0
  162. package/dist/form/field_bindings/BlockFieldBinding.d.ts +10 -0
  163. package/dist/form/field_bindings/DateTimeFieldBinding.d.ts +11 -0
  164. package/dist/form/field_bindings/KeyValueFieldBinding.d.ts +7 -0
  165. package/dist/form/field_bindings/MapFieldBinding.d.ts +9 -0
  166. package/dist/form/field_bindings/MarkdownEditorFieldBinding.d.ts +11 -0
  167. package/dist/form/field_bindings/MultiSelectFieldBinding.d.ts +9 -0
  168. package/dist/form/field_bindings/MultipleRelationFieldBinding.d.ts +9 -0
  169. package/dist/form/field_bindings/ReadOnlyFieldBinding.d.ts +10 -0
  170. package/dist/form/field_bindings/ReferenceAsStringFieldBinding.d.ts +9 -0
  171. package/dist/form/field_bindings/ReferenceFieldBinding.d.ts +9 -0
  172. package/dist/form/field_bindings/RelationFieldBinding.d.ts +2 -0
  173. package/dist/form/field_bindings/RepeatFieldBinding.d.ts +10 -0
  174. package/dist/form/field_bindings/SelectFieldBinding.d.ts +10 -0
  175. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +19 -0
  176. package/dist/form/field_bindings/SwitchFieldBinding.d.ts +9 -0
  177. package/dist/form/field_bindings/TextFieldBinding.d.ts +8 -0
  178. package/dist/form/field_bindings/UserSelectFieldBinding.d.ts +12 -0
  179. package/dist/form/index.d.ts +20 -0
  180. package/dist/form/useClearRestoreValue.d.ts +13 -0
  181. package/dist/form/validation.d.ts +26 -0
  182. package/dist/hooks/ApiConfigContext.d.ts +24 -0
  183. package/dist/hooks/data/delete.d.ts +33 -0
  184. package/dist/hooks/data/save.d.ts +37 -0
  185. package/dist/hooks/data/useCollectionFetch.d.ts +50 -0
  186. package/dist/hooks/data/useDataOrder.d.ts +12 -0
  187. package/dist/hooks/data/useDataSource.d.ts +6 -0
  188. package/dist/hooks/data/useEntityFetch.d.ts +29 -0
  189. package/dist/hooks/data/useRelationSelector.d.ts +45 -0
  190. package/dist/hooks/index.d.ts +41 -0
  191. package/dist/hooks/navigation/contexts/CMSUrlContext.d.ts +4 -0
  192. package/dist/hooks/navigation/contexts/CollectionRegistryContext.d.ts +4 -0
  193. package/dist/hooks/navigation/contexts/NavigationStateContext.d.ts +4 -0
  194. package/dist/hooks/navigation/contexts/index.d.ts +3 -0
  195. package/dist/hooks/navigation/useBuildCMSUrlController.d.ts +6 -0
  196. package/dist/hooks/navigation/useBuildCollectionRegistryController.d.ts +7 -0
  197. package/dist/hooks/navigation/useBuildNavigationStateController.d.ts +32 -0
  198. package/dist/hooks/navigation/useNavigationRegistry.d.ts +10 -0
  199. package/dist/hooks/navigation/useNavigationResolution.d.ts +5 -0
  200. package/dist/hooks/navigation/useNavigationURLs.d.ts +11 -0
  201. package/dist/hooks/navigation/useResolvedCollections.d.ts +26 -0
  202. package/dist/hooks/navigation/useResolvedViews.d.ts +28 -0
  203. package/dist/hooks/navigation/useTopLevelNavigation.d.ts +26 -0
  204. package/dist/hooks/navigation/utils.d.ts +12 -0
  205. package/dist/hooks/useAdminModeController.d.ts +19 -0
  206. package/dist/hooks/useAnalyticsController.d.ts +5 -0
  207. package/dist/hooks/useAuthController.d.ts +11 -0
  208. package/dist/hooks/useBackendStorageSource.d.ts +30 -0
  209. package/dist/hooks/useBreadcrumbsController.d.ts +42 -0
  210. package/dist/hooks/useBrowserTitleAndIcon.d.ts +6 -0
  211. package/dist/hooks/useBuildAdminModeController.d.ts +6 -0
  212. package/dist/hooks/useBuildEffectiveRoleController.d.ts +8 -0
  213. package/dist/hooks/useBuildLocalConfigurationPersistence.d.ts +2 -0
  214. package/dist/hooks/useBuildModeController.d.ts +6 -0
  215. package/dist/hooks/useBuildNavigationController.d.ts +16 -0
  216. package/dist/hooks/useClipboard.d.ts +57 -0
  217. package/dist/hooks/useCollapsedGroups.d.ts +12 -0
  218. package/dist/hooks/useCustomizationController.d.ts +11 -0
  219. package/dist/hooks/useDialogsController.d.ts +11 -0
  220. package/dist/hooks/useEffectiveRoleController.d.ts +7 -0
  221. package/dist/hooks/useEntitySelectionDialog.d.ts +18 -0
  222. package/dist/hooks/useInternalUserManagementController.d.ts +12 -0
  223. package/dist/hooks/useLargeLayout.d.ts +1 -0
  224. package/dist/hooks/useModeController.d.ts +19 -0
  225. package/dist/hooks/usePermissions.d.ts +11 -0
  226. package/dist/hooks/useRebaseContext.d.ts +11 -0
  227. package/dist/hooks/useResolvedNavigationFrom.d.ts +72 -0
  228. package/dist/hooks/useSideDialogsController.d.ts +18 -0
  229. package/dist/hooks/useSideEntityController.d.ts +12 -0
  230. package/dist/hooks/useSnackbarController.d.ts +20 -0
  231. package/dist/hooks/useStorageSource.d.ts +6 -0
  232. package/dist/hooks/useUnsavedChangesDialog.d.ts +12 -0
  233. package/dist/hooks/useUserConfigurationPersistence.d.ts +8 -0
  234. package/dist/hooks/useValidateAuthenticator.d.ts +21 -0
  235. package/dist/index.d.ts +15 -0
  236. package/dist/index.es.js +34745 -0
  237. package/dist/index.es.js.map +1 -0
  238. package/dist/index.umd.js +34751 -0
  239. package/dist/index.umd.js.map +1 -0
  240. package/dist/internal/common.d.ts +3 -0
  241. package/dist/internal/useBuildDataSource.d.ts +12 -0
  242. package/dist/internal/useBuildSideDialogsController.d.ts +2 -0
  243. package/dist/internal/useBuildSideEntityController.d.ts +4 -0
  244. package/dist/internal/useRestoreScroll.d.ts +6 -0
  245. package/dist/preview/PropertyPreview.d.ts +6 -0
  246. package/dist/preview/components/ArrayEnumPreview.d.ts +10 -0
  247. package/dist/preview/components/AsyncPreviewComponent.d.ts +11 -0
  248. package/dist/preview/components/BooleanPreview.d.ts +10 -0
  249. package/dist/preview/components/DatePreview.d.ts +17 -0
  250. package/dist/preview/components/EmptyValue.d.ts +6 -0
  251. package/dist/preview/components/EnumValuesChip.d.ts +13 -0
  252. package/dist/preview/components/ImagePreview.d.ts +16 -0
  253. package/dist/preview/components/ReferencePreview.d.ts +16 -0
  254. package/dist/preview/components/RelationPreview.d.ts +16 -0
  255. package/dist/preview/components/StorageThumbnail.d.ts +15 -0
  256. package/dist/preview/components/UrlComponentPreview.d.ts +13 -0
  257. package/dist/preview/components/UserPreview.d.ts +8 -0
  258. package/dist/preview/index.d.ts +24 -0
  259. package/dist/preview/property_previews/ArrayOfMapsPreview.d.ts +5 -0
  260. package/dist/preview/property_previews/ArrayOfReferencesPreview.d.ts +5 -0
  261. package/dist/preview/property_previews/ArrayOfRelationsPreview.d.ts +5 -0
  262. package/dist/preview/property_previews/ArrayOfStorageComponentsPreview.d.ts +5 -0
  263. package/dist/preview/property_previews/ArrayOfStringsPreview.d.ts +5 -0
  264. package/dist/preview/property_previews/ArrayOneOfPreview.d.ts +5 -0
  265. package/dist/preview/property_previews/ArrayPropertyEnumPreview.d.ts +5 -0
  266. package/dist/preview/property_previews/ArrayPropertyPreview.d.ts +5 -0
  267. package/dist/preview/property_previews/MapPropertyPreview.d.ts +8 -0
  268. package/dist/preview/property_previews/NumberPropertyPreview.d.ts +6 -0
  269. package/dist/preview/property_previews/SkeletonPropertyComponent.d.ts +13 -0
  270. package/dist/preview/property_previews/StringPropertyPreview.d.ts +6 -0
  271. package/dist/preview/util.d.ts +6 -0
  272. package/dist/routes/CustomCMSRoute.d.ts +4 -0
  273. package/dist/routes/RebaseRoute.d.ts +1 -0
  274. package/dist/routes/index.d.ts +2 -0
  275. package/dist/util/createFormexStub.d.ts +2 -0
  276. package/dist/util/entity_cache.d.ts +27 -0
  277. package/dist/util/enums.d.ts +5 -0
  278. package/dist/util/icon_list.d.ts +5 -0
  279. package/dist/util/icon_synonyms.d.ts +1853 -0
  280. package/dist/util/icons.d.ts +16 -0
  281. package/dist/util/index.d.ts +11 -0
  282. package/dist/util/previews.d.ts +3 -0
  283. package/dist/util/property_utils.d.ts +23 -0
  284. package/dist/util/useDebouncedCallback.d.ts +1 -0
  285. package/dist/util/useStorageUploadController.d.ts +36 -0
  286. package/dist/util/useTraceUpdate.d.ts +2 -0
  287. package/dist/vitePlugin.d.ts +16 -0
  288. package/package.json +165 -0
  289. package/src/app/AppBar.tsx +18 -0
  290. package/src/app/Drawer.tsx +30 -0
  291. package/src/app/Scaffold.tsx +238 -0
  292. package/src/app/index.ts +4 -0
  293. package/src/app/useApp.tsx +36 -0
  294. package/src/components/AIIcon.tsx +39 -0
  295. package/src/components/AdminModeSyncer.tsx +47 -0
  296. package/src/components/ArrayContainer.tsx +549 -0
  297. package/src/components/CircularProgressCenter.tsx +26 -0
  298. package/src/components/ClearFilterSortButton.tsx +44 -0
  299. package/src/components/ConfirmationDialog.tsx +46 -0
  300. package/src/components/Debug/UIReferenceView.tsx +710 -0
  301. package/src/components/Debug/UIStyleGuide.tsx +164 -0
  302. package/src/components/DeleteEntityDialog.tsx +181 -0
  303. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +225 -0
  304. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +383 -0
  305. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +180 -0
  306. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +561 -0
  307. package/src/components/EntityCollectionTable/column_utils.tsx +74 -0
  308. package/src/components/EntityCollectionTable/fields/TableMultipleRelationField.tsx +122 -0
  309. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +169 -0
  310. package/src/components/EntityCollectionTable/fields/TableRelationField.tsx +177 -0
  311. package/src/components/EntityCollectionTable/fields/TableRelationSelectorField.tsx +42 -0
  312. package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +315 -0
  313. package/src/components/EntityCollectionTable/index.tsx +12 -0
  314. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +90 -0
  315. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +311 -0
  316. package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +82 -0
  317. package/src/components/EntityCollectionTable/internal/common.tsx +72 -0
  318. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +425 -0
  319. package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +96 -0
  320. package/src/components/EntityCollectionTable/internal/popup_field/useWindowSize.tsx +20 -0
  321. package/src/components/EntityCollectionView/Board.tsx +324 -0
  322. package/src/components/EntityCollectionView/BoardColumn.tsx +158 -0
  323. package/src/components/EntityCollectionView/BoardColumnTitle.tsx +45 -0
  324. package/src/components/EntityCollectionView/BoardSortableList.tsx +172 -0
  325. package/src/components/EntityCollectionView/EntityBoardCard.tsx +200 -0
  326. package/src/components/EntityCollectionView/EntityCard.tsx +225 -0
  327. package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +746 -0
  328. package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +254 -0
  329. package/src/components/EntityCollectionView/EntityCollectionView.tsx +1220 -0
  330. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +142 -0
  331. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +131 -0
  332. package/src/components/EntityCollectionView/FiltersDialog.tsx +249 -0
  333. package/src/components/EntityCollectionView/ViewModeToggle.tsx +194 -0
  334. package/src/components/EntityCollectionView/board_types.ts +113 -0
  335. package/src/components/EntityCollectionView/useBoardDataController.tsx +490 -0
  336. package/src/components/EntityCollectionView/useSelectionController.tsx +43 -0
  337. package/src/components/EntityCollectionView/utils.ts +19 -0
  338. package/src/components/EntityJsonPreview.tsx +66 -0
  339. package/src/components/EntityPreview.tsx +367 -0
  340. package/src/components/EntityView.tsx +66 -0
  341. package/src/components/ErrorBoundary.tsx +40 -0
  342. package/src/components/ErrorTooltip.tsx +12 -0
  343. package/src/components/ErrorView.tsx +69 -0
  344. package/src/components/FieldCaption.tsx +14 -0
  345. package/src/components/HomePage/ContentHomePage.tsx +634 -0
  346. package/src/components/HomePage/FavouritesView.tsx +59 -0
  347. package/src/components/HomePage/HomePageDnD.tsx +702 -0
  348. package/src/components/HomePage/NavigationCard.tsx +80 -0
  349. package/src/components/HomePage/NavigationCardBinding.tsx +111 -0
  350. package/src/components/HomePage/NavigationGroup.tsx +154 -0
  351. package/src/components/HomePage/RenameGroupDialog.tsx +121 -0
  352. package/src/components/HomePage/SmallNavigationCard.tsx +45 -0
  353. package/src/components/HomePage/StudioHomePage.tsx +231 -0
  354. package/src/components/HomePage/index.tsx +6 -0
  355. package/src/components/NotFoundPage.tsx +25 -0
  356. package/src/components/PropertyCollectionView.tsx +333 -0
  357. package/src/components/PropertyConfigBadge.tsx +27 -0
  358. package/src/components/PropertyIdCopyTooltip.tsx +47 -0
  359. package/src/components/RebaseLogo.tsx +29 -0
  360. package/src/components/ReferenceTable/EntitySelectionTable.tsx +371 -0
  361. package/src/components/ReferenceWidget.tsx +152 -0
  362. package/src/components/RelationSelector.tsx +518 -0
  363. package/src/components/SearchIconsView.tsx +78 -0
  364. package/src/components/SelectableTable/SelectableTable.tsx +344 -0
  365. package/src/components/SelectableTable/SelectableTableContext.tsx +6 -0
  366. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +49 -0
  367. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +126 -0
  368. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +203 -0
  369. package/src/components/SelectableTable/filters/RelationFilterField.tsx +138 -0
  370. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +217 -0
  371. package/src/components/UnsavedChangesDialog.tsx +45 -0
  372. package/src/components/UserDisplay.tsx +55 -0
  373. package/src/components/UserSettingsView.tsx +220 -0
  374. package/src/components/VirtualTable/VirtualTable.performance.test.tsx +386 -0
  375. package/src/components/VirtualTable/VirtualTable.tsx +625 -0
  376. package/src/components/VirtualTable/VirtualTableCell.tsx +58 -0
  377. package/src/components/VirtualTable/VirtualTableHeader.tsx +275 -0
  378. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +249 -0
  379. package/src/components/VirtualTable/VirtualTableProps.tsx +298 -0
  380. package/src/components/VirtualTable/VirtualTableRow.tsx +52 -0
  381. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +39 -0
  382. package/src/components/VirtualTable/fields/VirtualTableInput.tsx +93 -0
  383. package/src/components/VirtualTable/fields/VirtualTableNumberInput.tsx +83 -0
  384. package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +133 -0
  385. package/src/components/VirtualTable/fields/VirtualTableSwitch.tsx +32 -0
  386. package/src/components/VirtualTable/fields/VirtualTableUserSelect.tsx +111 -0
  387. package/src/components/VirtualTable/index.tsx +3 -0
  388. package/src/components/VirtualTable/types.tsx +46 -0
  389. package/src/components/admin/RoleChip.tsx +23 -0
  390. package/src/components/admin/RolesView.tsx +408 -0
  391. package/src/components/admin/UsersView.tsx +353 -0
  392. package/src/components/admin/index.ts +3 -0
  393. package/src/components/common/default_entity_actions.tsx +144 -0
  394. package/src/components/common/index.ts +6 -0
  395. package/src/components/common/table_height.tsx +21 -0
  396. package/src/components/common/types.tsx +61 -0
  397. package/src/components/common/useColumnsIds.tsx +210 -0
  398. package/src/components/common/useDataSourceTableController.tsx +480 -0
  399. package/src/components/common/useDebouncedCallback.tsx +20 -0
  400. package/src/components/common/useDebouncedData.ts +49 -0
  401. package/src/components/common/useScrollRestoration.tsx +68 -0
  402. package/src/components/common/useTableSearchHelper.ts +75 -0
  403. package/src/components/index.tsx +49 -0
  404. package/src/contexts/AdminModeController.tsx +11 -0
  405. package/src/contexts/AnalyticsContext.tsx +4 -0
  406. package/src/contexts/AuthControllerContext.tsx +4 -0
  407. package/src/contexts/BreacrumbsContext.tsx +45 -0
  408. package/src/contexts/CustomizationControllerContext.tsx +4 -0
  409. package/src/contexts/DataSourceContext.tsx +4 -0
  410. package/src/contexts/DialogsProvider.tsx +53 -0
  411. package/src/contexts/EffectiveRoleController.tsx +11 -0
  412. package/src/contexts/InternalUserManagementContext.tsx +4 -0
  413. package/src/contexts/ModeController.tsx +11 -0
  414. package/src/contexts/NavigationContext.tsx +4 -0
  415. package/src/contexts/SideDialogsControllerContext.tsx +4 -0
  416. package/src/contexts/SideEntityControllerContext.tsx +4 -0
  417. package/src/contexts/SnackbarProvider.tsx +14 -0
  418. package/src/contexts/StorageSourceContext.tsx +4 -0
  419. package/src/contexts/UserConfigurationPersistenceContext.tsx +4 -0
  420. package/src/contexts/index.ts +15 -0
  421. package/src/core/DefaultAppBar.tsx +274 -0
  422. package/src/core/DefaultDrawer.tsx +267 -0
  423. package/src/core/DrawerNavigationGroup.tsx +117 -0
  424. package/src/core/DrawerNavigationItem.tsx +65 -0
  425. package/src/core/EntityEditView.tsx +590 -0
  426. package/src/core/EntityEditViewFormActions.tsx +343 -0
  427. package/src/core/EntitySidePanel.tsx +173 -0
  428. package/src/core/Rebase.tsx +229 -0
  429. package/src/core/RebaseRouter.tsx +17 -0
  430. package/src/core/RebaseRoutes.tsx +47 -0
  431. package/src/core/SideDialogs.tsx +200 -0
  432. package/src/core/field_configs.tsx +443 -0
  433. package/src/core/index.tsx +14 -0
  434. package/src/form/EntityForm.tsx +820 -0
  435. package/src/form/EntityFormActions.tsx +201 -0
  436. package/src/form/PropertyFieldBinding.tsx +348 -0
  437. package/src/form/components/ErrorFocus.tsx +44 -0
  438. package/src/form/components/FieldHelperText.tsx +45 -0
  439. package/src/form/components/FormEntry.tsx +22 -0
  440. package/src/form/components/FormLayout.tsx +16 -0
  441. package/src/form/components/LabelWithIcon.tsx +43 -0
  442. package/src/form/components/LabelWithIconAndTooltip.tsx +28 -0
  443. package/src/form/components/LocalChangesMenu.tsx +144 -0
  444. package/src/form/components/StorageItemPreview.tsx +79 -0
  445. package/src/form/components/StorageUploadProgress.tsx +105 -0
  446. package/src/form/components/index.tsx +5 -0
  447. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +105 -0
  448. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +163 -0
  449. package/src/form/field_bindings/BlockFieldBinding.tsx +268 -0
  450. package/src/form/field_bindings/DateTimeFieldBinding.tsx +70 -0
  451. package/src/form/field_bindings/KeyValueFieldBinding.tsx +567 -0
  452. package/src/form/field_bindings/MapFieldBinding.tsx +156 -0
  453. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +146 -0
  454. package/src/form/field_bindings/MultiSelectFieldBinding.tsx +120 -0
  455. package/src/form/field_bindings/MultipleRelationFieldBinding.tsx +151 -0
  456. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +64 -0
  457. package/src/form/field_bindings/ReferenceAsStringFieldBinding.tsx +135 -0
  458. package/src/form/field_bindings/ReferenceFieldBinding.tsx +134 -0
  459. package/src/form/field_bindings/RelationFieldBinding.tsx +176 -0
  460. package/src/form/field_bindings/RepeatFieldBinding.tsx +136 -0
  461. package/src/form/field_bindings/SelectFieldBinding.tsx +107 -0
  462. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +490 -0
  463. package/src/form/field_bindings/SwitchFieldBinding.tsx +64 -0
  464. package/src/form/field_bindings/TextFieldBinding.tsx +153 -0
  465. package/src/form/field_bindings/UserSelectFieldBinding.tsx +96 -0
  466. package/src/form/index.tsx +27 -0
  467. package/src/form/useClearRestoreValue.tsx +35 -0
  468. package/src/form/validation.ts +532 -0
  469. package/src/hooks/ApiConfigContext.tsx +40 -0
  470. package/src/hooks/data/delete.ts +77 -0
  471. package/src/hooks/data/save.ts +75 -0
  472. package/src/hooks/data/useCollectionFetch.tsx +148 -0
  473. package/src/hooks/data/useDataOrder.ts +26 -0
  474. package/src/hooks/data/useDataSource.tsx +22 -0
  475. package/src/hooks/data/useEntityFetch.tsx +121 -0
  476. package/src/hooks/data/useRelationSelector.tsx +205 -0
  477. package/src/hooks/index.tsx +51 -0
  478. package/src/hooks/navigation/contexts/CMSUrlContext.tsx +24 -0
  479. package/src/hooks/navigation/contexts/CollectionRegistryContext.tsx +19 -0
  480. package/src/hooks/navigation/contexts/NavigationStateContext.tsx +15 -0
  481. package/src/hooks/navigation/contexts/index.ts +14 -0
  482. package/src/hooks/navigation/useBuildCMSUrlController.tsx +68 -0
  483. package/src/hooks/navigation/useBuildCollectionRegistryController.tsx +150 -0
  484. package/src/hooks/navigation/useBuildNavigationStateController.tsx +135 -0
  485. package/src/hooks/navigation/useNavigationRegistry.ts +142 -0
  486. package/src/hooks/navigation/useNavigationResolution.ts +98 -0
  487. package/src/hooks/navigation/useNavigationURLs.ts +56 -0
  488. package/src/hooks/navigation/useResolvedCollections.ts +139 -0
  489. package/src/hooks/navigation/useResolvedViews.tsx +204 -0
  490. package/src/hooks/navigation/useTopLevelNavigation.ts +265 -0
  491. package/src/hooks/navigation/utils.ts +177 -0
  492. package/src/hooks/useAdminModeController.tsx +23 -0
  493. package/src/hooks/useAnalyticsController.tsx +8 -0
  494. package/src/hooks/useAuthController.tsx +14 -0
  495. package/src/hooks/useBackendStorageSource.ts +276 -0
  496. package/src/hooks/useBreadcrumbsController.tsx +49 -0
  497. package/src/hooks/useBrowserTitleAndIcon.tsx +25 -0
  498. package/src/hooks/useBuildAdminModeController.tsx +24 -0
  499. package/src/hooks/useBuildEffectiveRoleController.tsx +30 -0
  500. package/src/hooks/useBuildLocalConfigurationPersistence.tsx +65 -0
  501. package/src/hooks/useBuildModeController.tsx +71 -0
  502. package/src/hooks/useBuildNavigationController.tsx +341 -0
  503. package/src/hooks/useClipboard.tsx +158 -0
  504. package/src/hooks/useCollapsedGroups.ts +72 -0
  505. package/src/hooks/useCustomizationController.tsx +14 -0
  506. package/src/hooks/useDialogsController.tsx +14 -0
  507. package/src/hooks/useEffectiveRoleController.tsx +10 -0
  508. package/src/hooks/useEntitySelectionDialog.tsx +56 -0
  509. package/src/hooks/useInternalUserManagementController.tsx +17 -0
  510. package/src/hooks/useLargeLayout.tsx +65 -0
  511. package/src/hooks/useModeController.tsx +23 -0
  512. package/src/hooks/usePermissions.ts +43 -0
  513. package/src/hooks/useRebaseContext.tsx +86 -0
  514. package/src/hooks/useResolvedNavigationFrom.tsx +158 -0
  515. package/src/hooks/useSideDialogsController.tsx +21 -0
  516. package/src/hooks/useSideEntityController.tsx +15 -0
  517. package/src/hooks/useSnackbarController.tsx +52 -0
  518. package/src/hooks/useStorageSource.tsx +14 -0
  519. package/src/hooks/useUnsavedChangesDialog.tsx +62 -0
  520. package/src/hooks/useUserConfigurationPersistence.tsx +11 -0
  521. package/src/hooks/useValidateAuthenticator.tsx +115 -0
  522. package/src/index.ts +17 -0
  523. package/src/internal/common.tsx +5 -0
  524. package/src/internal/useBuildDataSource.ts +380 -0
  525. package/src/internal/useBuildSideDialogsController.tsx +135 -0
  526. package/src/internal/useBuildSideEntityController.tsx +309 -0
  527. package/src/internal/useRestoreScroll.tsx +60 -0
  528. package/src/preview/PropertyPreview.tsx +308 -0
  529. package/src/preview/components/ArrayEnumPreview.tsx +38 -0
  530. package/src/preview/components/AsyncPreviewComponent.tsx +47 -0
  531. package/src/preview/components/BooleanPreview.tsx +25 -0
  532. package/src/preview/components/DatePreview.tsx +94 -0
  533. package/src/preview/components/EmptyValue.tsx +10 -0
  534. package/src/preview/components/EnumValuesChip.tsx +39 -0
  535. package/src/preview/components/ImagePreview.tsx +111 -0
  536. package/src/preview/components/ReferencePreview.tsx +162 -0
  537. package/src/preview/components/RelationPreview.tsx +153 -0
  538. package/src/preview/components/StorageThumbnail.tsx +91 -0
  539. package/src/preview/components/UrlComponentPreview.tsx +113 -0
  540. package/src/preview/components/UserPreview.tsx +27 -0
  541. package/src/preview/index.ts +26 -0
  542. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +72 -0
  543. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +43 -0
  544. package/src/preview/property_previews/ArrayOfRelationsPreview.tsx +52 -0
  545. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +49 -0
  546. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +44 -0
  547. package/src/preview/property_previews/ArrayOneOfPreview.tsx +67 -0
  548. package/src/preview/property_previews/ArrayPropertyEnumPreview.tsx +34 -0
  549. package/src/preview/property_previews/ArrayPropertyPreview.tsx +69 -0
  550. package/src/preview/property_previews/MapPropertyPreview.tsx +145 -0
  551. package/src/preview/property_previews/NumberPropertyPreview.tsx +28 -0
  552. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +275 -0
  553. package/src/preview/property_previews/StringPropertyPreview.tsx +57 -0
  554. package/src/preview/util.ts +30 -0
  555. package/src/routes/CustomCMSRoute.tsx +21 -0
  556. package/src/routes/RebaseRoute.tsx +255 -0
  557. package/src/routes/index.ts +2 -0
  558. package/src/util/createFormexStub.tsx +66 -0
  559. package/src/util/entity_cache.ts +267 -0
  560. package/src/util/enums.ts +32 -0
  561. package/src/util/icon_list.ts +23 -0
  562. package/src/util/icon_synonyms.ts +1853 -0
  563. package/src/util/icons.tsx +87 -0
  564. package/src/util/index.ts +11 -0
  565. package/src/util/previews.ts +50 -0
  566. package/src/util/property_utils.tsx +152 -0
  567. package/src/util/useDebouncedCallback.ts +25 -0
  568. package/src/util/useStorageUploadController.tsx +342 -0
  569. package/src/util/useTraceUpdate.tsx +24 -0
  570. package/src/vitePlugin.ts +47 -0
@@ -0,0 +1,1220 @@
1
+ import React, { useCallback, useEffect, useMemo, useState } from "react";
2
+
3
+ import { deepEqual as equal } from "fast-equals"
4
+
5
+ import {
6
+ AdditionalFieldDelegate,
7
+ CollectionSize,
8
+ Entity,
9
+ EntityAction,
10
+ EntityCollection,
11
+ EntityReference,
12
+ EntityTableController,
13
+ FilterValues,
14
+ PartialEntityCollection,
15
+ Property,
16
+ SaveEntityProps,
17
+ ViewMode
18
+ } from "@rebasepro/types";
19
+ import {
20
+ EntityCollectionRowActions,
21
+ EntityCollectionTable,
22
+ useDataSourceTableController
23
+ } from "../EntityCollectionTable";
24
+ import { CollectionTableToolbar } from "../EntityCollectionTable/internal/CollectionTableToolbar";
25
+
26
+ import {
27
+ getSubcollections,
28
+ mergeDeep,
29
+ mergeEntityActions,
30
+ navigateToEntity,
31
+ resolveEntityAction
32
+ } from "@rebasepro/common";
33
+ import { getPropertyInPath } from "../../util";
34
+ import { ReferencePreview } from "../../preview";
35
+ import {
36
+ saveEntityWithCallbacks,
37
+ useAuthController,
38
+ useCustomizationController,
39
+ useDataSource,
40
+ useRebaseContext,
41
+ useLargeLayout,
42
+ useCollectionRegistryController,
43
+ useCMSUrlController,
44
+ useSideEntityController,
45
+ usePermissions
46
+ } from "../../hooks";
47
+ import { useBreadcrumbsController } from "../../hooks/useBreadcrumbsController";
48
+ import { useUserConfigurationPersistence } from "../../hooks/useUserConfigurationPersistence";
49
+ import { EntityCollectionViewActions } from "./EntityCollectionViewActions";
50
+ import { EntityCollectionCardView } from "./EntityCollectionCardView";
51
+ import { EntityCollectionBoardView } from "./EntityCollectionBoardView";
52
+ import { ViewModeToggle, KanbanPropertyOption } from "./ViewModeToggle";
53
+ import {
54
+ AddIcon,
55
+ Button,
56
+ cls,
57
+ focusedDisabled,
58
+ IconButton,
59
+ KeyboardTabIcon,
60
+ Markdown,
61
+ Popover,
62
+ SearchIcon,
63
+ Skeleton,
64
+ Tooltip,
65
+ Typography
66
+ } from "@rebasepro/ui";
67
+ import { setIn } from "@rebasepro/formex";
68
+ import { getSubcollectionColumnId } from "../EntityCollectionTable/internal/common";
69
+ import {
70
+ COLLECTION_GROUP_PARENT_ID,
71
+ copyEntityAction,
72
+ deleteEntityAction,
73
+ editEntityAction,
74
+ OnCellValueChange,
75
+ OnColumnResizeParams,
76
+ UniqueFieldValidator,
77
+ useColumnIds,
78
+ useTableSearchHelper
79
+ } from "../common";
80
+ import { PopupFormField } from "../EntityCollectionTable/internal/popup_field/PopupFormField";
81
+ import { GetPropertyForProps } from "../EntityCollectionTable/EntityCollectionTableProps";
82
+ import { DeleteEntityDialog } from "../DeleteEntityDialog";
83
+ import { useAnalyticsController } from "../../hooks/useAnalyticsController";
84
+ import { useSelectionController } from "./useSelectionController";
85
+ import { EntityCollectionViewStartActions } from "./EntityCollectionViewStartActions";
86
+ import { addRecentId, getRecentIds } from "./utils";
87
+ import { useScrollRestoration } from "../common/useScrollRestoration";
88
+
89
+ const DEFAULT_ENTITY_OPEN_MODE: "side_panel" | "full_screen" = "side_panel";
90
+
91
+ /**
92
+ * @group Components
93
+ */
94
+ export type EntityCollectionViewProps<M extends Record<string, any>> = {
95
+ /**
96
+ * Complete path where this collection is located.
97
+ * It defaults to the collection path if not provided.
98
+ */
99
+ path?: string;
100
+ /**
101
+ * Full path using navigation ids.
102
+ */
103
+ idPath?: string;
104
+ /**
105
+ * If this is a subcollection, specify the parent collection ids.
106
+ */
107
+ parentCollectionIds?: string[];
108
+ /**
109
+ * Whether this is a subcollection or not.
110
+ */
111
+ isSubCollection?: boolean;
112
+
113
+ className?: string;
114
+
115
+ /**
116
+ * If true, this view will store its filter and sorting status in the url params
117
+ */
118
+ updateUrl?: boolean;
119
+
120
+ } & EntityCollection<M>;
121
+
122
+ /**
123
+ * This component is in charge of binding a datasource path with an {@link EntityCollection}
124
+ * where it's configuration is defined. It includes an infinite scrolling table
125
+ * and a 'Add' new entities button,
126
+ *
127
+ * This component is the default one used for displaying entity collections
128
+ * and is in charge of generating all the specific actions and customization
129
+ * of the lower level {@link EntityCollectionTable}
130
+ *
131
+ * Please **note** that you only need to use this component if you are building
132
+ * a custom view. If you just need to create a default view you can do it
133
+ * exclusively with config options.
134
+ *
135
+ * If you need a lower level implementation with more granular options, you
136
+ * can use {@link EntityCollectionTable}.
137
+ *
138
+ * If you need a generic table that is not bound to the datasource or entities and
139
+ * properties at all, you can check {@link VirtualTable}
140
+ *
141
+ * @param path
142
+ * @param collection
143
+
144
+ * @group Components
145
+ */
146
+ export const EntityCollectionView = React.memo(
147
+ function EntityCollectionView<M extends Record<string, any>>({
148
+ path: pathProp,
149
+
150
+ parentCollectionIds,
151
+ isSubCollection,
152
+ className,
153
+ updateUrl,
154
+ ...collectionProp
155
+ }: EntityCollectionViewProps<M>
156
+ ) {
157
+
158
+ const context = useRebaseContext();
159
+ const collectionRegistry = useCollectionRegistryController();
160
+ const cmsUrlController = useCMSUrlController();
161
+ const breadcrumbs = useBreadcrumbsController();
162
+ const path = pathProp ?? collectionProp.dbPath;
163
+ const dataSource = useDataSource(collectionProp);
164
+ const sideEntityController = useSideEntityController();
165
+ const authController = useAuthController();
166
+ const userConfigPersistence = useUserConfigurationPersistence();
167
+ const analyticsController = useAnalyticsController();
168
+ const customizationController = useCustomizationController();
169
+ const { canCreate, canEdit, canDelete } = usePermissions();
170
+
171
+ const containerRef = React.useRef<HTMLDivElement>(null);
172
+
173
+ const scrollRestoration = useScrollRestoration();
174
+
175
+ const collection = useMemo(() => {
176
+ const userOverride = userConfigPersistence?.getCollectionConfig<M>(path);
177
+ return (userOverride ? mergeDeep(collectionProp, userOverride) : collectionProp) as EntityCollection<M>;
178
+ }, [collectionProp, path, userConfigPersistence?.getCollectionConfig]);
179
+
180
+ const openEntityMode = collection?.openEntityMode ?? DEFAULT_ENTITY_OPEN_MODE;
181
+
182
+ const collectionRef = React.useRef(collection);
183
+ useEffect(() => {
184
+ collectionRef.current = collection;
185
+ }, [collection]);
186
+
187
+ const canCreateEntities = canCreate(collection, path);
188
+ const [highlightedEntity, setHighlightedEntity] = useState<Entity<M> | undefined>(undefined);
189
+ const [deleteEntityClicked, setDeleteEntityClicked] = React.useState<Entity<M> | Entity<M>[] | undefined>(undefined);
190
+
191
+ const [lastDeleteTimestamp, setLastDeleteTimestamp] = React.useState<number>(0);
192
+
193
+ // Track recently deleted entities for optimistic Kanban count updates
194
+ const [deletedEntities, setDeletedEntities] = React.useState<Entity<M>[]>([]);
195
+
196
+ // number of entities in the collection (undefined = loading)
197
+ const [docsCount, setDocsCount] = useState<number | undefined>(undefined);
198
+
199
+ // Optimistic state for column order to prevent UI flickering during persistence
200
+ const [localPropertiesOrder, setLocalPropertiesOrder] = useState<string[] | undefined>(collection.propertiesOrder);
201
+
202
+ // Sync local state with collection's propertiesOrder when it changes from external sources
203
+ useEffect(() => {
204
+ setLocalPropertiesOrder(collection.propertiesOrder);
205
+ }, [collection.propertiesOrder]);
206
+
207
+ const unselectNavigatedEntity = useCallback(() => {
208
+ const currentSelection = highlightedEntity;
209
+ setTimeout(() => {
210
+ if (currentSelection === highlightedEntity)
211
+ setHighlightedEntity(undefined);
212
+ }, 2400);
213
+ }, [highlightedEntity]);
214
+
215
+ const checkInlineEditing = useCallback((entity?: Entity<any>): boolean => {
216
+ const collection = collectionRef.current;
217
+ if (!canEdit(collection, path, entity ?? null)) {
218
+ return false;
219
+ }
220
+ return collection.inlineEditing === undefined || collection.inlineEditing;
221
+ }, [canEdit, path]);
222
+
223
+ const selectionEnabled = collection.selectionEnabled === undefined || collection.selectionEnabled;
224
+ const hoverRow = !checkInlineEditing();
225
+
226
+ const [popOverOpen, setPopOverOpen] = useState(false);
227
+
228
+ // View mode priority: URL > saved user config > collection.defaultViewMode
229
+ const defaultViewMode = collection.defaultViewMode ?? "table";
230
+
231
+ // Parse view from URL
232
+ const getViewFromUrl = useCallback((): ViewMode | null => {
233
+ const params = new URLSearchParams(window.location.search);
234
+ const urlView = params.get("__view");
235
+ if (urlView && ["table", "kanban", "cards"].includes(urlView)) {
236
+ return urlView as ViewMode;
237
+ }
238
+ return null;
239
+ }, []);
240
+
241
+ // Get saved view from local persistence
242
+ const getSavedView = useCallback((): ViewMode | null => {
243
+ const saved = userConfigPersistence?.getCollectionConfig<M>(path)?.defaultViewMode;
244
+ return (saved as ViewMode) ?? null;
245
+ }, [userConfigPersistence, path]);
246
+
247
+ const [viewMode, setViewModeState] = useState<ViewMode>(() => {
248
+ // Priority: URL > saved config > collection default
249
+ const urlView = getViewFromUrl();
250
+ if (urlView) return urlView;
251
+ const savedView = getSavedView();
252
+ if (savedView) return savedView;
253
+ return defaultViewMode;
254
+ });
255
+
256
+ // Sync URL with current view on init (if view came from saved config)
257
+ useEffect(() => {
258
+ const urlView = getViewFromUrl();
259
+ if (!urlView && viewMode !== "table") {
260
+ // View came from saved config but URL doesn't have it - update URL without push
261
+ const url = new URL(window.location.href);
262
+ url.searchParams.set("__view", viewMode);
263
+ window.history.replaceState({}, "", url.toString());
264
+ }
265
+ }, []); // Only on mount
266
+
267
+ // Update URL when view mode changes (user action)
268
+ const setViewMode = useCallback((newMode: ViewMode) => {
269
+ setViewModeState(newMode);
270
+
271
+ // Update URL with __view param
272
+ const url = new URL(window.location.href);
273
+ if (newMode === "table") {
274
+ url.searchParams.delete("__view");
275
+ } else {
276
+ url.searchParams.set("__view", newMode);
277
+ }
278
+ window.history.pushState({}, "", url.toString());
279
+ }, []);
280
+
281
+ // Listen for browser back/forward
282
+ useEffect(() => {
283
+ const handlePopState = () => {
284
+ const urlView = getViewFromUrl();
285
+ if (urlView) {
286
+ // URL has explicit view - use it
287
+ setViewModeState(urlView);
288
+ } else {
289
+ // No URL param - fallback to saved config or collection default
290
+ const savedView = getSavedView();
291
+ setViewModeState(savedView ?? defaultViewMode);
292
+ }
293
+ };
294
+
295
+ window.addEventListener("popstate", handlePopState);
296
+ return () => window.removeEventListener("popstate", handlePopState);
297
+ }, [getViewFromUrl, getSavedView, defaultViewMode]);
298
+
299
+ // Card view size state - controls the grid column count
300
+ const [cardSize, setCardSize] = useState<CollectionSize>(collection.defaultSize ?? "m");
301
+
302
+ // Table view size state - controls row height
303
+ const [tableSize, setTableSize] = useState<CollectionSize>(collection.defaultSize ?? "m");
304
+
305
+ const selectionController = useSelectionController<M>();
306
+ const usedSelectionController = collection.selectionController ?? selectionController;
307
+ const {
308
+ selectedEntities,
309
+ setSelectedEntities
310
+ } = usedSelectionController;
311
+
312
+ const tableController = useDataSourceTableController<M>({
313
+ path,
314
+ collection,
315
+ lastDeleteTimestamp,
316
+ scrollRestoration,
317
+ updateUrl
318
+ });
319
+
320
+ const tableKey = React.useRef<string>(Math.random().toString(36));
321
+ const popupCell = tableController.popupCell;
322
+
323
+ const onPopupClose = useCallback(() => {
324
+ tableController.setPopupCell?.(undefined);
325
+ }, [tableController.setPopupCell]);
326
+
327
+ const onEntityClick = useCallback((clickedEntity: Entity<M>) => {
328
+ const collection = collectionRef.current;
329
+ setHighlightedEntity(clickedEntity);
330
+ analyticsController.onAnalyticsEvent?.("edit_entity_clicked", {
331
+ path: clickedEntity.path,
332
+ entityId: clickedEntity.id
333
+ });
334
+
335
+ if (collection) {
336
+ addRecentId(collection.slug, clickedEntity.id);
337
+ }
338
+
339
+ const entityPath = collection?.collectionGroup ? clickedEntity.path : (path ?? clickedEntity.path);
340
+ navigateToEntity({
341
+ navigation: cmsUrlController,
342
+ path: entityPath,
343
+ sideEntityController,
344
+ openEntityMode,
345
+ collection,
346
+ entityId: clickedEntity.id
347
+ });
348
+
349
+ }, [unselectNavigatedEntity, sideEntityController]);
350
+
351
+ const onNewClick = useCallback(() => {
352
+ const collection = collectionRef.current;
353
+ analyticsController.onAnalyticsEvent?.("new_entity_click", {
354
+ path: path
355
+ });
356
+ navigateToEntity({
357
+ openEntityMode,
358
+ collection,
359
+ entityId: undefined,
360
+ path: path,
361
+ sideEntityController,
362
+ navigation: cmsUrlController,
363
+ onClose: unselectNavigatedEntity
364
+ })
365
+ }, [path, sideEntityController]);
366
+
367
+ const onMultipleDeleteClick = () => {
368
+ analyticsController.onAnalyticsEvent?.("multiple_delete_dialog_open", {
369
+ path: path
370
+ });
371
+ setDeleteEntityClicked(selectedEntities);
372
+ };
373
+
374
+ const internalOnEntityDelete = (_path: string, entity: Entity<M>) => {
375
+ analyticsController.onAnalyticsEvent?.("single_entity_deleted", {
376
+ path: path
377
+ });
378
+ setSelectedEntities((selectedEntities) => selectedEntities.filter((e) => e.id !== entity.id));
379
+ setDeletedEntities(prev => [...prev, entity]);
380
+ setLastDeleteTimestamp(Date.now());
381
+ };
382
+
383
+ const internalOnMultipleEntitiesDelete = (_path: string, entities: Entity<M>[]) => {
384
+ analyticsController.onAnalyticsEvent?.("multiple_entities_deleted", {
385
+ path: path
386
+ });
387
+ setSelectedEntities([]);
388
+ setDeleteEntityClicked(undefined);
389
+ setDeletedEntities(prev => [...prev, ...entities]);
390
+ setLastDeleteTimestamp(Date.now());
391
+ };
392
+
393
+ let AddColumnComponent: React.ComponentType<{
394
+ path: string,
395
+ parentCollectionIds: string[],
396
+ collection: EntityCollection;
397
+ tableController: EntityTableController;
398
+ }> | undefined
399
+
400
+ // we are only using the first plugin that implements this
401
+ if (customizationController?.plugins) {
402
+ AddColumnComponent = customizationController.plugins.find(plugin => plugin.collectionView?.AddColumnComponent)?.collectionView?.AddColumnComponent;
403
+ }
404
+
405
+ const onCollectionModifiedForUser = useCallback((path: string, partialCollection: PartialEntityCollection<M>) => {
406
+ if (userConfigPersistence) {
407
+ const currentStoredConfig = userConfigPersistence.getCollectionConfig(path);
408
+ const updatedConfig = mergeDeep(currentStoredConfig, partialCollection);
409
+ userConfigPersistence.onCollectionModified(path, updatedConfig);
410
+ }
411
+ }, [userConfigPersistence]);
412
+
413
+ const onColumnResize = useCallback(({
414
+ width,
415
+ key
416
+ }: OnColumnResizeParams) => {
417
+
418
+ const collection = collectionRef.current;
419
+ // Only for property columns
420
+ if (!getPropertyInPath(collection.properties, key)) return;
421
+ const localCollection = buildPropertyWidthOverwrite(key, width);
422
+ onCollectionModifiedForUser(path, localCollection);
423
+ }, [onCollectionModifiedForUser, path]);
424
+
425
+ const onTableSizeChanged = useCallback((size: CollectionSize) => {
426
+ setTableSize(size);
427
+ if (userConfigPersistence)
428
+ onCollectionModifiedForUser(path, { defaultSize: size })
429
+ }, [onCollectionModifiedForUser, path, userConfigPersistence]);
430
+
431
+ // View mode change: update URL + save to local persistence
432
+ const onViewModeChange = useCallback((mode: ViewMode) => {
433
+ analyticsController.onAnalyticsEvent?.("view_mode_changed", {
434
+ path: path,
435
+ from: viewMode,
436
+ to: mode
437
+ });
438
+ setViewMode(mode);
439
+ // Save to local persistence for next visit
440
+ if (userConfigPersistence) {
441
+ onCollectionModifiedForUser(path, { defaultViewMode: mode } as PartialEntityCollection<M>);
442
+ }
443
+ }, [setViewMode, userConfigPersistence, onCollectionModifiedForUser, path, analyticsController, viewMode]);
444
+
445
+ const createEnabled = canCreate(collection, path);
446
+
447
+ const uniqueFieldValidator: UniqueFieldValidator = useCallback(
448
+ ({
449
+ name,
450
+ value,
451
+ property,
452
+ entityId
453
+ }) => dataSource.checkUniqueField(path, name, value, entityId, collection),
454
+ [path]);
455
+
456
+ const onValueChange: OnCellValueChange<any, any> = ({
457
+ value,
458
+ propertyKey,
459
+ onValueUpdated,
460
+ setError,
461
+ data: entity,
462
+ }) => {
463
+
464
+ const updatedValues = setIn({ ...entity.values }, propertyKey, value);
465
+
466
+ const saveProps: SaveEntityProps = {
467
+ path: entity.path ?? path,
468
+ entityId: entity.id,
469
+ values: updatedValues,
470
+ previousValues: entity.values,
471
+ collection,
472
+ status: "existing"
473
+ };
474
+
475
+ return saveEntityWithCallbacks({
476
+ ...saveProps,
477
+ collection,
478
+ dataSource,
479
+ context,
480
+ afterSave: () => {
481
+ setError(undefined);
482
+ onValueUpdated();
483
+ },
484
+ afterSaveError: (e: Error) => {
485
+ console.error("Save failure");
486
+ console.error(e);
487
+ setError(e);
488
+ }
489
+ }).then();
490
+
491
+ };
492
+
493
+ // In v4, collections are already resolved, so we use collection directly
494
+ const resolvedCollection = collection;
495
+
496
+ // Check if Kanban view is available (needs kanban.columnProperty with enum)
497
+ const kanbanEnabled = useMemo(() => {
498
+ if (!collection.kanban?.columnProperty) return false;
499
+ const property = getPropertyInPath(resolvedCollection.properties, collection.kanban.columnProperty);
500
+ if (!property || (property as any).type !== "string") return false;
501
+ return Boolean((property as any).enum);
502
+ }, [collection.kanban?.columnProperty, resolvedCollection.properties]);
503
+
504
+ // Compute the effective enabled views:
505
+ // - Start from collection.enabledViews (defaults to all three)
506
+ // - Filter out kanban if no enum properties exist
507
+ const hasEnumProperty = useMemo(() => {
508
+ return Object.values(resolvedCollection.properties).some((p: any) => p.type === "string" && p.enum);
509
+ }, [resolvedCollection.properties]);
510
+
511
+ const enabledViews: ViewMode[] = useMemo(() => {
512
+ const configured = collection.enabledViews ?? ["table", "cards", "kanban"];
513
+ if (!hasEnumProperty) {
514
+ return configured.filter(v => v !== "kanban");
515
+ }
516
+ return configured;
517
+ }, [collection.enabledViews, hasEnumProperty]);
518
+
519
+ // Compute available enum properties for kanban column selection
520
+ const kanbanPropertyOptions: KanbanPropertyOption[] = useMemo(() => {
521
+ const options: KanbanPropertyOption[] = [];
522
+ const properties = resolvedCollection.properties;
523
+
524
+ for (const [key, property] of Object.entries(properties)) {
525
+ const prop = property as any;
526
+ if (prop && prop.type === "string" && prop.enum) {
527
+ options.push({
528
+ key,
529
+ label: prop.name || key
530
+ });
531
+ }
532
+ }
533
+
534
+ return options;
535
+ }, [resolvedCollection.properties]);
536
+
537
+ // Get saved kanban property from user config
538
+ const getSavedKanbanProperty = useCallback((): string | undefined => {
539
+ const saved = userConfigPersistence?.getCollectionConfig<M>(path);
540
+ return (saved as any)?.kanbanColumnProperty;
541
+ }, [userConfigPersistence, path]);
542
+
543
+ // Selected kanban property state - priority: saved config > collection default > first available
544
+ const [selectedKanbanProperty, setSelectedKanbanProperty] = useState<string>(() => {
545
+ const saved = getSavedKanbanProperty();
546
+ if (saved && kanbanPropertyOptions.some(o => o.key === saved)) return saved;
547
+ if (collection.kanban?.columnProperty) return collection.kanban.columnProperty;
548
+ return kanbanPropertyOptions[0]?.key ?? "";
549
+ });
550
+
551
+ // Update selected property if options change and current selection is no longer valid
552
+ useEffect(() => {
553
+ if (kanbanPropertyOptions.length > 0 && !kanbanPropertyOptions.some(o => o.key === selectedKanbanProperty)) {
554
+ const saved = getSavedKanbanProperty();
555
+ if (saved && kanbanPropertyOptions.some(o => o.key === saved)) {
556
+ setSelectedKanbanProperty(saved);
557
+ } else if (collection.kanban?.columnProperty && kanbanPropertyOptions.some(o => o.key === collection.kanban?.columnProperty)) {
558
+ setSelectedKanbanProperty(collection.kanban.columnProperty);
559
+ } else {
560
+ setSelectedKanbanProperty(kanbanPropertyOptions[0]?.key ?? "");
561
+ }
562
+ }
563
+ }, [kanbanPropertyOptions, selectedKanbanProperty, getSavedKanbanProperty, collection.kanban?.columnProperty]);
564
+
565
+ // Handle kanban property change
566
+ const onKanbanPropertyChange = useCallback((property: string) => {
567
+ analyticsController.onAnalyticsEvent?.("kanban_property_changed", {
568
+ path: path,
569
+ property
570
+ });
571
+ setSelectedKanbanProperty(property);
572
+ // Save to local persistence
573
+ if (userConfigPersistence) {
574
+ onCollectionModifiedForUser(path, { kanbanColumnProperty: property } as any);
575
+ }
576
+ }, [userConfigPersistence, onCollectionModifiedForUser, path, analyticsController]);
577
+
578
+ const getPropertyFor = useCallback(({
579
+ propertyKey,
580
+ entity
581
+ }: GetPropertyForProps<M>) => {
582
+ let property: Property | undefined = getPropertyInPath(collection.properties, propertyKey);
583
+
584
+ // we might not find the property in the collection if combining property builders and map spread
585
+ if (!property) {
586
+ // these 2 properties are coming from the resolved collection with default values
587
+ property = getPropertyInPath(resolvedCollection.properties, propertyKey);
588
+ }
589
+
590
+ // In v4, properties are already resolved, so we return them directly
591
+ return property ?? null;
592
+ }, [collection.properties, resolvedCollection.properties]);
593
+
594
+ // Use a collection with local propertiesOrder for optimistic UI updates
595
+ const collectionWithLocalOrder = useMemo(() => {
596
+ if (localPropertiesOrder && localPropertiesOrder !== resolvedCollection.propertiesOrder) {
597
+ return {
598
+ ...resolvedCollection,
599
+ propertiesOrder: localPropertiesOrder
600
+ };
601
+ }
602
+ return resolvedCollection;
603
+ }, [resolvedCollection, localPropertiesOrder]);
604
+
605
+ const displayedColumnIds = useColumnIds(collectionWithLocalOrder, true);
606
+
607
+ const additionalFields = useMemo(() => {
608
+ // v4: use getSubcollections helper to access subcollections
609
+ const subcollectionsList = getSubcollections(collection);
610
+ const subcollectionColumns: AdditionalFieldDelegate<M, any>[] = subcollectionsList.map((subcollection: EntityCollection) => {
611
+ return {
612
+ key: getSubcollectionColumnId(subcollection),
613
+ name: subcollection.name,
614
+ width: 200,
615
+ dependencies: [],
616
+ Builder: ({ entity }: { entity: Entity }) => (
617
+ <Button
618
+ className={"max-w-full truncate justify-start"}
619
+ startIcon={<KeyboardTabIcon size={"small"} />}
620
+ onClick={(event: React.MouseEvent) => {
621
+ event.stopPropagation();
622
+ navigateToEntity({
623
+ openEntityMode,
624
+ collection,
625
+ entityId: entity.id,
626
+ selectedTab: subcollection.slug ?? subcollection.dbPath,
627
+ path: path,
628
+ navigation: cmsUrlController,
629
+ sideEntityController
630
+ })
631
+ }}>
632
+ {subcollection.name}
633
+ </Button>
634
+ )
635
+ };
636
+ }) ?? [];
637
+
638
+ const collectionGroupParentCollections: AdditionalFieldDelegate<M, any>[] = collection.collectionGroup
639
+ ? [{
640
+ key: COLLECTION_GROUP_PARENT_ID,
641
+ name: "Parent entities",
642
+ width: 260,
643
+ dependencies: [],
644
+ Builder: ({ entity }) => {
645
+ const collectionsWithPath = collectionRegistry.getParentReferencesFromPath(entity.path);
646
+ return (
647
+ <div className={"flex flex-col gap-2 w-full"}>
648
+ {collectionsWithPath.map((reference) => {
649
+ return (
650
+ <ReferencePreview
651
+ key={reference.path + "/" + reference.id}
652
+ reference={reference}
653
+ size={"small"} />
654
+ );
655
+ })}
656
+ </div>
657
+ );
658
+ }
659
+ }]
660
+ : [];
661
+
662
+ return [
663
+ ...(collection.additionalFields ?? []),
664
+ ...subcollectionColumns,
665
+ ...collectionGroupParentCollections
666
+ ];
667
+ }, [collection, path, sideEntityController]);
668
+
669
+ const updateLastDeleteTimestamp = useCallback(() => {
670
+ setLastDeleteTimestamp(Date.now());
671
+ }, []);
672
+
673
+ const largeLayout = useLargeLayout();
674
+
675
+ const getActionsForEntity = ({
676
+ entity,
677
+ customEntityActions
678
+ }: {
679
+ entity?: Entity<M>,
680
+ customEntityActions?: EntityAction[]
681
+ }): EntityAction[] => {
682
+ const deleteEnabled = entity ? canDelete(collection, path, entity) : true;
683
+ const actions: EntityAction[] = [editEntityAction];
684
+ if (createEnabled)
685
+ actions.push(copyEntityAction);
686
+ if (deleteEnabled)
687
+ actions.push(deleteEntityAction);
688
+ if (customEntityActions)
689
+ return mergeEntityActions(actions, customEntityActions);
690
+ return actions;
691
+ };
692
+
693
+ const getIdColumnWidth = () => {
694
+ const entityActions = getActionsForEntity({});
695
+ const collapsedActions = entityActions.filter(a => a.collapsed !== false);
696
+ const uncollapsedActions = entityActions.filter(a => a.collapsed === false);
697
+ const actionsWidth = uncollapsedActions.length * (largeLayout ? 40 : 30);
698
+ return (largeLayout ? (80 + actionsWidth) : (70 + actionsWidth)) + (collapsedActions.length > 0 ? (largeLayout ? 40 : 30) : 0);
699
+ };
700
+
701
+ const tableRowActionsBuilder = useCallback(({
702
+ entity,
703
+ size,
704
+ width,
705
+ frozen
706
+ }: {
707
+ entity: Entity<any>,
708
+ size: CollectionSize,
709
+ width: number,
710
+ frozen?: boolean
711
+ }) => {
712
+
713
+ const isSelected = Boolean(usedSelectionController.selectedEntities.find(e => e.id == entity.id && e.path == entity.path));
714
+ const customEntityActions = (collection.entityActions ?? [])
715
+ .map(action => resolveEntityAction(action, customizationController.entityActions))
716
+ .filter(Boolean) as EntityAction[];
717
+
718
+ const actions = getActionsForEntity({
719
+ entity,
720
+ customEntityActions
721
+ });
722
+
723
+ return (
724
+ <EntityCollectionRowActions
725
+ entity={entity}
726
+ width={width}
727
+ frozen={frozen}
728
+ isSelected={isSelected}
729
+ selectionEnabled={selectionEnabled}
730
+ size={size}
731
+ highlightEntity={setHighlightedEntity}
732
+ unhighlightEntity={unselectNavigatedEntity}
733
+ collection={collection}
734
+ path={path}
735
+ actions={actions}
736
+ hideId={collection?.hideIdFromCollection}
737
+ onCollectionChange={updateLastDeleteTimestamp}
738
+ selectionController={usedSelectionController}
739
+ openEntityMode={openEntityMode}
740
+ />
741
+ );
742
+
743
+ }, [updateLastDeleteTimestamp, usedSelectionController]);
744
+
745
+ // Update breadcrumb count when count changes (only if loaded)
746
+ useEffect(() => {
747
+ if (docsCount !== undefined) {
748
+ breadcrumbs.updateCount(path, docsCount);
749
+ }
750
+ }, [docsCount, path, breadcrumbs.updateCount]);
751
+
752
+ // EntitiesCount fetches count and updates breadcrumb - no visual rendering needed here
753
+ const countFetcher = <EntitiesCount
754
+ path={path}
755
+ collection={collection}
756
+ filter={tableController.filterValues}
757
+ sortBy={tableController.sortBy}
758
+ onCountChange={setDocsCount}
759
+ />;
760
+
761
+
762
+ const buildAdditionalHeaderWidget = useCallback(({
763
+ property,
764
+ propertyKey,
765
+ onHover
766
+ }: {
767
+ property: Property,
768
+ propertyKey: string,
769
+ onHover: boolean
770
+ }) => {
771
+ const collection = collectionRef.current;
772
+ if (!customizationController.plugins)
773
+ return null;
774
+ return <>
775
+ {customizationController.plugins.filter(plugin => plugin.collectionView?.HeaderAction)
776
+ .map((plugin, i) => {
777
+ const HeaderAction = plugin.collectionView!.HeaderAction!;
778
+ return <HeaderAction
779
+ onHover={onHover}
780
+ key={`plugin_header_action_${i}`}
781
+ propertyKey={propertyKey}
782
+ property={property}
783
+ path={path}
784
+ collection={collection}
785
+ tableController={tableController}
786
+ parentCollectionIds={parentCollectionIds ?? []} />;
787
+ })}
788
+ </>;
789
+ }, [customizationController.plugins, path, parentCollectionIds]);
790
+
791
+ const addColumnComponentInternal = AddColumnComponent
792
+ ? function () {
793
+ if (typeof AddColumnComponent === "function")
794
+ return <AddColumnComponent path={path}
795
+ parentCollectionIds={parentCollectionIds ?? []}
796
+ collection={collection}
797
+ tableController={tableController} />;
798
+ return null;
799
+ }
800
+ : undefined;
801
+
802
+ const {
803
+ textSearchLoading,
804
+ textSearchInitialised,
805
+ onTextSearchClick
806
+ } = useTableSearchHelper({
807
+ collection,
808
+ path: path,
809
+ parentCollectionIds
810
+ });
811
+
812
+ // Popover open state managed at parent level to prevent closing when view changes
813
+ const [viewModePopoverOpen, setViewModePopoverOpen] = useState(false);
814
+
815
+ // Create ViewModeToggle once to prevent remounting when view changes
816
+ const viewModeToggleElement = (
817
+ <ViewModeToggle
818
+ viewMode={viewMode}
819
+ onViewModeChange={onViewModeChange}
820
+ enabledViews={enabledViews}
821
+ size={viewMode === "table" ? tableSize : viewMode === "cards" ? cardSize : undefined}
822
+ onSizeChanged={viewMode === "table" ? onTableSizeChanged : viewMode === "cards" ? setCardSize : undefined}
823
+ open={viewModePopoverOpen}
824
+ onOpenChange={setViewModePopoverOpen}
825
+ kanbanPropertyOptions={kanbanPropertyOptions}
826
+ selectedKanbanProperty={selectedKanbanProperty}
827
+ onKanbanPropertyChange={onKanbanPropertyChange}
828
+ />
829
+ );
830
+
831
+ // Compute plugin-provided error view for collection loading errors
832
+ const pluginErrorView = useMemo(() => {
833
+ const error = tableController.dataLoadingError;
834
+ if (!error || !customizationController.plugins) return null;
835
+ for (const plugin of customizationController.plugins) {
836
+ if (plugin.collectionView?.CollectionError) {
837
+ const CollectionError = plugin.collectionView.CollectionError;
838
+ return <CollectionError
839
+ path={path}
840
+ collection={collection}
841
+ parentCollectionIds={parentCollectionIds}
842
+ error={error}
843
+ />;
844
+ }
845
+ }
846
+ return null;
847
+ }, [tableController.dataLoadingError, customizationController.plugins, path, collection, parentCollectionIds]);
848
+
849
+ return (
850
+ <div className={cls("overflow-hidden h-full w-full rounded-md flex flex-col", className)}
851
+ ref={containerRef}>
852
+
853
+ {/* Unified toolbar - rendered once, outside view conditionals */}
854
+ {countFetcher}
855
+ <CollectionTableToolbar
856
+ loading={tableController.dataLoading}
857
+ onTextSearch={textSearchInitialised ? tableController.setSearchString : undefined}
858
+ onTextSearchClick={!textSearchInitialised ? onTextSearchClick : undefined}
859
+ textSearchLoading={textSearchLoading}
860
+ viewModeToggle={viewModeToggleElement}
861
+ actionsStart={<EntityCollectionViewStartActions
862
+ parentCollectionIds={parentCollectionIds ?? []}
863
+ collection={collection}
864
+ tableController={tableController}
865
+ path={path}
866
+ relativePath={collection.dbPath}
867
+ selectionController={usedSelectionController}
868
+ collectionEntitiesCount={docsCount}
869
+ resolvedProperties={resolvedCollection.properties} />}
870
+ actions={<EntityCollectionViewActions
871
+ parentCollectionIds={parentCollectionIds ?? []}
872
+ collection={collection}
873
+ tableController={tableController}
874
+ onMultipleDeleteClick={onMultipleDeleteClick}
875
+ onNewClick={onNewClick}
876
+ path={path}
877
+ relativePath={collection.dbPath}
878
+ selectionController={usedSelectionController}
879
+ selectionEnabled={selectionEnabled}
880
+ collectionEntitiesCount={docsCount}
881
+ />}
882
+ />
883
+
884
+ {/* View content - only the view-specific content changes */}
885
+ {viewMode === "kanban" ? (
886
+ <EntityCollectionBoardView
887
+ key={`kanban-view-${path}-${selectedKanbanProperty}`}
888
+ collection={collection}
889
+ tableController={tableController}
890
+ fullPath={path}
891
+ parentCollectionIds={parentCollectionIds}
892
+ columnProperty={selectedKanbanProperty}
893
+ onEntityClick={onEntityClick}
894
+ selectionController={usedSelectionController}
895
+ selectionEnabled={selectionEnabled}
896
+ highlightedEntities={highlightedEntity ? [highlightedEntity] : []}
897
+ deletedEntities={deletedEntities}
898
+ emptyComponent={canCreateEntities && tableController.filterValues === undefined && tableController.sortBy === undefined
899
+ ? <div className="flex flex-col items-center justify-center">
900
+ <Typography variant={"subtitle2"}>So empty...</Typography>
901
+ <Button
902
+ onClick={onNewClick}
903
+ className="mt-4"
904
+ >
905
+ <AddIcon />
906
+ Create your first entry
907
+ </Button>
908
+ </div>
909
+ : <Typography variant={"label"}>No results with the applied filter/sort</Typography>
910
+ }
911
+ />
912
+ ) : viewMode === "cards" ? (
913
+ <EntityCollectionCardView
914
+ key={`cards-view-${path}`}
915
+ collection={collection}
916
+ tableController={tableController}
917
+ onEntityClick={onEntityClick}
918
+ selectionController={usedSelectionController}
919
+ selectionEnabled={selectionEnabled}
920
+ highlightedEntities={highlightedEntity ? [highlightedEntity] : []}
921
+ onScroll={tableController.onScroll}
922
+ initialScroll={tableController.initialScroll}
923
+ size={cardSize}
924
+ emptyComponent={canCreateEntities && tableController.filterValues === undefined && tableController.sortBy === undefined
925
+ ? <div className="flex flex-col items-center justify-center">
926
+ <Typography variant={"subtitle2"}>So empty...</Typography>
927
+ <Button
928
+ onClick={onNewClick}
929
+ className="mt-4"
930
+ >
931
+ <AddIcon />
932
+ Create your first entry
933
+ </Button>
934
+ </div>
935
+ : <Typography variant={"label"}>No results with the applied filter/sort</Typography>
936
+ }
937
+ />
938
+ ) : (
939
+ <EntityCollectionTable
940
+ key={`collection_table_${path}`}
941
+ hideToolbar={true}
942
+ additionalFields={additionalFields}
943
+ tableController={tableController}
944
+ enablePopupIcon={true}
945
+ displayedColumnIds={displayedColumnIds}
946
+ onSizeChanged={onTableSizeChanged}
947
+ onEntityClick={onEntityClick}
948
+ onColumnResize={onColumnResize}
949
+ onValueChange={onValueChange}
950
+ tableRowActionsBuilder={tableRowActionsBuilder}
951
+ uniqueFieldValidator={uniqueFieldValidator}
952
+ selectionController={usedSelectionController}
953
+ highlightedEntities={highlightedEntity ? [highlightedEntity] : []}
954
+ defaultSize={tableSize}
955
+ properties={resolvedCollection.properties}
956
+ getPropertyFor={getPropertyFor}
957
+ onTextSearchClick={textSearchInitialised ? undefined : onTextSearchClick}
958
+ onScroll={tableController.onScroll}
959
+ initialScroll={tableController.initialScroll}
960
+ textSearchLoading={textSearchLoading}
961
+ emptyComponent={canCreateEntities && tableController.filterValues === undefined && tableController.sortBy === undefined
962
+ ? <div className="flex flex-col items-center justify-center">
963
+ <Typography variant={"subtitle2"}>So empty...</Typography>
964
+ <Button
965
+ onClick={onNewClick}
966
+ className="mt-4"
967
+ >
968
+ <AddIcon />
969
+ Create your first entry
970
+ </Button>
971
+ </div>
972
+ : <Typography variant={"label"}>No results with the applied filter/sort</Typography>
973
+ }
974
+ hoverRow={hoverRow}
975
+ inlineEditing={checkInlineEditing()}
976
+ AdditionalHeaderWidget={buildAdditionalHeaderWidget}
977
+ AddColumnComponent={addColumnComponentInternal}
978
+ getIdColumnWidth={getIdColumnWidth}
979
+ additionalIDHeaderWidget={<EntityIdHeaderWidget
980
+ path={path}
981
+ idPath={path}
982
+ collection={collection} />}
983
+ openEntityMode={openEntityMode}
984
+ onColumnsOrderChange={(newColumns) => {
985
+ // Extract property keys from the new column order
986
+ // Filter to only include actual property columns (not frozen columns, not additional fields, etc.)
987
+ // Deduplicate to clean up any previously duplicated keys
988
+ const seenKeys = new Set<string>();
989
+ const newPropertiesOrder = newColumns
990
+ .filter(col => !col.frozen && getPropertyInPath(collection.properties, col.key))
991
+ .map(col => col.key)
992
+ .filter(key => {
993
+ if (seenKeys.has(key)) return false;
994
+ seenKeys.add(key);
995
+ return true;
996
+ });
997
+
998
+ // Optimistically update local state to prevent UI flickering
999
+ setLocalPropertiesOrder(newPropertiesOrder);
1000
+
1001
+ // Call each plugin's onColumnsReorder callback
1002
+ if (customizationController?.plugins) {
1003
+ customizationController.plugins
1004
+ .filter(plugin => plugin.collectionView?.onColumnsReorder)
1005
+ .forEach(plugin => {
1006
+ plugin.collectionView!.onColumnsReorder!({
1007
+ fullPath: path,
1008
+ parentCollectionIds: parentCollectionIds ?? [],
1009
+ collection,
1010
+ newPropertiesOrder
1011
+ });
1012
+ });
1013
+ }
1014
+ }}
1015
+ />
1016
+ )}
1017
+
1018
+ {popupCell && <PopupFormField
1019
+ key={`popup_form_${popupCell?.propertyKey}_${popupCell?.entityId}`}
1020
+ open={Boolean(popupCell)}
1021
+ onClose={onPopupClose}
1022
+ cellRect={popupCell?.cellRect}
1023
+ propertyKey={popupCell?.propertyKey}
1024
+ collection={collection}
1025
+ entityId={popupCell.entityId}
1026
+ tableKey={tableKey.current}
1027
+ customFieldValidator={uniqueFieldValidator}
1028
+ path={path}
1029
+ onCellValueChange={onValueChange}
1030
+ container={containerRef.current} />}
1031
+
1032
+ {deleteEntityClicked &&
1033
+ <DeleteEntityDialog
1034
+ entityOrEntitiesToDelete={deleteEntityClicked}
1035
+ path={path}
1036
+ collection={collection}
1037
+ callbacks={collection.callbacks}
1038
+ open={Boolean(deleteEntityClicked)}
1039
+ onEntityDelete={internalOnEntityDelete}
1040
+ onMultipleEntitiesDelete={internalOnMultipleEntitiesDelete}
1041
+ onClose={() => setDeleteEntityClicked(undefined)} />}
1042
+
1043
+ </div>
1044
+ );
1045
+ }, (a, b) => {
1046
+ return equal(a.path, b.path) &&
1047
+ equal(a.parentCollectionIds, b.parentCollectionIds) &&
1048
+ equal(a.isSubCollection, b.isSubCollection) &&
1049
+ equal(a.className, b.className) &&
1050
+ equal(a.properties, b.properties) &&
1051
+ equal(a.propertiesOrder, b.propertiesOrder) &&
1052
+ equal(a.hideIdFromCollection, b.hideIdFromCollection) &&
1053
+ equal(a.inlineEditing, b.inlineEditing) &&
1054
+ equal(a.selectionEnabled, b.selectionEnabled) &&
1055
+ equal(a.selectionController, b.selectionController) &&
1056
+ equal(a.Actions, b.Actions) &&
1057
+ equal(a.defaultSize, b.defaultSize) &&
1058
+ equal(a.includeJsonView, b.includeJsonView) &&
1059
+ equal(a.additionalFields, b.additionalFields) &&
1060
+ equal(a.sideDialogWidth, b.sideDialogWidth) &&
1061
+ equal(a.openEntityMode, b.openEntityMode) &&
1062
+ equal(a.exportable, b.exportable) &&
1063
+ equal(a.history, b.history) &&
1064
+ equal(a.forceFilter, b.forceFilter);
1065
+ }) as React.FunctionComponent<EntityCollectionViewProps<any>>
1066
+
1067
+ function EntitiesCount({
1068
+ path,
1069
+ collection,
1070
+ filter,
1071
+ sortBy,
1072
+ onCountChange
1073
+ }: {
1074
+ path: string,
1075
+ collection: EntityCollection,
1076
+ filter?: FilterValues<any>,
1077
+ sortBy?: [string, "asc" | "desc"],
1078
+ onCountChange?: (count: number) => void,
1079
+ }) {
1080
+
1081
+ const dataSource = useDataSource(collection);
1082
+ const navigation = useCollectionRegistryController();
1083
+ const [count, setCount] = useState<number | undefined>(undefined);
1084
+ const [error, setError] = useState<Error | undefined>(undefined);
1085
+
1086
+ const sortByProperty = sortBy ? sortBy[0] : undefined;
1087
+ const currentSort = sortBy ? sortBy[1] : undefined;
1088
+ // v4: use path directly instead of resolveIdsFrom
1089
+ const resolvedPath = path;
1090
+
1091
+ useEffect(() => {
1092
+ if (dataSource.countEntities)
1093
+ dataSource.countEntities({
1094
+ path: resolvedPath,
1095
+ collection,
1096
+ filter,
1097
+ orderBy: sortByProperty,
1098
+ order: currentSort
1099
+ }).then(setCount).catch(setError);
1100
+ }, [path, dataSource.countEntities, resolvedPath, collection, filter, sortByProperty, currentSort]);
1101
+
1102
+ useEffect(() => {
1103
+ if (onCountChange && count !== undefined) {
1104
+ setError(undefined);
1105
+ onCountChange(count);
1106
+ }
1107
+ }, [onCountChange, count]);
1108
+
1109
+ if (error) {
1110
+ return null;
1111
+ }
1112
+
1113
+ // Count is now displayed in the breadcrumb bar, this component only fetches and reports
1114
+ return null;
1115
+ }
1116
+
1117
+
1118
+ function buildPropertyWidthOverwrite(key: string, width: number): PartialEntityCollection {
1119
+ if (key.includes(".")) {
1120
+ const [parentKey, ...childKey] = key.split(".");
1121
+ return { properties: { [parentKey]: buildPropertyWidthOverwrite(childKey.join("."), width) } } as PartialEntityCollection;
1122
+ }
1123
+ return { properties: { [key]: { columnWidth: width } } } as PartialEntityCollection;
1124
+ }
1125
+
1126
+ function EntityIdHeaderWidget({
1127
+ collection,
1128
+ path,
1129
+ idPath
1130
+ }: {
1131
+ collection: EntityCollection,
1132
+ path: string,
1133
+ idPath: string
1134
+ }) {
1135
+
1136
+ const cmsUrlController = useCMSUrlController();
1137
+ const [openPopup, setOpenPopup] = React.useState(false);
1138
+ const [searchString, setSearchString] = React.useState("");
1139
+ const [recentIds, setRecentIds] = React.useState<string[]>(getRecentIds(collection.slug).map(String));
1140
+ const sideEntityController = useSideEntityController();
1141
+
1142
+ const openEntityMode = collection?.openEntityMode ?? DEFAULT_ENTITY_OPEN_MODE;
1143
+
1144
+ return (
1145
+ <Tooltip title={!openPopup ? "Find by ID" : undefined} asChild={false}>
1146
+ <Popover
1147
+ open={openPopup}
1148
+ onOpenChange={setOpenPopup}
1149
+ sideOffset={0}
1150
+ align={"start"}
1151
+ alignOffset={-117}
1152
+ trigger={
1153
+ <IconButton size={"small"}>
1154
+ <SearchIcon size={"small"} />
1155
+ </IconButton>
1156
+ }>
1157
+ <div
1158
+ className={cls("my-2 rounded-lg bg-surface-50 dark:bg-surface-950 text-surface-900 dark:text-white")}>
1159
+ <form noValidate={true}
1160
+ onSubmit={(e) => {
1161
+ e.preventDefault();
1162
+ if (!searchString) return;
1163
+ setOpenPopup(false);
1164
+ const entityId = searchString.trim();
1165
+ setRecentIds(addRecentId(collection.slug, entityId).map(String));
1166
+ navigateToEntity({
1167
+ openEntityMode,
1168
+ collection,
1169
+ entityId,
1170
+ path,
1171
+
1172
+ sideEntityController,
1173
+ navigation: cmsUrlController
1174
+ })
1175
+ }}
1176
+ className={"w-96 max-w-full"}>
1177
+
1178
+ <div className="flex p-2 w-full gap-2">
1179
+ <input
1180
+ autoFocus={openPopup}
1181
+ placeholder={"Find entity by ID"}
1182
+ // size={"small"}
1183
+ onChange={(e) => {
1184
+ setSearchString(e.target.value);
1185
+ }}
1186
+ value={searchString}
1187
+ className={"rounded-lg bg-white dark:bg-surface-800 flex-grow bg-transparent outline-none p-2 " + focusedDisabled} />
1188
+ <Button variant={"text"}
1189
+ disabled={!(searchString.trim())}
1190
+ type={"submit"}
1191
+ ><KeyboardTabIcon /></Button>
1192
+ </div>
1193
+ </form>
1194
+ {recentIds && recentIds.length > 0 && <div className="flex flex-col gap-2 p-2">
1195
+ {recentIds.map(id => (
1196
+ <ReferencePreview reference={new EntityReference({ id, path })}
1197
+ key={id}
1198
+ hover={true}
1199
+ onClick={() => {
1200
+ setOpenPopup(false);
1201
+ navigateToEntity({
1202
+ openEntityMode,
1203
+ collection,
1204
+ entityId: id,
1205
+ path,
1206
+
1207
+ sideEntityController,
1208
+ navigation: cmsUrlController
1209
+ })
1210
+ }}
1211
+ includeEntityLink={false}
1212
+ size={"small"} />
1213
+ ))}
1214
+ </div>}
1215
+ </div>
1216
+ </Popover>
1217
+
1218
+ </Tooltip>
1219
+ );
1220
+ }