@rebasepro/admin 0.7.0 → 0.9.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 (350) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +20 -20
  3. package/dist/{CollectionEditorDialog-iGgS4rLX.js → CollectionEditorDialog-B-7uW3iJ.js} +15 -15
  4. package/dist/CollectionEditorDialog-B-7uW3iJ.js.map +1 -0
  5. package/dist/{PropertyEditView-C9yhLyja.js → PropertyEditView-7KMTcrqi.js} +140 -106
  6. package/dist/PropertyEditView-7KMTcrqi.js.map +1 -0
  7. package/dist/{RouterCollectionsStudioView-Dqx27GD8.js → RouterCollectionsStudioView-epqIbZrJ.js} +4 -4
  8. package/dist/{RouterCollectionsStudioView-Dqx27GD8.js.map → RouterCollectionsStudioView-epqIbZrJ.js.map} +1 -1
  9. package/dist/collection_editor/_cms_internals.d.ts +4 -4
  10. package/dist/collection_editor/api/generateCollectionApi.d.ts +7 -6
  11. package/dist/collection_editor/extensibility_types.d.ts +3 -3
  12. package/dist/collection_editor/index.d.ts +2 -2
  13. package/dist/collection_editor/pgColumnToProperty.d.ts +3 -3
  14. package/dist/collection_editor/serializable_types.d.ts +12 -16
  15. package/dist/collection_editor/serializable_utils.d.ts +8 -8
  16. package/dist/collection_editor/types/collection_editor_controller.d.ts +5 -5
  17. package/dist/collection_editor/types/collection_inference.d.ts +2 -2
  18. package/dist/collection_editor/types/config_controller.d.ts +7 -7
  19. package/dist/collection_editor/ui/AddKanbanColumnAction.d.ts +2 -2
  20. package/dist/collection_editor/ui/CollectionViewHeaderAction.d.ts +2 -2
  21. package/dist/collection_editor/ui/KanbanSetupAction.d.ts +2 -2
  22. package/dist/collection_editor/ui/PropertyAddColumnComponent.d.ts +2 -2
  23. package/dist/collection_editor/ui/collection_editor/AICollectionGeneratorPopover.d.ts +3 -3
  24. package/dist/collection_editor/ui/collection_editor/CollectionDetailsForm.d.ts +2 -2
  25. package/dist/collection_editor/ui/collection_editor/CollectionEditorDialog.d.ts +4 -5
  26. package/dist/collection_editor/ui/collection_editor/CollectionEditorWelcomeView.d.ts +2 -2
  27. package/dist/collection_editor/ui/collection_editor/CollectionJsonImportDialog.d.ts +2 -2
  28. package/dist/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +4 -4
  29. package/dist/collection_editor/ui/collection_editor/CollectionStudioView.d.ts +2 -2
  30. package/dist/collection_editor/ui/collection_editor/CollectionsStudioView.d.ts +2 -2
  31. package/dist/collection_editor/ui/collection_editor/EntityActionsEditTab.d.ts +2 -2
  32. package/dist/collection_editor/ui/collection_editor/GeneralSettingsForm.d.ts +2 -2
  33. package/dist/collection_editor/ui/collection_editor/GetCodeDialog.d.ts +2 -2
  34. package/dist/collection_editor/ui/collection_editor/PropertyEditView.d.ts +4 -4
  35. package/dist/collection_editor/ui/collection_editor/SubcollectionsEditTab.d.ts +3 -3
  36. package/dist/collection_editor/ui/collection_editor/templates/blog_template.d.ts +2 -2
  37. package/dist/collection_editor/ui/collection_editor/templates/pages_template.d.ts +2 -2
  38. package/dist/collection_editor/ui/collection_editor/templates/products_template.d.ts +2 -2
  39. package/dist/collection_editor/ui/collection_editor/templates/users_template.d.ts +2 -2
  40. package/dist/collection_editor/useLocalCollectionsConfigController.d.ts +2 -2
  41. package/dist/collection_editor/validateCollectionJson.d.ts +2 -2
  42. package/dist/collection_editor_ui.js +4 -4
  43. package/dist/components/CollectionPanel.d.ts +4 -4
  44. package/dist/components/{EntityCollectionTable/EntityCollectionRowActions.d.ts → CollectionTableBinding/CollectionRowActions.d.ts} +3 -3
  45. package/dist/components/CollectionTableBinding/CollectionTableBinding.d.ts +28 -0
  46. package/dist/components/{EntityCollectionTable/EntityCollectionTableProps.d.ts → CollectionTableBinding/CollectionTableBindingProps.d.ts} +1 -1
  47. package/dist/components/{EntityCollectionTable → CollectionTableBinding}/fields/TableMultipleRelationField.d.ts +2 -2
  48. package/dist/components/{EntityCollectionTable → CollectionTableBinding}/fields/TableReferenceField.d.ts +2 -2
  49. package/dist/components/{EntityCollectionTable → CollectionTableBinding}/fields/TableRelationField.d.ts +2 -2
  50. package/dist/components/CollectionTableBinding/index.d.ts +6 -0
  51. package/dist/components/{EntityCollectionTable → CollectionTableBinding}/internal/common.d.ts +2 -2
  52. package/dist/components/{EntityCollectionTable → CollectionTableBinding}/internal/popup_field/PopupFormField.d.ts +2 -2
  53. package/dist/components/{EntityCollectionView/EntityBoardCard.d.ts → CollectionViewBinding/BoardCardBinding.d.ts} +8 -8
  54. package/dist/components/{EntityCollectionView/EntityCollectionBoardView.d.ts → CollectionViewBinding/CollectionBoardViewBinding.d.ts} +4 -4
  55. package/dist/components/{EntityCollectionView/EntityCollectionCardView.d.ts → CollectionViewBinding/CollectionCardViewBinding.d.ts} +5 -5
  56. package/dist/components/{EntityCollectionView/EntityCollectionListView.d.ts → CollectionViewBinding/CollectionListViewBinding.d.ts} +4 -4
  57. package/dist/components/{EntityCollectionView/EntityCollectionViewActions.d.ts → CollectionViewBinding/CollectionViewActions.d.ts} +4 -4
  58. package/dist/components/{EntityCollectionView/EntityCollectionView.d.ts → CollectionViewBinding/CollectionViewBinding.d.ts} +4 -4
  59. package/dist/components/{EntityCollectionView/EntityCollectionViewStartActions.d.ts → CollectionViewBinding/CollectionViewStartActions.d.ts} +4 -4
  60. package/dist/components/CollectionViewBinding/EntityCardBinding.d.ts +21 -0
  61. package/dist/components/{EntityCollectionView → CollectionViewBinding}/SplitListView.d.ts +3 -3
  62. package/dist/components/{EntityCollectionView → CollectionViewBinding}/hooks/useCollectionInlineEditor.d.ts +2 -2
  63. package/dist/components/{EntityCollectionView → CollectionViewBinding}/hooks/useKanbanDragAndDrop.d.ts +2 -2
  64. package/dist/components/{EntityCollectionView → CollectionViewBinding}/useBoardDataController.d.ts +2 -2
  65. package/dist/components/{EntityCollectionView/useEntityPreviewSlots.d.ts → CollectionViewBinding/usePreviewSlots.d.ts} +5 -5
  66. package/dist/components/DeleteEntityDialog.d.ts +4 -4
  67. package/dist/components/{EntityDetailView.d.ts → DetailViewBinding.d.ts} +5 -5
  68. package/dist/components/EditFormActions.d.ts +3 -0
  69. package/dist/components/{EntityEditView.d.ts → EditViewBinding.d.ts} +9 -9
  70. package/dist/components/{EntityPreview.d.ts → EntityPreviewBinding.d.ts} +13 -13
  71. package/dist/components/EntityViewBinding.d.ts +13 -0
  72. package/dist/components/{EntityJsonPreview.d.ts → JsonPreviewBinding.d.ts} +1 -1
  73. package/dist/components/RebaseCMS.d.ts +1 -1
  74. package/dist/components/RebaseNavigation.d.ts +1 -1
  75. package/dist/components/ReferenceTable/{EntitySelectionTable.d.ts → SelectionTableBinding.d.ts} +5 -5
  76. package/dist/components/SelectableTable/SelectableTable.d.ts +5 -5
  77. package/dist/components/SelectableTable/SelectableTableContext.d.ts +3 -3
  78. package/dist/components/SelectableTable/SelectionStore.d.ts +13 -22
  79. package/dist/components/SelectableTable/filters/BooleanFilterField.d.ts +6 -1
  80. package/dist/components/SelectableTable/filters/DateTimeFilterField.d.ts +7 -1
  81. package/dist/components/SelectableTable/filters/FilterFieldBinding.d.ts +40 -0
  82. package/dist/components/SelectableTable/filters/ReferenceFilterField.d.ts +7 -1
  83. package/dist/components/SelectableTable/filters/RelationFilterField.d.ts +7 -1
  84. package/dist/components/SelectableTable/filters/StringNumberFilterField.d.ts +7 -1
  85. package/dist/components/SideDialogs.d.ts +1 -1
  86. package/dist/components/SidePanelBinding.d.ts +11 -0
  87. package/dist/components/{SideEntityProvider.d.ts → SidePanelProvider.d.ts} +7 -7
  88. package/dist/components/field_configs.d.ts +1 -1
  89. package/dist/components/history/EntityHistoryEntry.d.ts +2 -2
  90. package/dist/components/history/LastEditedByIndicator.d.ts +2 -2
  91. package/dist/components/index.d.ts +14 -13
  92. package/dist/contexts/SidePanelControllerContext.d.ts +3 -0
  93. package/dist/data_export/export/ExportCollectionAction.d.ts +3 -3
  94. package/dist/data_import/components/ImportSaveInProgress.d.ts +2 -2
  95. package/dist/editor/editor.d.ts +0 -6
  96. package/dist/editor.js +1 -3
  97. package/dist/editor.js.map +1 -1
  98. package/dist/form/EntityForm.d.ts +1 -1
  99. package/dist/form/PropertyFieldBinding.d.ts +1 -1
  100. package/dist/form/components/StorageUploadProgress.d.ts +6 -1
  101. package/dist/form/form_utils.d.ts +2 -2
  102. package/dist/form/index.d.ts +0 -1
  103. package/dist/{history-ChHgyyvM.js → history-7X5bON_n.js} +4 -4
  104. package/dist/history-7X5bON_n.js.map +1 -0
  105. package/dist/hooks/index.d.ts +4 -4
  106. package/dist/hooks/navigation/contexts/CollectionRegistryContext.d.ts +2 -2
  107. package/dist/hooks/navigation/useBuildNavigationStateController.d.ts +5 -5
  108. package/dist/hooks/navigation/useNavigationResolution.d.ts +4 -4
  109. package/dist/hooks/navigation/useResolvedCollections.d.ts +7 -7
  110. package/dist/hooks/navigation/useTopLevelNavigation.d.ts +2 -2
  111. package/dist/hooks/navigation/utils.d.ts +5 -5
  112. package/dist/hooks/useBuildSidePanel.d.ts +6 -0
  113. package/dist/hooks/useCMSContext.d.ts +2 -2
  114. package/dist/hooks/{useEntityHistory.d.ts → useHistory.d.ts} +1 -1
  115. package/dist/hooks/useResolvedNavigationFrom.d.ts +3 -3
  116. package/dist/hooks/{useEntitySelectionDialog.d.ts → useSelectionDialog.d.ts} +2 -2
  117. package/dist/hooks/useSideDialogsController.d.ts +1 -1
  118. package/dist/hooks/useSidePanel.d.ts +11 -0
  119. package/dist/index.d.ts +3 -3
  120. package/dist/index.js +2 -2
  121. package/dist/preview/components/StorageThumbnail.d.ts +3 -1
  122. package/dist/{src-DOX2nOyh.js → src-sUZfe29F.js} +904 -1096
  123. package/dist/src-sUZfe29F.js.map +1 -0
  124. package/dist/types/components/EntityFormActionsProps.d.ts +2 -2
  125. package/dist/types/components/EntityFormProps.d.ts +3 -3
  126. package/dist/types/components/PropertyPreviewProps.d.ts +2 -1
  127. package/dist/types/fields.d.ts +6 -8
  128. package/dist/util/dataControllerAdapter.d.ts +2 -5
  129. package/dist/util/navigation_utils.d.ts +6 -6
  130. package/dist/util/previews.d.ts +3 -3
  131. package/dist/util/property_utils.d.ts +2 -2
  132. package/dist/util/{entity_view_constants.d.ts → view_constants.d.ts} +1 -1
  133. package/package.json +18 -18
  134. package/src/collection_editor/ConfigControllerProvider.tsx +10 -10
  135. package/src/collection_editor/_cms_internals.ts +4 -4
  136. package/src/collection_editor/api/generateCollectionApi.ts +7 -6
  137. package/src/collection_editor/extensibility_types.ts +3 -3
  138. package/src/collection_editor/index.ts +3 -3
  139. package/src/collection_editor/pgColumnToProperty.ts +4 -4
  140. package/src/collection_editor/serializable_types.ts +22 -35
  141. package/src/collection_editor/serializable_utils.ts +40 -52
  142. package/src/collection_editor/types/collection_editor_controller.tsx +5 -5
  143. package/src/collection_editor/types/collection_inference.ts +2 -2
  144. package/src/collection_editor/types/config_controller.tsx +7 -7
  145. package/src/collection_editor/ui/AddKanbanColumnAction.tsx +2 -2
  146. package/src/collection_editor/ui/CollectionViewHeaderAction.tsx +2 -2
  147. package/src/collection_editor/ui/EditorCollectionAction.tsx +2 -2
  148. package/src/collection_editor/ui/EditorCollectionActionStart.tsx +2 -2
  149. package/src/collection_editor/ui/EditorEntityAction.tsx +2 -2
  150. package/src/collection_editor/ui/KanbanSetupAction.tsx +2 -2
  151. package/src/collection_editor/ui/PropertyAddColumnComponent.tsx +2 -2
  152. package/src/collection_editor/ui/collection_editor/AICollectionGeneratorPopover.tsx +5 -5
  153. package/src/collection_editor/ui/collection_editor/CollectionDetailsForm.tsx +3 -3
  154. package/src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx +63 -46
  155. package/src/collection_editor/ui/collection_editor/CollectionEditorWelcomeView.tsx +3 -3
  156. package/src/collection_editor/ui/collection_editor/CollectionJsonImportDialog.tsx +2 -2
  157. package/src/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.tsx +8 -8
  158. package/src/collection_editor/ui/collection_editor/CollectionRLSTab.tsx +2 -2
  159. package/src/collection_editor/ui/collection_editor/CollectionRelationsTab.tsx +2 -2
  160. package/src/collection_editor/ui/collection_editor/CollectionStudioView.tsx +2 -2
  161. package/src/collection_editor/ui/collection_editor/CollectionsStudioView.tsx +2 -2
  162. package/src/collection_editor/ui/collection_editor/DisplaySettingsForm.tsx +2 -2
  163. package/src/collection_editor/ui/collection_editor/EntityActionsEditTab.tsx +3 -3
  164. package/src/collection_editor/ui/collection_editor/GeneralSettingsForm.tsx +5 -5
  165. package/src/collection_editor/ui/collection_editor/GetCodeDialog.tsx +4 -4
  166. package/src/collection_editor/ui/collection_editor/KanbanConfigSection.tsx +2 -2
  167. package/src/collection_editor/ui/collection_editor/PropertyEditView.tsx +7 -16
  168. package/src/collection_editor/ui/collection_editor/PropertyFieldPreview.tsx +45 -36
  169. package/src/collection_editor/ui/collection_editor/PropertyTree.tsx +1 -1
  170. package/src/collection_editor/ui/collection_editor/SubcollectionsEditTab.tsx +5 -5
  171. package/src/collection_editor/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +3 -3
  172. package/src/collection_editor/ui/collection_editor/import/CollectionEditorImportMapping.tsx +2 -2
  173. package/src/collection_editor/ui/collection_editor/properties/RelationPropertyField.tsx +2 -2
  174. package/src/collection_editor/ui/collection_editor/properties/StoragePropertyField.tsx +35 -1
  175. package/src/collection_editor/ui/collection_editor/templates/blog_template.ts +3 -3
  176. package/src/collection_editor/ui/collection_editor/templates/pages_template.ts +2 -2
  177. package/src/collection_editor/ui/collection_editor/templates/products_template.ts +2 -2
  178. package/src/collection_editor/ui/collection_editor/templates/users_template.ts +2 -2
  179. package/src/collection_editor/ui/collection_editor/utils/supported_fields.tsx +0 -1
  180. package/src/collection_editor/ui/collection_editor/utils/update_property_for_widget.ts +7 -29
  181. package/src/collection_editor/useJsonCollectionsConfigController.tsx +14 -14
  182. package/src/collection_editor/useLocalCollectionsConfigController.tsx +4 -4
  183. package/src/collection_editor/validateCollectionJson.ts +3 -3
  184. package/src/components/CollectionPanel.tsx +14 -17
  185. package/src/components/{EntityCollectionTable/EntityCollectionRowActions.tsx → CollectionTableBinding/CollectionRowActions.tsx} +6 -6
  186. package/src/components/{EntityCollectionTable/EntityCollectionTable.tsx → CollectionTableBinding/CollectionTableBinding.tsx} +19 -17
  187. package/src/components/{EntityCollectionTable/EntityCollectionTableProps.tsx → CollectionTableBinding/CollectionTableBindingProps.tsx} +1 -1
  188. package/src/components/{EntityCollectionTable → CollectionTableBinding}/fields/TableMultipleRelationField.tsx +7 -6
  189. package/src/components/{EntityCollectionTable → CollectionTableBinding}/fields/TableReferenceField.tsx +10 -10
  190. package/src/components/{EntityCollectionTable → CollectionTableBinding}/fields/TableRelationField.tsx +7 -6
  191. package/src/components/{EntityCollectionTable → CollectionTableBinding}/fields/TableStorageUpload.tsx +23 -20
  192. package/src/components/CollectionTableBinding/index.tsx +14 -0
  193. package/src/components/{EntityCollectionTable → CollectionTableBinding}/internal/common.tsx +2 -2
  194. package/src/components/{EntityCollectionTable → CollectionTableBinding}/internal/popup_field/PopupFormField.tsx +2 -2
  195. package/src/components/{EntityCollectionTable → CollectionTableBinding}/table_bindings.tsx +24 -44
  196. package/src/components/{EntityCollectionView/EntityBoardCard.tsx → CollectionViewBinding/BoardCardBinding.tsx} +15 -15
  197. package/src/components/{EntityCollectionView/EntityCollectionBoardView.tsx → CollectionViewBinding/CollectionBoardViewBinding.tsx} +15 -14
  198. package/src/components/{EntityCollectionView/EntityCollectionCardView.tsx → CollectionViewBinding/CollectionCardViewBinding.tsx} +8 -8
  199. package/src/components/{EntityCollectionView/EntityCollectionListView.tsx → CollectionViewBinding/CollectionListViewBinding.tsx} +24 -13
  200. package/src/components/{EntityCollectionView/EntityCollectionViewActions.tsx → CollectionViewBinding/CollectionViewActions.tsx} +5 -5
  201. package/src/components/{EntityCollectionView/EntityCollectionView.tsx → CollectionViewBinding/CollectionViewBinding.tsx} +112 -114
  202. package/src/components/{EntityCollectionView/EntityCollectionViewStartActions.tsx → CollectionViewBinding/CollectionViewStartActions.tsx} +5 -5
  203. package/src/components/{EntityCollectionView/EntityCard.tsx → CollectionViewBinding/EntityCardBinding.tsx} +9 -9
  204. package/src/components/{EntityCollectionView → CollectionViewBinding}/FiltersDialog.tsx +31 -72
  205. package/src/components/{EntityCollectionView → CollectionViewBinding}/SplitListView.tsx +9 -9
  206. package/src/components/{EntityCollectionView → CollectionViewBinding}/hooks/useCollectionInlineEditor.ts +6 -6
  207. package/src/components/{EntityCollectionView → CollectionViewBinding}/hooks/useKanbanDragAndDrop.ts +4 -4
  208. package/src/components/{EntityCollectionView → CollectionViewBinding}/useBoardDataController.tsx +28 -50
  209. package/src/components/{EntityCollectionView/useEntityPreviewSlots.ts → CollectionViewBinding/usePreviewSlots.ts} +11 -11
  210. package/src/components/DefaultDrawer.tsx +1 -1
  211. package/src/components/DeleteEntityDialog.tsx +6 -6
  212. package/src/components/{EntityDetailView.tsx → DetailViewBinding.tsx} +28 -31
  213. package/src/components/{EntityEditViewFormActions.tsx → EditFormActions.tsx} +15 -15
  214. package/src/components/{EntityEditView.tsx → EditViewBinding.tsx} +31 -34
  215. package/src/components/{EntityPreview.tsx → EntityPreviewBinding.tsx} +27 -27
  216. package/src/components/{EntityView.tsx → EntityViewBinding.tsx} +5 -5
  217. package/src/components/HomePage/ContentHomePage.tsx +1 -1
  218. package/src/components/HomePage/NavigationCardBinding.tsx +1 -1
  219. package/src/components/{EntityJsonPreview.tsx → JsonPreviewBinding.tsx} +1 -1
  220. package/src/components/RebaseCMS.tsx +4 -4
  221. package/src/components/RebaseNavigation.tsx +20 -10
  222. package/src/components/ReferenceTable/{EntitySelectionTable.tsx → SelectionTableBinding.tsx} +22 -19
  223. package/src/components/ReferenceWidget.tsx +4 -4
  224. package/src/components/RelationSelector.tsx +16 -14
  225. package/src/components/SelectableTable/SelectableTable.tsx +44 -89
  226. package/src/components/SelectableTable/SelectableTableContext.tsx +3 -3
  227. package/src/components/SelectableTable/SelectionStore.ts +22 -52
  228. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +9 -1
  229. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +33 -12
  230. package/src/components/SelectableTable/filters/FilterFieldBinding.tsx +187 -0
  231. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +21 -7
  232. package/src/components/SelectableTable/filters/RelationFilterField.tsx +17 -3
  233. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +66 -12
  234. package/src/components/SideDialogs.tsx +3 -3
  235. package/src/components/{EntitySidePanel.tsx → SidePanelBinding.tsx} +19 -19
  236. package/src/components/{SideEntityProvider.tsx → SidePanelProvider.tsx} +16 -16
  237. package/src/components/common/default_entity_actions.tsx +24 -13
  238. package/src/components/field_configs.tsx +0 -14
  239. package/src/components/history/EntityHistoryEntry.tsx +2 -2
  240. package/src/components/history/EntityHistoryView.tsx +3 -3
  241. package/src/components/history/LastEditedByIndicator.tsx +2 -2
  242. package/src/components/index.ts +15 -14
  243. package/src/contexts/SidePanelControllerContext.tsx +5 -0
  244. package/src/data_export/export/ExportCollectionAction.tsx +4 -4
  245. package/src/data_import/components/ImportSaveInProgress.tsx +3 -3
  246. package/src/data_import/import/ImportCollectionAction.tsx +4 -4
  247. package/src/data_import/utils/data.ts +2 -2
  248. package/src/editor/editor.tsx +4 -7
  249. package/src/form/EntityForm.tsx +2 -2
  250. package/src/form/EntityFormActions.tsx +4 -4
  251. package/src/form/EntityFormBinding.tsx +7 -7
  252. package/src/form/PropertyFieldBinding.tsx +4 -4
  253. package/src/form/components/StorageUploadProgress.tsx +9 -2
  254. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +4 -4
  255. package/src/form/field_bindings/KeyValueFieldBinding.tsx +19 -19
  256. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +12 -1
  257. package/src/form/field_bindings/MultipleRelationFieldBinding.tsx +6 -6
  258. package/src/form/field_bindings/ReferenceFieldBinding.tsx +5 -5
  259. package/src/form/field_bindings/RelationFieldBinding.tsx +8 -10
  260. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +19 -15
  261. package/src/form/form_utils.ts +2 -2
  262. package/src/form/index.tsx +0 -1
  263. package/src/hooks/index.ts +4 -4
  264. package/src/hooks/navigation/contexts/CollectionRegistryContext.tsx +2 -2
  265. package/src/hooks/navigation/useBuildCollectionRegistryController.tsx +11 -11
  266. package/src/hooks/navigation/useBuildNavigationStateController.tsx +5 -5
  267. package/src/hooks/navigation/useNavigationResolution.ts +10 -10
  268. package/src/hooks/navigation/useResolvedCollections.ts +8 -8
  269. package/src/hooks/navigation/useTopLevelNavigation.ts +2 -2
  270. package/src/hooks/navigation/utils.ts +5 -5
  271. package/src/hooks/{useBuildSideEntityController.tsx → useBuildSidePanel.tsx} +28 -28
  272. package/src/hooks/useCMSContext.tsx +6 -6
  273. package/src/hooks/{useEntityHistory.ts → useHistory.ts} +1 -1
  274. package/src/hooks/useResolvedNavigationFrom.tsx +8 -5
  275. package/src/hooks/{useEntitySelectionDialog.tsx → useSelectionDialog.tsx} +7 -7
  276. package/src/hooks/useSideDialogsController.tsx +1 -1
  277. package/src/hooks/useSidePanel.tsx +13 -0
  278. package/src/index.ts +13 -13
  279. package/src/preview/PropertyPreview.tsx +1 -16
  280. package/src/preview/components/ReferencePreview.tsx +10 -10
  281. package/src/preview/components/RelationPreview.tsx +13 -12
  282. package/src/preview/components/StorageThumbnail.tsx +24 -7
  283. package/src/routes/RebaseRoute.tsx +10 -10
  284. package/src/types/components/EntityFormActionsProps.tsx +2 -2
  285. package/src/types/components/EntityFormProps.tsx +3 -3
  286. package/src/types/components/PropertyPreviewProps.tsx +1 -1
  287. package/src/types/fields.tsx +4 -9
  288. package/src/util/dataControllerAdapter.ts +9 -15
  289. package/src/util/navigation_utils.ts +7 -7
  290. package/src/util/previews.ts +23 -3
  291. package/src/util/propertyConfigMapper.ts +3 -3
  292. package/src/util/property_utils.tsx +2 -3
  293. package/src/util/{entity_view_constants.ts → view_constants.ts} +1 -1
  294. package/dist/CollectionEditorDialog-iGgS4rLX.js.map +0 -1
  295. package/dist/PropertyEditView-C9yhLyja.js.map +0 -1
  296. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +0 -28
  297. package/dist/components/EntityCollectionTable/fields/VirtualTableDateField.d.ts +0 -12
  298. package/dist/components/EntityCollectionTable/fields/VirtualTableInput.d.ts +0 -10
  299. package/dist/components/EntityCollectionTable/fields/VirtualTableNumberInput.d.ts +0 -9
  300. package/dist/components/EntityCollectionTable/fields/VirtualTableSwitch.d.ts +0 -8
  301. package/dist/components/EntityCollectionTable/index.d.ts +0 -6
  302. package/dist/components/EntityCollectionView/EntityCard.d.ts +0 -21
  303. package/dist/components/EntityEditViewFormActions.d.ts +0 -3
  304. package/dist/components/EntitySidePanel.d.ts +0 -11
  305. package/dist/components/EntityView.d.ts +0 -13
  306. package/dist/contexts/SideEntityControllerContext.d.ts +0 -3
  307. package/dist/form/field_bindings/ReferenceAsStringFieldBinding.d.ts +0 -11
  308. package/dist/history-ChHgyyvM.js.map +0 -1
  309. package/dist/hooks/useBuildSideEntityController.d.ts +0 -6
  310. package/dist/hooks/useSideEntityController.d.ts +0 -11
  311. package/dist/src-DOX2nOyh.js.map +0 -1
  312. package/src/components/EntityCollectionTable/fields/VirtualTableDateField.tsx +0 -39
  313. package/src/components/EntityCollectionTable/fields/VirtualTableInput.tsx +0 -90
  314. package/src/components/EntityCollectionTable/fields/VirtualTableNumberInput.tsx +0 -83
  315. package/src/components/EntityCollectionTable/fields/VirtualTableSwitch.tsx +0 -32
  316. package/src/components/EntityCollectionTable/index.tsx +0 -14
  317. package/src/contexts/SideEntityControllerContext.tsx +0 -5
  318. package/src/form/field_bindings/ReferenceAsStringFieldBinding.tsx +0 -141
  319. package/src/hooks/useSideEntityController.tsx +0 -13
  320. /package/dist/components/{EntityCollectionTable → CollectionTableBinding}/PropertyTableCell.d.ts +0 -0
  321. /package/dist/components/{EntityCollectionTable → CollectionTableBinding}/column_utils.d.ts +0 -0
  322. /package/dist/components/{EntityCollectionTable → CollectionTableBinding}/fields/TableRelationSelectorField.d.ts +0 -0
  323. /package/dist/components/{EntityCollectionTable → CollectionTableBinding}/fields/TableStorageUpload.d.ts +0 -0
  324. /package/dist/components/{EntityCollectionTable → CollectionTableBinding}/fields/VirtualTableSelect.d.ts +0 -0
  325. /package/dist/components/{EntityCollectionTable → CollectionTableBinding}/fields/VirtualTableUserSelect.d.ts +0 -0
  326. /package/dist/components/{EntityCollectionTable → CollectionTableBinding}/internal/CollectionTableToolbar.d.ts +0 -0
  327. /package/dist/components/{EntityCollectionTable → CollectionTableBinding}/internal/EntityTableCell.d.ts +0 -0
  328. /package/dist/components/{EntityCollectionTable → CollectionTableBinding}/internal/EntityTableCellActions.d.ts +0 -0
  329. /package/dist/components/{EntityCollectionTable → CollectionTableBinding}/internal/popup_field/useDraggable.d.ts +0 -0
  330. /package/dist/components/{EntityCollectionTable → CollectionTableBinding}/internal/popup_field/useWindowSize.d.ts +0 -0
  331. /package/dist/components/{EntityCollectionTable → CollectionTableBinding}/table_bindings.d.ts +0 -0
  332. /package/dist/components/{EntityCollectionView → CollectionViewBinding}/FilterPresetsButton.d.ts +0 -0
  333. /package/dist/components/{EntityCollectionView → CollectionViewBinding}/FiltersDialog.d.ts +0 -0
  334. /package/dist/components/{EntityCollectionView → CollectionViewBinding}/ViewModeToggle.d.ts +0 -0
  335. /package/dist/components/{EntityCollectionView → CollectionViewBinding}/useSelectionController.d.ts +0 -0
  336. /package/dist/components/{EntityCollectionView → CollectionViewBinding}/utils.d.ts +0 -0
  337. /package/src/components/{EntityCollectionTable → CollectionTableBinding}/PropertyTableCell.tsx +0 -0
  338. /package/src/components/{EntityCollectionTable → CollectionTableBinding}/column_utils.tsx +0 -0
  339. /package/src/components/{EntityCollectionTable → CollectionTableBinding}/fields/TableRelationSelectorField.tsx +0 -0
  340. /package/src/components/{EntityCollectionTable → CollectionTableBinding}/fields/VirtualTableSelect.tsx +0 -0
  341. /package/src/components/{EntityCollectionTable → CollectionTableBinding}/fields/VirtualTableUserSelect.tsx +0 -0
  342. /package/src/components/{EntityCollectionTable → CollectionTableBinding}/internal/CollectionTableToolbar.tsx +0 -0
  343. /package/src/components/{EntityCollectionTable → CollectionTableBinding}/internal/EntityTableCell.tsx +0 -0
  344. /package/src/components/{EntityCollectionTable → CollectionTableBinding}/internal/EntityTableCellActions.tsx +0 -0
  345. /package/src/components/{EntityCollectionTable → CollectionTableBinding}/internal/popup_field/useDraggable.tsx +0 -0
  346. /package/src/components/{EntityCollectionTable → CollectionTableBinding}/internal/popup_field/useWindowSize.tsx +0 -0
  347. /package/src/components/{EntityCollectionView → CollectionViewBinding}/FilterPresetsButton.tsx +0 -0
  348. /package/src/components/{EntityCollectionView → CollectionViewBinding}/ViewModeToggle.tsx +0 -0
  349. /package/src/components/{EntityCollectionView → CollectionViewBinding}/useSelectionController.tsx +0 -0
  350. /package/src/components/{EntityCollectionView → CollectionViewBinding}/utils.ts +0 -0
@@ -2,14 +2,14 @@ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
2
  import * as React$1 from "react";
