@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
|
@@ -14,10 +14,8 @@ export function updatePropertyFromWidget(propertyData: any,
|
|
|
14
14
|
type: "string",
|
|
15
15
|
propertyConfig: "text_field",
|
|
16
16
|
storage: undefined,
|
|
17
|
-
multiline: undefined,
|
|
18
|
-
markdown: undefined,
|
|
17
|
+
ui: { multiline: undefined, markdown: undefined, url: undefined },
|
|
19
18
|
email: undefined,
|
|
20
|
-
url: undefined,
|
|
21
19
|
enum: undefined,
|
|
22
20
|
userSelect: undefined
|
|
23
21
|
} as StringProperty
|
|
@@ -29,10 +27,8 @@ export function updatePropertyFromWidget(propertyData: any,
|
|
|
29
27
|
type: "string",
|
|
30
28
|
propertyConfig: "user_select",
|
|
31
29
|
storage: undefined,
|
|
32
|
-
multiline: undefined,
|
|
33
|
-
markdown: undefined,
|
|
30
|
+
ui: { multiline: undefined, markdown: undefined, url: undefined },
|
|
34
31
|
email: undefined,
|
|
35
|
-
url: undefined,
|
|
36
32
|
enum: undefined,
|
|
37
33
|
userSelect: true
|
|
38
34
|
} as StringProperty
|
|
@@ -43,11 +39,9 @@ export function updatePropertyFromWidget(propertyData: any,
|
|
|
43
39
|
{
|
|
44
40
|
type: "string",
|
|
45
41
|
propertyConfig: "multiline",
|
|
46
|
-
multiline: true,
|
|
42
|
+
ui: { multiline: true, markdown: undefined, url: undefined },
|
|
47
43
|
storage: undefined,
|
|
48
|
-
markdown: undefined,
|
|
49
44
|
email: undefined,
|
|
50
|
-
url: undefined,
|
|
51
45
|
enum: undefined,
|
|
52
46
|
userSelect: undefined
|
|
53
47
|
} as StringProperty
|
|
@@ -59,10 +53,8 @@ export function updatePropertyFromWidget(propertyData: any,
|
|
|
59
53
|
type: "string",
|
|
60
54
|
propertyConfig: "markdown",
|
|
61
55
|
storage: undefined,
|
|
62
|
-
multiline: undefined,
|
|
63
|
-
markdown: true,
|
|
56
|
+
ui: { multiline: undefined, markdown: true, url: undefined },
|
|
64
57
|
email: undefined,
|
|
65
|
-
url: undefined,
|
|
66
58
|
userSelect: undefined
|
|
67
59
|
} as StringProperty
|
|
68
60
|
);
|
|
@@ -73,10 +65,8 @@ export function updatePropertyFromWidget(propertyData: any,
|
|
|
73
65
|
type: "string",
|
|
74
66
|
propertyConfig: "url",
|
|
75
67
|
storage: undefined,
|
|
76
|
-
multiline: undefined,
|
|
77
|
-
markdown: undefined,
|
|
68
|
+
ui: { multiline: undefined, markdown: undefined, url: true },
|
|
78
69
|
email: undefined,
|
|
79
|
-
url: true,
|
|
80
70
|
enum: undefined,
|
|
81
71
|
userSelect: undefined
|
|
82
72
|
} as StringProperty
|
|
@@ -88,10 +78,8 @@ export function updatePropertyFromWidget(propertyData: any,
|
|
|
88
78
|
type: "string",
|
|
89
79
|
propertyConfig: "email",
|
|
90
80
|
storage: undefined,
|
|
91
|
-
multiline: undefined,
|
|
92
|
-
markdown: undefined,
|
|
81
|
+
ui: { multiline: undefined, markdown: undefined, url: undefined },
|
|
93
82
|
email: true,
|
|
94
|
-
url: undefined,
|
|
95
83
|
enum: undefined,
|
|
96
84
|
userSelect: undefined
|
|
97
85
|
} as StringProperty
|
|
@@ -103,10 +91,8 @@ export function updatePropertyFromWidget(propertyData: any,
|
|
|
103
91
|
type: "string",
|
|
104
92
|
propertyConfig: "select",
|
|
105
93
|
storage: undefined,
|
|
106
|
-
multiline: undefined,
|
|
107
|
-
markdown: undefined,
|
|
94
|
+
ui: { multiline: undefined, markdown: undefined, url: undefined },
|
|
108
95
|
email: undefined,
|
|
109
|
-
url: undefined,
|
|
110
96
|
enum: propertyData.enum ?? [],
|
|
111
97
|
userSelect: undefined
|
|
112
98
|
} as StringProperty
|
|
@@ -206,14 +192,6 @@ export function updatePropertyFromWidget(propertyData: any,
|
|
|
206
192
|
propertyConfig: "reference"
|
|
207
193
|
} as Property
|
|
208
194
|
);
|
|
209
|
-
} else if (selectedWidgetId === "reference_as_string") {
|
|
210
|
-
updatedProperty = mergeDeep(
|
|
211
|
-
propertyData,
|
|
212
|
-
{
|
|
213
|
-
type: "string",
|
|
214
|
-
propertyConfig: "reference_as_string"
|
|
215
|
-
} as Property
|
|
216
|
-
);
|
|
217
195
|
} else if (selectedWidgetId === "multi_references") {
|
|
218
196
|
updatedProperty = mergeDeep(
|
|
219
197
|
propertyData,
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import type { EngineProperties, EntityCollection, NavigationGroupMapping, Property } from "@rebasepro/types";
|
|
3
|
+
import type {
|
|
4
|
+
CollectionsConfigController,
|
|
5
|
+
SaveCollectionParams,
|
|
6
|
+
UpdateCollectionParams,
|
|
7
|
+
DeleteCollectionParams,
|
|
8
|
+
SavePropertyParams,
|
|
9
|
+
DeletePropertyParams,
|
|
10
|
+
UpdatePropertiesOrderParams,
|
|
11
|
+
UpdateKanbanColumnsOrderParams,
|
|
12
|
+
} from "./types/config_controller";
|
|
13
|
+
import type { JsonCollectionStore, SerializableCollection } from "./serializable_types";
|
|
14
|
+
import { toSerializableCollection, toSerializableProperty, fromSerializableCollection } from "./serializable_utils";
|
|
15
|
+
|
|
16
|
+
export interface UseJsonCollectionsConfigControllerOptions {
|
|
17
|
+
/**
|
|
18
|
+
* The store adapter for persisting/loading collections.
|
|
19
|
+
*/
|
|
20
|
+
store: JsonCollectionStore;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* If true, the configuration cannot be modified.
|
|
24
|
+
*/
|
|
25
|
+
readOnly?: boolean;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* If true, collections will be loaded from the store on mount.
|
|
29
|
+
* Defaults to true.
|
|
30
|
+
*/
|
|
31
|
+
autoLoad?: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* A `CollectionsConfigController` implementation that persists collection
|
|
36
|
+
* configurations as JSON via a pluggable `JsonCollectionStore` adapter.
|
|
37
|
+
*
|
|
38
|
+
* Use this when you want to store collection schemas in a database, API,
|
|
39
|
+
* localStorage, or any other JSON-compatible backend — as opposed to the
|
|
40
|
+
* default code-based persistence.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```tsx
|
|
44
|
+
* const store: JsonCollectionStore = {
|
|
45
|
+
* load: async () => { const res = await fetch('/api/schemas'); return res.json(); },
|
|
46
|
+
* save: async (slug, data) => { await fetch(`/api/schemas/${slug}`, { method: 'PUT', body: JSON.stringify(data) }); },
|
|
47
|
+
* delete: async (slug) => { await fetch(`/api/schemas/${slug}`, { method: 'DELETE' }); },
|
|
48
|
+
* };
|
|
49
|
+
*
|
|
50
|
+
* const configController = useJsonCollectionsConfigController({ store });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export function useJsonCollectionsConfigController({
|
|
54
|
+
store,
|
|
55
|
+
readOnly = false,
|
|
56
|
+
autoLoad = true,
|
|
57
|
+
}: UseJsonCollectionsConfigControllerOptions): CollectionsConfigController {
|
|
58
|
+
const [collections, setCollections] = useState<EntityCollection[]>([]);
|
|
59
|
+
const [loading, setLoading] = useState(autoLoad);
|
|
60
|
+
const [navigationEntries, setNavigationEntries] = useState<NavigationGroupMapping[]>([]);
|
|
61
|
+
|
|
62
|
+
// Keep store ref stable to avoid stale closures in callbacks
|
|
63
|
+
const storeRef = useRef(store);
|
|
64
|
+
storeRef.current = store;
|
|
65
|
+
|
|
66
|
+
// ── Load on mount ─────────────────────────────────────────────────
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (!autoLoad) return;
|
|
69
|
+
let cancelled = false;
|
|
70
|
+
|
|
71
|
+
(async () => {
|
|
72
|
+
try {
|
|
73
|
+
const [serialized, navEntries] = await Promise.all([
|
|
74
|
+
storeRef.current.load(),
|
|
75
|
+
storeRef.current.loadNavigationEntries?.() ?? Promise.resolve([]),
|
|
76
|
+
]);
|
|
77
|
+
if (cancelled) return;
|
|
78
|
+
setCollections(serialized.map(fromSerializableCollection));
|
|
79
|
+
setNavigationEntries(navEntries);
|
|
80
|
+
} catch (e) {
|
|
81
|
+
console.error("useJsonCollectionsConfigController: failed to load collections", e);
|
|
82
|
+
} finally {
|
|
83
|
+
if (!cancelled) setLoading(false);
|
|
84
|
+
}
|
|
85
|
+
})();
|
|
86
|
+
|
|
87
|
+
return () => { cancelled = true; };
|
|
88
|
+
}, [autoLoad]);
|
|
89
|
+
|
|
90
|
+
// ── Helpers ────────────────────────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Update local state and persist a collection to the store.
|
|
94
|
+
*/
|
|
95
|
+
const persistCollection = useCallback(async (collection: EntityCollection) => {
|
|
96
|
+
const serializable = toSerializableCollection(collection);
|
|
97
|
+
await storeRef.current.save(collection.slug, serializable);
|
|
98
|
+
}, []);
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Find collection by id (slug).
|
|
102
|
+
*/
|
|
103
|
+
const getCollection = useCallback((id: string): EntityCollection => {
|
|
104
|
+
const found = collections.find(c => c.slug === id);
|
|
105
|
+
if (found) return found;
|
|
106
|
+
throw new Error(`Collection "${id}" not found`);
|
|
107
|
+
}, [collections]);
|
|
108
|
+
|
|
109
|
+
// ── CRUD operations ───────────────────────────────────────────────
|
|
110
|
+
|
|
111
|
+
const saveCollection = useCallback(async <M extends Record<string, unknown>>(
|
|
112
|
+
{ id, collectionData }: SaveCollectionParams<M>
|
|
113
|
+
) => {
|
|
114
|
+
const collection = collectionData as EntityCollection;
|
|
115
|
+
await persistCollection(collection);
|
|
116
|
+
setCollections(prev => {
|
|
117
|
+
const idx = prev.findIndex(c => c.slug === id);
|
|
118
|
+
if (idx >= 0) {
|
|
119
|
+
const next = [...prev];
|
|
120
|
+
next[idx] = collection;
|
|
121
|
+
return next;
|
|
122
|
+
}
|
|
123
|
+
return [...prev, collection];
|
|
124
|
+
});
|
|
125
|
+
}, [persistCollection]);
|
|
126
|
+
|
|
127
|
+
const updateCollection = useCallback(async <M extends Record<string, unknown>>(
|
|
128
|
+
{ id, collectionData, previousId }: UpdateCollectionParams<M>
|
|
129
|
+
) => {
|
|
130
|
+
setCollections(prev => {
|
|
131
|
+
const lookupId = previousId ?? id;
|
|
132
|
+
const idx = prev.findIndex(c => c.slug === lookupId);
|
|
133
|
+
if (idx < 0) return prev;
|
|
134
|
+
|
|
135
|
+
const merged = { ...prev[idx], ...collectionData } as EntityCollection;
|
|
136
|
+
const next = [...prev];
|
|
137
|
+
next[idx] = merged;
|
|
138
|
+
|
|
139
|
+
// Persist async — fire-and-forget with error logging
|
|
140
|
+
persistCollection(merged).catch(e =>
|
|
141
|
+
console.error("useJsonCollectionsConfigController: failed to update collection", e)
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
// If slug changed, clean up the old entry in the store
|
|
145
|
+
if (previousId && previousId !== id) {
|
|
146
|
+
storeRef.current.delete(previousId).catch(e =>
|
|
147
|
+
console.error("useJsonCollectionsConfigController: failed to delete old slug", e)
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return next;
|
|
152
|
+
});
|
|
153
|
+
}, [persistCollection]);
|
|
154
|
+
|
|
155
|
+
const deleteCollection = useCallback(async ({ id }: DeleteCollectionParams) => {
|
|
156
|
+
await storeRef.current.delete(id);
|
|
157
|
+
setCollections(prev => prev.filter(c => c.slug !== id));
|
|
158
|
+
}, []);
|
|
159
|
+
|
|
160
|
+
const saveProperty = useCallback(async ({
|
|
161
|
+
path,
|
|
162
|
+
propertyKey,
|
|
163
|
+
property,
|
|
164
|
+
newPropertiesOrder,
|
|
165
|
+
}: SavePropertyParams) => {
|
|
166
|
+
setCollections(prev => {
|
|
167
|
+
const idx = prev.findIndex(c => c.slug === path);
|
|
168
|
+
if (idx < 0) return prev;
|
|
169
|
+
|
|
170
|
+
const collection = { ...prev[idx] };
|
|
171
|
+
collection.properties = {
|
|
172
|
+
...collection.properties,
|
|
173
|
+
[propertyKey]: property,
|
|
174
|
+
} as EngineProperties;
|
|
175
|
+
if (newPropertiesOrder) {
|
|
176
|
+
collection.propertiesOrder = newPropertiesOrder as typeof collection.propertiesOrder;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const next = [...prev];
|
|
180
|
+
next[idx] = collection as EntityCollection;
|
|
181
|
+
|
|
182
|
+
persistCollection(next[idx]).catch(e =>
|
|
183
|
+
console.error("useJsonCollectionsConfigController: failed to save property", e)
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
return next;
|
|
187
|
+
});
|
|
188
|
+
}, [persistCollection]);
|
|
189
|
+
|
|
190
|
+
const deleteProperty = useCallback(async ({
|
|
191
|
+
path,
|
|
192
|
+
propertyKey,
|
|
193
|
+
newPropertiesOrder,
|
|
194
|
+
}: DeletePropertyParams) => {
|
|
195
|
+
setCollections(prev => {
|
|
196
|
+
const idx = prev.findIndex(c => c.slug === path);
|
|
197
|
+
if (idx < 0) return prev;
|
|
198
|
+
|
|
199
|
+
const collection = { ...prev[idx] };
|
|
200
|
+
const { [propertyKey]: _removed, ...remaining } = collection.properties;
|
|
201
|
+
collection.properties = remaining;
|
|
202
|
+
if (newPropertiesOrder) {
|
|
203
|
+
collection.propertiesOrder = newPropertiesOrder as typeof collection.propertiesOrder;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const next = [...prev];
|
|
207
|
+
next[idx] = collection as EntityCollection;
|
|
208
|
+
|
|
209
|
+
persistCollection(next[idx]).catch(e =>
|
|
210
|
+
console.error("useJsonCollectionsConfigController: failed to delete property", e)
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
return next;
|
|
214
|
+
});
|
|
215
|
+
}, [persistCollection]);
|
|
216
|
+
|
|
217
|
+
const updatePropertiesOrder = useCallback(async ({
|
|
218
|
+
collection,
|
|
219
|
+
newPropertiesOrder,
|
|
220
|
+
}: UpdatePropertiesOrderParams) => {
|
|
221
|
+
const updated = {
|
|
222
|
+
...collection,
|
|
223
|
+
propertiesOrder: newPropertiesOrder,
|
|
224
|
+
} as EntityCollection;
|
|
225
|
+
|
|
226
|
+
setCollections(prev => {
|
|
227
|
+
const idx = prev.findIndex(c => c.slug === collection.slug);
|
|
228
|
+
if (idx < 0) return prev;
|
|
229
|
+
const next = [...prev];
|
|
230
|
+
next[idx] = updated;
|
|
231
|
+
return next;
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
await persistCollection(updated);
|
|
235
|
+
}, [persistCollection]);
|
|
236
|
+
|
|
237
|
+
const updateKanbanColumnsOrder = useCallback(async ({
|
|
238
|
+
collection,
|
|
239
|
+
kanbanColumnProperty,
|
|
240
|
+
newColumnsOrder,
|
|
241
|
+
}: UpdateKanbanColumnsOrderParams) => {
|
|
242
|
+
// Kanban column order is stored in the enum order of the column property.
|
|
243
|
+
// For JSON persistence, we store it as-is — the view layer reads enum order.
|
|
244
|
+
// This is a no-op for now; the kanban order is determined by the enum
|
|
245
|
+
// definition on the property itself.
|
|
246
|
+
}, []);
|
|
247
|
+
|
|
248
|
+
const saveNavigationEntriesHandler = useCallback(async (entries: NavigationGroupMapping[]) => {
|
|
249
|
+
setNavigationEntries(entries);
|
|
250
|
+
if (storeRef.current.saveNavigationEntries) {
|
|
251
|
+
await storeRef.current.saveNavigationEntries(entries);
|
|
252
|
+
}
|
|
253
|
+
}, []);
|
|
254
|
+
|
|
255
|
+
// ── Return controller ─────────────────────────────────────────────
|
|
256
|
+
return useMemo<CollectionsConfigController>(() => ({
|
|
257
|
+
loading,
|
|
258
|
+
readOnly,
|
|
259
|
+
readOnlyReason: readOnly ? "Configuration is read-only." : undefined,
|
|
260
|
+
collections,
|
|
261
|
+
getCollection,
|
|
262
|
+
saveCollection,
|
|
263
|
+
updateCollection,
|
|
264
|
+
deleteCollection,
|
|
265
|
+
saveProperty,
|
|
266
|
+
deleteProperty,
|
|
267
|
+
updatePropertiesOrder,
|
|
268
|
+
updateKanbanColumnsOrder,
|
|
269
|
+
navigationEntries,
|
|
270
|
+
saveNavigationEntries: saveNavigationEntriesHandler,
|
|
271
|
+
}), [
|
|
272
|
+
loading,
|
|
273
|
+
readOnly,
|
|
274
|
+
collections,
|
|
275
|
+
getCollection,
|
|
276
|
+
saveCollection,
|
|
277
|
+
updateCollection,
|
|
278
|
+
deleteCollection,
|
|
279
|
+
saveProperty,
|
|
280
|
+
deleteProperty,
|
|
281
|
+
updatePropertiesOrder,
|
|
282
|
+
updateKanbanColumnsOrder,
|
|
283
|
+
navigationEntries,
|
|
284
|
+
saveNavigationEntriesHandler,
|
|
285
|
+
]);
|
|
286
|
+
}
|
|
@@ -13,3 +13,9 @@ export type { CollectionStudioViewProps } from "./collection_editor/ui/collectio
|
|
|
13
13
|
|
|
14
14
|
export { CollectionsStudioView } from "./collection_editor/ui/collection_editor/CollectionsStudioView";
|
|
15
15
|
export type { CollectionsStudioViewProps } from "./collection_editor/ui/collection_editor/CollectionsStudioView";
|
|
16
|
+
|
|
17
|
+
export { RouterCollectionStudioView } from "./collection_editor/ui/collection_editor/RouterCollectionStudioView";
|
|
18
|
+
export type { RouterCollectionStudioViewProps } from "./collection_editor/ui/collection_editor/RouterCollectionStudioView";
|
|
19
|
+
|
|
20
|
+
export { RouterCollectionsStudioView } from "./collection_editor/ui/collection_editor/RouterCollectionsStudioView";
|
|
21
|
+
export type { RouterCollectionsStudioViewProps } from "./collection_editor/ui/collection_editor/RouterCollectionsStudioView";
|
|
@@ -165,11 +165,21 @@ function CMSNavigationContent() {
|
|
|
165
165
|
|
|
166
166
|
const allNavigationEntries = navigationState.topLevelNavigation?.navigationEntries ?? [];
|
|
167
167
|
|
|
168
|
-
//
|
|
169
|
-
//
|
|
168
|
+
// Build a set of Studio-only dev view slugs so we can distinguish them from
|
|
169
|
+
// CMS custom views added via <RebaseCMS views={...}> or plugins.
|
|
170
|
+
const studioViewSlugs = useMemo(() => {
|
|
171
|
+
const slugs = new Set<string>();
|
|
172
|
+
(registry.studioConfig?.devViews ?? []).forEach(v => slugs.add(v.slug));
|
|
173
|
+
// The schema view is also a Studio dev view (auto-injected when collectionEditor is enabled)
|
|
174
|
+
if (registry.studioConfig && registry.cmsConfig?.collectionEditor) slugs.add("schema");
|
|
175
|
+
return slugs;
|
|
176
|
+
}, [registry.studioConfig, registry.cmsConfig?.collectionEditor]);
|
|
177
|
+
|
|
178
|
+
// Studio mode shows Studio dev views + admin entries (Users/Roles).
|
|
179
|
+
// Content mode shows collections, CMS custom views, and admin entries — but not Studio dev views.
|
|
170
180
|
const filteredEntries = adminModeController.mode === "studio"
|
|
171
|
-
? allNavigationEntries.filter(e => e.type === "view" || e.type === "admin")
|
|
172
|
-
: allNavigationEntries.filter(e => e.type !== "view");
|
|
181
|
+
? allNavigationEntries.filter(e => (e.type === "view" && studioViewSlugs.has(e.slug)) || e.type === "admin")
|
|
182
|
+
: allNavigationEntries.filter(e => e.type !== "view" || !studioViewSlugs.has(e.slug));
|
|
173
183
|
|
|
174
184
|
// Derive groups from the filtered entries, preserving the order from topLevelNavigation.groups
|
|
175
185
|
const entryGroups = new Set(filteredEntries.map(e => e.group).filter(Boolean));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { NavigationEntry } from "@rebasepro/types";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { ChevronDownIcon, cls, iconSize, Typography } from "@rebasepro/ui";
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
import { IconForView } from "@rebasepro/core";
|
|
6
6
|
import { DrawerNavigationItem } from "./DrawerNavigationItem";
|
|
7
7
|
import { useTranslation, useComponentOverride } from "@rebasepro/core";
|
|
@@ -108,7 +108,7 @@ export function DrawerNavigationGroup({
|
|
|
108
108
|
"transition-all duration-200 ease-in-out",
|
|
109
109
|
"overflow-hidden",
|
|
110
110
|
!hideHeader && "dark:bg-transparent",
|
|
111
|
-
|
|
111
|
+
"rounded-lg",
|
|
112
112
|
(!hideHeader && collapsed) ? "max-h-0 opacity-0" : "max-h-[2000px] opacity-100"
|
|
113
113
|
)}
|
|
114
114
|
>
|
|
@@ -42,7 +42,7 @@ import { getValueInPath } from "@rebasepro/utils";
|
|
|
42
42
|
* @see VirtualTable
|
|
43
43
|
* @group Components
|
|
44
44
|
*/
|
|
45
|
-
export const EntityCollectionTable = function EntityCollectionTable<M extends Record<string, unknown> =
|
|
45
|
+
export const EntityCollectionTable = function EntityCollectionTable<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>
|
|
46
46
|
({
|
|
47
47
|
className,
|
|
48
48
|
style,
|
|
@@ -113,7 +113,7 @@ export const EntityCollectionTable = function EntityCollectionTable<M extends Re
|
|
|
113
113
|
const additionalFieldsMap: Record<string, AdditionalFieldDelegate<M, USER>> = useMemo(() => {
|
|
114
114
|
return (additionalFields
|
|
115
115
|
? additionalFields
|
|
116
|
-
.map((aC) => ({ [aC.key]: aC as AdditionalFieldDelegate<M,
|
|
116
|
+
.map((aC) => ({ [aC.key]: aC as AdditionalFieldDelegate<M, USER> }))
|
|
117
117
|
.reduce((a, b) => ({ ...a,
|
|
118
118
|
...b }), {})
|
|
119
119
|
: {}) as Record<string, AdditionalFieldDelegate<M, USER>>;
|
|
@@ -132,9 +132,10 @@ export const EntityCollectionTable = function EntityCollectionTable<M extends Re
|
|
|
132
132
|
isDragging,
|
|
133
133
|
isDraggable,
|
|
134
134
|
frozen
|
|
135
|
-
}: CellRendererParams<
|
|
135
|
+
}: CellRendererParams<Entity<M>>) => {
|
|
136
136
|
|
|
137
|
-
const entity: Entity<M> = rowData;
|
|
137
|
+
const entity: Entity<M> | undefined = rowData;
|
|
138
|
+
if (!entity) return null;
|
|
138
139
|
|
|
139
140
|
const propertyKey = column.key;
|
|
140
141
|
|
|
@@ -192,9 +193,10 @@ export const EntityCollectionTable = function EntityCollectionTable<M extends Re
|
|
|
192
193
|
isDragging,
|
|
193
194
|
isDraggable,
|
|
194
195
|
frozen
|
|
195
|
-
}: CellRendererParams<
|
|
196
|
+
}: CellRendererParams<Entity<M>>) => {
|
|
196
197
|
|
|
197
|
-
const entity: Entity<M> = rowData;
|
|
198
|
+
const entity: Entity<M> | undefined = rowData;
|
|
199
|
+
if (!entity) return null;
|
|
198
200
|
|
|
199
201
|
const additionalField = additionalFieldsMap[column.key as string];
|
|
200
202
|
const value = additionalField.dependencies
|
|
@@ -293,7 +295,7 @@ export const EntityCollectionTable = function EntityCollectionTable<M extends Re
|
|
|
293
295
|
: collectionColumns) as VirtualTableColumn[]
|
|
294
296
|
], [idColumn, displayedColumnIds, collectionColumns]);
|
|
295
297
|
|
|
296
|
-
const cellRenderer = useCallback((props: CellRendererParams<
|
|
298
|
+
const cellRenderer = useCallback((props: CellRendererParams<Entity<M>>) => {
|
|
297
299
|
const column = props.column;
|
|
298
300
|
const columns = props.columns;
|
|
299
301
|
const columnKey = column.key;
|
|
@@ -302,13 +304,13 @@ export const EntityCollectionTable = function EntityCollectionTable<M extends Re
|
|
|
302
304
|
if (props.columnIndex === 0) {
|
|
303
305
|
if (tableRowActionsBuilder)
|
|
304
306
|
return tableRowActionsBuilder({
|
|
305
|
-
entity: props.rowData
|
|
307
|
+
entity: props.rowData!,
|
|
306
308
|
size,
|
|
307
309
|
width: column.width,
|
|
308
310
|
frozen: column.frozen
|
|
309
311
|
});
|
|
310
312
|
else
|
|
311
|
-
return <EntityCollectionRowActions entity={props.rowData}
|
|
313
|
+
return <EntityCollectionRowActions entity={props.rowData!}
|
|
312
314
|
width={column.width}
|
|
313
315
|
frozen={column.frozen}
|
|
314
316
|
isSelected={false}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useEntitySelectionDialog } from "../../../hooks/useEntitySelectionDialog";
|
|
2
2
|
import type { EntityCollection } from "@rebasepro/types";
|
|
3
|
+
import { getCollectionDataPath } from "@rebasepro/types";
|
|
3
4
|
import React, { useCallback } from "react";
|
|
4
5
|
import { deepEqual as equal } from "fast-equals";
|
|
5
6
|
|
|
@@ -58,7 +59,7 @@ export const TableMultipleRelationFieldInternal = React.memo(
|
|
|
58
59
|
|
|
59
60
|
const relationDialogController = useEntitySelectionDialog({
|
|
60
61
|
multiselect: true,
|
|
61
|
-
path: collection
|
|
62
|
+
path: getCollectionDataPath(collection),
|
|
62
63
|
collection,
|
|
63
64
|
onMultipleEntitiesSelected,
|
|
64
65
|
selectedEntityIds,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useEntitySelectionDialog } from "../../../hooks/useEntitySelectionDialog";
|
|
2
2
|
import type { EntityCollection } from "@rebasepro/types";
|
|
3
|
+
import { getCollectionDataPath } from "@rebasepro/types";
|
|
3
4
|
import React, { useCallback } from "react";
|
|
4
5
|
import { deepEqual as equal } from "fast-equals"
|
|
5
6
|
|
|
@@ -90,7 +91,7 @@ export const TableRelationFieldInternal = React.memo(
|
|
|
90
91
|
|
|
91
92
|
const relationDialogController = useEntitySelectionDialog({
|
|
92
93
|
multiselect,
|
|
93
|
-
path: collection
|
|
94
|
+
path: getCollectionDataPath(collection),
|
|
94
95
|
collection,
|
|
95
96
|
onMultipleEntitiesSelected,
|
|
96
97
|
onSingleEntitySelected,
|
|
@@ -8,7 +8,7 @@ import { useDropzone } from "react-dropzone";
|
|
|
8
8
|
import { PropertyPreview } from "../../../preview";
|
|
9
9
|
import { ErrorBoundary } from "@rebasepro/ui";
|
|
10
10
|
import { cls, IconButton, PencilIcon, Typography } from "@rebasepro/ui";
|
|
11
|
-
import { useSnackbarController, useStorageSource, useTranslation, StorageFieldItem, useStorageUploadController } from "@rebasepro/core";
|
|
11
|
+
import { useSnackbarController, useStorageSource, useTranslation, StorageFieldItem, useStorageUploadController, StorageSourceContext } from "@rebasepro/core";
|
|
12
12
|
import { getThumbnailMeasure } from "../../../preview/util";
|
|
13
13
|
import { StorageUploadProgress } from "../../../form/components/StorageUploadProgress";
|
|
14
14
|
import { EntityTableCellActions } from "../internal/EntityTableCellActions";
|
|
@@ -64,7 +64,8 @@ export function TableStorageUpload(props: {
|
|
|
64
64
|
storage,
|
|
65
65
|
onFileUploadComplete,
|
|
66
66
|
storagePathBuilder,
|
|
67
|
-
multipleFilesSupported
|
|
67
|
+
multipleFilesSupported,
|
|
68
|
+
resolvedStorageSource
|
|
68
69
|
} = useStorageUploadController({
|
|
69
70
|
entityValues: entity.values,
|
|
70
71
|
entityId: entity.id,
|
|
@@ -79,24 +80,26 @@ export function TableStorageUpload(props: {
|
|
|
79
80
|
|
|
80
81
|
return (
|
|
81
82
|
|
|
82
|
-
<
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
83
|
+
<StorageSourceContext.Provider value={resolvedStorageSource}>
|
|
84
|
+
<StorageUpload
|
|
85
|
+
internalValue={internalValue}
|
|
86
|
+
setInternalValue={setInternalValue}
|
|
87
|
+
name={propertyKey}
|
|
88
|
+
disabled={disabled}
|
|
89
|
+
autoFocus={false}
|
|
90
|
+
openPopup={openPopup}
|
|
91
|
+
error={error}
|
|
92
|
+
selected={selected}
|
|
93
|
+
property={property}
|
|
94
|
+
onChange={updateValue}
|
|
95
|
+
entity={entity}
|
|
96
|
+
storagePathBuilder={storagePathBuilder}
|
|
97
|
+
storage={storage}
|
|
98
|
+
multipleFilesSupported={multipleFilesSupported}
|
|
99
|
+
onFilesAdded={onFilesAdded}
|
|
100
|
+
onFileUploadComplete={onFileUploadComplete}
|
|
101
|
+
previewSize={previewSize}/>
|
|
102
|
+
</StorageSourceContext.Provider>
|
|
100
103
|
|
|
101
104
|
);
|
|
102
105
|
}
|