@rebasepro/admin 0.6.1 → 0.8.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-HNXGxXdO.js → CollectionEditorDialog-BO_aQ-Z4.js} +236 -155
- package/dist/CollectionEditorDialog-BO_aQ-Z4.js.map +1 -0
- package/dist/{PropertyEditView-C2wp8kQ9.js → PropertyEditView-DKzOpMjR.js} +190 -50
- package/dist/PropertyEditView-DKzOpMjR.js.map +1 -0
- package/dist/{CollectionsStudioView-B1mN33GB.js → RouterCollectionsStudioView-BQTIExjA.js} +61 -39
- package/dist/RouterCollectionsStudioView-BQTIExjA.js.map +1 -0
- package/dist/collection_editor/_cms_internals.d.ts +1 -1
- package/dist/collection_editor/api/generateCollectionApi.d.ts +3 -2
- package/dist/collection_editor/extensibility_types.d.ts +135 -0
- package/dist/collection_editor/index.d.ts +6 -0
- package/dist/collection_editor/serializable_types.d.ts +370 -0
- package/dist/collection_editor/serializable_utils.d.ts +50 -0
- package/dist/collection_editor/ui/collection_editor/CollectionEditorDialog.d.ts +3 -3
- package/dist/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +12 -1
- package/dist/collection_editor/ui/collection_editor/CollectionStudioView.d.ts +13 -1
- package/dist/collection_editor/ui/collection_editor/CollectionsStudioView.d.ts +24 -2
- package/dist/collection_editor/ui/collection_editor/DisplaySettingsForm.d.ts +2 -1
- package/dist/collection_editor/ui/collection_editor/GeneralSettingsForm.d.ts +4 -1
- package/dist/collection_editor/ui/collection_editor/PropertyEditView.d.ts +12 -1
- package/dist/collection_editor/ui/collection_editor/RouterCollectionStudioView.d.ts +15 -0
- package/dist/collection_editor/ui/collection_editor/RouterCollectionsStudioView.d.ts +14 -0
- package/dist/collection_editor/useJsonCollectionsConfigController.d.ts +37 -0
- package/dist/collection_editor/useSafeSnackbarController.d.ts +2 -0
- package/dist/collection_editor_ui.d.ts +4 -0
- package/dist/collection_editor_ui.js +33 -4
- package/dist/collection_editor_ui.js.map +1 -0
- package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +1 -1
- package/dist/components/EntityCollectionTable/index.d.ts +1 -1
- package/dist/components/EntityCollectionView/EntityBoardCard.d.ts +3 -3
- package/dist/components/EntityCollectionView/hooks/useKanbanDragAndDrop.d.ts +3 -3
- package/dist/components/EntityEditView.d.ts +3 -2
- package/dist/components/RebaseCMS.d.ts +1 -1
- package/dist/components/SelectableTable/SelectionStore.d.ts +12 -21
- package/dist/components/field_configs.d.ts +1 -1
- package/dist/editor/editor.d.ts +0 -6
- package/dist/editor.js +1 -3
- package/dist/editor.js.map +1 -1
- package/dist/form/EntityForm.d.ts +10 -9
- package/dist/form/EntityFormBinding.d.ts +27 -0
- package/dist/form/components/StorageUploadProgress.d.ts +6 -1
- package/dist/form/form_utils.d.ts +8 -0
- package/dist/form/index.d.ts +5 -2
- package/dist/{history-BO6VT85a.js → history-B3cqBzEV.js} +2 -2
- package/dist/{history-BO6VT85a.js.map → history-B3cqBzEV.js.map} +1 -1
- package/dist/hooks/navigation/contexts/CollectionRegistryContext.d.ts +1 -1
- package/dist/hooks/navigation/useAsyncResolver.d.ts +26 -0
- package/dist/hooks/navigation/useBuildCollectionRegistryController.d.ts +2 -0
- package/dist/hooks/navigation/useTopLevelNavigation.d.ts +1 -1
- package/dist/hooks/navigation/utils.d.ts +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -2
- package/dist/preview/components/StorageThumbnail.d.ts +3 -1
- package/dist/routes/CustomViewRoute.d.ts +2 -1
- package/dist/{src-BYniefVu.js → src-cxV1ODRG.js} +1731 -1710
- package/dist/src-cxV1ODRG.js.map +1 -0
- package/dist/types/components/EntityFormActionsProps.d.ts +1 -1
- package/dist/types/components/EntityFormProps.d.ts +59 -0
- package/dist/types/components/PropertyPreviewProps.d.ts +2 -1
- package/dist/types/fields.d.ts +10 -7
- package/dist/util/dataControllerAdapter.d.ts +30 -0
- package/dist/util/navigation_utils.d.ts +1 -1
- package/dist/util/propertyConfigMapper.d.ts +17 -0
- package/package.json +8 -8
- package/src/collection_editor/_cms_internals.ts +1 -1
- package/src/collection_editor/api/generateCollectionApi.ts +3 -2
- package/src/collection_editor/extensibility_types.ts +168 -0
- package/src/collection_editor/index.ts +46 -0
- package/src/collection_editor/pgColumnToProperty.ts +2 -2
- package/src/collection_editor/serializable_types.ts +474 -0
- package/src/collection_editor/serializable_utils.ts +576 -0
- package/src/collection_editor/ui/collection_editor/AICollectionGeneratorPopover.tsx +6 -6
- package/src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx +170 -89
- package/src/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.tsx +95 -78
- package/src/collection_editor/ui/collection_editor/CollectionStudioView.tsx +23 -20
- package/src/collection_editor/ui/collection_editor/CollectionsStudioView.tsx +79 -27
- package/src/collection_editor/ui/collection_editor/DisplaySettingsForm.tsx +9 -7
- package/src/collection_editor/ui/collection_editor/GeneralSettingsForm.tsx +22 -5
- package/src/collection_editor/ui/collection_editor/GetCodeDialog.tsx +3 -3
- package/src/collection_editor/ui/collection_editor/PropertyEditView.tsx +154 -18
- package/src/collection_editor/ui/collection_editor/PropertyFieldPreview.tsx +6 -6
- package/src/collection_editor/ui/collection_editor/PropertyTree.tsx +1 -0
- package/src/collection_editor/ui/collection_editor/RouterCollectionStudioView.tsx +44 -0
- package/src/collection_editor/ui/collection_editor/RouterCollectionsStudioView.tsx +41 -0
- package/src/collection_editor/ui/collection_editor/properties/EnumPropertyField.tsx +4 -3
- package/src/collection_editor/ui/collection_editor/properties/StoragePropertyField.tsx +35 -1
- package/src/collection_editor/ui/collection_editor/templates/blog_template.ts +1 -1
- package/src/collection_editor/ui/collection_editor/utils/supported_fields.tsx +0 -1
- package/src/collection_editor/ui/collection_editor/utils/update_property_for_widget.ts +7 -29
- package/src/collection_editor/useJsonCollectionsConfigController.tsx +286 -0
- package/src/collection_editor/useSafeSnackbarController.ts +9 -0
- package/src/collection_editor_ui.ts +6 -0
- package/src/components/DefaultDrawer.tsx +14 -4
- package/src/components/DrawerNavigationGroup.tsx +2 -2
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +11 -9
- package/src/components/EntityCollectionTable/fields/TableMultipleRelationField.tsx +2 -1
- package/src/components/EntityCollectionTable/fields/TableRelationField.tsx +2 -1
- package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +23 -20
- package/src/components/EntityCollectionTable/index.tsx +1 -1
- package/src/components/EntityCollectionTable/table_bindings.tsx +24 -44
- package/src/components/EntityCollectionView/EntityBoardCard.tsx +6 -6
- package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +13 -12
- package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +40 -190
- package/src/components/EntityCollectionView/EntityCollectionListView.tsx +66 -184
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +8 -25
- package/src/components/EntityCollectionView/hooks/useCollectionInlineEditor.ts +1 -1
- package/src/components/EntityCollectionView/hooks/useKanbanDragAndDrop.ts +6 -6
- package/src/components/EntityCollectionView/useBoardDataController.tsx +12 -40
- package/src/components/EntityCollectionView/useEntityPreviewSlots.ts +3 -3
- package/src/components/EntityDetailView.tsx +2 -2
- package/src/components/EntityEditView.tsx +7 -6
- package/src/components/EntityEditViewFormActions.tsx +35 -29
- package/src/components/HomePage/ContentHomePage.tsx +14 -5
- package/src/components/RebaseCMS.tsx +3 -3
- package/src/components/RebaseNavigation.tsx +74 -9
- package/src/components/RelationSelector.tsx +2 -2
- package/src/components/SelectableTable/SelectableTable.tsx +13 -5
- package/src/components/SelectableTable/SelectionStore.ts +18 -48
- package/src/components/SideDialogs.tsx +0 -7
- package/src/components/common/default_entity_actions.tsx +22 -11
- package/src/components/field_configs.tsx +0 -14
- package/src/contexts/BreacrumbsContext.tsx +15 -6
- package/src/editor/editor.tsx +4 -7
- package/src/editor/selectors/ai-selector.tsx +0 -1
- package/src/form/EntityForm.tsx +191 -428
- package/src/form/EntityFormActions.tsx +35 -49
- package/src/form/EntityFormBinding.tsx +323 -0
- package/src/form/components/FormLayout.tsx +1 -1
- package/src/form/components/StorageUploadProgress.tsx +9 -2
- package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +12 -1
- package/src/form/field_bindings/MultipleRelationFieldBinding.tsx +4 -4
- package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +7 -2
- package/src/form/field_bindings/RelationFieldBinding.tsx +5 -7
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +19 -15
- package/src/form/form_utils.ts +163 -0
- package/src/form/index.tsx +14 -6
- package/src/hooks/navigation/contexts/CollectionRegistryContext.tsx +2 -2
- package/src/hooks/navigation/contexts/NavigationStateContext.tsx +2 -2
- package/src/hooks/navigation/contexts/UrlContext.tsx +1 -2
- package/src/hooks/navigation/useAsyncResolver.ts +100 -0
- package/src/hooks/navigation/useBuildCollectionRegistryController.tsx +15 -8
- package/src/hooks/navigation/useBuildNavigationStateController.tsx +12 -8
- package/src/hooks/navigation/useNavigationResolution.ts +33 -0
- package/src/hooks/navigation/useResolvedCollections.ts +29 -71
- package/src/hooks/navigation/useResolvedViews.tsx +40 -70
- package/src/hooks/navigation/useTopLevelNavigation.ts +20 -16
- package/src/hooks/navigation/utils.ts +7 -4
- package/src/index.ts +6 -1
- package/src/preview/PropertyPreview.tsx +1 -16
- package/src/preview/components/StorageThumbnail.tsx +24 -7
- package/src/routes/CustomViewRoute.tsx +14 -6
- package/src/types/components/EntityFormActionsProps.tsx +1 -1
- package/src/types/components/EntityFormProps.tsx +68 -0
- package/src/types/components/PropertyPreviewProps.tsx +1 -1
- package/src/types/fields.tsx +9 -8
- package/src/util/dataControllerAdapter.ts +93 -0
- package/src/util/navigation_utils.ts +1 -1
- package/src/util/previews.ts +20 -0
- package/src/util/propertyConfigMapper.ts +134 -0
- package/src/util/property_utils.tsx +1 -2
- package/dist/CollectionEditorDialog-HNXGxXdO.js.map +0 -1
- package/dist/CollectionsStudioView-B1mN33GB.js.map +0 -1
- package/dist/PropertyEditView-C2wp8kQ9.js.map +0 -1
- package/dist/components/EntityCollectionTable/fields/VirtualTableDateField.d.ts +0 -12
- package/dist/components/EntityCollectionTable/fields/VirtualTableInput.d.ts +0 -10
- package/dist/components/EntityCollectionTable/fields/VirtualTableNumberInput.d.ts +0 -9
- package/dist/components/EntityCollectionTable/fields/VirtualTableSwitch.d.ts +0 -8
- package/dist/components/EntityCollectionView/Board.d.ts +0 -3
- package/dist/components/EntityCollectionView/BoardColumn.d.ts +0 -42
- package/dist/components/EntityCollectionView/BoardColumnTitle.d.ts +0 -9
- package/dist/components/EntityCollectionView/BoardSortableList.d.ts +0 -14
- package/dist/components/EntityCollectionView/board_types.d.ts +0 -105
- package/dist/form/field_bindings/ReferenceAsStringFieldBinding.d.ts +0 -11
- package/dist/hooks/navigation/useNavigationRegistry.d.ts +0 -12
- package/dist/hooks/navigation/useNavigationURLs.d.ts +0 -11
- package/dist/src-BYniefVu.js.map +0 -1
- package/src/components/EntityCollectionTable/fields/VirtualTableDateField.tsx +0 -39
- package/src/components/EntityCollectionTable/fields/VirtualTableInput.tsx +0 -90
- package/src/components/EntityCollectionTable/fields/VirtualTableNumberInput.tsx +0 -83
- package/src/components/EntityCollectionTable/fields/VirtualTableSwitch.tsx +0 -32
- package/src/components/EntityCollectionView/Board.tsx +0 -475
- package/src/components/EntityCollectionView/BoardColumn.tsx +0 -165
- package/src/components/EntityCollectionView/BoardColumnTitle.tsx +0 -46
- package/src/components/EntityCollectionView/BoardSortableList.tsx +0 -177
- package/src/components/EntityCollectionView/board_types.ts +0 -113
- package/src/form/field_bindings/ReferenceAsStringFieldBinding.tsx +0 -141
- package/src/hooks/navigation/useNavigationRegistry.ts +0 -164
- package/src/hooks/navigation/useNavigationURLs.ts +0 -56
|
@@ -10,7 +10,8 @@ import {
|
|
|
10
10
|
defaultBorderMixin,
|
|
11
11
|
IconButton,
|
|
12
12
|
Tooltip,
|
|
13
|
-
Typography
|
|
13
|
+
Typography,
|
|
14
|
+
ListView
|
|
14
15
|
} from "@rebasepro/ui";
|
|
15
16
|
import { PropertyPreview } from "../../preview";
|
|
16
17
|
import {
|
|
@@ -401,7 +402,18 @@ export function EntityCollectionListView<M extends Record<string, unknown> = Rec
|
|
|
401
402
|
"id"
|
|
402
403
|
]);
|
|
403
404
|
|
|
404
|
-
const availableExtraKeys = allKeys.filter(k =>
|
|
405
|
+
const availableExtraKeys = allKeys.filter(k => {
|
|
406
|
+
if (usedKeys.has(k)) return false;
|
|
407
|
+
const prop = resolvedCollection.properties[k] as Property | undefined;
|
|
408
|
+
if (!prop) return false;
|
|
409
|
+
// Exclude storage/image properties — they are already rendered in the image slot
|
|
410
|
+
if (prop.type === "string" && (prop.storage || prop.ui?.url === "image")) return false;
|
|
411
|
+
if (prop.type === "array" && prop.of && !Array.isArray(prop.of)) {
|
|
412
|
+
const inner = prop.of;
|
|
413
|
+
if (inner.type === "string" && (inner.storage || inner.ui?.url === "image")) return false;
|
|
414
|
+
}
|
|
415
|
+
return true;
|
|
416
|
+
});
|
|
405
417
|
|
|
406
418
|
availableExtraKeys.forEach(key => {
|
|
407
419
|
const prop = resolvedCollection.properties[key] as Property;
|
|
@@ -510,192 +522,62 @@ customEntityActions });
|
|
|
510
522
|
|
|
511
523
|
const rowClasses = getRowClasses(size);
|
|
512
524
|
|
|
513
|
-
|
|
514
|
-
const
|
|
515
|
-
// Empty state
|
|
516
|
-
const isEmpty = !dataLoading && data.length === 0 && !dataLoadingError;
|
|
517
|
-
|
|
518
|
-
// ── Virtualization: scroll-parent windowing ──
|
|
519
|
-
const estimatedRowHeight = getEstimatedRowHeight(size);
|
|
520
|
-
const [effectiveScrollTop, setEffectiveScrollTop] = useState(0);
|
|
521
|
-
const [viewportHeight, setViewportHeight] = useState(800);
|
|
522
|
-
|
|
523
|
-
// Keep mutable refs for values used in the scroll handler to avoid
|
|
524
|
-
// re-attaching the listener every time pagination state changes.
|
|
525
|
-
const paginationStateRef = useRef({ paginationEnabled,
|
|
526
|
-
noMoreToLoad,
|
|
527
|
-
itemCount,
|
|
528
|
-
pageSize });
|
|
529
|
-
useEffect(() => {
|
|
530
|
-
paginationStateRef.current = { paginationEnabled,
|
|
531
|
-
noMoreToLoad,
|
|
532
|
-
itemCount,
|
|
533
|
-
pageSize };
|
|
534
|
-
}, [paginationEnabled, noMoreToLoad, itemCount, pageSize]);
|
|
535
|
-
|
|
536
|
-
useEffect(() => {
|
|
537
|
-
const el = containerRef.current;
|
|
538
|
-
if (!el) return;
|
|
539
|
-
const scrollEl = getScrollParent(el);
|
|
540
|
-
if (!scrollEl) return;
|
|
541
|
-
|
|
542
|
-
let rafId: number | null = null;
|
|
543
|
-
|
|
544
|
-
const update = () => {
|
|
545
|
-
rafId = null;
|
|
546
|
-
const scrollRect = scrollEl.getBoundingClientRect();
|
|
547
|
-
const listRect = el.getBoundingClientRect();
|
|
548
|
-
|
|
549
|
-
// How much of the list has scrolled past the viewport top
|
|
550
|
-
const listTopRelative = listRect.top - scrollRect.top;
|
|
551
|
-
setEffectiveScrollTop(Math.max(0, -listTopRelative));
|
|
552
|
-
setViewportHeight(scrollRect.height);
|
|
553
|
-
|
|
554
|
-
// Infinite scroll: trigger load-more when near the bottom
|
|
555
|
-
const { paginationEnabled: pe, noMoreToLoad: nm, itemCount: ic, pageSize: ps } = paginationStateRef.current;
|
|
556
|
-
if (
|
|
557
|
-
pe &&
|
|
558
|
-
!nm &&
|
|
559
|
-
!isLoadingMore.current &&
|
|
560
|
-
scrollEl.scrollHeight - scrollEl.scrollTop - scrollEl.clientHeight < LOAD_MORE_THRESHOLD
|
|
561
|
-
) {
|
|
562
|
-
isLoadingMore.current = true;
|
|
563
|
-
setItemCount?.((ic ?? ps) + ps);
|
|
564
|
-
}
|
|
565
|
-
};
|
|
525
|
+
const selectedIds = useMemo(() => new Set(selectionController?.selectedEntities.map(e => e.id)), [selectionController?.selectedEntities]);
|
|
526
|
+
const highlightedIds = useMemo(() => new Set(highlightedEntities?.map(e => e.id)), [highlightedEntities]);
|
|
566
527
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
scrollEl.addEventListener("scroll", onScroll, { passive: true });
|
|
572
|
-
const ro = new ResizeObserver(() => update());
|
|
573
|
-
ro.observe(scrollEl);
|
|
574
|
-
update(); // initial measurement
|
|
575
|
-
|
|
576
|
-
return () => {
|
|
577
|
-
scrollEl.removeEventListener("scroll", onScroll);
|
|
578
|
-
ro.disconnect();
|
|
579
|
-
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
580
|
-
};
|
|
581
|
-
}, [setItemCount]); // stable deps only — mutable state via refs
|
|
582
|
-
|
|
583
|
-
// Compute the visible window of rows
|
|
584
|
-
const totalHeight = data.length * estimatedRowHeight;
|
|
585
|
-
const startIndex = Math.max(0, Math.floor(effectiveScrollTop / estimatedRowHeight) - OVERSCAN_COUNT);
|
|
586
|
-
const endIndex = Math.min(
|
|
587
|
-
data.length,
|
|
588
|
-
Math.ceil((effectiveScrollTop + viewportHeight) / estimatedRowHeight) + OVERSCAN_COUNT
|
|
589
|
-
);
|
|
590
|
-
const visibleData = data.slice(startIndex, endIndex);
|
|
591
|
-
const offsetY = startIndex * estimatedRowHeight;
|
|
592
|
-
|
|
593
|
-
// Footer height for loading/end indicators
|
|
594
|
-
const footerHeight = dataLoading ? 48 : (!dataLoading && noMoreToLoad && data.length > 0) ? 32 : 0;
|
|
528
|
+
const handleRowSelectionChange = useCallback((entity: Entity<M>, selected: boolean) => {
|
|
529
|
+
handleSelectionChange(entity, selected);
|
|
530
|
+
}, [handleSelectionChange]);
|
|
595
531
|
|
|
596
532
|
return (
|
|
597
|
-
<
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
{
|
|
605
|
-
{
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
!isLast && "border-b",
|
|
642
|
-
!isLast && defaultBorderMixin
|
|
643
|
-
)}
|
|
644
|
-
>
|
|
645
|
-
<ListRow
|
|
646
|
-
entity={entity}
|
|
647
|
-
collection={resolvedCollection}
|
|
648
|
-
onClick={handleEntityClick}
|
|
649
|
-
selected={isEntitySelected(entity)}
|
|
650
|
-
highlighted={isEntityHighlighted(entity)}
|
|
651
|
-
onSelectionChange={handleSelectionChange}
|
|
652
|
-
selectionEnabled={selectionEnabled}
|
|
653
|
-
columns={visibleColumns}
|
|
654
|
-
slotKeys={slotKeys}
|
|
655
|
-
rowClasses={rowClasses}
|
|
656
|
-
showImage={showImage}
|
|
657
|
-
size={size}
|
|
658
|
-
isLast={isLast}
|
|
659
|
-
isActive={selectedEntityId !== undefined && entity.id === selectedEntityId}
|
|
660
|
-
listViewActions={getListViewActions(entity)}
|
|
661
|
-
context={context}
|
|
662
|
-
path={path}
|
|
663
|
-
selectionController={selectionController}
|
|
664
|
-
openEntityMode={openEntityMode}
|
|
665
|
-
/>
|
|
666
|
-
</div>
|
|
667
|
-
);
|
|
668
|
-
})}
|
|
533
|
+
<ListView<Entity<M>>
|
|
534
|
+
data={data}
|
|
535
|
+
dataLoading={dataLoading}
|
|
536
|
+
noMoreToLoad={noMoreToLoad}
|
|
537
|
+
dataLoadingError={dataLoadingError}
|
|
538
|
+
itemCount={itemCount}
|
|
539
|
+
setItemCount={setItemCount}
|
|
540
|
+
pageSize={pageSize}
|
|
541
|
+
paginationEnabled={paginationEnabled}
|
|
542
|
+
onItemClick={handleEntityClick}
|
|
543
|
+
selectedIds={selectedIds}
|
|
544
|
+
highlightedIds={highlightedIds}
|
|
545
|
+
selectionEnabled={selectionEnabled}
|
|
546
|
+
emptyComponent={emptyComponent}
|
|
547
|
+
size={size}
|
|
548
|
+
selectedEntityId={selectedEntityId}
|
|
549
|
+
renderRow={useCallback(({ item: entity, style, className, selected, highlighted, isLast, onClick, onSelectionChange }) => {
|
|
550
|
+
return (
|
|
551
|
+
<div
|
|
552
|
+
key={entity.id}
|
|
553
|
+
style={style}
|
|
554
|
+
className={className}
|
|
555
|
+
>
|
|
556
|
+
<ListRow
|
|
557
|
+
entity={entity}
|
|
558
|
+
collection={resolvedCollection}
|
|
559
|
+
onClick={handleEntityClick}
|
|
560
|
+
selected={selected}
|
|
561
|
+
highlighted={highlighted}
|
|
562
|
+
onSelectionChange={handleRowSelectionChange}
|
|
563
|
+
selectionEnabled={selectionEnabled}
|
|
564
|
+
columns={visibleColumns}
|
|
565
|
+
slotKeys={slotKeys}
|
|
566
|
+
rowClasses={rowClasses}
|
|
567
|
+
showImage={showImage}
|
|
568
|
+
size={size}
|
|
569
|
+
isLast={isLast}
|
|
570
|
+
isActive={selectedEntityId !== undefined && entity.id === selectedEntityId}
|
|
571
|
+
listViewActions={getListViewActions(entity)}
|
|
572
|
+
context={context}
|
|
573
|
+
path={path}
|
|
574
|
+
selectionController={selectionController}
|
|
575
|
+
openEntityMode={openEntityMode}
|
|
576
|
+
/>
|
|
669
577
|
</div>
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
<div
|
|
674
|
-
className="flex items-center justify-center py-3"
|
|
675
|
-
style={{ position: "absolute",
|
|
676
|
-
top: totalHeight,
|
|
677
|
-
left: 0,
|
|
678
|
-
right: 0 }}
|
|
679
|
-
>
|
|
680
|
-
<CircularProgress size="small"/>
|
|
681
|
-
</div>
|
|
682
|
-
)}
|
|
683
|
-
{!dataLoading && noMoreToLoad && data.length > 0 && (
|
|
684
|
-
<div
|
|
685
|
-
className="flex items-center justify-center py-2 dark:bg-surface-900"
|
|
686
|
-
style={{ position: "absolute",
|
|
687
|
-
top: totalHeight,
|
|
688
|
-
left: 0,
|
|
689
|
-
right: 0 }}
|
|
690
|
-
>
|
|
691
|
-
<Typography variant="caption" color="secondary">
|
|
692
|
-
All {data.length} entries loaded
|
|
693
|
-
</Typography>
|
|
694
|
-
</div>
|
|
695
|
-
)}
|
|
696
|
-
</div>
|
|
697
|
-
)}
|
|
698
|
-
</div>
|
|
578
|
+
);
|
|
579
|
+
}, [resolvedCollection, selectionEnabled, visibleColumns, slotKeys, rowClasses, showImage, size, selectedEntityId, getListViewActions, context, path, selectionController, openEntityMode, handleRowSelectionChange, handleEntityClick])}
|
|
580
|
+
/>
|
|
699
581
|
);
|
|
700
582
|
}
|
|
701
583
|
|
|
@@ -7,10 +7,10 @@ import { useSearchParams } from "react-router-dom";
|
|
|
7
7
|
import { deepEqual as equal } from "fast-equals"
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
const EMPTY_ARRAY:
|
|
10
|
+
const EMPTY_ARRAY: never[] = [];
|
|
11
11
|
const DEFAULT_ENTITY_OPEN_MODE = "split";
|
|
12
12
|
|
|
13
|
-
import { CollectionSize, Entity, EntityReference, EntityTableController, FilterValues, PartialEntityCollection, ViewMode } from "@rebasepro/types";
|
|
13
|
+
import { CollectionSize, Entity, EntityReference, EntityTableController, FilterValues, getCollectionDataPath, PartialEntityCollection, ViewMode } from "@rebasepro/types";
|
|
14
14
|
import {
|
|
15
15
|
EntityCollectionRowActions,
|
|
16
16
|
EntityCollectionTable
|
|
@@ -163,7 +163,7 @@ const EntityCollectionViewInner = React.memo(
|
|
|
163
163
|
const collectionRegistry = useCollectionRegistryController();
|
|
164
164
|
const urlController = useUrlController();
|
|
165
165
|
const breadcrumbs = useBreadcrumbsController();
|
|
166
|
-
const path = pathProp ?? collectionProp
|
|
166
|
+
const path = pathProp ?? getCollectionDataPath(collectionProp);
|
|
167
167
|
const dataClient = useData();
|
|
168
168
|
const sideEntityController = useSideEntityController();
|
|
169
169
|
const authController = useAuthController();
|
|
@@ -215,7 +215,7 @@ const EntityCollectionViewInner = React.memo(
|
|
|
215
215
|
}, 2400);
|
|
216
216
|
}, [highlightedEntity]);
|
|
217
217
|
|
|
218
|
-
const checkInlineEditing = useCallback((entity?: Entity<
|
|
218
|
+
const checkInlineEditing = useCallback((entity?: Entity<M>): boolean => {
|
|
219
219
|
const collection = collectionRef.current;
|
|
220
220
|
if (!canEdit(collection, path, entity ?? null)) {
|
|
221
221
|
return false;
|
|
@@ -894,7 +894,7 @@ parentEntityIds,
|
|
|
894
894
|
collection={collection}
|
|
895
895
|
tableController={tableController}
|
|
896
896
|
path={path}
|
|
897
|
-
relativePath={collection
|
|
897
|
+
relativePath={getCollectionDataPath(collection)}
|
|
898
898
|
selectionController={usedSelectionController}
|
|
899
899
|
collectionEntitiesCount={docsCount ?? undefined}
|
|
900
900
|
resolvedProperties={resolvedCollection.properties}
|
|
@@ -909,7 +909,7 @@ parentEntityIds,
|
|
|
909
909
|
onNewClick={onNewClick}
|
|
910
910
|
openNewDocument={openNewDocument}
|
|
911
911
|
path={path}
|
|
912
|
-
relativePath={collection
|
|
912
|
+
relativePath={getCollectionDataPath(collection)}
|
|
913
913
|
selectionController={usedSelectionController}
|
|
914
914
|
selectionEnabled={activeSelectionEnabled}
|
|
915
915
|
collectionEntitiesCount={docsCount ?? undefined}
|
|
@@ -1301,25 +1301,8 @@ function EntitiesCount({
|
|
|
1301
1301
|
|
|
1302
1302
|
let cancelled = false;
|
|
1303
1303
|
|
|
1304
|
-
//
|
|
1305
|
-
const
|
|
1306
|
-
if (filter) {
|
|
1307
|
-
Object.entries(filter).forEach(([key, value]) => {
|
|
1308
|
-
if (value && Array.isArray(value)) {
|
|
1309
|
-
const [op, val] = value;
|
|
1310
|
-
const postgrestOp = op === "==" ? "eq" : op === "!=" ? "neq" : op === ">" ? "gt" : op === ">=" ? "gte" : op === "<" ? "lt" : op === "<=" ? "lte" : op === "in" ? "in" : op === "not-in" ? "nin" : op === "array-contains" ? "cs" : op === "array-contains-any" ? "csa" : "eq";
|
|
1311
|
-
|
|
1312
|
-
let stringVal: string;
|
|
1313
|
-
if (Array.isArray(val)) {
|
|
1314
|
-
stringVal = `(${val.join(",")})`;
|
|
1315
|
-
} else {
|
|
1316
|
-
stringVal = String(val);
|
|
1317
|
-
}
|
|
1318
|
-
whereMap[key] = `${postgrestOp}.${stringVal}`;
|
|
1319
|
-
}
|
|
1320
|
-
});
|
|
1321
|
-
}
|
|
1322
|
-
const whereParams = Object.keys(whereMap).length > 0 ? whereMap : undefined;
|
|
1304
|
+
// filterValues is already FilterValues — pass directly
|
|
1305
|
+
const whereParams = filter && Object.keys(filter).length > 0 ? filter : undefined;
|
|
1323
1306
|
const orderByParams = sortByProperty ? `${String(sortByProperty)}:${currentSort}` : undefined;
|
|
1324
1307
|
|
|
1325
1308
|
// Deduplicate inflight count requests (e.g. React StrictMode double-mount)
|
|
@@ -22,7 +22,7 @@ export function useCollectionInlineEditor<M extends Record<string, unknown>>({
|
|
|
22
22
|
async ({ name, value, property, entityId }: Parameters<UniqueFieldValidator>[0]) => {
|
|
23
23
|
const accessor = dataClient.collection(path);
|
|
24
24
|
const res = await accessor.find({
|
|
25
|
-
where: { [name]: "
|
|
25
|
+
where: { [name]: ["==", value] }
|
|
26
26
|
});
|
|
27
27
|
|
|
28
28
|
const conflictingEntities = res.data;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useCallback, useMemo } from "react";
|
|
2
2
|
import { setIn } from "@rebasepro/formex";
|
|
3
|
-
import { EntityCollection, SaveEntityProps, RebaseData, RebaseContext, AnalyticsController } from "@rebasepro/types";
|
|
3
|
+
import { EntityCollection, SaveEntityProps, RebaseData, RebaseContext, AnalyticsController, Entity } from "@rebasepro/types";
|
|
4
4
|
import { saveEntityWithCallbacks } from "@rebasepro/core";
|
|
5
|
-
import { BoardItem } from "
|
|
5
|
+
import { BoardItem } from "@rebasepro/ui";
|
|
6
6
|
import { BoardDataController } from "../useBoardDataController";
|
|
7
7
|
import { generateKeyBetween } from "fractional-indexing";
|
|
8
8
|
|
|
@@ -33,10 +33,10 @@ export function useKanbanDragAndDrop<M extends Record<string, unknown>>({
|
|
|
33
33
|
// to compute a single new sort key for the moved item.
|
|
34
34
|
// Only one DB write per drag — the moved item gets its new key.
|
|
35
35
|
const handleItemsReorder = useCallback(async (
|
|
36
|
-
items: BoardItem<M
|
|
36
|
+
items: BoardItem<Entity<M>>[],
|
|
37
37
|
moveInfo?: { itemId: string; sourceColumn: string; targetColumn: string; }
|
|
38
38
|
) => {
|
|
39
|
-
const entity = items.find(item => item.id === moveInfo?.itemId)?.
|
|
39
|
+
const entity = items.find(item => item.id === moveInfo?.itemId)?.data;
|
|
40
40
|
if (!entity || !moveInfo) return;
|
|
41
41
|
|
|
42
42
|
analyticsController.onAnalyticsEvent?.("kanban_card_moved", {
|
|
@@ -64,10 +64,10 @@ export function useKanbanDragAndDrop<M extends Record<string, unknown>>({
|
|
|
64
64
|
|
|
65
65
|
// Get the order keys of the neighbours
|
|
66
66
|
const prevKey = movedIndex > 0
|
|
67
|
-
? (targetColumnItems[movedIndex - 1].
|
|
67
|
+
? (targetColumnItems[movedIndex - 1].data.values?.[orderProperty] as string | null) ?? null
|
|
68
68
|
: null;
|
|
69
69
|
const nextKey = movedIndex < targetColumnItems.length - 1
|
|
70
|
-
? (targetColumnItems[movedIndex + 1].
|
|
70
|
+
? (targetColumnItems[movedIndex + 1].data.values?.[orderProperty] as string | null) ?? null
|
|
71
71
|
: null;
|
|
72
72
|
|
|
73
73
|
try {
|
|
@@ -238,25 +238,11 @@ export function useBoardDataController<M extends Record<string, unknown> = any,
|
|
|
238
238
|
return;
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
-
// Build
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
const [op, val] = value;
|
|
247
|
-
const postgrestOp = op === "==" ? "eq" : op === "!=" ? "neq" : op === ">" ? "gt" : op === ">=" ? "gte" : op === "<" ? "lt" : op === "<=" ? "lte" : op === "in" ? "in" : op === "not-in" ? "nin" : op === "array-contains" ? "cs" : op === "array-contains-any" ? "csa" : "eq";
|
|
248
|
-
|
|
249
|
-
let stringVal: string;
|
|
250
|
-
if (Array.isArray(val)) {
|
|
251
|
-
stringVal = `(${val.join(",")})`;
|
|
252
|
-
} else {
|
|
253
|
-
stringVal = String(val);
|
|
254
|
-
}
|
|
255
|
-
whereMap[key] = `${postgrestOp}.${stringVal}`;
|
|
256
|
-
}
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
whereMap[currentColumnProperty] = `eq.${column}`;
|
|
241
|
+
// Build filter map for this column — pass FilterValues directly
|
|
242
|
+
const whereFilter: FilterValues<string> = {
|
|
243
|
+
...(currentFilterValues ?? {}),
|
|
244
|
+
[currentColumnProperty]: ["==", column]
|
|
245
|
+
};
|
|
260
246
|
|
|
261
247
|
const orderByParam = currentOrderProperty ? `${currentOrderProperty}:asc` : undefined;
|
|
262
248
|
|
|
@@ -420,14 +406,14 @@ values: { ...e.values,
|
|
|
420
406
|
const accessor = currentDataClient.collection(currentResolvedPath);
|
|
421
407
|
if (accessor.listen) {
|
|
422
408
|
const unsubscribe = accessor.listen({
|
|
423
|
-
where:
|
|
409
|
+
where: whereFilter,
|
|
424
410
|
limit: itemCount,
|
|
425
411
|
orderBy: orderByParam
|
|
426
412
|
}, res => onUpdate(res.data as Entity<M>[]), onError);
|
|
427
413
|
unsubscribersRef.current[column] = unsubscribe;
|
|
428
414
|
} else {
|
|
429
415
|
accessor.find({
|
|
430
|
-
where:
|
|
416
|
+
where: whereFilter,
|
|
431
417
|
limit: itemCount,
|
|
432
418
|
orderBy: orderByParam
|
|
433
419
|
})
|
|
@@ -479,27 +465,13 @@ values: { ...e.values,
|
|
|
479
465
|
const accessor = currentDataClient.collection(currentResolvedPath);
|
|
480
466
|
if (accessor.count) {
|
|
481
467
|
|
|
482
|
-
const
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
const [op, val] = value;
|
|
487
|
-
const postgrestOp = op === "==" ? "eq" : op === "!=" ? "neq" : op === ">" ? "gt" : op === ">=" ? "gte" : op === "<" ? "lt" : op === "<=" ? "lte" : op === "in" ? "in" : op === "not-in" ? "nin" : op === "array-contains" ? "cs" : op === "array-contains-any" ? "csa" : "eq";
|
|
488
|
-
|
|
489
|
-
let stringVal: string;
|
|
490
|
-
if (Array.isArray(val)) {
|
|
491
|
-
stringVal = `(${val.join(",")})`;
|
|
492
|
-
} else {
|
|
493
|
-
stringVal = String(val);
|
|
494
|
-
}
|
|
495
|
-
whereMap[key] = `${postgrestOp}.${stringVal}`;
|
|
496
|
-
}
|
|
497
|
-
});
|
|
498
|
-
}
|
|
499
|
-
whereMap[currentColumnProperty] = `eq.${column}`;
|
|
468
|
+
const whereFilter: FilterValues<string> = {
|
|
469
|
+
...(currentFilterValues ?? {}),
|
|
470
|
+
[currentColumnProperty]: ["==", column]
|
|
471
|
+
};
|
|
500
472
|
|
|
501
473
|
accessor.count({
|
|
502
|
-
where:
|
|
474
|
+
where: whereFilter
|
|
503
475
|
}).then(count => {
|
|
504
476
|
if (isCleaningUpRef.current) return;
|
|
505
477
|
setColumnData(prev => ({
|
|
@@ -194,8 +194,8 @@ export function resolveCollectionSlotKeys(
|
|
|
194
194
|
: [...previewKeys].sort((a, b) => {
|
|
195
195
|
const propA = collection.properties[a] as Property | undefined;
|
|
196
196
|
const propB = collection.properties[b] as Property | undefined;
|
|
197
|
-
const scoreA = propA?.type === "string" ? (propA.multiline ? 2 : 1) : 0;
|
|
198
|
-
const scoreB = propB?.type === "string" ? (propB.multiline ? 2 : 1) : 0;
|
|
197
|
+
const scoreA = propA?.type === "string" ? (propA.ui?.multiline ? 2 : 1) : 0;
|
|
198
|
+
const scoreB = propB?.type === "string" ? (propB.ui?.multiline ? 2 : 1) : 0;
|
|
199
199
|
return scoreB - scoreA;
|
|
200
200
|
});
|
|
201
201
|
const subtitleKey = sortedPreviewKeys.length > 0 ? sortedPreviewKeys[0] : undefined;
|
|
@@ -468,7 +468,7 @@ function resolveRelationDisplayName(
|
|
|
468
468
|
|
|
469
469
|
// Helper to check if a property is a visible, non-id string
|
|
470
470
|
const isDisplayCandidate = (p: Property): boolean => {
|
|
471
|
-
return p.type === "string" && !p.multiline && !p.markdown && !p.storage
|
|
471
|
+
return p.type === "string" && !p.ui?.multiline && !p.ui?.markdown && !p.storage
|
|
472
472
|
&& !("isId" in p && p.isId) && !isHiddenProp(p);
|
|
473
473
|
};
|
|
474
474
|
|
|
@@ -2,7 +2,7 @@ import type { ComponentRef, EntityCollection, EntityCustomViewParams, FormViewCo
|
|
|
2
2
|
import type { FormContext } from "../types/fields";
|
|
3
3
|
import type { PluginFormActionProps } from "@rebasepro/types";
|
|
4
4
|
import React, { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
5
|
-
import { Entity, EntityStatus, Property } from "@rebasepro/types";
|
|
5
|
+
import { Entity, EntityStatus, getCollectionDataPath, Property } from "@rebasepro/types";
|
|
6
6
|
import { PluginProviderStack, resolveComponentRef, useComponentOverride, CollectionComponentOverrideProvider } from "@rebasepro/core";
|
|
7
7
|
|
|
8
8
|
import { EntityCollectionView, EntityView } from "../components";
|
|
@@ -347,7 +347,7 @@ entityId }
|
|
|
347
347
|
// Subcollection views
|
|
348
348
|
const subCollectionsViews = subcollections && subcollections.map((subcollection) => {
|
|
349
349
|
const subcollectionId = subcollection.slug;
|
|
350
|
-
const newFullPath = usedEntity ? `${path}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(subcollection
|
|
350
|
+
const newFullPath = usedEntity ? `${path}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(getCollectionDataPath(subcollection))}` : undefined;
|
|
351
351
|
|
|
352
352
|
if (activeTab !== subcollectionId) return null;
|
|
353
353
|
return (
|
|
@@ -2,7 +2,7 @@ import type { ComponentRef, EntityCollection, EntityCustomViewParams, FormViewCo
|
|
|
2
2
|
import type { FormContext } from "../types/fields";
|
|
3
3
|
import type { PluginFormActionProps } from "@rebasepro/types";
|
|
4
4
|
import React, { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
5
|
-
import { Entity, EntityStatus } from "@rebasepro/types";
|
|
5
|
+
import { Entity, EntityStatus, getCollectionDataPath } from "@rebasepro/types";
|
|
6
6
|
import { PluginProviderStack, resolveComponentRef, useComponentOverride, CollectionComponentOverrideProvider } from "@rebasepro/core";
|
|
7
7
|
|
|
8
8
|
import { EntityCollectionView, EntityView } from "../components";
|
|
@@ -39,8 +39,9 @@ import {
|
|
|
39
39
|
getIcon
|
|
40
40
|
} from "@rebasepro/core";
|
|
41
41
|
import { getEntityFromMemoryCache } from "@rebasepro/core";
|
|
42
|
-
import {
|
|
43
|
-
import type {
|
|
42
|
+
import { EntityFormBinding } from "../form";
|
|
43
|
+
import type { EntityFormBindingProps } from "../form";
|
|
44
|
+
import type { OnUpdateParams } from "../types/components/EntityFormProps";
|
|
44
45
|
import { EntityEditViewFormActions } from "./EntityEditViewFormActions";
|
|
45
46
|
import { EntityJsonPreview } from "../components/EntityJsonPreview";
|
|
46
47
|
// Lazy-load history view — only loaded when user clicks the HistoryIcon tab
|
|
@@ -85,7 +86,7 @@ export interface EntityEditViewProps<M extends Record<string, unknown> = Record<
|
|
|
85
86
|
navigateBack?: () => void;
|
|
86
87
|
layout?: "side_panel" | "full_screen" | "split" | "dialog";
|
|
87
88
|
barActions?: (params: BarActionsParams) => React.ReactNode;
|
|
88
|
-
formProps?: Partial<
|
|
89
|
+
formProps?: Partial<EntityFormBindingProps<M>>,
|
|
89
90
|
/**
|
|
90
91
|
* Pre-populate the form with these values when creating a new entity.
|
|
91
92
|
* Only applied when the form is in "new" mode (no entityId).
|
|
@@ -197,7 +198,7 @@ export function EntityEditViewInner<M extends Record<string, unknown>>({
|
|
|
197
198
|
}) {
|
|
198
199
|
|
|
199
200
|
const ResolvedFormActions = useComponentOverride("Entity.FormActions", EntityEditViewFormActions);
|
|
200
|
-
const ResolvedEntityForm = useComponentOverride("Entity.Form",
|
|
201
|
+
const ResolvedEntityForm = useComponentOverride("Entity.Form", EntityFormBinding) as typeof EntityFormBinding;
|
|
201
202
|
const ResolvedCollectionView = useComponentOverride("Collection.View", EntityCollectionView);
|
|
202
203
|
|
|
203
204
|
const context = useRebaseContext();
|
|
@@ -415,7 +416,7 @@ parentEntityIds,
|
|
|
415
416
|
|
|
416
417
|
const subCollectionsViews = subcollections && subcollections.map((subcollection) => {
|
|
417
418
|
const subcollectionId = subcollection.slug;
|
|
418
|
-
const newFullPath = usedEntity ? `${path}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(subcollection
|
|
419
|
+
const newFullPath = usedEntity ? `${path}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(getCollectionDataPath(subcollection))}` : undefined;
|
|
419
420
|
|
|
420
421
|
if (activeTab !== subcollectionId) return null;
|
|
421
422
|
return (
|