3
3
  import React, { Suspense, createContext, createElement, forwardRef, lazy, memo, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
4
4
  import { deepEqual } from "fast-equals";
5
- import { Alert, AlertCircleIcon, AlertTriangleIcon, AlignLeftIcon, ArrowLeftIcon, ArrowRightToLineIcon, Avatar, Badge, BooleanSwitch, BooleanSwitchWithLabel, Button, CHIP_COLORS, CalendarIcon, Card, CardView, CenteredView, CheckCircleIcon, CheckIcon, Checkbox, ChevronDownIcon, ChevronRightIcon, ChevronUpIcon, ChevronsLeftIcon, ChevronsRightIcon, ChevronsUpDownIcon, Chip, CircleIcon, CircularProgress, CircularProgressCenter, CodeIcon, Collapse, ColumnsIcon, Container, CopyIcon, DateTimeField, Dialog, DialogActions, DialogContent, DialogTitle, DownloadIcon, ErrorBoundary, ExpandablePanel, ExternalLinkIcon, EyeIcon, EyeOffIcon, FileTextIcon, FileUpload, FilterChip, FilterIcon, FilterXIcon, FlagIcon, FolderUpIcon, FunctionSquareIcon, GlobeIcon, HandleIcon, HashIcon, HistoryIcon, IconButton, ImageOffIcon, KanbanIcon, KanbanView, KeyRoundIcon, Label, LayoutGridIcon, LinkIcon, ListIcon, ListOrderedIcon, ListView, LoaderIcon, LoadingButton, LogOutIcon, MailIcon, Markdown, Maximize2Icon, Menu, MenuIcon, MenuItem, MinusIcon, MoonIcon, MoreVerticalIcon, MultiSelect, MultiSelectItem, PencilIcon, PlusIcon, Popover, PopoverPrimitive, Portal, QuoteIcon, RadioGroup, RadioGroupItem, RefreshCwIcon, RepeatIcon, ResizablePanels, Rows3Icon, SearchBar, SearchIcon, Select, SelectItem, Separator, SettingsIcon, Sheet, Skeleton, StarIcon, SunIcon, SunMoonIcon, Tab, Table, TableBody, TableCell, TableHeader, TableIcon, TableRow, TableView, Tabs, TextField, TextIcon, TextareaAutosize, ToggleButtonGroup, Tooltip, Trash2Icon, Typography, UploadIcon, UserIcon, VoteIcon, XCircleIcon, XIcon, cls, coolIconKeys, debounce, defaultBorderMixin, fieldBackgroundDisabledMixin, fieldBackgroundHoverMixin, fieldBackgroundInvisibleMixin, fieldBackgroundMixin, focusedDisabled, getColorSchemeForSeed, iconSize, lucideIcons, paperMixin, useDebouncedCallback, useInjectStyles, useOutsideAlerter } from "@rebasepro/ui";
6
- import { CollectionRegistry, DEFAULT_ONE_OF_TYPE, DEFAULT_ONE_OF_VALUE, addInitialSlash, buildRoutedRebaseData, canReadCollection, enumToObjectEntries, getArrayResolvedProperties, getCollectionBySlugWithin, getCollectionPathsCombinations, getDefaultValueFor, getDefaultValueFortype, getDefaultValuesFor, getEntityImagePreviewPropertyKey, getLabelOrConfigFrom, getLastSegment, getLastSegment as getLastSegment$1, getLocalChangesBackup, getNavigationEntriesFromPath, getParentReferencesFromPath, getReferenceFrom, getRelationFrom, getSubcollections, getTableName, isHidden, isPropertyBuilder, isReadOnly, normalizeToEntityRelation, removeInitialAndTrailingSlashes, removeInitialAndTrailingSlashes as removeInitialAndTrailingSlashes$1, removeInitialSlash, removeTrailingSlash, resolveArrayProperties, resolveCollectionPathIds, resolveCollectionPathIds as resolveCollectionPathIds$1, resolveDataSource, resolveDefaultSelectedView, resolveEnumValues, resolveProperty, resolveRelationProperty, resolveStorageFilenameString, resolveStoragePathString } from "@rebasepro/common";
7
- import { ADDITIONAL_TAB_WIDTH, CONTAINER_FULL_WIDTH, CollectionComponentOverrideProvider, ConfirmationDialog, CustomizationControllerContext, DEFAULT_PAGE_SIZE, ErrorTooltip, ErrorView, FORM_CONTAINER_WIDTH, IconForView, LanguageToggle, LoginView, NotFoundPage, PluginProviderStack, RebaseDataContext, RebaseLogo, RebaseRoutes, SchemaDriftBanner, StudioBridgeRegistryProvider, UIReferenceView, UnsavedChangesDialog, UserDisplay, UserSettingsView, buildCollapsedDefaults, buildEnumLabel, createFormexStub, deleteEntityWithCallbacks, flattenKeys, getColorScheme, getColumnKeysForProperty, getEntityFromCache, getEntityFromMemoryCache, getFormFieldKeys, getIcon, getRowHeight, iconsSearch, removeEntityFromCache, removeEntityFromMemoryCache, resolveComponentRef, saveEntityToCache, saveEntityToMemoryCache, saveEntityWithCallbacks, useAdminModeController, useAnalyticsController, useApiConfig, useAuthController, useBridgeRegistration, useBuildLocalConfigurationPersistence, useCollapsedGroups, useColumnIds, useComponentOverride, useCustomizationController, useData, useDataSources, useDataTableController, useEntityFetch, useLargeLayout, useModeController, usePermissions, useRebaseClient, useRebaseContext, useRebaseRegistry, useRebaseRegistryDispatch, useRelationSelector, useRestoreScroll, useScrollRestoration, useSlot, useSnackbarController, useStorageSource, useStorageUploadController, useTranslation, useUnsavedChangesDialog, useUserConfigurationPersistence } from "@rebasepro/core";
5
+ import { Alert, AlertCircleIcon, AlertTriangleIcon, AlignLeftIcon, ArrowLeftIcon, ArrowRightToLineIcon, Avatar, Badge, BooleanSwitchWithLabel, Button, CHIP_COLORS, CalendarIcon, Card, CardView, CenteredView, CheckCircleIcon, CheckIcon, Checkbox, ChevronDownIcon, ChevronRightIcon, ChevronUpIcon, ChevronsLeftIcon, ChevronsRightIcon, ChevronsUpDownIcon, Chip, CircleIcon, CircularProgress, CircularProgressCenter, CodeIcon, Collapse, ColumnsIcon, Container, CopyIcon, DateTimeField, Dialog, DialogActions, DialogContent, DialogTitle, DownloadIcon, ErrorBoundary, ExpandablePanel, ExternalLinkIcon, EyeIcon, EyeOffIcon, FileTextIcon, FileUpload, FilterChip, FilterIcon, FilterXIcon, FlagIcon, FolderUpIcon, FunctionSquareIcon, GlobeIcon, HandleIcon, HashIcon, HistoryIcon, IconButton, ImageOffIcon, KanbanIcon, KanbanView, KeyRoundIcon, Label, LayoutGridIcon, LinkIcon, ListIcon, ListOrderedIcon, ListView, LoaderIcon, LoadingButton, LogOutIcon, MailIcon, Markdown, Maximize2Icon, Menu, MenuIcon, MenuItem, MinusIcon, MoonIcon, MoreVerticalIcon, MultiSelect, MultiSelectItem, PencilIcon, PlusIcon, Popover, PopoverPrimitive, Portal, QuoteIcon, RadioGroup, RadioGroupItem, RefreshCwIcon, RepeatIcon, ResizablePanels, Rows3Icon, SearchBar, SearchIcon, Select, SelectItem, Separator, SettingsIcon, Sheet, Skeleton, StarIcon, SunIcon, SunMoonIcon, Tab, Table, TableBody, TableCell, TableHeader, TableIcon, TableRow, TableView, Tabs, TextField, TextIcon, TextareaAutosize, ToggleButtonGroup, Tooltip, Trash2Icon, Typography, UploadIcon, UserIcon, VirtualTableDateField, VirtualTableInput, VirtualTableInput as VirtualTableInput$1, VirtualTableNumberInput, VirtualTableSwitch, VoteIcon, XCircleIcon, XIcon, cls, coolIconKeys, createVirtualTableSelectionStore, debounce, defaultBorderMixin, fieldBackgroundDisabledMixin, fieldBackgroundHoverMixin, fieldBackgroundInvisibleMixin, fieldBackgroundMixin, focusedDisabled, getColorSchemeForSeed, iconSize, lucideIcons, paperMixin, useDebouncedCallback, useInjectStyles, useOutsideAlerter } from "@rebasepro/ui";
6
+ import { CollectionRegistry, DEFAULT_ONE_OF_TYPE, DEFAULT_ONE_OF_VALUE, addInitialSlash, buildRoutedRebaseData, canReadCollection, enumToObjectEntries, getArrayResolvedProperties, getCollectionBySlugWithin, getCollectionPathsCombinations, getDefaultValueFor, getDefaultValueFortype, getDefaultValuesFor, getEntityImagePreviewPropertyKey, getLabelOrConfigFrom, getLastSegment, getLastSegment as getLastSegment$1, getLocalChangesBackup, getNavigationEntriesFromPath, getParentReferencesFromPath, getReferenceFrom, getRelationFrom, getSubcollections, getTableName, isHidden, isPropertyBuilder, isReadOnly, normalizeToEntityRelation, removeInitialAndTrailingSlashes, removeInitialAndTrailingSlashes as removeInitialAndTrailingSlashes$1, removeInitialSlash, removeTrailingSlash, resolveArrayProperties, resolveCollectionPathIds, resolveCollectionPathIds as resolveCollectionPathIds$1, resolveDataSource, resolveDefaultSelectedView, resolveEnumValues, resolveFilterOperators, resolveProperty, resolveRelationProperty, resolveStorageFilenameString, resolveStoragePathString, resolveStorageSource } from "@rebasepro/common";
7
+ import { ADDITIONAL_TAB_WIDTH, CONTAINER_FULL_WIDTH, CollectionScopeProvider, ConfirmationDialog, CustomizationControllerContext, DEFAULT_PAGE_SIZE, ErrorTooltip, ErrorView, FORM_CONTAINER_WIDTH, IconForView, LanguageToggle, LoginView, NotFoundPage, PluginProviderStack, RebaseDataContext, RebaseLogo, RebaseRoutes, SchemaDriftBanner, StorageSourceContext, StudioBridgeRegistryProvider, UIReferenceView, UnsavedChangesDialog, UserDisplay, UserSettingsView, buildCollapsedDefaults, buildEnumLabel, createFormexStub, deleteEntityWithCallbacks, flattenKeys, getColorScheme, getColumnKeysForProperty, getEntityFromCache, getEntityFromMemoryCache, getFormFieldKeys, getIcon, getRowHeight, iconsSearch, removeEntityFromCache, removeEntityFromMemoryCache, resolveComponentRef, saveEntityToCache, saveEntityToMemoryCache, saveEntityWithCallbacks, useAdminModeController, useAnalyticsController, useApiConfig, useAuthController, useBridgeRegistration, useBuildLocalConfigurationPersistence, useCollapsedGroups, useCollectionScope, useColumnIds, useComponentOverride, useCustomizationController, useData, useDataSources, useDataTableController, useFetch, useLargeLayout, useModeController, usePermissions, useRebaseClient, useRebaseContext, useRebaseRegistry, useRebaseRegistryDispatch, useRelationSelector, useResolvedComponent, useRestoreScroll, useScrollRestoration, useSlot, useSnackbarController, useStorageSource, useStorageSources, useStorageUploadController, useTranslation, useUnsavedChangesDialog, useUserConfigurationPersistence } from "@rebasepro/core";
8
8
  import { Field, Formex, getIn, setIn, useCreateFormex, useFormex } from "@rebasepro/formex";
9
9
  import { z } from "zod";
10
10
  import { defaultDateFormat, getArrayValuesCount, getHashValue, getValueInPath, hydrateRegExp, isObject, mergeDeep, prettifyIdentifier, randomString, slugify, toArray } from "@rebasepro/utils";
11
+ import { EntityReference, EntityRelation, GeoPoint, Vector, getCollectionDataPath, getDataSourceCapabilities } from "@rebasepro/types";
11
12
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
12
- import { EntityReference, EntityRelation, GeoPoint, Vector, getDataSourceCapabilities } from "@rebasepro/types";
13
13
  import { Link, NavLink, Outlet, Route, useBlocker, useLocation, useNavigate, useSearchParams } from "react-router-dom";
14
14
  import { Highlight, themes } from "prism-react-renderer";
15
15
  import { Command } from "cmdk";
@@ -347,10 +347,10 @@ function buildBottomActions$1({ savingError, entity, path, formActions, collecti
347
347
  if (entity) action.onClick({
348
348
  view: "form",
349
349
  entity,
350
- path: path ?? collection.slug,
350
+ path: path ?? getCollectionDataPath(collection),
351
351
  collection,
352
352
  context: void 0,
353
- sideEntityController: void 0,
353
+ sidePanelController: void 0,
354
354
  openEntityMode,
355
355
  navigateBack,
356
356
  formContext
@@ -784,26 +784,32 @@ function renderSkeletonIcon() {
784
784
  */
785
785
  var StorageThumbnail = React.memo(StorageThumbnailInternal, areEqual$1);
786
786
  function areEqual$1(prevProps, nextProps) {
787
- return prevProps.size === nextProps.size && prevProps.storagePathOrDownloadUrl === nextProps.storagePathOrDownloadUrl && prevProps.storeUrl === nextProps.storeUrl && prevProps.interactive === nextProps.interactive && prevProps.fill === nextProps.fill;
787
+ return prevProps.size === nextProps.size && prevProps.storagePathOrDownloadUrl === nextProps.storagePathOrDownloadUrl && prevProps.storeUrl === nextProps.storeUrl && prevProps.interactive === nextProps.interactive && prevProps.fill === nextProps.fill && prevProps.storageSourceKey === nextProps.storageSourceKey;
788
788
  }
789
789
  var URL_CACHE = {};
790
- function StorageThumbnailInternal({ storeUrl, interactive, storagePathOrDownloadUrl, size, fill }) {
790
+ function StorageThumbnailInternal({ storeUrl, interactive, storagePathOrDownloadUrl, size, fill, storageSourceKey }) {
791
791
  const [error, setError] = React.useState(void 0);
792
- const storage = useStorageSource();
793
- const [downloadConfig, setDownloadConfig] = React.useState(URL_CACHE[storagePathOrDownloadUrl]);
792
+ const defaultStorage = useStorageSource();
793
+ const storage = resolveStorageSource({
794
+ sourceKey: storageSourceKey,
795
+ sources: useStorageSources().sources,
796
+ defaultSource: defaultStorage
797
+ });
798
+ const cacheKey = `${storageSourceKey ?? ""}::${storagePathOrDownloadUrl}`;
799
+ const [downloadConfig, setDownloadConfig] = React.useState(URL_CACHE[cacheKey]);
794
800
  useEffect(() => {
795
801
  if (!storagePathOrDownloadUrl) return;
796
802
  let unmounted = false;
797
803
  storage.getSignedUrl(storagePathOrDownloadUrl).then(function(downloadConfig) {
798
804
  if (!unmounted) {
799
805
  setDownloadConfig(downloadConfig);
800
- URL_CACHE[storagePathOrDownloadUrl] = downloadConfig;
806
+ URL_CACHE[cacheKey] = downloadConfig;
801
807
  }
802
808
  }).catch(setError);
803
809
  return () => {
804
810
  unmounted = true;
805
811
  };
806
- }, [storagePathOrDownloadUrl]);
812
+ }, [storagePathOrDownloadUrl, cacheKey]);
807
813
  if (!storagePathOrDownloadUrl) return null;
808
814
  const filetype = downloadConfig?.metadata ? getFiletype(downloadConfig?.metadata.contentType) : void 0;
809
815
  const previewType = filetype?.startsWith("image") ? "image" : filetype?.startsWith("video") ? "video" : filetype?.startsWith("audio") ? "audio" : "file";
@@ -951,7 +957,6 @@ function getDefaultIconForProperty(property) {
951
957
  if (property.ui?.url) return GlobeIcon;
952
958
  if (property.email) return MailIcon;
953
959
  if (property.ui?.multiline || property.ui?.markdown) return AlignLeftIcon;
954
- if (property.reference) return LinkIcon;
955
960
  return TextIcon;
956
961
  case "number": return HashIcon;
957
962
  case "boolean": return FlagIcon;
@@ -1054,6 +1059,21 @@ function isHiddenProperty(property) {
1054
1059
  if (!property) return false;
1055
1060
  return Boolean(property.ui?.hideFromCollection);
1056
1061
  }
1062
+ /**
1063
+ * Returns true when the property holds file-storage content (single image,
1064
+ * array of images, generic upload, …). These properties are rendered by the
1065
+ * dedicated image-slot and should NOT appear as regular preview columns.
1066
+ */
1067
+ function isStorageProperty$1(property) {
1068
+ if (!property) return false;
1069
+ if (property.type === "string" && property.storage) return true;
1070
+ if (property.type === "string" && property.ui?.url === "image") return true;
1071
+ if (property.type === "array" && property.of && !Array.isArray(property.of)) {
1072
+ const inner = property.of;
1073
+ if (inner.type === "string" && (inner.storage || inner.ui?.url === "image")) return true;
1074
+ }
1075
+ return false;
1076
+ }
1057
1077
  function getEntityPreviewKeys(authController, targetCollection, fields, previewProperties, limit = 3) {
1058
1078
  const allProperties = Object.keys(targetCollection.properties);
1059
1079
  let listProperties = previewProperties?.filter((p) => allProperties.includes(p));
@@ -1067,7 +1087,7 @@ function getEntityPreviewKeys(authController, targetCollection, fields, previewP
1067
1087
  return !(prop && typeof prop === "object" && "isId" in prop && Boolean(prop.isId)) && key !== "id";
1068
1088
  }).filter((key) => {
1069
1089
  const property = targetCollection.properties[key];
1070
- return property && !isPropertyBuilder(property) && !isReferenceProperty(property) && !isHiddenProperty(property) && (hasExplicitOrder || !isRelationProperty(property));
1090
+ return property && !isPropertyBuilder(property) && !isReferenceProperty(property) && !isHiddenProperty(property) && !isStorageProperty$1(property) && (hasExplicitOrder || !isRelationProperty(property));
1071
1091
  }).slice(0, limit);
1072
1092
  }
1073
1093
  }
@@ -1140,15 +1160,15 @@ function resolveTitleToString(title) {
1140
1160
  }
1141
1161
  }
1142
1162
  //#endregion
1143
- //#region src/components/EntityPreview.tsx
1163
+ //#region src/components/EntityPreviewBinding.tsx
1144
1164
  /**
1145
- * This component contains the main logic and content for displaying an entity preview,
1146
- * without any container wrapper. Used internally by EntityPreview.
1165
+ * This component contains the main logic and content for displaying a entity preview,
1166
+ * without any container wrapper. Used internally by EntityPreviewBinding.
1147
1167
  */
1148
- function EntityPreviewData({ actions, collection: collectionProp, previewKeys, size = "medium", includeId = true, onSideEntityClick, includeTitle = true, includeEntityLink = true, includeImage = true, entity }) {
1168
+ function EntityPreviewBindingData({ actions, collection: collectionProp, previewKeys, size = "medium", includeId = true, onSidePanelClick, includeTitle = true, includeEntityLink = true, includeImage = true, entity }) {
1149
1169
  const authController = useAuthController();
1150
1170
  const analyticsController = useAnalyticsController();
1151
- const sideEntityController = useSideEntityController();
1171
+ const sidePanelController = useSidePanel();
1152
1172
  const customizationController = useCustomizationController();
1153
1173
  const collectionRegistryController = useCollectionRegistryController();
1154
1174
  const collection = collectionProp ?? collectionRegistryController.getCollection(entity.path);
@@ -1245,12 +1265,12 @@ function EntityPreviewData({ actions, collection: collectionProp, previewKeys, s
1245
1265
  onClick: (e) => {
1246
1266
  e.stopPropagation();
1247
1267
  e.preventDefault();
1248
- onSideEntityClick?.(entity);
1268
+ onSidePanelClick?.(entity);
1249
1269
  analyticsController.onAnalyticsEvent?.("entity_click_from_reference", {
1250
1270
  path: entity.path,
1251
1271
  entityId: entity.id
1252
1272
  });
1253
- sideEntityController.open({
1273
+ sidePanelController.open({
1254
1274
  entityId: entity.id,
1255
1275
  path: entity.path,
1256
1276
  collection,
@@ -1268,15 +1288,15 @@ function EntityPreviewData({ actions, collection: collectionProp, previewKeys, s
1268
1288
  ] });
1269
1289
  }
1270
1290
  /**
1271
- * This view is used to display a preview of an entity.
1291
+ * This view is used to display a preview of a entity.
1272
1292
  * It is used by default in reference fields and whenever a reference is displayed.
1273
1293
  */
1274
- function EntityPreview({ actions, disabled, hover, collection, previewKeys, onClick, size = "medium", includeId = true, includeTitle = true, includeEntityLink = true, includeImage = true, onSideEntityClick, entity }) {
1294
+ function EntityPreviewBinding({ actions, disabled, hover, collection, previewKeys, onClick, size = "medium", includeId = true, includeTitle = true, includeEntityLink = true, includeImage = true, onSidePanelClick, entity }) {
1275
1295
  return /* @__PURE__ */ jsx(EntityPreviewContainer, {
1276
1296
  onClick: disabled ? void 0 : onClick,
1277
1297
  hover: disabled ? void 0 : hover,
1278
1298
  size,
1279
- children: /* @__PURE__ */ jsx(EntityPreviewData, {
1299
+ children: /* @__PURE__ */ jsx(EntityPreviewBindingData, {
1280
1300
  actions,
1281
1301
  collection,
1282
1302
  previewKeys,
@@ -1285,7 +1305,7 @@ function EntityPreview({ actions, disabled, hover, collection, previewKeys, onCl
1285
1305
  includeTitle,
1286
1306
  includeEntityLink,
1287
1307
  includeImage,
1288
- onSideEntityClick,
1308
+ onSidePanelClick,
1289
1309
  entity
1290
1310
  })
1291
1311
  });
@@ -1369,16 +1389,16 @@ function ReferencePreviewInternal(props) {
1369
1389
  ...props,
1370
1390
  collection
1371
1391
  });
1372
- if (collection?.components) return /* @__PURE__ */ jsx(CollectionComponentOverrideProvider, {
1373
- overrides: collection.components,
1392
+ if (collection) return /* @__PURE__ */ jsx(CollectionScopeProvider, {
1393
+ collection,
1374
1394
  children: content
1375
1395
  });
1376
1396
  return content;
1377
1397
  }
1378
1398
  function ReferencePreviewExisting({ reference, collection, previewProperties, size, disabled, includeEntityLink, includeId, onClick, hover, textOnly }) {
1379
- const ResolvedEntityPreview = useComponentOverride("Entity.Preview", EntityPreview);
1399
+ const ResolvedEntityPreview = useComponentOverride("EntityPreview", EntityPreviewBinding);
1380
1400
  const customizationController = useCustomizationController();
1381
- const { entity, dataLoading, dataLoadingError } = useEntityFetch({
1401
+ const { entity, dataLoading, dataLoadingError } = useFetch({
1382
1402
  path: reference.path,
1383
1403
  entityId: reference.id,
1384
1404
  collection,
@@ -1468,8 +1488,8 @@ function ArrayOfReferencesPreview({ propertyKey, value, property, size }) {
1468
1488
  });
1469
1489
  }
1470
1490
  //#endregion
1471
- //#region src/components/EntityView.tsx
1472
- function EntityView({ entity, collection, path, className }) {
1491
+ //#region src/components/EntityViewBinding.tsx
1492
+ function EntityViewBinding({ entity, collection, path, className }) {
1473
1493
  const customizationController = useCustomizationController();
1474
1494
  const properties = collection.properties;
1475
1495
  return /* @__PURE__ */ jsx("div", {
@@ -1540,8 +1560,8 @@ function resolvedSelectedEntityView(customViews, customizationController, select
1540
1560
  };
1541
1561
  }
1542
1562
  //#endregion
1543
- //#region src/components/EntityJsonPreview.tsx
1544
- function EntityJsonPreview({ values }) {
1563
+ //#region src/components/JsonPreviewBinding.tsx
1564
+ function JsonPreviewBinding({ values }) {
1545
1565
  const code = JSON.stringify(values, null, " ");
1546
1566
  const { mode } = useModeController();
1547
1567
  const preRef = useRef(null);
@@ -1568,17 +1588,17 @@ function EntityJsonPreview({ values }) {
1568
1588
  });
1569
1589
  }
1570
1590
  //#endregion
1571
- //#region src/util/entity_view_constants.ts
1591
+ //#region src/util/view_constants.ts
1572
1592
  /**
1573
- * Shared tab value constants used by EntityEditView and EntityDetailView.
1593
+ * Shared tab value constants used by EditViewBinding and DetailViewBinding.
1574
1594
  */
1575
1595
  var MAIN_TAB_VALUE = "__main_##Q$SC^#S6";
1576
1596
  var JSON_TAB_VALUE = "__json";
1577
1597
  //#endregion
1578
- //#region src/components/EntityDetailView.tsx
1579
- var EntityHistoryView$1 = lazy(() => import("./history-ChHgyyvM.js").then((m) => ({ default: m.EntityHistoryView })));
1580
- function EntityDetailView({ entityId, ...props }) {
1581
- const { entity, dataLoading, dataLoadingError } = useEntityFetch({
1598
+ //#region src/components/DetailViewBinding.tsx
1599
+ var EntityHistoryView$1 = lazy(() => import("./history-7X5bON_n.js").then((m) => ({ default: m.EntityHistoryView })));
1600
+ function DetailViewBinding({ entityId, ...props }) {
1601
+ const { entity, dataLoading, dataLoadingError } = useFetch({
1582
1602
  path: props.path,
1583
1603
  entityId,
1584
1604
  collection: props.collection,
@@ -1589,20 +1609,19 @@ function EntityDetailView({ entityId, ...props }) {
1589
1609
  variant: "label",
1590
1610
  children: "Entity not found"
1591
1611
  }) });
1592
- const content = /* @__PURE__ */ jsx(EntityDetailViewInner, {
1612
+ const content = /* @__PURE__ */ jsx(DetailViewBindingInner, {
1593
1613
  ...props,
1594
1614
  entityId,
1595
1615
  entity,
1596
1616
  dataLoading
1597
1617
  });
1598
- if (props.collection.components) return /* @__PURE__ */ jsx(CollectionComponentOverrideProvider, {
1599
- overrides: props.collection.components,
1618
+ return /* @__PURE__ */ jsx(CollectionScopeProvider, {
1619
+ collection: props.collection,
1600
1620
  children: content
1601
1621
  });
1602
- return content;
1603
1622
  }
1604
- function EntityDetailViewInner({ path, entityId, selectedTab: selectedTabProp, collection, parentCollectionSlugs, parentEntityIds, onTabChange, onEditClick, entity, dataLoading, layout = "full_screen", barActions }) {
1605
- const ResolvedCollectionView = useComponentOverride("Collection.View", EntityCollectionView);
1623
+ function DetailViewBindingInner({ path, entityId, selectedTab: selectedTabProp, collection, parentCollectionSlugs, parentEntityIds, onTabChange, onEditClick, entity, dataLoading, layout = "full_screen", barActions }) {
1624
+ const ResolvedCollectionView = useComponentOverride("Collection.View", CollectionViewBinding);
1606
1625
  const { t } = useTranslation();
1607
1626
  const context = useRebaseContext();
1608
1627
  const urlController = useUrlController();
@@ -1751,7 +1770,7 @@ function EntityDetailViewInner({ path, entityId, selectedTab: selectedTabProp, c
1751
1770
  const jsonView = activeTab === "__json" || jsonTabMounted ? /* @__PURE__ */ jsx("div", {
1752
1771
  className: cls("relative flex-1 h-full overflow-auto w-full", { "hidden": activeTab !== JSON_TAB_VALUE }),
1753
1772
  role: "tabpanel",
1754
- children: /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(EntityJsonPreview, { values: usedEntity?.values ?? {} }) })
1773
+ children: /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(JsonPreviewBinding, { values: usedEntity?.values ?? {} }) })
1755
1774
  }, "json_view") : null;
1756
1775
  const historyView = includeHistoryView && activeTab === "__rebase_history" ? /* @__PURE__ */ jsx("div", {
1757
1776
  className: "relative flex-1 h-full overflow-auto w-full",
@@ -1768,7 +1787,7 @@ function EntityDetailViewInner({ path, entityId, selectedTab: selectedTabProp, c
1768
1787
  }, "history_view") : null;
1769
1788
  const subCollectionsViews = subcollections && subcollections.map((subcollection) => {
1770
1789
  const subcollectionId = subcollection.slug;
1771
- const newFullPath = usedEntity ? `${path}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(subcollection.slug)}` : void 0;
1790
+ const newFullPath = usedEntity ? `${path}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(getCollectionDataPath(subcollection))}` : void 0;
1772
1791
  if (activeTab !== subcollectionId) return null;
1773
1792
  return /* @__PURE__ */ jsxs("div", {
1774
1793
  className: "relative flex-1 h-full overflow-auto w-full",
@@ -1816,7 +1835,7 @@ function EntityDetailViewInner({ path, entityId, selectedTab: selectedTabProp, c
1816
1835
  formContext: readOnlyFormContext
1817
1836
  })
1818
1837
  }) });
1819
- return /* @__PURE__ */ jsx(Fragment, { children: usedEntity && /* @__PURE__ */ jsx(EntityView, {
1838
+ return /* @__PURE__ */ jsx(Fragment, { children: usedEntity && /* @__PURE__ */ jsx(EntityViewBinding, {
1820
1839
  entity: usedEntity,
1821
1840
  collection,
1822
1841
  path
@@ -2058,44 +2077,9 @@ function DetailViewSkeleton({ collection }) {
2058
2077
  }
2059
2078
  //#endregion
2060
2079
  //#region src/components/SelectableTable/SelectionStore.ts
2061
- /**
2062
- * A ref-based selection store that avoids React context re-renders.
2063
- *
2064
- * The problem with putting `selectedCell` in a React context value is that
2065
- * ANY cell selection change triggers a context value change, which forces
2066
- * ALL consumers (every PropertyTableCell in the table) to re-render.
2067
- * This causes the DOM to be replaced between mousedown and click events,
2068
- * breaking `alwaysInteractive` cells (like relation selectors) where the
2069
- * user needs to click a button on the very first interaction.
2070
- *
2071
- * This store uses `useSyncExternalStore` so only cells whose `selected`
2072
- * derivation actually changed will re-render.
2073
- */
2074
2080
  function createSelectionStore() {
2075
- let selectedCell = void 0;
2076
- const listeners = /* @__PURE__ */ new Set();
2077
- function getSnapshot() {
2078
- return selectedCell;
2079
- }
2080
- function subscribe(listener) {
2081
- listeners.add(listener);
2082
- return () => listeners.delete(listener);
2083
- }
2084
- function select(cell) {
2085
- selectedCell = cell;
2086
- listeners.forEach((l) => l());
2087
- }
2088
- return {
2089
- getSnapshot,
2090
- subscribe,
2091
- select
2092
- };
2081
+ return createVirtualTableSelectionStore();
2093
2082
  }
2094
- /**
2095
- * Hook that subscribes a cell to the selection store and returns
2096
- * whether THIS cell is selected. Only re-renders when the cell's
2097
- * `selected` boolean actually changes (not on every store update).
2098
- */
2099
2083
  function useCellSelected(store, propertyKey, entityPath, entityId) {
2100
2084
  const selectorRef = useRef({
2101
2085
  propertyKey,
@@ -2107,79 +2091,16 @@ function useCellSelected(store, propertyKey, entityPath, entityId) {
2107
2091
  entityPath,
2108
2092
  entityId
2109
2093
  };
2110
- const getSnapshot = useCallback(() => {
2111
- const cell = store.getSnapshot();
2094
+ const getEntity = useCallback(() => {
2095
+ const cell = store.getEntity();
2112
2096
  if (!cell) return false;
2113
2097
  const s = selectorRef.current;
2114
2098
  return cell.propertyKey === s.propertyKey && cell.entityPath === s.entityPath && cell.entityId === s.entityId;
2115
2099
  }, [store]);
2116
- return useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);
2100
+ return useSyncExternalStore(store.subscribe, getEntity, getEntity);
2117
2101
  }
2118
2102
  //#endregion
2119
- //#region src/components/EntityCollectionTable/fields/VirtualTableInput.tsx
2120
- function VirtualTableInput(props) {
2121
- const ref = React.useRef(null);
2122
- const { disabled, value, multiline, updateValue, focused } = props;
2123
- const prevValue = useRef(value);
2124
- const [internalValue, setInternalValue] = useState(value);
2125
- const focusedState = useRef(false);
2126
- useEffect(() => {
2127
- if (prevValue.current !== value && value !== internalValue) setInternalValue(value);
2128
- prevValue.current = value;
2129
- }, [value]);
2130
- const doUpdate = React.useCallback(() => {
2131
- if (!value && !internalValue) return;
2132
- if (internalValue !== value && internalValue !== prevValue.current) {
2133
- prevValue.current = internalValue;
2134
- updateValue(internalValue);
2135
- }
2136
- }, [
2137
- internalValue,
2138
- updateValue,
2139
- value
2140
- ]);
2141
- useDebouncedCallback(internalValue, doUpdate, !focused, 400);
2142
- useEffect(() => {
2143
- if (ref.current && focused && !focusedState.current) {
2144
- focusedState.current = true;
2145
- ref.current.focus({ preventScroll: true });
2146
- ref.current.selectionStart = ref.current.value.length;
2147
- ref.current.selectionEnd = ref.current.value.length;
2148
- } else focusedState.current = focused;
2149
- }, [focused, ref]);
2150
- return /* @__PURE__ */ jsx(TextareaAutosize, {
2151
- className: focusedDisabled,
2152
- ref,
2153
- style: {
2154
- padding: 0,
2155
- margin: 0,
2156
- width: "100%",
2157
- color: "unset",
2158
- fontWeight: "unset",
2159
- fontSize: "unset",
2160
- fontFamily: "unset",
2161
- background: "unset",
2162
- border: "unset",
2163
- resize: "none",
2164
- outline: "none"
2165
- },
2166
- value: internalValue ?? "",
2167
- onChange: (evt) => {
2168
- const newValue = evt.target.value;
2169
- if (multiline || !newValue.endsWith("\n")) setInternalValue(newValue);
2170
- },
2171
- onFocus: () => {
2172
- focusedState.current = true;
2173
- },
2174
- onBlur: () => {
2175
- focusedState.current = false;
2176
- doUpdate();
2177
- if (props.onBlur) props.onBlur();
2178
- }
2179
- });
2180
- }
2181
- //#endregion
2182
- //#region src/components/EntityCollectionTable/fields/VirtualTableSelect.tsx
2103
+ //#region src/components/CollectionTableBinding/fields/VirtualTableSelect.tsx
2183
2104
  function VirtualTableSelect(props) {
2184
2105
  const { enumValues, internalValue, disabled, small, focused, updateValue, multiple, valueType } = props;
2185
2106
  const validValue = Array.isArray(internalValue) && multiple || !Array.isArray(internalValue) && !multiple;
@@ -2252,78 +2173,6 @@ function VirtualTableSelect(props) {
2252
2173
  });
2253
2174
  }
2254
2175
  //#endregion
2255
- //#region src/components/EntityCollectionTable/fields/VirtualTableNumberInput.tsx
2256
- function VirtualTableNumberInput(props) {
2257
- const { align, value, updateValue, focused } = props;
2258
- const propStringValue = value && typeof value === "number" ? value.toString() : "";
2259
- const [internalValue, setInternalValue] = useState(propStringValue);
2260
- const prevValue = useRef(value);
2261
- useEffect(() => {
2262
- if (prevValue.current !== value && String(value) !== internalValue) setInternalValue(value ? value.toString() : null);
2263
- prevValue.current = value;
2264
- }, [value]);
2265
- useDebouncedCallback(internalValue, React.useCallback(() => {
2266
- if (internalValue !== propStringValue) if (internalValue !== void 0 && internalValue !== null) {
2267
- const numberValue = parseFloat(internalValue);
2268
- if (isNaN(numberValue)) return;
2269
- if (numberValue !== void 0 && numberValue !== null) updateValue(numberValue);
2270
- } else updateValue(null);
2271
- }, [internalValue, value]), !focused, 400);
2272
- useEffect(() => {
2273
- if (!focused && propStringValue !== internalValue) setInternalValue(value !== void 0 && value !== null ? value.toString() : null);
2274
- }, [value, focused]);
2275
- const inputRef = React.useRef(null);
2276
- useEffect(() => {
2277
- if (inputRef.current && focused) inputRef.current.focus({ preventScroll: true });
2278
- }, [focused, inputRef]);
2279
- const regexp = /^-?[0-9]+[,.]?[0-9]*$/;
2280
- return /* @__PURE__ */ jsx(TextField, {
2281
- inputRef,
2282
- invisible: true,
2283
- size: "small",
2284
- className: "w-full",
2285
- inputClassName: cls("p-0 m-0 bg-transparent border-none outline-hidden font-normal leading-normal text-unset", focusedDisabled),
2286
- inputStyle: { textAlign: align },
2287
- value: internalValue ?? "",
2288
- onChange: (evt) => {
2289
- const newValue = evt.target.value.replace(",", ".");
2290
- if (newValue.length === 0) setInternalValue(null);
2291
- if (regexp.test(newValue) || newValue.startsWith("-")) setInternalValue(newValue);
2292
- }
2293
- });
2294
- }
2295
- //#endregion
2296
- //#region src/components/EntityCollectionTable/fields/VirtualTableSwitch.tsx
2297
- function VirtualTableSwitch(props) {
2298
- const { internalValue, updateValue, focused } = props;
2299
- const ref = React.useRef(null);
2300
- useEffect(() => {
2301
- if (ref.current && focused) ref.current.focus({ preventScroll: true });
2302
- }, [focused, ref]);
2303
- return /* @__PURE__ */ jsx(BooleanSwitch, {
2304
- ref,
2305
- size: "small",
2306
- value: Boolean(internalValue),
2307
- onValueChange: updateValue
2308
- });
2309
- }
2310
- //#endregion
2311
- //#region src/components/EntityCollectionTable/fields/VirtualTableDateField.tsx
2312
- function VirtualTableDateField(props) {
2313
- const { locale } = useCustomizationController();
2314
- const { disabled, error, mode, timezone, internalValue, updateValue } = props;
2315
- return /* @__PURE__ */ jsx(DateTimeField, {
2316
- value: internalValue ?? void 0,
2317
- onChange: (dateValue) => updateValue(dateValue ?? null),
2318
- invisible: true,
2319
- inputClassName: cls("w-full h-full", focusedDisabled),
2320
- className: cls("w-full h-full", focusedDisabled),
2321
- mode,
2322
- timezone,
2323
- locale
2324
- });
2325
- }
2326
- //#endregion
2327
2176
  //#region src/components/UserSelector.tsx
2328
2177
  var DEFAULT_PAGE_SIZE$2 = 10;
2329
2178
  /**
@@ -2639,7 +2488,7 @@ var UserSelector = React$1.forwardRef(({ value, size = "medium", onValueChange,
2639
2488
  });
2640
2489
  UserSelector.displayName = "UserSelector";
2641
2490
  //#endregion
2642
- //#region src/components/EntityCollectionTable/fields/VirtualTableUserSelect.tsx
2491
+ //#region src/components/CollectionTableBinding/fields/VirtualTableUserSelect.tsx
2643
2492
  function VirtualTableUserSelect(props) {
2644
2493
  const { internalValue, disabled, small, focused, updateValue, multiple } = props;
2645
2494
  return /* @__PURE__ */ jsx(UserSelector, {
@@ -2655,8 +2504,9 @@ function VirtualTableUserSelect(props) {
2655
2504
  }
2656
2505
  //#endregion
2657
2506
  //#region src/form/components/StorageUploadProgress.tsx
2658
- function StorageUploadProgress({ storagePath, entry, metadata, onFileUploadComplete, imageSize, simple }) {
2659
- const storageSource = useStorageSource();
2507
+ function StorageUploadProgress({ storagePath, entry, metadata, onFileUploadComplete, imageSize, simple, storageSource: storageSourceProp }) {
2508
+ const defaultStorageSource = useStorageSource();
2509
+ const storageSource = storageSourceProp ?? defaultStorageSource;
2660
2510
  const snackbarController = useSnackbarController();
2661
2511
  const [error, setError] = React.useState();
2662
2512
  const [loading, setLoading] = React.useState(false);
@@ -2720,7 +2570,7 @@ function StorageUploadProgress({ storagePath, entry, metadata, onFileUploadCompl
2720
2570
  });
2721
2571
  }
2722
2572
  //#endregion
2723
- //#region src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx
2573
+ //#region src/components/CollectionTableBinding/internal/EntityTableCellActions.tsx
2724
2574
  function EntityTableCellActions({ showError, disabled, showExpandIcon, selected, openPopup, children }) {
2725
2575
  const ref = useRef(null);
2726
2576
  const doOpenPopup = useCallback(() => {
@@ -2770,7 +2620,7 @@ function EntityTableCellActions({ showError, disabled, showExpandIcon, selected,
2770
2620
  }) });
2771
2621
  }
2772
2622
  //#endregion
2773
- //#region src/components/EntityCollectionTable/fields/TableStorageUpload.tsx
2623
+ //#region src/components/CollectionTableBinding/fields/TableStorageUpload.tsx
2774
2624
  var dropZoneClasses$1 = "max-w-full box-border relative pt-[2px] items-center border border-transparent outline-hidden rounded-md duration-200 ease-[cubic-bezier(0.4,0,0.2,1)] focus:border-primary-solid";
2775
2625
  var activeDropClasses$1 = "pt-0 border-2 border-solid";
2776
2626
  var acceptDropClasses$1 = "transition-colors duration-200 ease-[cubic-bezier(0,0,0.2,1)] border-2 border-solid border-green-500 bg-green-50 dark:bg-green-900";
@@ -2785,7 +2635,7 @@ var rejectDropClasses$1 = "transition-colors duration-200 ease-[cubic-bezier(0,0
2785
2635
  function TableStorageUpload(props) {
2786
2636
  const { propertyKey, error, selected, openPopup, value, disabled, property, entity, path, previewSize, updateValue } = props;
2787
2637
  const storageSource = useStorageSource();
2788
- const { internalValue, setInternalValue, onFilesAdded, storage, onFileUploadComplete, storagePathBuilder, multipleFilesSupported } = useStorageUploadController({
2638
+ const { internalValue, setInternalValue, onFilesAdded, storage, onFileUploadComplete, storagePathBuilder, multipleFilesSupported, resolvedStorageSource } = useStorageUploadController({
2789
2639
  entityValues: entity.values,
2790
2640
  entityId: entity.id,
2791
2641
  path,
@@ -2796,24 +2646,27 @@ function TableStorageUpload(props) {
2796
2646
  value,
2797
2647
  disabled
2798
2648
  });
2799
- return /* @__PURE__ */ jsx(StorageUpload$1, {
2800
- internalValue,
2801
- setInternalValue,
2802
- name: propertyKey,
2803
- disabled,
2804
- autoFocus: false,
2805
- openPopup,
2806
- error,
2807
- selected,
2808
- property,
2809
- onChange: updateValue,
2810
- entity,
2811
- storagePathBuilder,
2812
- storage,
2813
- multipleFilesSupported,
2814
- onFilesAdded,
2815
- onFileUploadComplete,
2816
- previewSize
2649
+ return /* @__PURE__ */ jsx(StorageSourceContext.Provider, {
2650
+ value: resolvedStorageSource,
2651
+ children: /* @__PURE__ */ jsx(StorageUpload$1, {
2652
+ internalValue,
2653
+ setInternalValue,
2654
+ name: propertyKey,
2655
+ disabled,
2656
+ autoFocus: false,
2657
+ openPopup,
2658
+ error,
2659
+ selected,
2660
+ property,
2661
+ onChange: updateValue,
2662
+ entity,
2663
+ storagePathBuilder,
2664
+ storage,
2665
+ multipleFilesSupported,
2666
+ onFilesAdded,
2667
+ onFileUploadComplete,
2668
+ previewSize
2669
+ })
2817
2670
  });
2818
2671
  }
2819
2672
  function StorageUpload$1({ property, name, internalValue, setInternalValue, openPopup, entity, selected, error, onChange, multipleFilesSupported, previewSize: previewSizeInput, disabled, autoFocus, storage, onFilesAdded, onFileUploadComplete, storagePathBuilder }) {
@@ -2923,7 +2776,7 @@ function TableStorageItemPreview({ propertyKey, property, value, size, entity })
2923
2776
  });
2924
2777
  }
2925
2778
  //#endregion
2926
- //#region src/hooks/useEntitySelectionDialog.tsx
2779
+ //#region src/hooks/useSelectionDialog.tsx
2927
2780
  /**
2928
2781
  * This hook is used to open a side dialog that allows the selection
2929
2782
  * of entities under a given path.
@@ -2934,17 +2787,17 @@ function TableStorageItemPreview({ propertyKey, property, value, size, entity })
2934
2787
  * This is the same hook used internally when a reference property is defined.
2935
2788
  * @group Hooks and utilities
2936
2789
  */
2937
- function useEntitySelectionDialog(referenceDialogProps) {
2790
+ function useSelectionDialog(referenceDialogProps) {
2938
2791
  const navigation = useCollectionRegistryController();
2939
2792
  const sideDialogsController = useSideDialogsController();
2940
2793
  const open = useCallback(() => {
2941
2794
  if (referenceDialogProps.path) {
2942
2795
  let usedCollection = referenceDialogProps.collection;
2943
2796
  if (!usedCollection) usedCollection = navigation.getCollection(referenceDialogProps.path);
2944
- if (!usedCollection) throw Error("Not able to resolve the collection in useEntitySelectionDialog. Make sure a collection is registered in path " + referenceDialogProps.path);
2797
+ if (!usedCollection) throw Error("Not able to resolve the collection in useSelectionDialog. Make sure a collection is registered in path " + referenceDialogProps.path);
2945
2798
  sideDialogsController.open({
2946
2799
  key: `reference_${referenceDialogProps.path}`,
2947
- component: /* @__PURE__ */ jsx(EntitySelectionTable, {
2800
+ component: /* @__PURE__ */ jsx(SelectionTableBinding, {
2948
2801
  collection: usedCollection,
2949
2802
  ...referenceDialogProps
2950
2803
  }),
@@ -2968,7 +2821,7 @@ function useEntitySelectionDialog(referenceDialogProps) {
2968
2821
  }), [open, close]);
2969
2822
  }
2970
2823
  //#endregion
2971
- //#region src/components/EntityCollectionTable/fields/TableReferenceField.tsx
2824
+ //#region src/components/CollectionTableBinding/fields/TableReferenceField.tsx
2972
2825
  var DefaultMissingReference$1 = () => null;
2973
2826
  function TableReferenceFieldResolver(props) {
2974
2827
  const ResolvedMissingReference = useComponentOverride("Entity.MissingReference", DefaultMissingReference$1);
@@ -2988,8 +2841,8 @@ function TableReferenceField(props) {
2988
2841
  ...props,
2989
2842
  collection
2990
2843
  });
2991
- if (collection?.components) return /* @__PURE__ */ jsx(CollectionComponentOverrideProvider, {
2992
- overrides: collection.components,
2844
+ if (collection) return /* @__PURE__ */ jsx(CollectionScopeProvider, {
2845
+ collection,
2993
2846
  children: content
2994
2847
  });
2995
2848
  return content;
@@ -2999,7 +2852,7 @@ var TableReferenceFieldInternal = React.memo(function TableReferenceFieldInterna
2999
2852
  const onSingleEntitySelected = useCallback((entity) => {
3000
2853
  updateValue(entity ? getReferenceFrom(entity) : null);
3001
2854
  }, [updateValue]);
3002
- const referenceDialogController = useEntitySelectionDialog({
2855
+ const referenceDialogController = useSelectionDialog({
3003
2856
  multiselect,
3004
2857
  path,
3005
2858
  collection,
@@ -3067,7 +2920,7 @@ var TableReferenceFieldInternal = React.memo(function TableReferenceFieldInterna
3067
2920
  });
3068
2921
  }, deepEqual);
3069
2922
  //#endregion
3070
- //#region src/components/EntityCollectionTable/fields/TableMultipleRelationField.tsx
2923
+ //#region src/components/CollectionTableBinding/fields/TableMultipleRelationField.tsx
3071
2924
  function TableMultipleRelationField(props) {
3072
2925
  const collection = props.relation.target();
3073
2926
  return /* @__PURE__ */ jsx(TableMultipleRelationFieldInternal, {
@@ -3082,9 +2935,9 @@ var TableMultipleRelationFieldInternal = React.memo(function TableMultipleRelati
3082
2935
  updateValue(entities.map((e) => getRelationFrom(e)));
3083
2936
  }, [updateValue]);
3084
2937
  const selectedEntityIds = value.map((ref) => ref.id);
3085
- const relationDialogController = useEntitySelectionDialog({
2938
+ const relationDialogController = useSelectionDialog({
3086
2939
  multiselect: true,
3087
- path: collection.slug,
2940
+ path: getCollectionDataPath(collection),
3088
2941
  collection,
3089
2942
  onMultipleEntitiesSelected,
3090
2943
  selectedEntityIds,
@@ -3126,7 +2979,7 @@ var TableMultipleRelationFieldInternal = React.memo(function TableMultipleRelati
3126
2979
  });
3127
2980
  }, deepEqual);
3128
2981
  //#endregion
3129
- //#region src/components/EntityCollectionTable/fields/TableRelationField.tsx
2982
+ //#region src/components/CollectionTableBinding/fields/TableRelationField.tsx
3130
2983
  function TableRelationField(props) {
3131
2984
  const collection = props.relation.target();
3132
2985
  if (props.relation?.cardinality === "many") return /* @__PURE__ */ jsx(TableMultipleRelationField, {
@@ -3156,9 +3009,9 @@ var TableRelationFieldInternal = React.memo(function TableRelationFieldInternal(
3156
3009
  updateValue(entities.map((e) => getRelationFrom(e)));
3157
3010
  }, [updateValue]);
3158
3011
  const selectedEntityIds = internalValue ? Array.isArray(internalValue) ? internalValue.map((ref) => ref.id) : internalValue.id ? [internalValue.id] : [] : [];
3159
- const relationDialogController = useEntitySelectionDialog({
3012
+ const relationDialogController = useSelectionDialog({
3160
3013
  multiselect,
3161
- path: collection.slug,
3014
+ path: getCollectionDataPath(collection),
3162
3015
  collection,
3163
3016
  onMultipleEntitiesSelected,
3164
3017
  onSingleEntitySelected,
@@ -3221,22 +3074,22 @@ var TableRelationFieldInternal = React.memo(function TableRelationFieldInternal(
3221
3074
  });
3222
3075
  }, deepEqual);
3223
3076
  //#endregion
3224
- //#region src/hooks/useSideEntityController.tsx
3225
- var SideEntityControllerContext = React.createContext({});
3077
+ //#region src/hooks/useSidePanel.tsx
3078
+ var SidePanelControllerContext = React.createContext({});
3226
3079
  /**
3227
- * Use this hook to retrieve an entity controller that allows you to open
3228
- * a side dialog to edit an entity.
3080
+ * Use this hook to retrieve a entity controller that allows you to open
3081
+ * a side dialog to edit a entity.
3229
3082
  *
3230
- * @see SideEntityController
3083
+ * @see SidePanelController
3231
3084
  * @group Hooks and utilities
3232
3085
  */
3233
- var useSideEntityController = () => useContext(SideEntityControllerContext);
3086
+ var useSidePanel = () => useContext(SidePanelControllerContext);
3234
3087
  //#endregion
3235
3088
  //#region src/components/RelationSelector.tsx
3236
3089
  var RelationSelector = React$1.forwardRef(({ value, size = "medium", onValueChange, invisible, disabled, placeholder, useChips = true, className, relation, fixedFilter, pageSize, emptyPlaceholder, searchPlaceholder = "Search...", noResultsText = "No relations found.", loadingText = "Loading..." }, ref) => {
3237
3090
  const collection = relation.target();
3238
3091
  const dataClient = useData();
3239
- const sideEntityController = useSideEntityController();
3092
+ const sidePanelController = useSidePanel();
3240
3093
  const multiple = relation.cardinality === "many";
3241
3094
  const [isPopoverOpen, setIsPopoverOpen] = useState(false);
3242
3095
  const isPopoverOpenRef = useRef(false);
@@ -3246,7 +3099,7 @@ var RelationSelector = React$1.forwardRef(({ value, size = "medium", onValueChan
3246
3099
  const localSelectionIdsRef = useRef(null);
3247
3100
  const pinnedIdsRef = useRef(null);
3248
3101
  const { items: availableItems, isLoading, hasMore, search, loadMore, entityToRelationItem } = useRelationSelector({
3249
- path: collection.slug,
3102
+ path: getCollectionDataPath(collection),
3250
3103
  collection,
3251
3104
  fixedFilter,
3252
3105
  pageSize
@@ -3520,12 +3373,12 @@ var RelationSelector = React$1.forwardRef(({ value, size = "medium", onValueChan
3520
3373
  children: selectedItems.map((item) => {
3521
3374
  if (!useChips || !multiple) return /* @__PURE__ */ jsx("div", {
3522
3375
  className: "flex flex-row items-center gap-1 truncate",
3523
- children: item.data ? /* @__PURE__ */ jsx(EntityPreviewData, {
3376
+ children: item.data ? /* @__PURE__ */ jsx(EntityPreviewBindingData, {
3524
3377
  size: "medium",
3525
3378
  entity: item.data,
3526
3379
  includeEntityLink: false,
3527
3380
  includeId: false,
3528
- onSideEntityClick: closePopover
3381
+ onSidePanelClick: closePopover
3529
3382
  }) : /* @__PURE__ */ jsx("span", {
3530
3383
  className: "text-sm truncate",
3531
3384
  children: item.label
@@ -3534,7 +3387,7 @@ var RelationSelector = React$1.forwardRef(({ value, size = "medium", onValueChan
3534
3387
  return /* @__PURE__ */ jsxs(Chip, {
3535
3388
  size: "small",
3536
3389
  className: cls("flex flex-row items-center gap-1 truncate"),
3537
- children: [item.data ? /* @__PURE__ */ jsx(EntityPreviewData, {
3390
+ children: [item.data ? /* @__PURE__ */ jsx(EntityPreviewBindingData, {
3538
3391
  size: "smallest",
3539
3392
  entity: item.data,
3540
3393
  includeEntityLink: false,
@@ -3568,7 +3421,7 @@ var RelationSelector = React$1.forwardRef(({ value, size = "medium", onValueChan
3568
3421
  e.preventDefault();
3569
3422
  const entity = selectedItems[0].data;
3570
3423
  setIsPopoverOpen(false);
3571
- sideEntityController.open({
3424
+ sidePanelController.open({
3572
3425
  entityId: entity.id,
3573
3426
  path: entity.path,
3574
3427
  collection,
@@ -3670,7 +3523,7 @@ var RelationSelector = React$1.forwardRef(({ value, size = "medium", onValueChan
3670
3523
  className: cls("flex flex-row items-center gap-1.5 m-1 p-1 rounded-xs cursor-pointer ring-offset-transparent", isSelected && "bg-surface-accent-200 dark:bg-surface-accent-950", "aria-selected:outline-hidden aria-selected:ring-2 aria-selected:ring-primary/75 aria-selected:ring-offset-2 aria-selected:bg-surface-accent-100 dark:aria-selected:bg-surface-accent-900"),
3671
3524
  children: [multiple && /* @__PURE__ */ jsx(InnerCheckBox, { checked: isSelected }), item.data ? /* @__PURE__ */ jsx("div", {
3672
3525
  className: "flex flex-row items-center gap-2 min-w-0 w-full",
3673
- children: /* @__PURE__ */ jsx(EntityPreviewData, {
3526
+ children: /* @__PURE__ */ jsx(EntityPreviewBindingData, {
3674
3527
  size: multiple ? "smallest" : "medium",
3675
3528
  entity: item.data,
3676
3529
  includeId: false,
@@ -3720,7 +3573,7 @@ function InnerCheckBox({ checked }) {
3720
3573
  });
3721
3574
  }
3722
3575
  //#endregion
3723
- //#region src/components/EntityCollectionTable/fields/TableRelationSelectorField.tsx
3576
+ //#region src/components/CollectionTableBinding/fields/TableRelationSelectorField.tsx
3724
3577
  /** Thin wrapper around RelationSelector for table cells */
3725
3578
  function TableRelationSelectorField({ disabled = false, internalValue, updateValue, relation, fixedFilter, size = "medium" }) {
3726
3579
  return /* @__PURE__ */ jsx(RelationSelector, {
@@ -3733,7 +3586,7 @@ function TableRelationSelectorField({ disabled = false, internalValue, updateVal
3733
3586
  });
3734
3587
  }
3735
3588
  //#endregion
3736
- //#region src/components/EntityCollectionTable/table_bindings.tsx
3589
+ //#region src/components/CollectionTableBinding/table_bindings.tsx
3737
3590
  function isStorageProperty(property) {
3738
3591
  if (property.type === "string" && property.ui?.markdown) return false;
3739
3592
  if (property.type === "string" && property.storage) return true;
@@ -3742,32 +3595,7 @@ function isStorageProperty(property) {
3742
3595
  return false;
3743
3596
  }
3744
3597
  function getTableBindingForProperty(property, selected) {
3745
- const isAStorageProperty = isStorageProperty(property);
3746
- if (property.type === "string" && property.reference?.path) return {
3747
- Component: ({ propertyKey, property, internalValue, updateValue, disabled, size, path }) => {
3748
- const referenceProperty = property.reference;
3749
- if (!referenceProperty) return null;
3750
- return /* @__PURE__ */ jsx(TableReferenceField, {
3751
- name: propertyKey,
3752
- internalValue: internalValue ? new EntityReference({
3753
- id: internalValue,
3754
- path: referenceProperty.path
3755
- }) : void 0,
3756
- updateValue: (v) => updateValue(v ? v.id : null),
3757
- disabled,
3758
- size,
3759
- path: referenceProperty.path,
3760
- multiselect: false,
3761
- previewProperties: referenceProperty.ui?.previewProperties,
3762
- includeId: referenceProperty.includeId,
3763
- includeEntityLink: referenceProperty.includeEntityLink,
3764
- title: property.name,
3765
- fixedFilter: referenceProperty.fixedFilter
3766
- });
3767
- },
3768
- allowScroll: false
3769
- };
3770
- else if (isAStorageProperty) return {
3598
+ if (isStorageProperty(property)) return {
3771
3599
  Component: ({ validationError, error, disabled, selected, openPopup, property, entity, path, internalValue, size, updateValue, propertyKey }) => /* @__PURE__ */ jsx(TableStorageUpload, {
3772
3600
  error: validationError ?? error,
3773
3601
  disabled,
@@ -3845,7 +3673,7 @@ function getTableBindingForProperty(property, selected) {
3845
3673
  }),
3846
3674
  fullHeight: true
3847
3675
  };
3848
- else if (stringProperty.ui?.markdown || !stringProperty.storage || !stringProperty.reference) {
3676
+ else if (stringProperty.ui?.markdown || !stringProperty.storage) {
3849
3677
  const multiline = Boolean(stringProperty.ui?.multiline) || Boolean(stringProperty.ui?.markdown);
3850
3678
  return {
3851
3679
  Component: ({ error, validationError, disabled, selected, internalValue, updateValue }) => /* @__PURE__ */ jsx(VirtualTableInput, {
@@ -3867,15 +3695,19 @@ function getTableBindingForProperty(property, selected) {
3867
3695
  updateValue
3868
3696
  }) };
3869
3697
  else if (property.type === "date") return {
3870
- Component: ({ propertyKey, error, validationError, disabled, selected, property, internalValue, updateValue }) => /* @__PURE__ */ jsx(VirtualTableDateField, {
3871
- name: propertyKey,
3872
- error: validationError ?? error,
3873
- disabled,
3874
- mode: property.mode,
3875
- focused: selected,
3876
- internalValue,
3877
- updateValue
3878
- }),
3698
+ Component: ({ propertyKey, error, validationError, disabled, selected, property, internalValue, updateValue }) => {
3699
+ const { locale } = useCustomizationController();
3700
+ return /* @__PURE__ */ jsx(VirtualTableDateField, {
3701
+ name: propertyKey,
3702
+ error: validationError ?? error,
3703
+ disabled,
3704
+ mode: property.mode,
3705
+ focused: selected,
3706
+ internalValue,
3707
+ updateValue,
3708
+ locale
3709
+ });
3710
+ },
3879
3711
  fullHeight: true,
3880
3712
  hideOverflow: false,
3881
3713
  allowScroll: false
@@ -3987,7 +3819,7 @@ function RelationSelectorBindingComponent({ propertyKey, internalValue, updateVa
3987
3819
  });
3988
3820
  }
3989
3821
  //#endregion
3990
- //#region src/components/EntityCollectionTable/internal/EntityTableCell.tsx
3822
+ //#region src/components/CollectionTableBinding/internal/EntityTableCell.tsx
3991
3823
  var TableCellInner = ({ justifyContent, scrollable, faded, fullHeight, children }) => {
3992
3824
  return /* @__PURE__ */ jsx("div", {
3993
3825
  className: cls("flex flex-col max-h-full w-full", { "items-start": faded || scrollable }),
@@ -4148,7 +3980,7 @@ function useClearRestoreValue({ property, value, setValue }) {
4148
3980
  }, [property]);
4149
3981
  }
4150
3982
  //#endregion
4151
- //#region src/components/EntityCollectionTable/PropertyTableCell.tsx
3983
+ //#region src/components/CollectionTableBinding/PropertyTableCell.tsx
4152
3984
  var PropertyTableCell = React.memo(function PropertyTableCell({ propertyKey, customFieldValidator, value, property, align, width, height, path, entity, readonly, disabled: disabledProp, enablePopupIcon = true, sortableNodeRef, sortableStyle, sortableAttributes, isDragging, isDraggable, frozen }) {
4153
3985
  const { onValueChange, size, selectionStore, select, setPopupCell } = useSelectableTableController();
4154
3986
  const dummySelectionStore = useMemo(() => createSelectionStore(), []);
@@ -4364,7 +4196,7 @@ function areEqual(prevProps, nextProps) {
4364
4196
  return prevProps.height === nextProps.height && prevProps.propertyKey === nextProps.propertyKey && prevProps.align === nextProps.align && prevProps.width === nextProps.width && deepEqual(prevProps.property, nextProps.property) && deepEqual(prevProps.value, nextProps.value) && prevProps.entity.id === nextProps.entity.id && prevProps.entity.path === nextProps.entity.path && prevProps.isDragging === nextProps.isDragging && prevProps.isDraggable === nextProps.isDraggable && prevProps.frozen === nextProps.frozen;
4365
4197
  }
4366
4198
  //#endregion
4367
- //#region src/components/EntityCollectionTable/EntityCollectionRowActions.tsx
4199
+ //#region src/components/CollectionTableBinding/CollectionRowActions.tsx
4368
4200
  /**
4369
4201
  *
4370
4202
  * @param entity
@@ -4378,9 +4210,9 @@ function areEqual(prevProps, nextProps) {
4378
4210
  *
4379
4211
  * @group Collection components
4380
4212
  */
4381
- var EntityCollectionRowActions = function EntityCollectionRowActions({ entity, collection, path, width, frozen, isSelected, selectionEnabled, size, highlightEntity, onCollectionChange, unhighlightEntity, actions = [], hideId, selectionController, openEntityMode, sortableNodeRef, sortableStyle, sortableAttributes, isDragging, isDraggable }) {
4213
+ var CollectionRowActions = function CollectionRowActions({ entity, collection, path, width, frozen, isSelected, selectionEnabled, size, highlightEntity, onCollectionChange, unhighlightEntity, actions = [], hideId, selectionController, openEntityMode, sortableNodeRef, sortableStyle, sortableAttributes, isDragging, isDraggable }) {
4382
4214
  const context = useCMSContext();
4383
- const sideEntityCtrl = context.sideEntityController;
4215
+ const sidePanelCtrl = context.sidePanelController;
4384
4216
  const { t } = useTranslation();
4385
4217
  const onCheckedChange = useCallback((checked) => {
4386
4218
  selectionController?.toggleEntitySelection(entity, checked);
@@ -4417,7 +4249,7 @@ var EntityCollectionRowActions = function EntityCollectionRowActions({ entity, c
4417
4249
  path,
4418
4250
  collection,
4419
4251
  context,
4420
- sideEntityController: sideEntityCtrl,
4252
+ sidePanelController: sidePanelCtrl,
4421
4253
  selectionController,
4422
4254
  highlightEntity,
4423
4255
  unhighlightEntity,
@@ -4452,7 +4284,7 @@ var EntityCollectionRowActions = function EntityCollectionRowActions({ entity, c
4452
4284
  path,
4453
4285
  collection,
4454
4286
  context,
4455
- sideEntityController: sideEntityCtrl,
4287
+ sidePanelController: sidePanelCtrl,
4456
4288
  selectionController,
4457
4289
  highlightEntity,
4458
4290
  unhighlightEntity,
@@ -4496,7 +4328,7 @@ var EntityCollectionRowActions = function EntityCollectionRowActions({ entity, c
4496
4328
  return content;
4497
4329
  };
4498
4330
  //#endregion
4499
- //#region src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx
4331
+ //#region src/components/CollectionTableBinding/internal/CollectionTableToolbar.tsx
4500
4332
  function CollectionTableToolbar({ actions, actionsStart, loading, onTextSearch, title, viewModeToggle, initialSearchText, compact = false }) {
4501
4333
  const largeLayout = useLargeLayout();
4502
4334
  const { t } = useTranslation();
@@ -4539,7 +4371,7 @@ function CollectionTableToolbar({ actions, actionsStart, loading, onTextSearch,
4539
4371
  });
4540
4372
  }
4541
4373
  //#endregion
4542
- //#region src/components/EntityCollectionTable/internal/common.tsx
4374
+ //#region src/components/CollectionTableBinding/internal/common.tsx
4543
4375
  function getTableCellAlignment(property) {
4544
4376
  if (property.type === "boolean") return "center";
4545
4377
  else if (property.type === "number") {
@@ -4576,7 +4408,7 @@ function getSubcollectionColumnId(collection) {
4576
4408
  return `subcollection:${collection.slug}`;
4577
4409
  }
4578
4410
  //#endregion
4579
- //#region src/components/EntityCollectionTable/column_utils.tsx
4411
+ //#region src/components/CollectionTableBinding/column_utils.tsx
4580
4412
  function propertiesToColumns({ properties, sortable, fixedFilter, AdditionalHeaderWidget }) {
4581
4413
  const disabledFilter = Boolean(fixedFilter);
4582
4414
  return Object.entries(properties).flatMap(([key, property]) => getColumnKeysForProperty(property, key)).map(({ key, disabled }) => {
@@ -4625,140 +4457,8 @@ function filterableProperty(property, partOfArray = false) {
4625
4457
  ].includes(property.type);
4626
4458
  }
4627
4459
  //#endregion
4628
- //#region src/components/SelectableTable/filters/ReferenceFilterField.tsx
4629
- var operationLabels$3 = {
4630
- "==": "==",
4631
- "!=": "!=",
4632
- ">": ">",
4633
- "<": "<",
4634
- ">=": ">=",
4635
- "<=": "<=",
4636
- in: "In",
4637
- "not-in": "Not in",
4638
- "array-contains": "Contains",
4639
- "array-contains-any": "Contains Any"
4640
- };
4641
- var multipleSelectOperations$3 = [
4642
- "array-contains-any",
4643
- "in",
4644
- "not-in"
4645
- ];
4646
- function ReferenceFilterField({ value, setValue, isArray, path, includeId = true, previewProperties, setHidden }) {
4647
- const { t } = useTranslation();
4648
- const possibleOperations = isArray ? ["array-contains"] : [
4649
- "==",
4650
- "!=",
4651
- ">",
4652
- "<",
4653
- ">=",
4654
- "<="
4655
- ];
4656
- if (isArray) possibleOperations.push("array-contains-any");
4657
- else possibleOperations.push("in", "not-in");
4658
- const [fieldOperation, fieldValue] = value || [possibleOperations[0], void 0];
4659
- const [operation, setOperation] = useState(fieldOperation);
4660
- const [internalValue, setInternalValue] = useState(fieldValue);
4661
- const selectedEntityIds = internalValue ? Array.isArray(internalValue) ? internalValue.map((ref) => {
4662
- if (!(ref?.isEntityReference && ref?.isEntityReference())) return null;
4663
- return ref.id;
4664
- }).filter(Boolean) : [internalValue.id] : [];
4665
- function updateFilter(op, val) {
4666
- const prevOpIsArray = multipleSelectOperations$3.includes(operation);
4667
- const newOpIsArray = multipleSelectOperations$3.includes(op);
4668
- let newValue = val;
4669
- if (prevOpIsArray !== newOpIsArray) newValue = newOpIsArray ? newValue && !Array.isArray(newValue) && newValue.isEntityReference?.() ? [newValue] : [] : void 0;
4670
- setOperation(op);
4671
- setInternalValue(newValue);
4672
- const hasNewValue = newValue !== null && Array.isArray(newValue) ? newValue.length > 0 : newValue !== void 0;
4673
- if (op && hasNewValue) setValue([op, newValue]);
4674
- else setValue(void 0);
4675
- }
4676
- const collectionRegistryController = useCollectionRegistryController();
4677
- const collection = useMemo(() => {
4678
- return path ? collectionRegistryController.getCollection(path) : void 0;
4679
- }, [path]);
4680
- const onSingleEntitySelected = (entity) => {
4681
- updateFilter(operation, getReferenceFrom(entity));
4682
- };
4683
- const onMultipleEntitiesSelected = (entities) => {
4684
- updateFilter(operation, entities.map((e) => getReferenceFrom(e)));
4685
- };
4686
- const multiple = multipleSelectOperations$3.includes(operation);
4687
- const referenceDialogController = useEntitySelectionDialog({
4688
- multiselect: multiple,
4689
- path,
4690
- collection,
4691
- onSingleEntitySelected,
4692
- onMultipleEntitiesSelected,
4693
- selectedEntityIds,
4694
- onClose: () => {
4695
- setHidden(false);
4696
- }
4697
- });
4698
- const doOpenDialog = () => {
4699
- setHidden(true);
4700
- referenceDialogController.open();
4701
- };
4702
- const buildEntry = (reference) => {
4703
- return /* @__PURE__ */ jsx(ReferencePreview, {
4704
- disabled: !path,
4705
- previewProperties,
4706
- size: "medium",
4707
- onClick: doOpenDialog,
4708
- reference,
4709
- hover: true,
4710
- includeId,
4711
- includeEntityLink: false
4712
- });
4713
- };
4714
- return /* @__PURE__ */ jsxs("div", {
4715
- className: "flex w-full flex-row",
4716
- children: [/* @__PURE__ */ jsx("div", {
4717
- className: "w-[100px]",
4718
- children: /* @__PURE__ */ jsx(Select, {
4719
- value: operation,
4720
- size: "medium",
4721
- fullWidth: true,
4722
- onValueChange: (value) => {
4723
- updateFilter(value, internalValue);
4724
- },
4725
- renderValue: (op) => operationLabels$3[op],
4726
- children: possibleOperations.map((op) => /* @__PURE__ */ jsx(SelectItem, {
4727
- value: op,
4728
- children: operationLabels$3[op]
4729
- }, op))
4730
- })
4731
- }), /* @__PURE__ */ jsxs("div", {
4732
- className: "grow ml-2 h-full gap-2 flex flex-col",
4733
- children: [
4734
- internalValue && Array.isArray(internalValue) && /* @__PURE__ */ jsx("div", { children: internalValue.map((ref, index) => buildEntry(ref)) }),
4735
- internalValue && !Array.isArray(internalValue) && /* @__PURE__ */ jsx("div", { children: buildEntry(internalValue) }),
4736
- (!internalValue || Array.isArray(internalValue) && internalValue.length === 0) && /* @__PURE__ */ jsx(Button, {
4737
- onClick: doOpenDialog,
4738
- size: "medium",
4739
- className: "h-full w-full",
4740
- children: multiple ? t("select_references") : t("select_reference")
4741
- }),
4742
- !isArray && /* @__PURE__ */ jsxs(Label, {
4743
- className: "border cursor-pointer rounded-md p-2 flex items-center gap-2 bg-surface-50 dark:bg-surface-900 hover:bg-surface-100 dark:hover:bg-surface-800",
4744
- htmlFor: "null-filter",
4745
- children: [/* @__PURE__ */ jsx(Checkbox, {
4746
- id: "null-filter",
4747
- checked: internalValue === null,
4748
- size: "small",
4749
- onCheckedChange: (checked) => {
4750
- if (internalValue !== null) updateFilter(operation, null);
4751
- else updateFilter(operation, void 0);
4752
- }
4753
- }), t("filter_for_null_values")]
4754
- })
4755
- ]
4756
- })]
4757
- });
4758
- }
4759
- //#endregion
4760
4460
  //#region src/components/SelectableTable/filters/StringNumberFilterField.tsx
4761
- var operationLabels$2 = {
4461
+ var operationLabels$3 = {
4762
4462
  "==": "==",
4763
4463
  "!=": "!=",
4764
4464
  ">": ">",
@@ -4769,40 +4469,62 @@ var operationLabels$2 = {
4769
4469
  "not-in": "Not in",
4770
4470
  "array-contains": "Contains",
4771
4471
  "array-contains-any": "Any",
4772
- "is-null": "Is null"
4472
+ "ilike": "Contains",
4473
+ "not-ilike": "Not contains",
4474
+ "is-null": "Is null",
4475
+ "is-not-null": "Is not null"
4773
4476
  };
4774
- var multipleSelectOperations$2 = [
4477
+ var multipleSelectOperations$3 = [
4775
4478
  "array-contains-any",
4776
4479
  "in",
4777
4480
  "not-in"
4778
4481
  ];
4779
- function StringNumberFilterField({ name, value, setValue, type, isArray, enumValues, title }) {
4482
+ /** Operators that match a substring, wrapped in SQL wildcards (`%value%`). */
4483
+ var containsOperations = ["ilike", "not-ilike"];
4484
+ /** Strip the surrounding `%` wildcards a contains-filter adds, for display. */
4485
+ function unwrapContains(value) {
4486
+ if (typeof value !== "string") return "";
4487
+ return value.replace(/^%/, "").replace(/%$/, "");
4488
+ }
4489
+ function StringNumberFilterField({ name, value, setValue, type, isArray, enumValues, title, operators }) {
4780
4490
  const { t } = useTranslation();
4781
- const possibleOperations = isArray ? ["array-contains"] : [
4491
+ let possibleOperations = isArray ? ["array-contains"] : [
4782
4492
  "==",
4783
4493
  "!=",
4784
4494
  ">",
4785
4495
  "<",
4786
4496
  ">=",
4787
4497
  "<=",
4788
- "is-null"
4498
+ "is-null",
4499
+ "is-not-null"
4789
4500
  ];
4501
+ if (!isArray && !enumValues && type === "string") possibleOperations.push("ilike", "not-ilike");
4790
4502
  if (enumValues) if (isArray) possibleOperations.push("array-contains-any");
4791
4503
  else possibleOperations.push("in", "not-in");
4504
+ if (operators) possibleOperations = possibleOperations.filter((op) => operators.includes(op));
4792
4505
  const [fieldOperation, fieldValue] = value || [possibleOperations[0], void 0];
4793
- const [operation, setOperation] = useState(fieldOperation === "==" && fieldValue === null ? "is-null" : fieldOperation);
4794
- const [internalValue, setInternalValue] = useState(fieldValue);
4795
- const isNullOperation = operation === "is-null";
4506
+ const [operation, setOperation] = useState(fieldOperation === "==" && fieldValue === null ? "is-null" : fieldOperation === "!=" && fieldValue === null ? "is-not-null" : fieldOperation);
4507
+ const [internalValue, setInternalValue] = useState(containsOperations.includes(fieldOperation) ? unwrapContains(fieldValue) : fieldValue);
4508
+ const isNullOperation = operation === "is-null" || operation === "is-not-null";
4509
+ if (possibleOperations.length === 0) return null;
4796
4510
  function updateFilter(op, val) {
4797
- if (op === "is-null") {
4511
+ if (op === "is-null" || op === "is-not-null") {
4798
4512
  setOperation(op);
4799
4513
  setInternalValue(null);
4800
- setValue(["==", null]);
4514
+ setValue([op, null]);
4515
+ return;
4516
+ }
4517
+ if (op === "ilike" || op === "not-ilike") {
4518
+ const raw = typeof val === "string" ? val : "";
4519
+ setOperation(op);
4520
+ setInternalValue(raw);
4521
+ if (raw.length > 0) setValue([op, `%${raw}%`]);
4522
+ else setValue(void 0);
4801
4523
  return;
4802
4524
  }
4803
4525
  let newValue = val;
4804
- const prevOpIsArray = multipleSelectOperations$2.includes(operation);
4805
- const newOpIsArray = multipleSelectOperations$2.includes(op);
4526
+ const prevOpIsArray = multipleSelectOperations$3.includes(operation);
4527
+ const newOpIsArray = multipleSelectOperations$3.includes(op);
4806
4528
  if (prevOpIsArray !== newOpIsArray) if (newOpIsArray) if (typeof val === "string") newValue = [val];
4807
4529
  else if (typeof val === "number") newValue = [val];
4808
4530
  else newValue = [];
@@ -4814,7 +4536,7 @@ function StringNumberFilterField({ name, value, setValue, type, isArray, enumVal
4814
4536
  if (op && hasNewValue) setValue([op, newValue]);
4815
4537
  else setValue(void 0);
4816
4538
  }
4817
- const multiple = multipleSelectOperations$2.includes(operation);
4539
+ const multiple = multipleSelectOperations$3.includes(operation);
4818
4540
  return /* @__PURE__ */ jsxs("div", {
4819
4541
  className: "flex w-full",
4820
4542
  children: [/* @__PURE__ */ jsx("div", {
@@ -4827,10 +4549,10 @@ function StringNumberFilterField({ name, value, setValue, type, isArray, enumVal
4827
4549
  onValueChange: (value) => {
4828
4550
  updateFilter(value, internalValue);
4829
4551
  },
4830
- renderValue: (op) => operationLabels$2[op],
4552
+ renderValue: (op) => operationLabels$3[op],
4831
4553
  children: possibleOperations.map((op) => /* @__PURE__ */ jsx(SelectItem, {
4832
4554
  value: op,
4833
- children: operationLabels$2[op]
4555
+ children: operationLabels$3[op]
4834
4556
  }, op))
4835
4557
  })
4836
4558
  }), /* @__PURE__ */ jsxs("div", {
@@ -4910,8 +4632,9 @@ function StringNumberFilterField({ name, value, setValue, type, isArray, enumVal
4910
4632
  }
4911
4633
  //#endregion
4912
4634
  //#region src/components/SelectableTable/filters/BooleanFilterField.tsx
4913
- function BooleanFilterField({ name, title, value, setValue }) {
4635
+ function BooleanFilterField({ name, title, value, setValue, operators }) {
4914
4636
  const { t } = useTranslation();
4637
+ if (operators && !operators.includes("==")) return null;
4915
4638
  function updateFilter(val) {
4916
4639
  if (val !== void 0) setValue(["==", val]);
4917
4640
  else setValue(void 0);
@@ -4930,7 +4653,7 @@ function BooleanFilterField({ name, title, value, setValue }) {
4930
4653
  }
4931
4654
  //#endregion
4932
4655
  //#region src/components/SelectableTable/filters/DateTimeFilterField.tsx
4933
- var operationLabels$1 = {
4656
+ var operationLabels$2 = {
4934
4657
  "==": "==",
4935
4658
  "!=": "!=",
4936
4659
  ">": ">",
@@ -4941,34 +4664,38 @@ var operationLabels$1 = {
4941
4664
  in: "in",
4942
4665
  "array-contains": "Contains",
4943
4666
  "array-contains-any": "Any",
4944
- "is-null": "Is null"
4667
+ "is-null": "Is null",
4668
+ "is-not-null": "Is not null"
4945
4669
  };
4946
- var multipleSelectOperations$1 = ["array-contains-any", "in"];
4947
- function DateTimeFilterField({ name, isArray, mode, value, setValue, title, timezone }) {
4670
+ var multipleSelectOperations$2 = ["array-contains-any", "in"];
4671
+ function DateTimeFilterField({ name, isArray, mode, value, setValue, title, timezone, operators }) {
4948
4672
  const { locale } = useCustomizationController();
4949
- const possibleOperations = isArray ? ["array-contains"] : [
4673
+ let possibleOperations = isArray ? ["array-contains"] : [
4950
4674
  "==",
4951
4675
  "!=",
4952
4676
  ">",
4953
4677
  "<",
4954
4678
  ">=",
4955
4679
  "<=",
4956
- "is-null"
4680
+ "is-null",
4681
+ "is-not-null"
4957
4682
  ];
4683
+ if (operators) possibleOperations = possibleOperations.filter((op) => operators.includes(op));
4958
4684
  const [fieldOperation, fieldValue] = value || [possibleOperations[0], void 0];
4959
- const [operation, setOperation] = useState(fieldOperation === "==" && fieldValue === null ? "is-null" : fieldOperation);
4685
+ const [operation, setOperation] = useState(fieldOperation === "==" && fieldValue === null ? "is-null" : fieldOperation === "!=" && fieldValue === null ? "is-not-null" : fieldOperation);
4960
4686
  const [internalValue, setInternalValue] = useState(fieldValue);
4961
- const isNullOperation = operation === "is-null";
4687
+ const isNullOperation = operation === "is-null" || operation === "is-not-null";
4688
+ if (possibleOperations.length === 0) return null;
4962
4689
  function updateFilter(op, val) {
4963
- if (op === "is-null") {
4690
+ if (op === "is-null" || op === "is-not-null") {
4964
4691
  setOperation(op);
4965
4692
  setInternalValue(null);
4966
- setValue(["==", null]);
4693
+ setValue([op, null]);
4967
4694
  return;
4968
4695
  }
4969
4696
  let newValue = val;
4970
- const prevOpIsArray = multipleSelectOperations$1.includes(operation);
4971
- const newOpIsArray = multipleSelectOperations$1.includes(op);
4697
+ const prevOpIsArray = multipleSelectOperations$2.includes(operation);
4698
+ const newOpIsArray = multipleSelectOperations$2.includes(op);
4972
4699
  if (prevOpIsArray !== newOpIsArray) newValue = newOpIsArray ? val ? [val] : [] : void 0;
4973
4700
  setOperation(op);
4974
4701
  setInternalValue(Array.isArray(newValue) ? newValue[0] ?? null : newValue);
@@ -4987,10 +4714,10 @@ function DateTimeFilterField({ name, isArray, mode, value, setValue, title, time
4987
4714
  onValueChange: (value) => {
4988
4715
  updateFilter(value, internalValue);
4989
4716
  },
4990
- renderValue: (op) => operationLabels$1[op],
4717
+ renderValue: (op) => operationLabels$2[op],
4991
4718
  children: possibleOperations.map((op) => /* @__PURE__ */ jsx(SelectItem, {
4992
4719
  value: op,
4993
- children: operationLabels$1[op]
4720
+ children: operationLabels$2[op]
4994
4721
  }, op))
4995
4722
  })
4996
4723
  }), /* @__PURE__ */ jsx("div", {
@@ -5011,6 +4738,140 @@ function DateTimeFilterField({ name, isArray, mode, value, setValue, title, time
5011
4738
  });
5012
4739
  }
5013
4740
  //#endregion
4741
+ //#region src/components/SelectableTable/filters/ReferenceFilterField.tsx
4742
+ var operationLabels$1 = {
4743
+ "==": "==",
4744
+ "!=": "!=",
4745
+ ">": ">",
4746
+ "<": "<",
4747
+ ">=": ">=",
4748
+ "<=": "<=",
4749
+ in: "In",
4750
+ "not-in": "Not in",
4751
+ "array-contains": "Contains",
4752
+ "array-contains-any": "Contains Any"
4753
+ };
4754
+ var multipleSelectOperations$1 = [
4755
+ "array-contains-any",
4756
+ "in",
4757
+ "not-in"
4758
+ ];
4759
+ function ReferenceFilterField({ value, setValue, isArray, path, includeId = true, previewProperties, setHidden, operators }) {
4760
+ const { t } = useTranslation();
4761
+ let possibleOperations = isArray ? ["array-contains"] : [
4762
+ "==",
4763
+ "!=",
4764
+ ">",
4765
+ "<",
4766
+ ">=",
4767
+ "<="
4768
+ ];
4769
+ if (isArray) possibleOperations.push("array-contains-any");
4770
+ else possibleOperations.push("in", "not-in");
4771
+ if (operators) possibleOperations = possibleOperations.filter((op) => operators.includes(op));
4772
+ const [fieldOperation, fieldValue] = value || [possibleOperations[0], void 0];
4773
+ const [operation, setOperation] = useState(fieldOperation);
4774
+ const [internalValue, setInternalValue] = useState(fieldValue);
4775
+ const selectedEntityIds = internalValue ? Array.isArray(internalValue) ? internalValue.map((ref) => {
4776
+ if (!(ref?.isEntityReference && ref?.isEntityReference())) return null;
4777
+ return ref.id;
4778
+ }).filter(Boolean) : [internalValue.id] : [];
4779
+ function updateFilter(op, val) {
4780
+ const prevOpIsArray = multipleSelectOperations$1.includes(operation);
4781
+ const newOpIsArray = multipleSelectOperations$1.includes(op);
4782
+ let newValue = val;
4783
+ if (prevOpIsArray !== newOpIsArray) newValue = newOpIsArray ? newValue && !Array.isArray(newValue) && newValue.isEntityReference?.() ? [newValue] : [] : void 0;
4784
+ setOperation(op);
4785
+ setInternalValue(newValue);
4786
+ const hasNewValue = newValue !== null && Array.isArray(newValue) ? newValue.length > 0 : newValue !== void 0;
4787
+ if (op && hasNewValue) setValue([op, newValue]);
4788
+ else setValue(void 0);
4789
+ }
4790
+ const collectionRegistryController = useCollectionRegistryController();
4791
+ const collection = useMemo(() => {
4792
+ return path ? collectionRegistryController.getCollection(path) : void 0;
4793
+ }, [path]);
4794
+ const onSingleEntitySelected = (entity) => {
4795
+ updateFilter(operation, getReferenceFrom(entity));
4796
+ };
4797
+ const onMultipleEntitiesSelected = (entities) => {
4798
+ updateFilter(operation, entities.map((e) => getReferenceFrom(e)));
4799
+ };
4800
+ const multiple = multipleSelectOperations$1.includes(operation);
4801
+ const referenceDialogController = useSelectionDialog({
4802
+ multiselect: multiple,
4803
+ path,
4804
+ collection,
4805
+ onSingleEntitySelected,
4806
+ onMultipleEntitiesSelected,
4807
+ selectedEntityIds,
4808
+ onClose: () => {
4809
+ setHidden(false);
4810
+ }
4811
+ });
4812
+ const doOpenDialog = () => {
4813
+ setHidden(true);
4814
+ referenceDialogController.open();
4815
+ };
4816
+ const buildEntry = (reference) => {
4817
+ return /* @__PURE__ */ jsx(ReferencePreview, {
4818
+ disabled: !path,
4819
+ previewProperties,
4820
+ size: "medium",
4821
+ onClick: doOpenDialog,
4822
+ reference,
4823
+ hover: true,
4824
+ includeId,
4825
+ includeEntityLink: false
4826
+ });
4827
+ };
4828
+ if (possibleOperations.length === 0) return null;
4829
+ return /* @__PURE__ */ jsxs("div", {
4830
+ className: "flex w-full flex-row",
4831
+ children: [/* @__PURE__ */ jsx("div", {
4832
+ className: "w-[100px]",
4833
+ children: /* @__PURE__ */ jsx(Select, {
4834
+ value: operation,
4835
+ size: "medium",
4836
+ fullWidth: true,
4837
+ onValueChange: (value) => {
4838
+ updateFilter(value, internalValue);
4839
+ },
4840
+ renderValue: (op) => operationLabels$1[op],
4841
+ children: possibleOperations.map((op) => /* @__PURE__ */ jsx(SelectItem, {
4842
+ value: op,
4843
+ children: operationLabels$1[op]
4844
+ }, op))
4845
+ })
4846
+ }), /* @__PURE__ */ jsxs("div", {
4847
+ className: "grow ml-2 h-full gap-2 flex flex-col",
4848
+ children: [
4849
+ internalValue && Array.isArray(internalValue) && /* @__PURE__ */ jsx("div", { children: internalValue.map((ref, index) => buildEntry(ref)) }),
4850
+ internalValue && !Array.isArray(internalValue) && /* @__PURE__ */ jsx("div", { children: buildEntry(internalValue) }),
4851
+ (!internalValue || Array.isArray(internalValue) && internalValue.length === 0) && /* @__PURE__ */ jsx(Button, {
4852
+ onClick: doOpenDialog,
4853
+ size: "medium",
4854
+ className: "h-full w-full",
4855
+ children: multiple ? t("select_references") : t("select_reference")
4856
+ }),
4857
+ !isArray && /* @__PURE__ */ jsxs(Label, {
4858
+ className: "border cursor-pointer rounded-md p-2 flex items-center gap-2 bg-surface-50 dark:bg-surface-900 hover:bg-surface-100 dark:hover:bg-surface-800",
4859
+ htmlFor: "null-filter",
4860
+ children: [/* @__PURE__ */ jsx(Checkbox, {
4861
+ id: "null-filter",
4862
+ checked: internalValue === null,
4863
+ size: "small",
4864
+ onCheckedChange: (checked) => {
4865
+ if (internalValue !== null) updateFilter(operation, null);
4866
+ else updateFilter(operation, void 0);
4867
+ }
4868
+ }), t("filter_for_null_values")]
4869
+ })
4870
+ ]
4871
+ })]
4872
+ });
4873
+ }
4874
+ //#endregion
5014
4875
  //#region src/components/SelectableTable/filters/RelationFilterField.tsx
5015
4876
  var operationLabels = {
5016
4877
  "==": "==",
@@ -5029,9 +4890,9 @@ var multipleSelectOperations = [
5029
4890
  "in",
5030
4891
  "not-in"
5031
4892
  ];
5032
- function RelationFilterField({ value, setValue, relation, name: _name, hidden: _hidden, setHidden: _setHidden }) {
4893
+ function RelationFilterField({ value, setValue, relation, name: _name, hidden: _hidden, setHidden: _setHidden, operators }) {
5033
4894
  const manyRelation = relation.cardinality === "many";
5034
- const possibleOperations = manyRelation ? ["array-contains", "array-contains-any"] : [
4895
+ let possibleOperations = manyRelation ? ["array-contains", "array-contains-any"] : [
5035
4896
  "==",
5036
4897
  "!=",
5037
4898
  ">",
@@ -5041,6 +4902,7 @@ function RelationFilterField({ value, setValue, relation, name: _name, hidden: _
5041
4902
  "in",
5042
4903
  "not-in"
5043
4904
  ];
4905
+ if (operators) possibleOperations = possibleOperations.filter((op) => operators.includes(op));
5044
4906
  const [fieldOperation, fieldValue] = value || [possibleOperations[0], void 0];
5045
4907
  const [operation, setOperation] = useState(fieldOperation);
5046
4908
  const [internalValue, setInternalValue] = useState(fieldValue);
@@ -5072,6 +4934,7 @@ function RelationFilterField({ value, setValue, relation, name: _name, hidden: _
5072
4934
  }
5073
4935
  updateFilter(operation, newVal);
5074
4936
  };
4937
+ if (possibleOperations.length === 0) return null;
5075
4938
  return /* @__PURE__ */ jsxs("div", {
5076
4939
  className: "flex flex-row",
5077
4940
  children: [/* @__PURE__ */ jsx("div", {
@@ -5113,28 +4976,146 @@ function RelationFilterField({ value, setValue, relation, name: _name, hidden: _
5113
4976
  });
5114
4977
  }
5115
4978
  //#endregion
4979
+ //#region src/components/SelectableTable/filters/FilterFieldBinding.tsx
4980
+ /**
4981
+ * The single entry point for rendering a collection filter field.
4982
+ * Used by both the table header filters ({@link SelectableTable}) and the
4983
+ * Filters dialog.
4984
+ *
4985
+ * Resolution order:
4986
+ * 1. `property.ui.Filter` — per-property replacement (rendered even when the
4987
+ * resolved operator list is empty; the component owns filterability).
4988
+ * 2. `components["Collection.FilterField"]` — collection-level or app-level
4989
+ * override (wrap mode supported via `OriginalComponent`).
4990
+ * 3. Built-in field dispatched by property type.
4991
+ *
4992
+ * The operators handed to the field are the intersection of the engine's
4993
+ * capabilities, the property-type defaults, and `property.ui.filterOperators`
4994
+ * (see `resolveFilterOperators`). When that intersection is empty and no
4995
+ * per-property `Filter` is set, nothing is rendered.
4996
+ *
4997
+ * @group Components
4998
+ */
4999
+ function FilterFieldBinding({ propertyKey, property, engine, value, setValue, hidden, setHidden }) {
5000
+ const isArray = property.type === "array";
5001
+ const ofVal = isArray ? property.of : void 0;
5002
+ const baseProperty = isArray ? Array.isArray(ofVal) ? ofVal[0] : ofVal : property;
5003
+ const scopeCollection = useCollectionScope();
5004
+ const ResolvedFilterField = useComponentOverride("Collection.FilterField", DefaultFilterField);
5005
+ const PropertyFilter = useResolvedComponent(baseProperty?.ui?.Filter);
5006
+ if (!baseProperty) return null;
5007
+ const operators = resolveFilterOperators({
5008
+ property: baseProperty,
5009
+ isArray,
5010
+ engine: engine ?? scopeCollection?.engine
5011
+ });
5012
+ const bindingProps = {
5013
+ propertyKey,
5014
+ property: baseProperty,
5015
+ isArray,
5016
+ operators,
5017
+ value,
5018
+ setValue,
5019
+ title: property.name,
5020
+ hidden,
5021
+ setHidden
5022
+ };
5023
+ if (PropertyFilter) return /* @__PURE__ */ jsx(Suspense, {
5024
+ fallback: null,
5025
+ children: /* @__PURE__ */ jsx(PropertyFilter, { ...bindingProps })
5026
+ });
5027
+ if (operators.length === 0) return null;
5028
+ return /* @__PURE__ */ jsx(ResolvedFilterField, { ...bindingProps });
5029
+ }
5030
+ /**
5031
+ * Built-in filter field dispatch by property type. This is the
5032
+ * `OriginalComponent` received by `"Collection.FilterField"` overrides in
5033
+ * wrap mode.
5034
+ */
5035
+ function DefaultFilterField({ propertyKey, property, isArray, operators, value, setValue, title, hidden, setHidden }) {
5036
+ if (property.type === "reference") {
5037
+ const referenceProperty = property;
5038
+ return /* @__PURE__ */ jsx(ReferenceFilterField, {
5039
+ value,
5040
+ setValue,
5041
+ name: propertyKey,
5042
+ isArray,
5043
+ operators,
5044
+ path: referenceProperty.path,
5045
+ title,
5046
+ includeId: referenceProperty.includeId,
5047
+ previewProperties: referenceProperty.ui?.previewProperties,
5048
+ hidden: hidden ?? false,
5049
+ setHidden: setHidden ?? (() => void 0)
5050
+ });
5051
+ }
5052
+ if (property.type === "relation") {
5053
+ const relation = property.relation;
5054
+ if (!relation) return null;
5055
+ return /* @__PURE__ */ jsx(RelationFilterField, {
5056
+ value,
5057
+ setValue,
5058
+ name: propertyKey,
5059
+ operators,
5060
+ relation,
5061
+ hidden: hidden ?? false,
5062
+ setHidden: setHidden ?? (() => void 0)
5063
+ });
5064
+ }
5065
+ if (property.type === "number" || property.type === "string") {
5066
+ const enumValues = property.enum ? enumToObjectEntries(property.enum) : void 0;
5067
+ return /* @__PURE__ */ jsx(StringNumberFilterField, {
5068
+ value,
5069
+ setValue,
5070
+ name: propertyKey,
5071
+ type: property.type,
5072
+ isArray,
5073
+ operators,
5074
+ enumValues,
5075
+ title
5076
+ });
5077
+ }
5078
+ if (property.type === "boolean") return /* @__PURE__ */ jsx(BooleanFilterField, {
5079
+ value,
5080
+ setValue,
5081
+ name: propertyKey,
5082
+ operators,
5083
+ title
5084
+ });
5085
+ if (property.type === "date") return /* @__PURE__ */ jsx(DateTimeFilterField, {
5086
+ value,
5087
+ setValue,
5088
+ name: propertyKey,
5089
+ mode: property.mode,
5090
+ isArray,
5091
+ operators,
5092
+ title
5093
+ });
5094
+ return null;
5095
+ }
5096
+ //#endregion
5116
5097
  //#region src/components/SelectableTable/SelectableTable.tsx
5117
5098
  /**
5118
5099
  * This component is in charge of rendering a collection table with a high
5119
5100
  * degree of customization.
5120
5101
  *
5121
- * This component is used internally by {@link EntityCollectionView} and
5102
+ * This component is used internally by {@link CollectionViewBinding} and
5122
5103
  * {@link useReferenceDialog}
5123
5104
  *
5124
5105
  * Please note that you only need to use this component if you are building
5125
5106
  * a custom view. If you just need to create a default view you can do it
5126
5107
  * exclusively with config options.
5127
5108
  *
5128
- * If you want to bind a {@link EntityCollection} to a table with the default
5109
+ * If you want to bind a {@link CollectionConfig} to a table with the default
5129
5110
  * options you see in collections in the top level navigation, you can
5130
- * check {@link EntityCollectionView}.
5111
+ * check {@link CollectionViewBinding}.
5131
5112
  *
5132
5113
  * The data displayed in the table is managed by a {@link EntityTableController}.
5133
5114
  * You can build the default, bound to a path in the driver, by using the hook
5134
5115
  * {@link useDataTableController}
5135
5116
  *
5136
- * @see EntityCollectionTableProps
5137
- * @see EntityCollectionView
5117
+ * @see CollectionTableBindingProps
5118
+ * @see CollectionViewBinding
5138
5119
  * @see VirtualTable
5139
5120
  * @group Components
5140
5121
  */
@@ -5162,7 +5143,12 @@ var SelectableTable = function SelectableTable({ onValueChange, cellRenderer, on
5162
5143
  }, [onEntityClick, inlineEditing]);
5163
5144
  const select = useCallback((cell) => {
5164
5145
  setLocalSelectedCell(cell);
5165
- selectionStore.select(cell);
5146
+ if (cell) selectionStore.select({
5147
+ ...cell,
5148
+ columnKey: cell.propertyKey,
5149
+ id: cell.entityId
5150
+ });
5151
+ else selectionStore.select(void 0);
5166
5152
  }, [selectionStore]);
5167
5153
  const unselect = useCallback(() => {
5168
5154
  setLocalSelectedCell(void 0);
@@ -5199,6 +5185,19 @@ var SelectableTable = function SelectableTable({ onValueChange, cellRenderer, on
5199
5185
  size,
5200
5186
  selectionStore
5201
5187
  ]);
5188
+ const createFilterField = useCallback(({ id, filterValue, setFilterValue, column, hidden, setHidden }) => {
5189
+ if (!column.custom) return null;
5190
+ const { resolvedProperty } = column.custom;
5191
+ if (!resolvedProperty) return null;
5192
+ return /* @__PURE__ */ jsx(FilterFieldBinding, {
5193
+ propertyKey: id,
5194
+ property: resolvedProperty,
5195
+ value: filterValue,
5196
+ setValue: setFilterValue,
5197
+ hidden,
5198
+ setHidden
5199
+ });
5200
+ }, []);
5202
5201
  return /* @__PURE__ */ jsx(SelectableTableContext.Provider, {
5203
5202
  value: contextValue,
5204
5203
  children: /* @__PURE__ */ jsx("div", {
@@ -5237,93 +5236,33 @@ var SelectableTable = function SelectableTable({ onValueChange, cellRenderer, on
5237
5236
  })
5238
5237
  });
5239
5238
  };
5240
- function createFilterField({ id, filterValue, setFilterValue, column, hidden, setHidden }) {
5241
- if (!column.custom) return null;
5242
- const { resolvedProperty } = column.custom;
5243
- const isArray = resolvedProperty?.type === "array";
5244
- const ofVal = isArray && resolvedProperty ? resolvedProperty.of : void 0;
5245
- const baseProperty = isArray ? Array.isArray(ofVal) ? ofVal[0] : ofVal : resolvedProperty;
5246
- if (!baseProperty) return null;
5247
- if (baseProperty.type === "reference") return /* @__PURE__ */ jsx(ReferenceFilterField, {
5248
- value: filterValue,
5249
- setValue: setFilterValue,
5250
- name: id,
5251
- isArray,
5252
- path: baseProperty.path,
5253
- title: resolvedProperty?.name,
5254
- includeId: baseProperty.includeId,
5255
- previewProperties: baseProperty?.ui?.previewProperties,
5256
- hidden,
5257
- setHidden
5258
- });
5259
- else if (baseProperty.type === "relation" && baseProperty.relation) return /* @__PURE__ */ jsx(RelationFilterField, {
5260
- value: filterValue,
5261
- setValue: setFilterValue,
5262
- name: id,
5263
- relation: baseProperty.relation,
5264
- hidden,
5265
- setHidden
5266
- });
5267
- else if (baseProperty.type === "number" || baseProperty.type === "string") {
5268
- const name = baseProperty.name;
5269
- const enumValues = baseProperty.enum ? enumToObjectEntries(baseProperty.enum) : void 0;
5270
- return /* @__PURE__ */ jsx(StringNumberFilterField, {
5271
- value: filterValue,
5272
- setValue: setFilterValue,
5273
- name: id,
5274
- type: baseProperty.type,
5275
- isArray,
5276
- enumValues,
5277
- title: name
5278
- });
5279
- } else if (baseProperty.type === "boolean") {
5280
- const name = baseProperty.name;
5281
- return /* @__PURE__ */ jsx(BooleanFilterField, {
5282
- value: filterValue,
5283
- setValue: setFilterValue,
5284
- name: id,
5285
- title: name
5286
- });
5287
- } else if (baseProperty.type === "date") {
5288
- const title = baseProperty.name;
5289
- return /* @__PURE__ */ jsx(DateTimeFilterField, {
5290
- value: filterValue,
5291
- setValue: setFilterValue,
5292
- name: id,
5293
- mode: baseProperty.mode,
5294
- isArray,
5295
- title
5296
- });
5297
- }
5298
- return /* @__PURE__ */ jsx("div", { children: `Currently the filter field ${resolvedProperty?.type} is not supported` });
5299
- }
5300
5239
  //#endregion
5301
- //#region src/components/EntityCollectionTable/EntityCollectionTable.tsx
5240
+ //#region src/components/CollectionTableBinding/CollectionTableBinding.tsx
5302
5241
  /**
5303
5242
  * This component is in charge of rendering a collection table with a high
5304
5243
  * degree of customization.
5305
5244
  *
5306
- * This component is used internally by {@link EntityCollectionView} and
5245
+ * This component is used internally by {@link CollectionViewBinding} and
5307
5246
  * {@link useReferenceDialog}
5308
5247
  *
5309
5248
  * Please note that you only need to use this component if you are building
5310
5249
  * a custom view. If you just need to create a default view you can do it
5311
5250
  * exclusively with config options.
5312
5251
  *
5313
- * If you want to bind a {@link EntityCollection} to a table with the default
5252
+ * If you want to bind a {@link CollectionConfig} to a table with the default
5314
5253
  * options you see in collections in the top level navigation, you can
5315
- * check {@link EntityCollectionView}.
5254
+ * check {@link CollectionViewBinding}.
5316
5255
  *
5317
5256
  * The data displayed in the table is managed by a {@link EntityTableController}.
5318
5257
  * You can build the default, bound to a path in the driver, by using the hook
5319
5258
  * {@link useDataTableController}
5320
5259
  *
5321
- * @see EntityCollectionTableProps
5322
- * @see EntityCollectionView
5260
+ * @see CollectionTableBindingProps
5261
+ * @see CollectionViewBinding
5323
5262
  * @see VirtualTable
5324
5263
  * @group Components
5325
5264
  */
5326
- var EntityCollectionTable = function EntityCollectionTable({ className, style, fixedFilter, actionsStart, actions, viewModeToggle, title, tableRowActionsBuilder, uniqueFieldValidator, getPropertyFor, onValueChange, selectionController, highlightedEntities, onEntityClick, onColumnResize, initialScroll, onScroll, onSizeChanged, hoverRow = true, inlineEditing = false, additionalFields, displayedColumnIds, defaultSize, properties, tableController, filterable = true, sortable = true, endAdornment, AddColumnComponent, AdditionalHeaderWidget, additionalIDHeaderWidget, emptyComponent, getIdColumnWidth, enablePopupIcon, openEntityMode = "side_panel", onColumnsOrderChange, hideToolbar = false }) {
5265
+ var CollectionTableBinding = function CollectionTableBinding({ className, style, fixedFilter, actionsStart, actions, viewModeToggle, title, tableRowActionsBuilder, uniqueFieldValidator, getPropertyFor, onValueChange, selectionController, highlightedEntities, onEntityClick, onColumnResize, initialScroll, onScroll, onSizeChanged, hoverRow = true, inlineEditing = false, additionalFields, displayedColumnIds, defaultSize, properties, tableController, filterable = true, sortable = true, endAdornment, AddColumnComponent, AdditionalHeaderWidget, additionalIDHeaderWidget, emptyComponent, getIdColumnWidth, enablePopupIcon, openEntityMode = "side_panel", onColumnsOrderChange, hideToolbar = false }) {
5327
5266
  const ref = useRef(null);
5328
5267
  const largeLayout = useLargeLayout();
5329
5268
  const selectedEntities = useMemo(() => {
@@ -5348,6 +5287,7 @@ var EntityCollectionTable = function EntityCollectionTable({ className, style, f
5348
5287
  const customFieldValidator = uniqueFieldValidator;
5349
5288
  const propertyCellRenderer = useCallback(({ column, columnIndex, rowData, rowIndex, sortableNodeRef, sortableStyle, sortableAttributes, isDragging, isDraggable, frozen }) => {
5350
5289
  const entity = rowData;
5290
+ if (!entity) return null;
5351
5291
  const propertyKey = column.key;
5352
5292
  const columnCustom = column.custom;
5353
5293
  let disabled = columnCustom?.disabled ?? false;
@@ -5387,6 +5327,7 @@ var EntityCollectionTable = function EntityCollectionTable({ className, style, f
5387
5327
  ]);
5388
5328
  const additionalCellRenderer = useCallback(({ column, rowData, width, sortableNodeRef, sortableStyle, sortableAttributes, isDragging, isDraggable, frozen }) => {
5389
5329
  const entity = rowData;
5330
+ if (!entity) return null;
5390
5331
  const additionalField = additionalFieldsMap[column.key];
5391
5332
  const value = additionalField.dependencies ? Object.entries(entity.values).filter(([key, value]) => additionalField.dependencies.includes(key)).reduce((a, b) => ({
5392
5333
  ...a,
@@ -5474,7 +5415,7 @@ var EntityCollectionTable = function EntityCollectionTable({ className, style, f
5474
5415
  width: column.width,
5475
5416
  frozen: column.frozen
5476
5417
  });
5477
- else return /* @__PURE__ */ jsx(EntityCollectionRowActions, {
5418
+ else return /* @__PURE__ */ jsx(CollectionRowActions, {
5478
5419
  entity: props.rowData,
5479
5420
  width: column.width,
5480
5421
  frozen: column.frozen,
@@ -5549,7 +5490,7 @@ var EntityCollectionTable = function EntityCollectionTable({ className, style, f
5549
5490
  });
5550
5491
  };
5551
5492
  //#endregion
5552
- //#region src/components/EntityCollectionView/useSelectionController.tsx
5493
+ //#region src/components/CollectionViewBinding/useSelectionController.tsx
5553
5494
  function useSelectionController(onSelectionChange) {
5554
5495
  const [selectedEntities, setSelectedEntities] = useState([]);
5555
5496
  const onSelectionChangeRef = useRef(onSelectionChange);
@@ -5608,11 +5549,11 @@ function mergeEntityActions(currentActions, newActions) {
5608
5549
  return updatedActions;
5609
5550
  }
5610
5551
  //#endregion
5611
- //#region src/components/EntityEditViewFormActions.tsx
5612
- function EntityEditViewFormActions({ collection, path, entity, layout, savingError, formex, disabled, status, pluginActions, openEntityMode, showDefaultActions = true, navigateBack, formContext }) {
5552
+ //#region src/components/EditFormActions.tsx
5553
+ function EditFormActions({ collection, path, entity, layout, savingError, formex, disabled, status, pluginActions, openEntityMode, showDefaultActions = true, navigateBack, formContext }) {
5613
5554
  const { canCreate, canDelete } = usePermissions();
5614
5555
  const context = useCMSContext();
5615
- const sideEntityController = context.sideEntityController;
5556
+ const sidePanelController = context.sidePanelController;
5616
5557
  const sideDialogContext = useSideDialogContext();
5617
5558
  const customizationController = useCustomizationController();
5618
5559
  const { t } = useTranslation();
@@ -5642,7 +5583,7 @@ function EntityEditViewFormActions({ collection, path, entity, layout, savingErr
5642
5583
  formActions,
5643
5584
  collection,
5644
5585
  context,
5645
- sideEntityController,
5586
+ sidePanelController,
5646
5587
  disabled,
5647
5588
  status,
5648
5589
  sideDialogContext,
@@ -5660,7 +5601,7 @@ function EntityEditViewFormActions({ collection, path, entity, layout, savingErr
5660
5601
  formActions,
5661
5602
  collection,
5662
5603
  context,
5663
- sideEntityController,
5604
+ sidePanelController,
5664
5605
  sideDialogContext,
5665
5606
  disabled,
5666
5607
  status,
@@ -5675,7 +5616,7 @@ function EntityEditViewFormActions({ collection, path, entity, layout, savingErr
5675
5616
  if (layout === "responsive") return /* @__PURE__ */ jsxs(Fragment, { children: [bottomActions, sideActions] });
5676
5617
  return layout === "bottom" ? bottomActions : sideActions;
5677
5618
  }
5678
- function buildBottomActions({ savingError, entity, formActions, collection, context, sideEntityController, disabled, status, sideDialogContext, pluginActions, openEntityMode, navigateBack, formContext, formex, t, className }) {
5619
+ function buildBottomActions({ savingError, entity, formActions, collection, context, sidePanelController, disabled, status, sideDialogContext, pluginActions, openEntityMode, navigateBack, formContext, formex, t, className }) {
5679
5620
  const hasErrors = Object.keys(formex.errors).length > 0 && formex.submitCount > 0;
5680
5621
  const canClose = openEntityMode === "side_panel" || openEntityMode === "dialog";
5681
5622
  return /* @__PURE__ */ jsxs(DialogActions, {
@@ -5695,10 +5636,10 @@ function buildBottomActions({ savingError, entity, formActions, collection, cont
5695
5636
  const props = {
5696
5637
  view: "form",
5697
5638
  entity,
5698
- path: collection.slug,
5639
+ path: getCollectionDataPath(collection),
5699
5640
  collection,
5700
5641
  context,
5701
- sideEntityController,
5642
+ sidePanelController,
5702
5643
  openEntityMode,
5703
5644
  navigateBack,
5704
5645
  formContext
@@ -5767,7 +5708,7 @@ function buildBottomActions({ savingError, entity, formActions, collection, cont
5767
5708
  ]
5768
5709
  });
5769
5710
  }
5770
- function buildSideActions({ savingError, entity, formActions, collection, context, sideEntityController, disabled, status, sideDialogContext, pluginActions, openEntityMode, navigateBack, formContext, formex, t, className }) {
5711
+ function buildSideActions({ savingError, entity, formActions, collection, context, sidePanelController, disabled, status, sideDialogContext, pluginActions, openEntityMode, navigateBack, formContext, formex, t, className }) {
5771
5712
  const hasErrors = Object.keys(formex.errors).length > 0 && formex.submitCount > 0;
5772
5713
  return /* @__PURE__ */ jsxs("div", {
5773
5714
  className: cls("overflow-auto h-full flex flex-col gap-2 w-80 2xl:w-96 px-4 py-16 sticky top-0 border-l", defaultBorderMixin, className),
@@ -5813,10 +5754,10 @@ function buildSideActions({ savingError, entity, formActions, collection, contex
5813
5754
  const props = {
5814
5755
  view: "form",
5815
5756
  entity,
5816
- path: collection.slug,
5757
+ path: getCollectionDataPath(collection),
5817
5758
  collection,
5818
5759
  context,
5819
- sideEntityController,
5760
+ sidePanelController,
5820
5761
  openEntityMode,
5821
5762
  navigateBack,
5822
5763
  formContext
@@ -5879,14 +5820,14 @@ function EntityActionButton({ action, enabled, props }) {
5879
5820
  });
5880
5821
  }
5881
5822
  //#endregion
5882
- //#region src/components/EntityEditView.tsx
5883
- var EntityHistoryView = lazy(() => import("./history-ChHgyyvM.js").then((m) => ({ default: m.EntityHistoryView })));
5823
+ //#region src/components/EditViewBinding.tsx
5824
+ var EntityHistoryView = lazy(() => import("./history-7X5bON_n.js").then((m) => ({ default: m.EntityHistoryView })));
5884
5825
  /**
5885
5826
  * This is the default view that is used as the content of a side panel when
5886
- * an entity is opened.
5827
+ * a record is opened.
5887
5828
  */
5888
- function EntityEditView({ entityId, ...props }) {
5889
- const { entity, dataLoading, dataLoadingError } = useEntityFetch({
5829
+ function EditViewBinding({ entityId, ...props }) {
5830
+ const { entity, dataLoading, dataLoadingError } = useFetch({
5890
5831
  path: props.path,
5891
5832
  entityId,
5892
5833
  collection: props.collection,
@@ -5914,7 +5855,7 @@ function EntityEditView({ entityId, ...props }) {
5914
5855
  children: "Entity not found"
5915
5856
  }) });
5916
5857
  }
5917
- const content = /* @__PURE__ */ jsx(EntityEditViewInner, {
5858
+ const content = /* @__PURE__ */ jsx(EditViewBindingInner, {
5918
5859
  ...props,
5919
5860
  entityId,
5920
5861
  entity,
@@ -5924,16 +5865,15 @@ function EntityEditView({ entityId, ...props }) {
5924
5865
  setStatus,
5925
5866
  canEdit
5926
5867
  });
5927
- if (props.collection.components) return /* @__PURE__ */ jsx(CollectionComponentOverrideProvider, {
5928
- overrides: props.collection.components,
5868
+ return /* @__PURE__ */ jsx(CollectionScopeProvider, {
5869
+ collection: props.collection,
5929
5870
  children: content
5930
5871
  });
5931
- return content;
5932
5872
  }
5933
- function EntityEditViewInner({ path, entityId, selectedTab: selectedTabProp, collection, parentCollectionSlugs, parentEntityIds, onValuesModified, onSaved, onTabChange, navigateBack, entity, initialDirtyValues, dataLoading, layout = "side_panel", barActions, status, setStatus, formProps, canEdit }) {
5934
- const ResolvedFormActions = useComponentOverride("Entity.FormActions", EntityEditViewFormActions);
5873
+ function EditViewBindingInner({ path, entityId, selectedTab: selectedTabProp, collection, parentCollectionSlugs, parentEntityIds, onValuesModified, onSaved, onTabChange, navigateBack, entity, initialDirtyValues, dataLoading, layout = "side_panel", barActions, status, setStatus, formProps, canEdit }) {
5874
+ const ResolvedFormActions = useComponentOverride("EditView.FormActions", EditFormActions);
5935
5875
  const ResolvedEntityForm = useComponentOverride("Entity.Form", EntityFormBinding);
5936
- const ResolvedCollectionView = useComponentOverride("Collection.View", EntityCollectionView);
5876
+ const ResolvedCollectionView = useComponentOverride("Collection.View", CollectionViewBinding);
5937
5877
  const context = useRebaseContext();
5938
5878
  const urlController = useUrlController();
5939
5879
  const navigate = useNavigate();
@@ -6081,7 +6021,7 @@ function EntityEditViewInner({ path, entityId, selectedTab: selectedTabProp, col
6081
6021
  const jsonView = activeTab === "__json" || jsonTabMounted ? /* @__PURE__ */ jsx("div", {
6082
6022
  className: cls("relative flex-1 h-full overflow-auto w-full", { "hidden": activeTab !== JSON_TAB_VALUE }),
6083
6023
  role: "tabpanel",
6084
- children: /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(EntityJsonPreview, { values: formContext?.values ?? entity?.values ?? {} }) })
6024
+ children: /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(JsonPreviewBinding, { values: formContext?.values ?? entity?.values ?? {} }) })
6085
6025
  }, "json_view") : null;
6086
6026
  const historyView = includeHistoryView && activeTab === "__rebase_history" ? /* @__PURE__ */ jsx("div", {
6087
6027
  className: "relative flex-1 h-full overflow-auto w-full",
@@ -6098,7 +6038,7 @@ function EntityEditViewInner({ path, entityId, selectedTab: selectedTabProp, col
6098
6038
  }, "history_view") : null;
6099
6039
  const subCollectionsViews = subcollections && subcollections.map((subcollection) => {
6100
6040
  const subcollectionId = subcollection.slug;
6101
- const newFullPath = usedEntity ? `${path}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(subcollection.slug)}` : void 0;
6041
+ const newFullPath = usedEntity ? `${path}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(getCollectionDataPath(subcollection))}` : void 0;
6102
6042
  if (activeTab !== subcollectionId) return null;
6103
6043
  return /* @__PURE__ */ jsxs("div", {
6104
6044
  className: "relative flex-1 h-full overflow-auto w-full",
@@ -6158,7 +6098,7 @@ function EntityEditViewInner({ path, entityId, selectedTab: selectedTabProp, col
6158
6098
  modifiedValues: usedEntity?.values,
6159
6099
  formContext: readOnlyFormContext
6160
6100
  })
6161
- }) }) : /* @__PURE__ */ jsx(EntityView, {
6101
+ }) }) : /* @__PURE__ */ jsx(EntityViewBinding, {
6162
6102
  className: "px-8 h-full overflow-auto",
6163
6103
  entity,
6164
6104
  path,
@@ -6407,21 +6347,21 @@ function EntityFormSkeleton({ collection }) {
6407
6347
  });
6408
6348
  }
6409
6349
  //#endregion
6410
- //#region src/components/EntitySidePanel.tsx
6350
+ //#region src/components/SidePanelBinding.tsx
6411
6351
  /**
6412
6352
  * This is the component in charge of rendering the side dialog used
6413
- * for editing entities. Use the {@link useSideEntityController} to open
6353
+ * for editing entities. Use the {@link useSidePanel} to open
6414
6354
  * and control the dialogs.
6415
6355
  * This component needs a parent {@link Rebase}
6416
- * {@link useSideEntityController}
6356
+ * {@link useSidePanel}
6417
6357
  * @group Components
6418
6358
  */
6419
- function EntitySidePanel(props) {
6359
+ function SidePanelBinding(props) {
6420
6360
  const { allowFullScreen = true, path, entityId, selectedTab, formProps } = props;
6421
- const ResolvedDetailView = useComponentOverride("Entity.DetailView", EntityDetailView);
6361
+ const ResolvedDetailView = useComponentOverride("DetailView", DetailViewBinding);
6422
6362
  const { blocked, setBlocked, setBlockedNavigationMessage, close } = useSideDialogContext();
6423
6363
  const navigate = useNavigate();
6424
- const sideEntityController = useSideEntityController();
6364
+ const sidePanelController = useSidePanel();
6425
6365
  const collectionRegistryController = useCollectionRegistryController();
6426
6366
  const sideDialogsController = useSideDialogContext();
6427
6367
  const urlController = useUrlController();
@@ -6433,7 +6373,7 @@ function EntitySidePanel(props) {
6433
6373
  const onUpdate = (params) => {
6434
6374
  if (props.onUpdate) props.onUpdate(params);
6435
6375
  setShowEditInPanel(false);
6436
- if (params.status !== "existing") sideEntityController.replace({
6376
+ if (params.status !== "existing") sidePanelController.replace({
6437
6377
  path: params.path,
6438
6378
  entityId: params.entityId,
6439
6379
  selectedTab: params.selectedTab,
@@ -6471,7 +6411,7 @@ function EntitySidePanel(props) {
6471
6411
  });
6472
6412
  if (effectiveDefault && effectiveDefault !== "edit") {
6473
6413
  hasCorrectedDefaultView.current = true;
6474
- sideEntityController.replace({
6414
+ sidePanelController.replace({
6475
6415
  path,
6476
6416
  entityId,
6477
6417
  selectedTab: effectiveDefault,
@@ -6484,7 +6424,7 @@ function EntitySidePanel(props) {
6484
6424
  entityId,
6485
6425
  collection,
6486
6426
  path,
6487
- sideEntityController
6427
+ sidePanelController
6488
6428
  ]);
6489
6429
  const onValuesModified = useCallback((modified) => {
6490
6430
  setBlockedNavigationMessage(modified ? /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -6525,7 +6465,7 @@ function EntitySidePanel(props) {
6525
6465
  }),
6526
6466
  onTabChange: ({ entityId: tabEntityId, selectedTab, collection: paramCollection }) => {
6527
6467
  if (collection?.openEntityMode === "dialog" || paramCollection?.openEntityMode === "dialog") return;
6528
- if (tabEntityId) sideEntityController.replace({
6468
+ if (tabEntityId) sidePanelController.replace({
6529
6469
  path,
6530
6470
  entityId: tabEntityId,
6531
6471
  selectedTab,
@@ -6533,7 +6473,7 @@ function EntitySidePanel(props) {
6533
6473
  collection: paramCollection ?? collection
6534
6474
  });
6535
6475
  }
6536
- }) : /* @__PURE__ */ jsx(EntityEditView, {
6476
+ }) : /* @__PURE__ */ jsx(EditViewBinding, {
6537
6477
  ...props,
6538
6478
  layout: collection?.openEntityMode === "dialog" ? "dialog" : "side_panel",
6539
6479
  collection,
@@ -6564,7 +6504,7 @@ function EntitySidePanel(props) {
6564
6504
  }),
6565
6505
  onTabChange: ({ entityId: tabEntityId, selectedTab, collection: paramCollection }) => {
6566
6506
  if (collection?.openEntityMode === "dialog" || paramCollection?.openEntityMode === "dialog") return;
6567
- if (tabEntityId) sideEntityController.replace({
6507
+ if (tabEntityId) sidePanelController.replace({
6568
6508
  path,
6569
6509
  entityId: tabEntityId,
6570
6510
  selectedTab,
@@ -6576,22 +6516,22 @@ function EntitySidePanel(props) {
6576
6516
  }) }) });
6577
6517
  }
6578
6518
  //#endregion
6579
- //#region src/hooks/useBuildSideEntityController.tsx
6519
+ //#region src/hooks/useBuildSidePanel.tsx
6580
6520
  /**
6581
6521
  * Thin wrapper that resolves the Entity.SidePanel component override.
6582
6522
  * Because the JSX is created inside `propsToSidePanel` (a plain function,
6583
6523
  * not a React component), we need this wrapper so the hook is called at the
6584
6524
  * top level of a React component per the Rules of Hooks.
6585
6525
  */
6586
- function ResolvedEntitySidePanelInner(props) {
6587
- return /* @__PURE__ */ jsx(useComponentOverride("Entity.SidePanel", EntitySidePanel), { ...props });
6526
+ function ResolvedSidePanelBindingInner(props) {
6527
+ return /* @__PURE__ */ jsx(useComponentOverride("Entity.SidePanel", SidePanelBinding), { ...props });
6588
6528
  }
6589
- function ResolvedEntitySidePanel(props) {
6590
- if (props.collection?.components) return /* @__PURE__ */ jsx(CollectionComponentOverrideProvider, {
6591
- overrides: props.collection.components,
6592
- children: /* @__PURE__ */ jsx(ResolvedEntitySidePanelInner, { ...props })
6529
+ function ResolvedSidePanelBinding(props) {
6530
+ if (props.collection) return /* @__PURE__ */ jsx(CollectionScopeProvider, {
6531
+ collection: props.collection,
6532
+ children: /* @__PURE__ */ jsx(ResolvedSidePanelBindingInner, { ...props })
6593
6533
  });
6594
- return /* @__PURE__ */ jsx(ResolvedEntitySidePanelInner, { ...props });
6534
+ return /* @__PURE__ */ jsx(ResolvedSidePanelBindingInner, { ...props });
6595
6535
  }
6596
6536
  var NEW_URL_HASH = "new_side";
6597
6537
  var SIDE_URL_HASH = "side";
@@ -6629,7 +6569,7 @@ function getNestedPropertiesDepth(property, accumulator = 0) {
6629
6569
  else return getNestedPropertiesDepth(property.of, accumulator + 1);
6630
6570
  else return accumulator + 1;
6631
6571
  }
6632
- var useBuildSideEntityController = (collectionRegistryController, urlController, navigationStateController, sideDialogsController, authController) => {
6572
+ var useBuildSidePanel = (collectionRegistryController, urlController, navigationStateController, sideDialogsController, authController) => {
6633
6573
  const location = useLocation();
6634
6574
  const initialised = useRef(false);
6635
6575
  const currentPanelKeysRef = useRef([]);
@@ -6682,7 +6622,7 @@ var useBuildSideEntityController = (collectionRegistryController, urlController,
6682
6622
  sideDialogsController.close();
6683
6623
  }, [sideDialogsController]);
6684
6624
  const open = useCallback((props) => {
6685
- if (props.copy && !props.entityId) throw Error("If you want to copy an entity you need to provide an entityId");
6625
+ if (props.copy && !props.entityId) throw Error("If you want to copy a entity you need to provide a entityId");
6686
6626
  const defaultSelectedView = resolveDefaultSelectedView(props.collection ? props.collection.defaultSelectedView : void 0, {
6687
6627
  status: props.copy ? "copy" : props.entityId ? "existing" : "new",
6688
6628
  entityId: props.entityId
@@ -6700,7 +6640,7 @@ var useBuildSideEntityController = (collectionRegistryController, urlController,
6700
6640
  location.search
6701
6641
  ]);
6702
6642
  const replace = useCallback((props) => {
6703
- if (props.copy && !props.entityId) throw Error("If you want to copy an entity you need to provide an entityId");
6643
+ if (props.copy && !props.entityId) throw Error("If you want to copy a entity you need to provide a entityId");
6704
6644
  sideDialogsController.replace(propsToSidePanel(props, urlController.buildUrlCollectionPath, urlController.resolveDatabasePathsFrom, smallLayout, customizationController, authController, location.search));
6705
6645
  }, [
6706
6646
  urlController.buildUrlCollectionPath,
@@ -6776,7 +6716,7 @@ var propsToSidePanel = (props, buildUrlCollectionPath, resolveIdsFrom, smallLayo
6776
6716
  const entityViewWidth = getEntityViewWidth(props, smallLayout, customizationController);
6777
6717
  return {
6778
6718
  key: `${props.path}/${props.entityId}`,
6779
- component: /* @__PURE__ */ jsx(ResolvedEntitySidePanel, { ...resolvedPanelProps }),
6719
+ component: /* @__PURE__ */ jsx(ResolvedSidePanelBinding, { ...resolvedPanelProps }),
6780
6720
  urlPath,
6781
6721
  parentUrlPath,
6782
6722
  width: entityViewWidth,
@@ -6849,21 +6789,21 @@ function useUrlController() {
6849
6789
  */
6850
6790
  function useCMSContext() {
6851
6791
  const baseContext = useRebaseContext();
6852
- const sideEntityController = useSideEntityController();
6792
+ const sidePanelController = useSidePanel();
6853
6793
  const sideDialogsController = useSideDialogsController();
6854
6794
  const urlController = useUrlController();
6855
6795
  const navigationStateController = useNavigationStateController();
6856
6796
  const collectionRegistryController = useCollectionRegistryController();
6857
6797
  return useMemo(() => ({
6858
6798
  ...baseContext,
6859
- sideEntityController,
6799
+ sidePanelController,
6860
6800
  sideDialogsController,
6861
6801
  urlController,
6862
6802
  navigationStateController,
6863
6803
  collectionRegistryController
6864
6804
  }), [
6865
6805
  baseContext,
6866
- sideEntityController,
6806
+ sidePanelController,
6867
6807
  sideDialogsController,
6868
6808
  urlController,
6869
6809
  navigationStateController,
@@ -6894,8 +6834,13 @@ function resolveNavigationFrom({ path, context }) {
6894
6834
  if (entry.type === "collection") return Promise.resolve(entry);
6895
6835
  else if (entry.type === "entity") {
6896
6836
  if (!collectionRegistryController.getCollection(entry.slug)) throw Error(`No collection defined in the navigation for the entity with path ${entry.slug}`);
6897
- return data.collection(entry.slug).findById(entry.entityId).then((entity) => {
6898
- if (!entity) return void 0;
6837
+ return data.collection(entry.slug).findById(entry.entityId).then((row) => {
6838
+ if (!row) return void 0;
6839
+ const entity = {
6840
+ id: row.id,
6841
+ path: entry.slug,
6842
+ values: row
6843
+ };
6899
6844
  return {
6900
6845
  ...entry,
6901
6846
  entity
@@ -6943,12 +6888,12 @@ function useResolvedNavigationFrom({ path }) {
6943
6888
  ]);
6944
6889
  }
6945
6890
  //#endregion
6946
- //#region src/hooks/useEntityHistory.ts
6891
+ //#region src/hooks/useHistory.ts
6947
6892
  /**
6948
6893
  * Hook to fetch entity history from the backend REST API.
6949
6894
  * Replaces the old subcollection-based approach with a proper API call.
6950
6895
  */
6951
- function useEntityHistory(params) {
6896
+ function useHistory(params) {
6952
6897
  const { slug, entityId, enabled = true, pageSize = 10 } = params;
6953
6898
  const apiConfig = useApiConfig();
6954
6899
  const [entries, setEntries] = useState([]);
@@ -7283,7 +7228,7 @@ function DeleteEntityDialog({ entityOrEntitiesToDelete, collection, onClose, ope
7283
7228
  if (entityOrEntities && multipleEntities) content = /* @__PURE__ */ jsx(Fragment, { children: t("multiple_entities") });
7284
7229
  else {
7285
7230
  const entity = entityOrEntities;
7286
- content = entity ? /* @__PURE__ */ jsx(EntityView, {
7231
+ content = entity ? /* @__PURE__ */ jsx(EntityViewBinding, {
7287
7232
  entity,
7288
7233
  collection,
7289
7234
  path
@@ -7331,7 +7276,7 @@ function DeleteEntityDialog({ entityOrEntitiesToDelete, collection, onClose, ope
7331
7276
  });
7332
7277
  }
7333
7278
  //#endregion
7334
- //#region src/components/EntityCollectionView/utils.ts
7279
+ //#region src/components/CollectionViewBinding/utils.ts
7335
7280
  function addRecentId(collectionId, id) {
7336
7281
  const newRecentIds = [id, ...getRecentIds(collectionId).filter((i) => i !== id)];
7337
7282
  if (newRecentIds.length > 5) newRecentIds.pop();
@@ -7349,11 +7294,11 @@ function getRecentIds(collectionId) {
7349
7294
  //#endregion
7350
7295
  //#region src/util/navigation_utils.ts
7351
7296
  /**
7352
- * Navigate to an entity using either a side panel or full-screen mode.
7297
+ * Navigate to a entity using either a side panel or full-screen mode.
7353
7298
  * This is an admin-specific UI concern and lives here (not in common).
7354
7299
  */
7355
- function navigateToEntity({ openEntityMode, collection, entityId, copy, path, selectedTab, defaultValues, sideEntityController, onClose, navigation, replace }) {
7356
- if (openEntityMode === "side_panel" || openEntityMode === "dialog") sideEntityController.open({
7300
+ function navigateToEntity({ openEntityMode, collection, entityId, copy, path, selectedTab, defaultValues, sidePanelController, onClose, navigation, replace }) {
7301
+ if (openEntityMode === "side_panel" || openEntityMode === "dialog") sidePanelController.open({
7357
7302
  entityId,
7358
7303
  path,
7359
7304
  copy,
@@ -7495,9 +7440,9 @@ var editEntityAction = {
7495
7440
  name: "Edit",
7496
7441
  collapsed: false,
7497
7442
  isEnabled: ({ entity }) => Boolean(entity),
7498
- onClick({ entity, collection, path, context, sideEntityController, highlightEntity, unhighlightEntity, openEntityMode }) {
7443
+ onClick({ entity, collection, path, context, sidePanelController, highlightEntity, unhighlightEntity, openEntityMode }) {
7499
7444
  if (!entity) throw new Error("INTERNAL: editEntityAction: Entity is undefined");
7500
- if (!sideEntityController) throw new Error("INTERNAL: editEntityAction: sideEntityController is undefined");
7445
+ if (!sidePanelController) throw new Error("INTERNAL: editEntityAction: sidePanelController is undefined");
7501
7446
  highlightEntity?.(entity);
7502
7447
  context?.analyticsController?.onAnalyticsEvent?.("entity_click", {
7503
7448
  path: entity.path,
@@ -7509,14 +7454,15 @@ var editEntityAction = {
7509
7454
  status: "existing",
7510
7455
  entityId: entity.id
7511
7456
  });
7457
+ if (!context?.urlController) throw new Error("INTERNAL: editEntityAction: urlController is undefined");
7512
7458
  navigateToEntity({
7513
7459
  openEntityMode,
7514
7460
  collection,
7515
7461
  entityId: entity.id,
7516
7462
  path: newFullIdPath,
7517
- sideEntityController,
7463
+ sidePanelController,
7518
7464
  onClose: () => unhighlightEntity?.(entity),
7519
- navigation: context?.urlController,
7465
+ navigation: context.urlController,
7520
7466
  selectedTab: defaultSelectedView
7521
7467
  });
7522
7468
  return Promise.resolve(void 0);
@@ -7527,24 +7473,25 @@ var copyEntityAction = {
7527
7473
  name: "Copy",
7528
7474
  key: "copy",
7529
7475
  isEnabled: ({ entity }) => Boolean(entity),
7530
- onClick({ entity, collection, context, path, sideEntityController, highlightEntity, unhighlightEntity, openEntityMode }) {
7476
+ onClick({ entity, collection, context, path, sidePanelController, highlightEntity, unhighlightEntity, openEntityMode }) {
7531
7477
  if (!entity) throw new Error("INTERNAL: copyEntityAction: Entity is undefined");
7532
- if (!sideEntityController) throw new Error("INTERNAL: copyEntityAction: sideEntityController is undefined");
7478
+ if (!sidePanelController) throw new Error("INTERNAL: copyEntityAction: sidePanelController is undefined");
7533
7479
  highlightEntity?.(entity);
7534
7480
  context?.analyticsController?.onAnalyticsEvent?.("copy_entity_click", {
7535
7481
  path: entity.path,
7536
7482
  entityId: entity.id
7537
7483
  });
7538
7484
  const usedPath = path ?? collection?.slug ?? entity.path;
7485
+ if (!context?.urlController) throw new Error("INTERNAL: copyEntityAction: urlController is undefined");
7539
7486
  navigateToEntity({
7540
7487
  openEntityMode,
7541
7488
  collection,
7542
7489
  entityId: entity.id,
7543
7490
  path: usedPath,
7544
7491
  copy: true,
7545
- sideEntityController,
7492
+ sidePanelController,
7546
7493
  onClose: () => unhighlightEntity?.(entity),
7547
- navigation: context?.urlController
7494
+ navigation: context.urlController
7548
7495
  });
7549
7496
  return Promise.resolve(void 0);
7550
7497
  }
@@ -7744,7 +7691,7 @@ function injectAuthCollectionConfig(collections) {
7744
7691
  const { dialogsController } = context;
7745
7692
  const creationResult = {
7746
7693
  user: {
7747
- uid: String(props.entityId),
7694
+ uid: String(props.id),
7748
7695
  email: typeof values.email === "string" ? values.email : "",
7749
7696
  displayName: typeof values.displayName === "string" ? values.displayName : "",
7750
7697
  roles: Array.isArray(values.roles) ? values.roles : [],
@@ -7989,7 +7936,7 @@ function useAsyncResolver({ resolver, initialValue, isEqual, deps, disabled }) {
7989
7936
  //#region src/hooks/navigation/useResolvedCollections.ts
7990
7937
  /**
7991
7938
  * Hook that resolves collection props (which may be async builders or arrays)
7992
- * into concrete EntityCollection[], and registers them with the CollectionRegistry.
7939
+ * into concrete CollectionConfig[], and registers them with the CollectionRegistry.
7993
7940
  *
7994
7941
  * When userManagement is provided, the default users collection is always
7995
7942
  * prepended. Developer collections override via generic slug-based dedup
@@ -8472,7 +8419,7 @@ var SideDialogContext = React.createContext({
8472
8419
  var useSideDialogContext = () => useContext(SideDialogContext);
8473
8420
  /**
8474
8421
  * This is the component in charge of rendering the side dialogs used
8475
- * for editing entities. Use the {@link useSideEntityController} to open
8422
+ * for editing entities. Use the {@link useSidePanel} to open
8476
8423
  * and control the dialogs.
8477
8424
  * This component needs a parent {@link Rebase}
8478
8425
  * {@link useSideDialogsController}
@@ -8590,22 +8537,22 @@ function SideDialogView({ offsetPosition, panel, panelIndex, isTopPanel }) {
8590
8537
  });
8591
8538
  }
8592
8539
  //#endregion
8593
- //#region src/components/ReferenceTable/EntitySelectionTable.tsx
8540
+ //#region src/components/ReferenceTable/SelectionTableBinding.tsx
8594
8541
  /**
8595
8542
  * This component allows to select entities from a given collection.
8596
- * You probably want to open this dialog as a side view using {@link useEntitySelectionTable}
8543
+ * You probably want to open this dialog as a side view using {@link useSelectionTableBinding}
8597
8544
  * @group Components
8598
8545
  */
8599
- function EntitySelectionTable(props) {
8546
+ function SelectionTableBinding(props) {
8600
8547
  if (!props.collection) return /* @__PURE__ */ jsx(ErrorView, { error: "Could not find collection" });
8601
- return /* @__PURE__ */ jsx(EntitySelectionTableInternal, {
8548
+ return /* @__PURE__ */ jsx(SelectionTableBindingInternal, {
8602
8549
  ...props,
8603
8550
  collection: props.collection
8604
8551
  });
8605
8552
  }
8606
- function EntitySelectionTableInternal({ onSingleEntitySelected, onMultipleEntitiesSelected, multiselect, collection, path: pathInput, selectedEntityIds: selectedEntityIdsProp, description, fixedFilter, maxSelection }) {
8553
+ function SelectionTableBindingInternal({ onSingleEntitySelected, onMultipleEntitiesSelected, multiselect, collection, path: pathInput, selectedEntityIds: selectedEntityIdsProp, description, fixedFilter, maxSelection }) {
8607
8554
  const sideDialogContext = useSideDialogContext();
8608
- const sideEntityController = useSideEntityController();
8555
+ const sidePanelController = useSidePanel();
8609
8556
  const urlController = useUrlController();
8610
8557
  const analyticsController = useAnalyticsController();
8611
8558
  const path = urlController.resolveDatabasePathsFrom(pathInput);
@@ -8682,7 +8629,7 @@ function EntitySelectionTableInternal({ onSingleEntitySelected, onMultipleEntiti
8682
8629
  ]);
8683
8630
  const onNewClick = () => {
8684
8631
  analyticsController.onAnalyticsEvent?.("reference_selection_new_entity", { path });
8685
- sideEntityController.open({
8632
+ sidePanelController.open({
8686
8633
  path,
8687
8634
  collection,
8688
8635
  updateUrl: true,
@@ -8695,7 +8642,7 @@ function EntitySelectionTableInternal({ onSingleEntitySelected, onMultipleEntiti
8695
8642
  };
8696
8643
  const tableRowActionsBuilder = ({ entity, size, width, frozen }) => {
8697
8644
  const selectedEntities = selectionController.selectedEntities;
8698
- return /* @__PURE__ */ jsx(EntityCollectionRowActions, {
8645
+ return /* @__PURE__ */ jsx(CollectionRowActions, {
8699
8646
  width,
8700
8647
  frozen,
8701
8648
  entity,
@@ -8720,51 +8667,54 @@ function EntitySelectionTableInternal({ onSingleEntitySelected, onMultipleEntiti
8720
8667
  fixedFilter,
8721
8668
  updateUrl: false
8722
8669
  });
8723
- return /* @__PURE__ */ jsxs("div", {
8724
- className: "flex flex-col h-full",
8725
- children: [/* @__PURE__ */ jsx("div", {
8726
- className: "grow",
8727
- children: entitiesDisplayedFirst && /* @__PURE__ */ jsx(EntityCollectionTable, {
8728
- additionalFields: collection.additionalFields,
8729
- displayedColumnIds,
8730
- onEntityClick,
8731
- tableController,
8732
- enablePopupIcon: false,
8733
- tableRowActionsBuilder,
8734
- openEntityMode: "side_panel",
8735
- title: /* @__PURE__ */ jsxs(Typography, {
8736
- variant: "subtitle2",
8737
- className: "flex flex-row gap-2",
8738
- children: [/* @__PURE__ */ jsx(IconForView, {
8739
- size: "small",
8740
- collectionOrView: collection,
8741
- className: "text-surface-300 dark:text-surface-600"
8742
- }), collection.singularName ? `Select ${collection.singularName}` : `Select from ${collection.name}`]
8743
- }),
8744
- defaultSize: collection.defaultSize,
8745
- properties: collection.properties,
8746
- fixedFilter,
8747
- inlineEditing: false,
8748
- selectionController,
8749
- actions: /* @__PURE__ */ jsx(EntitySelectionDialogActions, {
8750
- collection,
8751
- path,
8752
- onNewClick,
8753
- onClear
8670
+ return /* @__PURE__ */ jsx(CollectionScopeProvider, {
8671
+ collection,
8672
+ children: /* @__PURE__ */ jsxs("div", {
8673
+ className: "flex flex-col h-full",
8674
+ children: [/* @__PURE__ */ jsx("div", {
8675
+ className: "grow",
8676
+ children: entitiesDisplayedFirst && /* @__PURE__ */ jsx(CollectionTableBinding, {
8677
+ additionalFields: collection.additionalFields,
8678
+ displayedColumnIds,
8679
+ onEntityClick,
8680
+ tableController,
8681
+ enablePopupIcon: false,
8682
+ tableRowActionsBuilder,
8683
+ openEntityMode: "side_panel",
8684
+ title: /* @__PURE__ */ jsxs(Typography, {
8685
+ variant: "subtitle2",
8686
+ className: "flex flex-row gap-2",
8687
+ children: [/* @__PURE__ */ jsx(IconForView, {
8688
+ size: "small",
8689
+ collectionOrView: collection,
8690
+ className: "text-surface-300 dark:text-surface-600"
8691
+ }), collection.singularName ? `Select ${collection.singularName}` : `Select from ${collection.name}`]
8692
+ }),
8693
+ defaultSize: collection.defaultSize,
8694
+ properties: collection.properties,
8695
+ fixedFilter,
8696
+ inlineEditing: false,
8697
+ selectionController,
8698
+ actions: /* @__PURE__ */ jsx(EntitySelectionDialogActions, {
8699
+ collection,
8700
+ path,
8701
+ onNewClick,
8702
+ onClear
8703
+ })
8754
8704
  })
8755
- })
8756
- }), /* @__PURE__ */ jsxs(DialogActions, {
8757
- translucent: false,
8758
- children: [description && /* @__PURE__ */ jsx(Typography, {
8759
- variant: "body2",
8760
- className: "grow text-left",
8761
- children: description
8762
- }), /* @__PURE__ */ jsx(Button, {
8763
- onClick: onDone,
8764
- variant: "filled",
8765
- children: "Done"
8705
+ }), /* @__PURE__ */ jsxs(DialogActions, {
8706
+ translucent: false,
8707
+ children: [description && /* @__PURE__ */ jsx(Typography, {
8708
+ variant: "body2",
8709
+ className: "grow text-left",
8710
+ children: description
8711
+ }), /* @__PURE__ */ jsx(Button, {
8712
+ onClick: onDone,
8713
+ variant: "filled",
8714
+ children: "Done"
8715
+ })]
8766
8716
  })]
8767
- })]
8717
+ })
8768
8718
  });
8769
8719
  }
8770
8720
  function EntitySelectionDialogActions({ collection, path, onClear, onNewClick }) {
@@ -8789,10 +8739,10 @@ function EntitySelectionDialogActions({ collection, path, onClear, onNewClick })
8789
8739
  }), addButton] });
8790
8740
  }
8791
8741
  //#endregion
8792
- //#region src/components/EntityCollectionView/hooks/useCollectionInlineEditor.ts
8742
+ //#region src/components/CollectionViewBinding/hooks/useCollectionInlineEditor.ts
8793
8743
  function useCollectionInlineEditor({ path, collection, dataClient, context }) {
8794
8744
  const uniqueFieldValidator = useCallback(async ({ name, value, property, entityId }) => {
8795
- const conflictingEntities = (await dataClient.collection(path).find({ where: { [name]: "eq." + value } })).data;
8745
+ const conflictingEntities = (await dataClient.collection(path).find({ where: { [name]: ["==", value] } })).data;
8796
8746
  return conflictingEntities.length === 0 || conflictingEntities.length === 1 && conflictingEntities[0].id === entityId;
8797
8747
  }, [path, dataClient]);
8798
8748
  const onValueChange = useCallback(({ value, propertyKey, onValueUpdated, setError, data: entity }) => {
@@ -9080,7 +9030,7 @@ function ReadOnlyFieldBinding({ propertyKey, value, error, showError, minimalist
9080
9030
  *
9081
9031
  * Please note that if you build a custom field in a component, the
9082
9032
  * **validation** passed in the property will have no effect. You need to set
9083
- * the validation in the `EntityCollection` definition.
9033
+ * the validation in the `CollectionConfig` definition.
9084
9034
  *
9085
9035
  * @param propertyKey You can use nested names such as `address.street` or `friends[2]`
9086
9036
  * @param property
@@ -9663,7 +9613,7 @@ function ArrayOfReferencesFieldBinding({ propertyKey, value, error, showError, d
9663
9613
  const onMultipleEntitiesSelected = useCallback((entities) => {
9664
9614
  setValue(entities.map((e) => getReferenceFrom(e)));
9665
9615
  }, [setValue]);
9666
- const referenceDialogController = useEntitySelectionDialog({
9616
+ const referenceDialogController = useSelectionDialog({
9667
9617
  multiselect: true,
9668
9618
  path: ofProperty.path,
9669
9619
  collection,
@@ -10012,13 +9962,13 @@ function MapEditView({ value, initialValue, setValue, fieldName, disabled }) {
10012
9962
  });
10013
9963
  setInternalState(newRowIds);
10014
9964
  }, [value]);
10015
- const updatetype = (rowId, type) => {
10016
- if (!rowId) {
9965
+ const updatetype = (id, type) => {
9966
+ if (!id) {
10017
9967
  console.warn("No key selected for data type update");
10018
9968
  return;
10019
9969
  }
10020
9970
  setInternalState(internalState.map((row) => {
10021
- if (row[0] === rowId) return [row[0], {
9971
+ if (row[0] === id) return [row[0], {
10022
9972
  key: row[1].key,
10023
9973
  type
10024
9974
  }];
@@ -10026,20 +9976,20 @@ function MapEditView({ value, initialValue, setValue, fieldName, disabled }) {
10026
9976
  }));
10027
9977
  setValue({
10028
9978
  ...value ?? {},
10029
- [internalState.find((row) => row[0] === rowId)?.[1].key ?? ""]: getDefaultValueFortype(type)
9979
+ [internalState.find((row) => row[0] === id)?.[1].key ?? ""]: getDefaultValueFortype(type)
10030
9980
  });
10031
9981
  };
10032
9982
  return /* @__PURE__ */ jsxs("div", {
10033
9983
  className: "py-1 flex flex-col gap-1",
10034
- children: [internalState.map(([rowId, { key: fieldKey, type }], index) => {
9984
+ children: [internalState.map(([id, { key: fieldKey, type }], index) => {
10035
9985
  const entryValue = fieldKey ? value?.[fieldKey] : "";
10036
9986
  const onFieldKeyChange = (newKey) => {
10037
- setInternalState(internalState.map((currentRowId) => {
10038
- if (currentRowId[0] === rowId) return [rowId, {
9987
+ setInternalState(internalState.map((currentId) => {
9988
+ if (currentId[0] === id) return [id, {
10039
9989
  key: newKey ?? "",
10040
- type: currentRowId[1].type
9990
+ type: currentId[1].type
10041
9991
  }];
10042
- return currentRowId;
9992
+ return currentId;
10043
9993
  }));
10044
9994
  if (typeof value === "object" && newKey in value) return;
10045
9995
  const newValue = { ...value ?? {} };
@@ -10051,14 +10001,14 @@ function MapEditView({ value, initialValue, setValue, fieldName, disabled }) {
10051
10001
  });
10052
10002
  };
10053
10003
  return /* @__PURE__ */ jsx(MapKeyValueRow, {
10054
- rowId,
10004
+ id,
10055
10005
  fieldKey,
10056
10006
  value: value ?? {},
10057
10007
  onDeleteClick: () => {
10058
10008
  const newValue = { ...value ?? {} };
10059
10009
  if (initialValue && fieldKey in initialValue) newValue[fieldKey] = void 0;
10060
10010
  else delete newValue[fieldKey];
10061
- setInternalState(internalState.filter((currentRowId) => currentRowId[0] !== rowId));
10011
+ setInternalState(internalState.filter((currentId) => currentId[0] !== id));
10062
10012
  setValue({ ...newValue });
10063
10013
  },
10064
10014
  onFieldKeyChange,
@@ -10067,7 +10017,7 @@ function MapEditView({ value, initialValue, setValue, fieldName, disabled }) {
10067
10017
  type,
10068
10018
  disabled,
10069
10019
  updatetype
10070
- }, rowId);
10020
+ }, id);
10071
10021
  }), /* @__PURE__ */ jsx(Button, {
10072
10022
  variant: "text",
10073
10023
  size: "small",
@@ -10089,7 +10039,7 @@ function MapEditView({ value, initialValue, setValue, fieldName, disabled }) {
10089
10039
  })]
10090
10040
  });
10091
10041
  }
10092
- function MapKeyValueRow({ rowId, fieldKey, value, onFieldKeyChange, onDeleteClick, setValue, entryValue, type, updatetype, disabled }) {
10042
+ function MapKeyValueRow({ id, fieldKey, value, onFieldKeyChange, onDeleteClick, setValue, entryValue, type, updatetype, disabled }) {
10093
10043
  const { locale } = useCustomizationController();
10094
10044
  const { t } = useTranslation();
10095
10045
  function buildInput(entryValue, fieldKey, type) {
@@ -10151,7 +10101,7 @@ function MapKeyValueRow({ rowId, fieldKey, value, onFieldKeyChange, onDeleteClic
10151
10101
  children: /* @__PURE__ */ jsx(ArrayContainer, {
10152
10102
  value: arrayValue,
10153
10103
  newDefaultEntry: "",
10154
- droppableId: rowId.toString(),
10104
+ droppableId: id.toString(),
10155
10105
  addLabel: fieldKey ? t("add_to_field", { fieldName: fieldKey }) : t("add"),
10156
10106
  size: "small",
10157
10107
  disabled: disabled || !fieldKey,
@@ -10199,7 +10149,7 @@ function MapKeyValueRow({ rowId, fieldKey, value, onFieldKeyChange, onDeleteClic
10199
10149
  });
10200
10150
  }
10201
10151
  function doUpdatetype(type) {
10202
- updatetype(rowId, type);
10152
+ updatetype(id, type);
10203
10153
  }
10204
10154
  return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(Typography, {
10205
10155
  component: "div",
@@ -10268,7 +10218,7 @@ function MapKeyValueRow({ rowId, fieldKey, value, onFieldKeyChange, onDeleteClic
10268
10218
  })]
10269
10219
  })
10270
10220
  ]
10271
- }, rowId.toString()), (type === "map" || type === "array") && buildInput(entryValue, fieldKey, type)] });
10221
+ }, id.toString()), (type === "map" || type === "array") && buildInput(entryValue, fieldKey, type)] });
10272
10222
  }
10273
10223
  function ArrayKeyValueRow({ id, index, value, setValue }) {
10274
10224
  const { locale } = useCustomizationController();
@@ -10489,8 +10439,18 @@ function MarkdownEditorFieldBinding({ property, propertyKey, value, setValue, in
10489
10439
  const disabled = disabledProp || isSubmitting;
10490
10440
  const highlight = customProps?.highlight;
10491
10441
  const editorProps = customProps?.editorProps;
10492
- const storageSource = useStorageSource();
10442
+ const defaultStorageSource = useStorageSource();
10493
10443
  const storage = property.storage;
10444
+ const storageSources = useStorageSources();
10445
+ const storageSource = useMemo(() => resolveStorageSource({
10446
+ sourceKey: storage?.storageSource,
10447
+ sources: storageSources.sources,
10448
+ defaultSource: defaultStorageSource
10449
+ }), [
10450
+ storage?.storageSource,
10451
+ storageSources.sources,
10452
+ defaultStorageSource
10453
+ ]);
10494
10454
  const entityValues = context.values;
10495
10455
  const entityId = context.entityId;
10496
10456
  const path = context.path;
@@ -10701,91 +10661,6 @@ function MultiSelectFieldBinding({ propertyKey, value, setValue, error, showErro
10701
10661
  })] });
10702
10662
  }
10703
10663
  //#endregion
10704
- //#region src/form/field_bindings/ReferenceAsStringFieldBinding.tsx
10705
- /**
10706
- * Field that opens a reference selection dialog and stores the entity ID as a string.
10707
- *
10708
- * This is one of the internal components that get mapped natively inside forms
10709
- * and tables to the specified properties.
10710
- * @group Form fields
10711
- */
10712
- function ReferenceAsStringFieldBinding(props) {
10713
- if (typeof props.property.reference?.path !== "string") return /* @__PURE__ */ jsx(ReadOnlyFieldBinding, { ...props });
10714
- return /* @__PURE__ */ jsx(ReferenceAsStringFieldBindingInternal, { ...props });
10715
- }
10716
- function ReferenceAsStringFieldBindingInternal({ propertyKey, value, setValue, error, showError, isSubmitting, disabled, minimalistView, property, includeDescription, size = "medium" }) {
10717
- if (!property.reference?.path) throw new Error("Property path is required for ReferenceAsStringFieldBinding");
10718
- useClearRestoreValue({
10719
- property,
10720
- value,
10721
- setValue
10722
- });
10723
- const collectionRegistryController = useCollectionRegistryController();
10724
- const path = property.reference.path;
10725
- const collection = useMemo(() => {
10726
- return path ? collectionRegistryController.getCollection(path) : void 0;
10727
- }, [path]);
10728
- const referenceValue = useMemo(() => {
10729
- if (value && path) return new EntityReference({
10730
- id: value,
10731
- path
10732
- });
10733
- }, [value, path]);
10734
- if (!collection) throw Error(`Couldn't find the corresponding collection for the path: ${path}`);
10735
- const referenceDialogController = useEntitySelectionDialog({
10736
- multiselect: false,
10737
- path,
10738
- collection,
10739
- onSingleEntitySelected: useCallback((e) => {
10740
- setValue(e ? String(e.id) : null);
10741
- }, [setValue]),
10742
- selectedEntityIds: value ? [value] : void 0,
10743
- fixedFilter: property.reference?.fixedFilter
10744
- });
10745
- const onEntryClick = (e) => {
10746
- e.preventDefault();
10747
- referenceDialogController.open();
10748
- };
10749
- return /* @__PURE__ */ jsxs(Fragment, { children: [
10750
- !minimalistView && /* @__PURE__ */ jsx(LabelWithIconAndTooltip, {
10751
- propertyKey,
10752
- icon: getIconForProperty(property, "small"),
10753
- required: property.validation?.required,
10754
- title: property.name ?? propertyKey,
10755
- className: "h-8 text-text-secondary dark:text-text-secondary-dark ml-3.5"
10756
- }),
10757
- !collection && /* @__PURE__ */ jsx(ErrorView, { error: "The specified collection does not exist. Check console" }),
10758
- collection && /* @__PURE__ */ jsxs(Fragment, { children: [referenceValue && /* @__PURE__ */ jsx(ReferencePreview, {
10759
- disabled: !path,
10760
- previewProperties: property.reference?.ui?.previewProperties,
10761
- hover: !disabled,
10762
- size,
10763
- onClick: disabled || isSubmitting ? void 0 : onEntryClick,
10764
- reference: referenceValue,
10765
- includeEntityLink: property.reference?.includeEntityLink,
10766
- includeId: property.reference?.includeId
10767
- }), !value && /* @__PURE__ */ jsx("div", {
10768
- className: "justify-center text-left",
10769
- children: /* @__PURE__ */ jsxs(EntityPreviewContainer, {
10770
- className: cls("px-6 h-16 text-sm font-medium flex items-center gap-6", disabled || isSubmitting ? "text-surface-accent-500" : "cursor-pointer text-surface-accent-700 dark:text-surface-accent-300 hover:bg-surface-accent-50 dark:hover:bg-surface-800 group-hover:bg-surface-accent-50 dark:group-hover:bg-surface-800"),
10771
- onClick: onEntryClick,
10772
- size: "medium",
10773
- children: [/* @__PURE__ */ jsx(IconForView, {
10774
- collectionOrView: collection,
10775
- className: "text-surface-300 dark:text-surface-600"
10776
- }), `Edit ${property.name}`.toUpperCase()]
10777
- })
10778
- })] }),
10779
- /* @__PURE__ */ jsx(FieldHelperText, {
10780
- includeDescription,
10781
- showError,
10782
- error,
10783
- disabled,
10784
- property
10785
- })
10786
- ] });
10787
- }
10788
- //#endregion
10789
10664
  //#region src/form/field_bindings/ReferenceFieldBinding.tsx
10790
10665
  /**
10791
10666
  * Field that opens a reference selection dialog.
@@ -10815,7 +10690,7 @@ function ReferenceFieldBindingInternal({ propertyKey, value, setValue, error, sh
10815
10690
  const onSingleEntitySelected = useCallback((e) => {
10816
10691
  setValue(e ? getReferenceFrom(e) : null);
10817
10692
  }, [setValue, propertyKey]);
10818
- const referenceDialogController = useEntitySelectionDialog({
10693
+ const referenceDialogController = useSelectionDialog({
10819
10694
  multiselect: false,
10820
10695
  path: property.path,
10821
10696
  collection,
@@ -11078,9 +10953,9 @@ var acceptDropClasses = "transition-colors duration-200 ease-[cubic-bezier(0,0,0
11078
10953
  var rejectDropClasses = "transition-colors duration-200 ease-[cubic-bezier(0,0,0.2,1)] border-2 border-solid border-red-500";
11079
10954
  function StorageUploadFieldBinding({ propertyKey, value, setValue, error, showError, autoFocus, minimalistView, property, includeDescription, context, isSubmitting }) {
11080
10955
  useAuthController();
11081
- const storageSource = useStorageSource(context.collection);
10956
+ const storageSource = useStorageSource();
11082
10957
  const disabled = isReadOnly(property) || !!property.ui?.disabled || isSubmitting || context.disabled;
11083
- const { internalValue, setInternalValue, onFilesAdded, storage, onFileUploadComplete, storagePathBuilder, multipleFilesSupported } = useStorageUploadController({
10958
+ const { internalValue, setInternalValue, onFilesAdded, storage, onFileUploadComplete, storagePathBuilder, multipleFilesSupported, resolvedStorageSource } = useStorageUploadController({
11084
10959
  entityValues: context.values,
11085
10960
  entityId: context.entityId,
11086
10961
  path: context.path,
@@ -11104,19 +10979,22 @@ function StorageUploadFieldBinding({ propertyKey, value, setValue, error, showEr
11104
10979
  title: property.name ?? propertyKey,
11105
10980
  className: "h-8 text-text-secondary dark:text-text-secondary-dark ml-3.5"
11106
10981
  }),
11107
- /* @__PURE__ */ jsx(StorageUpload, {
11108
- value: internalValue,
11109
- name: propertyKey,
11110
- disabled: disabled ?? false,
11111
- autoFocus: autoFocus ?? false,
11112
- property,
11113
- onChange: setValue,
11114
- setInternalValue,
11115
- onFilesAdded,
11116
- onFileUploadComplete,
11117
- storagePathBuilder,
11118
- storage,
11119
- multipleFilesSupported
10982
+ /* @__PURE__ */ jsx(StorageSourceContext.Provider, {
10983
+ value: resolvedStorageSource,
10984
+ children: /* @__PURE__ */ jsx(StorageUpload, {
10985
+ value: internalValue,
10986
+ name: propertyKey,
10987
+ disabled: disabled ?? false,
10988
+ autoFocus: autoFocus ?? false,
10989
+ property,
10990
+ onChange: setValue,
10991
+ setInternalValue,
10992
+ onFilesAdded,
10993
+ onFileUploadComplete,
10994
+ storagePathBuilder,
10995
+ storage,
10996
+ multipleFilesSupported
10997
+ })
11120
10998
  }),
11121
10999
  /* @__PURE__ */ jsx(FieldHelperText, {
11122
11000
  includeDescription,
@@ -11623,7 +11501,7 @@ function MultipleRelationFieldBinding({ propertyKey, value: valueProp, error, sh
11623
11501
  const { t } = useTranslation();
11624
11502
  if (property.type !== "relation") throw Error("RelationFieldBinding expected a property containing a relation");
11625
11503
  const parentCollection = context.collection;
11626
- const capabilities = parentCollection ? getDataSourceCapabilities(parentCollection.driver) : void 0;
11504
+ const capabilities = parentCollection ? getDataSourceCapabilities(parentCollection.engine) : void 0;
11627
11505
  if (!parentCollection || !capabilities?.supportsRelations || !("relations" in parentCollection) || !parentCollection.relations) throw Error("RelationFieldBinding expected a collection with relations support");
11628
11506
  const relation = resolveRelationProperty(property, parentCollection.relations, propertyKey).relation;
11629
11507
  if (!relation) throw Error("Property relation is required for MultipleRelationFieldBinding");
@@ -11632,9 +11510,9 @@ function MultipleRelationFieldBinding({ propertyKey, value: valueProp, error, sh
11632
11510
  const onMultipleEntitiesSelected = useCallback((entities) => {
11633
11511
  setValue(entities.map((e) => getRelationFrom(e)));
11634
11512
  }, [setValue]);
11635
- const referenceDialogController = useEntitySelectionDialog({
11513
+ const referenceDialogController = useSelectionDialog({
11636
11514
  multiselect: true,
11637
- path: collection.slug,
11515
+ path: getCollectionDataPath(collection),
11638
11516
  collection,
11639
11517
  onMultipleEntitiesSelected,
11640
11518
  selectedEntityIds,
@@ -11720,7 +11598,7 @@ function RelationFieldBinding(props) {
11720
11598
  const { property, propertyKey, context } = props;
11721
11599
  if (property.type !== "relation") throw Error("RelationFieldBinding expected a property containing a relation");
11722
11600
  const collection = context.collection;
11723
- const capabilities = collection ? getDataSourceCapabilities(collection.driver) : void 0;
11601
+ const capabilities = collection ? getDataSourceCapabilities(collection.engine) : void 0;
11724
11602
  if (!collection || !capabilities?.supportsRelations || !("relations" in collection) || !collection.relations) throw Error("RelationFieldBinding expected a collection with relations support");
11725
11603
  const relation = resolveRelationProperty(property, collection.relations, propertyKey).relation;
11726
11604
  const manyRelation = relation?.cardinality === "many";
@@ -11778,9 +11656,9 @@ function SingleRelationFieldBinding({ propertyKey, value, size, error, showError
11778
11656
  const onSingleEntitySelected = useCallback((e) => {
11779
11657
  setValue(e ? getRelationFrom(e) : null);
11780
11658
  }, [setValue]);
11781
- const referenceDialogController = useEntitySelectionDialog({
11659
+ const referenceDialogController = useSelectionDialog({
11782
11660
  multiselect: false,
11783
- path: collection.slug,
11661
+ path: getCollectionDataPath(collection),
11784
11662
  collection,
11785
11663
  onSingleEntitySelected,
11786
11664
  selectedEntityIds: validValue && normalizedValue ? [normalizedValue.id] : void 0,
@@ -12052,17 +11930,6 @@ var DEFAULT_FIELD_CONFIGS = {
12052
11930
  ui: { Field: StorageUploadFieldBinding }
12053
11931
  }
12054
11932
  },
12055
- reference_as_string: {
12056
- key: "reference_as_string",
12057
- name: "Reference (as string)",
12058
- description: "The value refers to a different collection (it is saved as a string)",
12059
- Icon: LinkIcon,
12060
- color: "#154fb3",
12061
- property: {
12062
- type: "string",
12063
- ui: { Field: ReferenceAsStringFieldBinding }
12064
- }
12065
- },
12066
11933
  reference: {
12067
11934
  key: "reference",
12068
11935
  name: "Reference",
@@ -12208,7 +12075,6 @@ function getDefaultFieldId(property) {
12208
12075
  else if (property.email) return "email";
12209
12076
  else if (property.enum) return "select";
12210
12077
  else if (property.userSelect) return "user_select";
12211
- else if (property.reference) return "reference_as_string";
12212
12078
  else return "text_field";
12213
12079
  else if (property.type === "number") {
12214
12080
  if (property.enum) return "number_select";
@@ -13119,10 +12985,10 @@ function EditorCollectionAction({ path, parentCollectionSlugs, parentEntityIds,
13119
12985
  }) });
13120
12986
  }
13121
12987
  //#endregion
13122
- //#region src/components/EntityCollectionView/EntityCollectionViewActions.tsx
12988
+ //#region src/components/CollectionViewBinding/CollectionViewActions.tsx
13123
12989
  var ImportCollectionAction$1 = lazy(() => Promise.resolve().then(() => import_exports).then((m) => ({ default: m.ImportCollectionAction })));
13124
12990
  var ExportCollectionAction$1 = lazy(() => Promise.resolve().then(() => export_exports).then((m) => ({ default: m.ExportCollectionAction })));
13125
- function EntityCollectionViewActions({ collection, relativePath, parentCollectionSlugs, parentEntityIds, onNewClick, onMultipleDeleteClick, selectionEnabled, path, selectionController, tableController, collectionEntitiesCount, compact, children, openNewDocument }) {
12991
+ function CollectionViewActions({ collection, relativePath, parentCollectionSlugs, parentEntityIds, onNewClick, onMultipleDeleteClick, selectionEnabled, path, selectionController, tableController, collectionEntitiesCount, compact, children, openNewDocument }) {
13126
12992
  const context = useCMSContext();
13127
12993
  const { canCreate, canDelete } = usePermissions();
13128
12994
  const largeLayout = useLargeLayout();
@@ -13227,7 +13093,7 @@ function EntityCollectionViewActions({ collection, relativePath, parentCollectio
13227
13093
  });
13228
13094
  }
13229
13095
  //#endregion
13230
- //#region src/components/EntityCollectionView/useEntityPreviewSlots.ts
13096
+ //#region src/components/CollectionViewBinding/usePreviewSlots.ts
13231
13097
  /**
13232
13098
  * Resolve which property key fills each slot for a given collection.
13233
13099
  * Pure function — call inside `useMemo`.
@@ -13293,8 +13159,8 @@ function resolveCollectionSlotKeys(collection, authController, propertyConfigs)
13293
13159
  const sortedPreviewKeys = hasExplicitOrder ? previewKeys : [...previewKeys].sort((a, b) => {
13294
13160
  const propA = collection.properties[a];
13295
13161
  const propB = collection.properties[b];
13296
- const scoreA = propA?.type === "string" ? propA.multiline ? 2 : 1 : 0;
13297
- return (propB?.type === "string" ? propB.multiline ? 2 : 1 : 0) - scoreA;
13162
+ const scoreA = propA?.type === "string" ? propA.ui?.multiline ? 2 : 1 : 0;
13163
+ return (propB?.type === "string" ? propB.ui?.multiline ? 2 : 1 : 0) - scoreA;
13298
13164
  });
13299
13165
  return {
13300
13166
  titleKey,
@@ -13487,7 +13353,7 @@ function resolveRelationDisplayName(relation, prop) {
13487
13353
  return false;
13488
13354
  };
13489
13355
  const isDisplayCandidate = (p) => {
13490
- return p.type === "string" && !p.multiline && !p.markdown && !p.storage && !("isId" in p && p.isId) && !isHiddenProp(p);
13356
+ return p.type === "string" && !p.ui?.multiline && !p.ui?.markdown && !p.storage && !("isId" in p && p.isId) && !isHiddenProp(p);
13491
13357
  };
13492
13358
  for (const pk of [
13493
13359
  "name",
@@ -13522,12 +13388,12 @@ function resolveRelationDisplayName(relation, prop) {
13522
13388
  return id !== void 0 ? String(id) : void 0;
13523
13389
  }
13524
13390
  //#endregion
13525
- //#region src/components/EntityCollectionView/EntityCard.tsx
13391
+ //#region src/components/CollectionViewBinding/EntityCardBinding.tsx
13526
13392
  /**
13527
- * Card component for displaying an entity in a grid view.
13393
+ * Card component for displaying a entity in a grid view.
13528
13394
  * Shows thumbnail, title, and preview properties via the shared slot system.
13529
13395
  */
13530
- function EntityCard({ entity, collection, onClick, selected, highlighted, onSelectionChange, selectionEnabled, size = "m" }) {
13396
+ function EntityCardBinding({ entity, collection, onClick, selected, highlighted, onSelectionChange, selectionEnabled, size = "m" }) {
13531
13397
  const authController = useAuthController();
13532
13398
  const analyticsController = useAnalyticsController();
13533
13399
  const slotKeys = useCollectionSlotKeys(collection, authController, useCustomizationController().propertyConfigs);
@@ -13646,13 +13512,13 @@ function EntityCard({ entity, collection, onClick, selected, highlighted, onSele
13646
13512
  });
13647
13513
  }
13648
13514
  //#endregion
13649
- //#region src/components/EntityCollectionView/EntityCollectionCardView.tsx
13515
+ //#region src/components/CollectionViewBinding/CollectionCardViewBinding.tsx
13650
13516
  /**
13651
13517
  * Card grid view for displaying entities with infinite scroll.
13652
- * Alternative to the EntityCollectionTable for visual browsing.
13518
+ * Alternative to the CollectionTableBinding for visual browsing.
13653
13519
  */
13654
- function EntityCollectionCardView({ collection, tableController, onEntityClick, selectionController, selectionEnabled = true, highlightedEntities, emptyComponent, onScroll, initialScroll, size = "m" }) {
13655
- const ResolvedEntityCard = useComponentOverride("Collection.Card", EntityCard);
13520
+ function CollectionCardViewBinding({ collection, tableController, onEntityClick, selectionController, selectionEnabled = true, highlightedEntities, emptyComponent, onScroll, initialScroll, size = "m" }) {
13521
+ const ResolvedEntityCard = useComponentOverride("Collection.Card", EntityCardBinding);
13656
13522
  const { data, dataLoading, noMoreToLoad, dataLoadingError, itemCount, setItemCount, pageSize = 50, paginationEnabled } = tableController;
13657
13523
  const handleEntityClick = useCallback((entity) => {
13658
13524
  onEntityClick?.(entity);
@@ -13702,7 +13568,7 @@ function EntityCollectionCardView({ collection, tableController, onEntityClick,
13702
13568
  });
13703
13569
  }
13704
13570
  //#endregion
13705
- //#region src/components/EntityCollectionView/EntityCollectionListView.tsx
13571
+ //#region src/components/CollectionViewBinding/CollectionListViewBinding.tsx
13706
13572
  /**
13707
13573
  * Get row padding/spacing classes based on size
13708
13574
  */
@@ -13823,7 +13689,7 @@ function formatDateValue(value) {
13823
13689
  * - Column-sortable headers
13824
13690
  * - Infinite scroll
13825
13691
  */
13826
- function EntityCollectionListView({ collection, tableController, onEntityClick, selectionController, selectionEnabled = true, highlightedEntities, emptyComponent, size = "m", selectedEntityId, getActionsForEntity, path, openEntityMode }) {
13692
+ function CollectionListViewBinding({ collection, tableController, onEntityClick, selectionController, selectionEnabled = true, highlightedEntities, emptyComponent, size = "m", selectedEntityId, getActionsForEntity, path, openEntityMode }) {
13827
13693
  const authController = useAuthController();
13828
13694
  const customizationController = useCustomizationController();
13829
13695
  const analyticsController = useAnalyticsController();
@@ -13903,7 +13769,17 @@ function EntityCollectionListView({ collection, tableController, onEntityClick,
13903
13769
  subtitleKey,
13904
13770
  "id"
13905
13771
  ]);
13906
- allKeys.filter((k) => !usedKeys.has(k) && resolvedCollection.properties[k]).forEach((key) => {
13772
+ allKeys.filter((k) => {
13773
+ if (usedKeys.has(k)) return false;
13774
+ const prop = resolvedCollection.properties[k];
13775
+ if (!prop) return false;
13776
+ if (prop.type === "string" && (prop.storage || prop.ui?.url === "image")) return false;
13777
+ if (prop.type === "array" && prop.of && !Array.isArray(prop.of)) {
13778
+ const inner = prop.of;
13779
+ if (inner.type === "string" && (inner.storage || inner.ui?.url === "image")) return false;
13780
+ }
13781
+ return true;
13782
+ }).forEach((key) => {
13907
13783
  const prop = resolvedCollection.properties[key];
13908
13784
  cols.push({
13909
13785
  key,
@@ -14256,7 +14132,7 @@ var ListRow = React.memo(function ListRow({ entity, collection, onClick, selecte
14256
14132
  path,
14257
14133
  collection,
14258
14134
  context,
14259
- sideEntityController: context?.sideEntityController,
14135
+ sidePanelController: context?.sidePanelController,
14260
14136
  selectionController,
14261
14137
  openEntityMode: openEntityMode ?? collection?.openEntityMode ?? "full_screen"
14262
14138
  });
@@ -14269,7 +14145,7 @@ var ListRow = React.memo(function ListRow({ entity, collection, onClick, selecte
14269
14145
  });
14270
14146
  });
14271
14147
  //#endregion
14272
- //#region src/components/EntityCollectionView/SplitListView.tsx
14148
+ //#region src/components/CollectionViewBinding/SplitListView.tsx
14273
14149
  var PANEL_SIZE_KEY = "rebase_split_list_panel_size";
14274
14150
  function getSavedPanelSize(path) {
14275
14151
  try {
@@ -14298,7 +14174,7 @@ function savePanelSize(path, size) {
14298
14174
  * State management:
14299
14175
  * - The selected entity is driven by the URL path (e.g. /c/authors/14).
14300
14176
  * `selectedEntityId` comes from props via RebaseRoute, NOT from internal state.
14301
- * - Clicking an entity navigates to /c/authors/{id} via the standard onEntityClick handler.
14177
+ * - Clicking a entity navigates to /c/authors/{id} via the standard onEntityClick handler.
14302
14178
  * - Closing the detail navigates back to /c/authors.
14303
14179
  */
14304
14180
  function SplitListView({ collection, tableController, onEntityClick: externalOnEntityClick, onNewClick: externalOnNewClick, selectionController, selectionEnabled = true, highlightedEntities, emptyComponent, onScroll, initialScroll, size = "m", path, parentCollectionSlugs, parentEntityIds, selectedEntityId, selectedTab, toolbar, children }) {
@@ -14428,7 +14304,7 @@ function SplitListView({ collection, tableController, onEntityClick: externalOnE
14428
14304
  const detailPanel = renderedEntityId !== void 0 ? /* @__PURE__ */ jsx("div", {
14429
14305
  className: cls("flex-1 flex flex-col min-w-0 h-full transition-all ease-out w-full", animationPhase === "entered" ? "opacity-100 translate-x-0" : largeLayout ? "opacity-0 translate-x-8" : "opacity-0 translate-x-1/3"),
14430
14306
  style: { transitionDuration: `${TRANSITION_DURATION}ms` },
14431
- children: /* @__PURE__ */ jsx(ErrorBoundary, { children: collection.defaultEntityAction === "view" && !isEditMode ? /* @__PURE__ */ jsx(EntityDetailView, {
14307
+ children: /* @__PURE__ */ jsx(ErrorBoundary, { children: collection.defaultEntityAction === "view" && !isEditMode ? /* @__PURE__ */ jsx(DetailViewBinding, {
14432
14308
  path,
14433
14309
  collection,
14434
14310
  entityId: renderedEntityId,
@@ -14449,7 +14325,7 @@ function SplitListView({ collection, tableController, onEntityClick: externalOnE
14449
14325
  if (currentViewParam) entityUrl += `${entityUrl.includes("?") ? "&" : "?"}__view=${currentViewParam}`;
14450
14326
  navigate(entityUrl);
14451
14327
  }
14452
- }, String(renderedEntityId)) : /* @__PURE__ */ jsx(EntityEditView, {
14328
+ }, String(renderedEntityId)) : /* @__PURE__ */ jsx(EditViewBinding, {
14453
14329
  path,
14454
14330
  collection,
14455
14331
  entityId: renderedEntityId,
@@ -14489,16 +14365,16 @@ function SplitListView({ collection, tableController, onEntityClick: externalOnE
14489
14365
  });
14490
14366
  }
14491
14367
  //#endregion
14492
- //#region src/components/EntityCollectionView/EntityBoardCard.tsx
14368
+ //#region src/components/CollectionViewBinding/BoardCardBinding.tsx
14493
14369
  /**
14494
- * Compact card component for displaying an entity in a Kanban board.
14370
+ * Compact card component for displaying a entity in a Kanban board.
14495
14371
  * Uses the shared slot system for consistent preview rendering.
14496
14372
  *
14497
14373
  * Selection UX: The checkbox overlays on top of the image/icon thumbnail area,
14498
14374
  * revealed on card hover or when the card is selected. This keeps the card
14499
14375
  * layout clean while providing intuitive selection affordance.
14500
14376
  */
14501
- function EntityBoardCardInner({ item, isDragging, isGroupedOver, style, collection, onClick, selected, onSelectionChange, selectionEnabled = false }) {
14377
+ function BoardCardBindingInner({ item, isDragging, isGroupedOver, style, collection, onClick, selected, onSelectionChange, selectionEnabled = false }) {
14502
14378
  const entity = item.data;
14503
14379
  const slotKeys = useCollectionSlotKeys(collection, useAuthController(), useCustomizationController().propertyConfigs);
14504
14380
  const slots = useMemo(() => resolveEntitySlots(entity, collection, slotKeys), [
@@ -14635,9 +14511,9 @@ function EntityBoardCardInner({ item, isDragging, isGroupedOver, style, collecti
14635
14511
  })
14636
14512
  });
14637
14513
  }
14638
- var EntityBoardCard = memo(EntityBoardCardInner);
14514
+ var BoardCardBinding = memo(BoardCardBindingInner);
14639
14515
  //#endregion
14640
- //#region src/components/EntityCollectionView/useBoardDataController.tsx
14516
+ //#region src/components/CollectionViewBinding/useBoardDataController.tsx
14641
14517
  var DEFAULT_PAGE_SIZE$1 = 20;
14642
14518
  /**
14643
14519
  * Shallow equality for entity value records.
@@ -14761,19 +14637,11 @@ function useBoardDataController({ fullPath, collection, columnProperty, columns,
14761
14637
  }));
14762
14638
  return;
14763
14639
  }
14764
- const whereMap = {};
14765
- if (currentFilterValues) Object.entries(currentFilterValues).forEach(([key, value]) => {
14766
- if (value && Array.isArray(value)) {
14767
- const [op, val] = value;
14768
- const postgrestOp = op === "==" ? "eq" : op === "!=" ? "neq" : op === ">" ? "gt" : op === ">=" ? "gte" : op === "<" ? "lt" : op === "<=" ? "lte" : op === "in" ? "in" : op === "not-in" ? "nin" : op === "array-contains" ? "cs" : op === "array-contains-any" ? "csa" : "eq";
14769
- let stringVal;
14770
- if (Array.isArray(val)) stringVal = `(${val.join(",")})`;
14771
- else stringVal = String(val);
14772
- whereMap[key] = `${postgrestOp}.${stringVal}`;
14773
- }
14774
- });
14775
- whereMap[currentColumnProperty] = `eq.${column}`;
14776
- const orderByParam = currentOrderProperty ? `${currentOrderProperty}:asc` : void 0;
14640
+ const whereFilter = {
14641
+ ...currentFilterValues ?? {},
14642
+ [currentColumnProperty]: ["==", column]
14643
+ };
14644
+ const orderByParam = currentOrderProperty ? [currentOrderProperty, "asc"] : void 0;
14777
14645
  setColumnData((prev) => ({
14778
14646
  ...prev,
14779
14647
  [column]: {
@@ -14824,12 +14692,21 @@ function useBoardDataController({ fullPath, collection, columnProperty, columns,
14824
14692
  return valA < valB ? -1 : valA > valB ? 1 : 0;
14825
14693
  });
14826
14694
  if (currentCollection.callbacks?.afterRead) try {
14827
- processed = await Promise.all(processed.map((entity) => currentCollection.callbacks.afterRead({
14828
- collection: currentCollection,
14829
- path: currentResolvedPath,
14830
- entity,
14831
- context: currentContext
14832
- })));
14695
+ processed = await Promise.all(processed.map(async (entity) => {
14696
+ const processedRow = await currentCollection.callbacks.afterRead({
14697
+ collection: currentCollection,
14698
+ path: currentResolvedPath,
14699
+ row: {
14700
+ id: entity.id,
14701
+ ...entity.values
14702
+ },
14703
+ context: currentContext
14704
+ });
14705
+ return {
14706
+ ...entity,
14707
+ values: processedRow
14708
+ };
14709
+ }));
14833
14710
  } catch (e) {
14834
14711
  console.error("Error in afterRead callback:", e);
14835
14712
  }
@@ -14881,13 +14758,13 @@ function useBoardDataController({ fullPath, collection, columnProperty, columns,
14881
14758
  const accessor = currentDataClient.collection(currentResolvedPath);
14882
14759
  if (accessor.listen) {
14883
14760
  const unsubscribe = accessor.listen({
14884
- where: whereMap,
14761
+ where: whereFilter,
14885
14762
  limit: itemCount,
14886
14763
  orderBy: orderByParam
14887
14764
  }, (res) => onUpdate(res.data), onError);
14888
14765
  unsubscribersRef.current[column] = unsubscribe;
14889
14766
  } else accessor.find({
14890
- where: whereMap,
14767
+ where: whereFilter,
14891
14768
  limit: itemCount,
14892
14769
  orderBy: orderByParam
14893
14770
  }).then((res) => onUpdate(res.data)).catch(onError);
@@ -14916,19 +14793,11 @@ function useBoardDataController({ fullPath, collection, columnProperty, columns,
14916
14793
  if (isColumnExcludedByFilter(column, currentFilterValues, currentColumnProperty)) return;
14917
14794
  const accessor = currentDataClient.collection(currentResolvedPath);
14918
14795
  if (accessor.count) {
14919
- const whereMap = {};
14920
- if (currentFilterValues) Object.entries(currentFilterValues).forEach(([key, value]) => {
14921
- if (value && Array.isArray(value)) {
14922
- const [op, val] = value;
14923
- const postgrestOp = op === "==" ? "eq" : op === "!=" ? "neq" : op === ">" ? "gt" : op === ">=" ? "gte" : op === "<" ? "lt" : op === "<=" ? "lte" : op === "in" ? "in" : op === "not-in" ? "nin" : op === "array-contains" ? "cs" : op === "array-contains-any" ? "csa" : "eq";
14924
- let stringVal;
14925
- if (Array.isArray(val)) stringVal = `(${val.join(",")})`;
14926
- else stringVal = String(val);
14927
- whereMap[key] = `${postgrestOp}.${stringVal}`;
14928
- }
14929
- });
14930
- whereMap[currentColumnProperty] = `eq.${column}`;
14931
- accessor.count({ where: whereMap }).then((count) => {
14796
+ const whereFilter = {
14797
+ ...currentFilterValues ?? {},
14798
+ [currentColumnProperty]: ["==", column]
14799
+ };
14800
+ accessor.count({ where: whereFilter }).then((count) => {
14932
14801
  if (isCleaningUpRef.current) return;
14933
14802
  setColumnData((prev) => ({
14934
14803
  ...prev,
@@ -15111,7 +14980,7 @@ function useBoardDataController({ fullPath, collection, columnProperty, columns,
15111
14980
  ]);
15112
14981
  }
15113
14982
  //#endregion
15114
- //#region src/components/EntityCollectionView/hooks/useKanbanDragAndDrop.ts
14983
+ //#region src/components/CollectionViewBinding/hooks/useKanbanDragAndDrop.ts
15115
14984
  function useKanbanDragAndDrop({ collection, fullPath, columnProperty, orderProperty, dataClient, context, boardDataController, analyticsController }) {
15116
14985
  const handleItemsReorder = useCallback(async (items, moveInfo) => {
15117
14986
  const entity = items.find((item) => item.id === moveInfo?.itemId)?.data;
@@ -15184,15 +15053,15 @@ function useKanbanDragAndDrop({ collection, fullPath, columnProperty, orderPrope
15184
15053
  return useMemo(() => ({ handleItemsReorder }), [handleItemsReorder]);
15185
15054
  }
15186
15055
  //#endregion
15187
- //#region src/components/EntityCollectionView/EntityCollectionBoardView.tsx
15056
+ //#region src/components/CollectionViewBinding/CollectionBoardViewBinding.tsx
15188
15057
  /**
15189
15058
  * Kanban board view for displaying entities grouped by a string enum property.
15190
15059
  */
15191
- function EntityCollectionBoardView({ collection, tableController, fullPath, parentCollectionSlugs = [], parentEntityIds = [], columnProperty, onEntityClick, selectionController, selectionEnabled = true, highlightedEntities, emptyComponent, deletedEntities }) {
15060
+ function CollectionBoardViewBinding({ collection, tableController, fullPath, parentCollectionSlugs = [], parentEntityIds = [], columnProperty, onEntityClick, selectionController, selectionEnabled = true, highlightedEntities, emptyComponent, deletedEntities }) {
15192
15061
  const customizationController = useCustomizationController();
15193
15062
  const context = useRebaseContext();
15194
15063
  const dataClient = useData();
15195
- const sideEntityController = useSideEntityController();
15064
+ const sidePanelController = useSidePanel();
15196
15065
  const analyticsController = useAnalyticsController();
15197
15066
  const { t } = useTranslation();
15198
15067
  const plugins = customizationController.plugins ?? [];
@@ -15336,7 +15205,7 @@ function EntityCollectionBoardView({ collection, tableController, fullPath, pare
15336
15205
  completed++;
15337
15206
  if (completed === 2) setMissingOrderCount(Math.max(0, totalCount - orderedCount));
15338
15207
  }).catch((e) => console.warn("Failed to get total count:", e));
15339
- accessor.count({ where: { [orderProperty]: "neq.null" } }).then((count) => {
15208
+ accessor.count({ where: { [orderProperty]: ["!=", null] } }).then((count) => {
15340
15209
  orderedCount = count;
15341
15210
  completed++;
15342
15211
  if (completed === 2) setMissingOrderCount(Math.max(0, totalCount - orderedCount));
@@ -15477,7 +15346,7 @@ function EntityCollectionBoardView({ collection, tableController, fullPath, pare
15477
15346
  handleSelectionChangeRef.current(entity, sel);
15478
15347
  }, []);
15479
15348
  const ItemComponent = useMemo(() => {
15480
- const Comp = (props) => /* @__PURE__ */ jsx(EntityBoardCard, {
15349
+ const Comp = (props) => /* @__PURE__ */ jsx(BoardCardBinding, {
15481
15350
  ...props,
15482
15351
  collection: collectionRef.current,
15483
15352
  onClick: stableOnClick,
@@ -15600,7 +15469,7 @@ function EntityCollectionBoardView({ collection, tableController, fullPath, pare
15600
15469
  path: fullPath,
15601
15470
  column
15602
15471
  });
15603
- sideEntityController.open({
15472
+ sidePanelController.open({
15604
15473
  path: fullPath,
15605
15474
  collection,
15606
15475
  entityId: void 0,
@@ -15643,7 +15512,7 @@ function EntityCollectionBoardView({ collection, tableController, fullPath, pare
15643
15512
  });
15644
15513
  }
15645
15514
  //#endregion
15646
- //#region src/components/EntityCollectionView/ViewModeToggle.tsx
15515
+ //#region src/components/CollectionViewBinding/ViewModeToggle.tsx
15647
15516
  var ALL_VIEW_MODES = [
15648
15517
  "list",
15649
15518
  "table",
@@ -15768,7 +15637,7 @@ function ViewModeToggle({ viewMode = "table", onViewModeChange, enabledViews = A
15768
15637
  });
15769
15638
  }
15770
15639
  //#endregion
15771
- //#region src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx
15640
+ //#region src/components/CollectionTableBinding/internal/popup_field/useDraggable.tsx
15772
15641
  /** Tracks events originating inside the inner (non-draggable) area. */
15773
15642
  var innerClicked = /* @__PURE__ */ new WeakSet();
15774
15643
  function useDraggable({ containerRef, innerRef, x, y, onMove }) {
@@ -15832,7 +15701,7 @@ function useDraggable({ containerRef, innerRef, x, y, onMove }) {
15832
15701
  ]);
15833
15702
  }
15834
15703
  //#endregion
15835
- //#region src/components/EntityCollectionTable/internal/popup_field/useWindowSize.tsx
15704
+ //#region src/components/CollectionTableBinding/internal/popup_field/useWindowSize.tsx
15836
15705
  function useWindowSize() {
15837
15706
  const [size, setSize] = useState({
15838
15707
  width: 0,
@@ -15852,7 +15721,7 @@ function useWindowSize() {
15852
15721
  return size;
15853
15722
  }
15854
15723
  //#endregion
15855
- //#region src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx
15724
+ //#region src/components/CollectionTableBinding/internal/popup_field/PopupFormField.tsx
15856
15725
  function PopupFormField(props) {
15857
15726
  if (!props.open) return null;
15858
15727
  return /* @__PURE__ */ jsx(PopupFormFieldLoading, { ...props });
@@ -16132,13 +16001,14 @@ function ClearFilterSortButton({ tableController, enabled }) {
16132
16001
  return null;
16133
16002
  }
16134
16003
  //#endregion
16135
- //#region src/components/EntityCollectionView/FiltersDialog.tsx
16004
+ //#region src/components/CollectionViewBinding/FiltersDialog.tsx
16136
16005
  /**
16137
16006
  * Dialog that displays all filterable properties from a collection
16138
16007
  * and allows setting filter values for each.
16139
16008
  */
16140
16009
  function FiltersDialog({ open, onOpenChange, properties, filterValues, setFilterValues, fixedFilter }) {
16141
16010
  const { t } = useTranslation();
16011
+ const engine = useCollectionScope()?.engine;
16142
16012
  const [localFilters, setLocalFilters] = useState(filterValues ?? {});
16143
16013
  const [hiddenFields, setHiddenFields] = useState({});
16144
16014
  React.useEffect(() => {
@@ -16148,17 +16018,22 @@ function FiltersDialog({ open, onOpenChange, properties, filterValues, setFilter
16148
16018
  return Object.entries(properties).filter(([key, property]) => {
16149
16019
  if (!property) return false;
16150
16020
  if (fixedFilter && key in fixedFilter) return false;
16151
- const baseProperty = property.type === "array" ? property.of : property;
16152
- if (!baseProperty || Array.isArray(baseProperty)) return false;
16153
- return [
16154
- "string",
16155
- "number",
16156
- "boolean",
16157
- "date",
16158
- "reference"
16159
- ].includes(baseProperty.type);
16021
+ const isArray = property.type === "array";
16022
+ const ofProp = isArray && "of" in property ? property.of : void 0;
16023
+ const baseProperty = isArray ? Array.isArray(ofProp) ? ofProp[0] : ofProp : property;
16024
+ if (!baseProperty) return false;
16025
+ if (baseProperty.ui?.Filter) return true;
16026
+ return resolveFilterOperators({
16027
+ property: baseProperty,
16028
+ isArray,
16029
+ engine
16030
+ }).length > 0;
16160
16031
  });
16161
- }, [properties, fixedFilter]);
16032
+ }, [
16033
+ properties,
16034
+ fixedFilter,
16035
+ engine
16036
+ ]);
16162
16037
  const handleFilterChange = useCallback((propertyKey, value) => {
16163
16038
  setLocalFilters((prev) => {
16164
16039
  const newFilters = { ...prev };
@@ -16191,55 +16066,23 @@ function FiltersDialog({ open, onOpenChange, properties, filterValues, setFilter
16191
16066
  const isAnyFieldHidden = Object.values(hiddenFields).some((hidden) => hidden);
16192
16067
  const activeFilterCount = Object.keys(localFilters).length;
16193
16068
  const renderFilterField = useCallback((propertyKey, property) => {
16194
- const isArray = property.type === "array";
16195
- const ofProp = isArray && "of" in property ? property.of : void 0;
16196
- const baseProperty = isArray ? Array.isArray(ofProp) ? ofProp[0] : ofProp : property;
16197
- if (!baseProperty) return null;
16198
16069
  const filterValue = localFilters[propertyKey];
16199
16070
  const setValue = (value) => handleFilterChange(propertyKey, value);
16200
- if (baseProperty.type === "reference") return /* @__PURE__ */ jsx(ReferenceFilterField, {
16071
+ return /* @__PURE__ */ jsx(FilterFieldBinding, {
16072
+ propertyKey,
16073
+ property,
16074
+ engine,
16201
16075
  value: filterValue,
16202
16076
  setValue,
16203
- name: propertyKey,
16204
- isArray,
16205
- path: baseProperty.path,
16206
- title: property.name,
16207
- includeId: baseProperty.includeId,
16208
- previewProperties: baseProperty.ui?.previewProperties,
16209
16077
  hidden: hiddenFields[propertyKey] ?? false,
16210
16078
  setHidden: (hidden) => setHiddenForField(propertyKey, hidden)
16211
16079
  });
16212
- else if (baseProperty.type === "number" || baseProperty.type === "string") {
16213
- const enumValues = baseProperty.enum ? enumToObjectEntries(baseProperty.enum) : void 0;
16214
- return /* @__PURE__ */ jsx(StringNumberFilterField, {
16215
- value: filterValue,
16216
- setValue,
16217
- name: propertyKey,
16218
- type: baseProperty.type,
16219
- isArray,
16220
- enumValues,
16221
- title: property.name
16222
- });
16223
- } else if (baseProperty.type === "boolean") return /* @__PURE__ */ jsx(BooleanFilterField, {
16224
- value: filterValue,
16225
- setValue,
16226
- name: propertyKey,
16227
- title: property.name
16228
- });
16229
- else if (baseProperty.type === "date") return /* @__PURE__ */ jsx(DateTimeFilterField, {
16230
- value: filterValue,
16231
- setValue,
16232
- name: propertyKey,
16233
- mode: baseProperty.mode,
16234
- isArray,
16235
- title: property.name
16236
- });
16237
- return null;
16238
16080
  }, [
16239
16081
  localFilters,
16240
16082
  handleFilterChange,
16241
16083
  hiddenFields,
16242
- setHiddenForField
16084
+ setHiddenForField,
16085
+ engine
16243
16086
  ]);
16244
16087
  return /* @__PURE__ */ jsxs(Dialog, {
16245
16088
  open,
@@ -16303,7 +16146,7 @@ function FiltersDialog({ open, onOpenChange, properties, filterValues, setFilter
16303
16146
  });
16304
16147
  }
16305
16148
  //#endregion
16306
- //#region src/components/EntityCollectionView/FilterPresetsButton.tsx
16149
+ //#region src/components/CollectionViewBinding/FilterPresetsButton.tsx
16307
16150
  /**
16308
16151
  * Maximum number of presets shown as inline toggle chips before the
16309
16152
  * rest are collapsed into an overflow menu.
@@ -16496,8 +16339,8 @@ function FilterPresetsButton({ filterPresets, tableController, compact }) {
16496
16339
  });
16497
16340
  }
16498
16341
  //#endregion
16499
- //#region src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx
16500
- function EntityCollectionViewStartActions({ collection, relativePath, parentCollectionSlugs, parentEntityIds, path, selectionController, tableController, collectionEntitiesCount, resolvedProperties, compact, openNewDocument }) {
16342
+ //#region src/components/CollectionViewBinding/CollectionViewStartActions.tsx
16343
+ function CollectionViewStartActions({ collection, relativePath, parentCollectionSlugs, parentEntityIds, path, selectionController, tableController, collectionEntitiesCount, resolvedProperties, compact, openNewDocument }) {
16501
16344
  const context = useCMSContext();
16502
16345
  const largeLayout = useLargeLayout();
16503
16346
  const { t } = useTranslation();
@@ -16586,7 +16429,7 @@ function EntityCollectionViewStartActions({ collection, relativePath, parentColl
16586
16429
  ] });
16587
16430
  }
16588
16431
  //#endregion
16589
- //#region src/components/EntityCollectionView/EntityCollectionView.tsx
16432
+ //#region src/components/CollectionViewBinding/CollectionViewBinding.tsx
16590
16433
  var EMPTY_ARRAY = [];
16591
16434
  var DEFAULT_ENTITY_OPEN_MODE = "split";
16592
16435
  function getOpenEntityMode(viewMode, configuredMode) {
@@ -16596,20 +16439,20 @@ function getOpenEntityMode(viewMode, configuredMode) {
16596
16439
  return "split";
16597
16440
  }
16598
16441
  /**
16599
- * This component is in charge of binding a driver path with an {@link EntityCollection}
16442
+ * This component is in charge of binding a driver path with an {@link CollectionConfig}
16600
16443
  * where it's configuration is defined. It includes an infinite scrolling table
16601
16444
  * and a 'Add' new entities button,
16602
16445
  *
16603
16446
  * This component is the default one used for displaying entity collections
16604
16447
  * and is in charge of generating all the specific actions and customization
16605
- * of the lower level {@link EntityCollectionTable}
16448
+ * of the lower level {@link CollectionTableBinding}
16606
16449
  *
16607
16450
  * Please **note** that you only need to use this component if you are building
16608
16451
  * a custom view. If you just need to create a default view you can do it
16609
16452
  * exclusively with config options.
16610
16453
  *
16611
16454
  * If you need a lower level implementation with more granular options, you
16612
- * can use {@link EntityCollectionTable}.
16455
+ * can use {@link CollectionTableBinding}.
16613
16456
  *
16614
16457
  * If you need a generic table that is not bound to the driver or entities and
16615
16458
  * properties at all, you can check {@link VirtualTable}
@@ -16619,15 +16462,15 @@ function getOpenEntityMode(viewMode, configuredMode) {
16619
16462
 
16620
16463
  * @group Components
16621
16464
  */
16622
- var EntityCollectionViewInner = React.memo(function EntityCollectionViewInner({ path: pathProp, parentCollectionSlugs, parentEntityIds, isSubCollection, className, updateUrl, selectedEntityId: selectedEntityIdProp, selectedTab: selectedTabProp, ...collectionProp }) {
16465
+ var CollectionViewBindingInner = React.memo(function CollectionViewBindingInner({ path: pathProp, parentCollectionSlugs, parentEntityIds, isSubCollection, className, updateUrl, selectedEntityId: selectedEntityIdProp, selectedTab: selectedTabProp, ...collectionProp }) {
16623
16466
  const { t } = useTranslation();
16624
16467
  const context = useCMSContext();
16625
16468
  const collectionRegistry = useCollectionRegistryController();
16626
16469
  const urlController = useUrlController();
16627
16470
  const breadcrumbs = useBreadcrumbsController();
16628
- const path = pathProp ?? collectionProp.slug;
16471
+ const path = pathProp ?? getCollectionDataPath(collectionProp);
16629
16472
  const dataClient = useData();
16630
- const sideEntityController = useSideEntityController();
16473
+ const sidePanelController = useSidePanel();
16631
16474
  useAuthController();
16632
16475
  const userConfigPersistence = useUserConfigurationPersistence();
16633
16476
  const analyticsController = useAnalyticsController();
@@ -16748,14 +16591,14 @@ var EntityCollectionViewInner = React.memo(function EntityCollectionViewInner({
16748
16591
  navigateToEntity({
16749
16592
  navigation: urlController,
16750
16593
  path: path ?? clickedEntity.path,
16751
- sideEntityController,
16594
+ sidePanelController,
16752
16595
  openEntityMode,
16753
16596
  collection,
16754
16597
  entityId: clickedEntity.id,
16755
16598
  replace: openEntityMode === "split" && selectedEntityIdProp !== void 0
16756
16599
  });
16757
16600
  }, [
16758
- sideEntityController,
16601
+ sidePanelController,
16759
16602
  openEntityMode,
16760
16603
  selectedEntityIdProp,
16761
16604
  path,
@@ -16770,11 +16613,11 @@ var EntityCollectionViewInner = React.memo(function EntityCollectionViewInner({
16770
16613
  collection,
16771
16614
  entityId: void 0,
16772
16615
  path,
16773
- sideEntityController,
16616
+ sidePanelController,
16774
16617
  navigation: urlController,
16775
16618
  onClose: unselectNavigatedEntity
16776
16619
  });
16777
- }, [path, sideEntityController]);
16620
+ }, [path, sidePanelController]);
16778
16621
  const openNewDocument = useCallback((defaultValues) => {
16779
16622
  const collection = collectionRef.current;
16780
16623
  analyticsController.onAnalyticsEvent?.("new_entity_click", { path });
@@ -16784,13 +16627,13 @@ var EntityCollectionViewInner = React.memo(function EntityCollectionViewInner({
16784
16627
  entityId: void 0,
16785
16628
  defaultValues,
16786
16629
  path,
16787
- sideEntityController,
16630
+ sidePanelController,
16788
16631
  navigation: urlController,
16789
16632
  onClose: unselectNavigatedEntity
16790
16633
  });
16791
16634
  }, [
16792
16635
  path,
16793
- sideEntityController,
16636
+ sidePanelController,
16794
16637
  openEntityMode,
16795
16638
  urlController,
16796
16639
  unselectNavigatedEntity
@@ -16989,7 +16832,7 @@ var EntityCollectionViewInner = React.memo(function EntityCollectionViewInner({
16989
16832
  selectedTab: subcollection.slug,
16990
16833
  path,
16991
16834
  navigation: urlController,
16992
- sideEntityController
16835
+ sidePanelController
16993
16836
  });
16994
16837
  },
16995
16838
  children: subcollection.name
@@ -17000,7 +16843,7 @@ var EntityCollectionViewInner = React.memo(function EntityCollectionViewInner({
17000
16843
  }, [
17001
16844
  collection,
17002
16845
  path,
17003
- sideEntityController
16846
+ sidePanelController
17004
16847
  ]);
17005
16848
  const updateLastDeleteTimestamp = useCallback(() => {
17006
16849
  setLastDeleteTimestamp(Date.now());
@@ -17031,7 +16874,7 @@ var EntityCollectionViewInner = React.memo(function EntityCollectionViewInner({
17031
16874
  return (largeLayout ? 80 + actionsWidth : 70 + actionsWidth) + (collapsedActions.length > 0 ? largeLayout ? 40 : 30 : 0);
17032
16875
  }, [getActionsForEntity, largeLayout]);
17033
16876
  const tableRowActionsBuilder = useCallback(({ entity, size, width, frozen }) => {
17034
- return /* @__PURE__ */ jsx(EntityCollectionRowActions, {
16877
+ return /* @__PURE__ */ jsx(CollectionRowActions, {
17035
16878
  entity,
17036
16879
  width,
17037
16880
  frozen,
@@ -17144,8 +16987,8 @@ var EntityCollectionViewInner = React.memo(function EntityCollectionViewInner({
17144
16987
  const isSearching = !!tableController.searchString;
17145
16988
  const isFilteredOrSorted = tableController.filterValues !== void 0 || tableController.sortBy !== void 0 || isSearching;
17146
16989
  const ResolvedEmptyState = useComponentOverride("Collection.EmptyState", DefaultCollectionEmptyState);
17147
- const ResolvedCollectionActions = useComponentOverride("Collection.Actions", EntityCollectionViewActions);
17148
- const ResolvedCollectionTable = useComponentOverride("Collection.Table", EntityCollectionTable);
16990
+ const ResolvedCollectionActions = useComponentOverride("Collection.Actions", CollectionViewActions);
16991
+ const ResolvedCollectionTable = useComponentOverride("Collection.Table", CollectionTableBinding);
17149
16992
  const emptyComponent = pluginEmptyStates.length > 0 ? /* @__PURE__ */ jsx(Fragment, { children: pluginEmptyStates }) : /* @__PURE__ */ jsx(ResolvedEmptyState, {
17150
16993
  canCreate: canCreateEntities && !isFilteredOrSorted,
17151
16994
  onNewClick,
@@ -17158,13 +17001,13 @@ var EntityCollectionViewInner = React.memo(function EntityCollectionViewInner({
17158
17001
  onTextSearch: tableController.setSearchString,
17159
17002
  initialSearchText: tableController.searchString,
17160
17003
  viewModeToggle: viewModeToggleElement,
17161
- actionsStart: /* @__PURE__ */ jsx(EntityCollectionViewStartActions, {
17004
+ actionsStart: /* @__PURE__ */ jsx(CollectionViewStartActions, {
17162
17005
  parentCollectionSlugs: parentCollectionSlugs ?? EMPTY_ARRAY,
17163
17006
  parentEntityIds: parentEntityIds ?? EMPTY_ARRAY,
17164
17007
  collection,
17165
17008
  tableController,
17166
17009
  path,
17167
- relativePath: collection.slug,
17010
+ relativePath: getCollectionDataPath(collection),
17168
17011
  selectionController: usedSelectionController,
17169
17012
  collectionEntitiesCount: docsCount ?? void 0,
17170
17013
  resolvedProperties: resolvedCollection.properties,
@@ -17180,7 +17023,7 @@ var EntityCollectionViewInner = React.memo(function EntityCollectionViewInner({
17180
17023
  onNewClick,
17181
17024
  openNewDocument,
17182
17025
  path,
17183
- relativePath: collection.slug,
17026
+ relativePath: getCollectionDataPath(collection),
17184
17027
  selectionController: usedSelectionController,
17185
17028
  selectionEnabled: activeSelectionEnabled,
17186
17029
  collectionEntitiesCount: docsCount ?? void 0,
@@ -17188,7 +17031,7 @@ var EntityCollectionViewInner = React.memo(function EntityCollectionViewInner({
17188
17031
  children: pluginToolbarWidgets
17189
17032
  })
17190
17033
  });
17191
- const innerView = viewMode === "kanban" ? /* @__PURE__ */ jsx(EntityCollectionBoardView, {
17034
+ const innerView = viewMode === "kanban" ? /* @__PURE__ */ jsx(CollectionBoardViewBinding, {
17192
17035
  collection,
17193
17036
  tableController,
17194
17037
  fullPath: path,
@@ -17201,7 +17044,7 @@ var EntityCollectionViewInner = React.memo(function EntityCollectionViewInner({
17201
17044
  highlightedEntities: highlightedEntity ? [highlightedEntity] : [],
17202
17045
  deletedEntities,
17203
17046
  emptyComponent
17204
- }, `kanban-view-${path}-${selectedKanbanProperty}`) : viewMode === "cards" ? /* @__PURE__ */ jsx(EntityCollectionCardView, {
17047
+ }, `kanban-view-${path}-${selectedKanbanProperty}`) : viewMode === "cards" ? /* @__PURE__ */ jsx(CollectionCardViewBinding, {
17205
17048
  collection,
17206
17049
  tableController,
17207
17050
  onEntityClick,
@@ -17212,7 +17055,7 @@ var EntityCollectionViewInner = React.memo(function EntityCollectionViewInner({
17212
17055
  initialScroll: tableController.initialScroll,
17213
17056
  size: cardSize,
17214
17057
  emptyComponent
17215
- }, `cards-view-${path}`) : viewMode === "list" ? /* @__PURE__ */ jsx(EntityCollectionListView, {
17058
+ }, `cards-view-${path}`) : viewMode === "list" ? /* @__PURE__ */ jsx(CollectionListViewBinding, {
17216
17059
  collection,
17217
17060
  tableController,
17218
17061
  onEntityClick,
@@ -17315,7 +17158,7 @@ var EntityCollectionViewInner = React.memo(function EntityCollectionViewInner({
17315
17158
  children: pluginInsights
17316
17159
  })
17317
17160
  }),
17318
- /* @__PURE__ */ jsx(EntityCollectionListView, {
17161
+ /* @__PURE__ */ jsx(CollectionListViewBinding, {
17319
17162
  collection,
17320
17163
  tableController,
17321
17164
  onEntityClick,
@@ -17388,13 +17231,13 @@ var EntityCollectionViewInner = React.memo(function EntityCollectionViewInner({
17388
17231
  }, (a, b) => {
17389
17232
  return deepEqual(a.path, b.path) && deepEqual(a.parentCollectionSlugs, b.parentCollectionSlugs) && deepEqual(a.parentEntityIds, b.parentEntityIds) && deepEqual(a.isSubCollection, b.isSubCollection) && deepEqual(a.className, b.className) && deepEqual(a.properties, b.properties) && deepEqual(a.propertiesOrder, b.propertiesOrder) && deepEqual(a.hideIdFromCollection, b.hideIdFromCollection) && deepEqual(a.inlineEditing, b.inlineEditing) && deepEqual(a.selectionEnabled, b.selectionEnabled) && deepEqual(a.selectionController, b.selectionController) && deepEqual(a.Actions, b.Actions) && deepEqual(a.defaultSize, b.defaultSize) && deepEqual(a.includeJsonView, b.includeJsonView) && deepEqual(a.additionalFields, b.additionalFields) && deepEqual(a.sideDialogWidth, b.sideDialogWidth) && deepEqual(a.openEntityMode, b.openEntityMode) && deepEqual(a.exportable, b.exportable) && deepEqual(a.history, b.history) && deepEqual(a.fixedFilter, b.fixedFilter) && deepEqual(a.selectedEntityId, b.selectedEntityId) && deepEqual(a.selectedTab, b.selectedTab);
17390
17233
  });
17391
- var EntityCollectionView = React.memo(function EntityCollectionView(props) {
17234
+ var CollectionViewBinding = React.memo(function CollectionViewBinding(props) {
17392
17235
  const collectionRegistry = useCollectionRegistryController();
17393
17236
  const path = props.path ?? props.slug;
17394
17237
  const collection = collectionRegistry.getCollection(path) ?? props;
17395
- const content = /* @__PURE__ */ jsx(EntityCollectionViewInner, { ...props });
17396
- if (collection?.components) return /* @__PURE__ */ jsx(CollectionComponentOverrideProvider, {
17397
- overrides: collection.components,
17238
+ const content = /* @__PURE__ */ jsx(CollectionViewBindingInner, { ...props });
17239
+ if (collection) return /* @__PURE__ */ jsx(CollectionScopeProvider, {
17240
+ collection,
17398
17241
  children: content
17399
17242
  });
17400
17243
  return content;
@@ -17445,19 +17288,8 @@ function EntitiesCount({ path, collection, filter, sortBy, onCountChange }) {
17445
17288
  return;
17446
17289
  }
17447
17290
  let cancelled = false;
17448
- const whereMap = {};
17449
- if (filter) Object.entries(filter).forEach(([key, value]) => {
17450
- if (value && Array.isArray(value)) {
17451
- const [op, val] = value;
17452
- const postgrestOp = op === "==" ? "eq" : op === "!=" ? "neq" : op === ">" ? "gt" : op === ">=" ? "gte" : op === "<" ? "lt" : op === "<=" ? "lte" : op === "in" ? "in" : op === "not-in" ? "nin" : op === "array-contains" ? "cs" : op === "array-contains-any" ? "csa" : "eq";
17453
- let stringVal;
17454
- if (Array.isArray(val)) stringVal = `(${val.join(",")})`;
17455
- else stringVal = String(val);
17456
- whereMap[key] = `${postgrestOp}.${stringVal}`;
17457
- }
17458
- });
17459
- const whereParams = Object.keys(whereMap).length > 0 ? whereMap : void 0;
17460
- const orderByParams = sortByProperty ? `${String(sortByProperty)}:${currentSort}` : void 0;
17291
+ const whereParams = filter && Object.keys(filter).length > 0 ? filter : void 0;
17292
+ const orderByParams = sortByProperty && currentSort ? [String(sortByProperty), currentSort] : void 0;
17461
17293
  const cacheKey = `${path}|${filterKey}|${sortByProperty ?? ""}|${currentSort ?? ""}`;
17462
17294
  let countPromise = inflightCountRequests.get(cacheKey);
17463
17295
  if (!countPromise) {
@@ -17498,7 +17330,7 @@ function EntityIdHeaderWidget({ collection, path, idPath }) {
17498
17330
  const [openPopup, setOpenPopup] = React.useState(false);
17499
17331
  const [searchString, setSearchString] = React.useState("");
17500
17332
  const [recentIds, setRecentIds] = React.useState(getRecentIds(collection.slug).map(String));
17501
- const sideEntityController = useSideEntityController();
17333
+ const sidePanelController = useSidePanel();
17502
17334
  const openEntityMode = collection?.openEntityMode ?? DEFAULT_ENTITY_OPEN_MODE;
17503
17335
  return /* @__PURE__ */ jsx(Tooltip, {
17504
17336
  title: !openPopup ? t("find_by_id") : void 0,
@@ -17528,7 +17360,7 @@ function EntityIdHeaderWidget({ collection, path, idPath }) {
17528
17360
  collection,
17529
17361
  entityId,
17530
17362
  path,
17531
- sideEntityController,
17363
+ sidePanelController,
17532
17364
  navigation: urlController
17533
17365
  });
17534
17366
  },
@@ -17567,7 +17399,7 @@ function EntityIdHeaderWidget({ collection, path, idPath }) {
17567
17399
  collection,
17568
17400
  entityId: id,
17569
17401
  path,
17570
- sideEntityController,
17402
+ sidePanelController,
17571
17403
  navigation: urlController
17572
17404
  });
17573
17405
  },
@@ -17606,7 +17438,7 @@ function ReferenceWidget({ name, multiselect = false, path, disabled, value, onR
17606
17438
  entities
17607
17439
  });
17608
17440
  }, [disabled, onReferenceSelected]);
17609
- const referenceDialogController = useEntitySelectionDialog({
17441
+ const referenceDialogController = useSelectionDialog({
17610
17442
  multiselect,
17611
17443
  path,
17612
17444
  collection,
@@ -17750,15 +17582,15 @@ function useBuildSideDialogsController() {
17750
17582
  ]);
17751
17583
  }
17752
17584
  //#endregion
17753
- //#region src/components/SideEntityProvider.tsx
17585
+ //#region src/components/SidePanelProvider.tsx
17754
17586
  /**
17755
- * Provider that builds the SideEntityController and makes it available
17756
- * via the SideEntityControllerContext from @rebasepro/core.
17587
+ * Provider that builds the SidePanelController and makes it available
17588
+ * via the SidePanelControllerContext from @rebasepro/core.
17757
17589
  *
17758
- * After the CMS extraction refactor, `useBuildSideEntityController` lives
17590
+ * After the CMS extraction refactor, `useBuildSidePanel` lives
17759
17591
  * in the CMS package while the context it feeds into lives in core.
17760
17592
  * This provider bridges the two: place it inside the `<Rebase>` tree and
17761
- * above any component that calls `useSideEntityController()`.
17593
+ * above any component that calls `useSidePanel()`.
17762
17594
  *
17763
17595
  * Also auto-registers the side entity controller and breadcrumbs into the
17764
17596
  * self-assembling Studio bridge (when a StudioBridgeRegistryProvider is
@@ -17768,28 +17600,28 @@ function useBuildSideDialogsController() {
17768
17600
  * ```tsx
17769
17601
  * <Rebase ...>
17770
17602
  * {({ loading }) => (
17771
- * <SideEntityProvider>
17603
+ * <SidePanelProvider>
17772
17604
  * <RebaseRoutes>
17773
17605
  * ...
17774
17606
  * </RebaseRoutes>
17775
- * </SideEntityProvider>
17607
+ * </SidePanelProvider>
17776
17608
  * )}
17777
17609
  * </Rebase>
17778
17610
  * ```
17779
17611
  *
17780
17612
  * @group Components
17781
17613
  */
17782
- function SideEntityProvider({ children }) {
17614
+ function SidePanelProvider({ children }) {
17783
17615
  const collectionRegistryController = useCollectionRegistryController();
17784
17616
  const urlController = useUrlController();
17785
17617
  const navigationStateController = useNavigationStateController();
17786
17618
  const sideDialogsController = useBuildSideDialogsController();
17787
- const sideEntityController = useBuildSideEntityController(collectionRegistryController, urlController, navigationStateController, sideDialogsController, useAuthController());
17619
+ const sidePanelController = useBuildSidePanel(collectionRegistryController, urlController, navigationStateController, sideDialogsController, useAuthController());
17788
17620
  return /* @__PURE__ */ jsx(BreadcrumbsProvider, { children: /* @__PURE__ */ jsx(SideDialogsControllerContext.Provider, {
17789
17621
  value: sideDialogsController,
17790
- children: /* @__PURE__ */ jsxs(SideEntityControllerContext.Provider, {
17791
- value: sideEntityController,
17792
- children: [/* @__PURE__ */ jsx(BridgeAutoRegistrar$1, { sideEntityController }), children]
17622
+ children: /* @__PURE__ */ jsxs(SidePanelControllerContext.Provider, {
17623
+ value: sidePanelController,
17624
+ children: [/* @__PURE__ */ jsx(BridgeAutoRegistrar$1, { sidePanelController }), children]
17793
17625
  })
17794
17626
  }) });
17795
17627
  }
@@ -17797,9 +17629,9 @@ function SideEntityProvider({ children }) {
17797
17629
  * Internal component that auto-registers side entity and breadcrumbs
17798
17630
  * into the Studio bridge. Must be a child of BreadcrumbsProvider.
17799
17631
  */
17800
- function BridgeAutoRegistrar$1({ sideEntityController }) {
17632
+ function BridgeAutoRegistrar$1({ sidePanelController }) {
17801
17633
  const breadcrumbs = useBreadcrumbsController();
17802
- useBridgeRegistration("sideEntityController", sideEntityController);
17634
+ useBridgeRegistration("sidePanelController", sidePanelController);
17803
17635
  useBridgeRegistration("breadcrumbs", breadcrumbs);
17804
17636
  return null;
17805
17637
  }
@@ -18185,7 +18017,7 @@ function CMSNavigationContent() {
18185
18017
  if (registry.studioConfig && registry.cmsConfig?.collectionEditor) slugs.add("schema");
18186
18018
  return slugs;
18187
18019
  }, [registry.studioConfig, registry.cmsConfig?.collectionEditor]);
18188
- const filteredEntries = adminModeController.mode === "studio" ? allNavigationEntries.filter((e) => e.type === "view" || e.type === "admin") : allNavigationEntries.filter((e) => e.type !== "view" || !studioViewSlugs.has(e.slug));
18020
+ const filteredEntries = adminModeController.mode === "studio" ? allNavigationEntries.filter((e) => e.type === "view" && studioViewSlugs.has(e.slug) || e.type === "admin") : allNavigationEntries.filter((e) => e.type !== "view" || !studioViewSlugs.has(e.slug));
18189
18021
  const entryGroups = new Set(filteredEntries.map((e) => e.group).filter(Boolean));
18190
18022
  const orderedGroups = navigationState.topLevelNavigation?.groups ?? [];
18191
18023
  const groupsToRender = [...orderedGroups.filter((g) => entryGroups.has(g)), ...[...entryGroups].filter((g) => !orderedGroups.includes(g))];
@@ -18623,7 +18455,7 @@ function DrawerWrapper(props) {
18623
18455
  * is auto-wired as a native feature (slots, provider, Studio view) without
18624
18456
  * needing any external plugin.
18625
18457
  */
18626
- function RebaseCMS({ collections, views, homePage, entityViews, entityActions, plugins, collectionEditor, navigationGroupMappings }) {
18458
+ function RebaseCMS({ collections, views, homePage, entityViews, entityActions, collectionEditor, navigationGroupMappings, basePath }) {
18627
18459
  const dispatch = useRebaseRegistryDispatch();
18628
18460
  useLayoutEffect(() => {
18629
18461
  dispatch.registerCMS({
@@ -18632,9 +18464,9 @@ function RebaseCMS({ collections, views, homePage, entityViews, entityActions, p
18632
18464
  homePage,
18633
18465
  entityViews,
18634
18466
  entityActions,
18635
- plugins,
18636
18467
  collectionEditor,
18637
- navigationGroupMappings
18468
+ navigationGroupMappings,
18469
+ basePath
18638
18470
  });
18639
18471
  return () => dispatch.unregisterCMS();
18640
18472
  }, [
@@ -18644,9 +18476,9 @@ function RebaseCMS({ collections, views, homePage, entityViews, entityActions, p
18644
18476
  homePage,
18645
18477
  entityViews,
18646
18478
  entityActions,
18647
- plugins,
18648
18479
  collectionEditor,
18649
- navigationGroupMappings
18480
+ navigationGroupMappings,
18481
+ basePath
18650
18482
  ]);
18651
18483
  return null;
18652
18484
  }
@@ -18780,7 +18612,7 @@ function useLocalCollectionsConfigController(clientOrUrl, baseCollections = [],
18780
18612
  //#region src/components/RebaseNavigation.tsx
18781
18613
  var EMPTY_PLUGINS = [];
18782
18614
  var EMPTY_COLLECTIONS = [];
18783
- var CollectionsStudioView = lazy(() => import("./RouterCollectionsStudioView-Dqx27GD8.js").then((n) => n.n).then((m) => ({ default: m.RouterCollectionsStudioView })));
18615
+ var CollectionsStudioView = lazy(() => import("./RouterCollectionsStudioView-epqIbZrJ.js").then((n) => n.n).then((m) => ({ default: m.RouterCollectionsStudioView })));
18784
18616
  /**
18785
18617
  * Navigation layer — builds and provides all CMS navigation controllers:
18786
18618
  * collection registry, URL controller, navigation state, side entity,
@@ -18795,7 +18627,7 @@ var CollectionsStudioView = lazy(() => import("./RouterCollectionsStudioView-Dqx
18795
18627
  * ```tsx
18796
18628
  * <RebaseNavigation>
18797
18629
  * <MyCustomLayout>
18798
- * <EntityCollectionView ... />
18630
+ * <CollectionViewBinding ... />
18799
18631
  * </MyCustomLayout>
18800
18632
  * </RebaseNavigation>
18801
18633
  * ```
@@ -18827,7 +18659,12 @@ function RebaseNavigation({ children }) {
18827
18659
  resolveKey: (slugOrPath) => resolveDataSource(getCollectionRef.current(slugOrPath), dataSources.registry).key
18828
18660
  }), [defaultData, dataSources]);
18829
18661
  const urlController = useBuildUrlController({
18830
- basePath: "/",
18662
+ basePath: useMemo(() => {
18663
+ const raw = registry.cmsConfig?.basePath;
18664
+ if (!raw || raw === "/") return "/";
18665
+ const trimmed = raw.replace(/^\/+/, "").replace(/\/+$/, "");
18666
+ return trimmed ? `/${trimmed}` : "/";
18667
+ }, [registry.cmsConfig?.basePath]),
18831
18668
  baseCollectionPath: "/c",
18832
18669
  collectionRegistryController
18833
18670
  });
@@ -18884,8 +18721,9 @@ function RebaseNavigation({ children }) {
18884
18721
  };
18885
18722
  return [...cmsViews, ...devViews];
18886
18723
  }, [cmsViews, devViews]);
18724
+ const parentCustomizationController = useCustomizationController();
18887
18725
  const navigationStateController = useBuildNavigationStateController({
18888
- plugins: registry.cmsConfig?.plugins ?? EMPTY_PLUGINS,
18726
+ plugins: parentCustomizationController.plugins ?? EMPTY_PLUGINS,
18889
18727
  collections: collectionsBuilder,
18890
18728
  views: mergedViews,
18891
18729
  navigationGroupMappings: registry.cmsConfig?.navigationGroupMappings,
@@ -18895,7 +18733,6 @@ function RebaseNavigation({ children }) {
18895
18733
  urlController,
18896
18734
  adminMode: adminModeController?.mode
18897
18735
  });
18898
- const parentCustomizationController = useCustomizationController();
18899
18736
  const enrichedCustomizationController = useMemo(() => {
18900
18737
  const cmsEntityViews = registry.cmsConfig?.entityViews ?? [];
18901
18738
  const cmsEntityActions = registry.cmsConfig?.entityActions ?? [];
@@ -18920,7 +18757,7 @@ function RebaseNavigation({ children }) {
18920
18757
  value: urlController,
18921
18758
  children: /* @__PURE__ */ jsx(NavigationStateContext.Provider, {
18922
18759
  value: navigationStateController,
18923
- children: /* @__PURE__ */ jsxs(SideEntityProvider, { children: [/* @__PURE__ */ jsx(BridgeAutoRegistrar, {
18760
+ children: /* @__PURE__ */ jsxs(SidePanelProvider, { children: [/* @__PURE__ */ jsx(BridgeAutoRegistrar, {
18924
18761
  collectionRegistryController,
18925
18762
  urlController,
18926
18763
  navigationStateController
@@ -19720,7 +19557,7 @@ function ContentHomePage({ additionalActions, additionalChildrenStart, additiona
19720
19557
  return slugs;
19721
19558
  }, [registry.studioConfig, registry.cmsConfig?.collectionEditor]);
19722
19559
  const rawNavigationEntries = useMemo(() => {
19723
- if (adminModeController.mode === "studio") return unFilteredNavigationEntries.filter((e) => e.type === "view" || e.type === "admin");
19560
+ if (adminModeController.mode === "studio") return unFilteredNavigationEntries.filter((e) => e.type === "view" && studioViewSlugs.has(e.slug) || e.type === "admin");
19724
19561
  return unFilteredNavigationEntries.filter((e) => e.type !== "view" || !studioViewSlugs.has(e.slug));
19725
19562
  }, [
19726
19563
  unFilteredNavigationEntries,
@@ -20003,7 +19840,7 @@ function RebaseRoute() {
20003
19840
  const urlController = useUrlController();
20004
19841
  const breadcrumbs = useBreadcrumbsController();
20005
19842
  const userConfigPersistence = useUserConfigurationPersistence();
20006
- const ResolvedCollectionView = useComponentOverride("Collection.View", EntityCollectionView);
19843
+ const ResolvedCollectionView = useComponentOverride("Collection.View", CollectionViewBinding);
20007
19844
  const hash = location.hash;
20008
19845
  const isSidePanel = hash.includes("#side");
20009
19846
  const isNew = hash.includes("#new") || hash.includes("#new_side");
@@ -20198,7 +20035,7 @@ function EntityFullScreenRoute({ pathname, navigationEntries, isNew, isCopy }) {
20198
20035
  const fullIdPath = isNew ? lastCollectionEntry.slug : lastEntityEntry.slug;
20199
20036
  const collectionPath = urlController.resolveDatabasePathsFrom(fullIdPath);
20200
20037
  const isEditRoute = pathname.endsWith("/edit") || pathname.split("/").pop() === "edit";
20201
- if (collection.defaultEntityAction === "view" && !isNew && !isCopy && entityId && !isEditRoute) return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(EntityDetailView, {
20038
+ if (collection.defaultEntityAction === "view" && !isNew && !isCopy && entityId && !isEditRoute) return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(DetailViewBinding, {
20202
20039
  entityId,
20203
20040
  collection,
20204
20041
  layout: "full_screen",
@@ -20216,7 +20053,7 @@ function EntityFullScreenRoute({ pathname, navigationEntries, isNew, isCopy }) {
20216
20053
  parentCollectionSlugs,
20217
20054
  parentEntityIds
20218
20055
  }, collection.slug + "_view_" + entityId) });
20219
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(EntityEditView, {
20056
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(EditViewBinding, {
20220
20057
  entityId: isNew ? void 0 : entityId,
20221
20058
  collection,
20222
20059
  layout: "full_screen",
@@ -20272,8 +20109,8 @@ function CustomViewRoute({ view }) {
20272
20109
  }
20273
20110
  //#endregion
20274
20111
  //#region src/components/CollectionEditorDialogs.tsx
20275
- var CollectionEditorDialog = lazy(() => import("./CollectionEditorDialog-iGgS4rLX.js").then((n) => n.r).then((m) => ({ default: m.CollectionEditorDialog })));
20276
- var PropertyFormDialog = lazy(() => import("./PropertyEditView-C9yhLyja.js").then((n) => n.t).then((m) => ({ default: m.PropertyFormDialog })));
20112
+ var CollectionEditorDialog = lazy(() => import("./CollectionEditorDialog-B-7uW3iJ.js").then((n) => n.r).then((m) => ({ default: m.CollectionEditorDialog })));
20113
+ var PropertyFormDialog = lazy(() => import("./PropertyEditView-7KMTcrqi.js").then((n) => n.t).then((m) => ({ default: m.PropertyFormDialog })));
20277
20114
  /**
20278
20115
  * Renders the CollectionEditorDialog and PropertyFormDialog inside
20279
20116
  * the RebaseShell tree where CMS-internal contexts
@@ -20467,7 +20304,7 @@ function RebaseShell(props) {
20467
20304
  * @group Components
20468
20305
  */
20469
20306
  function CollectionPanelInner({ mergedCollection, path, title, updateUrl, className }) {
20470
- const ResolvedCollectionView = useComponentOverride("Collection.View", EntityCollectionView);
20307
+ const ResolvedCollectionView = useComponentOverride("Collection.View", CollectionViewBinding);
20471
20308
  return /* @__PURE__ */ jsxs("div", {
20472
20309
  className,
20473
20310
  children: [title !== false && /* @__PURE__ */ jsx(Typography, {
@@ -20516,15 +20353,13 @@ function CollectionPanel(props) {
20516
20353
  ]
20517
20354
  })
20518
20355
  });
20519
- const content = /* @__PURE__ */ jsx(CollectionPanelInner, {
20520
- ...props,
20521
- mergedCollection
20522
- });
20523
- if (mergedCollection.components) return /* @__PURE__ */ jsx(CollectionComponentOverrideProvider, {
20524
- overrides: mergedCollection.components,
20525
- children: content
20356
+ return /* @__PURE__ */ jsx(CollectionScopeProvider, {
20357
+ collection: mergedCollection,
20358
+ children: /* @__PURE__ */ jsx(CollectionPanelInner, {
20359
+ ...props,
20360
+ mergedCollection
20361
+ })
20526
20362
  });
20527
- return content;
20528
20363
  }
20529
20364
  //#endregion
20530
20365
  //#region src/preview/components/RelationPreview.tsx
@@ -20619,17 +20454,17 @@ function RelationPreviewInternal(props) {
20619
20454
  ...props,
20620
20455
  collection
20621
20456
  });
20622
- if (collection?.components) return /* @__PURE__ */ jsx(CollectionComponentOverrideProvider, {
20623
- overrides: collection.components,
20457
+ if (collection) return /* @__PURE__ */ jsx(CollectionScopeProvider, {
20458
+ collection,
20624
20459
  children: content
20625
20460
  });
20626
20461
  return content;
20627
20462
  }
20628
20463
  function RelationPreviewExisting({ relation, collection, previewProperties, size, disabled, includeEntityLink, includeId, onClick, hover, textOnly }) {
20629
20464
  const passedEntity = relation.data;
20630
- const ResolvedEntityPreview = useComponentOverride("Entity.Preview", EntityPreview);
20465
+ const ResolvedEntityPreview = useComponentOverride("EntityPreview", EntityPreviewBinding);
20631
20466
  const customizationController = useCustomizationController();
20632
- const { entity, dataLoading, dataLoadingError } = useEntityFetch({
20467
+ const { entity, dataLoading, dataLoadingError } = useFetch({
20633
20468
  path: relation.path,
20634
20469
  entityId: passedEntity ? void 0 : relation.id,
20635
20470
  collection,
@@ -21062,6 +20897,7 @@ var PropertyPreview = React.memo(function PropertyPreview(props) {
21062
20897
  content = /* @__PURE__ */ jsx(StorageThumbnail, {
21063
20898
  interactive,
21064
20899
  storeUrl: property.storage?.storeUrl ?? false,
20900
+ storageSourceKey: stringProperty.storage.storageSource,
21065
20901
  size: props.size,
21066
20902
  fill,
21067
20903
  storagePathOrDownloadUrl: filePath
@@ -21089,19 +20925,6 @@ var PropertyPreview = React.memo(function PropertyPreview(props) {
21089
20925
  propertyKey,
21090
20926
  size: props.size
21091
20927
  });
21092
- else if (stringProperty.reference) if (typeof stringProperty.reference.path === "string") content = /* @__PURE__ */ jsx(ReferencePreview, {
21093
- disabled: !stringProperty.reference.path,
21094
- previewProperties: stringProperty.reference?.ui?.previewProperties,
21095
- includeId: stringProperty.reference.includeId,
21096
- includeEntityLink: stringProperty.reference.includeEntityLink,
21097
- size: props.size,
21098
- reference: new EntityReference({
21099
- id: value,
21100
- path: stringProperty.reference.path
21101
- }),
21102
- textOnly: props.textOnly
21103
- });
21104
- else content = /* @__PURE__ */ jsx(EmptyValue, {});
21105
20928
  else content = /* @__PURE__ */ jsx(StringPropertyPreview, {
21106
20929
  ...props,
21107
20930
  property: stringProperty,
@@ -21691,7 +21514,7 @@ function zodToFormErrors(zodError) {
21691
21514
  /**
21692
21515
  * Headless entity form component.
21693
21516
  *
21694
- * Renders a form for an entity collection without any CMS or backend dependencies.
21517
+ * Renders a form for a entity collection without any CMS or backend dependencies.
21695
21518
  * All backend concerns (save, caching, analytics, plugin slots) are provided via
21696
21519
  * callback props. For CMS-connected usage, use {@link EntityFormBinding} instead.
21697
21520
  *
@@ -22143,7 +21966,7 @@ function useOnAutoSave(autoSave, formex, lastSavedValues, save) {
22143
21966
  */
22144
21967
  function EntityFormBinding({ path, entityId: entityIdProp, collection, entity, initialStatus, onSaved, onValuesModified, onEntityChange, onStatusChange, openEntityMode = "full_screen", navigateBack: navigateBackProp, initialDirtyValues, ...restProps }) {
22145
21968
  const { t } = useTranslation();
22146
- const sideEntityController = useSideEntityController();
21969
+ const sidePanelController = useSidePanel();
22147
21970
  const collectionRegistryController = useCollectionRegistryController();
22148
21971
  const authController = useAuthController();
22149
21972
  const dataClient = useData();
@@ -22197,12 +22020,12 @@ function EntityFormBinding({ path, entityId: entityIdProp, collection, entity, i
22197
22020
  navigateBackProp();
22198
22021
  return;
22199
22022
  }
22200
- if (openEntityMode === "side_panel" || openEntityMode === "dialog") sideEntityController.close();
22023
+ if (openEntityMode === "side_panel" || openEntityMode === "dialog") sidePanelController.close();
22201
22024
  else window.history.back();
22202
22025
  }, [
22203
22026
  navigateBackProp,
22204
22027
  openEntityMode,
22205
- sideEntityController
22028
+ sidePanelController
22206
22029
  ]);
22207
22030
  const clearDirtyCache = useCallback(() => {
22208
22031
  if (status === "new" || status === "copy") {
@@ -22298,7 +22121,7 @@ function EntityFormBinding({ path, entityId: entityIdProp, collection, entity, i
22298
22121
  const uniqueFieldValidator = useCallback(async ({ name, value }) => {
22299
22122
  try {
22300
22123
  const { data } = await dataClient.collection(path).find({
22301
- where: { [name]: `eq.${value}` },
22124
+ where: { [name]: ["==", value] },
22302
22125
  limit: 2
22303
22126
  });
22304
22127
  return (entityId ? data.filter((e) => e.id !== entityId) : data).length === 0;
@@ -22398,10 +22221,10 @@ function mapPropertyToConfig(property) {
22398
22221
  };
22399
22222
  if (property.type === "string") {
22400
22223
  if (property.enum) base.enum = mapEnumValues(property.enum);
22401
- if (property.multiline) base.multiline = true;
22224
+ if (property.ui?.multiline) base.multiline = true;
22402
22225
  if (property.ui?.previewAsTag) base.previewAsTag = true;
22403
- if (property.url || property.ui?.url) base.url = property.url ?? property.ui?.url;
22404
- if (property.ui?.markdown || property.markdown) base.markdown = true;
22226
+ if (property.ui?.url) base.url = property.ui.url;
22227
+ if (property.ui?.markdown) base.markdown = true;
22405
22228
  if (property.storage) base.storage = true;
22406
22229
  if (property.email) base.email = true;
22407
22230
  }
@@ -22453,22 +22276,16 @@ function normalizeEnumValueConfig(config) {
22453
22276
  * entity-aware data layer to the headless collection view.
22454
22277
  */
22455
22278
  /**
22456
- * Flatten Entity<M> objects to plain row objects.
22457
- * The headless view works with flat `Record<string, unknown>` rows,
22458
- * while the entity system uses `{ id, path, values: M }`.
22459
- *
22460
- * The flattened row includes `id` and `path` at the top level,
22461
- * plus all values spread.
22279
+ * Unwrap `Entity<M>` objects to flat rows for the headless view.
22280
+ * The entity system uses `{ id, path, values: M }`; `values` is already the
22281
+ * flat row `M` carrying its real primary key, so unwrapping is just `.values` —
22282
+ * no `id`/`path` merge (those are view-model metadata, not row columns).
22462
22283
  */
22463
22284
  function flattenEntities(entities) {
22464
- return entities.map((entity) => ({
22465
- id: entity.id,
22466
- path: entity.path,
22467
- ...entity.values
22468
- }));
22285
+ return entities.map((entity) => entity.values);
22469
22286
  }
22470
22287
  /**
22471
- * React hook that adapts an EntityTableController to a CollectionDataController.
22288
+ * React hook that adapts a EntityTableController to a CollectionDataController.
22472
22289
  *
22473
22290
  * Usage:
22474
22291
  * ```tsx
@@ -22776,7 +22593,7 @@ function ImportDataPreview({ importConfig, properties, propertiesOrder }) {
22776
22593
  importConfig.setEntities(mappedData);
22777
22594
  }, []);
22778
22595
  const selectionController = useSelectionController();
22779
- return /* @__PURE__ */ jsx(EntityCollectionTable, {
22596
+ return /* @__PURE__ */ jsx(CollectionTableBinding, {
22780
22597
  title: /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Typography, {
22781
22598
  variant: "subtitle2",
22782
22599
  children: "Imported data preview"
@@ -23372,6 +23189,7 @@ function toSerializableStorageConfig(storage) {
23372
23189
  if (storage.includeBucketUrl !== void 0) result.includeBucketUrl = storage.includeBucketUrl;
23373
23190
  if (storage.storeUrl !== void 0) result.storeUrl = storage.storeUrl;
23374
23191
  if (storage.maxSize !== void 0) result.maxSize = storage.maxSize;
23192
+ if (storage.storageSource !== void 0) result.storageSource = storage.storageSource;
23375
23193
  return result;
23376
23194
  }
23377
23195
  /**
@@ -23384,7 +23202,7 @@ function serializeMatches(matches) {
23384
23202
  }
23385
23203
  /**
23386
23204
  * Resolve a relation target to a string slug.
23387
- * Functions are called to extract the target; EntityCollection objects
23205
+ * Functions are called to extract the target; CollectionConfig objects
23388
23206
  * use their slug.
23389
23207
  */
23390
23208
  function resolveRelationTarget(target) {
@@ -23429,12 +23247,8 @@ function toSerializableProperty(property) {
23429
23247
  if (sp.columnType) result.columnType = sp.columnType;
23430
23248
  if (sp.isId !== void 0) result.isId = sp.isId;
23431
23249
  if (sp.enum) result.enum = sp.enum;
23432
- if (sp.multiline) result.multiline = sp.multiline;
23433
- if (sp.markdown) result.markdown = sp.markdown;
23434
23250
  if (sp.userSelect) result.userSelect = sp.userSelect;
23435
- if (sp.url) result.url = sp.url;
23436
23251
  if (sp.email) result.email = sp.email;
23437
- if (sp.previewAsTag) result.previewAsTag = sp.previewAsTag;
23438
23252
  if (sp.validation) {
23439
23253
  const { matches, ...restValidation } = sp.validation;
23440
23254
  const serializedValidation = { ...restValidation };
@@ -23444,7 +23258,6 @@ function toSerializableProperty(property) {
23444
23258
  }
23445
23259
  const storage = toSerializableStorageConfig(sp.storage);
23446
23260
  if (storage) result.storage = storage;
23447
- if (sp.reference) result.reference = toSerializableProperty(sp.reference);
23448
23261
  return result;
23449
23262
  }
23450
23263
  case "number": {
@@ -23478,7 +23291,6 @@ function toSerializableProperty(property) {
23478
23291
  if (dp.mode) result.mode = dp.mode;
23479
23292
  if (dp.timezone) result.timezone = dp.timezone;
23480
23293
  if (dp.autoValue) result.autoValue = dp.autoValue;
23481
- if (dp.clearable) result.clearable = dp.clearable;
23482
23294
  if (dp.validation) {
23483
23295
  const serializedValidation = {};
23484
23296
  if (dp.validation.required !== void 0) serializedValidation.required = dp.validation.required;
@@ -23605,14 +23417,14 @@ function toSerializableProperties(properties) {
23605
23417
  return result;
23606
23418
  }
23607
23419
  /**
23608
- * Convert an `EntityCollection` to its JSON-serializable form.
23420
+ * Convert an `CollectionConfig` to its JSON-serializable form.
23609
23421
  *
23610
23422
  * Strips all non-serializable fields (functions, React nodes, class instances)
23611
23423
  * while preserving the structural schema that the collection editor works with.
23612
23424
  *
23613
23425
  * The result is safe for `JSON.stringify()` and database storage.
23614
23426
  */
23615
- function toSerializableCollection(collection) {
23427
+ function toSerializableCollectionConfig(collection) {
23616
23428
  const result = {
23617
23429
  slug: collection.slug,
23618
23430
  name: collection.name,
@@ -23621,7 +23433,8 @@ function toSerializableCollection(collection) {
23621
23433
  if (collection.singularName) result.singularName = collection.singularName;
23622
23434
  if (collection.description) result.description = collection.description;
23623
23435
  if (collection.group) result.group = collection.group;
23624
- if (collection.driver) result.driver = collection.driver;
23436
+ if (collection.engine) result.engine = collection.engine;
23437
+ if (collection.dataSource) result.dataSource = collection.dataSource;
23625
23438
  if (collection.databaseId) result.databaseId = collection.databaseId;
23626
23439
  if (collection.titleProperty) result.titleProperty = collection.titleProperty;
23627
23440
  if (collection.ownerId) result.ownerId = collection.ownerId;
@@ -23703,12 +23516,7 @@ function fromSerializableProperty(serialized) {
23703
23516
  if (sp.properties) result.properties = fromSerializableProperties(sp.properties);
23704
23517
  return result;
23705
23518
  }
23706
- case "string": {
23707
- const sp = serialized;
23708
- const result = { ...sp };
23709
- if (sp.reference) result.reference = fromSerializableProperty(sp.reference);
23710
- return result;
23711
- }
23519
+ case "string": return { ...serialized };
23712
23520
  default: return serialized;
23713
23521
  }
23714
23522
  }
@@ -23721,13 +23529,13 @@ function fromSerializableProperties(serialized) {
23721
23529
  return result;
23722
23530
  }
23723
23531
  /**
23724
- * Convert a `SerializableCollection` back to an `EntityCollection`.
23532
+ * Convert a `SerializableCollectionConfig` back to an `CollectionConfig`.
23725
23533
  *
23726
23534
  * The result will NOT contain any of the non-serializable fields
23727
23535
  * (callbacks, entityActions, etc.) — those must be re-attached by the
23728
23536
  * consumer if needed.
23729
23537
  */
23730
- function fromSerializableCollection(serialized) {
23538
+ function fromSerializableCollectionConfig(serialized) {
23731
23539
  const { properties, ...rest } = serialized;
23732
23540
  return {
23733
23541
  ...rest,
@@ -23768,7 +23576,7 @@ function useJsonCollectionsConfigController({ store, readOnly = false, autoLoad
23768
23576
  try {
23769
23577
  const [serialized, navEntries] = await Promise.all([storeRef.current.load(), storeRef.current.loadNavigationEntries?.() ?? Promise.resolve([])]);
23770
23578
  if (cancelled) return;
23771
- setCollections(serialized.map(fromSerializableCollection));
23579
+ setCollections(serialized.map(fromSerializableCollectionConfig));
23772
23580
  setNavigationEntries(navEntries);
23773
23581
  } catch (e) {
23774
23582
  console.error("useJsonCollectionsConfigController: failed to load collections", e);
@@ -23784,7 +23592,7 @@ function useJsonCollectionsConfigController({ store, readOnly = false, autoLoad
23784
23592
  * Update local state and persist a collection to the store.
23785
23593
  */
23786
23594
  const persistCollection = useCallback(async (collection) => {
23787
- const serializable = toSerializableCollection(collection);
23595
+ const serializable = toSerializableCollectionConfig(collection);
23788
23596
  await storeRef.current.save(collection.slug, serializable);
23789
23597
  }, []);
23790
23598
  /**
@@ -24309,6 +24117,6 @@ function getFullIdPath(propertyKey, propertyNamespace) {
24309
24117
  return idToPropertiesPath(propertyNamespace ? `${propertyNamespace}.${propertyKey}` : propertyKey);
24310
24118
  }
24311
24119
  //#endregion
24312
- export { RelationPreview as $, SelectableTable as $n, DateTimeFieldBinding as $t, useCollectionDataController as A, getLastSegment$1 as An, renderSkeletonCaptionText as Ar, useImportConfig as At, ArrayOfMapsPreview as B, UrlContext as Bn, getFieldId as Bt, downloadEntitiesExport as C, deleteEntityAction as Cn, isRelationProperty as Cr, useCollectionEditorController as Ct, ImportDataPreview as D, addInitialSlash as Dn, StorageThumbnail as Dr, flattenEntry as Dt, ImportCollectionAction as E, CreationResultDialog as En, EnumValuesChip as Er, convertDataToEntity as Et, extractTouchedValues as F, useBuildCollectionRegistryController as Fn, sanitizeUrl as Fr, PropertyConfigBadge as Ft, DatePreview as G, useCollectionRegistryController as Gn, SelectFieldBinding as Gt, UserPreview as H, NavigationStateContext as Hn, TextFieldBinding as Ht, getChanges as I, useEntityHistory as In, ImagePreview as Ir, DEFAULT_FIELD_CONFIGS as It, ArrayOneOfPreview as J, getEntityViewWidth as Jn, ReferenceAsStringFieldBinding as Jt, KeyValuePreview as K, useSideDialogsController as Kn, RepeatFieldBinding as Kt, getInitialEntityValues as L, resolveNavigationFrom as Ln, EmptyValue as Lr, getDefaultFieldConfig as Lt, mapPropertyToConfig as M, removeInitialSlash as Mn, renderSkeletonImageThumbnail as Mr, ImportFileUpload as Mt, EntityFormBinding as N, removeTrailingSlash as Nn, renderSkeletonText as Nr, convertFileToJson as Nt, PropertySelectEntry as O, getCollectionBySlugWithin as On, StorageThumbnailInternal as Or, processValueMapping as Ot, EntityForm as P, resolveCollectionPathIds$1 as Pn, UrlComponentPreview as Pr, unflattenObject as Pt, ArrayOfStorageComponentsPreview as Q, EntityCollectionTable as Qn, KeyValueFieldBinding as Qt, removeEmptyContainers as R, useResolvedNavigationFrom as Rn, getDefaultFieldId as Rt, downloadDataAsCsv as S, copyEntityAction as Sn, isReferenceProperty as Sr, EntityCollectionViewActions as St, getEntityJsonExportableData as T, resetPasswordAction as Tn, StringPropertyPreview as Tr, DataNewPropertiesMapping as Tt, NumberPropertyPreview as U, useNavigationStateController as Un, SwitchFieldBinding as Ut, PropertyPreview as V, useUrlController as Vn, VectorFieldBinding as Vt, BooleanPreview as W, CollectionRegistryContext as Wn, StorageUploadFieldBinding as Wt, ArrayPropertyEnumPreview as X, mergeEntityActions as Xn, MarkdownEditorFieldBinding as Xt, ArrayOfStringsPreview as Y, useBuildSideEntityController as Yn, MultiSelectFieldBinding as Yt, ArrayEnumPreview as Z, useSelectionController as Zn, MapFieldBinding as Zt, toSerializableProperty as _, useBuildUrlController as _n, getIconForProperty as _r, SideEntityProvider as _t, namespaceToPropertiesPath as a, ReadOnlyFieldBinding as an, useEntitySelectionDialog as ar, RebaseLayout as at, BasicExportAction as b, useResolvedViews as bn, getPropertyInPath as br, EntityCollectionCardView as bt, DEFAULT_COLLECTION_GENERATION_ENDPOINT as c, LabelWithIconAndTooltip as cn, resolveEntityView as cr, RebaseAuthGate as ct, useJsonCollectionsConfigController as d, FieldHelperText as dn, ReferencePreview as dr, Drawer as dt, BlockFieldBinding as en, EntityCollectionRowActions as er, CollectionPanel as et, fromSerializableCollection as f, SearchIconsView as fn, EntityPreview as fr, DefaultDrawer as ft, toSerializableProperties as g, useBreadcrumbsController as gn, getDefaultPropertiesOrder as gr, AdminModeSyncer as gt, toSerializableCollection as h, SideDialogs as hn, getBracketNotation as hr, useApp as ht, namespaceToPropertiesOrderPath as i, PropertyFieldBinding as in, useSideEntityController as ir, RebaseRoute as it, mapPropertiesToConfigs as j, removeInitialAndTrailingSlashes$1 as jn, renderSkeletonIcon as jr, ImportSaveInProgress as jt, createStaticDataController as k, getCollectionPathsCombinations as kn, SkeletonPropertyComponent as kr, getInferenceType as kt, buildCollectionGenerationCallback as l, PropertyIdCopyTooltip as ln, EntityView as lr, RebaseCMS as lt, fromSerializableProperty as m, EntitySelectionTable as mn, getEntityTitlePropertyKey as mr, AppBar as mt, getFullIdPath as n, ArrayContainer as nn, SelectableTableContext as nr, RebaseRouteDefs as nt, MissingReferenceWidget as o, FormLayout as on, VirtualTableInput as or, RebaseNavigation as ot, fromSerializableProperties as p, FieldCaption as pn, getEntityPreviewKeys as pr, DrawerFooterActions as pt, MapPropertyPreview as q, buildSidePanelsFromUrl as qn, ReferenceFieldBinding as qt, idToPropertiesPath as r, ArrayCustomShapedFieldBinding as rn, SideEntityControllerContext as rr, CustomViewRoute as rt, CollectionGenerationApiError as s, FormEntry as sn, resolveEntityAction as sr, useLocalCollectionsConfigController as st, getFullId as t, ArrayOfReferencesFieldBinding as tn, useClearRestoreValue as tr, RebaseShell as tt, validateCollectionJson as u, LabelWithIcon as un, ArrayOfReferencesPreview as ur, Scaffold as ut, useCollectionsConfigController as v, useBuildNavigationStateController as vn, getIconForWidget as vr, ReferenceWidget as vt, getEntityCSVExportableData as w, editEntityAction as wn, ArrayPropertyPreview as wr, ImportNewPropertyFieldPreview as wt, downloadBlob as x, useResolvedCollections as xn, getResolvedPropertyInPath as xr, EntityCard as xt, ExportCollectionAction as y, useTopLevelNavigation as yn, getPropertiesWithPropertiesOrder as yr, EntityCollectionView as yt, zodToFormErrors as z, useCMSContext as zn, getFieldConfig as zt };
24120
+ export { RelationPreview as $, SelectableTable as $n, BlockFieldBinding as $t, useCollectionDataController as A, removeInitialAndTrailingSlashes$1 as An, renderSkeletonIcon as Ar, useImportConfig as At, ArrayOfMapsPreview as B, useUrlController as Bn, getFieldId as Bt, downloadEntitiesExport as C, editEntityAction as Cn, ArrayPropertyPreview as Cr, useCollectionEditorController as Ct, ImportDataPreview as D, getCollectionBySlugWithin as Dn, StorageThumbnailInternal as Dr, flattenEntry as Dt, ImportCollectionAction as E, addInitialSlash as En, StorageThumbnail as Er, convertDataToEntity as Et, extractTouchedValues as F, useHistory as Fn, ImagePreview as Fr, PropertyConfigBadge as Ft, DatePreview as G, useSideDialogsController as Gn, SelectFieldBinding as Gt, UserPreview as H, useNavigationStateController as Hn, TextFieldBinding as Ht, getChanges as I, resolveNavigationFrom as In, EmptyValue as Ir, DEFAULT_FIELD_CONFIGS as It, ArrayOneOfPreview as J, useBuildSidePanel as Jn, MultiSelectFieldBinding as Jt, KeyValuePreview as K, buildSidePanelsFromUrl as Kn, RepeatFieldBinding as Kt, getInitialEntityValues as L, useResolvedNavigationFrom as Ln, getDefaultFieldConfig as Lt, mapPropertyToConfig as M, removeTrailingSlash as Mn, renderSkeletonText as Mr, ImportFileUpload as Mt, EntityFormBinding as N, resolveCollectionPathIds$1 as Nn, UrlComponentPreview as Nr, convertFileToJson as Nt, PropertySelectEntry as O, getCollectionPathsCombinations as On, SkeletonPropertyComponent as Or, processValueMapping as Ot, EntityForm as P, useBuildCollectionRegistryController as Pn, sanitizeUrl as Pr, unflattenObject as Pt, ArrayOfStorageComponentsPreview as Q, CollectionTableBinding as Qn, DateTimeFieldBinding as Qt, removeEmptyContainers as R, useCMSContext as Rn, getDefaultFieldId as Rt, downloadDataAsCsv as S, deleteEntityAction as Sn, isRelationProperty as Sr, CollectionViewActions as St, getEntityJsonExportableData as T, CreationResultDialog as Tn, EnumValuesChip as Tr, DataNewPropertiesMapping as Tt, NumberPropertyPreview as U, CollectionRegistryContext as Un, SwitchFieldBinding as Ut, PropertyPreview as V, NavigationStateContext as Vn, VectorFieldBinding as Vt, BooleanPreview as W, useCollectionRegistryController as Wn, StorageUploadFieldBinding as Wt, ArrayPropertyEnumPreview as X, useSelectionController as Xn, MapFieldBinding as Xt, ArrayOfStringsPreview as Y, mergeEntityActions as Yn, MarkdownEditorFieldBinding as Yt, ArrayEnumPreview as Z, VirtualTableInput$1 as Zn, KeyValueFieldBinding as Zt, toSerializableProperty as _, useBuildNavigationStateController as _n, getIconForWidget as _r, SidePanelProvider as _t, namespaceToPropertiesPath as a, FormLayout as an, useSelectionDialog as ar, RebaseLayout as at, BasicExportAction as b, useResolvedCollections as bn, getResolvedPropertyInPath as br, CollectionCardViewBinding as bt, DEFAULT_COLLECTION_GENERATION_ENDPOINT as c, PropertyIdCopyTooltip as cn, EntityViewBinding as cr, RebaseAuthGate as ct, useJsonCollectionsConfigController as d, SearchIconsView as dn, EntityPreviewBinding as dr, Drawer as dt, ArrayOfReferencesFieldBinding as en, CollectionRowActions as er, CollectionPanel as et, fromSerializableCollectionConfig as f, FieldCaption as fn, getEntityPreviewKeys as fr, DefaultDrawer as ft, toSerializableProperties as g, useBuildUrlController as gn, getIconForProperty as gr, AdminModeSyncer as gt, toSerializableCollectionConfig as h, useBreadcrumbsController as hn, getDefaultPropertiesOrder as hr, useApp as ht, namespaceToPropertiesOrderPath as i, ReadOnlyFieldBinding as in, useSidePanel as ir, RebaseRoute as it, mapPropertiesToConfigs as j, removeInitialSlash as jn, renderSkeletonImageThumbnail as jr, ImportSaveInProgress as jt, createStaticDataController as k, getLastSegment$1 as kn, renderSkeletonCaptionText as kr, getInferenceType as kt, buildCollectionGenerationCallback as l, LabelWithIcon as ln, ArrayOfReferencesPreview as lr, RebaseCMS as lt, fromSerializableProperty as m, SideDialogs as mn, getBracketNotation as mr, AppBar as mt, getFullIdPath as n, ArrayCustomShapedFieldBinding as nn, SelectableTableContext as nr, RebaseRouteDefs as nt, MissingReferenceWidget as o, FormEntry as on, resolveEntityAction as or, RebaseNavigation as ot, fromSerializableProperties as p, SelectionTableBinding as pn, getEntityTitlePropertyKey as pr, DrawerFooterActions as pt, MapPropertyPreview as q, getEntityViewWidth as qn, ReferenceFieldBinding as qt, idToPropertiesPath as r, PropertyFieldBinding as rn, SidePanelControllerContext as rr, CustomViewRoute as rt, CollectionGenerationApiError as s, LabelWithIconAndTooltip as sn, resolveEntityView as sr, useLocalCollectionsConfigController as st, getFullId as t, ArrayContainer as tn, useClearRestoreValue as tr, RebaseShell as tt, validateCollectionJson as u, FieldHelperText as un, ReferencePreview as ur, Scaffold as ut, useCollectionsConfigController as v, useTopLevelNavigation as vn, getPropertiesWithPropertiesOrder as vr, ReferenceWidget as vt, getEntityCSVExportableData as w, resetPasswordAction as wn, StringPropertyPreview as wr, ImportNewPropertyFieldPreview as wt, downloadBlob as x, copyEntityAction as xn, isReferenceProperty as xr, EntityCardBinding as xt, ExportCollectionAction as y, useResolvedViews as yn, getPropertyInPath as yr, CollectionViewBinding as yt, zodToFormErrors as z, UrlContext as zn, getFieldConfig as zt };
24313
24121
 
24314
- //# sourceMappingURL=src-DOX2nOyh.js.map
24122
+ //# sourceMappingURL=src-sUZfe29F.js.map