@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
|
@@ -3,7 +3,7 @@ import type { EntityCollection } from "@rebasepro/types";
|
|
|
3
3
|
import type { FormContext } from "../types/fields";
|
|
4
4
|
import type { EntityAction, EntityActionClickProps, SideEntityController } from "@rebasepro/types";
|
|
5
5
|
import React, { useMemo } from "react";
|
|
6
|
-
import { Entity, RebaseContext } from "@rebasepro/types";
|
|
6
|
+
import { Entity, getCollectionDataPath, RebaseContext } from "@rebasepro/types";
|
|
7
7
|
import type { EntityFormActionsProps } from "../types/components/EntityFormActionsProps";
|
|
8
8
|
import { copyEntityAction, deleteEntityAction } from "../components";
|
|
9
9
|
import { mergeEntityActions } from "../util/entity_actions";
|
|
@@ -123,7 +123,7 @@ type ActionsViewProps<M extends Record<string, unknown>> = {
|
|
|
123
123
|
status: "new" | "existing" | "copy",
|
|
124
124
|
sideDialogContext: SideDialogController,
|
|
125
125
|
pluginActions?: React.ReactNode[],
|
|
126
|
-
openEntityMode
|
|
126
|
+
openEntityMode?: "side_panel" | "full_screen" | "split" | "dialog";
|
|
127
127
|
navigateBack: () => void;
|
|
128
128
|
formContext: FormContext,
|
|
129
129
|
formex: FormexController<Record<string, unknown>>;
|
|
@@ -164,10 +164,11 @@ function buildBottomActions<M extends Record<string, unknown>>({
|
|
|
164
164
|
{formActions.length > 0 && <div className="grow flex overflow-auto no-scrollbar">
|
|
165
165
|
{formActions.map((action, index) => {
|
|
166
166
|
|
|
167
|
+
|
|
167
168
|
const props = {
|
|
168
169
|
view: "form",
|
|
169
170
|
entity,
|
|
170
|
-
path: collection
|
|
171
|
+
path: getCollectionDataPath(collection),
|
|
171
172
|
collection: collection,
|
|
172
173
|
context,
|
|
173
174
|
sideEntityController,
|
|
@@ -208,17 +209,19 @@ function buildBottomActions<M extends Record<string, unknown>>({
|
|
|
208
209
|
{t("back_to_detail") ?? "Back to details"}
|
|
209
210
|
</Button>
|
|
210
211
|
)}
|
|
211
|
-
<
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
212
|
+
<Tooltip title={hasErrors ? (t("fix_errors_before_saving") ?? "Fix highlighted errors before saving") : undefined}>
|
|
213
|
+
<Button variant={canClose ? "text" : "filled"}
|
|
214
|
+
color="primary"
|
|
215
|
+
type="submit"
|
|
216
|
+
disabled={disabled || formex.isSubmitting}
|
|
217
|
+
onClick={() => {
|
|
218
|
+
sideDialogContext.setPendingClose(false);
|
|
219
|
+
}}>
|
|
220
|
+
{status === "existing" && t("save")}
|
|
221
|
+
{status === "copy" && t("create_copy")}
|
|
222
|
+
{status === "new" && t("create")}
|
|
223
|
+
</Button>
|
|
224
|
+
</Tooltip>
|
|
222
225
|
{canClose && <LoadingButton variant="filled"
|
|
223
226
|
color="primary"
|
|
224
227
|
type="submit"
|
|
@@ -256,19 +259,22 @@ function buildSideActions<M extends Record<string, unknown>>({
|
|
|
256
259
|
const hasErrors = Object.keys(formex.errors).length > 0 && formex.submitCount > 0;
|
|
257
260
|
return <div
|
|
258
261
|
className={cls("overflow-auto h-full flex flex-col gap-2 w-80 2xl:w-96 px-4 py-16 sticky top-0 border-l", defaultBorderMixin, className)}>
|
|
259
|
-
<
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
262
|
+
<Tooltip title={hasErrors ? (t("fix_errors_before_saving") ?? "Fix highlighted errors before saving") : undefined}>
|
|
263
|
+
<LoadingButton fullWidth={true}
|
|
264
|
+
variant="filled"
|
|
265
|
+
color="primary"
|
|
266
|
+
type="submit"
|
|
267
|
+
loading={formex.isSubmitting}
|
|
268
|
+
startIcon={hasErrors ? <AlertCircleIcon/> : undefined}
|
|
269
|
+
disabled={disabled || formex.isSubmitting}
|
|
270
|
+
onClick={() => {
|
|
271
|
+
sideDialogContext.setPendingClose?.(false);
|
|
272
|
+
}}>
|
|
273
|
+
{status === "existing" && t("save")}
|
|
274
|
+
{status === "copy" && t("create_copy")}
|
|
275
|
+
{status === "new" && t("create")}
|
|
276
|
+
</LoadingButton>
|
|
277
|
+
</Tooltip>
|
|
272
278
|
|
|
273
279
|
<Button fullWidth={true} variant="text" disabled={disabled || formex.isSubmitting} type="reset">
|
|
274
280
|
{status === "existing" ? t("discard") : t("clear")}
|
|
@@ -286,14 +292,14 @@ function buildSideActions<M extends Record<string, unknown>>({
|
|
|
286
292
|
const props = {
|
|
287
293
|
view: "form",
|
|
288
294
|
entity,
|
|
289
|
-
path: collection
|
|
295
|
+
path: getCollectionDataPath(collection),
|
|
290
296
|
collection: collection,
|
|
291
297
|
context,
|
|
292
298
|
sideEntityController,
|
|
293
299
|
openEntityMode,
|
|
294
300
|
navigateBack,
|
|
295
301
|
formContext
|
|
296
|
-
} satisfies EntityActionClickProps<
|
|
302
|
+
} satisfies EntityActionClickProps<Record<string, unknown>>;
|
|
297
303
|
const isEnabled = !action.isEnabled || action.isEnabled(props);
|
|
298
304
|
return (
|
|
299
305
|
<EntityActionButton key={action.key ?? action.name ?? index} action={action} enabled={isEnabled} props={props}/>
|
|
@@ -63,14 +63,23 @@ export function ContentHomePage({
|
|
|
63
63
|
onNavigationEntriesUpdate = () => {}
|
|
64
64
|
} = navigationStateController.topLevelNavigation || {};
|
|
65
65
|
|
|
66
|
-
//
|
|
67
|
-
//
|
|
66
|
+
// Build a set of Studio-only dev view slugs so we can distinguish them from
|
|
67
|
+
// CMS custom views added via <RebaseCMS views={...}> or plugins.
|
|
68
|
+
const studioViewSlugs = useMemo(() => {
|
|
69
|
+
const slugs = new Set<string>();
|
|
70
|
+
(registry.studioConfig?.devViews ?? []).forEach(v => slugs.add(v.slug));
|
|
71
|
+
if (registry.studioConfig && registry.cmsConfig?.collectionEditor) slugs.add("schema");
|
|
72
|
+
return slugs;
|
|
73
|
+
}, [registry.studioConfig, registry.cmsConfig?.collectionEditor]);
|
|
74
|
+
|
|
75
|
+
// Studio mode shows Studio dev views + admin entries (Users/Roles).
|
|
76
|
+
// Content mode shows collections, CMS custom views, and admin entries — but not Studio dev views.
|
|
68
77
|
const rawNavigationEntries = useMemo(() => {
|
|
69
78
|
if (adminModeController.mode === "studio") {
|
|
70
|
-
return unFilteredNavigationEntries.filter(e => e.type === "view" || e.type === "admin");
|
|
79
|
+
return unFilteredNavigationEntries.filter(e => (e.type === "view" && studioViewSlugs.has(e.slug)) || e.type === "admin");
|
|
71
80
|
}
|
|
72
|
-
return unFilteredNavigationEntries.filter(e => e.type !== "view");
|
|
73
|
-
}, [unFilteredNavigationEntries, adminModeController.mode]);
|
|
81
|
+
return unFilteredNavigationEntries.filter(e => e.type !== "view" || !studioViewSlugs.has(e.slug));
|
|
82
|
+
}, [unFilteredNavigationEntries, adminModeController.mode, studioViewSlugs]);
|
|
74
83
|
|
|
75
84
|
const groupOrderFromNavController = useMemo(() => {
|
|
76
85
|
const entryGroups = new Set(rawNavigationEntries.map(e => e.group).filter(Boolean));
|
|
@@ -10,19 +10,19 @@ import type { RebaseCMSConfig } from "@rebasepro/types";
|
|
|
10
10
|
* is auto-wired as a native feature (slots, provider, Studio view) without
|
|
11
11
|
* needing any external plugin.
|
|
12
12
|
*/
|
|
13
|
-
export function RebaseCMS({ collections, homePage, entityViews, entityActions,
|
|
13
|
+
export function RebaseCMS({ collections, views, homePage, entityViews, entityActions, collectionEditor, navigationGroupMappings }: RebaseCMSConfig) {
|
|
14
14
|
const dispatch = useRebaseRegistryDispatch();
|
|
15
15
|
|
|
16
16
|
useLayoutEffect(() => {
|
|
17
17
|
dispatch.registerCMS({ collections,
|
|
18
|
+
views,
|
|
18
19
|
homePage,
|
|
19
20
|
entityViews,
|
|
20
21
|
entityActions,
|
|
21
|
-
plugins,
|
|
22
22
|
collectionEditor,
|
|
23
23
|
navigationGroupMappings });
|
|
24
24
|
return () => dispatch.unregisterCMS();
|
|
25
|
-
}, [dispatch, collections, homePage, entityViews, entityActions,
|
|
25
|
+
}, [dispatch, collections, views, homePage, entityViews, entityActions, collectionEditor, navigationGroupMappings]);
|
|
26
26
|
|
|
27
27
|
return null;
|
|
28
28
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useMemo, lazy, Suspense } from "react";
|
|
1
|
+
import React, { useMemo, useRef, useEffect, lazy, Suspense } from "react";
|
|
2
2
|
import {
|
|
3
3
|
useRebaseRegistry,
|
|
4
4
|
useRebaseContext,
|
|
@@ -7,10 +7,14 @@ import {
|
|
|
7
7
|
useAdminModeController,
|
|
8
8
|
useBuildLocalConfigurationPersistence,
|
|
9
9
|
useRebaseClient,
|
|
10
|
+
useData,
|
|
11
|
+
useDataSources,
|
|
10
12
|
StudioBridgeRegistryProvider,
|
|
11
13
|
useBridgeRegistration,
|
|
12
|
-
CustomizationControllerContext
|
|
14
|
+
CustomizationControllerContext,
|
|
15
|
+
RebaseDataContext
|
|
13
16
|
} from "@rebasepro/core";
|
|
17
|
+
import { buildRoutedRebaseData, resolveDataSource } from "@rebasepro/common";
|
|
14
18
|
import { CircularProgressCenter } from "@rebasepro/ui";
|
|
15
19
|
import type { AppView, CollectionEditorOptions, EntityCustomView, EntityAction, EntityCollection, RebasePlugin } from "@rebasepro/types";
|
|
16
20
|
import type { CollectionRegistryController } from "@rebasepro/types";
|
|
@@ -35,8 +39,8 @@ import { ConfigControllerProvider } from "../collection_editor/ConfigControllerP
|
|
|
35
39
|
|
|
36
40
|
// Lazy-load the schema view — only fetched when studio schema tool is active
|
|
37
41
|
const CollectionsStudioView = lazy(() =>
|
|
38
|
-
import("../collection_editor/ui/collection_editor/
|
|
39
|
-
.then(m => ({ default: m.
|
|
42
|
+
import("../collection_editor/ui/collection_editor/RouterCollectionsStudioView")
|
|
43
|
+
.then(m => ({ default: m.RouterCollectionsStudioView }))
|
|
40
44
|
);
|
|
41
45
|
|
|
42
46
|
export interface RebaseNavigationProps {
|
|
@@ -86,7 +90,24 @@ export function RebaseNavigation({ children }: RebaseNavigationProps) {
|
|
|
86
90
|
// ── Build the navigation controllers ──────────────────────────────
|
|
87
91
|
const collectionsBuilder = useMemo(() => Array.isArray(cmsCollections) ? () => [...cmsCollections] : cmsCollections, [cmsCollections]);
|
|
88
92
|
|
|
89
|
-
const
|
|
93
|
+
const dataSources = useDataSources();
|
|
94
|
+
const collectionRegistryController = useBuildCollectionRegistryController({ userConfigPersistence, dataSources: dataSources.registry });
|
|
95
|
+
|
|
96
|
+
// ── Multi-data-source routing ─────────────────────────────────────
|
|
97
|
+
// Combine the default data source (server transport) with the registered
|
|
98
|
+
// direct/custom sources from <Rebase> and route each collection by its
|
|
99
|
+
// resolved data-source key, looked up by path against the collection
|
|
100
|
+
// registry. A stable resolver ref keeps the routed data instance
|
|
101
|
+
// referentially stable across registry rebuilds, so data-effect
|
|
102
|
+
// dependencies don't thrash.
|
|
103
|
+
const defaultData = useData();
|
|
104
|
+
const getCollectionRef = useRef(collectionRegistryController.getCollection);
|
|
105
|
+
getCollectionRef.current = collectionRegistryController.getCollection;
|
|
106
|
+
const routedData = useMemo(() => buildRoutedRebaseData({
|
|
107
|
+
defaultData,
|
|
108
|
+
sources: dataSources.sources,
|
|
109
|
+
resolveKey: (slugOrPath) => resolveDataSource(getCollectionRef.current(slugOrPath), dataSources.registry).key
|
|
110
|
+
}), [defaultData, dataSources]);
|
|
90
111
|
|
|
91
112
|
const urlController = useBuildUrlController({
|
|
92
113
|
basePath: "/",
|
|
@@ -102,6 +123,26 @@ export function RebaseNavigation({ children }: RebaseNavigationProps) {
|
|
|
102
123
|
[cmsCollections]
|
|
103
124
|
);
|
|
104
125
|
|
|
126
|
+
// ── Dev-only data-source sanity check ─────────────────────────────
|
|
127
|
+
// Warn about data sources declared with a direct/custom transport that
|
|
128
|
+
// have no client-side driver — these silently fall back to the default
|
|
129
|
+
// (server) source, a common source of misrouting. Unambiguous: it never
|
|
130
|
+
// false-positives on server-mediated sources (which intentionally have
|
|
131
|
+
// no client driver).
|
|
132
|
+
useEffect(() => {
|
|
133
|
+
if (process.env.NODE_ENV === "production") return;
|
|
134
|
+
const { registry, sources } = dataSources;
|
|
135
|
+
const missing = Object.values(registry)
|
|
136
|
+
.filter((d) => (d.transport === "direct" || d.transport === "custom") && !sources[d.key])
|
|
137
|
+
.map((d) => d.key);
|
|
138
|
+
if (missing.length > 0) {
|
|
139
|
+
console.warn(
|
|
140
|
+
`[Rebase] These data source(s) declare a direct/custom transport but have no client-side driver and will fall back to the default data source: ${missing.map(k => `"${k}"`).join(", ")}. ` +
|
|
141
|
+
`Provide a \`driver\` for them in \`dataSources\` on <Rebase>.`
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
}, [dataSources]);
|
|
145
|
+
|
|
105
146
|
const internalConfigController = useLocalCollectionsConfigController(
|
|
106
147
|
rebaseClient,
|
|
107
148
|
resolvedCollections,
|
|
@@ -120,6 +161,7 @@ export function RebaseNavigation({ children }: RebaseNavigationProps) {
|
|
|
120
161
|
return {
|
|
121
162
|
slug: "schema",
|
|
122
163
|
name: "Edit collections",
|
|
164
|
+
group: "Database",
|
|
123
165
|
icon: "LayoutList",
|
|
124
166
|
nestedRoutes: true,
|
|
125
167
|
view: (
|
|
@@ -136,13 +178,32 @@ export function RebaseNavigation({ children }: RebaseNavigationProps) {
|
|
|
136
178
|
return base;
|
|
137
179
|
}, [registry.studioConfig?.devViews, schemaView]);
|
|
138
180
|
|
|
181
|
+
// Merge CMS-registered views with Studio dev views.
|
|
182
|
+
// Order: CMS views (developer's primary content) → Studio dev views (tooling).
|
|
183
|
+
// Plugin views are merged later inside resolveAppViews.
|
|
184
|
+
const cmsViews = registry.cmsConfig?.views;
|
|
185
|
+
const mergedViews = useMemo(() => {
|
|
186
|
+
if (!cmsViews) return devViews;
|
|
187
|
+
if (Array.isArray(cmsViews) && cmsViews.length === 0) return devViews;
|
|
188
|
+
// When cmsViews is a builder function, wrap it to append devViews after resolution
|
|
189
|
+
if (typeof cmsViews === "function") {
|
|
190
|
+
return async (params: Parameters<typeof cmsViews>[0]) => {
|
|
191
|
+
const resolved = await cmsViews(params) ?? [];
|
|
192
|
+
return [...resolved, ...devViews];
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
return [...cmsViews, ...devViews];
|
|
196
|
+
}, [cmsViews, devViews]);
|
|
197
|
+
|
|
198
|
+
const parentCustomizationController = useCustomizationController();
|
|
199
|
+
|
|
139
200
|
const navigationStateController = useBuildNavigationStateController({
|
|
140
|
-
plugins:
|
|
201
|
+
plugins: parentCustomizationController.plugins ?? EMPTY_PLUGINS,
|
|
141
202
|
collections: collectionsBuilder,
|
|
142
|
-
views:
|
|
203
|
+
views: mergedViews,
|
|
143
204
|
navigationGroupMappings: registry.cmsConfig?.navigationGroupMappings,
|
|
144
205
|
authController: context.authController!,
|
|
145
|
-
data:
|
|
206
|
+
data: routedData,
|
|
146
207
|
collectionRegistryController,
|
|
147
208
|
urlController,
|
|
148
209
|
adminMode: adminModeController?.mode
|
|
@@ -154,7 +215,6 @@ export function RebaseNavigation({ children }: RebaseNavigationProps) {
|
|
|
154
215
|
// automatically merged. We re-provide an enriched controller here so that
|
|
155
216
|
// downstream consumers (EntityEditView, side panels, etc.) can resolve
|
|
156
217
|
// string-keyed entity views like "blog_preview".
|
|
157
|
-
const parentCustomizationController = useCustomizationController();
|
|
158
218
|
const enrichedCustomizationController = useMemo(() => {
|
|
159
219
|
const cmsEntityViews = (registry.cmsConfig?.entityViews ?? []) as EntityCustomView[];
|
|
160
220
|
const cmsEntityActions = (registry.cmsConfig?.entityActions ?? []) as EntityAction[];
|
|
@@ -175,7 +235,11 @@ export function RebaseNavigation({ children }: RebaseNavigationProps) {
|
|
|
175
235
|
}, [parentCustomizationController, registry.cmsConfig?.entityViews, registry.cmsConfig?.entityActions]);
|
|
176
236
|
|
|
177
237
|
// ── Inner content with all context providers ──────────────────────
|
|
238
|
+
// Re-provide RebaseDataContext with the routed data so that every CMS
|
|
239
|
+
// consumer (list/entity views, references, board, import/export, and
|
|
240
|
+
// `context.data`) is routed to the correct driver by collection path.
|
|
178
241
|
const navigationContent = (
|
|
242
|
+
<RebaseDataContext.Provider value={routedData}>
|
|
179
243
|
<CustomizationControllerContext.Provider value={enrichedCustomizationController}>
|
|
180
244
|
<StudioBridgeRegistryProvider>
|
|
181
245
|
<CollectionRegistryContext.Provider value={collectionRegistryController}>
|
|
@@ -194,6 +258,7 @@ export function RebaseNavigation({ children }: RebaseNavigationProps) {
|
|
|
194
258
|
</CollectionRegistryContext.Provider>
|
|
195
259
|
</StudioBridgeRegistryProvider>
|
|
196
260
|
</CustomizationControllerContext.Provider>
|
|
261
|
+
</RebaseDataContext.Provider>
|
|
197
262
|
);
|
|
198
263
|
|
|
199
264
|
// ── Wrap with ConfigControllerProvider when collection editor is enabled ──
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
import * as React from "react";
|
|
25
25
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
26
26
|
import { Command as CommandPrimitive } from "cmdk";
|
|
27
|
-
import { Entity, EntityRelation, FilterValues, Relation } from "@rebasepro/types";
|
|
27
|
+
import { Entity, EntityRelation, FilterValues, Relation, getCollectionDataPath } from "@rebasepro/types";
|
|
28
28
|
import { EntityPreviewData } from "./EntityPreview";
|
|
29
29
|
import { useData, useRelationSelector } from "@rebasepro/core";
|
|
30
30
|
import { useSideEntityController } from "../hooks/useSideEntityController";
|
|
@@ -115,7 +115,7 @@ export const RelationSelector = React.forwardRef<
|
|
|
115
115
|
loadMore,
|
|
116
116
|
entityToRelationItem
|
|
117
117
|
} = useRelationSelector({
|
|
118
|
-
path: collection
|
|
118
|
+
path: getCollectionDataPath(collection),
|
|
119
119
|
collection,
|
|
120
120
|
fixedFilter,
|
|
121
121
|
pageSize
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { createSelectionStore } from "./SelectionStore";
|
|
1
|
+
import { createSelectionStore, AdminSelectedCell } from "./SelectionStore";
|
|
2
2
|
import type { Property } from "@rebasepro/types";
|
|
3
3
|
import React, { useCallback, useEffect, useMemo, useRef } from "react";
|
|
4
4
|
import { CollectionSize, Entity, EntityRelation, EntityTableController, FilterValues, SelectedCellProps } from "@rebasepro/types";
|
|
5
|
-
import { CellRendererParams,
|
|
5
|
+
import { CellRendererParams, TableView, VirtualTableColumn, VirtualTableFilterValues, OnRowClickParams, VirtualTableWhereFilterOp } from "@rebasepro/ui";
|
|
6
6
|
import { enumToObjectEntries } from "@rebasepro/common";
|
|
7
7
|
import { DEFAULT_PAGE_SIZE, EntityCollectionTableController, OnCellValueChange, OnColumnResizeParams } from "@rebasepro/core";
|
|
8
8
|
import { FilterFormFieldProps } from "@rebasepro/ui";
|
|
@@ -192,7 +192,15 @@ export const SelectableTable = function SelectableTable<M extends Record<string,
|
|
|
192
192
|
|
|
193
193
|
const select = useCallback((cell?: SelectedCellProps<M>) => {
|
|
194
194
|
setLocalSelectedCell(cell);
|
|
195
|
-
|
|
195
|
+
if (cell) {
|
|
196
|
+
selectionStore.select({
|
|
197
|
+
...cell,
|
|
198
|
+
columnKey: cell.propertyKey,
|
|
199
|
+
rowId: cell.entityId
|
|
200
|
+
} as AdminSelectedCell);
|
|
201
|
+
} else {
|
|
202
|
+
selectionStore.select(undefined);
|
|
203
|
+
}
|
|
196
204
|
}, [selectionStore]);
|
|
197
205
|
|
|
198
206
|
const unselect = useCallback(() => {
|
|
@@ -244,7 +252,7 @@ export const SelectableTable = function SelectableTable<M extends Record<string,
|
|
|
244
252
|
<div className="h-full w-full flex flex-col bg-white dark:bg-surface-900"
|
|
245
253
|
ref={ref}>
|
|
246
254
|
|
|
247
|
-
|
|
255
|
+
<TableView
|
|
248
256
|
data={data as unknown as Record<string, unknown>[]}
|
|
249
257
|
columns={columns}
|
|
250
258
|
cellRenderer={(props) => cellRenderer(props as unknown as CellRendererParams<Entity<M>>)}
|
|
@@ -255,7 +263,7 @@ export const SelectableTable = function SelectableTable<M extends Record<string,
|
|
|
255
263
|
onColumnResize={onColumnResize}
|
|
256
264
|
rowHeight={getRowHeight(size)}
|
|
257
265
|
loading={dataLoading}
|
|
258
|
-
filter={filterValues}
|
|
266
|
+
filter={filterValues as any}
|
|
259
267
|
onFilterUpdate={setFilterValues ? onFilterUpdate : undefined}
|
|
260
268
|
sortBy={sortBy}
|
|
261
269
|
onSortByUpdate={setSortBy as ((sortBy?: [string, "asc" | "desc"]) => void)}
|
|
@@ -1,64 +1,34 @@
|
|
|
1
1
|
import { useSyncExternalStore, useCallback, useRef } from "react";
|
|
2
2
|
import { SelectedCellProps } from "@rebasepro/types";
|
|
3
|
+
import {
|
|
4
|
+
createVirtualTableSelectionStore,
|
|
5
|
+
VirtualTableSelectionStore,
|
|
6
|
+
SelectedCell
|
|
7
|
+
} from "@rebasepro/ui";
|
|
8
|
+
|
|
9
|
+
export interface AdminSelectedCell extends SelectedCell {
|
|
10
|
+
entityPath: string;
|
|
11
|
+
entityId: string | number;
|
|
12
|
+
propertyKey: string;
|
|
13
|
+
cellRect: DOMRect;
|
|
14
|
+
width: number;
|
|
15
|
+
height: number;
|
|
16
|
+
}
|
|
3
17
|
|
|
4
|
-
/**
|
|
5
|
-
* A ref-based selection store that avoids React context re-renders.
|
|
6
|
-
*
|
|
7
|
-
* The problem with putting `selectedCell` in a React context value is that
|
|
8
|
-
* ANY cell selection change triggers a context value change, which forces
|
|
9
|
-
* ALL consumers (every PropertyTableCell in the table) to re-render.
|
|
10
|
-
* This causes the DOM to be replaced between mousedown and click events,
|
|
11
|
-
* breaking `alwaysInteractive` cells (like relation selectors) where the
|
|
12
|
-
* user needs to click a button on the very first interaction.
|
|
13
|
-
*
|
|
14
|
-
* This store uses `useSyncExternalStore` so only cells whose `selected`
|
|
15
|
-
* derivation actually changed will re-render.
|
|
16
|
-
*/
|
|
17
18
|
export function createSelectionStore() {
|
|
18
|
-
|
|
19
|
-
const listeners = new Set<() => void>();
|
|
20
|
-
|
|
21
|
-
function getSnapshot(): SelectedCellProps | undefined {
|
|
22
|
-
return selectedCell;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function subscribe(listener: () => void): () => void {
|
|
26
|
-
listeners.add(listener);
|
|
27
|
-
return () => listeners.delete(listener);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function select(cell: SelectedCellProps | undefined) {
|
|
31
|
-
selectedCell = cell;
|
|
32
|
-
listeners.forEach(l => l());
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return { getSnapshot,
|
|
36
|
-
subscribe,
|
|
37
|
-
select };
|
|
19
|
+
return createVirtualTableSelectionStore<AdminSelectedCell>();
|
|
38
20
|
}
|
|
39
21
|
|
|
40
|
-
export type SelectionStore =
|
|
22
|
+
export type SelectionStore = VirtualTableSelectionStore<AdminSelectedCell>;
|
|
41
23
|
|
|
42
|
-
/**
|
|
43
|
-
* Hook that subscribes a cell to the selection store and returns
|
|
44
|
-
* whether THIS cell is selected. Only re-renders when the cell's
|
|
45
|
-
* `selected` boolean actually changes (not on every store update).
|
|
46
|
-
*/
|
|
47
24
|
export function useCellSelected(
|
|
48
25
|
store: { getSnapshot: () => SelectedCellProps | undefined; subscribe: (listener: () => void) => () => void },
|
|
49
26
|
propertyKey: string,
|
|
50
27
|
entityPath: string,
|
|
51
28
|
entityId: string | number
|
|
52
29
|
): boolean {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
// React only re-renders when the returned value !== the previous one.
|
|
56
|
-
const selectorRef = useRef({ propertyKey,
|
|
57
|
-
entityPath,
|
|
58
|
-
entityId });
|
|
59
|
-
selectorRef.current = { propertyKey,
|
|
60
|
-
entityPath,
|
|
61
|
-
entityId };
|
|
30
|
+
const selectorRef = useRef({ propertyKey, entityPath, entityId });
|
|
31
|
+
selectorRef.current = { propertyKey, entityPath, entityId };
|
|
62
32
|
|
|
63
33
|
const getSnapshot = useCallback(() => {
|
|
64
34
|
const cell = store.getSnapshot();
|
|
@@ -179,13 +179,6 @@ function SideDialogView({
|
|
|
179
179
|
style={{ zIndex: 45 + panelIndex * 10 }}
|
|
180
180
|
onOpenChange={(open) => {
|
|
181
181
|
if (!open) {
|
|
182
|
-
// Check if any suggestion menu is visible in DOM
|
|
183
|
-
const suggestionMenu = document.querySelector("[data-suggestion-menu=\"true\"]");
|
|
184
|
-
if (suggestionMenu && window.getComputedStyle(suggestionMenu).visibility !== "hidden") {
|
|
185
|
-
// Don't close the sheet if a suggestion menu is visible
|
|
186
|
-
// Let Tiptap handle closing the menu first
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
182
|
onCloseRequest();
|
|
190
183
|
}
|
|
191
184
|
}}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { CopyIcon, iconSize, KeyRoundIcon, PencilIcon, Trash2Icon } from "@rebasepro/ui";
|
|
2
2
|
import type { EntityAction, User, UserCreationResult } from "@rebasepro/types";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
ConfirmationDialog,
|
|
5
|
+
useAuthController,
|
|
6
|
+
useRebaseClient,
|
|
7
|
+
useSnackbarController,
|
|
8
|
+
useTranslation
|
|
9
|
+
} from "@rebasepro/core";
|
|
4
10
|
import { DeleteEntityDialog } from "../DeleteEntityDialog";
|
|
5
11
|
import { addRecentId } from "../EntityCollectionView/utils";
|
|
6
12
|
import { navigateToEntity } from "../../util/navigation_utils";
|
|
@@ -8,7 +14,6 @@ import { resolveDefaultSelectedView } from "@rebasepro/common";
|
|
|
8
14
|
import { CreationResultDialog } from "../admin/CreationResultDialog";
|
|
9
15
|
import React, { useState } from "react";
|
|
10
16
|
|
|
11
|
-
|
|
12
17
|
export const editEntityAction: EntityAction = {
|
|
13
18
|
icon: <PencilIcon size={iconSize.smallest}/>,
|
|
14
19
|
key: "edit",
|
|
@@ -36,7 +41,7 @@ export const editEntityAction: EntityAction = {
|
|
|
36
41
|
|
|
37
42
|
highlightEntity?.(entity);
|
|
38
43
|
|
|
39
|
-
context
|
|
44
|
+
context?.analyticsController?.onAnalyticsEvent?.("entity_click", {
|
|
40
45
|
path: entity.path,
|
|
41
46
|
entityId: entity.id
|
|
42
47
|
});
|
|
@@ -55,6 +60,9 @@ export const editEntityAction: EntityAction = {
|
|
|
55
60
|
entityId: entity.id
|
|
56
61
|
}
|
|
57
62
|
);
|
|
63
|
+
if (!context?.urlController) {
|
|
64
|
+
throw new Error("INTERNAL: editEntityAction: urlController is undefined");
|
|
65
|
+
}
|
|
58
66
|
navigateToEntity({
|
|
59
67
|
openEntityMode,
|
|
60
68
|
collection,
|
|
@@ -62,7 +70,7 @@ export const editEntityAction: EntityAction = {
|
|
|
62
70
|
path: newFullIdPath,
|
|
63
71
|
sideEntityController,
|
|
64
72
|
onClose: () => unhighlightEntity?.(entity),
|
|
65
|
-
navigation: context.urlController
|
|
73
|
+
navigation: context.urlController,
|
|
66
74
|
selectedTab: defaultSelectedView
|
|
67
75
|
});
|
|
68
76
|
|
|
@@ -92,12 +100,15 @@ export const copyEntityAction: EntityAction = {
|
|
|
92
100
|
throw new Error("INTERNAL: copyEntityAction: sideEntityController is undefined");
|
|
93
101
|
}
|
|
94
102
|
highlightEntity?.(entity);
|
|
95
|
-
context
|
|
103
|
+
context?.analyticsController?.onAnalyticsEvent?.("copy_entity_click", {
|
|
96
104
|
path: entity.path,
|
|
97
105
|
entityId: entity.id
|
|
98
106
|
});
|
|
99
107
|
|
|
100
108
|
const usedPath = path ?? collection?.slug ?? entity.path;
|
|
109
|
+
if (!context?.urlController) {
|
|
110
|
+
throw new Error("INTERNAL: copyEntityAction: urlController is undefined");
|
|
111
|
+
}
|
|
101
112
|
navigateToEntity({
|
|
102
113
|
openEntityMode,
|
|
103
114
|
collection,
|
|
@@ -106,7 +117,7 @@ export const copyEntityAction: EntityAction = {
|
|
|
106
117
|
copy: true,
|
|
107
118
|
sideEntityController,
|
|
108
119
|
onClose: () => unhighlightEntity?.(entity),
|
|
109
|
-
navigation: context.urlController
|
|
120
|
+
navigation: context.urlController
|
|
110
121
|
});
|
|
111
122
|
|
|
112
123
|
return Promise.resolve(undefined);
|
|
@@ -131,7 +142,7 @@ export const deleteEntityAction: EntityAction = {
|
|
|
131
142
|
if (!entity) {
|
|
132
143
|
throw new Error("INTERNAL: deleteEntityAction: Entity is undefined");
|
|
133
144
|
}
|
|
134
|
-
if (!context
|
|
145
|
+
if (!context?.dialogsController) {
|
|
135
146
|
throw new Error("INTERNAL: deleteEntityAction: context.dialogsController is undefined");
|
|
136
147
|
}
|
|
137
148
|
const { closeDialog } = context.dialogsController.open({
|
|
@@ -146,14 +157,14 @@ export const deleteEntityAction: EntityAction = {
|
|
|
146
157
|
callbacks={collection.callbacks}
|
|
147
158
|
open={open}
|
|
148
159
|
onEntityDelete={() => {
|
|
149
|
-
context
|
|
160
|
+
context?.analyticsController?.onAnalyticsEvent?.("single_entity_deleted", {
|
|
150
161
|
path
|
|
151
162
|
});
|
|
152
163
|
selectionController?.setSelectedEntities(selectionController.selectedEntities.filter(e => e.id !== entity.id));
|
|
153
164
|
onCollectionChange?.();
|
|
154
165
|
// In full-screen mode, navigateBack would go to the deleted entity's
|
|
155
166
|
// detail URL, which no longer exists. Navigate to the parent collection instead.
|
|
156
|
-
if (openEntityMode === "full_screen" && context
|
|
167
|
+
if (openEntityMode === "full_screen" && context?.urlController) {
|
|
157
168
|
const collectionUrl = context.urlController.buildUrlCollectionPath(path);
|
|
158
169
|
context.urlController.navigate(collectionUrl, { replace: true });
|
|
159
170
|
} else {
|
|
@@ -258,7 +269,7 @@ export const resetPasswordAction: EntityAction = {
|
|
|
258
269
|
if (!entity) {
|
|
259
270
|
throw new Error("INTERNAL: resetPasswordAction: Entity is undefined");
|
|
260
271
|
}
|
|
261
|
-
if (!context
|
|
272
|
+
if (!context?.dialogsController) {
|
|
262
273
|
throw new Error("INTERNAL: resetPasswordAction: context.dialogsController is undefined");
|
|
263
274
|
}
|
|
264
275
|
|
|
@@ -272,7 +283,7 @@ export const resetPasswordAction: EntityAction = {
|
|
|
272
283
|
roles: entity.values?.roles as string[] || []
|
|
273
284
|
};
|
|
274
285
|
|
|
275
|
-
const { closeDialog } = context
|
|
286
|
+
const { closeDialog } = context!.dialogsController.open({
|
|
276
287
|
key: "reset_password_dialog_" + entity.id,
|
|
277
288
|
Component: ({ open }) => (
|
|
278
289
|
<ResetPasswordActionDialog
|
|
@@ -9,7 +9,6 @@ import { KeyValueFieldBinding } from "../form/field_bindings/KeyValueFieldBindin
|
|
|
9
9
|
import { MapFieldBinding } from "../form/field_bindings/MapFieldBinding";
|
|
10
10
|
import { MarkdownEditorFieldBinding } from "../form/field_bindings/MarkdownEditorFieldBinding";
|
|
11
11
|
import { MultiSelectFieldBinding } from "../form/field_bindings/MultiSelectFieldBinding";
|
|
12
|
-
import { ReferenceAsStringFieldBinding } from "../form/field_bindings/ReferenceAsStringFieldBinding";
|
|
13
12
|
import { ReferenceFieldBinding } from "../form/field_bindings/ReferenceFieldBinding";
|
|
14
13
|
import { RepeatFieldBinding } from "../form/field_bindings/RepeatFieldBinding";
|
|
15
14
|
import { SelectFieldBinding } from "../form/field_bindings/SelectFieldBinding";
|
|
@@ -220,17 +219,6 @@ Field: TextFieldBinding }
|
|
|
220
219
|
ui: { Field: StorageUploadFieldBinding }
|
|
221
220
|
}
|
|
222
221
|
},
|
|
223
|
-
reference_as_string: {
|
|
224
|
-
key: "reference_as_string",
|
|
225
|
-
name: "Reference (as string)",
|
|
226
|
-
description: "The value refers to a different collection (it is saved as a string)",
|
|
227
|
-
Icon: LinkIcon,
|
|
228
|
-
color: "#154fb3",
|
|
229
|
-
property: {
|
|
230
|
-
type: "string",
|
|
231
|
-
ui: { Field: ReferenceAsStringFieldBinding }
|
|
232
|
-
}
|
|
233
|
-
},
|
|
234
222
|
reference: {
|
|
235
223
|
key: "reference",
|
|
236
224
|
name: "Reference",
|
|
@@ -393,8 +381,6 @@ export function getDefaultFieldId(property: Property) {
|
|
|
393
381
|
return "select";
|
|
394
382
|
} else if (property.userSelect) {
|
|
395
383
|
return "user_select";
|
|
396
|
-
} else if ((property as StringProperty).reference) {
|
|
397
|
-
return "reference_as_string";
|
|
398
384
|
} else {
|
|
399
385
|
return "text_field";
|
|
400
386
|
}
|