@rebasepro/app 0.13.0 → 0.13.1-canary.gcd6689e
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/collections/entity-display-cache.d.ts +50 -0
- package/dist/collections/entity-display.d.ts +35 -0
- package/dist/collections/entity_image_preview.d.ts +8 -0
- package/dist/collections/index.d.ts +3 -0
- package/dist/collections/property-path.d.ts +16 -0
- package/dist/index.es.js +214 -13
- package/dist/index.es.js.map +1 -1
- package/package.json +7 -7
- package/src/collections/entity-display-cache.ts +166 -0
- package/src/collections/entity-display.ts +105 -0
- package/src/collections/entity_image_preview.ts +13 -0
- package/src/collections/index.ts +3 -0
- package/src/collections/property-path.ts +30 -0
- package/src/collections/title-property.ts +12 -3
- package/src/components/common/useColumnsIds.tsx +1 -20
- package/src/locales/de.ts +1 -0
- package/src/locales/en.ts +1 -0
- package/src/locales/es.ts +1 -0
- package/src/locales/fr.ts +1 -0
- package/src/locales/hi.ts +1 -0
- package/src/locales/it.ts +1 -0
- package/src/locales/pt.ts +1 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The store behind a computed display value.
|
|
3
|
+
*
|
|
4
|
+
* A record's title is asked for far more often than it changes, and by many
|
|
5
|
+
* components at once: a list of fifty rows, each row's relation chips, the
|
|
6
|
+
* breadcrumb above them. Resolving per component is what makes an async display
|
|
7
|
+
* value a bad idea — fifty rows becomes fifty reads, then fifty more on the next
|
|
8
|
+
* render.
|
|
9
|
+
*
|
|
10
|
+
* So resolution is keyed by record *and* role, in-flight calls are shared, and
|
|
11
|
+
* results are kept until something says otherwise. Deliberately not a React
|
|
12
|
+
* thing: the same store answers an imperative caller (an export, a breadcrumb
|
|
13
|
+
* built outside the tree), and it is testable without a renderer.
|
|
14
|
+
*/
|
|
15
|
+
import type { EntityDisplayRole } from "@rebasepro/admin-types";
|
|
16
|
+
export type EntityDisplayKey = string;
|
|
17
|
+
/** The identity of one role of one record, as a cache key. */
|
|
18
|
+
export declare function entityDisplayKey(path: string, entityId: string | number | undefined, role: EntityDisplayRole): EntityDisplayKey;
|
|
19
|
+
export declare class EntityDisplayCache {
|
|
20
|
+
private readonly entries;
|
|
21
|
+
private readonly listeners;
|
|
22
|
+
/**
|
|
23
|
+
* The resolved value, or `undefined` when this pair has not been resolved
|
|
24
|
+
* yet. `null` is a resolved absence, and the two must stay distinct: a
|
|
25
|
+
* caller that reads "not yet" as "nothing" flickers its fallback in on every
|
|
26
|
+
* mount.
|
|
27
|
+
*/
|
|
28
|
+
peek(key: EntityDisplayKey): unknown | undefined;
|
|
29
|
+
/** True while a resolution for this pair is in flight. */
|
|
30
|
+
isLoading(key: EntityDisplayKey): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Resolve once per record and role. Concurrent callers share the first
|
|
33
|
+
* call's promise; later callers get the cached value with no promise at all.
|
|
34
|
+
*
|
|
35
|
+
* A resolver that throws is recorded as "nothing" rather than retried: the
|
|
36
|
+
* alternative is every render re-running a call that just failed. The caller
|
|
37
|
+
* that saw the rejection is the one that logs it.
|
|
38
|
+
*/
|
|
39
|
+
resolve(key: EntityDisplayKey, resolver: () => unknown): Promise<unknown>;
|
|
40
|
+
/**
|
|
41
|
+
* Drop what is known about a record, so the next ask resolves again. Called
|
|
42
|
+
* after a write: the row that just saved may be called something else now.
|
|
43
|
+
*/
|
|
44
|
+
invalidate(path: string, entityId?: string | number): void;
|
|
45
|
+
/** Drop everything. The user signed out, or the app swapped datasource. */
|
|
46
|
+
clear(): void;
|
|
47
|
+
subscribe(listener: () => void): () => void;
|
|
48
|
+
private set;
|
|
49
|
+
private emit;
|
|
50
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading a collection's `display` block.
|
|
3
|
+
*
|
|
4
|
+
* Two questions, kept apart because they are answered at different times: which
|
|
5
|
+
* *property* fills a role (readable from values already in hand) and which
|
|
6
|
+
* *resolver* fills it (may have to go to the network). A caller that cannot
|
|
7
|
+
* await — a sort comparator, an export column, a server render — uses the key
|
|
8
|
+
* and is documented to ignore resolvers.
|
|
9
|
+
*/
|
|
10
|
+
import type { AdminCollection, EntityDisplayResolver, EntityDisplayRole } from "@rebasepro/admin-types";
|
|
11
|
+
/**
|
|
12
|
+
* The property path a role is declared to read, when it is declared as a path.
|
|
13
|
+
*
|
|
14
|
+
* Returns `undefined` for a role filled by a resolver — a resolver has no key —
|
|
15
|
+
* and for a role the collection says nothing about, which is then derived.
|
|
16
|
+
*
|
|
17
|
+
* @group Collections
|
|
18
|
+
*/
|
|
19
|
+
export declare function getDisplayPropertyKey<M extends Record<string, unknown>>(collection: AdminCollection<M>, role: EntityDisplayRole): string | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* The resolver a role is declared to use, when it is declared as one.
|
|
22
|
+
*
|
|
23
|
+
* @group Collections
|
|
24
|
+
*/
|
|
25
|
+
export declare function getDisplayResolver<M extends Record<string, unknown>>(collection: AdminCollection<M>, role: EntityDisplayRole): EntityDisplayResolver<M, unknown> | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* True when the collection states this role at all, in either form.
|
|
28
|
+
*
|
|
29
|
+
* The derivation is a guess about what a collection probably means; a statement
|
|
30
|
+
* outranks it, and the heuristics that look for "the first enum" or "the leading
|
|
31
|
+
* relation" have to stand down when one exists.
|
|
32
|
+
*
|
|
33
|
+
* @group Collections
|
|
34
|
+
*/
|
|
35
|
+
export declare function hasDeclaredDisplay<M extends Record<string, unknown>>(collection: AdminCollection<M>, role: EntityDisplayRole): boolean;
|
|
@@ -1,2 +1,10 @@
|
|
|
1
1
|
import { CollectionConfig } from "@rebasepro/types";
|
|
2
|
+
/**
|
|
3
|
+
* The property that fills a record's image slot.
|
|
4
|
+
*
|
|
5
|
+
* `admin.display.image` first, then six fallbacks in descending confidence —
|
|
6
|
+
* the first image-typed storage property, an array of them, a URL rendered as an
|
|
7
|
+
* image, and so on. The ladder stays for collections that say nothing; a
|
|
8
|
+
* collection that names its picture is not guessed at.
|
|
9
|
+
*/
|
|
2
10
|
export declare function getEntityImagePreviewPropertyKey<M extends Record<string, unknown>>(collection: CollectionConfig<M>): string | undefined;
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
export * from "./collection_view_config";
|
|
2
2
|
export * from "./entity_image_preview";
|
|
3
|
+
export * from "./entity-display";
|
|
4
|
+
export * from "./entity-display-cache";
|
|
3
5
|
export * from "./filter-operator-resolution";
|
|
4
6
|
export * from "./form-layout";
|
|
5
7
|
export * from "./navigation_from_path";
|
|
6
8
|
export * from "./navigation_utils";
|
|
7
9
|
export * from "./parent_references_from_path";
|
|
10
|
+
export * from "./property-path";
|
|
8
11
|
export * from "./property_presentation";
|
|
9
12
|
export * from "./title-property";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Properties, Property } from "@rebasepro/types";
|
|
2
|
+
/**
|
|
3
|
+
* The property at a dotted path, walking `map` children — `address.street`.
|
|
4
|
+
*
|
|
5
|
+
* The value counterpart is `getValueInPath` in `@rebasepro/utils`; this is the
|
|
6
|
+
* schema half, and the two have to be used together. Reading a dotted path off
|
|
7
|
+
* an entity while looking its property up with a flat `properties[path]` gives
|
|
8
|
+
* the value and `undefined` for how to render it, which is how a declared title
|
|
9
|
+
* on a nested field silently fell back to a derived one.
|
|
10
|
+
*
|
|
11
|
+
* There were three copies of this: one private to `useColumnsIds`, one exported
|
|
12
|
+
* from the admin layer, and the flat lookup in the title resolver that was not
|
|
13
|
+
* this function at all. This is the one, in the lowest layer that needs it —
|
|
14
|
+
* admin re-exports it under the name it already published.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getPropertyInPath(properties: Properties, path: string): Property | undefined;
|
package/dist/index.es.js
CHANGED
|
@@ -2325,21 +2325,32 @@ function useDebouncedData(data, deps, timeoutMs = 5e3) {
|
|
|
2325
2325
|
return immediateUpdate ? data : deferredData;
|
|
2326
2326
|
}
|
|
2327
2327
|
//#endregion
|
|
2328
|
-
//#region src/
|
|
2328
|
+
//#region src/collections/property-path.ts
|
|
2329
2329
|
/**
|
|
2330
|
-
*
|
|
2331
|
-
*
|
|
2330
|
+
* The property at a dotted path, walking `map` children — `address.street`.
|
|
2331
|
+
*
|
|
2332
|
+
* The value counterpart is `getValueInPath` in `@rebasepro/utils`; this is the
|
|
2333
|
+
* schema half, and the two have to be used together. Reading a dotted path off
|
|
2334
|
+
* an entity while looking its property up with a flat `properties[path]` gives
|
|
2335
|
+
* the value and `undefined` for how to render it, which is how a declared title
|
|
2336
|
+
* on a nested field silently fell back to a derived one.
|
|
2337
|
+
*
|
|
2338
|
+
* There were three copies of this: one private to `useColumnsIds`, one exported
|
|
2339
|
+
* from the admin layer, and the flat lookup in the title resolver that was not
|
|
2340
|
+
* this function at all. This is the one, in the lowest layer that needs it —
|
|
2341
|
+
* admin re-exports it under the name it already published.
|
|
2332
2342
|
*/
|
|
2333
2343
|
function getPropertyInPath(properties, path) {
|
|
2334
|
-
if (typeof properties
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
}
|
|
2344
|
+
if (typeof properties !== "object" || !properties) return void 0;
|
|
2345
|
+
if (path in properties) return properties[path];
|
|
2346
|
+
if (path.includes(".")) {
|
|
2347
|
+
const pathSegments = path.split(".");
|
|
2348
|
+
const childProperty = properties[pathSegments[0]];
|
|
2349
|
+
if (typeof childProperty === "object" && childProperty?.type === "map" && childProperty.properties) return getPropertyInPath(childProperty.properties, pathSegments.slice(1).join("."));
|
|
2341
2350
|
}
|
|
2342
2351
|
}
|
|
2352
|
+
//#endregion
|
|
2353
|
+
//#region src/components/common/useColumnsIds.tsx
|
|
2343
2354
|
function getSubcollectionColumnId(collection) {
|
|
2344
2355
|
return `subcollection:${collection.slug}`;
|
|
2345
2356
|
}
|
|
@@ -9821,6 +9832,7 @@ var en = {
|
|
|
9821
9832
|
column_cannot_be_edited: "This column can't be edited directly",
|
|
9822
9833
|
close: "Close",
|
|
9823
9834
|
hide_list: "Hide list",
|
|
9835
|
+
show_list: "Show list",
|
|
9824
9836
|
unsaved_local_changes: "Unsaved Local changes",
|
|
9825
9837
|
unsaved_local_changes_description: "This document was edited locally and has unsaved changes. These local changes will be lost if you don't apply them.",
|
|
9826
9838
|
preview_changes: "Preview Changes",
|
|
@@ -10720,6 +10732,7 @@ var es = {
|
|
|
10720
10732
|
column_cannot_be_edited: "Esta columna no se puede editar directamente",
|
|
10721
10733
|
close: "Cerrar",
|
|
10722
10734
|
hide_list: "Ocultar lista",
|
|
10735
|
+
show_list: "Mostrar lista",
|
|
10723
10736
|
unsaved_local_changes: "Cambios locales sin guardar",
|
|
10724
10737
|
unsaved_local_changes_description: "Este documento ha sido editado localmente y tiene cambios sin guardar. Estos cambios locales se perderán si no los aplicas.",
|
|
10725
10738
|
preview_changes: "Previsualizar cambios",
|
|
@@ -11576,6 +11589,7 @@ var de = {
|
|
|
11576
11589
|
column_cannot_be_edited: "Diese Spalte kann nicht direkt bearbeitet werden",
|
|
11577
11590
|
close: "Schließen",
|
|
11578
11591
|
hide_list: "Liste ausblenden",
|
|
11592
|
+
show_list: "Liste einblenden",
|
|
11579
11593
|
unsaved_local_changes: "Ungespeicherte lokale Änderungen",
|
|
11580
11594
|
unsaved_local_changes_description: "Dieses Dokument wurde lokal bearbeitet und weist ungespeicherte Änderungen auf. Diese lokalen Änderungen gehen verloren, wenn Sie sie nicht anwenden.",
|
|
11581
11595
|
preview_changes: "Änderungen in der Vorschau anzeigen",
|
|
@@ -12422,6 +12436,7 @@ var fr = {
|
|
|
12422
12436
|
column_cannot_be_edited: "Cette colonne ne peut pas être modifiée directement",
|
|
12423
12437
|
close: "Fermer",
|
|
12424
12438
|
hide_list: "Masquer la liste",
|
|
12439
|
+
show_list: "Afficher la liste",
|
|
12425
12440
|
unsaved_local_changes: "Modifications locales non enregistrées",
|
|
12426
12441
|
unsaved_local_changes_description: "Ce document a été modifié localement et contient des modifications non enregistrées. Ces modifications locales seront perdues si vous ne les appliquez pas.",
|
|
12427
12442
|
preview_changes: "Aperçu des modifications",
|
|
@@ -13268,6 +13283,7 @@ var it = {
|
|
|
13268
13283
|
column_cannot_be_edited: "Questa colonna non può essere modificata direttamente",
|
|
13269
13284
|
close: "Chiudi",
|
|
13270
13285
|
hide_list: "Nascondi elenco",
|
|
13286
|
+
show_list: "Mostra elenco",
|
|
13271
13287
|
unsaved_local_changes: "Modifiche locali non salvate",
|
|
13272
13288
|
unsaved_local_changes_description: "Questo documento è stato modificato localmente e ha modifiche non salvate. Queste modifiche locali andranno perse se non le applichi.",
|
|
13273
13289
|
preview_changes: "Anteprima modifiche",
|
|
@@ -14114,6 +14130,7 @@ var hi = {
|
|
|
14114
14130
|
column_cannot_be_edited: "इस कॉलम को सीधे संपादित नहीं किया जा सकता",
|
|
14115
14131
|
close: "बंद करें",
|
|
14116
14132
|
hide_list: "सूची छिपाएँ",
|
|
14133
|
+
show_list: "सूची दिखाएँ",
|
|
14117
14134
|
unsaved_local_changes: "सहेजे नहीं गए स्थानीय परिवर्तन",
|
|
14118
14135
|
unsaved_local_changes_description: "इस दस्तावेज़ को स्थानीय स्तर पर संपादित किया गया था और इसमें सहेजे नहीं गए परिवर्तन हैं। यदि आप इन्हें लागू नहीं करते हैं तो ये स्थानीय परिवर्तन खो जाएंगे।",
|
|
14119
14136
|
preview_changes: "परिवर्तनों का पूर्वावलोकन करें",
|
|
@@ -14965,6 +14982,7 @@ var pt = {
|
|
|
14965
14982
|
column_cannot_be_edited: "Esta coluna não pode ser editada diretamente",
|
|
14966
14983
|
close: "Fechar",
|
|
14967
14984
|
hide_list: "Ocultar lista",
|
|
14985
|
+
show_list: "Mostrar lista",
|
|
14968
14986
|
unsaved_local_changes: "Alterações locais não guardadas",
|
|
14969
14987
|
unsaved_local_changes_description: "Este documento foi editado localmente e tem alterações não guardadas. Estas alterações locais serão perdidas se não as aplicar.",
|
|
14970
14988
|
preview_changes: "Pré-visualizar alterações",
|
|
@@ -17359,8 +17377,82 @@ function getAdminEntityChildViews(collection) {
|
|
|
17359
17377
|
}));
|
|
17360
17378
|
}
|
|
17361
17379
|
//#endregion
|
|
17380
|
+
//#region src/collections/entity-display.ts
|
|
17381
|
+
/**
|
|
17382
|
+
* Collections that have already warned about a deprecated field, so a list of
|
|
17383
|
+
* fifty rows produces one line in the console rather than fifty.
|
|
17384
|
+
*/
|
|
17385
|
+
var deprecationWarned = /* @__PURE__ */ new Set();
|
|
17386
|
+
function collectionId(collection) {
|
|
17387
|
+
return collection.slug ?? collection.name ?? "collection";
|
|
17388
|
+
}
|
|
17389
|
+
function warnOnce(id, message) {
|
|
17390
|
+
const key = `${id}:${message}`;
|
|
17391
|
+
if (deprecationWarned.has(key)) return;
|
|
17392
|
+
deprecationWarned.add(key);
|
|
17393
|
+
console.warn(message);
|
|
17394
|
+
}
|
|
17395
|
+
/**
|
|
17396
|
+
* What the collection declares for a role, before deciding which form it is.
|
|
17397
|
+
*
|
|
17398
|
+
* `display.title` wins over the deprecated `titleProperty`: a collection setting
|
|
17399
|
+
* both is mid-migration, and the new field is the one it means.
|
|
17400
|
+
*/
|
|
17401
|
+
function getDeclaredSource(collection, role) {
|
|
17402
|
+
const declared = collection.display?.[role];
|
|
17403
|
+
if (declared !== void 0) return declared;
|
|
17404
|
+
if (role === "title" && collection.titleProperty) {
|
|
17405
|
+
const id = collectionId(collection);
|
|
17406
|
+
warnOnce(id, `[rebase] Collection "${id}" uses admin.titleProperty, which is deprecated. Move it to admin.display.title — the same string works there, and display.title also accepts a resolver for a title the record does not carry.`);
|
|
17407
|
+
return collection.titleProperty;
|
|
17408
|
+
}
|
|
17409
|
+
}
|
|
17410
|
+
/**
|
|
17411
|
+
* The property path a role is declared to read, when it is declared as a path.
|
|
17412
|
+
*
|
|
17413
|
+
* Returns `undefined` for a role filled by a resolver — a resolver has no key —
|
|
17414
|
+
* and for a role the collection says nothing about, which is then derived.
|
|
17415
|
+
*
|
|
17416
|
+
* @group Collections
|
|
17417
|
+
*/
|
|
17418
|
+
function getDisplayPropertyKey(collection, role) {
|
|
17419
|
+
const declared = getDeclaredSource(collection, role);
|
|
17420
|
+
return typeof declared === "string" ? declared : void 0;
|
|
17421
|
+
}
|
|
17422
|
+
/**
|
|
17423
|
+
* The resolver a role is declared to use, when it is declared as one.
|
|
17424
|
+
*
|
|
17425
|
+
* @group Collections
|
|
17426
|
+
*/
|
|
17427
|
+
function getDisplayResolver(collection, role) {
|
|
17428
|
+
const declared = getDeclaredSource(collection, role);
|
|
17429
|
+
return typeof declared === "function" ? declared : void 0;
|
|
17430
|
+
}
|
|
17431
|
+
/**
|
|
17432
|
+
* True when the collection states this role at all, in either form.
|
|
17433
|
+
*
|
|
17434
|
+
* The derivation is a guess about what a collection probably means; a statement
|
|
17435
|
+
* outranks it, and the heuristics that look for "the first enum" or "the leading
|
|
17436
|
+
* relation" have to stand down when one exists.
|
|
17437
|
+
*
|
|
17438
|
+
* @group Collections
|
|
17439
|
+
*/
|
|
17440
|
+
function hasDeclaredDisplay(collection, role) {
|
|
17441
|
+
return getDeclaredSource(collection, role) !== void 0;
|
|
17442
|
+
}
|
|
17443
|
+
//#endregion
|
|
17362
17444
|
//#region src/collections/entity_image_preview.ts
|
|
17445
|
+
/**
|
|
17446
|
+
* The property that fills a record's image slot.
|
|
17447
|
+
*
|
|
17448
|
+
* `admin.display.image` first, then six fallbacks in descending confidence —
|
|
17449
|
+
* the first image-typed storage property, an array of them, a URL rendered as an
|
|
17450
|
+
* image, and so on. The ladder stays for collections that say nothing; a
|
|
17451
|
+
* collection that names its picture is not guessed at.
|
|
17452
|
+
*/
|
|
17363
17453
|
function getEntityImagePreviewPropertyKey(collection) {
|
|
17454
|
+
const declared = getDisplayPropertyKey(collection, "image");
|
|
17455
|
+
if (declared) return declared;
|
|
17364
17456
|
for (const key in collection.properties) {
|
|
17365
17457
|
const property = collection.properties[key];
|
|
17366
17458
|
if (property.type === "string" && property.storage?.acceptedFiles?.includes("image/*")) return key;
|
|
@@ -17387,6 +17479,114 @@ function getEntityImagePreviewPropertyKey(collection) {
|
|
|
17387
17479
|
}
|
|
17388
17480
|
}
|
|
17389
17481
|
//#endregion
|
|
17482
|
+
//#region src/collections/entity-display-cache.ts
|
|
17483
|
+
/** The identity of one role of one record, as a cache key. */
|
|
17484
|
+
function entityDisplayKey(path, entityId, role) {
|
|
17485
|
+
return `${role} ${path} ${entityId ?? ""}`;
|
|
17486
|
+
}
|
|
17487
|
+
var EntityDisplayCache = class {
|
|
17488
|
+
entries = /* @__PURE__ */ new Map();
|
|
17489
|
+
listeners = /* @__PURE__ */ new Set();
|
|
17490
|
+
/**
|
|
17491
|
+
* The resolved value, or `undefined` when this pair has not been resolved
|
|
17492
|
+
* yet. `null` is a resolved absence, and the two must stay distinct: a
|
|
17493
|
+
* caller that reads "not yet" as "nothing" flickers its fallback in on every
|
|
17494
|
+
* mount.
|
|
17495
|
+
*/
|
|
17496
|
+
peek(key) {
|
|
17497
|
+
const entry = this.entries.get(key);
|
|
17498
|
+
if (!entry || "promise" in entry) return void 0;
|
|
17499
|
+
return entry.value;
|
|
17500
|
+
}
|
|
17501
|
+
/** True while a resolution for this pair is in flight. */
|
|
17502
|
+
isLoading(key) {
|
|
17503
|
+
const entry = this.entries.get(key);
|
|
17504
|
+
return Boolean(entry && "promise" in entry);
|
|
17505
|
+
}
|
|
17506
|
+
/**
|
|
17507
|
+
* Resolve once per record and role. Concurrent callers share the first
|
|
17508
|
+
* call's promise; later callers get the cached value with no promise at all.
|
|
17509
|
+
*
|
|
17510
|
+
* A resolver that throws is recorded as "nothing" rather than retried: the
|
|
17511
|
+
* alternative is every render re-running a call that just failed. The caller
|
|
17512
|
+
* that saw the rejection is the one that logs it.
|
|
17513
|
+
*/
|
|
17514
|
+
resolve(key, resolver) {
|
|
17515
|
+
const entry = this.entries.get(key);
|
|
17516
|
+
if (entry) return "promise" in entry ? entry.promise : Promise.resolve(entry.value);
|
|
17517
|
+
let produced;
|
|
17518
|
+
try {
|
|
17519
|
+
produced = resolver();
|
|
17520
|
+
} catch {
|
|
17521
|
+
this.set(key, null);
|
|
17522
|
+
return Promise.resolve(null);
|
|
17523
|
+
}
|
|
17524
|
+
if (!isPromise(produced)) {
|
|
17525
|
+
const value = normalize(produced);
|
|
17526
|
+
this.set(key, value);
|
|
17527
|
+
return Promise.resolve(value);
|
|
17528
|
+
}
|
|
17529
|
+
const promise = produced.then((resolved) => {
|
|
17530
|
+
const value = normalize(resolved);
|
|
17531
|
+
this.set(key, value);
|
|
17532
|
+
return value;
|
|
17533
|
+
}).catch(() => {
|
|
17534
|
+
this.set(key, null);
|
|
17535
|
+
return null;
|
|
17536
|
+
});
|
|
17537
|
+
this.entries.set(key, { promise });
|
|
17538
|
+
return promise;
|
|
17539
|
+
}
|
|
17540
|
+
/**
|
|
17541
|
+
* Drop what is known about a record, so the next ask resolves again. Called
|
|
17542
|
+
* after a write: the row that just saved may be called something else now.
|
|
17543
|
+
*/
|
|
17544
|
+
invalidate(path, entityId) {
|
|
17545
|
+
const suffix = ` ${path} ${entityId ?? ""}`;
|
|
17546
|
+
let changed = false;
|
|
17547
|
+
for (const key of [...this.entries.keys()]) if (entityId === void 0 ? key.includes(` ${path} `) || key.endsWith(` ${path} `) : key.endsWith(suffix)) {
|
|
17548
|
+
this.entries.delete(key);
|
|
17549
|
+
changed = true;
|
|
17550
|
+
}
|
|
17551
|
+
if (changed) this.emit();
|
|
17552
|
+
}
|
|
17553
|
+
/** Drop everything. The user signed out, or the app swapped datasource. */
|
|
17554
|
+
clear() {
|
|
17555
|
+
if (this.entries.size === 0) return;
|
|
17556
|
+
this.entries.clear();
|
|
17557
|
+
this.emit();
|
|
17558
|
+
}
|
|
17559
|
+
subscribe(listener) {
|
|
17560
|
+
this.listeners.add(listener);
|
|
17561
|
+
return () => {
|
|
17562
|
+
this.listeners.delete(listener);
|
|
17563
|
+
};
|
|
17564
|
+
}
|
|
17565
|
+
set(key, value) {
|
|
17566
|
+
this.entries.set(key, { value });
|
|
17567
|
+
this.emit();
|
|
17568
|
+
}
|
|
17569
|
+
emit() {
|
|
17570
|
+
for (const listener of [...this.listeners]) listener();
|
|
17571
|
+
}
|
|
17572
|
+
};
|
|
17573
|
+
/**
|
|
17574
|
+
* Empty strings and empty arrays are absences, not values — a title of `" "`
|
|
17575
|
+
* would otherwise beat the derived one and render as a blank heading.
|
|
17576
|
+
*/
|
|
17577
|
+
function normalize(value) {
|
|
17578
|
+
if (value === void 0 || value === null) return null;
|
|
17579
|
+
if (typeof value === "string") {
|
|
17580
|
+
const trimmed = value.trim();
|
|
17581
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
17582
|
+
}
|
|
17583
|
+
if (Array.isArray(value)) return value.length > 0 ? value : null;
|
|
17584
|
+
return value;
|
|
17585
|
+
}
|
|
17586
|
+
function isPromise(value) {
|
|
17587
|
+
return typeof value?.then === "function";
|
|
17588
|
+
}
|
|
17589
|
+
//#endregion
|
|
17390
17590
|
//#region src/collections/filter-operator-resolution.ts
|
|
17391
17591
|
/**
|
|
17392
17592
|
* Default operators offered per property type, before engine capabilities and
|
|
@@ -18170,7 +18370,8 @@ function scoreTitleCandidate(property, key, idKeys, foreignKeys) {
|
|
|
18170
18370
|
*/
|
|
18171
18371
|
function getTitlePropertyCandidates(collection) {
|
|
18172
18372
|
if (!collection.properties) return [];
|
|
18173
|
-
|
|
18373
|
+
const declared = getDisplayPropertyKey(collection, "title");
|
|
18374
|
+
if (declared && getPropertyInPath(collection.properties, declared)) return [declared];
|
|
18174
18375
|
const idKeys = new Set(getPrimaryKeys(collection));
|
|
18175
18376
|
const foreignKeys = getForeignKeyColumns(collection);
|
|
18176
18377
|
const explicitOrder = collection.propertiesOrder;
|
|
@@ -18213,7 +18414,7 @@ function getTitlePropertyCandidates(collection) {
|
|
|
18213
18414
|
*/
|
|
18214
18415
|
function getLeadingRelationTitleKey(collection) {
|
|
18215
18416
|
if (!collection.properties) return void 0;
|
|
18216
|
-
if (collection
|
|
18417
|
+
if (hasDeclaredDisplay(collection, "title")) return void 0;
|
|
18217
18418
|
const idKeys = new Set(getPrimaryKeys(collection));
|
|
18218
18419
|
const foreignKeys = getForeignKeyColumns(collection);
|
|
18219
18420
|
const order = collection.propertiesOrder ?? Object.keys(collection.properties);
|
|
@@ -18274,6 +18475,6 @@ function getTitlePropertyKeyForValues(collection, values, entityId) {
|
|
|
18274
18475
|
return candidates[0];
|
|
18275
18476
|
}
|
|
18276
18477
|
//#endregion
|
|
18277
|
-
export { AIIcon, AIModifiedIndicator, AdminModeControllerContext, AdminModeControllerProvider, AnalyticsContext, ApiConfigProvider, AuthControllerContext, CONTAINER_FULL_WIDTH, CollectionComponentOverrideProvider, CollectionResolverRegistrationContext, CollectionScopeContext, CollectionScopeProvider, ComponentOverrideContext, ConfirmationDialog, CrmDashboardDemo, CustomizationControllerContext, DEFAULT_API_PATH, DEFAULT_PAGE_SIZE, DataDriverContext, DataSourcesContext, DialogsControllerContext, DialogsProvider, EffectiveRoleControllerContext, EffectiveRoleControllerProvider, ErrorTooltip, ErrorView, FORM_CONTAINER_WIDTH, GlobalComponentOverrideProvider, IconForView, LanguageToggle, LoginView, ModeControllerContext, ModeControllerProvider, NavigationBlockerProvider, NotFoundPage, PluginProviderStack, REBASE_LOCALE_STORAGE_KEY, Rebase, RebaseAuth, RebaseClientInstanceContext, RebaseDataContext, RebaseI18nProvider, RebaseLogo, RebaseRegistryProvider, RebaseRouter, RebaseRoutes, SIDE_PANEL_DEFAULT_WIDTH, STUDIO_NAVIGATION_GROUPS, SchemaDriftBanner, SchemaDriftProvider, SnackbarProvider, StorageSourceContext, StorageSourcesContext, StudioBridgeContext, StudioBridgeProvider, StudioBridgeRegistryContext, StudioBridgeRegistryProvider, UIReferenceView, UIStyleGuide, UnsavedChangesDialog, UserConfigurationPersistenceContext, UserDisplay, UserSelectPopover, UserSettingsView, addInitialSlash, apiBaseOf, applyPropertyConditions, buildCollapsedDefaults, buildEnumLabel, clearAuthConfigCache, clearFetchCache, createAuthConfigCache, createFormexStub, deleteEntityWithCallbacks, deriveSpan, en, es, fetchAuthConfig, fillRows, flattenKeys, getAdminEntityChildViews, getAdminSubcollections, getCollectionBySlugWithin, getCollectionPathsCombinations, getColorScheme, getColumnKeysForProperty, getEntityFromCache, getEntityFromMemoryCache, getEntityImagePreviewPropertyKey, getEntityPreviewKeys, getEntityTitlePropertyKey, getFormFieldKeys, getIcon, getLastSegment, getLeadingRelationTitleKey, getLocalChangesBackup, getNavigationEntriesFromPath, getParentReferencesFromPath, getRelationIncludeParams, getRowHeight, getSubcollectionColumnId, getTitlePropertyCandidates, getTitlePropertyKey, getTitlePropertyKeyForValues, iconsSearch, isAuditTimestamp, isEnumValueDisabled, isFilterableRelation, isHidden, isIdPropertyEditable, isReadOnly, isSchemaDriftError, looksLikeIdentifierValue, populateFetchCache, removeEntityFromCache, removeEntityFromMemoryCache, removeInitialAndTrailingSlashes, removeInitialSlash, removeTrailingSlash, resolveCollectionPathIds, resolveComponentRef, resolveDefaultSelectedView, resolveFilterOperators, resolveFormLayout, saveEntityToCache, saveEntityToMemoryCache, saveEntityWithCallbacks, useAdminModeController, useAnalyticsController, useApiBase, useApiConfig, useAuthController, useAuthSubscription, useBackendStorageSource, useBridgeRegistration, useBrowserTitleAndIcon, useBuildAdminModeController, useBuildEffectiveRoleController, useBuildLocalConfigurationPersistence, useBuildModeController, useClipboard, useCollapsedGroups, useCollection, useCollectionScope, useColumnIds, useComponentOverride, useCustomizationController, useData, useDataSources, useDataTableController, useDebouncedData, useDialogsController, useEffectiveRoleController, useFetch, useLargeLayout, useModeController, useNavigationBlocker, usePermissions, useRebaseAuthController, useRebaseClient, useRebaseContext, useRebaseRegistry, useRebaseRegistryDispatch, useRelationSelector, useResolvedComponent, useRestoreScroll, useSchemaDriftContext, useScrollRestoration, useSlot, useSnackbarController, useStorageSource, useStorageSources, useStorageUploadController, useStudioBreadcrumbs, useStudioCapabilities, useStudioCollectionRegistry, useStudioNavigationState, useStudioSidePanelController, useStudioUrlController, useTranslation, useUnsavedChangesDialog, useUserConfigurationPersistence };
|
|
18478
|
+
export { AIIcon, AIModifiedIndicator, AdminModeControllerContext, AdminModeControllerProvider, AnalyticsContext, ApiConfigProvider, AuthControllerContext, CONTAINER_FULL_WIDTH, CollectionComponentOverrideProvider, CollectionResolverRegistrationContext, CollectionScopeContext, CollectionScopeProvider, ComponentOverrideContext, ConfirmationDialog, CrmDashboardDemo, CustomizationControllerContext, DEFAULT_API_PATH, DEFAULT_PAGE_SIZE, DataDriverContext, DataSourcesContext, DialogsControllerContext, DialogsProvider, EffectiveRoleControllerContext, EffectiveRoleControllerProvider, EntityDisplayCache, ErrorTooltip, ErrorView, FORM_CONTAINER_WIDTH, GlobalComponentOverrideProvider, IconForView, LanguageToggle, LoginView, ModeControllerContext, ModeControllerProvider, NavigationBlockerProvider, NotFoundPage, PluginProviderStack, REBASE_LOCALE_STORAGE_KEY, Rebase, RebaseAuth, RebaseClientInstanceContext, RebaseDataContext, RebaseI18nProvider, RebaseLogo, RebaseRegistryProvider, RebaseRouter, RebaseRoutes, SIDE_PANEL_DEFAULT_WIDTH, STUDIO_NAVIGATION_GROUPS, SchemaDriftBanner, SchemaDriftProvider, SnackbarProvider, StorageSourceContext, StorageSourcesContext, StudioBridgeContext, StudioBridgeProvider, StudioBridgeRegistryContext, StudioBridgeRegistryProvider, UIReferenceView, UIStyleGuide, UnsavedChangesDialog, UserConfigurationPersistenceContext, UserDisplay, UserSelectPopover, UserSettingsView, addInitialSlash, apiBaseOf, applyPropertyConditions, buildCollapsedDefaults, buildEnumLabel, clearAuthConfigCache, clearFetchCache, createAuthConfigCache, createFormexStub, deleteEntityWithCallbacks, deriveSpan, en, entityDisplayKey, es, fetchAuthConfig, fillRows, flattenKeys, getAdminEntityChildViews, getAdminSubcollections, getCollectionBySlugWithin, getCollectionPathsCombinations, getColorScheme, getColumnKeysForProperty, getDisplayPropertyKey, getDisplayResolver, getEntityFromCache, getEntityFromMemoryCache, getEntityImagePreviewPropertyKey, getEntityPreviewKeys, getEntityTitlePropertyKey, getFormFieldKeys, getIcon, getLastSegment, getLeadingRelationTitleKey, getLocalChangesBackup, getNavigationEntriesFromPath, getParentReferencesFromPath, getPropertyInPath, getRelationIncludeParams, getRowHeight, getSubcollectionColumnId, getTitlePropertyCandidates, getTitlePropertyKey, getTitlePropertyKeyForValues, hasDeclaredDisplay, iconsSearch, isAuditTimestamp, isEnumValueDisabled, isFilterableRelation, isHidden, isIdPropertyEditable, isReadOnly, isSchemaDriftError, looksLikeIdentifierValue, populateFetchCache, removeEntityFromCache, removeEntityFromMemoryCache, removeInitialAndTrailingSlashes, removeInitialSlash, removeTrailingSlash, resolveCollectionPathIds, resolveComponentRef, resolveDefaultSelectedView, resolveFilterOperators, resolveFormLayout, saveEntityToCache, saveEntityToMemoryCache, saveEntityWithCallbacks, useAdminModeController, useAnalyticsController, useApiBase, useApiConfig, useAuthController, useAuthSubscription, useBackendStorageSource, useBridgeRegistration, useBrowserTitleAndIcon, useBuildAdminModeController, useBuildEffectiveRoleController, useBuildLocalConfigurationPersistence, useBuildModeController, useClipboard, useCollapsedGroups, useCollection, useCollectionScope, useColumnIds, useComponentOverride, useCustomizationController, useData, useDataSources, useDataTableController, useDebouncedData, useDialogsController, useEffectiveRoleController, useFetch, useLargeLayout, useModeController, useNavigationBlocker, usePermissions, useRebaseAuthController, useRebaseClient, useRebaseContext, useRebaseRegistry, useRebaseRegistryDispatch, useRelationSelector, useResolvedComponent, useRestoreScroll, useSchemaDriftContext, useScrollRestoration, useSlot, useSnackbarController, useStorageSource, useStorageSources, useStorageUploadController, useStudioBreadcrumbs, useStudioCapabilities, useStudioCollectionRegistry, useStudioNavigationState, useStudioSidePanelController, useStudioUrlController, useTranslation, useUnsavedChangesDialog, useUserConfigurationPersistence };
|
|
18278
18479
|
|
|
18279
18480
|
//# sourceMappingURL=index.es.js.map
|