@rebasepro/core 0.3.0 → 0.5.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/README.md +142 -210
- package/dist/components/LoginView/LoginView.d.ts +9 -1
- package/dist/components/common/types.d.ts +3 -3
- package/dist/hooks/data/useCollectionFetch.d.ts +12 -1
- package/dist/index.es.js +162 -126
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +162 -126
- package/dist/index.umd.js.map +1 -1
- package/package.json +6 -7
- package/src/components/LoginView/LoginView.tsx +27 -5
- package/src/components/common/types.tsx +3 -3
- package/src/components/common/useDataTableController.tsx +49 -37
- package/src/hooks/data/useCollectionFetch.tsx +27 -4
- package/src/hooks/data/useUserSelector.tsx +1 -1
- package/src/hooks/useResolvedComponent.tsx +3 -3
- package/src/locales/en.ts +2 -2
- package/src/util/previews.ts +9 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebasepro/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.0",
|
|
5
5
|
"description": "Rebase core — framework-agnostic runtime for data-driven admin panels",
|
|
6
6
|
"funding": {
|
|
7
7
|
"url": "https://github.com/sponsors/rebaseco"
|
|
@@ -51,13 +51,12 @@
|
|
|
51
51
|
"fuse.js": "^7.3.0",
|
|
52
52
|
"i18next": "^23.16.8",
|
|
53
53
|
"notistack": "^3.0.2",
|
|
54
|
-
"react-compiler-runtime": "1.0.0",
|
|
55
54
|
"react-i18next": "^14.1.3",
|
|
56
|
-
"@rebasepro/common": "0.
|
|
57
|
-
"@rebasepro/formex": "0.
|
|
58
|
-
"@rebasepro/
|
|
59
|
-
"@rebasepro/
|
|
60
|
-
"@rebasepro/
|
|
55
|
+
"@rebasepro/common": "0.5.0",
|
|
56
|
+
"@rebasepro/formex": "0.5.0",
|
|
57
|
+
"@rebasepro/types": "0.5.0",
|
|
58
|
+
"@rebasepro/ui": "0.5.0",
|
|
59
|
+
"@rebasepro/utils": "0.5.0"
|
|
61
60
|
},
|
|
62
61
|
"peerDependencies": {
|
|
63
62
|
"react": ">=19.0.0",
|
|
@@ -126,6 +126,16 @@ export interface LoginViewProps {
|
|
|
126
126
|
* If not set, derived from `authController.capabilities.registration`.
|
|
127
127
|
*/
|
|
128
128
|
registrationEnabled?: boolean;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Pre-fill the email field (e.g. for demo or testing environments).
|
|
132
|
+
*/
|
|
133
|
+
defaultEmail?: string;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Pre-fill the password field (e.g. for demo or testing environments).
|
|
137
|
+
*/
|
|
138
|
+
defaultPassword?: string;
|
|
129
139
|
}
|
|
130
140
|
|
|
131
141
|
type AuthMode = "buttons" | "login" | "register" | "forgot";
|
|
@@ -149,7 +159,9 @@ export function LoginView({
|
|
|
149
159
|
subtitle,
|
|
150
160
|
needsSetup,
|
|
151
161
|
registrationEnabled,
|
|
152
|
-
additionalComponent
|
|
162
|
+
additionalComponent,
|
|
163
|
+
defaultEmail,
|
|
164
|
+
defaultPassword
|
|
153
165
|
}: LoginViewProps) {
|
|
154
166
|
|
|
155
167
|
const modeState = useModeController();
|
|
@@ -301,6 +313,8 @@ export function LoginView({
|
|
|
301
313
|
noUserComponent={noUserComponent}
|
|
302
314
|
disableSignupScreen={false}
|
|
303
315
|
bootstrapMode={true}
|
|
316
|
+
defaultEmail={defaultEmail}
|
|
317
|
+
defaultPassword={defaultPassword}
|
|
304
318
|
/>
|
|
305
319
|
)}
|
|
306
320
|
|
|
@@ -376,6 +390,8 @@ export function LoginView({
|
|
|
376
390
|
noUserComponent={noUserComponent}
|
|
377
391
|
disableSignupScreen={disableSignupScreen}
|
|
378
392
|
switchToRegister={showRegistration ? () => switchMode("register") : undefined}
|
|
393
|
+
defaultEmail={defaultEmail}
|
|
394
|
+
defaultPassword={defaultPassword}
|
|
379
395
|
/>
|
|
380
396
|
)}
|
|
381
397
|
|
|
@@ -389,6 +405,8 @@ export function LoginView({
|
|
|
389
405
|
noUserComponent={noUserComponent}
|
|
390
406
|
disableSignupScreen={disableSignupScreen}
|
|
391
407
|
switchToLogin={() => switchMode("login")}
|
|
408
|
+
defaultEmail={defaultEmail}
|
|
409
|
+
defaultPassword={defaultPassword}
|
|
392
410
|
/>
|
|
393
411
|
)}
|
|
394
412
|
|
|
@@ -576,7 +594,9 @@ function LoginForm({
|
|
|
576
594
|
disableSignupScreen,
|
|
577
595
|
bootstrapMode = false,
|
|
578
596
|
switchToRegister,
|
|
579
|
-
switchToLogin
|
|
597
|
+
switchToLogin,
|
|
598
|
+
defaultEmail,
|
|
599
|
+
defaultPassword
|
|
580
600
|
}: {
|
|
581
601
|
onClose: () => void,
|
|
582
602
|
onForgotPassword?: () => void,
|
|
@@ -586,12 +606,14 @@ function LoginForm({
|
|
|
586
606
|
disableSignupScreen: boolean,
|
|
587
607
|
bootstrapMode?: boolean,
|
|
588
608
|
switchToRegister?: () => void,
|
|
589
|
-
switchToLogin?: () => void
|
|
609
|
+
switchToLogin?: () => void,
|
|
610
|
+
defaultEmail?: string,
|
|
611
|
+
defaultPassword?: string
|
|
590
612
|
}) {
|
|
591
613
|
const passwordRef = useRef<HTMLInputElement | null>(null);
|
|
592
614
|
|
|
593
|
-
const [email, setEmail] = useState<string>();
|
|
594
|
-
const [password, setPassword] = useState<string>();
|
|
615
|
+
const [email, setEmail] = useState<string | undefined>(defaultEmail);
|
|
616
|
+
const [password, setPassword] = useState<string | undefined>(defaultPassword);
|
|
595
617
|
const [displayName, setDisplayName] = useState<string>();
|
|
596
618
|
|
|
597
619
|
useEffect(() => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Property } from "@rebasepro/types";
|
|
1
|
+
import type { Property, Entity } from "@rebasepro/types";
|
|
2
2
|
import { CollectionSize, SelectedCellProps } from "@rebasepro/types";
|
|
3
3
|
|
|
4
4
|
export type EntityCollectionTableController<M extends Record<string, unknown>> = {
|
|
@@ -25,7 +25,7 @@ export type EntityCollectionTableController<M extends Record<string, unknown>> =
|
|
|
25
25
|
* Callback used when the value of a cell has changed.
|
|
26
26
|
* @param params
|
|
27
27
|
*/
|
|
28
|
-
onValueChange?: (params: OnCellValueChangeParams<unknown, M
|
|
28
|
+
onValueChange?: (params: OnCellValueChangeParams<unknown, Entity<M>>) => void;
|
|
29
29
|
/**
|
|
30
30
|
* Size of the elements in the collection
|
|
31
31
|
*/
|
|
@@ -58,7 +58,7 @@ export type UniqueFieldValidator = (props: {
|
|
|
58
58
|
* Callback when a cell has changed in a table
|
|
59
59
|
* @group Collection components
|
|
60
60
|
*/
|
|
61
|
-
export type OnCellValueChange<T, M extends Record<string, unknown>> = (params: OnCellValueChangeParams<T, M
|
|
61
|
+
export type OnCellValueChange<T, M extends Record<string, unknown>> = (params: OnCellValueChangeParams<T, Entity<M>>) => Promise<void> | void;
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
64
|
* @group Collection components
|
|
@@ -128,7 +128,7 @@ export function useDataTableController<M extends Record<string, any> = any, USER
|
|
|
128
128
|
|
|
129
129
|
const { filterValues: urlFilterValues, sortBy: urlSortBy } = parseFilterAndSort(location.search);
|
|
130
130
|
if (!fixedFilter) {
|
|
131
|
-
setFilterValues(urlFilterValues as FilterValues<Extract<keyof M, string> | (string & {})> | undefined);
|
|
131
|
+
setFilterValues((urlFilterValues ?? defaultFilter) as FilterValues<Extract<keyof M, string> | (string & {})> | undefined);
|
|
132
132
|
}
|
|
133
133
|
if (urlSortBy && fixedFilter && !checkFilterCombination(fixedFilter, urlSortBy)) {
|
|
134
134
|
console.warn("URL sort is not compatible with the force filter.");
|
|
@@ -186,7 +186,7 @@ export function useDataTableController<M extends Record<string, any> = any, USER
|
|
|
186
186
|
const [dataLoadingError, setDataLoadingError] = useState<Error | undefined>();
|
|
187
187
|
const [noMoreToLoad, setNoMoreToLoad] = useState<boolean>(false);
|
|
188
188
|
|
|
189
|
-
const clearFilter = useCallback(() => setFilterValues(fixedFilter ?? undefined), [fixedFilter]);
|
|
189
|
+
const clearFilter = useCallback(() => setFilterValues(fixedFilter ?? defaultFilter ?? undefined), [fixedFilter, defaultFilter]);
|
|
190
190
|
|
|
191
191
|
const updateFilterValues = useCallback((updatedFilter: FilterValues<Extract<keyof M, string> | (string & {})> | undefined) => {
|
|
192
192
|
if (fixedFilter) {
|
|
@@ -246,16 +246,22 @@ export function useDataTableController<M extends Record<string, any> = any, USER
|
|
|
246
246
|
if (filterValues) {
|
|
247
247
|
Object.entries(filterValues).forEach(([key, value]) => {
|
|
248
248
|
if (value && Array.isArray(value)) {
|
|
249
|
-
const [
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
249
|
+
const conditions: [WhereFilterOp, unknown][] = Array.isArray(value[0])
|
|
250
|
+
? (value as [WhereFilterOp, unknown][])
|
|
251
|
+
: [value as [WhereFilterOp, unknown]];
|
|
252
|
+
|
|
253
|
+
const [op, val] = conditions[0] || [];
|
|
254
|
+
if (op) {
|
|
255
|
+
const postgrestOp = op === "==" ? "eq" : op === "!=" ? "neq" : op === ">" ? "gt" : op === ">=" ? "gte" : op === "<" ? "lt" : op === "<=" ? "lte" : op === "in" ? "in" : op === "not-in" ? "nin" : op === "array-contains" ? "cs" : op === "array-contains-any" ? "csa" : "eq";
|
|
256
|
+
|
|
257
|
+
let stringVal: string;
|
|
258
|
+
if (Array.isArray(val)) {
|
|
259
|
+
stringVal = `(${val.join(",")})`;
|
|
260
|
+
} else {
|
|
261
|
+
stringVal = String(val);
|
|
262
|
+
}
|
|
263
|
+
whereMap[key] = `${postgrestOp}.${stringVal}`;
|
|
257
264
|
}
|
|
258
|
-
whereMap[key] = `${postgrestOp}.${stringVal}`;
|
|
259
265
|
}
|
|
260
266
|
});
|
|
261
267
|
}
|
|
@@ -388,34 +394,40 @@ function encodeFilterAndSort(filterValues?: FilterValues<string>, sortBy?: [stri
|
|
|
388
394
|
if (filterValues) {
|
|
389
395
|
Object.entries(filterValues).forEach(([key, value]) => {
|
|
390
396
|
if (value) {
|
|
391
|
-
const [
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
397
|
+
const conditions: [WhereFilterOp, unknown][] = Array.isArray(value[0])
|
|
398
|
+
? (value as [WhereFilterOp, unknown][])
|
|
399
|
+
: [value as [WhereFilterOp, unknown]];
|
|
400
|
+
|
|
401
|
+
const [op, val] = conditions[0] || [];
|
|
402
|
+
if (op) {
|
|
403
|
+
let encodedValue: unknown = val;
|
|
404
|
+
try {
|
|
405
|
+
if (typeof val === "object") {
|
|
406
|
+
if (val instanceof Date) {
|
|
407
|
+
encodedValue = val.toISOString();
|
|
408
|
+
} else if (Array.isArray(val)) {
|
|
409
|
+
encodedValue = JSON.stringify(val, (k, v) => {
|
|
410
|
+
if (v instanceof EntityRelation) {
|
|
411
|
+
return encodeRelation(v);
|
|
412
|
+
}
|
|
413
|
+
if (v instanceof EntityReference) {
|
|
414
|
+
return encodeReference(v);
|
|
415
|
+
}
|
|
416
|
+
return v;
|
|
417
|
+
});
|
|
418
|
+
} else if (val instanceof EntityRelation) {
|
|
419
|
+
encodedValue = encodeRelation(val);
|
|
420
|
+
} else if (val instanceof EntityReference) {
|
|
421
|
+
encodedValue = encodeReference(val);
|
|
422
|
+
}
|
|
411
423
|
}
|
|
424
|
+
} catch (e) {
|
|
425
|
+
encodedValue = val;
|
|
426
|
+
}
|
|
427
|
+
if (encodedValue !== undefined) {
|
|
428
|
+
entries[encodeURIComponent(`${key}_op`)] = encodeURIComponent(op);
|
|
429
|
+
entries[encodeURIComponent(`${key}_value`)] = encodedValue ? encodeURIComponent(String(encodedValue)) : "null";
|
|
412
430
|
}
|
|
413
|
-
} catch (e) {
|
|
414
|
-
encodedValue = val;
|
|
415
|
-
}
|
|
416
|
-
if (encodedValue !== undefined) {
|
|
417
|
-
entries[encodeURIComponent(`${key}_op`)] = encodeURIComponent(op);
|
|
418
|
-
entries[encodeURIComponent(`${key}_value`)] = encodedValue ? encodeURIComponent(String(encodedValue)) : "null";
|
|
419
431
|
}
|
|
420
432
|
}
|
|
421
433
|
});
|
|
@@ -22,6 +22,16 @@ export interface CollectionFetchProps<M extends Record<string, any>> {
|
|
|
22
22
|
*/
|
|
23
23
|
itemCount?: number;
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Number of items to skip
|
|
27
|
+
*/
|
|
28
|
+
offset?: number;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Page number (1-indexed), alternative to offset
|
|
32
|
+
*/
|
|
33
|
+
page?: number;
|
|
34
|
+
|
|
25
35
|
/**
|
|
26
36
|
* Filter the fetched data by the property
|
|
27
37
|
*/
|
|
@@ -46,6 +56,7 @@ export interface CollectionFetchResult<M extends Record<string, any>> {
|
|
|
46
56
|
dataLoading: boolean;
|
|
47
57
|
noMoreToLoad: boolean;
|
|
48
58
|
dataLoadingError?: Error;
|
|
59
|
+
totalCount?: number;
|
|
49
60
|
}
|
|
50
61
|
|
|
51
62
|
/**
|
|
@@ -55,6 +66,8 @@ export interface CollectionFetchResult<M extends Record<string, any>> {
|
|
|
55
66
|
* @param filterValues
|
|
56
67
|
* @param sortBy
|
|
57
68
|
* @param itemCount
|
|
69
|
+
* @param offset
|
|
70
|
+
* @param page
|
|
58
71
|
* @param searchString
|
|
59
72
|
* @group Hooks and utilities
|
|
60
73
|
*/
|
|
@@ -65,6 +78,8 @@ export function useCollectionFetch<M extends Record<string, any>, USER extends U
|
|
|
65
78
|
filterValues,
|
|
66
79
|
sortBy,
|
|
67
80
|
itemCount,
|
|
81
|
+
offset,
|
|
82
|
+
page,
|
|
68
83
|
searchString
|
|
69
84
|
}: CollectionFetchProps<M>): CollectionFetchResult<M> {
|
|
70
85
|
const dataClient = useData();
|
|
@@ -99,12 +114,13 @@ export function useCollectionFetch<M extends Record<string, any>, USER extends U
|
|
|
99
114
|
const [dataLoading, setDataLoading] = useState<boolean>(false);
|
|
100
115
|
const [dataLoadingError, setDataLoadingError] = useState<Error | undefined>();
|
|
101
116
|
const [noMoreToLoad, setNoMoreToLoad] = useState<boolean>(false);
|
|
117
|
+
const [totalCount, setTotalCount] = useState<number | undefined>();
|
|
102
118
|
|
|
103
119
|
useEffect(() => {
|
|
104
120
|
|
|
105
121
|
setDataLoading(true);
|
|
106
122
|
|
|
107
|
-
const onEntitiesUpdate = async (res: { data: Entity<M>[], meta: { hasMore: boolean } }) => {
|
|
123
|
+
const onEntitiesUpdate = async (res: { data: Entity<M>[], meta: { hasMore: boolean; total?: number } }) => {
|
|
108
124
|
const entities = res.data;
|
|
109
125
|
setDataLoading(false);
|
|
110
126
|
setDataLoadingError(undefined);
|
|
@@ -112,6 +128,7 @@ export function useCollectionFetch<M extends Record<string, any>, USER extends U
|
|
|
112
128
|
...e
|
|
113
129
|
})));
|
|
114
130
|
setNoMoreToLoad(!res.meta.hasMore);
|
|
131
|
+
setTotalCount(res.meta.total);
|
|
115
132
|
};
|
|
116
133
|
|
|
117
134
|
const onError = (error: Error) => {
|
|
@@ -119,6 +136,7 @@ export function useCollectionFetch<M extends Record<string, any>, USER extends U
|
|
|
119
136
|
setDataLoading(false);
|
|
120
137
|
setData([]);
|
|
121
138
|
setDataLoadingError(error);
|
|
139
|
+
setTotalCount(undefined);
|
|
122
140
|
};
|
|
123
141
|
|
|
124
142
|
const accessor = dataClient.collection(path);
|
|
@@ -133,6 +151,8 @@ export function useCollectionFetch<M extends Record<string, any>, USER extends U
|
|
|
133
151
|
return accessor.listen({
|
|
134
152
|
where: whereParams,
|
|
135
153
|
limit: itemCount,
|
|
154
|
+
offset,
|
|
155
|
+
page,
|
|
136
156
|
orderBy: orderByParams,
|
|
137
157
|
searchString,
|
|
138
158
|
include: includeParams
|
|
@@ -141,6 +161,8 @@ export function useCollectionFetch<M extends Record<string, any>, USER extends U
|
|
|
141
161
|
accessor.find({
|
|
142
162
|
where: whereParams,
|
|
143
163
|
limit: itemCount,
|
|
164
|
+
offset,
|
|
165
|
+
page,
|
|
144
166
|
orderBy: orderByParams,
|
|
145
167
|
searchString,
|
|
146
168
|
include: includeParams
|
|
@@ -150,13 +172,14 @@ export function useCollectionFetch<M extends Record<string, any>, USER extends U
|
|
|
150
172
|
return () => {
|
|
151
173
|
};
|
|
152
174
|
}
|
|
153
|
-
}, [path, itemCount, currentSort, sortByProperty, filterValues, searchString, dataClient, collection]);
|
|
175
|
+
}, [path, itemCount, offset, page, currentSort, sortByProperty, filterValues, searchString, dataClient, collection]);
|
|
154
176
|
|
|
155
177
|
return useMemo(() => ({
|
|
156
178
|
data,
|
|
157
179
|
dataLoading,
|
|
158
180
|
dataLoadingError,
|
|
159
|
-
noMoreToLoad
|
|
160
|
-
|
|
181
|
+
noMoreToLoad,
|
|
182
|
+
totalCount
|
|
183
|
+
}), [data, dataLoading, dataLoadingError, noMoreToLoad, totalCount]);
|
|
161
184
|
|
|
162
185
|
}
|
|
@@ -142,7 +142,7 @@ export function useUserSelector(
|
|
|
142
142
|
}, []);
|
|
143
143
|
|
|
144
144
|
const getUser = useCallback((uid: string): User | null => {
|
|
145
|
-
return userManagement?.getUser(uid) ?? null;
|
|
145
|
+
return userManagement?.getUser?.(uid) ?? null;
|
|
146
146
|
}, [userManagement]);
|
|
147
147
|
|
|
148
148
|
return useMemo(() => ({
|
|
@@ -14,7 +14,7 @@ import { isLazyComponentRef } from "@rebasepro/types";
|
|
|
14
14
|
* plain Map since they can't be WeakMap keys.
|
|
15
15
|
*/
|
|
16
16
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
-
const lazyCache = new WeakMap<object |
|
|
17
|
+
const lazyCache = new WeakMap<object | ((...args: any[]) => any), React.ComponentType<any>>();
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Resolves a `ComponentRef` into a renderable `React.ComponentType`.
|
|
@@ -63,7 +63,7 @@ export function useResolvedComponent<P = unknown>(
|
|
|
63
63
|
* same loader always returns the same lazy component identity.
|
|
64
64
|
*/
|
|
65
65
|
function getOrCreateLazy<P>(
|
|
66
|
-
key: object |
|
|
66
|
+
key: object | ((...args: any[]) => any),
|
|
67
67
|
loader: () => Promise<{ default: React.ComponentType<P> }>
|
|
68
68
|
): React.ComponentType<P> {
|
|
69
69
|
const cached = lazyCache.get(key);
|
|
@@ -109,7 +109,7 @@ export function resolveComponentRef<P = unknown>(
|
|
|
109
109
|
|
|
110
110
|
// 3. Function — either a React component or a lazy import loader.
|
|
111
111
|
if (typeof ref === "function") {
|
|
112
|
-
const fn = ref as
|
|
112
|
+
const fn = ref as (...args: any[]) => any;
|
|
113
113
|
|
|
114
114
|
// Class components (React.Component / PureComponent) have this flag
|
|
115
115
|
if (fn.prototype?.isReactComponent) {
|
package/src/locales/en.ts
CHANGED
|
@@ -406,14 +406,14 @@ export const en: RebaseTranslations = {
|
|
|
406
406
|
data_imported_successfully: "Data imported successfully",
|
|
407
407
|
export: "Export",
|
|
408
408
|
export_data: "Export data",
|
|
409
|
-
download_table_csv: "Download the
|
|
409
|
+
download_table_csv: "Download the content of this table as a CSV",
|
|
410
410
|
csv: "CSV",
|
|
411
411
|
json: "JSON",
|
|
412
412
|
dates_as_timestamps: "Dates as timestamps",
|
|
413
413
|
dates_as_strings: "Dates as strings",
|
|
414
414
|
flatten_arrays: "Flatten arrays",
|
|
415
415
|
download: "Download",
|
|
416
|
-
large_number_of_documents: "This
|
|
416
|
+
large_number_of_documents: "This collection has a large number of documents ({{count}}).",
|
|
417
417
|
include_undefined_values: "Include undefined values",
|
|
418
418
|
submit: "Submit",
|
|
419
419
|
|
package/src/util/previews.ts
CHANGED
|
@@ -22,6 +22,11 @@ function isRelationProperty(property: Property) {
|
|
|
22
22
|
return false;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
function isHiddenProperty(property: Property | undefined): boolean {
|
|
26
|
+
if (!property) return false;
|
|
27
|
+
return Boolean(property.ui?.hideFromCollection);
|
|
28
|
+
}
|
|
29
|
+
|
|
25
30
|
export function getEntityPreviewKeys(
|
|
26
31
|
authController: AuthController,
|
|
27
32
|
targetCollection: EntityCollection<any>,
|
|
@@ -45,7 +50,7 @@ export function getEntityPreviewKeys(
|
|
|
45
50
|
})
|
|
46
51
|
.filter(key => {
|
|
47
52
|
const property = targetCollection.properties[key];
|
|
48
|
-
return property && !isPropertyBuilder(property) && !isReferenceProperty(property) && !isRelationProperty(property);
|
|
53
|
+
return property && !isPropertyBuilder(property) && !isReferenceProperty(property) && !isRelationProperty(property) && !isHiddenProperty(property);
|
|
49
54
|
}).slice(0, limit);
|
|
50
55
|
}
|
|
51
56
|
}
|
|
@@ -62,6 +67,9 @@ export function getEntityTitlePropertyKey<M extends Record<string, any>>(collect
|
|
|
62
67
|
const property = collection.properties[key];
|
|
63
68
|
if (property && !isPropertyBuilder(property)) {
|
|
64
69
|
const prop = property as Property;
|
|
70
|
+
if (isHiddenProperty(prop)) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
65
73
|
if (prop.type === "string" && !prop.ui?.multiline && !prop.ui?.markdown && !prop.storage && !prop.isId) {
|
|
66
74
|
if (!firstStringCandidate) {
|
|
67
75
|
firstStringCandidate = key;
|