@rebasepro/admin 0.0.1-canary.f81da60 → 0.1.2
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-D509-IMx.js → CollectionEditorDialog-ywdxhs1L.js} +18 -18
- package/dist/CollectionEditorDialog-ywdxhs1L.js.map +1 -0
- package/dist/{CollectionsStudioView-B549BDpU.js → CollectionsStudioView-BDzMFzqH.js} +4 -4
- package/dist/{CollectionsStudioView-B549BDpU.js.map → CollectionsStudioView-BDzMFzqH.js.map} +1 -1
- package/dist/{ContentHomePage--Bl1FXk7.js → ContentHomePage-0tHuEIm_.js} +26 -26
- package/dist/ContentHomePage-0tHuEIm_.js.map +1 -0
- package/dist/{ExportCollectionAction-CttNAdM1.js → ExportCollectionAction-BIrq92To.js} +2 -2
- package/dist/{ExportCollectionAction-CttNAdM1.js.map → ExportCollectionAction-BIrq92To.js.map} +1 -1
- package/dist/{ImportCollectionAction-BB33kxAN.js → ImportCollectionAction-h8yg_To8.js} +2 -2
- package/dist/{ImportCollectionAction-BB33kxAN.js.map → ImportCollectionAction-h8yg_To8.js.map} +1 -1
- package/dist/{PropertyEditView-UtDO8g0A.js → PropertyEditView-BuZrNnBN.js} +79 -101
- package/dist/PropertyEditView-BuZrNnBN.js.map +1 -0
- package/dist/{RolesView-B0E7L0hE.js → RolesView-CMPsaIXo.js} +2 -2
- package/dist/{RolesView-B0E7L0hE.js.map → RolesView-CMPsaIXo.js.map} +1 -1
- package/dist/{UsersView-BM2_7VPV.js → UsersView-BkeblMVT.js} +6 -28
- package/dist/UsersView-BkeblMVT.js.map +1 -0
- package/dist/collection_editor/ConfigControllerProvider.d.ts +0 -4
- package/dist/collection_editor/ui/collection_editor/CollectionDetailsForm.d.ts +1 -3
- package/dist/collection_editor/ui/collection_editor/CollectionEditorDialog.d.ts +0 -2
- package/dist/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +1 -2
- package/dist/collection_editor_ui.js +3 -3
- package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +5 -1
- package/dist/components/EntityCollectionView/EntityCollectionViewActions.d.ts +2 -1
- package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +2 -1
- package/dist/components/EntityEditView.d.ts +6 -0
- package/dist/components/RebaseCMS.d.ts +1 -1
- package/dist/{index-C9YDsMC9.js → index-BuZaHcyc.js} +3 -3
- package/dist/index-BuZaHcyc.js.map +1 -0
- package/dist/{index-CNDetux9.js → index-CS6uJ7oW.js} +2 -2
- package/dist/{index-CNDetux9.js.map → index-CS6uJ7oW.js.map} +1 -1
- package/dist/{index-DO7lMeNB.js → index-eRJbMvHi.js} +3 -3
- package/dist/index-eRJbMvHi.js.map +1 -0
- package/dist/index.js +18 -14
- package/dist/index.js.map +1 -1
- package/dist/util/navigation_utils.d.ts +10 -1
- package/dist/{util-DK1O3uM0.js → util-zfU1zOCX.js} +713 -603
- package/dist/util-zfU1zOCX.js.map +1 -0
- package/package.json +8 -8
- package/src/collection_editor/ConfigControllerProvider.tsx +1 -10
- package/src/collection_editor/ui/collection_editor/CollectionDetailsForm.tsx +3 -47
- package/src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx +2 -10
- package/src/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.tsx +1 -3
- package/src/collection_editor/ui/collection_editor/CollectionRelationsTab.tsx +3 -3
- package/src/collection_editor/ui/collection_editor/GetCodeDialog.tsx +0 -1
- package/src/collection_editor/ui/collection_editor/PropertyFieldPreview.tsx +6 -6
- package/src/collection_editor/ui/collection_editor/properties/MapPropertyField.tsx +1 -1
- package/src/collection_editor/ui/collection_editor/properties/ReferencePropertyField.tsx +15 -49
- package/src/collection_editor/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.tsx +2 -3
- 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/EntityCollectionRowActions.tsx +5 -3
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +1 -1
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +8 -2
- package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +2 -2
- package/src/components/EntityCollectionTable/table_bindings.tsx +37 -27
- package/src/components/EntityCollectionView/EntityCard.tsx +2 -2
- package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +4 -3
- package/src/components/EntityCollectionView/EntityCollectionListView.tsx +7 -6
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +50 -7
- package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +17 -8
- package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +8 -4
- package/src/components/EntityCollectionView/useEntityPreviewSlots.ts +33 -5
- package/src/components/EntityEditView.tsx +80 -81
- package/src/components/EntitySidePanel.tsx +11 -7
- 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 +7 -4
- package/src/components/RelationSelector.tsx +30 -2
- package/src/components/SelectableTable/SelectableTable.tsx +2 -2
- package/src/components/UserSelector.tsx +1 -1
- package/src/components/admin/UsersView.tsx +2 -17
- package/src/components/app/Scaffold.tsx +3 -3
- package/src/components/field_configs.tsx +3 -3
- package/src/form/PropertyFieldBinding.tsx +10 -6
- 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/preview/PropertyPreview.tsx +17 -13
- package/src/routes/RebaseRoute.tsx +27 -2
- package/src/util/navigation_utils.ts +16 -2
- package/src/util/previews.ts +14 -5
- package/dist/CollectionEditorDialog-D509-IMx.js.map +0 -1
- package/dist/ContentHomePage--Bl1FXk7.js.map +0 -1
- package/dist/PropertyEditView-UtDO8g0A.js.map +0 -1
- package/dist/UsersView-BM2_7VPV.js.map +0 -1
- package/dist/index-C9YDsMC9.js.map +0 -1
- package/dist/index-DO7lMeNB.js.map +0 -1
- package/dist/util-DK1O3uM0.js.map +0 -1
|
@@ -137,7 +137,7 @@ export const Scaffold = React.memo<PropsWithChildren<ScaffoldProps>>(
|
|
|
137
137
|
{hasAppBar && <DrawerHeader/>}
|
|
138
138
|
|
|
139
139
|
<div
|
|
140
|
-
className={cls(defaultBorderMixin, "bg-
|
|
140
|
+
className={cls(defaultBorderMixin, "bg-surface-50 dark:bg-surface-800", "grow overflow-auto m-0", {
|
|
141
141
|
"lg:mt-4": !hasAppBar,
|
|
142
142
|
"mt-1 lg:m-0 lg:mx-2 lg:mb-2 lg:rounded-lg lg:border-t lg:border-x lg:border-solid": padding,
|
|
143
143
|
"border-t": hasAppBar && !padding
|
|
@@ -158,7 +158,7 @@ export const Scaffold = React.memo<PropsWithChildren<ScaffoldProps>>(
|
|
|
158
158
|
|
|
159
159
|
const DrawerHeader = () => {
|
|
160
160
|
return (
|
|
161
|
-
<div className="flex flex-col min-h-
|
|
161
|
+
<div className="flex flex-col min-h-14"></div>
|
|
162
162
|
);
|
|
163
163
|
};
|
|
164
164
|
|
|
@@ -185,7 +185,7 @@ function DrawerWrapper(props: {
|
|
|
185
185
|
|
|
186
186
|
const innerDrawer = <div
|
|
187
187
|
className={cls("h-full overflow-hidden", defaultBorderMixin,
|
|
188
|
-
isFloating ? `absolute top-0 left-0 bottom-0 z-50 bg-surface-50 ${darkBgFloating} shadow-
|
|
188
|
+
isFloating ? `absolute top-0 left-0 bottom-0 z-50 bg-surface-50 ${darkBgFloating} shadow-lg border-r` : `relative bg-surface-50 ${darkBg}`)}
|
|
189
189
|
style={{
|
|
190
190
|
width: visualWidth,
|
|
191
191
|
transition: "left 75ms cubic-bezier(0.4, 0, 0.6, 1) 0ms, opacity 75ms cubic-bezier(0.4, 0, 0.6, 1) 0ms, width 75ms cubic-bezier(0.4, 0, 0.6, 1) 0ms"
|
|
@@ -344,10 +344,10 @@ export function getFieldConfig(property: Property, propertyConfigs: Record<strin
|
|
|
344
344
|
|
|
345
345
|
export function getDefaultFieldId(property: Property) {
|
|
346
346
|
if (property.type === "string") {
|
|
347
|
-
if (property.ui?.
|
|
348
|
-
return "multiline";
|
|
349
|
-
} else if (property.ui?.markdown) {
|
|
347
|
+
if (property.ui?.markdown) {
|
|
350
348
|
return "markdown";
|
|
349
|
+
} else if (property.ui?.multiline) {
|
|
350
|
+
return "multiline";
|
|
351
351
|
} else if (property.storage) {
|
|
352
352
|
return "file_upload";
|
|
353
353
|
} else if (property.ui?.url) {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { EntityCollection } from "@rebasepro/types";
|
|
2
2
|
import type { FieldProps, PropertyFieldBindingProps } from "../types/fields";
|
|
3
3
|
import type { RebasePlugin, PluginFieldBuilderParams, Property } from "@rebasepro/types";
|
|
4
|
-
import React, { ComponentType, ReactElement, useCallback, useRef } from "react";
|
|
4
|
+
import React, { ComponentType, ReactElement, Suspense, useCallback, useRef } from "react";
|
|
5
5
|
import { deepEqual as equal } from "fast-equals"
|
|
6
6
|
|
|
7
|
+
import { resolveComponentRef } from "@rebasepro/core";
|
|
8
|
+
|
|
7
9
|
import { Field, FieldProps as FormexFieldProps, getIn } from "@rebasepro/formex";
|
|
8
10
|
|
|
9
11
|
;
|
|
@@ -114,8 +116,9 @@ function PropertyFieldBindingInternal<M extends Record<string, unknown> = Record
|
|
|
114
116
|
} else if (readOnly) {
|
|
115
117
|
Component = ReadOnlyFieldBinding;
|
|
116
118
|
} else if (resolvedProperty.ui?.Field) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
+
const resolved = resolveComponentRef(resolvedProperty.ui.Field);
|
|
120
|
+
if (resolved) {
|
|
121
|
+
Component = resolved as ComponentType<FieldProps<any>>;
|
|
119
122
|
}
|
|
120
123
|
} else {
|
|
121
124
|
const propertyConfig = getFieldConfig(resolvedProperty, customizationController.propertyConfigs);
|
|
@@ -139,7 +142,7 @@ function PropertyFieldBindingInternal<M extends Record<string, unknown> = Record
|
|
|
139
142
|
index,
|
|
140
143
|
authController
|
|
141
144
|
}) as Property | null;
|
|
142
|
-
Component = configProperty?.ui?.Field as ComponentType<FieldProps> | undefined;
|
|
145
|
+
Component = resolveComponentRef(configProperty?.ui?.Field) as ComponentType<FieldProps> | undefined;
|
|
143
146
|
}
|
|
144
147
|
if (!Component) {
|
|
145
148
|
console.warn(`No field component found for property ${propertyKey}`);
|
|
@@ -265,8 +268,9 @@ function FieldInternal<CustomProps, M extends Record<string, any>>
|
|
|
265
268
|
|
|
266
269
|
return (
|
|
267
270
|
<ErrorBoundary>
|
|
268
|
-
|
|
269
|
-
|
|
271
|
+
<Suspense fallback={null}>
|
|
272
|
+
<UsedComponent {...cmsFieldProps}/>
|
|
273
|
+
</Suspense>
|
|
270
274
|
|
|
271
275
|
{underlyingValueHasChanged && !isSubmitting &&
|
|
272
276
|
<Typography variant={"caption"} className={"ml-3.5"}>
|
|
@@ -21,7 +21,7 @@ import { AuthController, RebaseData, User } from "@rebasepro/types";
|
|
|
21
21
|
import { UserManagementDelegate } from "@rebasepro/types";
|
|
22
22
|
|
|
23
23
|
import { resolveAppViews } from "./useNavigationResolution";
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
|
|
26
26
|
// Lazy-load admin views — only rendered when navigation reaches /users or /roles
|
|
27
27
|
const UsersView = lazy(() => import("../../components/admin/UsersView").then(m => ({ default: m.UsersView })));
|
|
@@ -128,7 +128,6 @@ export function useResolvedViews<USER extends User>(
|
|
|
128
128
|
views.push({
|
|
129
129
|
slug: "users",
|
|
130
130
|
name: "Users",
|
|
131
|
-
group: NAVIGATION_ADMIN_GROUP_NAME,
|
|
132
131
|
icon: "Headset",
|
|
133
132
|
view: usersViewElement
|
|
134
133
|
});
|
|
@@ -136,7 +135,6 @@ export function useResolvedViews<USER extends User>(
|
|
|
136
135
|
views.push({
|
|
137
136
|
slug: "roles",
|
|
138
137
|
name: "Roles",
|
|
139
|
-
group: NAVIGATION_ADMIN_GROUP_NAME,
|
|
140
138
|
icon: "Shield",
|
|
141
139
|
view: rolesViewElement
|
|
142
140
|
});
|
|
@@ -152,7 +152,7 @@ export function useTopLevelNavigation(
|
|
|
152
152
|
if (adminView.hideFromNavigation) return acc;
|
|
153
153
|
|
|
154
154
|
const pathKey = adminView.slug;
|
|
155
|
-
let groupName =
|
|
155
|
+
let groupName = NAVIGATION_ADMIN_GROUP_NAME;
|
|
156
156
|
|
|
157
157
|
if (finalNavigationGroupMappings) {
|
|
158
158
|
for (const pluginGroupDef of finalNavigationGroupMappings) {
|
|
@@ -11,7 +11,7 @@ export function getGroup(collectionOrView: EntityCollection<any, any> | AppView)
|
|
|
11
11
|
if (!trimmed || trimmed === "") {
|
|
12
12
|
return NAVIGATION_DEFAULT_GROUP_NAME;
|
|
13
13
|
}
|
|
14
|
-
return trimmed
|
|
14
|
+
return trimmed;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export function computeNavigationGroups({
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { ArrayProperty, MapProperty, NumberProperty, Property, StringProperty } from "@rebasepro/types";
|
|
2
|
-
import React, { createElement } from "react";
|
|
2
|
+
import React, { createElement, Suspense } from "react";
|
|
3
3
|
import { deepEqual as equal } from "fast-equals"
|
|
4
4
|
|
|
5
5
|
import { EntityReference, EntityRelation } from "@rebasepro/types";
|
|
6
6
|
import type { PropertyPreviewProps } from "../types/components/PropertyPreviewProps";
|
|
7
7
|
import { resolveProperty, normalizeToEntityRelation } from "@rebasepro/common";
|
|
8
|
-
import { useAuthController, useCustomizationController } from "@rebasepro/core";
|
|
8
|
+
import { useAuthController, useCustomizationController, resolveComponentRef } from "@rebasepro/core";
|
|
9
9
|
import { EmptyValue } from "./components/EmptyValue";
|
|
10
10
|
import { UrlComponentPreview } from "./components/UrlComponentPreview";
|
|
11
11
|
import { StorageThumbnail } from "./components/StorageThumbnail";
|
|
@@ -57,17 +57,21 @@ export const PropertyPreview = React.memo(function PropertyPreview<P extends Pro
|
|
|
57
57
|
if (property === null) {
|
|
58
58
|
content = <EmptyValue/>;
|
|
59
59
|
} else if (property.ui?.Preview) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
60
|
+
const ResolvedPreview = resolveComponentRef(property.ui.Preview);
|
|
61
|
+
if (ResolvedPreview) {
|
|
62
|
+
content = <Suspense fallback={null}>
|
|
63
|
+
{createElement(ResolvedPreview,
|
|
64
|
+
{
|
|
65
|
+
propertyKey,
|
|
66
|
+
value,
|
|
67
|
+
property,
|
|
68
|
+
size,
|
|
69
|
+
height,
|
|
70
|
+
width,
|
|
71
|
+
customProps: property.ui?.customProps
|
|
72
|
+
})}
|
|
73
|
+
</Suspense>;
|
|
74
|
+
}
|
|
71
75
|
} else if (value === undefined || value === null) {
|
|
72
76
|
content = <EmptyValue/>;
|
|
73
77
|
} else if (property.type === "string") {
|
|
@@ -235,6 +235,10 @@ function EntityFullScreenRoute({
|
|
|
235
235
|
const navigate = useNavigate();
|
|
236
236
|
const location = useLocation();
|
|
237
237
|
|
|
238
|
+
// defaultValues may be carried via location.state when openNewDocument() is called
|
|
239
|
+
// for full-screen mode. We read it once on mount — after that, the form owns its state.
|
|
240
|
+
const defaultValues = (location.state as { defaultValues?: Record<string, unknown> } | null)?.defaultValues;
|
|
241
|
+
|
|
238
242
|
// Preserve the current hash (e.g. #full) across tab/save navigations
|
|
239
243
|
const hash = location.hash;
|
|
240
244
|
|
|
@@ -289,10 +293,27 @@ function EntityFullScreenRoute({
|
|
|
289
293
|
let blocker: Blocker | undefined = undefined;
|
|
290
294
|
try {
|
|
291
295
|
blocker = useBlocker(({
|
|
296
|
+
currentLocation,
|
|
292
297
|
nextLocation
|
|
293
298
|
}) => {
|
|
294
299
|
if (nextLocation.pathname.startsWith(entityPath))
|
|
295
300
|
return false;
|
|
301
|
+
|
|
302
|
+
// Side panel overlay navigations preserve the underlying form via
|
|
303
|
+
// base_location in router state — no data is lost in either direction.
|
|
304
|
+
|
|
305
|
+
// Opening a side panel (e.g. clicking a relation arrow)
|
|
306
|
+
const nextHash = nextLocation.hash;
|
|
307
|
+
if (nextHash === "#side" || nextHash === "#new_side")
|
|
308
|
+
return false;
|
|
309
|
+
|
|
310
|
+
// Closing a side panel (navigate(-1) back to the form's own path)
|
|
311
|
+
const currentHash = currentLocation.hash;
|
|
312
|
+
if ((currentHash === "#side" || currentHash === "#new_side") &&
|
|
313
|
+
(nextLocation.pathname === basePath ||
|
|
314
|
+
nextLocation.pathname.startsWith(entityPath)))
|
|
315
|
+
return false;
|
|
316
|
+
|
|
296
317
|
return blocked.current;
|
|
297
318
|
});
|
|
298
319
|
} catch (e) {
|
|
@@ -330,14 +351,18 @@ function EntityFullScreenRoute({
|
|
|
330
351
|
path={collectionPath}
|
|
331
352
|
copy={isCopy}
|
|
332
353
|
selectedTab={selectedTab ?? undefined}
|
|
354
|
+
defaultValues={isNew ? defaultValues : undefined}
|
|
333
355
|
onValuesModified={(modified) => blocked.current = modified}
|
|
334
356
|
onSaved={(params) => {
|
|
335
357
|
const newSelectedTab = params.selectedTab;
|
|
336
358
|
const newEntityId = params.entityId;
|
|
359
|
+
// Clear the hash after saving a new entity — preserving #new
|
|
360
|
+
// would cause the route to re-parse as "new" and show "not found".
|
|
361
|
+
const savedHash = isNew ? "" : hash;
|
|
337
362
|
if (newSelectedTab) {
|
|
338
|
-
navigate(`${basePath}/${newEntityId}/${newSelectedTab}${
|
|
363
|
+
navigate(`${basePath}/${newEntityId}/${newSelectedTab}${savedHash}`, { replace: true });
|
|
339
364
|
} else {
|
|
340
|
-
navigate(`${basePath}/${newEntityId}${
|
|
365
|
+
navigate(`${basePath}/${newEntityId}${savedHash}`, { replace: true });
|
|
341
366
|
}
|
|
342
367
|
}}
|
|
343
368
|
onTabChange={(params) => {
|
|
@@ -23,6 +23,7 @@ export function navigateToEntity({
|
|
|
23
23
|
copy,
|
|
24
24
|
path,
|
|
25
25
|
selectedTab,
|
|
26
|
+
defaultValues,
|
|
26
27
|
sideEntityController,
|
|
27
28
|
onClose,
|
|
28
29
|
navigation
|
|
@@ -34,6 +35,15 @@ export function navigateToEntity({
|
|
|
34
35
|
entityId?: string | number;
|
|
35
36
|
selectedTab?: string;
|
|
36
37
|
copy?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Pre-populate the new entity form with these values.
|
|
40
|
+
* Only applied when entityId is not set (i.e. "new" mode).
|
|
41
|
+
*
|
|
42
|
+
* Side panel: passed through EntitySidePanelProps → EntityEditView.
|
|
43
|
+
* Full screen: carried via React Router location.state so the route
|
|
44
|
+
* component can read it on mount without polluting the URL.
|
|
45
|
+
*/
|
|
46
|
+
defaultValues?: Record<string, unknown>;
|
|
37
47
|
path: string;
|
|
38
48
|
sideEntityController: SideEntityController;
|
|
39
49
|
onClose?: () => void;
|
|
@@ -49,7 +59,8 @@ export function navigateToEntity({
|
|
|
49
59
|
selectedTab,
|
|
50
60
|
collection,
|
|
51
61
|
updateUrl: true,
|
|
52
|
-
onClose
|
|
62
|
+
onClose,
|
|
63
|
+
defaultValues
|
|
53
64
|
});
|
|
54
65
|
|
|
55
66
|
} else {
|
|
@@ -68,7 +79,10 @@ export function navigateToEntity({
|
|
|
68
79
|
if (copy) {
|
|
69
80
|
to += "#copy";
|
|
70
81
|
}
|
|
71
|
-
|
|
82
|
+
// Use React Router location.state to carry defaultValues — the correct SPA
|
|
83
|
+
// approach. No URL size limits, no encoding, nothing in the address bar.
|
|
84
|
+
// EntityFullScreenRoute reads location.state.defaultValues on mount.
|
|
85
|
+
navigation.navigate(to, defaultValues ? { state: { defaultValues } } : undefined);
|
|
72
86
|
}
|
|
73
87
|
|
|
74
88
|
}
|
package/src/util/previews.ts
CHANGED
|
@@ -35,16 +35,25 @@ export function getEntityTitlePropertyKey<M extends Record<string, unknown>>(col
|
|
|
35
35
|
if (collection.titleProperty) {
|
|
36
36
|
return collection.titleProperty as string;
|
|
37
37
|
}
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
|
|
39
|
+
const orderToSearch = (collection.propertiesOrder as string[]) || Object.keys(collection.properties);
|
|
40
|
+
let firstStringCandidate: string | undefined;
|
|
41
|
+
|
|
42
|
+
for (const key of orderToSearch) {
|
|
40
43
|
const property = collection.properties[key];
|
|
41
|
-
if (!isPropertyBuilder(property)) {
|
|
44
|
+
if (property && !isPropertyBuilder(property)) {
|
|
42
45
|
const prop = property as Property;
|
|
43
46
|
if (prop.type === "string" && !prop.ui?.multiline && !prop.ui?.markdown && !prop.storage && !prop.isId) {
|
|
44
|
-
|
|
47
|
+
if (!firstStringCandidate) {
|
|
48
|
+
firstStringCandidate = key;
|
|
49
|
+
}
|
|
50
|
+
const lowerKey = key.toLowerCase();
|
|
51
|
+
if (["name", "title", "label", "displayname", "username"].includes(lowerKey)) {
|
|
52
|
+
return key; // Immediate return if it's a strong title candidate
|
|
53
|
+
}
|
|
45
54
|
}
|
|
46
55
|
}
|
|
47
56
|
}
|
|
48
|
-
return
|
|
57
|
+
return firstStringCandidate;
|
|
49
58
|
}
|
|
50
59
|
|