@rebasepro/cms 0.17.3 → 0.18.1

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 (449) hide show
  1. package/README.md +4 -0
  2. package/dist/{CollectionEditorDialog-B-akreOU.js → CollectionEditorDialog-BeX4b92r.js} +13 -7
  3. package/dist/{CollectionEditorDialog-B-akreOU.js.map → CollectionEditorDialog-BeX4b92r.js.map} +1 -1
  4. package/dist/{PropertyEditView-CiY84wkR.js → PropertyEditView-C7thfj4L.js} +3 -3
  5. package/dist/{PropertyEditView-CiY84wkR.js.map → PropertyEditView-C7thfj4L.js.map} +1 -1
  6. package/dist/{RouterCollectionsStudioView-DkAWda4N.js → RouterCollectionsStudioView-BtjzvB6E.js} +4 -4
  7. package/dist/{RouterCollectionsStudioView-DkAWda4N.js.map → RouterCollectionsStudioView-BtjzvB6E.js.map} +1 -1
  8. package/dist/{SchemaChangeDialog-DceT8QFX.js → SchemaChangeDialog-CkqK6KOC.js} +4 -2
  9. package/dist/{SchemaChangeDialog-DceT8QFX.js.map → SchemaChangeDialog-CkqK6KOC.js.map} +1 -1
  10. package/dist/collection_editor/api/generateCollectionApi.d.ts +1 -2
  11. package/dist/collection_editor_ui.d.ts +2 -0
  12. package/dist/collection_editor_ui.js +6 -5
  13. package/dist/collection_editor_ui.js.map +1 -1
  14. package/dist/components/DeleteEntityDialog.d.ts +2 -3
  15. package/dist/components/RebaseLayout.d.ts +11 -4
  16. package/dist/components/field_configs.d.ts +1 -1
  17. package/dist/editor/sanitize-html.d.ts +15 -0
  18. package/dist/editor.js +195 -10
  19. package/dist/editor.js.map +1 -1
  20. package/dist/{export-Ben8E355.js → export--arni_VY.js} +2 -2
  21. package/dist/{export-Ben8E355.js.map → export--arni_VY.js.map} +1 -1
  22. package/dist/form/components/LabelWithIcon.d.ts +10 -0
  23. package/dist/{history-DIEVd26f.js → history-C2TpoQwi.js} +2 -2
  24. package/dist/{history-DIEVd26f.js.map → history-C2TpoQwi.js.map} +1 -1
  25. package/dist/hooks/navigation/useBuildNavigationStateController.d.ts +1 -1
  26. package/dist/hooks/navigation/useResolvedViews.d.ts +1 -1
  27. package/dist/hooks/navigation/useTopLevelNavigation.d.ts +1 -1
  28. package/dist/{import-D25x7ko-.js → import-DTkXNoBg.js} +2 -2
  29. package/dist/{import-D25x7ko-.js.map → import-DTkXNoBg.js.map} +1 -1
  30. package/dist/index.js +78 -33
  31. package/dist/index.js.map +1 -1
  32. package/dist/util/propertyConfigMapper.d.ts +1 -1
  33. package/dist/util-CfLFggP7.js +57 -0
  34. package/dist/util-CfLFggP7.js.map +1 -0
  35. package/dist/{util-DVqnqlLn.js → util-DE1WQW6h.js} +134 -112
  36. package/dist/util-DE1WQW6h.js.map +1 -0
  37. package/package.json +42 -34
  38. package/dist/util-DVqnqlLn.js.map +0 -1
  39. package/src/collection_editor/CollectionEditorDialogsContext.tsx +0 -25
  40. package/src/collection_editor/ConfigControllerProvider.tsx +0 -395
  41. package/src/collection_editor/_cms_internals.ts +0 -41
  42. package/src/collection_editor/api/generateCollectionApi.ts +0 -126
  43. package/src/collection_editor/api/index.ts +0 -1
  44. package/src/collection_editor/extensibility_types.ts +0 -168
  45. package/src/collection_editor/index.ts +0 -108
  46. package/src/collection_editor/liveSchemaClient.ts +0 -285
  47. package/src/collection_editor/relation_kinds.ts +0 -44
  48. package/src/collection_editor/serializable_types.ts +0 -535
  49. package/src/collection_editor/serializable_utils.ts +0 -729
  50. package/src/collection_editor/types/collection_editor_controller.tsx +0 -62
  51. package/src/collection_editor/types/collection_inference.ts +0 -18
  52. package/src/collection_editor/types/config_controller.tsx +0 -121
  53. package/src/collection_editor/ui/AddKanbanColumnAction.tsx +0 -199
  54. package/src/collection_editor/ui/CollectionViewHeaderAction.tsx +0 -51
  55. package/src/collection_editor/ui/EditorCollectionAction.tsx +0 -54
  56. package/src/collection_editor/ui/EditorCollectionActionStart.tsx +0 -90
  57. package/src/collection_editor/ui/EditorEntityAction.tsx +0 -50
  58. package/src/collection_editor/ui/HomePageEditorCollectionAction.tsx +0 -114
  59. package/src/collection_editor/ui/KanbanSetupAction.tsx +0 -43
  60. package/src/collection_editor/ui/MissingReferenceWidget.tsx +0 -35
  61. package/src/collection_editor/ui/NewCollectionButton.tsx +0 -27
  62. package/src/collection_editor/ui/NewCollectionCard.tsx +0 -48
  63. package/src/collection_editor/ui/PropertyAddColumnComponent.tsx +0 -49
  64. package/src/collection_editor/ui/collection_editor/AICollectionGeneratorPopover.tsx +0 -260
  65. package/src/collection_editor/ui/collection_editor/AIModifiedPathsContext.tsx +0 -90
  66. package/src/collection_editor/ui/collection_editor/CollectionDetailsForm.tsx +0 -388
  67. package/src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx +0 -1098
  68. package/src/collection_editor/ui/collection_editor/CollectionEditorWelcomeView.tsx +0 -301
  69. package/src/collection_editor/ui/collection_editor/CollectionJsonImportDialog.tsx +0 -172
  70. package/src/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.tsx +0 -620
  71. package/src/collection_editor/ui/collection_editor/CollectionRLSTab.tsx +0 -530
  72. package/src/collection_editor/ui/collection_editor/CollectionRelationsTab.tsx +0 -462
  73. package/src/collection_editor/ui/collection_editor/CollectionStudioView.tsx +0 -104
  74. package/src/collection_editor/ui/collection_editor/CollectionYupValidation.tsx +0 -9
  75. package/src/collection_editor/ui/collection_editor/CollectionsStudioView.tsx +0 -199
  76. package/src/collection_editor/ui/collection_editor/DisplaySettingsForm.tsx +0 -315
  77. package/src/collection_editor/ui/collection_editor/EntityActionsEditTab.tsx +0 -164
  78. package/src/collection_editor/ui/collection_editor/EntityActionsSelectDialog.tsx +0 -40
  79. package/src/collection_editor/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +0 -39
  80. package/src/collection_editor/ui/collection_editor/EnumForm.tsx +0 -373
  81. package/src/collection_editor/ui/collection_editor/GeneralSettingsForm.tsx +0 -288
  82. package/src/collection_editor/ui/collection_editor/GetCodeDialog.tsx +0 -141
  83. package/src/collection_editor/ui/collection_editor/KanbanConfigSection.tsx +0 -194
  84. package/src/collection_editor/ui/collection_editor/LayoutModeSwitch.tsx +0 -53
  85. package/src/collection_editor/ui/collection_editor/PropertyEditView.tsx +0 -980
  86. package/src/collection_editor/ui/collection_editor/PropertyFieldPreview.tsx +0 -164
  87. package/src/collection_editor/ui/collection_editor/PropertyTree.tsx +0 -364
  88. package/src/collection_editor/ui/collection_editor/RouterCollectionStudioView.tsx +0 -44
  89. package/src/collection_editor/ui/collection_editor/RouterCollectionsStudioView.tsx +0 -41
  90. package/src/collection_editor/ui/collection_editor/SchemaChangeDialog.tsx +0 -470
  91. package/src/collection_editor/ui/collection_editor/SubcollectionsEditTab.tsx +0 -256
  92. package/src/collection_editor/ui/collection_editor/SwitchControl.tsx +0 -39
  93. package/src/collection_editor/ui/collection_editor/ViewModeSwitch.tsx +0 -68
  94. package/src/collection_editor/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +0 -67
  95. package/src/collection_editor/ui/collection_editor/import/CollectionEditorImportMapping.tsx +0 -296
  96. package/src/collection_editor/ui/collection_editor/import/clean_import_data.ts +0 -57
  97. package/src/collection_editor/ui/collection_editor/properties/BlockPropertyField.tsx +0 -147
  98. package/src/collection_editor/ui/collection_editor/properties/BooleanPropertyField.tsx +0 -41
  99. package/src/collection_editor/ui/collection_editor/properties/CommonPropertyFields.tsx +0 -113
  100. package/src/collection_editor/ui/collection_editor/properties/DateTimePropertyField.tsx +0 -250
  101. package/src/collection_editor/ui/collection_editor/properties/EnumPropertyField.tsx +0 -126
  102. package/src/collection_editor/ui/collection_editor/properties/KeyValuePropertyField.tsx +0 -20
  103. package/src/collection_editor/ui/collection_editor/properties/MapPropertyField.tsx +0 -153
  104. package/src/collection_editor/ui/collection_editor/properties/MarkdownPropertyField.tsx +0 -217
  105. package/src/collection_editor/ui/collection_editor/properties/NumberPropertyField.tsx +0 -117
  106. package/src/collection_editor/ui/collection_editor/properties/ReferencePropertyField.tsx +0 -129
  107. package/src/collection_editor/ui/collection_editor/properties/RelationPropertyField.tsx +0 -335
  108. package/src/collection_editor/ui/collection_editor/properties/RepeatPropertyField.tsx +0 -107
  109. package/src/collection_editor/ui/collection_editor/properties/StoragePropertyField.tsx +0 -403
  110. package/src/collection_editor/ui/collection_editor/properties/StringPropertyField.tsx +0 -148
  111. package/src/collection_editor/ui/collection_editor/properties/UrlPropertyField.tsx +0 -91
  112. package/src/collection_editor/ui/collection_editor/properties/VectorPropertyField.tsx +0 -34
  113. package/src/collection_editor/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.tsx +0 -49
  114. package/src/collection_editor/ui/collection_editor/properties/conditions/ConditionsEditor.tsx +0 -925
  115. package/src/collection_editor/ui/collection_editor/properties/conditions/ConditionsPanel.tsx +0 -28
  116. package/src/collection_editor/ui/collection_editor/properties/conditions/EnumConditionsEditor.tsx +0 -626
  117. package/src/collection_editor/ui/collection_editor/properties/conditions/index.ts +0 -6
  118. package/src/collection_editor/ui/collection_editor/properties/conditions/property_paths.ts +0 -93
  119. package/src/collection_editor/ui/collection_editor/properties/validation/ArrayPropertyValidation.tsx +0 -52
  120. package/src/collection_editor/ui/collection_editor/properties/validation/GeneralPropertyValidation.tsx +0 -63
  121. package/src/collection_editor/ui/collection_editor/properties/validation/NumberPropertyValidation.tsx +0 -114
  122. package/src/collection_editor/ui/collection_editor/properties/validation/StringPropertyValidation.tsx +0 -154
  123. package/src/collection_editor/ui/collection_editor/properties/validation/ValidationPanel.tsx +0 -28
  124. package/src/collection_editor/ui/collection_editor/templates/blog_template.ts +0 -112
  125. package/src/collection_editor/ui/collection_editor/templates/pages_template.ts +0 -183
  126. package/src/collection_editor/ui/collection_editor/templates/products_template.ts +0 -88
  127. package/src/collection_editor/ui/collection_editor/templates/users_template.ts +0 -42
  128. package/src/collection_editor/ui/collection_editor/util.ts +0 -28
  129. package/src/collection_editor/ui/collection_editor/utils/strings.ts +0 -1
  130. package/src/collection_editor/ui/collection_editor/utils/supported_fields.tsx +0 -39
  131. package/src/collection_editor/ui/collection_editor/utils/update_property_for_widget.ts +0 -276
  132. package/src/collection_editor/useCollectionEditorController.tsx +0 -9
  133. package/src/collection_editor/useCollectionsConfigController.tsx +0 -9
  134. package/src/collection_editor/useJsonCollectionsConfigController.tsx +0 -297
  135. package/src/collection_editor/useLiveSchemaEditing.tsx +0 -315
  136. package/src/collection_editor/useLocalCollectionsConfigController.tsx +0 -341
  137. package/src/collection_editor/useSafeSnackbarController.ts +0 -9
  138. package/src/collection_editor/validateCollectionJson.ts +0 -440
  139. package/src/collection_editor_ui.ts +0 -21
  140. package/src/components/AdditionalFieldValue.tsx +0 -68
  141. package/src/components/AdminModeSyncer.tsx +0 -56
  142. package/src/components/ArrayContainer.tsx +0 -542
  143. package/src/components/ClearFilterSortButton.tsx +0 -56
  144. package/src/components/CollectionEditorDialogs.tsx +0 -69
  145. package/src/components/CollectionPanel.tsx +0 -179
  146. package/src/components/CollectionTableBinding/CollectionRowActions.tsx +0 -244
  147. package/src/components/CollectionTableBinding/CollectionTableBinding.tsx +0 -394
  148. package/src/components/CollectionTableBinding/CollectionTableBindingProps.tsx +0 -172
  149. package/src/components/CollectionTableBinding/PropertyTableCell.tsx +0 -350
  150. package/src/components/CollectionTableBinding/column_utils.tsx +0 -155
  151. package/src/components/CollectionTableBinding/fields/TableMultipleRelationField.tsx +0 -131
  152. package/src/components/CollectionTableBinding/fields/TableReferenceField.tsx +0 -193
  153. package/src/components/CollectionTableBinding/fields/TableRelationField.tsx +0 -192
  154. package/src/components/CollectionTableBinding/fields/TableRelationSelectorField.tsx +0 -42
  155. package/src/components/CollectionTableBinding/fields/TableStorageUpload.tsx +0 -324
  156. package/src/components/CollectionTableBinding/fields/VirtualTableSelect.tsx +0 -132
  157. package/src/components/CollectionTableBinding/fields/VirtualTableUserSelect.tsx +0 -41
  158. package/src/components/CollectionTableBinding/index.tsx +0 -14
  159. package/src/components/CollectionTableBinding/internal/CollectionTableToolbar.tsx +0 -96
  160. package/src/components/CollectionTableBinding/internal/EntityTableCell.tsx +0 -309
  161. package/src/components/CollectionTableBinding/internal/EntityTableCellActions.tsx +0 -80
  162. package/src/components/CollectionTableBinding/internal/common.tsx +0 -74
  163. package/src/components/CollectionTableBinding/internal/popup_field/PopupFormField.tsx +0 -422
  164. package/src/components/CollectionTableBinding/internal/popup_field/useDraggable.tsx +0 -99
  165. package/src/components/CollectionTableBinding/internal/popup_field/useWindowSize.tsx +0 -22
  166. package/src/components/CollectionTableBinding/table_bindings.tsx +0 -350
  167. package/src/components/CollectionViewBinding/BoardCardBinding.tsx +0 -263
  168. package/src/components/CollectionViewBinding/CollectionBoardViewBinding.tsx +0 -662
  169. package/src/components/CollectionViewBinding/CollectionCardViewBinding.tsx +0 -159
  170. package/src/components/CollectionViewBinding/CollectionListViewBinding.tsx +0 -1430
  171. package/src/components/CollectionViewBinding/CollectionViewActions.tsx +0 -227
  172. package/src/components/CollectionViewBinding/CollectionViewBinding.tsx +0 -1603
  173. package/src/components/CollectionViewBinding/CollectionViewStartActions.tsx +0 -240
  174. package/src/components/CollectionViewBinding/EntityCardBinding.tsx +0 -239
  175. package/src/components/CollectionViewBinding/FilterPresetsButton.tsx +0 -298
  176. package/src/components/CollectionViewBinding/FiltersDialog.tsx +0 -218
  177. package/src/components/CollectionViewBinding/SearchExplanation.tsx +0 -106
  178. package/src/components/CollectionViewBinding/SearchHighlight.tsx +0 -311
  179. package/src/components/CollectionViewBinding/SlotValue.tsx +0 -156
  180. package/src/components/CollectionViewBinding/SortButton.tsx +0 -354
  181. package/src/components/CollectionViewBinding/SplitListCloseButton.tsx +0 -49
  182. package/src/components/CollectionViewBinding/SplitListShowButton.tsx +0 -28
  183. package/src/components/CollectionViewBinding/SplitListView.tsx +0 -488
  184. package/src/components/CollectionViewBinding/SplitViewContext.tsx +0 -34
  185. package/src/components/CollectionViewBinding/ViewModeToggle.tsx +0 -250
  186. package/src/components/CollectionViewBinding/hooks/useCollectionInlineEditor.ts +0 -81
  187. package/src/components/CollectionViewBinding/hooks/useKanbanDragAndDrop.ts +0 -181
  188. package/src/components/CollectionViewBinding/useBoardDataController.tsx +0 -802
  189. package/src/components/CollectionViewBinding/usePreviewSlots.ts +0 -703
  190. package/src/components/CollectionViewBinding/useSelectionController.tsx +0 -40
  191. package/src/components/CollectionViewBinding/utils.ts +0 -22
  192. package/src/components/DefaultAppBar.tsx +0 -264
  193. package/src/components/DefaultDrawer.tsx +0 -593
  194. package/src/components/DeleteEntityDialog.tsx +0 -205
  195. package/src/components/DetailViewBinding.tsx +0 -731
  196. package/src/components/DrawerNavigationGroup.tsx +0 -141
  197. package/src/components/DrawerNavigationItem.tsx +0 -115
  198. package/src/components/EditFormActions.tsx +0 -303
  199. package/src/components/EditViewBinding.tsx +0 -1069
  200. package/src/components/EntityDisplayHeader.tsx +0 -170
  201. package/src/components/EntityIdentityBar.tsx +0 -428
  202. package/src/components/EntityInspector.tsx +0 -156
  203. package/src/components/EntityPreviewBinding.tsx +0 -432
  204. package/src/components/EntityPreviewNesting.tsx +0 -50
  205. package/src/components/EntityViewBinding.tsx +0 -374
  206. package/src/components/FieldCaption.tsx +0 -14
  207. package/src/components/HomePage/ContentHomePage.tsx +0 -586
  208. package/src/components/HomePage/FavouritesView.tsx +0 -60
  209. package/src/components/HomePage/HomePageDnD.tsx +0 -704
  210. package/src/components/HomePage/NavigationCard.tsx +0 -81
  211. package/src/components/HomePage/NavigationCardBinding.tsx +0 -107
  212. package/src/components/HomePage/NavigationGroup.tsx +0 -156
  213. package/src/components/HomePage/RenameGroupDialog.tsx +0 -123
  214. package/src/components/HomePage/SmallNavigationCard.tsx +0 -41
  215. package/src/components/HomePage/index.tsx +0 -5
  216. package/src/components/InlineEntityPreview.tsx +0 -149
  217. package/src/components/JsonPreviewBinding.tsx +0 -66
  218. package/src/components/PropertyCollectionView.tsx +0 -336
  219. package/src/components/PropertyConfigBadge.tsx +0 -28
  220. package/src/components/PropertyIdCopyTooltip.tsx +0 -47
  221. package/src/components/RebaseAuthGate.tsx +0 -44
  222. package/src/components/RebaseCMS.tsx +0 -30
  223. package/src/components/RebaseLayout.tsx +0 -80
  224. package/src/components/RebaseNavigation.tsx +0 -369
  225. package/src/components/RebaseRouteDefs.tsx +0 -127
  226. package/src/components/RebaseShell.tsx +0 -83
  227. package/src/components/ReferenceTable/SelectionTableBinding.tsx +0 -389
  228. package/src/components/ReferenceWidget.tsx +0 -156
  229. package/src/components/RelationSelector.tsx +0 -926
  230. package/src/components/SearchIconsView.tsx +0 -78
  231. package/src/components/SelectableTable/SelectableTable.tsx +0 -309
  232. package/src/components/SelectableTable/SelectableTableContext.tsx +0 -7
  233. package/src/components/SelectableTable/SelectionStore.ts +0 -43
  234. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +0 -59
  235. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +0 -146
  236. package/src/components/SelectableTable/filters/FilterFieldBinding.tsx +0 -190
  237. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +0 -250
  238. package/src/components/SelectableTable/filters/RelationFilterField.tsx +0 -238
  239. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +0 -282
  240. package/src/components/SelectableTable/filters/null_filter.ts +0 -63
  241. package/src/components/SideDialogs.tsx +0 -238
  242. package/src/components/SidePanelBinding.tsx +0 -361
  243. package/src/components/SidePanelProvider.tsx +0 -80
  244. package/src/components/UserSelector.tsx +0 -513
  245. package/src/components/admin/CreationResultDialog.tsx +0 -138
  246. package/src/components/admin/index.ts +0 -1
  247. package/src/components/app/AppBar.tsx +0 -17
  248. package/src/components/app/Drawer.tsx +0 -38
  249. package/src/components/app/Scaffold.tsx +0 -366
  250. package/src/components/app/index.ts +0 -4
  251. package/src/components/app/useApp.tsx +0 -36
  252. package/src/components/common/default_entity_actions.tsx +0 -440
  253. package/src/components/common/index.ts +0 -1
  254. package/src/components/field_configs.tsx +0 -506
  255. package/src/components/history/EntityHistoryEntry.tsx +0 -203
  256. package/src/components/history/EntityHistoryView.tsx +0 -206
  257. package/src/components/history/LastEditedByFormAction.tsx +0 -24
  258. package/src/components/history/LastEditedByIndicator.tsx +0 -95
  259. package/src/components/history/UserChip.tsx +0 -15
  260. package/src/components/history/index.tsx +0 -5
  261. package/src/components/index.ts +0 -63
  262. package/src/contexts/BreacrumbsContext.tsx +0 -45
  263. package/src/contexts/SideDialogsControllerContext.tsx +0 -5
  264. package/src/contexts/SidePanelControllerContext.tsx +0 -5
  265. package/src/data_export/export/BasicExportAction.tsx +0 -142
  266. package/src/data_export/export/ExportCollectionAction.tsx +0 -321
  267. package/src/data_export/export/export.ts +0 -295
  268. package/src/data_export/export/fetch_export_data.ts +0 -90
  269. package/src/data_export/export/index.ts +0 -4
  270. package/src/data_export/index.ts +0 -1
  271. package/src/data_import/components/DataNewPropertiesMapping.tsx +0 -261
  272. package/src/data_import/components/ImportFileUpload.tsx +0 -42
  273. package/src/data_import/components/ImportNewPropertyFieldPreview.tsx +0 -58
  274. package/src/data_import/components/ImportSaveInProgress.tsx +0 -121
  275. package/src/data_import/components/index.ts +0 -4
  276. package/src/data_import/hooks/index.ts +0 -1
  277. package/src/data_import/hooks/useImportConfig.tsx +0 -34
  278. package/src/data_import/import/ImportCollectionAction.tsx +0 -461
  279. package/src/data_import/import/index.ts +0 -1
  280. package/src/data_import/index.ts +0 -5
  281. package/src/data_import/types/column_mapping.ts +0 -32
  282. package/src/data_import/types/index.ts +0 -1
  283. package/src/data_import/utils/csv.ts +0 -153
  284. package/src/data_import/utils/data.ts +0 -181
  285. package/src/data_import/utils/file_headers.ts +0 -14
  286. package/src/data_import/utils/file_to_json.ts +0 -149
  287. package/src/data_import/utils/get_import_inference_type.ts +0 -33
  288. package/src/data_import/utils/get_properties_mapping.ts +0 -67
  289. package/src/data_import/utils/index.ts +0 -5
  290. package/src/data_import/utils/save_entities.ts +0 -138
  291. package/src/data_import/utils/transforms.ts +0 -70
  292. package/src/editor/components/SlashCommandMenu.tsx +0 -532
  293. package/src/editor/components/editor-bubble-item.tsx +0 -32
  294. package/src/editor/components/editor-bubble.tsx +0 -143
  295. package/src/editor/components/image-bubble.tsx +0 -183
  296. package/src/editor/components/index.ts +0 -14
  297. package/src/editor/components/table-bubble.tsx +0 -233
  298. package/src/editor/editor.tsx +0 -529
  299. package/src/editor/extensions/HighlightDecorationExtension.ts +0 -115
  300. package/src/editor/extensions/Image.ts +0 -159
  301. package/src/editor/extensions/TextLoadingDecorationExtension.tsx +0 -107
  302. package/src/editor/extensions/clipboard.ts +0 -72
  303. package/src/editor/extensions/custom-keymap.ts +0 -25
  304. package/src/editor/extensions/drag-and-drop.tsx +0 -508
  305. package/src/editor/hooks/useProseMirror.ts +0 -126
  306. package/src/editor/hooks/useProseMirrorContext.ts +0 -15
  307. package/src/editor/index.ts +0 -2
  308. package/src/editor/markdown-it-plugins.d.ts +0 -24
  309. package/src/editor/markdown.ts +0 -204
  310. package/src/editor/nodeViews/ImageComponent.tsx +0 -20
  311. package/src/editor/nodeViews/ReactNodeView.tsx +0 -89
  312. package/src/editor/nodeViews/TaskItemComponent.tsx +0 -30
  313. package/src/editor/nodeViews/index.ts +0 -35
  314. package/src/editor/plugins/index.ts +0 -58
  315. package/src/editor/plugins/inputrules.ts +0 -82
  316. package/src/editor/plugins/placeholderPlugin.ts +0 -55
  317. package/src/editor/plugins/slashCommandPlugin.ts +0 -65
  318. package/src/editor/schema.ts +0 -339
  319. package/src/editor/selectors/ai-selector.tsx +0 -110
  320. package/src/editor/selectors/color-selector.tsx +0 -199
  321. package/src/editor/selectors/link-selector.tsx +0 -122
  322. package/src/editor/selectors/node-selector.tsx +0 -159
  323. package/src/editor/selectors/text-buttons.tsx +0 -79
  324. package/src/editor/types.ts +0 -6
  325. package/src/editor/useProseMirror.ts +0 -125
  326. package/src/editor/utils/prosemirror-utils.ts +0 -113
  327. package/src/editor/utils/remove_classes.ts +0 -18
  328. package/src/editor/utils/useDebouncedCallback.ts +0 -25
  329. package/src/form/EntityForm.tsx +0 -761
  330. package/src/form/EntityFormActions.tsx +0 -160
  331. package/src/form/EntityFormBinding.tsx +0 -342
  332. package/src/form/PropertyFieldBinding.tsx +0 -348
  333. package/src/form/components/ErrorFocus.tsx +0 -44
  334. package/src/form/components/FieldBlock.tsx +0 -189
  335. package/src/form/components/FieldHelperText.tsx +0 -84
  336. package/src/form/components/FormRail.tsx +0 -153
  337. package/src/form/components/FormSections.tsx +0 -145
  338. package/src/form/components/LabelWithIcon.tsx +0 -43
  339. package/src/form/components/LabelWithIconAndTooltip.tsx +0 -28
  340. package/src/form/components/LocalChangesMenu.tsx +0 -147
  341. package/src/form/components/StorageItemPreview.tsx +0 -81
  342. package/src/form/components/StorageUploadProgress.tsx +0 -118
  343. package/src/form/components/index.tsx +0 -6
  344. package/src/form/components/useRailVisible.tsx +0 -47
  345. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +0 -109
  346. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +0 -172
  347. package/src/form/field_bindings/BinaryFieldBinding.tsx +0 -177
  348. package/src/form/field_bindings/BlockFieldBinding.tsx +0 -282
  349. package/src/form/field_bindings/DateTimeFieldBinding.tsx +0 -78
  350. package/src/form/field_bindings/GeopointFieldBinding.tsx +0 -200
  351. package/src/form/field_bindings/KeyValueFieldBinding.tsx +0 -574
  352. package/src/form/field_bindings/MapFieldBinding.tsx +0 -120
  353. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +0 -259
  354. package/src/form/field_bindings/MultiSelectFieldBinding.tsx +0 -130
  355. package/src/form/field_bindings/MultipleRelationFieldBinding.tsx +0 -168
  356. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +0 -94
  357. package/src/form/field_bindings/ReferenceFieldBinding.tsx +0 -146
  358. package/src/form/field_bindings/RelationFieldBinding.tsx +0 -202
  359. package/src/form/field_bindings/RepeatFieldBinding.tsx +0 -143
  360. package/src/form/field_bindings/SelectFieldBinding.tsx +0 -111
  361. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +0 -521
  362. package/src/form/field_bindings/SwitchFieldBinding.tsx +0 -70
  363. package/src/form/field_bindings/TextFieldBinding.tsx +0 -189
  364. package/src/form/field_bindings/UserSelectFieldBinding.tsx +0 -71
  365. package/src/form/field_bindings/VectorFieldBinding.tsx +0 -209
  366. package/src/form/form_utils.ts +0 -243
  367. package/src/form/index.tsx +0 -36
  368. package/src/form/useClearRestoreValue.tsx +0 -36
  369. package/src/form/useUndoableDiscard.ts +0 -39
  370. package/src/form/validation.ts +0 -583
  371. package/src/hooks/index.ts +0 -16
  372. package/src/hooks/navigation/contexts/CollectionRegistryContext.tsx +0 -22
  373. package/src/hooks/navigation/contexts/NavigationStateContext.tsx +0 -16
  374. package/src/hooks/navigation/contexts/UrlContext.tsx +0 -24
  375. package/src/hooks/navigation/contexts/index.ts +0 -14
  376. package/src/hooks/navigation/useAsyncResolver.ts +0 -100
  377. package/src/hooks/navigation/useBuildCollectionRegistryController.tsx +0 -218
  378. package/src/hooks/navigation/useBuildNavigationStateController.tsx +0 -134
  379. package/src/hooks/navigation/useBuildUrlController.tsx +0 -66
  380. package/src/hooks/navigation/useNavigationResolution.ts +0 -271
  381. package/src/hooks/navigation/useResolvedCollections.ts +0 -102
  382. package/src/hooks/navigation/useResolvedViews.tsx +0 -139
  383. package/src/hooks/navigation/useTopLevelNavigation.ts +0 -273
  384. package/src/hooks/navigation/utils.ts +0 -200
  385. package/src/hooks/useAdminContext.tsx +0 -83
  386. package/src/hooks/useBreadcrumbsController.tsx +0 -17
  387. package/src/hooks/useBuildSideDialogsController.tsx +0 -145
  388. package/src/hooks/useBuildSidePanel.tsx +0 -315
  389. package/src/hooks/useChildViewSource.ts +0 -46
  390. package/src/hooks/useEntityDisplay.tsx +0 -262
  391. package/src/hooks/useEntityDisplayTitle.tsx +0 -49
  392. package/src/hooks/useHistory.ts +0 -178
  393. package/src/hooks/useRecordActions.tsx +0 -69
  394. package/src/hooks/useResolvedNavigationFrom.tsx +0 -167
  395. package/src/hooks/useResolvedUsers.ts +0 -148
  396. package/src/hooks/useSelectionDialog.tsx +0 -58
  397. package/src/hooks/useSideDialogsController.tsx +0 -25
  398. package/src/hooks/useSidePanel.tsx +0 -13
  399. package/src/index.ts +0 -124
  400. package/src/preview/PropertyPreview.tsx +0 -331
  401. package/src/preview/compact_text.ts +0 -68
  402. package/src/preview/components/ArrayEnumPreview.tsx +0 -39
  403. package/src/preview/components/BooleanPreview.tsx +0 -28
  404. package/src/preview/components/DatePreview.tsx +0 -106
  405. package/src/preview/components/EmptyValue.tsx +0 -10
  406. package/src/preview/components/EnumValuesChip.tsx +0 -39
  407. package/src/preview/components/ImagePreview.tsx +0 -144
  408. package/src/preview/components/InlineEntityListPreview.tsx +0 -42
  409. package/src/preview/components/ReferencePreview.tsx +0 -235
  410. package/src/preview/components/RelationPreview.tsx +0 -271
  411. package/src/preview/components/StorageThumbnail.tsx +0 -147
  412. package/src/preview/components/UrlComponentPreview.tsx +0 -116
  413. package/src/preview/components/UserPreview.tsx +0 -30
  414. package/src/preview/components/date_fns_locales.ts +0 -125
  415. package/src/preview/index.ts +0 -26
  416. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +0 -73
  417. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +0 -67
  418. package/src/preview/property_previews/ArrayOfRelationsPreview.tsx +0 -77
  419. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +0 -49
  420. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +0 -70
  421. package/src/preview/property_previews/ArrayOneOfPreview.tsx +0 -79
  422. package/src/preview/property_previews/ArrayPropertyEnumPreview.tsx +0 -35
  423. package/src/preview/property_previews/ArrayPropertyPreview.tsx +0 -79
  424. package/src/preview/property_previews/MapPropertyPreview.tsx +0 -198
  425. package/src/preview/property_previews/NumberPropertyPreview.tsx +0 -39
  426. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +0 -276
  427. package/src/preview/property_previews/StringPropertyPreview.tsx +0 -70
  428. package/src/preview/util.ts +0 -39
  429. package/src/routes/CustomViewRoute.tsx +0 -33
  430. package/src/routes/RebaseRoute.tsx +0 -467
  431. package/src/routes/index.ts +0 -2
  432. package/src/types/components/EntityFormActionsProps.tsx +0 -20
  433. package/src/types/components/EntityFormProps.tsx +0 -119
  434. package/src/types/components/PropertyPreviewProps.tsx +0 -85
  435. package/src/types/components/formex.tsx +0 -2
  436. package/src/types/components/index.ts +0 -3
  437. package/src/types/fields.tsx +0 -340
  438. package/src/types/index.ts +0 -4
  439. package/src/util/dataControllerAdapter.ts +0 -88
  440. package/src/util/entity_actions.ts +0 -28
  441. package/src/util/index.ts +0 -5
  442. package/src/util/navigation_utils.ts +0 -89
  443. package/src/util/number_format.ts +0 -46
  444. package/src/util/previews.ts +0 -131
  445. package/src/util/propertyConfigMapper.ts +0 -134
  446. package/src/util/property_utils.tsx +0 -236
  447. package/src/util/resolutions.ts +0 -96
  448. package/src/util/view_constants.ts +0 -33
  449. package/src/util/view_mode.ts +0 -176
