@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
|
@@ -16,7 +16,7 @@ export type EntityCollectionViewStartActionsProps<M extends Record<string, unkno
|
|
|
16
16
|
collection: EntityCollection<M>;
|
|
17
17
|
path: string;
|
|
18
18
|
relativePath: string;
|
|
19
|
-
|
|
19
|
+
parentCollectionSlugs: string[], parentEntityIds: string[];
|
|
20
20
|
selectionController: SelectionController<M>;
|
|
21
21
|
tableController: EntityTableController<M>;
|
|
22
22
|
collectionEntitiesCount?: number;
|
|
@@ -25,18 +25,20 @@ export type EntityCollectionViewStartActionsProps<M extends Record<string, unkno
|
|
|
25
25
|
*/
|
|
26
26
|
resolvedProperties?: Properties;
|
|
27
27
|
compact?: boolean;
|
|
28
|
+
openNewDocument: (defaultValues?: Record<string, unknown>) => void;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
export function EntityCollectionViewStartActions<M extends Record<string, unknown>>({
|
|
31
32
|
collection,
|
|
32
33
|
relativePath,
|
|
33
|
-
|
|
34
|
+
parentCollectionSlugs, parentEntityIds,
|
|
34
35
|
path,
|
|
35
36
|
selectionController,
|
|
36
37
|
tableController,
|
|
37
38
|
collectionEntitiesCount,
|
|
38
39
|
resolvedProperties,
|
|
39
|
-
compact
|
|
40
|
+
compact,
|
|
41
|
+
openNewDocument
|
|
40
42
|
}: EntityCollectionViewStartActionsProps<M>) {
|
|
41
43
|
|
|
42
44
|
const context = useCMSContext();
|
|
@@ -51,24 +53,30 @@ export function EntityCollectionViewStartActions<M extends Record<string, unknow
|
|
|
51
53
|
|
|
52
54
|
// Count active filters (excluding force filters)
|
|
53
55
|
const filterValues = tableController.filterValues;
|
|
54
|
-
const
|
|
56
|
+
const fixedFilter = collection.fixedFilter;
|
|
55
57
|
const activeFilterCount = filterValues
|
|
56
|
-
? Object.keys(filterValues).filter(key => !
|
|
58
|
+
? Object.keys(filterValues).filter(key => !fixedFilter || !(key in fixedFilter)).length
|
|
57
59
|
: 0;
|
|
58
60
|
|
|
59
61
|
const actionProps: CollectionActionsProps<M> = {
|
|
60
62
|
path,
|
|
61
63
|
relativePath,
|
|
62
|
-
|
|
64
|
+
parentCollectionSlugs, parentEntityIds,
|
|
63
65
|
collection,
|
|
64
66
|
selectionController,
|
|
65
67
|
context,
|
|
66
68
|
tableController,
|
|
67
|
-
collectionEntitiesCount
|
|
69
|
+
collectionEntitiesCount,
|
|
70
|
+
openNewDocument
|
|
68
71
|
};
|
|
69
72
|
|
|
70
73
|
const handleBackClick = useCallback(() => {
|
|
71
|
-
|
|
74
|
+
let collectionUrl = urlController.buildUrlCollectionPath(path);
|
|
75
|
+
// Preserve the __view query param so the view mode is retained
|
|
76
|
+
const currentViewParam = new URLSearchParams(window.location.search).get("__view");
|
|
77
|
+
if (currentViewParam) {
|
|
78
|
+
collectionUrl += `${collectionUrl.includes("?") ? "&" : "?"}__view=${currentViewParam}`;
|
|
79
|
+
}
|
|
72
80
|
navigate(collectionUrl);
|
|
73
81
|
}, [navigate, urlController, path]);
|
|
74
82
|
|
|
@@ -103,13 +111,14 @@ export function EntityCollectionViewStartActions<M extends Record<string, unknow
|
|
|
103
111
|
{t("filters")}{activeFilterCount > 0 ? ` (${activeFilterCount})` : ""}
|
|
104
112
|
</Button>
|
|
105
113
|
) : (
|
|
106
|
-
<
|
|
114
|
+
<Button
|
|
115
|
+
variant="text"
|
|
107
116
|
size="small"
|
|
108
117
|
onClick={() => setFiltersDialogOpen(true)}
|
|
109
118
|
className={cls(activeFilterCount > 0 && "text-primary")}
|
|
110
119
|
>
|
|
111
120
|
<FilterIcon size={iconSize.small}/>
|
|
112
|
-
</
|
|
121
|
+
</Button>
|
|
113
122
|
)}
|
|
114
123
|
</Badge>
|
|
115
124
|
</Tooltip>
|
|
@@ -121,7 +130,7 @@ export function EntityCollectionViewStartActions<M extends Record<string, unknow
|
|
|
121
130
|
<ClearFilterSortButton
|
|
122
131
|
key={"clear_filter"}
|
|
123
132
|
tableController={tableController}
|
|
124
|
-
enabled={!collection.
|
|
133
|
+
enabled={!collection.fixedFilter}/>
|
|
125
134
|
];
|
|
126
135
|
|
|
127
136
|
const pluginActionsStart = useSlot("collection.actions.start", actionProps);
|
|
@@ -139,7 +148,7 @@ export function EntityCollectionViewStartActions<M extends Record<string, unknow
|
|
|
139
148
|
properties={resolvedProperties}
|
|
140
149
|
filterValues={tableController.filterValues}
|
|
141
150
|
setFilterValues={(filterValues) => tableController.setFilterValues?.(filterValues ?? {})}
|
|
142
|
-
|
|
151
|
+
fixedFilter={collection.fixedFilter}
|
|
143
152
|
/>
|
|
144
153
|
)}
|
|
145
154
|
</>
|
|
@@ -18,7 +18,7 @@ export interface FiltersDialogProps {
|
|
|
18
18
|
properties: Record<string, Property>;
|
|
19
19
|
filterValues: FilterValues<any> | undefined;
|
|
20
20
|
setFilterValues: (filterValues?: FilterValues<any>) => void;
|
|
21
|
-
|
|
21
|
+
fixedFilter?: FilterValues<any>;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/**
|
|
@@ -31,7 +31,7 @@ export function FiltersDialog({
|
|
|
31
31
|
properties,
|
|
32
32
|
filterValues,
|
|
33
33
|
setFilterValues,
|
|
34
|
-
|
|
34
|
+
fixedFilter
|
|
35
35
|
}: FiltersDialogProps) {
|
|
36
36
|
const { t } = useTranslation();
|
|
37
37
|
// Local state for filters being edited
|
|
@@ -52,13 +52,13 @@ export function FiltersDialog({
|
|
|
52
52
|
return Object.entries(properties).filter(([key, property]) => {
|
|
53
53
|
if (!property) return false;
|
|
54
54
|
// Force filter properties should not be editable
|
|
55
|
-
if (
|
|
55
|
+
if (fixedFilter && key in fixedFilter) return false;
|
|
56
56
|
// Check if property type is filterable
|
|
57
57
|
const baseProperty = property.type === "array" ? property.of : property;
|
|
58
58
|
if (!baseProperty || Array.isArray(baseProperty)) return false;
|
|
59
59
|
return ["string", "number", "boolean", "date", "reference"].includes(baseProperty.type);
|
|
60
60
|
});
|
|
61
|
-
}, [properties,
|
|
61
|
+
}, [properties, fixedFilter]);
|
|
62
62
|
|
|
63
63
|
const handleFilterChange = useCallback((propertyKey: string, value?: [VirtualTableWhereFilterOp, any]) => {
|
|
64
64
|
setLocalFilters(prev => {
|
|
@@ -75,9 +75,9 @@ export function FiltersDialog({
|
|
|
75
75
|
const handleApply = useCallback(() => {
|
|
76
76
|
const hasFilters = Object.keys(localFilters).length > 0;
|
|
77
77
|
setFilterValues(hasFilters ? { ...localFilters,
|
|
78
|
-
...
|
|
78
|
+
...fixedFilter } : (fixedFilter || undefined));
|
|
79
79
|
onOpenChange(false);
|
|
80
|
-
}, [localFilters, setFilterValues,
|
|
80
|
+
}, [localFilters, setFilterValues, fixedFilter, onOpenChange]);
|
|
81
81
|
|
|
82
82
|
const handleClearAll = useCallback(() => {
|
|
83
83
|
setLocalFilters({});
|
|
@@ -114,7 +114,7 @@ export function FiltersDialog({
|
|
|
114
114
|
path={baseProperty.path}
|
|
115
115
|
title={property.name}
|
|
116
116
|
includeId={baseProperty.includeId}
|
|
117
|
-
previewProperties={baseProperty.previewProperties}
|
|
117
|
+
previewProperties={baseProperty.ui?.previewProperties}
|
|
118
118
|
hidden={hiddenFields[propertyKey] ?? false}
|
|
119
119
|
setHidden={(hidden) => setHiddenForField(propertyKey, hidden)}
|
|
120
120
|
/>
|
|
@@ -30,7 +30,7 @@ export type SplitListViewProps<M extends Record<string, unknown> = Record<string
|
|
|
30
30
|
initialScroll?: number;
|
|
31
31
|
size?: CollectionSize;
|
|
32
32
|
path: string;
|
|
33
|
-
|
|
33
|
+
parentCollectionSlugs?: string[], parentEntityIds?: string[];
|
|
34
34
|
/**
|
|
35
35
|
* The entity ID to show in the detail panel.
|
|
36
36
|
* Comes from the URL path (e.g. /c/authors/14 → selectedEntityId = "14").
|
|
@@ -99,7 +99,7 @@ export function SplitListView<M extends Record<string, unknown> = Record<string,
|
|
|
99
99
|
initialScroll,
|
|
100
100
|
size = "m",
|
|
101
101
|
path,
|
|
102
|
-
|
|
102
|
+
parentCollectionSlugs, parentEntityIds,
|
|
103
103
|
selectedEntityId,
|
|
104
104
|
selectedTab,
|
|
105
105
|
toolbar,
|
|
@@ -169,7 +169,12 @@ export function SplitListView<M extends Record<string, unknown> = Record<string,
|
|
|
169
169
|
|
|
170
170
|
// Close the detail panel: navigate back to the collection path
|
|
171
171
|
const handleCloseDetail = useCallback(() => {
|
|
172
|
-
|
|
172
|
+
let collectionUrl = urlController.buildUrlCollectionPath(path);
|
|
173
|
+
// Preserve the __view query param so the view mode is retained
|
|
174
|
+
const currentViewParam = new URLSearchParams(window.location.search).get("__view");
|
|
175
|
+
if (currentViewParam) {
|
|
176
|
+
collectionUrl += `${collectionUrl.includes("?") ? "&" : "?"}__view=${currentViewParam}`;
|
|
177
|
+
}
|
|
173
178
|
navigate(collectionUrl);
|
|
174
179
|
}, [navigate, urlController, path]);
|
|
175
180
|
|
|
@@ -246,7 +251,8 @@ export function SplitListView<M extends Record<string, unknown> = Record<string,
|
|
|
246
251
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
247
252
|
}, [selectedEntityId, handleCloseDetail, externalOnEntityClick, externalOnNewClick, entityIds, tableController.data]);
|
|
248
253
|
|
|
249
|
-
const usedParentCollectionIds =
|
|
254
|
+
const usedParentCollectionIds = parentCollectionSlugs ?? collectionRegistryController.getParentCollectionSlugs(path);
|
|
255
|
+
const usedParentEntityIds = parentEntityIds ?? collectionRegistryController.getParentEntityIds(path);
|
|
250
256
|
|
|
251
257
|
const isDetailVisible = animationPhase !== "idle";
|
|
252
258
|
|
|
@@ -255,15 +261,19 @@ export function SplitListView<M extends Record<string, unknown> = Record<string,
|
|
|
255
261
|
const listPanel = (
|
|
256
262
|
<div
|
|
257
263
|
className={cls(
|
|
258
|
-
"flex flex-col h-full
|
|
264
|
+
"flex flex-col h-full min-w-0 transition-all ease-out w-full",
|
|
259
265
|
(!largeLayout && isDetailVisible)
|
|
260
266
|
? "opacity-0 -translate-x-1/3 pointer-events-none"
|
|
261
267
|
: "opacity-100 translate-x-0"
|
|
262
268
|
)}
|
|
263
269
|
style={{ transitionDuration: `${TRANSITION_DURATION}ms` }}
|
|
264
270
|
>
|
|
271
|
+
{/* Toolbar stays fixed above the scrollable area */}
|
|
265
272
|
{toolbar}
|
|
266
|
-
{
|
|
273
|
+
{/* Scrollable content: title + insights + list rows */}
|
|
274
|
+
<div className="flex-1 overflow-y-auto overflow-x-hidden min-h-0">
|
|
275
|
+
{children}
|
|
276
|
+
</div>
|
|
267
277
|
</div>
|
|
268
278
|
);
|
|
269
279
|
|
|
@@ -283,16 +293,22 @@ export function SplitListView<M extends Record<string, unknown> = Record<string,
|
|
|
283
293
|
path={path}
|
|
284
294
|
collection={collection as EntityCollection<Record<string, unknown>>}
|
|
285
295
|
entityId={renderedEntityId}
|
|
286
|
-
|
|
296
|
+
parentCollectionSlugs={usedParentCollectionIds}
|
|
297
|
+
parentEntityIds={usedParentEntityIds}
|
|
287
298
|
selectedTab={selectedTab}
|
|
288
299
|
layout="split"
|
|
289
300
|
onTabChange={(params) => {
|
|
290
301
|
const newSelectedTab = params.selectedTab;
|
|
291
|
-
|
|
302
|
+
let entityUrl = urlController.buildUrlCollectionPath(
|
|
292
303
|
newSelectedTab
|
|
293
304
|
? `${path}/${renderedEntityId}/${newSelectedTab}`
|
|
294
305
|
: `${path}/${renderedEntityId}`
|
|
295
306
|
);
|
|
307
|
+
// Preserve the __view query param
|
|
308
|
+
const currentViewParam = new URLSearchParams(window.location.search).get("__view");
|
|
309
|
+
if (currentViewParam) {
|
|
310
|
+
entityUrl += `${entityUrl.includes("?") ? "&" : "?"}__view=${currentViewParam}`;
|
|
311
|
+
}
|
|
296
312
|
navigate(entityUrl);
|
|
297
313
|
}}
|
|
298
314
|
/>
|
|
@@ -110,11 +110,39 @@ export function resolveCollectionSlotKeys(
|
|
|
110
110
|
|
|
111
111
|
// Status: first string-enum that isn't the title
|
|
112
112
|
let statusKey: string | undefined;
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
113
|
+
|
|
114
|
+
// 1. Explicitly defined in previewProperties
|
|
115
|
+
if (!statusKey && collection.previewProperties) {
|
|
116
|
+
for (const key of collection.previewProperties) {
|
|
117
|
+
const p = collection.properties[key] as Property | undefined;
|
|
118
|
+
if (p?.type === "string" && "enum" in p && p.enum && key !== titleKey) {
|
|
119
|
+
statusKey = key;
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 2. Explicitly defined in propertiesOrder
|
|
126
|
+
if (!statusKey && collection.propertiesOrder) {
|
|
127
|
+
for (const key of collection.propertiesOrder) {
|
|
128
|
+
if (typeof key === "string" && !key.startsWith("subcollection:")) {
|
|
129
|
+
const p = collection.properties[key] as Property | undefined;
|
|
130
|
+
if (p?.type === "string" && "enum" in p && p.enum && key !== titleKey) {
|
|
131
|
+
statusKey = key;
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// 3. Default automatic inference
|
|
139
|
+
if (!statusKey) {
|
|
140
|
+
for (const [key, prop] of Object.entries(collection.properties)) {
|
|
141
|
+
const p = prop as Property;
|
|
142
|
+
if (p.type === "string" && "enum" in p && p.enum && key !== titleKey) {
|
|
143
|
+
statusKey = key;
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
118
146
|
}
|
|
119
147
|
}
|
|
120
148
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { EntityCollection, EntityCustomViewParams } from "@rebasepro/types";
|
|
1
|
+
import type { ComponentRef, EntityCollection, EntityCustomViewParams } from "@rebasepro/types";
|
|
2
2
|
import type { FormContext } from "../types/fields";
|
|
3
3
|
import type { PluginFormActionProps } from "@rebasepro/types";
|
|
4
|
-
import React, { lazy, Suspense, useEffect, useMemo, useState } from "react";
|
|
4
|
+
import React, { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
5
5
|
import { Entity, EntityStatus } from "@rebasepro/types";
|
|
6
|
-
import { PluginProviderStack } from "@rebasepro/core";
|
|
6
|
+
import { PluginProviderStack, resolveComponentRef } from "@rebasepro/core";
|
|
7
7
|
|
|
8
8
|
import { EntityCollectionView, EntityView } from "../components";
|
|
9
9
|
import { CircularProgressCenter, iconSize } from "@rebasepro/ui";
|
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
resolveDefaultSelectedView
|
|
17
17
|
} from "@rebasepro/common";
|
|
18
18
|
import { resolvedSelectedEntityView } from "../util/resolutions";
|
|
19
|
-
import { getEntityTitlePropertyKey } from "../util/previews";
|
|
20
19
|
import { CenteredView, CircularProgress, cls, defaultBorderMixin, IconButton, Tab, Tabs, Tooltip, Typography, Skeleton } from "@rebasepro/ui";
|
|
21
20
|
import {
|
|
22
21
|
useCustomizationController,
|
|
@@ -66,13 +65,19 @@ export interface EntityEditViewProps<M extends Record<string, unknown> = Record<
|
|
|
66
65
|
databaseId?: string;
|
|
67
66
|
copy?: boolean;
|
|
68
67
|
selectedTab?: string;
|
|
69
|
-
|
|
68
|
+
parentCollectionSlugs: string[], parentEntityIds: string[];
|
|
70
69
|
onValuesModified?: (modified: boolean, values: M) => void;
|
|
71
70
|
onSaved?: (params: OnUpdateParams) => void;
|
|
72
71
|
onTabChange?: (props: OnTabChangeParams<M>) => void;
|
|
73
72
|
layout?: "side_panel" | "full_screen" | "split";
|
|
74
73
|
barActions?: (params: BarActionsParams) => any;
|
|
75
74
|
formProps?: Partial<EntityFormProps<M>>,
|
|
75
|
+
/**
|
|
76
|
+
* Pre-populate the form with these values when creating a new entity.
|
|
77
|
+
* Only applied when the form is in "new" mode (no entityId).
|
|
78
|
+
* Sourced from EntitySidePanelProps (side panel) or location.state (full screen).
|
|
79
|
+
*/
|
|
80
|
+
defaultValues?: Partial<M>;
|
|
76
81
|
}
|
|
77
82
|
|
|
78
83
|
/**
|
|
@@ -99,7 +104,7 @@ export function EntityEditView<M extends Record<string, unknown>>({
|
|
|
99
104
|
|
|
100
105
|
const initialDirtyValues = entityId
|
|
101
106
|
? getEntityFromMemoryCache(props.path + "/" + entityId)
|
|
102
|
-
: getEntityFromMemoryCache(props.path + "#new");
|
|
107
|
+
: (props.defaultValues ?? getEntityFromMemoryCache(props.path + "#new"));
|
|
103
108
|
|
|
104
109
|
const { canEdit: canEditHook } = usePermissions();
|
|
105
110
|
|
|
@@ -143,7 +148,7 @@ export function EntityEditViewInner<M extends Record<string, unknown>>({
|
|
|
143
148
|
entityId,
|
|
144
149
|
selectedTab: selectedTabProp,
|
|
145
150
|
collection,
|
|
146
|
-
|
|
151
|
+
parentCollectionSlugs, parentEntityIds,
|
|
147
152
|
onValuesModified,
|
|
148
153
|
onSaved,
|
|
149
154
|
onTabChange,
|
|
@@ -183,9 +188,9 @@ export function EntityEditViewInner<M extends Record<string, unknown>>({
|
|
|
183
188
|
const customizationController = useCustomizationController();
|
|
184
189
|
const plugins = customizationController.plugins;
|
|
185
190
|
|
|
186
|
-
const formActionTopProps: PluginFormActionProps = {
|
|
191
|
+
const formActionTopProps: PluginFormActionProps = useMemo(() => ({
|
|
187
192
|
entityId,
|
|
188
|
-
|
|
193
|
+
parentCollectionSlugs, parentEntityIds,
|
|
189
194
|
path: path,
|
|
190
195
|
status,
|
|
191
196
|
collection: collection!,
|
|
@@ -193,7 +198,7 @@ export function EntityEditViewInner<M extends Record<string, unknown>>({
|
|
|
193
198
|
formContext: formContext as FormContext<Record<string, unknown>> | undefined,
|
|
194
199
|
openEntityMode: layout,
|
|
195
200
|
disabled: false
|
|
196
|
-
};
|
|
201
|
+
}), [entityId, parentCollectionSlugs, parentEntityIds, path, status, collection, context, formContext, layout]);
|
|
197
202
|
const pluginActionsTop = useSlot("form.actions.top", formActionTopProps);
|
|
198
203
|
|
|
199
204
|
const defaultSelectedView = useMemo(() => resolveDefaultSelectedView(
|
|
@@ -230,15 +235,51 @@ export function EntityEditViewInner<M extends Record<string, unknown>>({
|
|
|
230
235
|
|
|
231
236
|
const mainViewVisible = selectedTab === MAIN_TAB_VALUE || Boolean(selectedSecondaryForm);
|
|
232
237
|
|
|
233
|
-
|
|
234
|
-
|
|
238
|
+
// Track which custom view tabs have been visited so we keep them mounted
|
|
239
|
+
// (preserving their state) but don't eagerly mount tabs never visited.
|
|
240
|
+
const mountedTabsRef = useRef<Set<string>>(new Set());
|
|
241
|
+
if (selectedTab) {
|
|
242
|
+
mountedTabsRef.current.add(selectedTab);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Memoize the read-only fallback form context to avoid recreating it every render
|
|
246
|
+
const readOnlyFormContext = useMemo<FormContext<M> | undefined>(() => {
|
|
247
|
+
if (formContext) return undefined; // not needed when real formContext exists
|
|
248
|
+
if (!entityId) return undefined;
|
|
249
|
+
const formexStub = createFormexStub<M>(usedEntity?.values ?? {} as M);
|
|
250
|
+
return {
|
|
251
|
+
entityId,
|
|
252
|
+
disabled: false,
|
|
253
|
+
openEntityMode: layout,
|
|
254
|
+
status: status,
|
|
255
|
+
values: usedEntity?.values ?? ({} as M),
|
|
256
|
+
setFieldValue: (key: string, value: any) => {
|
|
257
|
+
throw new Error("You can't update values in read only mode");
|
|
258
|
+
},
|
|
259
|
+
save: () => {
|
|
260
|
+
throw new Error("You can't save in read only mode");
|
|
261
|
+
},
|
|
262
|
+
collection,
|
|
263
|
+
path: path,
|
|
264
|
+
entity: usedEntity,
|
|
265
|
+
savingError: undefined,
|
|
266
|
+
formex: formexStub
|
|
267
|
+
};
|
|
268
|
+
}, [formContext, entityId, layout, status, usedEntity, collection, path]);
|
|
269
|
+
|
|
270
|
+
const nonActionCustomViews = useMemo(() =>
|
|
271
|
+
resolvedEntityViews.filter(e => !e.includeActions),
|
|
272
|
+
[resolvedEntityViews]
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
const customViewsView: any[] | undefined = customViews && nonActionCustomViews
|
|
235
276
|
.map((customView) => {
|
|
236
277
|
|
|
237
278
|
if (!customView)
|
|
238
279
|
return null;
|
|
239
|
-
const Builder = customView.Builder;
|
|
280
|
+
const Builder = resolveComponentRef<EntityCustomViewParams>(customView.Builder);
|
|
240
281
|
if (!Builder) {
|
|
241
|
-
console.error("INTERNAL: customView.Builder is not defined");
|
|
282
|
+
console.error("INTERNAL: customView.Builder is not defined or could not be resolved");
|
|
242
283
|
return null;
|
|
243
284
|
}
|
|
244
285
|
|
|
@@ -246,48 +287,41 @@ export function EntityEditViewInner<M extends Record<string, unknown>>({
|
|
|
246
287
|
return null;
|
|
247
288
|
}
|
|
248
289
|
|
|
249
|
-
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
throw new Error("You can't update values in read only mode");
|
|
258
|
-
},
|
|
259
|
-
save: () => {
|
|
260
|
-
throw new Error("You can't save in read only mode");
|
|
261
|
-
},
|
|
262
|
-
collection,
|
|
263
|
-
path: path,
|
|
264
|
-
entity: usedEntity,
|
|
265
|
-
savingError: undefined,
|
|
266
|
-
formex: formexStub
|
|
267
|
-
};
|
|
290
|
+
// Only mount tabs that have been visited at least once
|
|
291
|
+
const isActive = selectedTab === customView.key;
|
|
292
|
+
const hasBeenMounted = mountedTabsRef.current.has(customView.key);
|
|
293
|
+
if (!isActive && !hasBeenMounted) {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const usedFormContext: FormContext<M> = formContext ?? readOnlyFormContext!;
|
|
268
298
|
|
|
269
299
|
return <div
|
|
270
300
|
className={cls(defaultBorderMixin,
|
|
271
301
|
"relative flex-1 w-full h-full overflow-auto",
|
|
272
|
-
{ "hidden":
|
|
302
|
+
{ "hidden": !isActive }
|
|
273
303
|
)}
|
|
274
304
|
key={`custom_view_${customView.key}`}
|
|
275
305
|
role="tabpanel">
|
|
276
306
|
<ErrorBoundary>
|
|
277
|
-
{
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
307
|
+
<Suspense fallback={<CircularProgressCenter />}>
|
|
308
|
+
{usedFormContext && <Builder
|
|
309
|
+
collection={collection}
|
|
310
|
+
parentCollectionSlugs={parentCollectionSlugs} parentEntityIds={parentEntityIds}
|
|
311
|
+
entity={usedEntity}
|
|
312
|
+
modifiedValues={usedFormContext?.formex?.values ?? usedEntity?.values}
|
|
313
|
+
formContext={usedFormContext as unknown as FormContext<Record<string, unknown>>}
|
|
314
|
+
/>}
|
|
315
|
+
</Suspense>
|
|
284
316
|
</ErrorBoundary>
|
|
285
317
|
</div>;
|
|
286
318
|
}).filter(Boolean);
|
|
287
319
|
|
|
288
320
|
const globalLoading = (dataLoading && !usedEntity) || (canEdit === undefined && (status === "existing" || status === "copy"));
|
|
289
321
|
|
|
290
|
-
|
|
322
|
+
// Only mount JSON view when its tab is selected (or was previously selected)
|
|
323
|
+
const jsonTabMounted = mountedTabsRef.current.has(JSON_TAB_VALUE);
|
|
324
|
+
const jsonView = (selectedTab === JSON_TAB_VALUE || jsonTabMounted) ? <div
|
|
291
325
|
className={cls("relative flex-1 h-full overflow-auto w-full",
|
|
292
326
|
{ "hidden": selectedTab !== JSON_TAB_VALUE })}
|
|
293
327
|
key={"json_view"}
|
|
@@ -296,11 +330,11 @@ export function EntityEditViewInner<M extends Record<string, unknown>>({
|
|
|
296
330
|
<EntityJsonPreview
|
|
297
331
|
values={formContext?.values ?? entity?.values ?? {}} />
|
|
298
332
|
</ErrorBoundary>
|
|
299
|
-
</div
|
|
333
|
+
</div> : null;
|
|
300
334
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
335
|
+
// Only mount history view when its tab is actually selected
|
|
336
|
+
const historyView = includeHistoryView && selectedTab === HISTORY_TAB_VALUE ? <div
|
|
337
|
+
className={"relative flex-1 h-full overflow-auto w-full"}
|
|
304
338
|
key={"history_view"}
|
|
305
339
|
role="tabpanel">
|
|
306
340
|
<ErrorBoundary>
|
|
@@ -332,7 +366,8 @@ export function EntityEditViewInner<M extends Record<string, unknown>>({
|
|
|
332
366
|
(usedEntity && newFullPath
|
|
333
367
|
? <EntityCollectionView
|
|
334
368
|
path={newFullPath}
|
|
335
|
-
|
|
369
|
+
parentCollectionSlugs={[...parentCollectionSlugs, collection.slug]}
|
|
370
|
+
parentEntityIds={[...parentEntityIds, String(usedEntity?.id)]}
|
|
336
371
|
updateUrl={false}
|
|
337
372
|
{...subcollection}
|
|
338
373
|
openEntityMode={layout} />
|
|
@@ -348,7 +383,7 @@ export function EntityEditViewInner<M extends Record<string, unknown>>({
|
|
|
348
383
|
);
|
|
349
384
|
}).filter(Boolean);
|
|
350
385
|
|
|
351
|
-
const onSideTabClick = (value: string) => {
|
|
386
|
+
const onSideTabClick = useCallback((value: string) => {
|
|
352
387
|
setSelectedTab(value);
|
|
353
388
|
if (status === "existing") {
|
|
354
389
|
onTabChange?.({
|
|
@@ -358,7 +393,7 @@ export function EntityEditViewInner<M extends Record<string, unknown>>({
|
|
|
358
393
|
collection
|
|
359
394
|
});
|
|
360
395
|
}
|
|
361
|
-
};
|
|
396
|
+
}, [status, onTabChange, path, entityId, collection]);
|
|
362
397
|
|
|
363
398
|
const entityReadOnlyView = !canEdit && entity ? <div
|
|
364
399
|
className={cls("flex-1 flex flex-row w-full overflow-y-auto justify-center", (canEdit || !mainViewVisible || selectedSecondaryForm) ? "hidden" : "")}>
|
|
@@ -410,7 +445,7 @@ export function EntityEditViewInner<M extends Record<string, unknown>>({
|
|
|
410
445
|
onSaved?.(res);
|
|
411
446
|
formProps?.onSaved?.(res);
|
|
412
447
|
}}
|
|
413
|
-
Builder={selectedSecondaryForm?.Builder as React.ComponentType<EntityCustomViewParams<M>> | undefined}
|
|
448
|
+
Builder={resolveComponentRef(selectedSecondaryForm?.Builder as ComponentRef<EntityCustomViewParams<M>> | undefined) as React.ComponentType<EntityCustomViewParams<M>> | undefined}
|
|
414
449
|
/>;
|
|
415
450
|
|
|
416
451
|
const subcollectionTabs = subcollections && subcollections.map((subcollection) =>
|
|
@@ -457,33 +492,6 @@ export function EntityEditViewInner<M extends Record<string, unknown>>({
|
|
|
457
492
|
</Tooltip>
|
|
458
493
|
) : null;
|
|
459
494
|
|
|
460
|
-
// Compute contextual title for subcollection tabs, e.g. "Orders of James"
|
|
461
|
-
const subcollectionContextTitle = useMemo(() => {
|
|
462
|
-
if (selectedTab === MAIN_TAB_VALUE || selectedTab === JSON_TAB_VALUE || selectedTab === HISTORY_TAB_VALUE) {
|
|
463
|
-
return null;
|
|
464
|
-
}
|
|
465
|
-
// Check if the selected tab is a subcollection
|
|
466
|
-
const matchedSubcollection = subcollections.find(sc => sc.slug === selectedTab);
|
|
467
|
-
if (!matchedSubcollection) {
|
|
468
|
-
return null;
|
|
469
|
-
}
|
|
470
|
-
// Check if the selected tab is a custom view (not a subcollection)
|
|
471
|
-
const isCustomView = resolvedEntityViews.some(v => v.key === selectedTab);
|
|
472
|
-
if (isCustomView) {
|
|
473
|
-
return null;
|
|
474
|
-
}
|
|
475
|
-
// Resolve the parent entity's title
|
|
476
|
-
const titleKey = getEntityTitlePropertyKey(collection, customizationController.propertyConfigs);
|
|
477
|
-
const entityValues = usedEntity?.values;
|
|
478
|
-
if (!titleKey || !entityValues) {
|
|
479
|
-
return matchedSubcollection.name;
|
|
480
|
-
}
|
|
481
|
-
const titleValue = entityValues[titleKey as keyof M];
|
|
482
|
-
if (!titleValue || typeof titleValue !== "string") {
|
|
483
|
-
return matchedSubcollection.name;
|
|
484
|
-
}
|
|
485
|
-
return `${matchedSubcollection.name} of ${titleValue}`;
|
|
486
|
-
}, [selectedTab, subcollections, resolvedEntityViews, collection, customizationController.propertyConfigs, usedEntity?.values]);
|
|
487
495
|
|
|
488
496
|
let result = <div className="relative flex flex-col h-full w-full bg-white dark:bg-surface-800">
|
|
489
497
|
|
|
@@ -499,14 +507,6 @@ export function EntityEditViewInner<M extends Record<string, unknown>>({
|
|
|
499
507
|
status
|
|
500
508
|
})}
|
|
501
509
|
|
|
502
|
-
{subcollectionContextTitle && (
|
|
503
|
-
<Typography
|
|
504
|
-
variant="label"
|
|
505
|
-
className="truncate min-w-0 shrink ml-2 text-surface-600 dark:text-surface-400"
|
|
506
|
-
>
|
|
507
|
-
{subcollectionContextTitle}
|
|
508
|
-
</Typography>
|
|
509
|
-
)}
|
|
510
510
|
|
|
511
511
|
{pluginActionsTop}
|
|
512
512
|
|
|
@@ -9,6 +9,7 @@ import { EntityEditView } from "./EntityEditView";
|
|
|
9
9
|
import { useSideDialogContext } from "./SideDialogs";
|
|
10
10
|
import { IconButton } from "@rebasepro/ui";
|
|
11
11
|
import { useLocation, useNavigate } from "react-router-dom";
|
|
12
|
+
import { removeInitialAndTrailingSlashes } from "@rebasepro/common";
|
|
12
13
|
import { saveEntityToMemoryCache } from "@rebasepro/core";
|
|
13
14
|
import { useCollectionRegistryController, useSideEntityController } from "../index";
|
|
14
15
|
import { useUrlController } from "../index";
|
|
@@ -75,8 +76,12 @@ export function EntitySidePanel(props: EntitySidePanelProps) {
|
|
|
75
76
|
|
|
76
77
|
}
|
|
77
78
|
|
|
78
|
-
const
|
|
79
|
-
return collectionRegistryController.
|
|
79
|
+
const parentCollectionSlugs = useMemo(() => {
|
|
80
|
+
return collectionRegistryController.getParentCollectionSlugs(path);
|
|
81
|
+
}, [collectionRegistryController, path]);
|
|
82
|
+
|
|
83
|
+
const parentEntityIds = useMemo(() => {
|
|
84
|
+
return collectionRegistryController.getParentEntityIds(path);
|
|
80
85
|
}, [collectionRegistryController, path]);
|
|
81
86
|
|
|
82
87
|
const collection = collectionRegistryController.getCollection(path) ?? props.collection;
|
|
@@ -102,7 +107,7 @@ export function EntitySidePanel(props: EntitySidePanelProps) {
|
|
|
102
107
|
{...props}
|
|
103
108
|
layout={"side_panel"}
|
|
104
109
|
collection={collection as EntityCollection}
|
|
105
|
-
|
|
110
|
+
parentCollectionSlugs={parentCollectionSlugs} parentEntityIds={parentEntityIds}
|
|
106
111
|
onValuesModified={onValuesModified}
|
|
107
112
|
onSaved={onUpdate}
|
|
108
113
|
barActions={({
|
|
@@ -143,13 +148,16 @@ export function EntitySidePanel(props: EntitySidePanelProps) {
|
|
|
143
148
|
selectedTab,
|
|
144
149
|
collection
|
|
145
150
|
}) => {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
151
|
+
// Only update the URL to reflect the new tab — don't call
|
|
152
|
+
// sideEntityController.replace() which would recreate the
|
|
153
|
+
// entire EntitySidePanel component, causing a full
|
|
154
|
+
// unmount/remount and expensive re-render of the form.
|
|
155
|
+
if (entityId) {
|
|
156
|
+
const collectionPath = removeInitialAndTrailingSlashes(path);
|
|
157
|
+
const tabSuffix = selectedTab ? "/" + selectedTab : "";
|
|
158
|
+
const fullUrl = urlController.buildUrlCollectionPath(`${collectionPath}/${entityId}${tabSuffix}#side`);
|
|
159
|
+
navigate(fullUrl, { replace: true, state: location.state });
|
|
160
|
+
}
|
|
153
161
|
}}
|
|
154
162
|
formProps={formProps}
|
|
155
163
|
/>
|