@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
@@ -1,67 +1,37 @@
1
1
  import { useSyncExternalStore, useCallback, useRef } from "react";
2
2
  import { SelectedCellProps } from "@rebasepro/types";
3
+ import {
4
+ createVirtualTableSelectionStore,
5
+ VirtualTableSelectionStore,
6
+ SelectedCell
7
+ } from "@rebasepro/ui";
8
+
9
+ export interface AdminSelectedCell extends SelectedCell {
10
+ entityPath: string;
11
+ entityId: string | number;
12
+ propertyKey: string;
13
+ cellRect: DOMRect;
14
+ width: number;
15
+ height: number;
16
+ }
3
17
 
4
- /**
5
- * A ref-based selection store that avoids React context re-renders.
6
- *
7
- * The problem with putting `selectedCell` in a React context value is that
8
- * ANY cell selection change triggers a context value change, which forces
9
- * ALL consumers (every PropertyTableCell in the table) to re-render.
10
- * This causes the DOM to be replaced between mousedown and click events,
11
- * breaking `alwaysInteractive` cells (like relation selectors) where the
12
- * user needs to click a button on the very first interaction.
13
- *
14
- * This store uses `useSyncExternalStore` so only cells whose `selected`
15
- * derivation actually changed will re-render.
16
- */
17
18
  export function createSelectionStore() {
18
- let selectedCell: SelectedCellProps | undefined = undefined;
19
- const listeners = new Set<() => void>();
20
-
21
- function getSnapshot(): SelectedCellProps | undefined {
22
- return selectedCell;
23
- }
24
-
25
- function subscribe(listener: () => void): () => void {
26
- listeners.add(listener);
27
- return () => listeners.delete(listener);
28
- }
29
-
30
- function select(cell: SelectedCellProps | undefined) {
31
- selectedCell = cell;
32
- listeners.forEach(l => l());
33
- }
34
-
35
- return { getSnapshot,
36
- subscribe,
37
- select };
19
+ return createVirtualTableSelectionStore<AdminSelectedCell>();
38
20
  }
39
21
 
40
- export type SelectionStore = ReturnType<typeof createSelectionStore>;
22
+ export type SelectionStore = VirtualTableSelectionStore<AdminSelectedCell>;
41
23
 
42
- /**
43
- * Hook that subscribes a cell to the selection store and returns
44
- * whether THIS cell is selected. Only re-renders when the cell's
45
- * `selected` boolean actually changes (not on every store update).
46
- */
47
24
  export function useCellSelected(
48
- store: { getSnapshot: () => SelectedCellProps | undefined; subscribe: (listener: () => void) => () => void },
25
+ store: { getEntity: () => SelectedCellProps | undefined; subscribe: (listener: () => void) => () => void },
49
26
  propertyKey: string,
50
27
  entityPath: string,
51
28
  entityId: string | number
52
29
  ): boolean {
53
- // Memoize a selector that derives a boolean from the store snapshot.
54
- // useSyncExternalStore calls this on every store notification, but
55
- // React only re-renders when the returned value !== the previous one.
56
- const selectorRef = useRef({ propertyKey,
57
- entityPath,
58
- entityId });
59
- selectorRef.current = { propertyKey,
60
- entityPath,
61
- entityId };
30
+ const selectorRef = useRef({ propertyKey, entityPath, entityId });
31
+ selectorRef.current = { propertyKey, entityPath, entityId };
62
32
 
63
- const getSnapshot = useCallback(() => {
64
- const cell = store.getSnapshot();
33
+ const getEntity = useCallback(() => {
34
+ const cell = store.getEntity();
65
35
  if (!cell) return false;
66
36
  const s = selectorRef.current;
67
37
  return cell.propertyKey === s.propertyKey &&
@@ -69,5 +39,5 @@ entityId };
69
39
  cell.entityId === s.entityId;
70
40
  }, [store]);
71
41
 
72
- return useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);
42
+ return useSyncExternalStore(store.subscribe, getEntity, getEntity);
73
43
  }
