@rebasepro/admin 0.0.1-canary.eae7889 → 0.1.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.
- package/dist/{CollectionEditorDialog-B2M9lCyL.js → CollectionEditorDialog-MbvXGzEq.js} +42 -31
- package/dist/CollectionEditorDialog-MbvXGzEq.js.map +1 -0
- package/dist/{CollectionsStudioView-WG6soyfs.js → CollectionsStudioView-D9X6aiAr.js} +12 -12
- package/dist/CollectionsStudioView-D9X6aiAr.js.map +1 -0
- package/dist/{ContentHomePage-CDF_a6Lp.js → ContentHomePage-CfVB1eUo.js} +26 -26
- package/dist/ContentHomePage-CfVB1eUo.js.map +1 -0
- package/dist/{ExportCollectionAction-Dc0VOWMN.js → ExportCollectionAction-CUwJg4F9.js} +2 -2
- package/dist/{ExportCollectionAction-Dc0VOWMN.js.map → ExportCollectionAction-CUwJg4F9.js.map} +1 -1
- package/dist/{ImportCollectionAction-DpCagAOy.js → ImportCollectionAction-DGa_SF_8.js} +2 -2
- package/dist/{ImportCollectionAction-DpCagAOy.js.map → ImportCollectionAction-DGa_SF_8.js.map} +1 -1
- package/dist/{PropertyEditView-DS67DxoT.js → PropertyEditView-C4nlYmAc.js} +82 -104
- package/dist/PropertyEditView-C4nlYmAc.js.map +1 -0
- package/dist/{RolesView-CIuYBimF.js → RolesView-CNWxnR8e.js} +7 -5
- package/dist/RolesView-CNWxnR8e.js.map +1 -0
- package/dist/{UsersView-B5zelXnH.js → UsersView-YiTIcXkA.js} +14 -35
- package/dist/UsersView-YiTIcXkA.js.map +1 -0
- package/dist/collection_editor/ConfigControllerProvider.d.ts +0 -4
- package/dist/collection_editor/types/collection_editor_controller.d.ts +6 -3
- package/dist/collection_editor/types/config_controller.d.ts +14 -7
- package/dist/collection_editor/ui/AddKanbanColumnAction.d.ts +3 -2
- package/dist/collection_editor/ui/CollectionViewHeaderAction.d.ts +3 -2
- package/dist/collection_editor/ui/EditorCollectionAction.d.ts +1 -1
- package/dist/collection_editor/ui/EditorCollectionActionStart.d.ts +1 -1
- package/dist/collection_editor/ui/EditorEntityAction.d.ts +1 -1
- package/dist/collection_editor/ui/KanbanSetupAction.d.ts +3 -2
- package/dist/collection_editor/ui/PropertyAddColumnComponent.d.ts +3 -2
- package/dist/collection_editor/ui/collection_editor/CollectionDetailsForm.d.ts +3 -4
- package/dist/collection_editor/ui/collection_editor/CollectionEditorDialog.d.ts +2 -3
- package/dist/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +1 -2
- package/dist/collection_editor/ui/collection_editor/SubcollectionsEditTab.d.ts +3 -2
- package/dist/collection_editor_ui.js +3 -3
- package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +1 -1
- package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +1 -1
- package/dist/components/EntityCollectionTable/column_utils.d.ts +2 -2
- package/dist/components/EntityCollectionTable/fields/TableMultipleRelationField.d.ts +1 -1
- package/dist/components/EntityCollectionTable/fields/TableReferenceField.d.ts +1 -1
- package/dist/components/EntityCollectionTable/fields/TableRelationField.d.ts +1 -1
- package/dist/components/EntityCollectionTable/fields/TableRelationSelectorField.d.ts +2 -2
- package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +5 -1
- package/dist/components/EntityCollectionView/EntityCollectionBoardView.d.ts +3 -2
- package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +2 -1
- package/dist/components/EntityCollectionView/EntityCollectionViewActions.d.ts +4 -2
- package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +4 -2
- package/dist/components/EntityCollectionView/FiltersDialog.d.ts +2 -2
- package/dist/components/EntityCollectionView/SplitListView.d.ts +3 -2
- package/dist/components/EntityEditView.d.ts +9 -2
- package/dist/components/RebaseCMS.d.ts +1 -1
- package/dist/components/ReferenceTable/EntitySelectionTable.d.ts +2 -2
- package/dist/components/ReferenceWidget.d.ts +2 -2
- package/dist/components/RelationSelector.d.ts +1 -1
- package/dist/components/SelectableTable/SelectableTable.d.ts +2 -2
- package/dist/editor.js +2 -2
- package/dist/editor.js.map +1 -1
- package/dist/hooks/navigation/useNavigationRegistry.d.ts +2 -1
- package/dist/hooks/useEntityHistory.d.ts +1 -1
- package/dist/{index-CHxgwt6E.js → index-CtzpHzMQ.js} +11 -4
- package/dist/index-CtzpHzMQ.js.map +1 -0
- package/dist/{index-Dey5WJpO.js → index-DKlrVD1m.js} +3 -3
- package/dist/index-DKlrVD1m.js.map +1 -0
- package/dist/{index-CBhrgpR7.js → index-kHJXfLNI.js} +3 -3
- package/dist/index-kHJXfLNI.js.map +1 -0
- package/dist/index.js +79 -63
- package/dist/index.js.map +1 -1
- package/dist/{useEntityHistory-Dcj4zhGj.js → useEntityHistory-UVsSclfZ.js} +3 -1
- package/dist/useEntityHistory-UVsSclfZ.js.map +1 -0
- package/dist/util/navigation_utils.d.ts +10 -1
- package/dist/{util-BQ82ySL3.js → util-CwLmSpGp.js} +1653 -1257
- package/dist/util-CwLmSpGp.js.map +1 -0
- package/package.json +9 -17
- package/src/collection_editor/ConfigControllerProvider.tsx +19 -28
- package/src/collection_editor/types/collection_editor_controller.tsx +3 -3
- package/src/collection_editor/types/config_controller.tsx +7 -7
- package/src/collection_editor/ui/AddKanbanColumnAction.tsx +4 -4
- package/src/collection_editor/ui/CollectionViewHeaderAction.tsx +3 -3
- package/src/collection_editor/ui/EditorCollectionAction.tsx +3 -3
- package/src/collection_editor/ui/EditorCollectionActionStart.tsx +7 -7
- package/src/collection_editor/ui/EditorEntityAction.tsx +3 -3
- package/src/collection_editor/ui/HomePageEditorCollectionAction.tsx +4 -2
- package/src/collection_editor/ui/KanbanSetupAction.tsx +4 -3
- package/src/collection_editor/ui/MissingReferenceWidget.tsx +3 -2
- package/src/collection_editor/ui/NewCollectionButton.tsx +2 -1
- package/src/collection_editor/ui/NewCollectionCard.tsx +2 -1
- package/src/collection_editor/ui/PropertyAddColumnComponent.tsx +3 -3
- package/src/collection_editor/ui/collection_editor/CollectionDetailsForm.tsx +5 -50
- package/src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx +12 -20
- package/src/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.tsx +1 -3
- package/src/collection_editor/ui/collection_editor/CollectionRLSTab.tsx +17 -2
- package/src/collection_editor/ui/collection_editor/CollectionRelationsTab.tsx +3 -3
- package/src/collection_editor/ui/collection_editor/CollectionStudioView.tsx +2 -1
- package/src/collection_editor/ui/collection_editor/CollectionsStudioView.tsx +18 -12
- package/src/collection_editor/ui/collection_editor/DisplaySettingsForm.tsx +1 -2
- package/src/collection_editor/ui/collection_editor/GetCodeDialog.tsx +1 -2
- package/src/collection_editor/ui/collection_editor/PropertyFieldPreview.tsx +6 -6
- package/src/collection_editor/ui/collection_editor/SubcollectionsEditTab.tsx +4 -4
- package/src/collection_editor/ui/collection_editor/properties/MapPropertyField.tsx +2 -2
- package/src/collection_editor/ui/collection_editor/properties/ReferencePropertyField.tsx +15 -49
- package/src/collection_editor/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.tsx +4 -5
- package/src/collection_editor/ui/collection_editor/templates/pages_template.ts +1 -1
- package/src/collection_editor/ui/collection_editor/templates/products_template.ts +2 -2
- package/src/components/DefaultAppBar.tsx +2 -2
- package/src/components/DefaultDrawer.tsx +25 -17
- package/src/components/DrawerNavigationGroup.tsx +4 -4
- package/src/components/DrawerNavigationItem.tsx +6 -6
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +4 -4
- package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +1 -1
- package/src/components/EntityCollectionTable/PropertyTableCell.tsx +4 -4
- package/src/components/EntityCollectionTable/column_utils.tsx +3 -3
- package/src/components/EntityCollectionTable/fields/TableMultipleRelationField.tsx +3 -3
- package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +3 -3
- package/src/components/EntityCollectionTable/fields/TableRelationField.tsx +4 -4
- package/src/components/EntityCollectionTable/fields/TableRelationSelectorField.tsx +3 -3
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +8 -2
- package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +1 -1
- package/src/components/EntityCollectionTable/internal/common.tsx +5 -5
- package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +1 -1
- package/src/components/EntityCollectionTable/table_bindings.tsx +45 -35
- package/src/components/EntityCollectionView/EntityBoardCard.tsx +18 -19
- package/src/components/EntityCollectionView/EntityCard.tsx +2 -2
- package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +42 -14
- package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +4 -3
- package/src/components/EntityCollectionView/EntityCollectionListView.tsx +157 -54
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +169 -75
- package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +23 -13
- package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +21 -12
- package/src/components/EntityCollectionView/FiltersDialog.tsx +7 -7
- package/src/components/EntityCollectionView/SplitListView.tsx +24 -8
- package/src/components/EntityCollectionView/useEntityPreviewSlots.ts +33 -5
- package/src/components/EntityEditView.tsx +85 -85
- package/src/components/EntitySidePanel.tsx +18 -10
- package/src/components/HomePage/ContentHomePage.tsx +24 -15
- package/src/components/HomePage/NavigationCard.tsx +4 -4
- package/src/components/HomePage/NavigationGroup.tsx +2 -2
- package/src/components/RebaseAuthGate.tsx +2 -0
- package/src/components/RebaseCMS.tsx +4 -3
- package/src/components/RebaseNavigation.tsx +8 -5
- package/src/components/ReferenceTable/EntitySelectionTable.tsx +4 -4
- package/src/components/ReferenceWidget.tsx +3 -3
- package/src/components/RelationSelector.tsx +33 -5
- package/src/components/SelectableTable/SelectableTable.tsx +6 -6
- package/src/components/UserSelector.tsx +1 -1
- package/src/components/admin/RolesView.tsx +10 -3
- package/src/components/admin/UsersView.tsx +13 -25
- package/src/components/app/Scaffold.tsx +4 -4
- package/src/components/field_configs.tsx +29 -32
- package/src/components/history/EntityHistoryView.tsx +12 -1
- package/src/editor/editor.tsx +2 -2
- package/src/form/EntityForm.tsx +5 -4
- package/src/form/PropertyFieldBinding.tsx +14 -10
- package/src/form/components/FieldHelperText.tsx +1 -1
- package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +3 -3
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +5 -5
- package/src/form/field_bindings/BlockFieldBinding.tsx +4 -4
- package/src/form/field_bindings/DateTimeFieldBinding.tsx +1 -1
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +1 -1
- package/src/form/field_bindings/MapFieldBinding.tsx +7 -7
- package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +1 -1
- package/src/form/field_bindings/MultipleRelationFieldBinding.tsx +3 -3
- package/src/form/field_bindings/ReferenceAsStringFieldBinding.tsx +7 -7
- package/src/form/field_bindings/ReferenceFieldBinding.tsx +2 -2
- package/src/form/field_bindings/RelationFieldBinding.tsx +4 -4
- package/src/form/field_bindings/RepeatFieldBinding.tsx +5 -5
- package/src/form/field_bindings/SelectFieldBinding.tsx +1 -1
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +1 -1
- package/src/form/field_bindings/SwitchFieldBinding.tsx +1 -1
- package/src/form/field_bindings/TextFieldBinding.tsx +7 -7
- package/src/form/field_bindings/UserSelectFieldBinding.tsx +1 -1
- package/src/form/useClearRestoreValue.tsx +1 -1
- package/src/form/validation.ts +1 -1
- package/src/hooks/navigation/contexts/CollectionRegistryContext.tsx +2 -1
- package/src/hooks/navigation/useBuildCollectionRegistryController.tsx +15 -3
- package/src/hooks/navigation/useNavigationRegistry.ts +14 -3
- package/src/hooks/navigation/useResolvedViews.tsx +1 -3
- package/src/hooks/navigation/useTopLevelNavigation.ts +1 -1
- package/src/hooks/navigation/utils.ts +1 -1
- package/src/hooks/useEntityHistory.ts +7 -2
- package/src/preview/PropertyPreview.tsx +27 -23
- package/src/preview/components/StorageThumbnail.tsx +4 -1
- package/src/preview/property_previews/ArrayOfMapsPreview.tsx +1 -1
- package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +1 -1
- package/src/preview/property_previews/ArrayOfRelationsPreview.tsx +1 -1
- package/src/preview/property_previews/SkeletonPropertyComponent.tsx +3 -3
- package/src/preview/property_previews/StringPropertyPreview.tsx +3 -3
- package/src/routes/RebaseRoute.tsx +57 -11
- package/src/util/navigation_utils.ts +21 -2
- package/src/util/previews.ts +15 -6
- package/src/util/property_utils.tsx +3 -3
- package/dist/CollectionEditorDialog-B2M9lCyL.js.map +0 -1
- package/dist/CollectionsStudioView-WG6soyfs.js.map +0 -1
- package/dist/ContentHomePage-CDF_a6Lp.js.map +0 -1
- package/dist/PropertyEditView-DS67DxoT.js.map +0 -1
- package/dist/RolesView-CIuYBimF.js.map +0 -1
- package/dist/UsersView-B5zelXnH.js.map +0 -1
- package/dist/index-CBhrgpR7.js.map +0 -1
- package/dist/index-CHxgwt6E.js.map +0 -1
- package/dist/index-Dey5WJpO.js.map +0 -1
- package/dist/useEntityHistory-Dcj4zhGj.js.map +0 -1
- package/dist/util-BQ82ySL3.js.map +0 -1
|
@@ -147,29 +147,28 @@ function EntityBoardCardInner<M extends Record<string, unknown> = Record<string,
|
|
|
147
147
|
</div>
|
|
148
148
|
)}
|
|
149
149
|
|
|
150
|
-
{/* Selection checkbox overlay —
|
|
151
|
-
{
|
|
150
|
+
{/* Selection checkbox overlay — always in the DOM, visibility controlled by CSS */}
|
|
151
|
+
<div className={cls(
|
|
152
|
+
"absolute inset-0 flex items-center justify-center rounded-md transition-[opacity,background-color] duration-200",
|
|
153
|
+
!selectionEnabled && "invisible pointer-events-none",
|
|
154
|
+
selectionEnabled && (selected
|
|
155
|
+
? "opacity-100 bg-primary/10 dark:bg-primary/20"
|
|
156
|
+
: "opacity-0 group-hover/card:opacity-100")
|
|
157
|
+
)}>
|
|
152
158
|
<div className={cls(
|
|
153
|
-
"
|
|
159
|
+
"transition-transform duration-200",
|
|
154
160
|
selected
|
|
155
|
-
? "
|
|
156
|
-
: "
|
|
161
|
+
? "scale-100"
|
|
162
|
+
: "scale-75 group-hover/card:scale-100"
|
|
157
163
|
)}>
|
|
158
|
-
<
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
<Checkbox
|
|
165
|
-
checked={selected ?? false}
|
|
166
|
-
onCheckedChange={handleSelectionChange}
|
|
167
|
-
size="small"
|
|
168
|
-
padding={false}
|
|
169
|
-
/>
|
|
170
|
-
</div>
|
|
164
|
+
<Checkbox
|
|
165
|
+
checked={selected ?? false}
|
|
166
|
+
onCheckedChange={handleSelectionChange}
|
|
167
|
+
size="small"
|
|
168
|
+
padding={false}
|
|
169
|
+
/>
|
|
171
170
|
</div>
|
|
172
|
-
|
|
171
|
+
</div>
|
|
173
172
|
</div>
|
|
174
173
|
|
|
175
174
|
{/* Content */}
|
|
@@ -94,8 +94,8 @@ export function EntityCard<M extends Record<string, unknown> = Record<string, un
|
|
|
94
94
|
"cursor-pointer overflow-hidden group relative",
|
|
95
95
|
"transition-all duration-200",
|
|
96
96
|
"hover:shadow-lg hover:-translate-y-0.5",
|
|
97
|
-
selected && "ring-2 ring-primary",
|
|
98
|
-
highlighted && !selected && "ring-2 ring-primary ring-opacity-50"
|
|
97
|
+
selected && "ring-2 ring-primary bg-surface-accent-50 dark:bg-surface-accent-950",
|
|
98
|
+
highlighted && !selected && "ring-2 ring-primary ring-opacity-50 bg-surface-accent-50/50 dark:bg-surface-accent-950/50"
|
|
99
99
|
)}
|
|
100
100
|
onClick={handleClick}
|
|
101
101
|
>
|
|
@@ -30,7 +30,7 @@ export type EntityCollectionBoardViewProps<M extends Record<string, unknown> = R
|
|
|
30
30
|
collection: EntityCollection<M>;
|
|
31
31
|
tableController: EntityTableController<M>;
|
|
32
32
|
fullPath: string;
|
|
33
|
-
|
|
33
|
+
parentCollectionSlugs?: string[], parentEntityIds?: string[];
|
|
34
34
|
columnProperty: string;
|
|
35
35
|
onEntityClick?: (entity: Entity<M>) => void;
|
|
36
36
|
selectionController?: SelectionController<M>;
|
|
@@ -48,7 +48,8 @@ export function EntityCollectionBoardView<M extends Record<string, unknown> = Re
|
|
|
48
48
|
collection,
|
|
49
49
|
tableController,
|
|
50
50
|
fullPath,
|
|
51
|
-
|
|
51
|
+
parentCollectionSlugs = [],
|
|
52
|
+
parentEntityIds = [],
|
|
52
53
|
columnProperty,
|
|
53
54
|
onEntityClick,
|
|
54
55
|
selectionController,
|
|
@@ -225,13 +226,13 @@ export function EntityCollectionBoardView<M extends Record<string, unknown> = Re
|
|
|
225
226
|
.forEach(plugin => {
|
|
226
227
|
plugin.hooks!.onKanbanColumnsReorder!({
|
|
227
228
|
fullPath,
|
|
228
|
-
|
|
229
|
+
parentCollectionSlugs, parentEntityIds,
|
|
229
230
|
collection,
|
|
230
231
|
kanbanColumnProperty: columnProperty,
|
|
231
232
|
newColumnsOrder: newColumns
|
|
232
233
|
});
|
|
233
234
|
});
|
|
234
|
-
}, [plugins, fullPath,
|
|
235
|
+
}, [plugins, fullPath, parentCollectionSlugs, parentEntityIds, collection, columnProperty, analyticsController]);
|
|
235
236
|
|
|
236
237
|
// Collection-level count queries to detect missing order property
|
|
237
238
|
// Just TWO counts: total and ordered (for the entire collection, not per column)
|
|
@@ -432,24 +433,51 @@ export function EntityCollectionBoardView<M extends Record<string, unknown> = Re
|
|
|
432
433
|
return selectionController?.isEntitySelected(entity) ?? false;
|
|
433
434
|
}, [selectionController]);
|
|
434
435
|
|
|
435
|
-
|
|
436
|
-
|
|
436
|
+
// Store latest callbacks in refs so the stable ItemComponent always
|
|
437
|
+
// reads fresh values without changing its own identity.
|
|
438
|
+
const handleEntityClickRef = useRef(handleEntityClick);
|
|
439
|
+
handleEntityClickRef.current = handleEntityClick;
|
|
440
|
+
const isEntitySelectedRef = useRef(isEntitySelected);
|
|
441
|
+
isEntitySelectedRef.current = isEntitySelected;
|
|
442
|
+
const handleSelectionChangeRef = useRef(handleSelectionChange);
|
|
443
|
+
handleSelectionChangeRef.current = handleSelectionChange;
|
|
444
|
+
const selectionEnabledRef = useRef(selectionEnabled);
|
|
445
|
+
selectionEnabledRef.current = selectionEnabled;
|
|
446
|
+
|
|
447
|
+
// Stable callback wrappers — identity never changes, delegates to refs.
|
|
448
|
+
const stableOnClick = useCallback((entity: Entity<M>) => {
|
|
449
|
+
handleEntityClickRef.current(entity);
|
|
450
|
+
}, []);
|
|
451
|
+
const stableOnSelectionChange = useCallback((entity: Entity<M>, sel: boolean) => {
|
|
452
|
+
handleSelectionChangeRef.current(entity, sel);
|
|
453
|
+
}, []);
|
|
454
|
+
|
|
455
|
+
// Build a single, truly stable component reference.
|
|
456
|
+
// Uses refs for ALL dynamic values so the component type never changes.
|
|
457
|
+
// When ItemComponent identity changes, React.memo'd SortableItem remounts
|
|
458
|
+
// the card → DOM is destroyed/recreated → CSS :hover state is lost → flicker.
|
|
459
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
460
|
+
const ItemComponent = useMemo(() => {
|
|
461
|
+
const Comp = (props: BoardItemViewProps<M>) => (
|
|
437
462
|
<EntityBoardCard
|
|
438
463
|
{...props}
|
|
439
|
-
collection={
|
|
440
|
-
onClick={
|
|
441
|
-
selected={
|
|
442
|
-
onSelectionChange={
|
|
443
|
-
selectionEnabled={
|
|
464
|
+
collection={collectionRef.current as EntityCollection<M>}
|
|
465
|
+
onClick={stableOnClick}
|
|
466
|
+
selected={isEntitySelectedRef.current(props.item.entity)}
|
|
467
|
+
onSelectionChange={stableOnSelectionChange}
|
|
468
|
+
selectionEnabled={selectionEnabledRef.current}
|
|
444
469
|
/>
|
|
445
470
|
);
|
|
446
|
-
|
|
471
|
+
Comp.displayName = "KanbanItemComponent";
|
|
472
|
+
return Comp;
|
|
473
|
+
}, []);
|
|
447
474
|
|
|
448
475
|
// Get KanbanSetupComponent from plugin slots
|
|
449
476
|
const kanbanSetupSlots = useSlot("kanban.setup", {
|
|
450
477
|
collection,
|
|
451
478
|
fullPath,
|
|
452
|
-
|
|
479
|
+
parentCollectionSlugs,
|
|
480
|
+
parentEntityIds
|
|
453
481
|
});
|
|
454
482
|
const KanbanSetupComponent = kanbanSetupSlots.length > 0 ? () => <>{kanbanSetupSlots[0]}</> : null;
|
|
455
483
|
|
|
@@ -457,7 +485,7 @@ export function EntityCollectionBoardView<M extends Record<string, unknown> = Re
|
|
|
457
485
|
const addKanbanColumnSlots = useSlot("kanban.add-column", {
|
|
458
486
|
collection,
|
|
459
487
|
fullPath,
|
|
460
|
-
|
|
488
|
+
parentCollectionSlugs, parentEntityIds,
|
|
461
489
|
columnProperty
|
|
462
490
|
});
|
|
463
491
|
const AddKanbanColumnComponent = addKanbanColumnSlots.length > 0 ? () => <>{addKanbanColumnSlots[0]}</> : null;
|
|
@@ -5,7 +5,6 @@ import { EntityCard } from "./EntityCard";
|
|
|
5
5
|
import {
|
|
6
6
|
cls,
|
|
7
7
|
CircularProgress,
|
|
8
|
-
CircularProgressCenter,
|
|
9
8
|
Typography
|
|
10
9
|
} from "@rebasepro/ui";
|
|
11
10
|
import { useAuthController, useCustomizationController } from "@rebasepro/core";
|
|
@@ -213,9 +212,11 @@ export function EntityCollectionCardView<M extends Record<string, unknown> = Rec
|
|
|
213
212
|
</Typography>
|
|
214
213
|
</div>
|
|
215
214
|
) : isInitialLoading ? (
|
|
216
|
-
<
|
|
215
|
+
<div className="flex items-center justify-center py-12 px-8">
|
|
216
|
+
<CircularProgress size="small"/>
|
|
217
|
+
</div>
|
|
217
218
|
) : isEmpty ? (
|
|
218
|
-
<div className="
|
|
219
|
+
<div className="flex items-center justify-center py-12 px-8">
|
|
219
220
|
{emptyComponent ?? (
|
|
220
221
|
<Typography variant="label" color="secondary">
|
|
221
222
|
No entries found
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
Checkbox,
|
|
8
8
|
Chip,
|
|
9
9
|
CircularProgress,
|
|
10
|
-
CircularProgressCenter,
|
|
11
10
|
cls,
|
|
12
11
|
defaultBorderMixin,
|
|
13
12
|
Typography
|
|
@@ -88,6 +87,44 @@ function getRowClasses(size: CollectionSize): string {
|
|
|
88
87
|
}
|
|
89
88
|
}
|
|
90
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Estimated row height in pixels for virtualization, based on size.
|
|
92
|
+
*/
|
|
93
|
+
function getEstimatedRowHeight(size: CollectionSize): number {
|
|
94
|
+
switch (size) {
|
|
95
|
+
case "xs": return 44;
|
|
96
|
+
case "s": return 52;
|
|
97
|
+
case "m": return 64;
|
|
98
|
+
case "l": return 76;
|
|
99
|
+
case "xl": return 88;
|
|
100
|
+
default: return 64;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Number of extra rows rendered above/below the viewport. */
|
|
105
|
+
const OVERSCAN_COUNT = 8;
|
|
106
|
+
|
|
107
|
+
/** Threshold in pixels from the bottom of the scroll area to trigger loading more. */
|
|
108
|
+
const LOAD_MORE_THRESHOLD = 400;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Walk up the DOM from `element` to find the nearest scrollable ancestor.
|
|
112
|
+
*/
|
|
113
|
+
function getScrollParent(element: HTMLElement | null): HTMLElement | null {
|
|
114
|
+
let parent = element?.parentElement ?? null;
|
|
115
|
+
while (parent) {
|
|
116
|
+
const style = getComputedStyle(parent);
|
|
117
|
+
if (
|
|
118
|
+
style.overflowY === "auto" || style.overflowY === "scroll" ||
|
|
119
|
+
style.overflow === "auto" || style.overflow === "scroll"
|
|
120
|
+
) {
|
|
121
|
+
return parent;
|
|
122
|
+
}
|
|
123
|
+
parent = parent.parentElement;
|
|
124
|
+
}
|
|
125
|
+
return document.documentElement;
|
|
126
|
+
}
|
|
127
|
+
|
|
91
128
|
/**
|
|
92
129
|
* Returns true if a property type should NOT be rendered via
|
|
93
130
|
* PropertyPreview in list row columns (because it would blow up height).
|
|
@@ -446,22 +483,77 @@ export function EntityCollectionListView<M extends Record<string, unknown> = Rec
|
|
|
446
483
|
// Empty state
|
|
447
484
|
const isEmpty = !dataLoading && data.length === 0 && !dataLoadingError;
|
|
448
485
|
|
|
486
|
+
// ── Virtualization: scroll-parent windowing ──
|
|
487
|
+
const estimatedRowHeight = getEstimatedRowHeight(size);
|
|
488
|
+
const [effectiveScrollTop, setEffectiveScrollTop] = useState(0);
|
|
489
|
+
const [viewportHeight, setViewportHeight] = useState(800);
|
|
490
|
+
|
|
491
|
+
// Keep mutable refs for values used in the scroll handler to avoid
|
|
492
|
+
// re-attaching the listener every time pagination state changes.
|
|
493
|
+
const paginationStateRef = useRef({ paginationEnabled, noMoreToLoad, itemCount, pageSize });
|
|
494
|
+
useEffect(() => {
|
|
495
|
+
paginationStateRef.current = { paginationEnabled, noMoreToLoad, itemCount, pageSize };
|
|
496
|
+
}, [paginationEnabled, noMoreToLoad, itemCount, pageSize]);
|
|
449
497
|
|
|
450
|
-
// Sentinel ref for IntersectionObserver-based infinite scroll
|
|
451
|
-
const sentinelRef = useRef<HTMLDivElement | null>(null);
|
|
452
498
|
useEffect(() => {
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
499
|
+
const el = containerRef.current;
|
|
500
|
+
if (!el) return;
|
|
501
|
+
const scrollEl = getScrollParent(el);
|
|
502
|
+
if (!scrollEl) return;
|
|
503
|
+
|
|
504
|
+
let rafId: number | null = null;
|
|
505
|
+
|
|
506
|
+
const update = () => {
|
|
507
|
+
rafId = null;
|
|
508
|
+
const scrollRect = scrollEl.getBoundingClientRect();
|
|
509
|
+
const listRect = el.getBoundingClientRect();
|
|
510
|
+
|
|
511
|
+
// How much of the list has scrolled past the viewport top
|
|
512
|
+
const listTopRelative = listRect.top - scrollRect.top;
|
|
513
|
+
setEffectiveScrollTop(Math.max(0, -listTopRelative));
|
|
514
|
+
setViewportHeight(scrollRect.height);
|
|
515
|
+
|
|
516
|
+
// Infinite scroll: trigger load-more when near the bottom
|
|
517
|
+
const { paginationEnabled: pe, noMoreToLoad: nm, itemCount: ic, pageSize: ps } = paginationStateRef.current;
|
|
518
|
+
if (
|
|
519
|
+
pe &&
|
|
520
|
+
!nm &&
|
|
521
|
+
!isLoadingMore.current &&
|
|
522
|
+
scrollEl.scrollHeight - scrollEl.scrollTop - scrollEl.clientHeight < LOAD_MORE_THRESHOLD
|
|
523
|
+
) {
|
|
458
524
|
isLoadingMore.current = true;
|
|
459
|
-
setItemCount?.((
|
|
525
|
+
setItemCount?.((ic ?? ps) + ps);
|
|
460
526
|
}
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
const onScroll = () => {
|
|
530
|
+
if (rafId === null) rafId = requestAnimationFrame(update);
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
scrollEl.addEventListener("scroll", onScroll, { passive: true });
|
|
534
|
+
const ro = new ResizeObserver(() => update());
|
|
535
|
+
ro.observe(scrollEl);
|
|
536
|
+
update(); // initial measurement
|
|
537
|
+
|
|
538
|
+
return () => {
|
|
539
|
+
scrollEl.removeEventListener("scroll", onScroll);
|
|
540
|
+
ro.disconnect();
|
|
541
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
542
|
+
};
|
|
543
|
+
}, [setItemCount]); // stable deps only — mutable state via refs
|
|
544
|
+
|
|
545
|
+
// Compute the visible window of rows
|
|
546
|
+
const totalHeight = data.length * estimatedRowHeight;
|
|
547
|
+
const startIndex = Math.max(0, Math.floor(effectiveScrollTop / estimatedRowHeight) - OVERSCAN_COUNT);
|
|
548
|
+
const endIndex = Math.min(
|
|
549
|
+
data.length,
|
|
550
|
+
Math.ceil((effectiveScrollTop + viewportHeight) / estimatedRowHeight) + OVERSCAN_COUNT
|
|
551
|
+
);
|
|
552
|
+
const visibleData = data.slice(startIndex, endIndex);
|
|
553
|
+
const offsetY = startIndex * estimatedRowHeight;
|
|
554
|
+
|
|
555
|
+
// Footer height for loading/end indicators
|
|
556
|
+
const footerHeight = dataLoading ? 48 : (!dataLoading && noMoreToLoad && data.length > 0) ? 32 : 0;
|
|
465
557
|
|
|
466
558
|
return (
|
|
467
559
|
<div
|
|
@@ -479,9 +571,11 @@ export function EntityCollectionListView<M extends Record<string, unknown> = Rec
|
|
|
479
571
|
</Typography>
|
|
480
572
|
</div>
|
|
481
573
|
) : isInitialLoading ? (
|
|
482
|
-
<
|
|
574
|
+
<div className="flex items-center justify-center py-12 px-8">
|
|
575
|
+
<CircularProgress size="small"/>
|
|
576
|
+
</div>
|
|
483
577
|
) : isEmpty ? (
|
|
484
|
-
<div className="flex items-center justify-center
|
|
578
|
+
<div className="flex items-center justify-center py-12 px-8">
|
|
485
579
|
{emptyComponent ?? (
|
|
486
580
|
<Typography variant="label" color="secondary">
|
|
487
581
|
No entries found
|
|
@@ -489,55 +583,64 @@ export function EntityCollectionListView<M extends Record<string, unknown> = Rec
|
|
|
489
583
|
)}
|
|
490
584
|
</div>
|
|
491
585
|
) : (
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
586
|
+
/* Spacer with total height — no internal scroll.
|
|
587
|
+
The nearest scrollable ancestor provides the scrollbar. */
|
|
588
|
+
<div style={{ height: totalHeight + footerHeight, position: "relative" }}>
|
|
589
|
+
{/* Windowed rows */}
|
|
590
|
+
<div style={{ position: "absolute", top: offsetY, left: 0, right: 0 }}>
|
|
591
|
+
{visibleData.map((entity, i) => {
|
|
592
|
+
const actualIndex = startIndex + i;
|
|
593
|
+
const isLast = actualIndex === data.length - 1;
|
|
594
|
+
return (
|
|
595
|
+
<div
|
|
596
|
+
key={entity.id}
|
|
597
|
+
style={{ height: estimatedRowHeight }}
|
|
598
|
+
className={cls(
|
|
599
|
+
!isLast && "border-b",
|
|
600
|
+
!isLast && defaultBorderMixin
|
|
601
|
+
)}
|
|
602
|
+
>
|
|
603
|
+
<ListRow
|
|
604
|
+
entity={entity}
|
|
605
|
+
collection={resolvedCollection}
|
|
606
|
+
onClick={handleEntityClick}
|
|
607
|
+
selected={isEntitySelected(entity)}
|
|
608
|
+
highlighted={isEntityHighlighted(entity)}
|
|
609
|
+
onSelectionChange={handleSelectionChange}
|
|
610
|
+
selectionEnabled={selectionEnabled}
|
|
611
|
+
columns={visibleColumns}
|
|
612
|
+
slotKeys={slotKeys}
|
|
613
|
+
rowClasses={rowClasses}
|
|
614
|
+
showImage={showImage}
|
|
615
|
+
size={size}
|
|
616
|
+
isLast={isLast}
|
|
617
|
+
isActive={selectedEntityId !== undefined && entity.id === selectedEntityId}
|
|
618
|
+
/>
|
|
619
|
+
</div>
|
|
620
|
+
);
|
|
621
|
+
})}
|
|
622
|
+
</div>
|
|
527
623
|
|
|
624
|
+
{/* Loading / end indicators pinned at the bottom */}
|
|
528
625
|
{dataLoading && (
|
|
529
|
-
<div
|
|
626
|
+
<div
|
|
627
|
+
className="flex items-center justify-center py-3"
|
|
628
|
+
style={{ position: "absolute", top: totalHeight, left: 0, right: 0 }}
|
|
629
|
+
>
|
|
530
630
|
<CircularProgress size="small"/>
|
|
531
631
|
</div>
|
|
532
632
|
)}
|
|
533
633
|
{!dataLoading && noMoreToLoad && data.length > 0 && (
|
|
534
|
-
<div
|
|
634
|
+
<div
|
|
635
|
+
className="flex items-center justify-center py-2 dark:bg-surface-900"
|
|
636
|
+
style={{ position: "absolute", top: totalHeight, left: 0, right: 0 }}
|
|
637
|
+
>
|
|
535
638
|
<Typography variant="caption" color="secondary">
|
|
536
639
|
All {data.length} entries loaded
|
|
537
640
|
</Typography>
|
|
538
641
|
</div>
|
|
539
642
|
)}
|
|
540
|
-
|
|
643
|
+
</div>
|
|
541
644
|
)}
|
|
542
645
|
</div>
|
|
543
646
|
);
|
|
@@ -619,7 +722,7 @@ const ListRow = React.memo(function ListRow<M extends Record<string, unknown>>({
|
|
|
619
722
|
isActive
|
|
620
723
|
? "bg-surface-accent-100 dark:bg-surface-accent-950 hover:bg-surface-accent-200 dark:hover:bg-surface-accent-900"
|
|
621
724
|
: selected
|
|
622
|
-
? "bg-
|
|
725
|
+
? "bg-surface-accent-50 dark:bg-surface-accent-950 hover:bg-surface-accent-100 dark:hover:bg-surface-accent-900"
|
|
623
726
|
: highlighted
|
|
624
727
|
? "bg-surface-accent-50 dark:bg-surface-accent-950 hover:bg-surface-50 dark:hover:bg-surface-800/40"
|
|
625
728
|
: "bg-white dark:bg-surface-900 hover:bg-surface-50 dark:hover:bg-surface-800/40"
|