@@ -1,802 +0,0 @@
1
-
2
- import { Entity, FilterValues, MAX_LIST_LIMIT } from "@rebasepro/types";
3
- import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
- import { getRelationIncludeParams, useData, useRebaseContext } from "@rebasepro/app";
5
- import type { AdminCollection } from "@rebasepro/cms-types";
6
-
7
- const DEFAULT_PAGE_SIZE = 20;
8
-
9
- /**
10
- * How long a column waits for its subscription's first payload before reading
11
- * once over HTTP instead. Long enough that a healthy socket always wins the
12
- * race, short enough that a dead one does not hold a blank board.
13
- */
14
- const LIVE_FIRST_PAINT_TIMEOUT_MS = 2500;
15
-
16
- /**
17
- * Shallow equality for entity value records.
18
- * Handles primitives and reference equality for nested values.
19
- * Avoids JSON.stringify allocation on every comparison.
20
- */
21
- function shallowEqualValues(
22
- a: Record<string, unknown> | undefined,
23
- b: Record<string, unknown> | undefined
24
- ): boolean {
25
- if (a === b) return true;
26
- if (!a || !b) return false;
27
- const keysA = Object.keys(a);
28
- const keysB = Object.keys(b);
29
- if (keysA.length !== keysB.length) return false;
30
- for (const key of keysA) {
31
- if (a[key] !== b[key]) return false;
32
- }
33
- return true;
34
- }
35
-
36
- /**
37
- * Data state for a single board column
38
- */
39
- export interface BoardColumnData<M extends Record<string, unknown> = Record<string, unknown>> {
40
- /** Entities loaded for this column */
41
- entities: Entity<M>[];
42
- /** Whether the column is currently loading data */
43
- loading: boolean;
44
- /** Whether there are more items to load */
45
- hasMore: boolean;
46
- /** Error if loading failed */
47
- error?: Error;
48
- /** Total count of entities in this column */
49
- totalCount?: number;
50
- }
51
-
52
- /**
53
- * Controller for managing per-column data in a Kanban board
54
- */
55
- export interface BoardDataController<M extends Record<string, unknown> = any, COLUMN extends string = string> {
56
- /** Data state for each column */
57
- columnData: Record<COLUMN, BoardColumnData<M>>;
58
- /** Load more items for a specific column */
59
- loadMoreColumn: (column: COLUMN) => void;
60
- /** Refresh data for a specific column */
61
- refreshColumn: (column: COLUMN) => void;
62
- /** Refresh all columns */
63
- refreshAll: () => void;
64
- /** Update column counts and optionally move item optimistically */
65
- moveItemOptimistically: (itemId: string, sourceColumn: COLUMN, targetColumn: COLUMN, newValues?: Record<string, any>, newIndex?: number) => void;
66
- /** Decrement column counts (for optimistic updates when deleting items) */
67
- decrementColumnCounts: (columnDeltas: Record<COLUMN, number>) => void;
68
- /** Whether any column is loading */
69
- loading: boolean;
70
- /** Any error from any column */
71
- error?: Error;
72
- }
73
-
74
- export interface UseBoardDataControllerProps<M extends Record<string, unknown> = Record<string, unknown>> {
75
- /** Full path to the collection */
76
- fullPath: string;
77
- /** The entity collection configuration */
78
- collection: AdminCollection<M>;
79
- /** Property key used for column assignment */
80
- columnProperty: string;
81
- /** Array of column values (enum values from columnProperty) */
82
- columns: string[];
83
- /** Property key used for ordering within columns */
84
- orderProperty?: string;
85
- /** Number of items to load per page per column */
86
- pageSize?: number;
87
- /** Text search string to filter entities */
88
- searchString?: string;
89
- /** Additional filter values */
90
- filterValues?: FilterValues<string>;
91
- }
92
-
93
- /**
94
- * Hook that manages per-column data loading for the Kanban board.
95
- * Each column gets its own independent query to the data source.
96
- */
97
- export function useBoardDataController<M extends Record<string, unknown> = any, COLUMN extends string = string>({
98
- fullPath,
99
- collection,
100
- columnProperty,
101
- columns,
102
- orderProperty,
103
- pageSize = DEFAULT_PAGE_SIZE,
104
- searchString,
105
- filterValues
106
- }: UseBoardDataControllerProps<M>): BoardDataController<M, COLUMN> {
107
-
108
- const context = useRebaseContext();
109
- const dataClient = useData();
110
- // v4: use fullPath directly instead of resolveIdsFrom
111
- const resolvedPath = fullPath;
112
-
113
- // Stable refs for objects that shouldn't trigger re-subscriptions
114
- const dataClientRef = useRef(dataClient);
115
- const collectionRef = useRef(collection);
116
- const contextRef = useRef(context);
117
- dataClientRef.current = dataClient;
118
- collectionRef.current = collection;
119
- contextRef.current = context;
120
-
121
- // Store filter/order params in refs so they're accessible without causing re-subscriptions
122
- const filterValuesRef = useRef(filterValues);
123
- const columnPropertyRef = useRef(columnProperty);
124
- const orderPropertyRef = useRef(orderProperty);
125
- const searchStringRef = useRef(searchString);
126
- const resolvedPathRef = useRef(resolvedPath);
127
- filterValuesRef.current = filterValues;
128
- columnPropertyRef.current = columnProperty;
129
- orderPropertyRef.current = orderProperty;
130
- searchStringRef.current = searchString;
131
- resolvedPathRef.current = resolvedPath;
132
-
133
- // Track item count per column for pagination
134
- const [columnItemCounts, setColumnItemCounts] = useState<Record<string, number>>(() => {
135
- const initial: Record<string, number> = {};
136
- columns.forEach(col => {
137
- initial[col] = pageSize;
138
- });
139
- return initial;
140
- });
141
-
142
- // Per-column data state
143
- const [columnData, setColumnData] = useState<Record<string, BoardColumnData<M>>>(() => {
144
- const initial: Record<string, BoardColumnData<M>> = {};
145
- columns.forEach(col => {
146
- initial[col] = {
147
- entities: [],
148
- loading: true,
149
- hasMore: true,
150
- error: undefined,
151
- totalCount: undefined
152
- };
153
- });
154
- return initial;
155
- });
156
-
157
- // Track cleanup functions for subscriptions
158
- const unsubscribersRef = useRef<Record<string, () => void>>({});
159
-
160
- // Flag to prevent race conditions during cleanup
161
- const isCleaningUpRef = useRef(false);
162
-
163
- // Track items that are currently in an optimistic state (awaiting DB sync)
164
- const pendingItemsRef = useRef<Record<string, { entity: Entity<M>, expectedValues: Record<string, any> }>>({});
165
-
166
- // Stable keys for dependency comparison
167
- const columnsKey = useMemo(() => [...columns].sort().join(","), [columns]);
168
- const filterKey = useMemo(() => JSON.stringify(filterValues), [filterValues]);
169
-
170
- // Track previous column item counts to detect which column changed
171
- const prevColumnItemCountsRef = useRef<Record<string, number>>(columnItemCounts);
172
-
173
- // Version counter to trigger full re-subscription when params change (not just load-more)
174
- const [subscriptionVersion, setSubscriptionVersion] = useState(0);
175
-
176
- // Trigger full re-subscription when key params change
177
- useEffect(() => {
178
- setSubscriptionVersion(v => v + 1);
179
- }, [columnsKey, resolvedPath, columnProperty, orderProperty, searchString, filterKey, pageSize]);
180
-
181
- // Cleanup subscriptions on unmount
182
- useEffect(() => {
183
- return () => {
184
- isCleaningUpRef.current = true;
185
- Object.values(unsubscribersRef.current).forEach(unsub => unsub?.());
186
- unsubscribersRef.current = {};
187
- };
188
- }, []);
189
-
190
- /**
191
- * Check if a column value is excluded by the active filter on the columnProperty.
192
- * E.g. if the user sets "Status IN (Open, In Progress)", this returns true
193
- * for "Waiting on Customer" since that column should show as empty.
194
- */
195
- const isColumnExcludedByFilter = useCallback((column: string, filterValues?: FilterValues<string>, colProperty?: string): boolean => {
196
- if (!filterValues || !colProperty) return false;
197
- const filterForColumn = filterValues[colProperty as keyof typeof filterValues];
198
- if (!filterForColumn || !Array.isArray(filterForColumn)) return false;
199
-
200
- const [op, val] = filterForColumn as [string, unknown];
201
-
202
- if (op === "==" && typeof val === "string") {
203
- return column !== val;
204
- }
205
- if (op === "!=" && typeof val === "string") {
206
- return column === val;
207
- }
208
- if (op === "in" && Array.isArray(val)) {
209
- return !val.map(String).includes(column);
210
- }
211
- if (op === "not-in" && Array.isArray(val)) {
212
- return val.map(String).includes(column);
213
- }
214
-
215
- return false;
216
- }, []);
217
-
218
- // Helper function to subscribe to a single column - uses refs to avoid dependency issues
219
- const subscribeToColumn = useCallback((column: string, itemCount: number) => {
220
- // Skip if we're in the middle of cleanup
221
- if (isCleaningUpRef.current) return;
222
-
223
- // `itemCount` grows by one page per "load more" click with nothing
224
- // stopping it, and a read above `MAX_LIST_LIMIT` is refused rather than
225
- // trimmed — a column would stop loading with an error instead of
226
- // stopping at the ceiling. Ask for what the platform serves; `hasMore`
227
- // below still compares against the count the board asked for, so the
228
- // column reports itself exhausted exactly where it did before.
229
- const requestedCount = Math.min(itemCount, MAX_LIST_LIMIT);
230
-
231
- const currentDataClient = dataClientRef.current;
232
- const currentCollection = collectionRef.current;
233
- const currentContext = contextRef.current;
234
- const currentFilterValues = filterValuesRef.current;
235
- const currentColumnProperty = columnPropertyRef.current;
236
- const currentOrderProperty = orderPropertyRef.current;
237
- const currentSearchString = searchStringRef.current;
238
- const currentResolvedPath = resolvedPathRef.current;
239
-
240
- // If the column is excluded by the active filter on the column property,
241
- // set it as empty immediately without querying.
242
- const excluded = isColumnExcludedByFilter(column, currentFilterValues, currentColumnProperty);
243
- if (excluded) {
244
- setColumnData(prev => ({
245
- ...prev,
246
- [column]: {
247
- entities: [],
248
- loading: false,
249
- hasMore: false,
250
- error: undefined,
251
- totalCount: 0
252
- }
253
- }));
254
- return;
255
- }
256
-
257
- // Build filter map for this column — pass FilterValues directly
258
- const whereFilter: FilterValues<string> = {
259
- ...(currentFilterValues ?? {}),
260
- [currentColumnProperty]: ["==", column]
261
- };
262
-
263
- const orderByParam: [string, "asc" | "desc"] | undefined = currentOrderProperty ? [currentOrderProperty, "asc"] : undefined;
264
-
265
- // Mark column as loading
266
- setColumnData(prev => ({
267
- ...prev,
268
- [column]: {
269
- ...prev[column],
270
- loading: true,
271
- error: undefined
272
- }
273
- }));
274
-
275
- // onUpdate callback
276
- const onUpdate = async (entities: Entity<M>[]) => {
277
- // Skip updates if we're cleaning up
278
- if (isCleaningUpRef.current) return;
279
-
280
- const pendingMap = pendingItemsRef.current;
281
-
282
- // Apply pending updates to incoming entities
283
- const mergedEntities = entities.map(e => {
284
- const pending = pendingMap[String(e.id)];
285
- if (pending) {
286
- // Check if DB entity has caught up to the expected column and order
287
- const expectedCol = pending.expectedValues[currentColumnProperty];
288
- const expectedOrder = currentOrderProperty ? pending.expectedValues[currentOrderProperty] : undefined;
289
-
290
- let caughtUp = true;
291
- if (e.values?.[currentColumnProperty] !== expectedCol) {
292
- caughtUp = false;
293
- }
294
- if (currentOrderProperty && e.values?.[currentOrderProperty] !== expectedOrder) {
295
- caughtUp = false;
296
- }
297
-
298
- if (caughtUp) {
299
- // DB has caught up, clear pending state
300
- delete pendingMap[String(e.id)];
301
- return e; // Use the real DB entity
302
- }
303
-
304
- // DB hasn't caught up, overlay expected values
305
- return { ...e,
306
- values: { ...e.values,
307
- ...pending.expectedValues } };
308
- }
309
- return e;
310
- });
311
-
312
- // Add any pending items that belong to this column but aren't in the incoming entities yet
313
- // (e.g. backend hasn't moved them to this column yet)
314
- Object.values(pendingMap).forEach(pending => {
315
- if (pending.expectedValues[currentColumnProperty] === column) {
316
- if (!mergedEntities.some(e => String(e.id) === String(pending.entity.id))) {
317
- mergedEntities.push(pending.entity);
318
- }
319
- }
320
- });
321
-
322
- // Always filter in memory to only show entities that belong to this specific column.
323
- // This is required because text search returns all matches, and collection_entity_patch
324
- // may contain entities that have just been moved out of this column.
325
- let processed = mergedEntities.filter(e => e.values?.[currentColumnProperty] === column);
326
-
327
- // Sort locally if orderProperty is defined. This ensures that collection_entity_patch
328
- // insertions (which prepend by default in websocket.ts) are correctly placed.
329
- if (currentOrderProperty) {
330
- processed = [...processed].sort((a, b) => {
331
- const valA = a.values?.[currentOrderProperty] as string | undefined | null;
332
- const valB = b.values?.[currentOrderProperty] as string | undefined | null;
333
-
334
- const isAEmpty = valA === undefined || valA === null || valA === "";
335
- const isBEmpty = valB === undefined || valB === null || valB === "";
336
-
337
- if (isAEmpty && isBEmpty) return 0;
338
- if (isAEmpty) return 1;
339
- if (isBEmpty) return -1;
340
-
341
- return valA < valB ? -1 : valA > valB ? 1 : 0;
342
- });
343
- }
344
-
345
- // Apply afterRead callbacks if any.
346
- // afterRead operates on flat rows; unwrap the Entity view-model
347
- // before invoking and re-wrap the processed row after.
348
- if (currentCollection.callbacks?.afterRead) {
349
- try {
350
- processed = await Promise.all(
351
- processed.map(async (entity) => {
352
- const processedRow = await currentCollection.callbacks!.afterRead!({
353
- collection: currentCollection,
354
- path: currentResolvedPath,
355
- row: { id: entity.id, ...entity.values },
356
- context: currentContext
357
- });
358
- return {
359
- ...entity,
360
- values: processedRow as M
361
- };
362
- })
363
- );
364
- } catch (e) {
365
- console.error("Error in afterRead callback:", e);
366
- }
367
- }
368
-
369
- const newHasMore = entities.length >= itemCount;
370
-
371
- // Compare with current state — skip update if identical to avoid UI flash
372
- setColumnData(prev => {
373
- const existing = prev[column];
374
- if (existing && !existing.loading && existing.entities.length === processed.length) {
375
- // Quick structural equality check: same IDs in same order with same values
376
- let identical = true;
377
- for (let i = 0; i < processed.length; i++) {
378
- const a = existing.entities[i];
379
- const b = processed[i];
380
- if (a.id !== b.id) {
381
- identical = false;
382
- break;
383
- }
384
- // Shallow-compare values to avoid JSON.stringify allocations
385
- // entity.values are flat records from the DB, so shallow suffices
386
- if (!shallowEqualValues(a.values, b.values)) {
387
- identical = false;
388
- break;
389
- }
390
- }
391
- if (identical && existing.hasMore === newHasMore) {
392
- // Data is the same — return previous reference to prevent re-render
393
- return prev;
394
- }
395
- }
396
-
397
- return {
398
- ...prev,
399
- [column]: {
400
- entities: processed,
401
- loading: false,
402
- hasMore: newHasMore,
403
- error: undefined,
404
- totalCount: prev[column]?.totalCount // Keep existing count
405
- }
406
- };
407
- });
408
- };
409
-
410
- const accessor = currentDataClient.collection(currentResolvedPath);
411
-
412
- // Eagerly include relations to avoid N+1 fetches.
413
- const includeParams = getRelationIncludeParams(currentCollection);
414
-
415
- const fetchOnce = () => accessor.find({
416
- where: whereFilter,
417
- limit: requestedCount,
418
- orderBy: orderByParam,
419
- include: includeParams,
420
- searchString: currentSearchString
421
- });
422
-
423
- const onError = (error: Error) => {
424
- // Skip error handling if we're cleaning up
425
- if (isCleaningUpRef.current) return;
426
-
427
- console.error(`Error loading column ${column}:`, error);
428
-
429
- // A live subscription that fails is not the same thing as a column
430
- // with nothing in it, but that is exactly what this used to render:
431
- // entities cleared, no error surfaced, and a column reading "No
432
- // items" above a header still counting eleven of them. Read once
433
- // over HTTP instead — the board loses its live updates, not its
434
- // contents — and only report the failure if that fails too.
435
- fetchOnce()
436
- .then(res => onUpdate(res.data as Entity<M>[]))
437
- .catch(() => {
438
- if (isCleaningUpRef.current) return;
439
- setColumnData(prev => ({
440
- ...prev,
441
- [column]: {
442
- ...prev[column],
443
- entities: prev[column]?.entities ?? [],
444
- loading: false,
445
- hasMore: false,
446
- error
447
- }
448
- }));
449
- });
450
- };
451
-
452
- if (accessor.listen) {
453
- let liveDataReceived = false;
454
- const unsubscribe = accessor.listen({
455
- where: whereFilter,
456
- limit: requestedCount,
457
- orderBy: orderByParam,
458
- include: includeParams,
459
- // Read into a local at the top of this function and then used
460
- // nowhere, in both places it was read. The board took a search
461
- // term, re-subscribed every column when it changed, and
462
- // returned the same rows.
463
- searchString: currentSearchString
464
- }, res => {
465
- liveDataReceived = true;
466
- onUpdate(res.data as Entity<M>[]);
467
- }, onError);
468
-
469
- // A subscription that is never going to answer takes the client's
470
- // full 30s watchdog to say so, and the board spins the whole time.
471
- // If the socket has not delivered shortly after mount, read once
472
- // over HTTP and paint that; the live data still wins whenever it
473
- // arrives. Costs nothing when realtime is healthy.
474
- const firstPaintFallback = setTimeout(() => {
475
- if (liveDataReceived || isCleaningUpRef.current) return;
476
- fetchOnce()
477
- .then(res => {
478
- if (liveDataReceived || isCleaningUpRef.current) return;
479
- onUpdate(res.data as Entity<M>[]);
480
- })
481
- .catch(() => undefined);
482
- }, LIVE_FIRST_PAINT_TIMEOUT_MS);
483
-
484
- unsubscribersRef.current[column] = () => {
485
- clearTimeout(firstPaintFallback);
486
- unsubscribe?.();
487
- };
488
- } else {
489
- fetchOnce()
490
- .then(res => onUpdate(res.data as Entity<M>[]))
491
- .catch((error: Error) => {
492
- if (isCleaningUpRef.current) return;
493
- setColumnData(prev => ({
494
- ...prev,
495
- [column]: {
496
- ...prev[column],
497
- entities: prev[column]?.entities ?? [],
498
- loading: false,
499
- hasMore: false,
500
- error
501
- }
502
- }));
503
- });
504
- }
505
- }, []); // No dependencies - uses refs for all values
506
-
507
- // Main effect for all column subscriptions - runs when subscriptionVersion changes (i.e., key params change)
508
- useEffect(() => {
509
- // Mark that we're setting up new subscriptions
510
- isCleaningUpRef.current = false;
511
-
512
- // Clean up all existing subscriptions synchronously
513
- const existingUnsubscribers = { ...unsubscribersRef.current };
514
- unsubscribersRef.current = {};
515
- Object.values(existingUnsubscribers).forEach(unsub => {
516
- try {
517
- unsub?.();
518
- } catch (e) {
519
- // Ignore cleanup errors
520
- }
521
- });
522
-
523
- const currentDataClient = dataClientRef.current;
524
- const currentCollection = collectionRef.current;
525
- const currentFilterValues = filterValuesRef.current;
526
- const currentColumnProperty = columnPropertyRef.current;
527
- const currentSearchString = searchStringRef.current;
528
- const currentResolvedPath = resolvedPathRef.current;
529
- const currentColumns = columns;
530
- const currentColumnItemCounts = columnItemCounts;
531
-
532
- // Small delay to ensure Firestore has cleaned up previous listeners
533
- const timeoutId = setTimeout(() => {
534
- if (isCleaningUpRef.current) return;
535
-
536
- currentColumns.forEach(column => {
537
- const itemCount = currentColumnItemCounts[column] ?? pageSize;
538
- subscribeToColumn(column, itemCount);
539
-
540
- // Skip count query for columns excluded by the filter — subscribeToColumn
541
- // already set them to totalCount: 0.
542
- if (isColumnExcludedByFilter(column, currentFilterValues, currentColumnProperty)) {
543
- return;
544
- }
545
-
546
- // Count query for column (for display in column header)
547
- const accessor = currentDataClient.collection(currentResolvedPath);
548
- if (accessor.count) {
549
-
550
- const whereFilter: FilterValues<string> = {
551
- ...(currentFilterValues ?? {}),
552
- [currentColumnProperty]: ["==", column]
553
- };
554
-
555
- accessor.count({
556
- where: whereFilter,
557
- // Or the column header counts the unsearched collection
558
- // while the column beneath it shows searched rows.
559
- searchString: currentSearchString
560
- }).then(count => {
561
- if (isCleaningUpRef.current) return;
562
- setColumnData(prev => ({
563
- ...prev,
564
- [column]: {
565
- ...prev[column],
566
- totalCount: count
567
- }
568
- }));
569
- }).catch(e => {
570
- console.warn(`Failed to get count for column ${column}:`, e);
571
- });
572
- }
573
- });
574
-
575
- // Update the ref after subscribing all
576
- prevColumnItemCountsRef.current = { ...currentColumnItemCounts };
577
- }, 0);
578
-
579
- return () => {
580
- clearTimeout(timeoutId);
581
- isCleaningUpRef.current = true;
582
- const unsubscribers = { ...unsubscribersRef.current };
583
- unsubscribersRef.current = {};
584
- Object.values(unsubscribers).forEach(unsub => {
585
- try {
586
- unsub?.();
587
- } catch (e) {
588
- // Ignore cleanup errors
589
- }
590
- });
591
- };
592
-
593
- }, [subscriptionVersion, subscribeToColumn, pageSize]);
594
-
595
- // Track which subscription version last updated the counts
596
- const lastProcessedVersionRef = useRef(subscriptionVersion);
597
-
598
- // Separate effect to handle individual column load-more WITHOUT triggering full re-subscription
599
- useEffect(() => {
600
- // If subscriptionVersion changed, the main effect will handle everything
601
- // Skip this effect to avoid race conditions
602
- if (subscriptionVersion !== lastProcessedVersionRef.current) {
603
- lastProcessedVersionRef.current = subscriptionVersion;
604
- prevColumnItemCountsRef.current = { ...columnItemCounts };
605
- return;
606
- }
607
-
608
- const prevCounts = prevColumnItemCountsRef.current;
609
-
610
- columns.forEach(column => {
611
- const prevCount = prevCounts[column] ?? pageSize;
612
- const newCount = columnItemCounts[column] ?? pageSize;
613
-
614
- // Only re-subscribe if this specific column's count increased (load more)
615
- if (newCount > prevCount && !isCleaningUpRef.current) {
616
- // Unsubscribe only this column
617
- if (unsubscribersRef.current[column]) {
618
- try {
619
- unsubscribersRef.current[column]();
620
- } catch (e) {
621
- // Ignore cleanup errors
622
- }
623
- delete unsubscribersRef.current[column];
624
- }
625
- // Re-subscribe with new limit after a small delay
626
- setTimeout(() => {
627
- if (!isCleaningUpRef.current) {
628
- subscribeToColumn(column, newCount);
629
- }
630
- }, 0);
631
- }
632
- });
633
-
634
- // Update the ref
635
- prevColumnItemCountsRef.current = { ...columnItemCounts };
636
- }, [columnItemCounts, columns, pageSize, subscribeToColumn, subscriptionVersion]);
637
-
638
- const loadMoreColumn = useCallback((column: COLUMN) => {
639
- setColumnItemCounts(prev => ({
640
- ...prev,
641
- [column]: (prev[column] ?? pageSize) + pageSize
642
- }));
643
- }, [pageSize]);
644
-
645
- const refreshColumn = useCallback((column: COLUMN) => {
646
- // Force re-subscribe by resetting to initial count
647
- setColumnItemCounts(prev => ({
648
- ...prev,
649
- [column]: pageSize
650
- }));
651
- }, [pageSize]);
652
-
653
- const refreshAll = useCallback(() => {
654
- const reset: Record<string, number> = {};
655
- columns.forEach(col => {
656
- reset[col] = pageSize;
657
- });
658
- setColumnItemCounts(reset);
659
- }, [columns, pageSize]);
660
-
661
- // Optimistic update for when moving an item
662
- const moveItemOptimistically = useCallback((itemId: string, sourceColumn: COLUMN, targetColumn: COLUMN, newValues?: Record<string, any>, newIndex?: number) => {
663
- setColumnData(prev => {
664
- const updated = { ...prev };
665
- let itemToMove: Entity<M> | undefined;
666
-
667
- const sourceEntities = [...(updated[sourceColumn]?.entities || [])];
668
- const itemIndex = sourceEntities.findIndex(e => String(e.id) === itemId);
669
-
670
- if (itemIndex !== -1) {
671
- itemToMove = sourceEntities[itemIndex];
672
- sourceEntities.splice(itemIndex, 1);
673
- }
674
-
675
- if (itemToMove) {
676
- const newValuesMerged = {
677
- ...itemToMove.values,
678
- ...(newValues || {})
679
- };
680
-
681
- const updatedEntity = {
682
- ...itemToMove,
683
- values: newValuesMerged
684
- };
685
-
686
- // Store in pending items ref
687
- pendingItemsRef.current[String(updatedEntity.id)] = {
688
- entity: updatedEntity,
689
- expectedValues: newValuesMerged
690
- };
691
-
692
- const targetEntities = sourceColumn === targetColumn ? sourceEntities : [...(updated[targetColumn]?.entities || [])];
693
-
694
- if (newIndex !== undefined && newIndex >= 0 && newIndex <= targetEntities.length) {
695
- targetEntities.splice(newIndex, 0, updatedEntity);
696
- } else {
697
- targetEntities.push(updatedEntity);
698
- if (orderPropertyRef.current) {
699
- const orderProp = orderPropertyRef.current;
700
- targetEntities.sort((a, b) => {
701
- const valA = a.values?.[orderProp] as string | undefined | null;
702
- const valB = b.values?.[orderProp] as string | undefined | null;
703
-
704
- // Handle nulls/empty strings to match Postgres NULLS LAST (ASC) behavior
705
- const isAEmpty = valA === undefined || valA === null || valA === "";
706
- const isBEmpty = valB === undefined || valB === null || valB === "";
707
-
708
- if (isAEmpty && isBEmpty) return 0;
709
- if (isAEmpty) return 1; // A is null, B is not -> A goes after B
710
- if (isBEmpty) return -1; // B is null, A is not -> A goes before B
711
-
712
- return valA < valB ? -1 : valA > valB ? 1 : 0;
713
- });
714
- }
715
- }
716
-
717
- updated[sourceColumn] = {
718
- ...updated[sourceColumn],
719
- entities: sourceColumn === targetColumn ? targetEntities : sourceEntities,
720
- totalCount: sourceColumn === targetColumn
721
- ? updated[sourceColumn].totalCount
722
- : Math.max(0, (updated[sourceColumn].totalCount ?? 0) - 1)
723
- };
724
-
725
- if (sourceColumn !== targetColumn) {
726
- updated[targetColumn] = {
727
- ...updated[targetColumn],
728
- entities: targetEntities,
729
- totalCount: (updated[targetColumn].totalCount ?? 0) + 1
730
- };
731
- }
732
-
733
- } else if (sourceColumn !== targetColumn) {
734
- // If item not found locally but counts need update
735
- if (updated[sourceColumn]?.totalCount !== undefined) {
736
- updated[sourceColumn] = {
737
- ...updated[sourceColumn],
738
- totalCount: Math.max(0, (updated[sourceColumn].totalCount ?? 0) - 1)
739
- };
740
- }
741
- if (updated[targetColumn]?.totalCount !== undefined) {
742
- updated[targetColumn] = {
743
- ...updated[targetColumn],
744
- totalCount: (updated[targetColumn].totalCount ?? 0) + 1
745
- };
746
- }
747
- }
748
-
749
- return updated;
750
- });
751
- }, []);
752
-
753
- // Optimistic update for column counts when deleting items
754
- const decrementColumnCounts = useCallback((columnDeltas: Record<COLUMN, number>) => {
755
- setColumnData(prev => {
756
- const updated = { ...prev };
757
-
758
- for (const [column, delta] of Object.entries(columnDeltas) as [COLUMN, number][]) {
759
- if (updated[column]?.totalCount !== undefined) {
760
- updated[column] = {
761
- ...updated[column],
762
- totalCount: Math.max(0, (updated[column].totalCount ?? 0) - delta)
763
- };
764
- }
765
- }
766
-
767
- return updated;
768
- });
769
- }, []);
770
-
771
- // Aggregate loading and error state
772
- const loading = useMemo(() => {
773
- return Object.values(columnData).some((col) => col.loading);
774
- }, [columnData]);
775
-
776
- const error = useMemo(() => {
777
- const errors = Object.values(columnData)
778
- .map((col) => col.error)
779
- .filter(Boolean);
780
- return errors[0];
781
- }, [columnData]);
782
-
783
- return useMemo(() => ({
784
- columnData: columnData as Record<COLUMN, BoardColumnData<M>>,
785
- loadMoreColumn,
786
- refreshColumn,
787
- refreshAll,
788
- moveItemOptimistically,
789
- decrementColumnCounts,
790
- loading,
791
- error
792
- }), [
793
- columnData,
794
- loadMoreColumn,
795
- refreshColumn,
796
- refreshAll,
797
- moveItemOptimistically,
798
- decrementColumnCounts,
799
- loading,
800
- error
801
- ]);
802
- }