@@ -8,16 +8,24 @@ interface BooleanFieldProps {
8
8
  value?: [op: VirtualTableWhereFilterOp, fieldValue: unknown];
9
9
  setValue: (value?: [op: VirtualTableWhereFilterOp, newValue: unknown]) => void;
10
10
  title?: string;
11
+ /**
12
+ * Restrict the offered operators. This field only ever emits `["==", …]`,
13
+ * so it renders nothing when `==` is not allowed.
14
+ */
15
+ operators?: readonly VirtualTableWhereFilterOp[];
11
16
  }
12
17
 
13
18
  export function BooleanFilterField({
14
19
  name,
15
20
  title,
16
21
  value,
17
- setValue
22
+ setValue,
23
+ operators
18
24
  }: BooleanFieldProps) {
19
25
  const { t } = useTranslation();
20
26
 
27
+ if (operators && !operators.includes("==")) return null;
28
+
21
29
  function updateFilter(val?: boolean) {
22
30
  if (val !== undefined) {
23
31
  setValue(
@@ -11,9 +11,15 @@ interface DateTimeFilterFieldProps {
11
11
  isArray?: boolean;
12
12
  title?: string;
13
13
  timezone?: string;
14
+ /**
15
+ * Restrict the offered operators (already resolved against engine
16
+ * capabilities and property config). When omitted, all operators this
17
+ * field can render are offered.
18
+ */
19
+ operators?: readonly VirtualTableWhereFilterOp[];
14
20
  }
15
21
 
16
- const operationLabels: Record<VirtualTableWhereFilterOp | "is-null", string> = {
22
+ const operationLabels: Partial<Record<VirtualTableWhereFilterOp, string>> = {
17
23
  "==": "==",
18
24
  "!=": "!=",
19
25
  ">": ">",
@@ -24,7 +30,8 @@ const operationLabels: Record<VirtualTableWhereFilterOp | "is-null", string> = {
24
30
  in: "in",
25
31
  "array-contains": "Contains",
26
32
  "array-contains-any": "Any",
27
- "is-null": "Is null"
33
+ "is-null": "Is null",
34
+ "is-not-null": "Is not null"
28
35
  };
29
36
 
30
37
  const multipleSelectOperations = ["array-contains-any", "in"];
@@ -36,26 +43,40 @@ export function DateTimeFilterField({
36
43
  value,
37
44
  setValue,
38
45
  title,
39
- timezone
46
+ timezone,
47
+ operators
40
48
  }: DateTimeFilterFieldProps) {
41
49
 
42
50
  const { locale } = useCustomizationController();
43
- const possibleOperations: (keyof typeof operationLabels)[] = isArray
51
+ let possibleOperations: (keyof typeof operationLabels)[] = isArray
44
52
  ? ["array-contains"]
45
- : ["==", "!=", ">", "<", ">=", "<=", "is-null"];
53
+ : ["==", "!=", ">", "<", ">=", "<=", "is-null", "is-not-null"];
54
+
55
+ if (operators) {
56
+ possibleOperations = possibleOperations.filter(op => (operators as readonly string[]).includes(op));
57
+ }
46
58
 
47
59
  const [fieldOperation, fieldValue] = value || [possibleOperations[0], undefined];
48
- const [operation, setOperation] = useState<VirtualTableWhereFilterOp | "is-null">(fieldOperation === "==" && fieldValue === null ? "is-null" : fieldOperation);
60
+ // Read back both the canonical null operators and the legacy `["==", null]` /
61
+ // `["!=", null]` form saved by older filter presets.
62
+ const [operation, setOperation] = useState<VirtualTableWhereFilterOp>(
63
+ fieldOperation === "==" && fieldValue === null ? "is-null"
64
+ : fieldOperation === "!=" && fieldValue === null ? "is-not-null"
65
+ : fieldOperation
66
+ );
49
67
  const [internalValue, setInternalValue] = useState<Date | null | undefined>(fieldValue as Date | null | undefined);
50
68
 
51
- const isNullOperation = operation === "is-null";
69
+ const isNullOperation = operation === "is-null" || operation === "is-not-null";
70
+
71
+ // All renderable operators were filtered out (engine/property narrowing).
72
+ if (possibleOperations.length === 0) return null;
52
73
 
53
- function updateFilter(op: VirtualTableWhereFilterOp | "is-null", val: Date | undefined | null) {
54
- // Handle "is null" operation
55
- if (op === "is-null") {
74
+ function updateFilter(op: VirtualTableWhereFilterOp, val: Date | undefined | null) {
75
+ // Null-testing operators ignore their value.
76
+ if (op === "is-null" || op === "is-not-null") {
56
77
  setOperation(op);
57
78
  setInternalValue(null);
58
- setValue(["==", null]);
79
+ setValue([op, null]);
59
80
  return;
60
81
  }
61
82
 
@@ -91,7 +112,7 @@ export function DateTimeFilterField({
91
112
  size={"medium"}
92
113
  fullWidth={true}
93
114
  onValueChange={(value) => {
94
- updateFilter(value as VirtualTableWhereFilterOp | "is-null", internalValue);
115
+ updateFilter(value as VirtualTableWhereFilterOp, internalValue);
95
116
  }}
96
117
  renderValue={(op) => operationLabels[op as keyof typeof operationLabels]}>
97
118
  {possibleOperations.map((op) => (
@@ -0,0 +1,187 @@
1
+ import React, { Suspense } from "react";
2
+ import {
3
+ ArrayProperty,
4
+ FilterFieldBindingProps,
5
+ Property,
6
+ ReferenceProperty,
7
+ RelationProperty,
8
+ WhereFilterOp
9
+ } from "@rebasepro/types";
10
+ import { enumToObjectEntries, resolveFilterOperators } from "@rebasepro/common";
11
+ import { useCollectionScope, useComponentOverride, useResolvedComponent } from "@rebasepro/core";
12
+ import { StringNumberFilterField } from "./StringNumberFilterField";
13
+ import { BooleanFilterField } from "./BooleanFilterField";
14
+ import { DateTimeFilterField } from "./DateTimeFilterField";
15
+ import { ReferenceFilterField } from "./ReferenceFilterField";
16
+ import { RelationFilterField } from "./RelationFilterField";
17
+
18
+ export interface FilterFieldBindingInput {
19
+ /** Key of the property being filtered (the column id). */
20
+ propertyKey: string;
21
+ /** The raw property — array properties are unwrapped internally. */
22
+ property: Property;
23
+ /**
24
+ * Engine backing the collection (`collection.engine`). Drives which
25
+ * operators the engine can execute. Usually omitted — it is read from
26
+ * the surrounding {@link CollectionScopeProvider}; pass it explicitly
27
+ * only when rendering outside any collection scope.
28
+ */
29
+ engine?: string;
30
+ value?: [WhereFilterOp, unknown];
31
+ setValue: (value?: [WhereFilterOp, unknown]) => void;
32
+ /** Coordination flags for fields that open their own dialogs. */
33
+ hidden?: boolean;
34
+ setHidden?: (hidden: boolean) => void;
35
+ }
36
+
37
+ /**
38
+ * The single entry point for rendering a collection filter field.
39
+ * Used by both the table header filters ({@link SelectableTable}) and the
40
+ * Filters dialog.
41
+ *
42
+ * Resolution order:
43
+ * 1. `property.ui.Filter` — per-property replacement (rendered even when the
44
+ * resolved operator list is empty; the component owns filterability).
45
+ * 2. `components["Collection.FilterField"]` — collection-level or app-level
46
+ * override (wrap mode supported via `OriginalComponent`).
47
+ * 3. Built-in field dispatched by property type.
48
+ *
49
+ * The operators handed to the field are the intersection of the engine's
50
+ * capabilities, the property-type defaults, and `property.ui.filterOperators`
51
+ * (see `resolveFilterOperators`). When that intersection is empty and no
52
+ * per-property `Filter` is set, nothing is rendered.
53
+ *
54
+ * @group Components
55
+ */
56
+ export function FilterFieldBinding({
57
+ propertyKey,
58
+ property,
59
+ engine,
60
+ value,
61
+ setValue,
62
+ hidden,
63
+ setHidden
64
+ }: FilterFieldBindingInput): React.ReactNode {
65
+
66
+ const isArray = property.type === "array";
67
+ const ofVal = isArray ? (property as ArrayProperty).of : undefined;
68
+ const baseProperty: Property | undefined = isArray
69
+ ? (Array.isArray(ofVal) ? ofVal[0] : ofVal) as Property | undefined
70
+ : property;
71
+
72
+ // Hooks must run unconditionally — before any early return.
73
+ const scopeCollection = useCollectionScope();
74
+ const ResolvedFilterField = useComponentOverride<FilterFieldBindingProps>("Collection.FilterField", DefaultFilterField);
75
+ const PropertyFilter = useResolvedComponent<FilterFieldBindingProps>(baseProperty?.ui?.Filter);
76
+
77
+ if (!baseProperty) return null;
78
+
79
+ const operators = resolveFilterOperators({
80
+ property: baseProperty,
81
+ isArray,
82
+ engine: engine ?? scopeCollection?.engine
83
+ });
84
+
85
+ const bindingProps: FilterFieldBindingProps = {
86
+ propertyKey,
87
+ property: baseProperty,
88
+ isArray,
89
+ operators,
90
+ value,
91
+ setValue,
92
+ title: property.name,
93
+ hidden,
94
+ setHidden
95
+ };
96
+
97
+ // 1. Per-property replacement — always rendered, the dev owns filterability.
98
+ if (PropertyFilter) {
99
+ return (
100
+ <Suspense fallback={null}>
101
+ <PropertyFilter {...bindingProps}/>
102
+ </Suspense>
103
+ );
104
+ }
105
+
106
+ // 2/3. Override or built-in — only when the property is filterable here.
107
+ if (operators.length === 0) return null;
108
+
109
+ return <ResolvedFilterField {...bindingProps}/>;
110
+ }
111
+
112
+ /**
113
+ * Built-in filter field dispatch by property type. This is the
114
+ * `OriginalComponent` received by `"Collection.FilterField"` overrides in
115
+ * wrap mode.
116
+ */
117
+ function DefaultFilterField({
118
+ propertyKey,
119
+ property,
120
+ isArray,
121
+ operators,
122
+ value,
123
+ setValue,
124
+ title,
125
+ hidden,
126
+ setHidden
127
+ }: FilterFieldBindingProps): React.ReactNode {
128
+
129
+ if (property.type === "reference") {
130
+ const referenceProperty = property as ReferenceProperty;
131
+ return <ReferenceFilterField value={value}
132
+ setValue={setValue}
133
+ name={propertyKey}
134
+ isArray={isArray}
135
+ operators={operators}
136
+ path={referenceProperty.path}
137
+ title={title}
138
+ includeId={referenceProperty.includeId}
139
+ previewProperties={referenceProperty.ui?.previewProperties}
140
+ hidden={hidden ?? false}
141
+ setHidden={setHidden ?? (() => undefined)}/>;
142
+ }
143
+
144
+ if (property.type === "relation") {
145
+ const relation = (property as RelationProperty).relation;
146
+ if (!relation) return null;
147
+ return <RelationFilterField value={value as never}
148
+ setValue={setValue}
149
+ name={propertyKey}
150
+ operators={operators}
151
+ relation={relation}
152
+ hidden={hidden ?? false}
153
+ setHidden={setHidden ?? (() => undefined)}/>;
154
+ }
155
+
156
+ if (property.type === "number" || property.type === "string") {
157
+ const enumValues = property.enum ? enumToObjectEntries(property.enum) : undefined;
158
+ return <StringNumberFilterField value={value}
159
+ setValue={setValue}
160
+ name={propertyKey}
161
+ type={property.type}
162
+ isArray={isArray}
163
+ operators={operators}
164
+ enumValues={enumValues}
165
+ title={title}/>;
166
+ }
167
+
168
+ if (property.type === "boolean") {
169
+ return <BooleanFilterField value={value}
170
+ setValue={setValue}
171
+ name={propertyKey}
172
+ operators={operators}
173
+ title={title}/>;
174
+ }
175
+
176
+ if (property.type === "date") {
177
+ return <DateTimeFilterField value={value}
178
+ setValue={setValue}
179
+ name={propertyKey}
180
+ mode={property.mode}
181
+ isArray={isArray}
182
+ operators={operators}
183
+ title={title}/>;
184
+ }
185
+
186
+ return null;
187
+ }
@@ -1,5 +1,5 @@
1
- import { useEntitySelectionDialog } from "../../../hooks/useEntitySelectionDialog";
2
- import type { EntityCollection } from "@rebasepro/types";
1
+ import { useSelectionDialog } from "../../../hooks/useSelectionDialog";
2
+ import type { CollectionConfig } from "@rebasepro/types";
3
3
  import React, { useMemo, useState } from "react";
4
4
  import { VirtualTableWhereFilterOp } from "@rebasepro/ui";
5
5
  import { Entity, EntityReference } from "@rebasepro/types";
@@ -20,6 +20,12 @@ interface ReferenceFilterFieldProps {
20
20
  previewProperties?: string[];
21
21
  hidden: boolean;
22
22
  setHidden: (hidden: boolean) => void;
23
+ /**
24
+ * Restrict the offered operators (already resolved against engine
25
+ * capabilities and property config). When omitted, all operators this
26
+ * field can render are offered.
27
+ */
28
+ operators?: readonly VirtualTableWhereFilterOp[];
23
29
  }
24
30
 
25
31
  const operationLabels = {
@@ -44,11 +50,12 @@ export function ReferenceFilterField({
44
50
  path,
45
51
  includeId = true,
46
52
  previewProperties,
47
- setHidden
53
+ setHidden,
54
+ operators
48
55
  }: ReferenceFilterFieldProps) {
49
56
  const { t } = useTranslation();
50
57
 
51
- const possibleOperations: (keyof typeof operationLabels)[] = isArray
58
+ let possibleOperations: (keyof typeof operationLabels)[] = isArray
52
59
  ? ["array-contains"]
53
60
  : ["==", "!=", ">", "<", ">=", "<="];
54
61
 
@@ -58,6 +65,10 @@ export function ReferenceFilterField({
58
65
  possibleOperations.push("in", "not-in");
59
66
  }
60
67
 
68
+ if (operators) {
69
+ possibleOperations = possibleOperations.filter(op => (operators as readonly string[]).includes(op));
70
+ }
71
+
61
72
  const [fieldOperation, fieldValue] = value || [possibleOperations[0], undefined];
62
73
  const [operation, setOperation] = useState<VirtualTableWhereFilterOp>(fieldOperation);
63
74
  const [internalValue, setInternalValue] = useState<EntityReference | EntityReference[] | undefined | null>(fieldValue as EntityReference | EntityReference[] | undefined | null);
@@ -100,7 +111,7 @@ export function ReferenceFilterField({
100
111
  }
101
112
 
102
113
  const collectionRegistryController = useCollectionRegistryController();
103
- const collection: EntityCollection | undefined = useMemo(() => {
114
+ const collection: CollectionConfig | undefined = useMemo(() => {
104
115
  return path ? collectionRegistryController.getCollection(path) : undefined;
105
116
  }, [path]);
106
117
 
@@ -114,7 +125,7 @@ export function ReferenceFilterField({
114
125
 
115
126
  const multiple = multipleSelectOperations.includes(operation);
116
127
 
117
- const referenceDialogController = useEntitySelectionDialog({
128
+ const referenceDialogController = useSelectionDialog({
118
129
  multiselect: multiple,
119
130
  path,
120
131
  collection,
@@ -147,6 +158,9 @@ export function ReferenceFilterField({
147
158
  );
148
159
  };
149
160
 
161
+ // All renderable operators were filtered out (engine/property narrowing).
162
+ if (possibleOperations.length === 0) return null;
163
+
150
164
  return (
151
165
 
152
166
  <div className="flex w-full flex-row">
@@ -157,7 +171,7 @@ export function ReferenceFilterField({
157
171
  onValueChange={(value) => {
158
172
  updateFilter(value as VirtualTableWhereFilterOp, internalValue);
159
173
  }}
160
- renderValue={(op) => operationLabels[op as VirtualTableWhereFilterOp]}>
174
+ renderValue={(op) => operationLabels[op as keyof typeof operationLabels]}>
161
175
  {possibleOperations.map((op) => (
162
176
  <SelectItem key={op} value={op}>
163
177
  {operationLabels[op]}
@@ -11,6 +11,12 @@ interface RelationFilterFieldProps {
11
11
  relation: Relation; // relation config provided externally
12
12
  hidden: boolean;
13
13
  setHidden: (value: boolean) => void;
14
+ /**
15
+ * Restrict the offered operators (already resolved against engine
16
+ * capabilities and property config). When omitted, all operators this
17
+ * field can render are offered.
18
+ */
19
+ operators?: readonly VirtualTableWhereFilterOp[];
14
20
  }
15
21
 
16
22
  const operationLabels = {
@@ -34,15 +40,20 @@ export function RelationFilterField({
34
40
  relation,
35
41
  name: _name,
36
42
  hidden: _hidden,
37
- setHidden: _setHidden
43
+ setHidden: _setHidden,
44
+ operators
38
45
  }: RelationFilterFieldProps) {
39
46
 
40
47
  const manyRelation = relation.cardinality === "many";
41
48
 
42
- const possibleOperations: (keyof typeof operationLabels)[] = manyRelation
49
+ let possibleOperations: (keyof typeof operationLabels)[] = manyRelation
43
50
  ? ["array-contains", "array-contains-any"]
44
51
  : ["==", "!=", ">", "<", ">=", "<=", "in", "not-in"];
45
52
 
53
+ if (operators) {
54
+ possibleOperations = possibleOperations.filter(op => (operators as readonly string[]).includes(op));
55
+ }
56
+
46
57
  const [fieldOperation, fieldValue] = value || [possibleOperations[0], undefined];
47
58
  const [operation, setOperation] = useState<VirtualTableWhereFilterOp>(fieldOperation);
48
59
  const [internalValue, setInternalValue] = useState<EntityRelation | EntityRelation[] | undefined | null>(fieldValue);
@@ -89,6 +100,9 @@ export function RelationFilterField({
89
100
  updateFilter(operation, newVal);
90
101
  };
91
102
 
103
+ // All renderable operators were filtered out (engine/property narrowing).
104
+ if (possibleOperations.length === 0) return null;
105
+
92
106
  return (
93
107
  <div className="flex flex-row">
94
108
  <div className="">
@@ -98,7 +112,7 @@ export function RelationFilterField({
98
112
  onValueChange={(newOp) => {
99
113
  updateFilter(newOp as VirtualTableWhereFilterOp, internalValue);
100
114
  }}
101
- renderValue={(op) => operationLabels[op as VirtualTableWhereFilterOp]}
115
+ renderValue={(op) => operationLabels[op as keyof typeof operationLabels]}
102
116
  >
103
117
  {possibleOperations.map((op) => (
104
118
  <SelectItem key={op} value={op}>
@@ -21,6 +21,12 @@ interface StringNumberFilterFieldProps {
21
21
  isArray?: boolean;
22
22
  enumValues?: EnumValueConfig[];
23
23
  title?: string;
24
+ /**
25
+ * Restrict the offered operators (already resolved against engine
26
+ * capabilities and property config). When omitted, all operators this
27
+ * field can render are offered.
28
+ */
29
+ operators?: readonly VirtualTableWhereFilterOp[];
24
30
  }
25
31
 
26
32
  const operationLabels = {
@@ -34,11 +40,23 @@ const operationLabels = {
34
40
  "not-in": "Not in",
35
41
  "array-contains": "Contains",
36
42
  "array-contains-any": "Any",
37
- "is-null": "Is null"
43
+ "ilike": "Contains",
44
+ "not-ilike": "Not contains",
45
+ "is-null": "Is null",
46
+ "is-not-null": "Is not null"
38
47
  };
39
48
 
40
49
  const multipleSelectOperations = ["array-contains-any", "in", "not-in"];
41
50
 
51
+ /** Operators that match a substring, wrapped in SQL wildcards (`%value%`). */
52
+ const containsOperations = ["ilike", "not-ilike"];
53
+
54
+ /** Strip the surrounding `%` wildcards a contains-filter adds, for display. */
55
+ function unwrapContains(value: unknown): string {
56
+ if (typeof value !== "string") return "";
57
+ return value.replace(/^%/, "").replace(/%$/, "");
58
+ }
59
+
42
60
  export function StringNumberFilterField({
43
61
  name,
44
62
  value,
@@ -46,13 +64,20 @@ export function StringNumberFilterField({
46
64
  type,
47
65
  isArray,
48
66
  enumValues,
49
- title
67
+ title,
68
+ operators
50
69
  }: StringNumberFilterFieldProps) {
51
70
  const { t } = useTranslation();
52
71
 
53
- const possibleOperations: (keyof typeof operationLabels)[] = isArray
72
+ let possibleOperations: (keyof typeof operationLabels)[] = isArray
54
73
  ? ["array-contains"]
55
- : ["==", "!=", ">", "<", ">=", "<=", "is-null"];
74
+ : ["==", "!=", ">", "<", ">=", "<=", "is-null", "is-not-null"];
75
+
76
+ // Case-insensitive substring matching is only meaningful for free-text
77
+ // string columns (not numbers, arrays, or enums).
78
+ if (!isArray && !enumValues && type === "string") {
79
+ possibleOperations.push("ilike", "not-ilike");
80
+ }
56
81
 
57
82
  if (enumValues) {
58
83
  if (isArray) {
@@ -62,18 +87,47 @@ export function StringNumberFilterField({
62
87
  }
63
88
  }
64
89
 
90
+ if (operators) {
91
+ possibleOperations = possibleOperations.filter(op => (operators as readonly string[]).includes(op));
92
+ }
93
+
65
94
  const [fieldOperation, fieldValue] = value || [possibleOperations[0], undefined];
66
- const [operation, setOperation] = useState<VirtualTableWhereFilterOp | "is-null">(fieldOperation === "==" && fieldValue === null ? "is-null" : fieldOperation);
67
- const [internalValue, setInternalValue] = useState<string | number | string[] | number[] | null | undefined>(fieldValue as string | number | string[] | number[] | null | undefined);
95
+ // Read back both the canonical null operators and the legacy `["==", null]` /
96
+ // `["!=", null]` form saved by older filter presets.
97
+ const [operation, setOperation] = useState<VirtualTableWhereFilterOp>(
98
+ fieldOperation === "==" && fieldValue === null ? "is-null"
99
+ : fieldOperation === "!=" && fieldValue === null ? "is-not-null"
100
+ : fieldOperation
101
+ );
102
+ const [internalValue, setInternalValue] = useState<string | number | string[] | number[] | null | undefined>(
103
+ containsOperations.includes(fieldOperation) ? unwrapContains(fieldValue) : (fieldValue as string | number | string[] | number[] | null | undefined)
104
+ );
105
+
106
+ const isNullOperation = operation === "is-null" || operation === "is-not-null";
68
107
 
69
- const isNullOperation = operation === "is-null";
108
+ // All renderable operators were filtered out (engine/property narrowing).
109
+ if (possibleOperations.length === 0) return null;
70
110
 
71
- function updateFilter(op: VirtualTableWhereFilterOp | "is-null", val: string | number | string[] | number[] | null | undefined) {
72
- // Handle "is null" operation
73
- if (op === "is-null") {
111
+ function updateFilter(op: VirtualTableWhereFilterOp, val: string | number | string[] | number[] | null | undefined) {
112
+ // Null-testing operators ignore their value.
113
+ if (op === "is-null" || op === "is-not-null") {
74
114
  setOperation(op);
75
115
  setInternalValue(null);
76
- setValue(["==", null]);
116
+ setValue([op, null]);
117
+ return;
118
+ }
119
+
120
+ // Substring matching: keep the raw text in the field, emit it wrapped
121
+ // in SQL wildcards so the backend runs `column ILIKE '%value%'`.
122
+ if (op === "ilike" || op === "not-ilike") {
123
+ const raw = typeof val === "string" ? val : "";
124
+ setOperation(op);
125
+ setInternalValue(raw);
126
+ if (raw.length > 0) {
127
+ setValue([op, `%${raw}%`]);
128
+ } else {
129
+ setValue(undefined);
130
+ }
77
131
  return;
78
132
  }
79
133
 
@@ -121,7 +175,7 @@ export function StringNumberFilterField({
121
175
  fullWidth={true}
122
176
  position={"item-aligned"}
123
177
  onValueChange={(value) => {
124
- updateFilter(value as VirtualTableWhereFilterOp | "is-null", internalValue);
178
+ updateFilter(value as VirtualTableWhereFilterOp, internalValue);
125
179
  }}
126
180
  renderValue={(op) => operationLabels[op as keyof typeof operationLabels]}>
127
181
  {possibleOperations.map((op) => (