@mulmoclaude/collection-plugin 0.7.5 → 0.7.6
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/vue/components/CollectionKanbanView.vue.d.ts.map +1 -1
- package/dist/vue/components/CollectionRecordPanel.vue.d.ts +24 -2
- package/dist/vue/components/CollectionRecordPanel.vue.d.ts.map +1 -1
- package/dist/vue/components/CollectionView.vue.d.ts.map +1 -1
- package/dist/vue/useCollectionRendering.d.ts +1 -1
- package/dist/vue/useCollectionRendering.d.ts.map +1 -1
- package/dist/vue/useCollectionRendering.helpers.d.ts +3 -1
- package/dist/vue/useCollectionRendering.helpers.d.ts.map +1 -1
- package/dist/vue/useCollectionRendering.renderers.d.ts +22 -0
- package/dist/vue/useCollectionRendering.renderers.d.ts.map +1 -0
- package/dist/vue/useLinkedCollectionCaches.d.ts +33 -0
- package/dist/vue/useLinkedCollectionCaches.d.ts.map +1 -0
- package/dist/vue.cjs +212 -167
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +212 -167
- package/dist/vue.js.map +1 -1
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CollectionKanbanView.vue.d.ts","sourceRoot":"","sources":["../../../src/vue/components/CollectionKanbanView.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CollectionKanbanView.vue.d.ts","sourceRoot":"","sources":["../../../src/vue/components/CollectionKanbanView.vue"],"names":[],"mappings":"AAoOA,OAAO,KAAK,EAAE,wBAAwB,IAAI,gBAAgB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAYnI,KAAK,WAAW,GAAG;IACjB,MAAM,EAAE,gBAAgB,CAAC;IACzB,gEAAgE;IAChE,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;gFAC4E;IAC5E,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAC1C,CAAC;AAwVF,QAAA,MAAM,YAAY;;;;;;kFAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -29,7 +29,18 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
29
29
|
submit: () => any;
|
|
30
30
|
cancel: () => any;
|
|
31
31
|
edit: () => any;
|
|
32
|
-
runAction: (action:
|
|
32
|
+
runAction: (action: {
|
|
33
|
+
id: string;
|
|
34
|
+
label: string;
|
|
35
|
+
kind: "chat";
|
|
36
|
+
role: string;
|
|
37
|
+
template: string;
|
|
38
|
+
icon?: string | undefined;
|
|
39
|
+
when?: {
|
|
40
|
+
field: string;
|
|
41
|
+
in: string[];
|
|
42
|
+
} | undefined;
|
|
43
|
+
}) => any;
|
|
33
44
|
itemChat: (message: string) => any;
|
|
34
45
|
"update:editing": (value: EditState | null) => any;
|
|
35
46
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
@@ -38,7 +49,18 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
38
49
|
onSubmit?: (() => any) | undefined;
|
|
39
50
|
onCancel?: (() => any) | undefined;
|
|
40
51
|
onEdit?: (() => any) | undefined;
|
|
41
|
-
onRunAction?: ((action:
|
|
52
|
+
onRunAction?: ((action: {
|
|
53
|
+
id: string;
|
|
54
|
+
label: string;
|
|
55
|
+
kind: "chat";
|
|
56
|
+
role: string;
|
|
57
|
+
template: string;
|
|
58
|
+
icon?: string | undefined;
|
|
59
|
+
when?: {
|
|
60
|
+
field: string;
|
|
61
|
+
in: string[];
|
|
62
|
+
} | undefined;
|
|
63
|
+
}) => any) | undefined;
|
|
42
64
|
onItemChat?: ((message: string) => any) | undefined;
|
|
43
65
|
"onUpdate:editing"?: ((value: EditState | null) => any) | undefined;
|
|
44
66
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CollectionRecordPanel.vue.d.ts","sourceRoot":"","sources":["../../../src/vue/components/CollectionRecordPanel.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CollectionRecordPanel.vue.d.ts","sourceRoot":"","sources":["../../../src/vue/components/CollectionRecordPanel.vue"],"names":[],"mappings":"AAosBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,KAAK,EACV,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EAEd,SAAS,EAEV,MAAM,8BAA8B,CAAC;AAQtC,KAAK,WAAW,GAAG;IACjB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,8CAA8C;IAC9C,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/B,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,EAAE,gBAAgB,EAAE,CAAC;IACnC,qEAAqE;IACrE,UAAU,EAAE,cAAc,GAAG,IAAI,CAAC;IAClC,gDAAgD;IAChD,WAAW,EAAE,cAAc,GAAG,IAAI,CAAC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,8DAA8D;IAC9D,MAAM,EAAE,mBAAmB,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AA+JF,KAAK,gBAAgB,GAAG;IACxB,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;CAC3B,CAAC;AAKF,KAAK,iBAAiB,GAAG,WAAW,GAAG,gBAAgB,CAAC;AA27CxD,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kFAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CollectionView.vue.d.ts","sourceRoot":"","sources":["../../../src/vue/components/CollectionView.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CollectionView.vue.d.ts","sourceRoot":"","sources":["../../../src/vue/components/CollectionView.vue"],"names":[],"mappings":"AA00EA,OAAO,EAML,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACrB,MAAM,uBAAuB,CAAC;AAqC/B;;;;;;;;;6CAS6C;AAC7C,KAAK,WAAW,GAAG;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C;;;;;uBAKmB;IACnB,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;4EAGwE;IACxE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;wDAGoD;IACpD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;4EACwE;IACxE,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAozHF,QAAA,MAAM,YAAY;;;cAzyHiB,eAAe;qBAAe,MAAM;oBAAc,MAAM;;;;;cAAxD,eAAe;qBAAe,MAAM;oBAAc,MAAM;;kFA4yHzF,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Ref } from "vue";
|
|
2
2
|
import type { CollectionDetail, CollectionItem, CollectionSchema, CollectionFieldSpec as FieldSpec, CollectionFieldType as FieldType, EmbedCache, EmbedView, RefCache, RefOption, RefRecordCache } from "@mulmoclaude/core/collection";
|
|
3
3
|
export interface CollectionRendering {
|
|
4
4
|
refCache: Ref<RefCache>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCollectionRendering.d.ts","sourceRoot":"","sources":["../../src/vue/useCollectionRendering.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useCollectionRendering.d.ts","sourceRoot":"","sources":["../../src/vue/useCollectionRendering.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAG/B,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,mBAAmB,IAAI,SAAS,EAChC,mBAAmB,IAAI,SAAS,EAChC,UAAU,EACV,SAAS,EACT,QAAQ,EACR,SAAS,EACT,cAAc,EACf,MAAM,8BAA8B,CAAC;AAwBtC,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;IACxB,cAAc,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;IACpC,UAAU,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;IAC5B,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,qBAAqB,EAAE,CAAC,MAAM,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzF,UAAU,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7D,UAAU,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;IAChD,YAAY,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;IAClD,aAAa,EAAE,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,KAAK,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC5E,eAAe,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,KAAK,MAAM,GAAG,SAAS,CAAC;IACrG,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,KAAK,MAAM,CAAC;IACzD,WAAW,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,aAAa,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7F,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,KAAK,MAAM,CAAC;IACxD,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC;IACvC,aAAa,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;IAC3C,WAAW,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,CAAC;IAC/C,aAAa,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,CAAC;IACjD,SAAS,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACzD,YAAY,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;IAC1C,aAAa,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI,KAAK,MAAM,CAAC;IAC9F,YAAY,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,MAAM,CAAC;IAC1C,OAAO,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,MAAM,GAAG,SAAS,CAAC;IACjD,SAAS,EAAE,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,EAAE,cAAc,EAAE,UAAU,EAAE,cAAc,KAAK,cAAc,CAAC;IAC1G,0BAA0B,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,KAAK,MAAM,GAAG,IAAI,CAAC;IACxG,cAAc,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI,KAAK,MAAM,CAAC;CACrG;AAiBD,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,GAAG,CAAC,gBAAgB,GAAG,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,mBAAmB,CAsBzH"}
|
|
@@ -6,7 +6,9 @@ export declare function detailText(value: unknown): string;
|
|
|
6
6
|
export declare function formatCell(value: unknown, type: FieldType): string;
|
|
7
7
|
/** Resolve the ISO 4217 code for a money field: a per-record
|
|
8
8
|
* `currencyField` (when present and non-blank) wins over the field's
|
|
9
|
-
* literal `currency`.
|
|
9
|
+
* literal `currency`. Only `money` / `derived` variants carry currency
|
|
10
|
+
* keys; any other field resolves to undefined (the formatter's USD
|
|
11
|
+
* fallback), as before. */
|
|
10
12
|
export declare function resolveCurrency(field: FieldSpec, record: CollectionItem | null | undefined): string | undefined;
|
|
11
13
|
export declare function formatMoney(value: unknown, currency: string | undefined, displayLocale: string): string;
|
|
12
14
|
export declare function currencySymbolForLocale(currency: string | undefined, locale: string): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCollectionRendering.helpers.d.ts","sourceRoot":"","sources":["../../src/vue/useCollectionRendering.helpers.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,wBAAwB,EACxB,cAAc,EACd,gBAAgB,EAChB,mBAAmB,IAAI,SAAS,EAChC,mBAAmB,IAAI,SAAS,EAChC,aAAa,EACb,SAAS,EACT,YAAY,EACb,MAAM,8BAA8B,CAAC;AAWtC,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAIpE;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAOpD;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAErD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAGjD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,GAAG,MAAM,CAOlE;AAED
|
|
1
|
+
{"version":3,"file":"useCollectionRendering.helpers.d.ts","sourceRoot":"","sources":["../../src/vue/useCollectionRendering.helpers.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,wBAAwB,EACxB,cAAc,EACd,gBAAgB,EAChB,mBAAmB,IAAI,SAAS,EAChC,mBAAmB,IAAI,SAAS,EAChC,aAAa,EACb,SAAS,EACT,YAAY,EACb,MAAM,8BAA8B,CAAC;AAWtC,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAIpE;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAOpD;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAErD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAGjD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,GAAG,MAAM,CAOlE;AAED;;;;4BAI4B;AAC5B,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAO/G;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAUvG;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAQ5F;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAGnE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEpD;AAED;qEACqE;AACrE,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAI7F;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAYnE;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAQrE;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,wBAAwB,GAAG,aAAa,CAWlF;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,wBAAwB,GAAG,YAAY,CAQhF;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,SAAS,EAAE,CAIhE;AAED;;yEAEyE;AACzE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,SAAS,EAAE,CAYhG"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { CollectionItem, CollectionSchema, CollectionFieldSpec as FieldSpec, EmbedCache, EmbedView, RefCache, RefOption, RefRecordCache } from "@mulmoclaude/core/collection";
|
|
2
|
+
export declare function lookupRefDisplay(refCache: RefCache, targetSlug: string, itemSlug: string): string;
|
|
3
|
+
export declare function refOptionsFor(refCache: RefCache, targetSlug: string): RefOption[];
|
|
4
|
+
/** Dropdown options for an `embed` field's per-record picker (`idField`):
|
|
5
|
+
* every record in the target collection, labelled by its name/title (or
|
|
6
|
+
* primary key). Built from `embedCache` so it works for embed targets
|
|
7
|
+
* that aren't also `ref` targets (the profile collection, say). */
|
|
8
|
+
export declare function embedOptionsFor(embedCache: EmbedCache, targetSlug: string): RefOption[];
|
|
9
|
+
export declare function resolveEmbed(field: FieldSpec, record: CollectionItem | null, embedCache: EmbedCache): {
|
|
10
|
+
schema: CollectionSchema | null;
|
|
11
|
+
item: CollectionItem | null;
|
|
12
|
+
};
|
|
13
|
+
export declare function formatEmbedValue(field: FieldSpec, value: unknown, record: CollectionItem | null, locale: string): string;
|
|
14
|
+
/** Build the read-only embed view-models for one record. A function of the
|
|
15
|
+
* open record (not a bare computed) because a per-record `idField` embed
|
|
16
|
+
* resolves a different target per row. `schema` is the OPEN collection's
|
|
17
|
+
* schema (null when no collection is loaded → no views). */
|
|
18
|
+
export declare function buildEmbedViews(schema: CollectionSchema | null, embedCache: EmbedCache, record: CollectionItem | null, locale: string): Record<string, EmbedView>;
|
|
19
|
+
export declare function renderSubCell(subField: FieldSpec, value: unknown, record: CollectionItem | null, refCache: RefCache, locale: string): string;
|
|
20
|
+
export declare function evaluateDerived(field: FieldSpec, fieldKey: string, item: CollectionItem, schema: CollectionSchema | null, refRecords: RefRecordCache): number | null;
|
|
21
|
+
export declare function renderDerived(field: FieldSpec, computedValue: unknown, record: CollectionItem | null, locale: string): string;
|
|
22
|
+
//# sourceMappingURL=useCollectionRendering.renderers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCollectionRendering.renderers.d.ts","sourceRoot":"","sources":["../../src/vue/useCollectionRendering.renderers.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAChB,mBAAmB,IAAI,SAAS,EAChC,UAAU,EAEV,SAAS,EACT,QAAQ,EACR,SAAS,EACT,cAAc,EACf,MAAM,8BAA8B,CAAC;AAGtC,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGjG;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,CAGjF;AAED;;;oEAGoE;AACpE,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,CAGvF;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,cAAc,GAAG,IAAI,EAC7B,UAAU,EAAE,UAAU,GACrB;IAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CAAA;CAAE,CAOlE;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGxH;AAED;;;6DAG6D;AAC7D,wBAAgB,eAAe,CAC7B,MAAM,EAAE,gBAAgB,GAAG,IAAI,EAC/B,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,cAAc,GAAG,IAAI,EAC7B,MAAM,EAAE,MAAM,GACb,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAmB3B;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAI5I;AAOD,wBAAgB,eAAe,CAC7B,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,gBAAgB,GAAG,IAAI,EAC/B,UAAU,EAAE,cAAc,GACzB,MAAM,GAAG,IAAI,CAKf;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAK7H"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type Ref } from "vue";
|
|
2
|
+
import { type CollectionApiResult } from "./uiContext";
|
|
3
|
+
import type { CollectionDetail, CollectionDetailResponse, CollectionSchema, EmbedCache, RefCache, RefRecordCache } from "@mulmoclaude/core/collection";
|
|
4
|
+
export interface LinkedCollectionCaches {
|
|
5
|
+
refCache: Ref<RefCache>;
|
|
6
|
+
refRecordCache: Ref<RefRecordCache>;
|
|
7
|
+
embedCache: Ref<EmbedCache>;
|
|
8
|
+
resetLinkedCaches: () => void;
|
|
9
|
+
loadLinkedCollections: (schema: CollectionSchema, expectedSlug: string) => Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
export interface LinkedTargets {
|
|
12
|
+
refTargets: Set<string>;
|
|
13
|
+
embedTargets: Set<string>;
|
|
14
|
+
allTargets: string[];
|
|
15
|
+
}
|
|
16
|
+
export interface LinkedCachesSnapshot {
|
|
17
|
+
refCache: RefCache;
|
|
18
|
+
refRecordCache: RefRecordCache;
|
|
19
|
+
embedCache: EmbedCache;
|
|
20
|
+
}
|
|
21
|
+
type FetchCollectionDetail = (slug: string) => Promise<CollectionApiResult<CollectionDetailResponse>>;
|
|
22
|
+
/** The de-duplicated ref + embed target slugs a schema links to. `allTargets`
|
|
23
|
+
* is the union (each target fetched once even when both ref'd and embedded). */
|
|
24
|
+
export declare function linkedTargets(schema: CollectionSchema): LinkedTargets;
|
|
25
|
+
/** Fan-out fetch that hydrates the linked-collection caches. Best-effort: a
|
|
26
|
+
* target whose fetch *rejects* (vs. resolving `{ ok: false }`) is coerced to a
|
|
27
|
+
* skip and must not abort the others. Returns null when a quicker subsequent
|
|
28
|
+
* load has already moved on (stale-write guard) so the caller drops the write.
|
|
29
|
+
* Pure + injectable (`fetchDetail`, `currentSlug`) so both paths are testable. */
|
|
30
|
+
export declare function fetchLinkedCaches(targets: LinkedTargets, fetchDetail: FetchCollectionDetail, currentSlug: () => string | undefined, expectedSlug: string): Promise<LinkedCachesSnapshot | null>;
|
|
31
|
+
export declare function useLinkedCollectionCaches(collection: Ref<CollectionDetail | null>): LinkedCollectionCaches;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=useLinkedCollectionCaches.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLinkedCollectionCaches.d.ts","sourceRoot":"","sources":["../../src/vue/useLinkedCollectionCaches.ts"],"names":[],"mappings":"AAOA,OAAO,EAAO,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAgB,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAErE,OAAO,KAAK,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,UAAU,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAEvJ,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;IACxB,cAAc,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;IACpC,UAAU,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;IAC5B,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,qBAAqB,EAAE,CAAC,MAAM,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1F;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACxB,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC1B,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,QAAQ,CAAC;IACnB,cAAc,EAAE,cAAc,CAAC;IAC/B,UAAU,EAAE,UAAU,CAAC;CACxB;AAED,KAAK,qBAAqB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,mBAAmB,CAAC,wBAAwB,CAAC,CAAC,CAAC;AAEtG;iFACiF;AACjF,wBAAgB,aAAa,CAAC,MAAM,EAAE,gBAAgB,GAAG,aAAa,CAKrE;AAED;;;;mFAImF;AACnF,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,aAAa,EACtB,WAAW,EAAE,qBAAqB,EAClC,WAAW,EAAE,MAAM,MAAM,GAAG,SAAS,EACrC,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CA2BtC;AAED,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,GAAG,CAAC,gBAAgB,GAAG,IAAI,CAAC,GAAG,sBAAsB,CA4B1G"}
|
package/dist/vue.cjs
CHANGED
|
@@ -1741,7 +1741,10 @@ var CollectionKanbanView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1741
1741
|
const emit = __emit;
|
|
1742
1742
|
const { t } = useCollectionI18n();
|
|
1743
1743
|
/** The Uncategorized column uses the empty string as its sentinel value. */
|
|
1744
|
-
const groupSpec = (0, vue.computed)(() =>
|
|
1744
|
+
const groupSpec = (0, vue.computed)(() => {
|
|
1745
|
+
const spec = props.schema.fields[props.groupField];
|
|
1746
|
+
return spec?.type === "enum" ? spec : void 0;
|
|
1747
|
+
});
|
|
1745
1748
|
/** Declared enum values become columns in order, with a trailing
|
|
1746
1749
|
* Uncategorized column for empty/unknown values (also a drop target that
|
|
1747
1750
|
* clears the field). The Uncategorized column is omitted when the group
|
|
@@ -1788,7 +1791,10 @@ var CollectionKanbanView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1788
1791
|
const value = String(raw);
|
|
1789
1792
|
return (groupSpec.value?.values ?? []).includes(value) ? value : UNCATEGORIZED;
|
|
1790
1793
|
}
|
|
1791
|
-
const visibleItems = (0, vue.computed)(() =>
|
|
1794
|
+
const visibleItems = (0, vue.computed)(() => {
|
|
1795
|
+
const spec = groupSpec.value;
|
|
1796
|
+
return spec ? props.items.filter((item) => (0, _mulmoclaude_core_collection.fieldVisible)(spec, item)) : [];
|
|
1797
|
+
});
|
|
1792
1798
|
const itemsByColumnMap = (0, vue.computed)(() => {
|
|
1793
1799
|
const map = /* @__PURE__ */ new Map();
|
|
1794
1800
|
for (const column of columns.value) map.set(column.value, []);
|
|
@@ -2315,7 +2321,8 @@ var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
2315
2321
|
/** Required flag for an embed's per-record picker — read off the storage
|
|
2316
2322
|
* field it writes (`idField`), since the embed itself stores nothing. */
|
|
2317
2323
|
function embedPickerRequired(field) {
|
|
2318
|
-
const
|
|
2324
|
+
const idField = field.type === "embed" ? field.idField : void 0;
|
|
2325
|
+
const target = idField ? props.collection.schema.fields[idField] : void 0;
|
|
2319
2326
|
return target ? isFieldRequiredInUi(target) : false;
|
|
2320
2327
|
}
|
|
2321
2328
|
/** Tailwind fill/text/border classes tinting an enum `<select>` by its current
|
|
@@ -3067,8 +3074,11 @@ function formatCell(value, type) {
|
|
|
3067
3074
|
}
|
|
3068
3075
|
/** Resolve the ISO 4217 code for a money field: a per-record
|
|
3069
3076
|
* `currencyField` (when present and non-blank) wins over the field's
|
|
3070
|
-
* literal `currency`.
|
|
3077
|
+
* literal `currency`. Only `money` / `derived` variants carry currency
|
|
3078
|
+
* keys; any other field resolves to undefined (the formatter's USD
|
|
3079
|
+
* fallback), as before. */
|
|
3071
3080
|
function resolveCurrency(field, record) {
|
|
3081
|
+
if (field.type !== "money" && field.type !== "derived") return void 0;
|
|
3072
3082
|
if (field.currencyField && record) {
|
|
3073
3083
|
const code = record[field.currencyField];
|
|
3074
3084
|
if (typeof code === "string" && code.trim().length > 0) return code;
|
|
@@ -3173,8 +3183,60 @@ function buildEmbedOptions(schema, items) {
|
|
|
3173
3183
|
}).filter((opt) => opt.slug.length > 0).sort((left, right) => left.display.localeCompare(right.display));
|
|
3174
3184
|
}
|
|
3175
3185
|
//#endregion
|
|
3176
|
-
//#region src/vue/
|
|
3177
|
-
|
|
3186
|
+
//#region src/vue/useLinkedCollectionCaches.ts
|
|
3187
|
+
/** The de-duplicated ref + embed target slugs a schema links to. `allTargets`
|
|
3188
|
+
* is the union (each target fetched once even when both ref'd and embedded). */
|
|
3189
|
+
function linkedTargets(schema) {
|
|
3190
|
+
const refTargets = new Set(uniqueRefTargets(schema));
|
|
3191
|
+
const embedTargets = new Set(uniqueEmbedTargets(schema));
|
|
3192
|
+
return {
|
|
3193
|
+
refTargets,
|
|
3194
|
+
embedTargets,
|
|
3195
|
+
allTargets: [.../* @__PURE__ */ new Set([...refTargets, ...embedTargets])]
|
|
3196
|
+
};
|
|
3197
|
+
}
|
|
3198
|
+
/** Fan-out fetch that hydrates the linked-collection caches. Best-effort: a
|
|
3199
|
+
* target whose fetch *rejects* (vs. resolving `{ ok: false }`) is coerced to a
|
|
3200
|
+
* skip and must not abort the others. Returns null when a quicker subsequent
|
|
3201
|
+
* load has already moved on (stale-write guard) so the caller drops the write.
|
|
3202
|
+
* Pure + injectable (`fetchDetail`, `currentSlug`) so both paths are testable. */
|
|
3203
|
+
async function fetchLinkedCaches(targets, fetchDetail, currentSlug, expectedSlug) {
|
|
3204
|
+
const { refTargets, embedTargets, allTargets } = targets;
|
|
3205
|
+
const results = await Promise.all(allTargets.map(async (target) => {
|
|
3206
|
+
try {
|
|
3207
|
+
return {
|
|
3208
|
+
target,
|
|
3209
|
+
result: await fetchDetail(target)
|
|
3210
|
+
};
|
|
3211
|
+
} catch {
|
|
3212
|
+
return {
|
|
3213
|
+
target,
|
|
3214
|
+
result: { ok: false }
|
|
3215
|
+
};
|
|
3216
|
+
}
|
|
3217
|
+
}));
|
|
3218
|
+
if (currentSlug() !== expectedSlug) return null;
|
|
3219
|
+
const refCache = {};
|
|
3220
|
+
const refRecordCache = {};
|
|
3221
|
+
const embedCache = {};
|
|
3222
|
+
for (const { target, result } of results) {
|
|
3223
|
+
if (!result.ok) continue;
|
|
3224
|
+
if (refTargets.has(target)) {
|
|
3225
|
+
refCache[target] = buildRefDisplayMap(result.data);
|
|
3226
|
+
refRecordCache[target] = buildRefRecordMap(result.data);
|
|
3227
|
+
}
|
|
3228
|
+
if (embedTargets.has(target)) embedCache[target] = {
|
|
3229
|
+
schema: result.data.collection.schema,
|
|
3230
|
+
items: result.data.items
|
|
3231
|
+
};
|
|
3232
|
+
}
|
|
3233
|
+
return {
|
|
3234
|
+
refCache,
|
|
3235
|
+
refRecordCache,
|
|
3236
|
+
embedCache
|
|
3237
|
+
};
|
|
3238
|
+
}
|
|
3239
|
+
function useLinkedCollectionCaches(collection) {
|
|
3178
3240
|
const refCache = (0, vue.ref)({});
|
|
3179
3241
|
const refRecordCache = (0, vue.ref)({});
|
|
3180
3242
|
const embedCache = (0, vue.ref)({});
|
|
@@ -3184,161 +3246,139 @@ function useCollectionRendering(collection, locale) {
|
|
|
3184
3246
|
embedCache.value = {};
|
|
3185
3247
|
}
|
|
3186
3248
|
async function loadLinkedCollections(schema, expectedSlug) {
|
|
3187
|
-
const
|
|
3188
|
-
|
|
3189
|
-
const allTargets = [.../* @__PURE__ */ new Set([...refTargets, ...embedTargets])];
|
|
3190
|
-
if (allTargets.length === 0) return;
|
|
3249
|
+
const targets = linkedTargets(schema);
|
|
3250
|
+
if (targets.allTargets.length === 0) return;
|
|
3191
3251
|
const binding = collectionUi();
|
|
3192
|
-
const
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
};
|
|
3198
|
-
} catch {
|
|
3199
|
-
return {
|
|
3200
|
-
target,
|
|
3201
|
-
result: { ok: false }
|
|
3202
|
-
};
|
|
3203
|
-
}
|
|
3204
|
-
}));
|
|
3205
|
-
if (collection.value?.slug !== expectedSlug) return;
|
|
3206
|
-
const nextRef = {};
|
|
3207
|
-
const nextRefRecords = {};
|
|
3208
|
-
const nextEmbed = {};
|
|
3209
|
-
for (const { target, result } of results) {
|
|
3210
|
-
if (!result.ok) continue;
|
|
3211
|
-
if (refTargets.has(target)) {
|
|
3212
|
-
nextRef[target] = buildRefDisplayMap(result.data);
|
|
3213
|
-
nextRefRecords[target] = buildRefRecordMap(result.data);
|
|
3214
|
-
}
|
|
3215
|
-
if (embedTargets.has(target)) nextEmbed[target] = {
|
|
3216
|
-
schema: result.data.collection.schema,
|
|
3217
|
-
items: result.data.items
|
|
3218
|
-
};
|
|
3219
|
-
}
|
|
3220
|
-
refCache.value = nextRef;
|
|
3221
|
-
refRecordCache.value = nextRefRecords;
|
|
3222
|
-
embedCache.value = nextEmbed;
|
|
3223
|
-
}
|
|
3224
|
-
function refDisplay(targetSlug, itemSlug) {
|
|
3225
|
-
const map = refCache.value[targetSlug];
|
|
3226
|
-
return map && map[itemSlug] || itemSlug;
|
|
3227
|
-
}
|
|
3228
|
-
function refOptions(targetSlug) {
|
|
3229
|
-
const map = refCache.value[targetSlug];
|
|
3230
|
-
return map ? sortedRefOptions(map) : [];
|
|
3231
|
-
}
|
|
3232
|
-
/** Dropdown options for an `embed` field's per-record picker (`idField`):
|
|
3233
|
-
* every record in the target collection, labelled by its name/title (or
|
|
3234
|
-
* primary key). Built from `embedCache` so it works for embed targets
|
|
3235
|
-
* that aren't also `ref` targets (the profile collection, say). */
|
|
3236
|
-
function embedOptions(targetSlug) {
|
|
3237
|
-
const data = embedCache.value[targetSlug];
|
|
3238
|
-
return data ? buildEmbedOptions(data.schema, data.items) : [];
|
|
3239
|
-
}
|
|
3240
|
-
function resolveEmbed(field, record) {
|
|
3241
|
-
if (field.type !== "embed" || !field.to) return {
|
|
3242
|
-
schema: null,
|
|
3243
|
-
item: null
|
|
3244
|
-
};
|
|
3245
|
-
const targetId = (0, _mulmoclaude_core_collection.embedTargetId)(field, record);
|
|
3246
|
-
const data = targetId ? embedCache.value[field.to] : void 0;
|
|
3247
|
-
if (!data) return {
|
|
3248
|
-
schema: null,
|
|
3249
|
-
item: null
|
|
3250
|
-
};
|
|
3251
|
-
const item = data.items.find((entry) => String(entry[data.schema.primaryKey] ?? "") === targetId) ?? null;
|
|
3252
|
-
return {
|
|
3253
|
-
schema: data.schema,
|
|
3254
|
-
item
|
|
3255
|
-
};
|
|
3256
|
-
}
|
|
3257
|
-
function embedValue(field, value, record) {
|
|
3258
|
-
if (field.type === "money") return formatMoney(value, resolveCurrency(field, record), locale.value);
|
|
3259
|
-
return detailText(value);
|
|
3260
|
-
}
|
|
3261
|
-
/** Build the read-only embed view-models for one record. A function of
|
|
3262
|
-
* the open record (not a bare computed) because a per-record `idField`
|
|
3263
|
-
* embed resolves a different target per row. */
|
|
3264
|
-
function embedViewsFor(record) {
|
|
3265
|
-
const out = {};
|
|
3266
|
-
if (!collection.value) return out;
|
|
3267
|
-
for (const [key, field] of Object.entries(collection.value.schema.fields)) {
|
|
3268
|
-
if (field.type !== "embed") continue;
|
|
3269
|
-
const { schema, item } = resolveEmbed(field, record);
|
|
3270
|
-
const rows = [];
|
|
3271
|
-
if (schema && item) for (const [subKey, subField] of Object.entries(schema.fields)) {
|
|
3272
|
-
const value = item[subKey];
|
|
3273
|
-
if (value === void 0 || value === null || value === "") continue;
|
|
3274
|
-
rows.push({
|
|
3275
|
-
key: subKey,
|
|
3276
|
-
label: subField.label,
|
|
3277
|
-
type: subField.type,
|
|
3278
|
-
value,
|
|
3279
|
-
display: embedValue(subField, value, item)
|
|
3280
|
-
});
|
|
3281
|
-
}
|
|
3282
|
-
out[key] = {
|
|
3283
|
-
found: Boolean(item),
|
|
3284
|
-
rows,
|
|
3285
|
-
targetSlug: field.to ?? "",
|
|
3286
|
-
recordId: (0, _mulmoclaude_core_collection.embedTargetId)(field, record)
|
|
3287
|
-
};
|
|
3288
|
-
}
|
|
3289
|
-
return out;
|
|
3290
|
-
}
|
|
3291
|
-
function currencySymbol(currency) {
|
|
3292
|
-
return currencySymbolForLocale(currency, locale.value);
|
|
3293
|
-
}
|
|
3294
|
-
function artifactUrl(value) {
|
|
3295
|
-
return collectionUi().fileAssetUrl(value);
|
|
3296
|
-
}
|
|
3297
|
-
function fileRoutePath(value) {
|
|
3298
|
-
return collectionUi().fileRoutePath(value);
|
|
3299
|
-
}
|
|
3300
|
-
function formatSubCell(subField, value, record) {
|
|
3301
|
-
if (subField.type === "money") return formatMoney(value, resolveCurrency(subField, record), locale.value);
|
|
3302
|
-
if (subField.type === "ref" && subField.to && typeof value === "string" && value.length > 0) return refDisplay(subField.to, value);
|
|
3303
|
-
return formatCell(value, subField.type);
|
|
3304
|
-
}
|
|
3305
|
-
const stepFor = stepForFieldType;
|
|
3306
|
-
function evaluateDerivedAgainstItem(field, fieldKey, item) {
|
|
3307
|
-
if (!field.formula || !collection.value) return null;
|
|
3308
|
-
const result = (0, _mulmoclaude_core_collection.deriveAll)(collection.value.schema, item, refRecordCache.value)[fieldKey];
|
|
3309
|
-
return typeof result === "number" && Number.isFinite(result) ? result : null;
|
|
3310
|
-
}
|
|
3311
|
-
function derivedDisplay(field, computedValue, record) {
|
|
3312
|
-
if (computedValue === null || computedValue === void 0) return "—";
|
|
3313
|
-
if (field.display === "money") return formatMoney(computedValue, resolveCurrency(field, record), locale.value);
|
|
3314
|
-
return formatCell(computedValue, field.display ?? "number");
|
|
3252
|
+
const snapshot = await fetchLinkedCaches(targets, (slug) => binding.fetchCollectionDetail(slug), () => collection.value?.slug, expectedSlug);
|
|
3253
|
+
if (!snapshot) return;
|
|
3254
|
+
refCache.value = snapshot.refCache;
|
|
3255
|
+
refRecordCache.value = snapshot.refRecordCache;
|
|
3256
|
+
embedCache.value = snapshot.embedCache;
|
|
3315
3257
|
}
|
|
3316
3258
|
return {
|
|
3317
3259
|
refCache,
|
|
3318
3260
|
refRecordCache,
|
|
3319
3261
|
embedCache,
|
|
3320
3262
|
resetLinkedCaches,
|
|
3321
|
-
loadLinkedCollections
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3263
|
+
loadLinkedCollections
|
|
3264
|
+
};
|
|
3265
|
+
}
|
|
3266
|
+
//#endregion
|
|
3267
|
+
//#region src/vue/useCollectionRendering.renderers.ts
|
|
3268
|
+
function lookupRefDisplay(refCache, targetSlug, itemSlug) {
|
|
3269
|
+
const map = refCache[targetSlug];
|
|
3270
|
+
return map && map[itemSlug] || itemSlug;
|
|
3271
|
+
}
|
|
3272
|
+
function refOptionsFor(refCache, targetSlug) {
|
|
3273
|
+
const map = refCache[targetSlug];
|
|
3274
|
+
return map ? sortedRefOptions(map) : [];
|
|
3275
|
+
}
|
|
3276
|
+
/** Dropdown options for an `embed` field's per-record picker (`idField`):
|
|
3277
|
+
* every record in the target collection, labelled by its name/title (or
|
|
3278
|
+
* primary key). Built from `embedCache` so it works for embed targets
|
|
3279
|
+
* that aren't also `ref` targets (the profile collection, say). */
|
|
3280
|
+
function embedOptionsFor(embedCache, targetSlug) {
|
|
3281
|
+
const data = embedCache[targetSlug];
|
|
3282
|
+
return data ? buildEmbedOptions(data.schema, data.items) : [];
|
|
3283
|
+
}
|
|
3284
|
+
function resolveEmbed(field, record, embedCache) {
|
|
3285
|
+
if (field.type !== "embed" || !field.to) return {
|
|
3286
|
+
schema: null,
|
|
3287
|
+
item: null
|
|
3288
|
+
};
|
|
3289
|
+
const targetId = (0, _mulmoclaude_core_collection.embedTargetId)(field, record);
|
|
3290
|
+
const data = targetId ? embedCache[field.to] : void 0;
|
|
3291
|
+
if (!data) return {
|
|
3292
|
+
schema: null,
|
|
3293
|
+
item: null
|
|
3294
|
+
};
|
|
3295
|
+
const item = data.items.find((entry) => String(entry[data.schema.primaryKey] ?? "") === targetId) ?? null;
|
|
3296
|
+
return {
|
|
3297
|
+
schema: data.schema,
|
|
3298
|
+
item
|
|
3299
|
+
};
|
|
3300
|
+
}
|
|
3301
|
+
function formatEmbedValue(field, value, record, locale) {
|
|
3302
|
+
if (field.type === "money") return formatMoney(value, resolveCurrency(field, record), locale);
|
|
3303
|
+
return detailText(value);
|
|
3304
|
+
}
|
|
3305
|
+
/** Build the read-only embed view-models for one record. A function of the
|
|
3306
|
+
* open record (not a bare computed) because a per-record `idField` embed
|
|
3307
|
+
* resolves a different target per row. `schema` is the OPEN collection's
|
|
3308
|
+
* schema (null when no collection is loaded → no views). */
|
|
3309
|
+
function buildEmbedViews(schema, embedCache, record, locale) {
|
|
3310
|
+
const out = {};
|
|
3311
|
+
if (!schema) return out;
|
|
3312
|
+
for (const [key, field] of Object.entries(schema.fields)) {
|
|
3313
|
+
if (field.type !== "embed") continue;
|
|
3314
|
+
const { schema: targetSchema, item } = resolveEmbed(field, record, embedCache);
|
|
3315
|
+
const rows = [];
|
|
3316
|
+
if (targetSchema && item) for (const [subKey, subField] of Object.entries(targetSchema.fields)) {
|
|
3317
|
+
const value = item[subKey];
|
|
3318
|
+
if (value === void 0 || value === null || value === "") continue;
|
|
3319
|
+
rows.push({
|
|
3320
|
+
key: subKey,
|
|
3321
|
+
label: subField.label,
|
|
3322
|
+
type: subField.type,
|
|
3323
|
+
value,
|
|
3324
|
+
display: formatEmbedValue(subField, value, item, locale)
|
|
3325
|
+
});
|
|
3326
|
+
}
|
|
3327
|
+
out[key] = {
|
|
3328
|
+
found: Boolean(item),
|
|
3329
|
+
rows,
|
|
3330
|
+
targetSlug: field.to ?? "",
|
|
3331
|
+
recordId: (0, _mulmoclaude_core_collection.embedTargetId)(field, record)
|
|
3332
|
+
};
|
|
3333
|
+
}
|
|
3334
|
+
return out;
|
|
3335
|
+
}
|
|
3336
|
+
function renderSubCell(subField, value, record, refCache, locale) {
|
|
3337
|
+
if (subField.type === "money") return formatMoney(value, resolveCurrency(subField, record), locale);
|
|
3338
|
+
if (subField.type === "ref" && subField.to && typeof value === "string" && value.length > 0) return lookupRefDisplay(refCache, subField.to, value);
|
|
3339
|
+
return formatCell(value, subField.type);
|
|
3340
|
+
}
|
|
3341
|
+
function evaluateDerived(field, fieldKey, item, schema, refRecords) {
|
|
3342
|
+
if (field.type !== "derived" || !schema) return null;
|
|
3343
|
+
const result = (0, _mulmoclaude_core_collection.deriveAll)(schema, item, refRecords)[fieldKey];
|
|
3344
|
+
return typeof result === "number" && Number.isFinite(result) ? result : null;
|
|
3345
|
+
}
|
|
3346
|
+
function renderDerived(field, computedValue, record, locale) {
|
|
3347
|
+
if (computedValue === null || computedValue === void 0) return "—";
|
|
3348
|
+
const display = field.type === "derived" ? field.display : void 0;
|
|
3349
|
+
if (display === "money") return formatMoney(computedValue, resolveCurrency(field, record), locale);
|
|
3350
|
+
return formatCell(computedValue, display ?? "number");
|
|
3351
|
+
}
|
|
3352
|
+
//#endregion
|
|
3353
|
+
//#region src/vue/useCollectionRendering.ts
|
|
3354
|
+
var STATELESS_RENDERERS = {
|
|
3355
|
+
resolveCurrency,
|
|
3356
|
+
formatMoney,
|
|
3357
|
+
formatCell,
|
|
3358
|
+
detailText,
|
|
3359
|
+
isExternalUrl,
|
|
3360
|
+
tableRows,
|
|
3361
|
+
hasTableRows,
|
|
3362
|
+
inputTypeFor,
|
|
3363
|
+
stepFor: stepForFieldType,
|
|
3364
|
+
deriveAll: _mulmoclaude_core_collection.deriveAll
|
|
3365
|
+
};
|
|
3366
|
+
function useCollectionRendering(collection, locale) {
|
|
3367
|
+
const caches = useLinkedCollectionCaches(collection);
|
|
3368
|
+
const { refCache, refRecordCache, embedCache } = caches;
|
|
3369
|
+
return {
|
|
3370
|
+
...caches,
|
|
3371
|
+
...STATELESS_RENDERERS,
|
|
3372
|
+
refDisplay: (targetSlug, itemSlug) => lookupRefDisplay(refCache.value, targetSlug, itemSlug),
|
|
3373
|
+
refOptions: (targetSlug) => refOptionsFor(refCache.value, targetSlug),
|
|
3374
|
+
embedOptions: (targetSlug) => embedOptionsFor(embedCache.value, targetSlug),
|
|
3375
|
+
embedViewsFor: (record) => buildEmbedViews(collection.value?.schema ?? null, embedCache.value, record, locale.value),
|
|
3376
|
+
currencySymbol: (currency) => currencySymbolForLocale(currency, locale.value),
|
|
3377
|
+
artifactUrl: (value) => collectionUi().fileAssetUrl(value),
|
|
3378
|
+
fileRoutePath: (value) => collectionUi().fileRoutePath(value),
|
|
3379
|
+
formatSubCell: (subField, value, record) => renderSubCell(subField, value, record, refCache.value, locale.value),
|
|
3380
|
+
evaluateDerivedAgainstItem: (field, fieldKey, item) => evaluateDerived(field, fieldKey, item, collection.value?.schema ?? null, refRecordCache.value),
|
|
3381
|
+
derivedDisplay: (field, computedValue, record) => renderDerived(field, computedValue, record, locale.value)
|
|
3342
3382
|
};
|
|
3343
3383
|
}
|
|
3344
3384
|
//#endregion
|
|
@@ -3829,12 +3869,12 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
3829
3869
|
return scalarSortValue(field, item[key]);
|
|
3830
3870
|
}
|
|
3831
3871
|
/** Derived rows sort by their display type: money/number → numeric,
|
|
3832
|
-
* date
|
|
3872
|
+
* date → epoch, anything else → the enriched value as a string. */
|
|
3833
3873
|
function derivedSortValue(field, key, item) {
|
|
3834
|
-
const
|
|
3874
|
+
const display = field.type === "derived" ? field.display : void 0;
|
|
3835
3875
|
if (display === void 0 || display === "number" || display === "money") return (0, _mulmoclaude_core_collection.numericSortValue)(evaluateDerivedAgainstItem(field, key, item));
|
|
3836
3876
|
const enriched = collection.value ? render.deriveAll(collection.value.schema, item, render.refRecordCache.value) : item;
|
|
3837
|
-
if (display === "date"
|
|
3877
|
+
if (display === "date") return (0, _mulmoclaude_core_collection.dateSortValue)(enriched[key]);
|
|
3838
3878
|
return (0, _mulmoclaude_core_collection.stringSortValue)(enriched[key]);
|
|
3839
3879
|
}
|
|
3840
3880
|
const sortedItems = (0, vue.computed)(() => {
|
|
@@ -4012,10 +4052,12 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
4012
4052
|
function buildChatSeed(slug, message, itemId) {
|
|
4013
4053
|
const current = collection.value;
|
|
4014
4054
|
if (current?.source !== "feed") return itemId ? `/${slug} id=${itemId} ${message}` : `/${slug} ${message}`;
|
|
4055
|
+
const dataPath = current.schema.dataPath ?? `data/feeds/${slug}`;
|
|
4056
|
+
const scoped = itemId ? `(for record \`${itemId}\`) ${message}` : message;
|
|
4015
4057
|
return t("collectionsView.feedChatSeed", {
|
|
4016
4058
|
slug,
|
|
4017
|
-
dataPath
|
|
4018
|
-
message:
|
|
4059
|
+
dataPath,
|
|
4060
|
+
message: scoped
|
|
4019
4061
|
});
|
|
4020
4062
|
}
|
|
4021
4063
|
/** Start a new general-role chat seeded from the current view. */
|
|
@@ -4090,7 +4132,10 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
4090
4132
|
enumOriginallyEmpty.value = snapshotEmptyEnums(result.data.collection.schema, result.data.items);
|
|
4091
4133
|
await render.loadLinkedCollections(result.data.collection.schema, slug);
|
|
4092
4134
|
if (activeSlug.value !== slug) return;
|
|
4093
|
-
if (viewing.value)
|
|
4135
|
+
if (viewing.value) {
|
|
4136
|
+
const openId = String(viewing.value[result.data.collection.schema.primaryKey] ?? "");
|
|
4137
|
+
viewing.value = findItemById(openId) ?? null;
|
|
4138
|
+
}
|
|
4094
4139
|
}
|
|
4095
4140
|
function maybeAutoRefreshFeed(slug) {
|
|
4096
4141
|
if (embedded.value) return;
|
|
@@ -4268,7 +4313,8 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
4268
4313
|
}
|
|
4269
4314
|
/** Select a custom view by id (builds the `custom:<id>` mode key). */
|
|
4270
4315
|
function setCustomView(viewId) {
|
|
4271
|
-
|
|
4316
|
+
const mode = `custom:${viewId}`;
|
|
4317
|
+
view.value = mode;
|
|
4272
4318
|
}
|
|
4273
4319
|
/** A short, slug-safe id not already used by a loaded record. Collisions
|
|
4274
4320
|
* are astronomically unlikely (32 bits), but we still re-roll a few
|
|
@@ -4426,7 +4472,8 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
4426
4472
|
viewing.value = null;
|
|
4427
4473
|
return;
|
|
4428
4474
|
}
|
|
4429
|
-
|
|
4475
|
+
const match = findItemById(selected) ?? null;
|
|
4476
|
+
viewing.value = match;
|
|
4430
4477
|
}
|
|
4431
4478
|
/** Title for the open-mode header: the record's primary-key value
|
|
4432
4479
|
* (e.g. `INV-2026-0001`), falling back to the collection title.
|
|
@@ -4520,19 +4567,17 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
4520
4567
|
/** Whether a `toggle` field reads as checked: its projected enum field
|
|
4521
4568
|
* currently equals `onValue`. The toggle stores nothing itself. */
|
|
4522
4569
|
function toggleChecked(item, field) {
|
|
4523
|
-
return field.
|
|
4570
|
+
return field.type === "toggle" && String(item[field.field] ?? "") === field.onValue;
|
|
4524
4571
|
}
|
|
4525
4572
|
/** Flip a `toggle`: write the projected enum field to `offValue` when
|
|
4526
4573
|
* currently checked, else `onValue`. Reuses the inline-edit PUT path
|
|
4527
4574
|
* (optimistic + rollback) — the toggle has no value of its own. */
|
|
4528
4575
|
function commitToggle(item, field) {
|
|
4576
|
+
if (field.type !== "toggle" || !collection.value) return;
|
|
4529
4577
|
const targetKey = field.field;
|
|
4530
|
-
if (!targetKey || !collection.value) return;
|
|
4531
4578
|
const enumField = collection.value.schema.fields[targetKey];
|
|
4532
4579
|
if (!enumField) return;
|
|
4533
|
-
|
|
4534
|
-
if (next === void 0) return;
|
|
4535
|
-
commitInlineEdit(item, targetKey, enumField, next);
|
|
4580
|
+
commitInlineEdit(item, targetKey, enumField, toggleChecked(item, field) ? field.offValue : field.onValue);
|
|
4536
4581
|
}
|
|
4537
4582
|
async function confirmDelete(item) {
|
|
4538
4583
|
if (!collection.value) return;
|