@mintplayer/ng-spark 22.23.0 → 22.24.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.
Files changed (68) hide show
  1. package/README.md +181 -0
  2. package/fesm2022/mintplayer-ng-spark-attribute-description.mjs +100 -47
  3. package/fesm2022/mintplayer-ng-spark-attribute-description.mjs.map +1 -1
  4. package/fesm2022/mintplayer-ng-spark-client-operations.mjs +308 -329
  5. package/fesm2022/mintplayer-ng-spark-client-operations.mjs.map +1 -1
  6. package/fesm2022/mintplayer-ng-spark-column-filter.mjs +175 -135
  7. package/fesm2022/mintplayer-ng-spark-column-filter.mjs.map +1 -1
  8. package/fesm2022/mintplayer-ng-spark-grid.mjs +2259 -1119
  9. package/fesm2022/mintplayer-ng-spark-grid.mjs.map +1 -1
  10. package/fesm2022/mintplayer-ng-spark-history.mjs +611 -0
  11. package/fesm2022/mintplayer-ng-spark-history.mjs.map +1 -0
  12. package/fesm2022/mintplayer-ng-spark-icon.mjs +64 -27
  13. package/fesm2022/mintplayer-ng-spark-icon.mjs.map +1 -1
  14. package/fesm2022/mintplayer-ng-spark-models.mjs +366 -762
  15. package/fesm2022/mintplayer-ng-spark-models.mjs.map +1 -1
  16. package/fesm2022/mintplayer-ng-spark-moderation.mjs +1212 -0
  17. package/fesm2022/mintplayer-ng-spark-moderation.mjs.map +1 -0
  18. package/fesm2022/mintplayer-ng-spark-panels.mjs +52 -0
  19. package/fesm2022/mintplayer-ng-spark-panels.mjs.map +1 -0
  20. package/fesm2022/mintplayer-ng-spark-pipes.mjs +1122 -765
  21. package/fesm2022/mintplayer-ng-spark-pipes.mjs.map +1 -1
  22. package/fesm2022/mintplayer-ng-spark-po-create.mjs +273 -169
  23. package/fesm2022/mintplayer-ng-spark-po-create.mjs.map +1 -1
  24. package/fesm2022/mintplayer-ng-spark-po-detail.mjs +786 -410
  25. package/fesm2022/mintplayer-ng-spark-po-detail.mjs.map +1 -1
  26. package/fesm2022/mintplayer-ng-spark-po-edit.mjs +292 -284
  27. package/fesm2022/mintplayer-ng-spark-po-edit.mjs.map +1 -1
  28. package/fesm2022/mintplayer-ng-spark-po-form.mjs +2187 -1225
  29. package/fesm2022/mintplayer-ng-spark-po-form.mjs.map +1 -1
  30. package/fesm2022/mintplayer-ng-spark-query-list.mjs +516 -303
  31. package/fesm2022/mintplayer-ng-spark-query-list.mjs.map +1 -1
  32. package/fesm2022/mintplayer-ng-spark-renderers.mjs +17 -55
  33. package/fesm2022/mintplayer-ng-spark-renderers.mjs.map +1 -1
  34. package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs +216 -177
  35. package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs.map +1 -1
  36. package/fesm2022/mintplayer-ng-spark-routes.mjs +24 -28
  37. package/fesm2022/mintplayer-ng-spark-routes.mjs.map +1 -1
  38. package/fesm2022/mintplayer-ng-spark-services.mjs +625 -640
  39. package/fesm2022/mintplayer-ng-spark-services.mjs.map +1 -1
  40. package/fesm2022/mintplayer-ng-spark-shell.mjs +1013 -397
  41. package/fesm2022/mintplayer-ng-spark-shell.mjs.map +1 -1
  42. package/fesm2022/mintplayer-ng-spark-soft-delete.mjs +294 -0
  43. package/fesm2022/mintplayer-ng-spark-soft-delete.mjs.map +1 -0
  44. package/fesm2022/mintplayer-ng-spark.mjs +13 -50
  45. package/fesm2022/mintplayer-ng-spark.mjs.map +1 -1
  46. package/package.json +17 -1
  47. package/types/mintplayer-ng-spark-attribute-description.d.ts +25 -18
  48. package/types/mintplayer-ng-spark-client-operations.d.ts +133 -160
  49. package/types/mintplayer-ng-spark-column-filter.d.ts +73 -55
  50. package/types/mintplayer-ng-spark-grid.d.ts +885 -448
  51. package/types/mintplayer-ng-spark-history.d.ts +223 -0
  52. package/types/mintplayer-ng-spark-icon.d.ts +15 -13
  53. package/types/mintplayer-ng-spark-models.d.ts +624 -573
  54. package/types/mintplayer-ng-spark-moderation.d.ts +402 -0
  55. package/types/mintplayer-ng-spark-panels.d.ts +108 -0
  56. package/types/mintplayer-ng-spark-pipes.d.ts +120 -149
  57. package/types/mintplayer-ng-spark-po-create.d.ts +46 -37
  58. package/types/mintplayer-ng-spark-po-detail.d.ts +177 -117
  59. package/types/mintplayer-ng-spark-po-edit.d.ts +64 -65
  60. package/types/mintplayer-ng-spark-po-form.d.ts +507 -371
  61. package/types/mintplayer-ng-spark-query-list.d.ts +118 -82
  62. package/types/mintplayer-ng-spark-renderers.d.ts +79 -85
  63. package/types/mintplayer-ng-spark-retry-action-modal.d.ts +31 -34
  64. package/types/mintplayer-ng-spark-routes.d.ts +7 -11
  65. package/types/mintplayer-ng-spark-services.d.ts +377 -261
  66. package/types/mintplayer-ng-spark-shell.d.ts +209 -128
  67. package/types/mintplayer-ng-spark-soft-delete.d.ts +90 -0
  68. package/types/mintplayer-ng-spark.d.ts +7 -12
@@ -1,768 +1,1125 @@
1
- import * as i0 from '@angular/core';
2
- import { inject, Pipe } from '@angular/core';
3
- import { SparkLanguageService } from '@mintplayer/ng-spark/services';
4
- import { resolveTranslation, resolvedBreadcrumb, nestedPoToDict, isReservedAsDetailKey, valueFor, AS_DETAIL_BREADCRUMBS_KEY, selfBreadcrumb, ELookupDisplayType, nestedPoToDisplayRow } from '@mintplayer/ng-spark/models';
5
-
6
- class TranslateKeyPipe {
7
- lang = inject(SparkLanguageService);
8
- transform(key) {
9
- return this.lang.t(key);
10
- }
11
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: TranslateKeyPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
12
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: TranslateKeyPipe, isStandalone: true, name: "t", pure: false });
13
- }
14
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: TranslateKeyPipe, decorators: [{
15
- type: Pipe,
16
- args: [{ name: 't', pure: false, standalone: true }]
17
- }] });
18
-
19
- class ResolveTranslationPipe {
20
- transform(value, fallback) {
21
- return resolveTranslation(value) || fallback || '';
22
- }
23
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ResolveTranslationPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
24
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: ResolveTranslationPipe, isStandalone: true, name: "resolveTranslation", pure: false });
25
- }
26
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ResolveTranslationPipe, decorators: [{
27
- type: Pipe,
28
- args: [{ name: 'resolveTranslation', standalone: true, pure: false }]
29
- }] });
30
-
31
- class InputTypePipe {
32
- transform(dataType) {
33
- switch (dataType) {
34
- case 'number':
35
- case 'decimal':
36
- return 'number';
37
- case 'boolean':
38
- return 'checkbox';
39
- case 'datetime':
40
- return 'datetime-local';
41
- case 'date':
42
- return 'date';
43
- case 'color':
44
- return 'color';
45
- case 'url':
46
- case 'image':
47
- // Both hold a URL, so `url` gets the browser's own validation and keyboard. `image` is a
48
- // link to an image rather than an upload: the value is still a string the author types.
49
- return 'url';
50
- default:
51
- return 'text';
52
- }
53
- }
54
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: InputTypePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
55
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: InputTypePipe, isStandalone: true, name: "inputType" });
56
- }
57
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: InputTypePipe, decorators: [{
58
- type: Pipe,
59
- args: [{ name: 'inputType', standalone: true, pure: true }]
60
- }] });
61
-
62
- /**
63
- * Parses a wire value into a `Date`, or `null` when it is absent or unparseable.
64
- *
65
- * Exists so the detail page and the grid agree. The grid gets its `Date` from `queryCellValue`, which
66
- * needs a cell and a column and so cannot be reused on a detail attribute; before this, the detail page
67
- * had no parsing step at all and printed the raw ISO string — `2026-12-31T23:59:00-08:00` in a
68
- * definition list, while the grid showed `01/01/2027, 08:59` for the same document.
69
- *
70
- * The parsing contract is deliberately identical to `queryCellValue`'s: `new Date(...)`, and an
71
- * unparseable value yields `null` so the caller can fall back to its own text rather than rendering
72
- * "Invalid Date".
73
- *
74
- * Note what `new Date(...)` does to an offset, because it is the whole reason this is a separate step:
75
- * it collapses the value to an instant and forgets the offset it was written with. That is correct for
76
- * display — a viewer wants the moment in their own zone — but it means a `Date` can never be the thing
77
- * you reach for when you need the *originating* wall clock. Read that from the wire value instead.
78
- */
79
- class ParsedDatePipe {
80
- transform(value) {
81
- if (value == null || value === '')
82
- return null;
83
- if (value instanceof Date)
84
- return Number.isNaN(value.getTime()) ? null : value;
85
- if (typeof value !== 'string' && typeof value !== 'number')
86
- return null;
87
- const parsed = new Date(value);
88
- return Number.isNaN(parsed.getTime()) ? null : parsed;
89
- }
90
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ParsedDatePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
91
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: ParsedDatePipe, isStandalone: true, name: "parsedDate" });
92
- }
93
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ParsedDatePipe, decorators: [{
94
- type: Pipe,
95
- args: [{ name: 'parsedDate', standalone: true, pure: true }]
96
- }] });
97
-
98
- /**
99
- * Fills a `{Field}` template from a plain object's own fields. Used ONLY for AsDetail
100
- * nested-object summary display: an embedded value object (no id, no document) is rendered
101
- * client-side from its own fields. This is deliberately distinct from entity/reference
102
- * breadcrumbs — those are resolved recursively on the server (BreadcrumbResolver) and the
103
- * client only reads the resulting strings. Unknown or null placeholders render empty.
104
- */
1
+ import * as i0 from "@angular/core";
2
+ import { Pipe, inject } from "@angular/core";
3
+ import { SparkLanguageService } from "@mintplayer/ng-spark/services";
4
+ import { AS_DETAIL_BREADCRUMBS_KEY, ELookupDisplayType, isReservedAsDetailKey, nestedPoToDict, nestedPoToDisplayRow, resolveTranslation, resolvedBreadcrumb, selfBreadcrumb, valueFor } from "@mintplayer/ng-spark/models";
5
+ var TranslateKeyPipe = class TranslateKeyPipe {
6
+ lang = inject(SparkLanguageService);
7
+ transform(key) {
8
+ return this.lang.t(key);
9
+ }
10
+ static ɵfac = i0.ɵɵngDeclareFactory({
11
+ minVersion: "12.0.0",
12
+ version: "22.2.0",
13
+ ngImport: i0,
14
+ type: TranslateKeyPipe,
15
+ deps: [],
16
+ target: i0.ɵɵFactoryTarget.Pipe
17
+ });
18
+ static ɵpipe = i0.ɵɵngDeclarePipe({
19
+ minVersion: "14.0.0",
20
+ version: "22.2.0",
21
+ ngImport: i0,
22
+ type: TranslateKeyPipe,
23
+ isStandalone: true,
24
+ name: "t",
25
+ pure: false
26
+ });
27
+ };
28
+ i0.ɵɵngDeclareClassMetadata({
29
+ minVersion: "12.0.0",
30
+ version: "22.2.0",
31
+ ngImport: i0,
32
+ type: TranslateKeyPipe,
33
+ decorators: [{
34
+ type: Pipe,
35
+ args: [{
36
+ name: "t",
37
+ pure: false,
38
+ standalone: true
39
+ }]
40
+ }]
41
+ });
42
+ var ResolveTranslationPipe = class ResolveTranslationPipe {
43
+ transform(value, fallback) {
44
+ return resolveTranslation(value) || fallback || "";
45
+ }
46
+ static ɵfac = i0.ɵɵngDeclareFactory({
47
+ minVersion: "12.0.0",
48
+ version: "22.2.0",
49
+ ngImport: i0,
50
+ type: ResolveTranslationPipe,
51
+ deps: [],
52
+ target: i0.ɵɵFactoryTarget.Pipe
53
+ });
54
+ static ɵpipe = i0.ɵɵngDeclarePipe({
55
+ minVersion: "14.0.0",
56
+ version: "22.2.0",
57
+ ngImport: i0,
58
+ type: ResolveTranslationPipe,
59
+ isStandalone: true,
60
+ name: "resolveTranslation",
61
+ pure: false
62
+ });
63
+ };
64
+ i0.ɵɵngDeclareClassMetadata({
65
+ minVersion: "12.0.0",
66
+ version: "22.2.0",
67
+ ngImport: i0,
68
+ type: ResolveTranslationPipe,
69
+ decorators: [{
70
+ type: Pipe,
71
+ args: [{
72
+ name: "resolveTranslation",
73
+ standalone: true,
74
+ pure: false
75
+ }]
76
+ }]
77
+ });
78
+ var InputTypePipe = class InputTypePipe {
79
+ transform(dataType) {
80
+ switch (dataType) {
81
+ case "number":
82
+ case "decimal": return "number";
83
+ case "boolean": return "checkbox";
84
+ case "datetime": return "datetime-local";
85
+ case "date": return "date";
86
+ case "color": return "color";
87
+ case "url":
88
+ case "image": return "url";
89
+ default: return "text";
90
+ }
91
+ }
92
+ static ɵfac = i0.ɵɵngDeclareFactory({
93
+ minVersion: "12.0.0",
94
+ version: "22.2.0",
95
+ ngImport: i0,
96
+ type: InputTypePipe,
97
+ deps: [],
98
+ target: i0.ɵɵFactoryTarget.Pipe
99
+ });
100
+ static ɵpipe = i0.ɵɵngDeclarePipe({
101
+ minVersion: "14.0.0",
102
+ version: "22.2.0",
103
+ ngImport: i0,
104
+ type: InputTypePipe,
105
+ isStandalone: true,
106
+ name: "inputType"
107
+ });
108
+ };
109
+ i0.ɵɵngDeclareClassMetadata({
110
+ minVersion: "12.0.0",
111
+ version: "22.2.0",
112
+ ngImport: i0,
113
+ type: InputTypePipe,
114
+ decorators: [{
115
+ type: Pipe,
116
+ args: [{
117
+ name: "inputType",
118
+ standalone: true,
119
+ pure: true
120
+ }]
121
+ }]
122
+ });
123
+ var ParsedDatePipe = class ParsedDatePipe {
124
+ transform(value) {
125
+ if (value == null || value === "") return null;
126
+ if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value;
127
+ if (typeof value !== "string" && typeof value !== "number") return null;
128
+ const parsed = new Date(value);
129
+ return Number.isNaN(parsed.getTime()) ? null : parsed;
130
+ }
131
+ static ɵfac = i0.ɵɵngDeclareFactory({
132
+ minVersion: "12.0.0",
133
+ version: "22.2.0",
134
+ ngImport: i0,
135
+ type: ParsedDatePipe,
136
+ deps: [],
137
+ target: i0.ɵɵFactoryTarget.Pipe
138
+ });
139
+ static ɵpipe = i0.ɵɵngDeclarePipe({
140
+ minVersion: "14.0.0",
141
+ version: "22.2.0",
142
+ ngImport: i0,
143
+ type: ParsedDatePipe,
144
+ isStandalone: true,
145
+ name: "parsedDate"
146
+ });
147
+ };
148
+ i0.ɵɵngDeclareClassMetadata({
149
+ minVersion: "12.0.0",
150
+ version: "22.2.0",
151
+ ngImport: i0,
152
+ type: ParsedDatePipe,
153
+ decorators: [{
154
+ type: Pipe,
155
+ args: [{
156
+ name: "parsedDate",
157
+ standalone: true,
158
+ pure: true
159
+ }]
160
+ }]
161
+ });
105
162
  function applyFieldTemplate(template, data) {
106
- return template.replace(/\{(\w+)\}/g, (_match, propertyName) => {
107
- const value = data[propertyName];
108
- return value != null ? String(value) : '';
109
- });
110
- }
111
-
112
- class AttributeValuePipe {
113
- transform(attrName, item, entityType, lookupRefOptions, allEntityTypes) {
114
- if (!item)
115
- return '';
116
- const attr = item.attributes.find(a => a.name === attrName);
117
- if (!attr)
118
- return '';
119
- if (attr.breadcrumb)
120
- return attr.breadcrumb;
121
- const attrDef = entityType?.attributes.find(a => a.name === attrName);
122
- if (attrDef?.dataType === 'AsDetail') {
123
- // Server emits nested PO(s) in attr.objects (array) / attr.object (single) — attr.value is null.
124
- if (attr.isArray) {
125
- const count = attr.objects?.length ?? 0;
126
- if (count === 0)
127
- return '';
128
- return `${count} item${count !== 1 ? 's' : ''}`;
129
- }
130
- if (attr.object) {
131
- // The server has already resolved this object's breadcrumb, and it can resolve templates
132
- // this side cannot. A type's breadcrumb may name a computed property that `[IgnoreProperty]`
133
- // keeps out of the model — HR's `Address.Crumb` is exactly that, `[Breadcrumb, IgnoreProperty]`
134
- // — so the template `{Crumb}` has no matching attribute here and never will. Recomputing it
135
- // client-side produced an empty string and fell through to "(object)" while the correct
136
- // "Voorbeeldstraat 1, 1000 Brussel" sat unread on `attr.object.breadcrumb`.
137
- //
138
- // One value on that property is NOT a breadcrumb: when the template renders blank the
139
- // server substitutes the CLR type name, and printing it reads as data — a `Build` whose
140
- // `Feedback.State` was unset showed the literal "BuildFeedback" (#384). Filtering it here
141
- // lets the fallbacks below run, which is what they are for.
142
- const resolved = resolvedBreadcrumb(attr.object.breadcrumb, attrDef.asDetailType);
143
- if (resolved)
144
- return resolved;
145
- return this.formatAsDetailValue(attrDef, nestedPoToDict(attr.object), allEntityTypes);
146
- }
147
- }
148
- if (attrDef?.lookupReferenceType && attr.value != null && attr.value !== '') {
149
- const lookupRef = lookupRefOptions[attrDef.lookupReferenceType];
150
- if (lookupRef) {
151
- const option = lookupRef.values.find(v => v.key === String(attr.value));
152
- if (option) {
153
- return resolveTranslation(option.values) || option.key;
154
- }
155
- }
156
- }
157
- if (attrDef?.dataType === 'boolean') {
158
- return attr.value ?? null;
159
- }
160
- return attr.value ?? '';
161
- }
162
- formatAsDetailValue(attrDef, value, allEntityTypes) {
163
- const asDetailType = allEntityTypes.find(t => t.clrType === attrDef.asDetailType);
164
- if (asDetailType?.breadcrumb) {
165
- const result = applyFieldTemplate(asDetailType.breadcrumb, value);
166
- if (result && result.trim())
167
- return result;
168
- }
169
- // Last resort, reached when the type declares no breadcrumb or its template resolved to
170
- // nothing. Joining the scalar values is always more use to a reader than "(object)", which
171
- // named the failure rather than the row and looked identical for every unresolvable cell.
172
- // Reserved keys are skipped: `nestedPoToDict` stashes the row key and the row's own breadcrumb
173
- // in this same dict, and joining those prints a guid and a placeholder as though they were
174
- // fields. Previously masked -- this branch was only reachable when the server sent no
175
- // breadcrumb, which is exactly when there was nothing stashed to leak.
176
- return Object.entries(value)
177
- .filter(([k, v]) => !isReservedAsDetailKey(k) && v != null && typeof v !== 'object' && String(v).trim() !== '')
178
- .map(([, v]) => v)
179
- .join(', ');
180
- }
181
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AttributeValuePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
182
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: AttributeValuePipe, isStandalone: true, name: "attributeValue" });
183
- }
184
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AttributeValuePipe, decorators: [{
185
- type: Pipe,
186
- args: [{ name: 'attributeValue', standalone: true, pure: true }]
187
- }] });
188
-
189
- class RawAttributeValuePipe {
190
- transform(attrName, item) {
191
- return item?.attributes.find(a => a.name === attrName)?.value;
192
- }
193
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: RawAttributeValuePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
194
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: RawAttributeValuePipe, isStandalone: true, name: "rawAttributeValue" });
195
- }
196
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: RawAttributeValuePipe, decorators: [{
197
- type: Pipe,
198
- args: [{ name: 'rawAttributeValue', standalone: true, pure: true }]
199
- }] });
200
-
201
- class ReferenceDisplayValuePipe {
202
- lang = inject(SparkLanguageService);
203
- transform(attr, formData, referenceOptions) {
204
- const selectedId = formData[attr.name];
205
- if (!selectedId)
206
- return this.lang.t('notSelected');
207
- const options = referenceOptions[attr.name] || [];
208
- const selected = options.find(o => o.id === selectedId);
209
- // The server resolves a row's display string into `breadcrumb`; falling back to the id
210
- // beats showing nothing, and there is no third source now that a row carries no `name`.
211
- return selected?.breadcrumb || selectedId;
212
- }
213
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ReferenceDisplayValuePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
214
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: ReferenceDisplayValuePipe, isStandalone: true, name: "referenceDisplayValue" });
215
- }
216
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ReferenceDisplayValuePipe, decorators: [{
217
- type: Pipe,
218
- args: [{ name: 'referenceDisplayValue', standalone: true, pure: true }]
219
- }] });
220
-
221
- /**
222
- * The text a reference picker's result grid shows in one column.
223
- *
224
- * ⚠️ **Reads the row through {@link valueFor}, not through a shape it assumes.** This used to do
225
- * `item.attributes.find(...)`, which is the `PersistentObject` shape — but a picker's rows are
226
- * `QueryResultItem`s, which carry `values` (`[{ key, value, breadcrumb }]`) and have no `attributes`
227
- * at all. Every cell therefore threw `can't access property "find", item.attributes is undefined`,
228
- * and the picker rendered nothing selectable.
229
- *
230
- * There are three row shapes in this codebase and `valueFor` exists precisely so a consumer does not
231
- * have to know which one it was handed. Using it is also what keeps this working if a picker is ever
232
- * pointed at an AsDetail sub-table, whose rows are the flat record shape.
233
- */
234
- class ReferenceAttrValuePipe {
235
- transform(item, attrName) {
236
- const cell = valueFor(item, attrName);
237
- if (!cell)
238
- return '';
239
- // Breadcrumb first: a reference cell's value is an id, and the id is not what a person reads.
240
- if (cell.breadcrumb)
241
- return cell.breadcrumb;
242
- return cell.value ?? '';
243
- }
244
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ReferenceAttrValuePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
245
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: ReferenceAttrValuePipe, isStandalone: true, name: "referenceAttrValue" });
246
- }
247
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ReferenceAttrValuePipe, decorators: [{
248
- type: Pipe,
249
- args: [{ name: 'referenceAttrValue', standalone: true, pure: true }]
250
- }] });
251
-
252
- class ReferenceLinkRoutePipe {
253
- transform(referenceClrType, referenceId, allEntityTypes) {
254
- if (!referenceId || !referenceClrType)
255
- return null;
256
- const targetType = allEntityTypes.find(t => t.clrType === referenceClrType);
257
- if (!targetType)
258
- return null;
259
- // Presence in the catalogue means the caller may LIST this type; opening one is a different
260
- // right. Without this a type granted Query but not Read rendered a clickable reference whose
261
- // click refused on arrival — while the grid's own first column, three components away, gated on
262
- // canRead and got it right. Same question, two answers.
263
- if (targetType.canRead === false)
264
- return null;
265
- return ['/po', targetType.alias || targetType.id, referenceId];
266
- }
267
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ReferenceLinkRoutePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
268
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: ReferenceLinkRoutePipe, isStandalone: true, name: "referenceLinkRoute" });
269
- }
270
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ReferenceLinkRoutePipe, decorators: [{
271
- type: Pipe,
272
- args: [{ name: 'referenceLinkRoute', standalone: true, pure: true }]
273
- }] });
274
-
275
- /**
276
- * Resolves a multi-reference attribute (`dataType === 'Reference'`, `isArray === true`)
277
- * to a list of chips. The attribute's `value` carries the id array; `breadcrumbs` (a
278
- * server-resolved id → label map) provides each chip's display label, falling back to
279
- * the id when no breadcrumb is present. Mirrors the single-reference `breadcrumb`
280
- * display, applied per id.
281
- */
282
- class ReferenceChipsPipe {
283
- transform(attrName, item) {
284
- const attr = item?.attributes.find(a => a.name === attrName);
285
- if (!attr || !Array.isArray(attr.value))
286
- return [];
287
- const breadcrumbs = attr.breadcrumbs ?? {};
288
- return attr.value
289
- .filter(v => v != null && v !== '')
290
- .map(v => {
291
- const id = String(v);
292
- return { id, label: breadcrumbs[id] || id };
293
- });
294
- }
295
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ReferenceChipsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
296
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: ReferenceChipsPipe, isStandalone: true, name: "referenceChips" });
297
- }
298
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ReferenceChipsPipe, decorators: [{
299
- type: Pipe,
300
- args: [{ name: 'referenceChips', standalone: true, pure: true }]
301
- }] });
302
-
303
- /**
304
- * Maps a program unit to the router commands that open it. Type comparisons are exact: the
305
- * server's loader canonicalizes `type` casing, so tolerating variants here would only mask a
306
- * server that stopped doing so.
307
- *
308
- * Returns null for a `url` unit — an external address is an `<a href>`, not a router link; the
309
- * component rendering the menu owns that branch.
310
- */
311
- class RouterLinkPipe {
312
- transform(unit) {
313
- if (unit.type === 'query') {
314
- return ['/query', unit.alias || unit.queryId];
315
- }
316
- else if (unit.type === 'persistentObject') {
317
- const type = unit.alias || unit.persistentObjectId;
318
- return unit.objectId ? ['/po', type, unit.objectId] : ['/po', type];
319
- }
320
- else if (unit.type === 'url') {
321
- return null;
322
- }
323
- return ['/'];
324
- }
325
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: RouterLinkPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
326
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: RouterLinkPipe, isStandalone: true, name: "routerLink" });
327
- }
328
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: RouterLinkPipe, decorators: [{
329
- type: Pipe,
330
- args: [{ name: 'routerLink', standalone: true, pure: true }]
331
- }] });
332
-
333
- class AsDetailTypePipe {
334
- transform(attr, asDetailTypes) {
335
- return asDetailTypes[attr.name] || null;
336
- }
337
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AsDetailTypePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
338
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: AsDetailTypePipe, isStandalone: true, name: "asDetailType" });
339
- }
340
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AsDetailTypePipe, decorators: [{
341
- type: Pipe,
342
- args: [{ name: 'asDetailType', standalone: true, pure: true }]
343
- }] });
344
-
345
- class AsDetailColumnsPipe {
346
- transform(attr, asDetailTypes) {
347
- const type = asDetailTypes[attr.name];
348
- if (!type)
349
- return [];
350
- return type.attributes
351
- .filter(a => a.isVisible)
352
- .sort((a, b) => a.order - b.order);
353
- }
354
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AsDetailColumnsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
355
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: AsDetailColumnsPipe, isStandalone: true, name: "asDetailColumns" });
356
- }
357
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AsDetailColumnsPipe, decorators: [{
358
- type: Pipe,
359
- args: [{ name: 'asDetailColumns', standalone: true, pure: true }]
360
- }] });
361
-
362
- /**
363
- * The value of one cell in an `AsDetail` table, **typed by the column's `dataType`** rather than
364
- * flattened to a string.
365
- *
366
- * <p>
367
- * This used to end in `return String(value)` for everything, and declare `: string`. That is fine
368
- * for a cell which is only interpolated, and wrong for one whose consumer inspects it —
369
- * `spark-grid-cell` branches on the column type and binds `[checked]="display() === true"` and
370
- * `[indeterminate]="display() == null"` for a boolean, so it needs the value and not a rendering
371
- * of it.
372
- * </p>
373
- * <p>
374
- * The visible symptom was a detail page showing unticked checkboxes for rows whose edit form showed
375
- * them ticked — the edit form reads `attribute.objects` directly, so it never went through here. All
376
- * three states of a `bool?` were affected, and one of them silently:
377
- * </p>
378
- * <ul>
379
- * <li><b>true</b> — `'true' === true` is false, so it rendered <b>unchecked</b>;</li>
380
- * <li><b>null</b> — became `''`, and `'' == null` is false, so it rendered unchecked <b>and
381
- * determinate</b>, i.e. claiming to be false;</li>
382
- * <li><b>false</b> — `'false'` is not `=== true`, so it rendered correctly <b>by accident</b>.</li>
383
- * </ul>
384
- * <p>
385
- * Types that stay strings do so deliberately, not by omission. `color`, `image` and `url` are bound
386
- * into a style, an `src` and an `href`, so a string is what they need. `Reference` and `AsDetail`
387
- * resolve to a breadcrumb, which is a label rather than a value.
388
- * </p>
389
- * <p>
390
- * `date` and `datetime` return a real `Date`. They arrive as ISO strings, and the cell used to
391
- * print that string verbatim — `2026-09-07T13:25:57.3119825Z` in a table column. Returning the
392
- * parsed value lets `spark-grid-cell` format it in one place for both grids; an unparseable value
393
- * falls back to its text, because showing what is there beats showing `Invalid Date`.
394
- * </p>
395
- */
396
- class AsDetailCellValuePipe {
397
- transform(row, parentAttr, col, asDetailRefOptions) {
398
- const value = row[col.name];
399
- // Before the null short-circuit, because for these types "absent" is a value the consumer has
400
- // to be able to see: `null` is what makes a checkbox indeterminate rather than false, and it is
401
- // what distinguishes "no number" from the number zero. `''` erases both.
402
- switch (col.dataType) {
403
- case 'boolean':
404
- return typeof value === 'boolean' ? value : null;
405
- case 'number':
406
- case 'decimal': {
407
- if (value == null || value === '')
408
- return null;
409
- const asNumber = typeof value === 'number' ? value : Number(value);
410
- // A value that is not a number is passed through as text rather than reported as NaN: the
411
- // cell's job is to show what is there, and "NaN" tells the reader nothing about it.
412
- return Number.isNaN(asNumber) ? String(value) : asNumber;
413
- }
414
- case 'date':
415
- case 'datetime': {
416
- if (value == null || value === '')
417
- return null;
418
- if (value instanceof Date)
419
- return Number.isNaN(value.getTime()) ? null : value;
420
- const parsed = new Date(value);
421
- // Same rule as the number branch: an unparseable date shows its own text rather than
422
- // "Invalid Date", which would hide the value that is actually stored.
423
- return Number.isNaN(parsed.getTime()) ? String(value) : parsed;
424
- }
425
- }
426
- if (value == null)
427
- return '';
428
- if (col.dataType === 'Reference' && col.query) {
429
- // Prefer the breadcrumb the server already resolved by id — it is page-independent, so it
430
- // renders the label even when the referenced document falls outside the reference query's
431
- // first options page (issue #185).
432
- const serverBreadcrumb = row[AS_DETAIL_BREADCRUMBS_KEY]?.[col.name];
433
- if (serverBreadcrumb)
434
- return serverBreadcrumb;
435
- // Fallback: resolve against the loaded options page (legacy path).
436
- const parentOptions = asDetailRefOptions[parentAttr.name];
437
- if (parentOptions) {
438
- const options = parentOptions[col.name];
439
- if (options) {
440
- const match = options.find(o => o.id === value);
441
- if (match)
442
- return match.breadcrumb || String(value);
443
- }
444
- }
445
- }
446
- // A nested-AsDetail column's value is an inner dict, so String(value) produced "[object
447
- // Object]". The flattener kept that object's server-resolved breadcrumb for exactly this.
448
- if (col.dataType === 'AsDetail' && typeof value === 'object') {
449
- return selfBreadcrumb(value, col.asDetailType) ?? '';
450
- }
451
- return String(value);
452
- }
453
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AsDetailCellValuePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
454
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: AsDetailCellValuePipe, isStandalone: true, name: "asDetailCellValue" });
163
+ return template.replace(/\{(\w+)\}/g, (_match, propertyName) => {
164
+ const value = data[propertyName];
165
+ return value != null ? String(value) : "";
166
+ });
455
167
  }
456
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AsDetailCellValuePipe, decorators: [{
457
- type: Pipe,
458
- args: [{ name: 'asDetailCellValue', standalone: true, pure: true }]
459
- }] });
460
-
461
- class AsDetailDisplayValuePipe {
462
- lang = inject(SparkLanguageService);
463
- transform(attr, formData, asDetailTypes) {
464
- const value = formData[attr.name];
465
- if (!value)
466
- return this.lang.t('notSet');
467
- const asDetailType = asDetailTypes[attr.name] || null;
468
- // The server's own resolution wins, because it can render templates this side cannot: a
469
- // breadcrumb may name a property that `[IgnoreProperty]` deliberately keeps out of the model
470
- // (HR's `Address.Crumb`), and no amount of client-side substitution will ever find it. Passing
471
- // the type name filters out the mapper's "template rendered blank" placeholder, which is the
472
- // bare type name rather than an empty string — see `selfBreadcrumb`.
473
- const resolved = selfBreadcrumb(value, asDetailType?.name);
474
- if (resolved)
475
- return resolved;
476
- // Still correct for a template naming real, projected attributes (`"{Street}, {City}"`), which
477
- // is the common case and the only one reachable on the create path, where there is no server
478
- // object to have resolved anything yet.
479
- if (asDetailType?.breadcrumb) {
480
- const result = applyFieldTemplate(asDetailType.breadcrumb, value);
481
- if (result && result.trim())
482
- return result;
483
- }
484
- return this.lang.t('clickToEdit');
485
- }
486
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AsDetailDisplayValuePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
487
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: AsDetailDisplayValuePipe, isStandalone: true, name: "asDetailDisplayValue" });
488
- }
489
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AsDetailDisplayValuePipe, decorators: [{
490
- type: Pipe,
491
- args: [{ name: 'asDetailDisplayValue', standalone: true, pure: true }]
492
- }] });
493
-
494
- class CanCreateDetailRowPipe {
495
- transform(attr, permissions) {
496
- const perms = permissions[attr.name];
497
- // Fail closed. An absent entry means the child type's permissions were never fetched, not that
498
- // the user may do this -- and since the save path now enforces `New/{RowType}`, defaulting
499
- // to true renders a button whose save is refused. The fetch is also not guaranteed: it used to
500
- // go through the entity-type catalogue, which is Query-gated, so a user with `New` but not
501
- // `Query` never got an entry at all.
502
- return perms ? perms.canCreate : false;
503
- }
504
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: CanCreateDetailRowPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
505
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: CanCreateDetailRowPipe, isStandalone: true, name: "canCreateDetailRow" });
506
- }
507
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: CanCreateDetailRowPipe, decorators: [{
508
- type: Pipe,
509
- args: [{ name: 'canCreateDetailRow', standalone: true, pure: true }]
510
- }] });
511
-
512
- class CanDeleteDetailRowPipe {
513
- transform(attr, permissions) {
514
- const perms = permissions[attr.name];
515
- // Fail closed. An absent entry means the child type's permissions were never fetched, not that
516
- // the user may do this -- and since the save path now enforces `Delete/{RowType}`, defaulting
517
- // to true renders a button whose save is refused. The fetch is also not guaranteed: it used to
518
- // go through the entity-type catalogue, which is Query-gated, so a user with `Delete` but not
519
- // `Query` never got an entry at all.
520
- return perms ? perms.canDelete : false;
521
- }
522
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: CanDeleteDetailRowPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
523
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: CanDeleteDetailRowPipe, isStandalone: true, name: "canDeleteDetailRow" });
524
- }
525
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: CanDeleteDetailRowPipe, decorators: [{
526
- type: Pipe,
527
- args: [{ name: 'canDeleteDetailRow', standalone: true, pure: true }]
528
- }] });
529
-
530
- /**
531
- * Whether the caller may edit rows of an AsDetail attribute's row type.
532
- *
533
- * The third of the `can*DetailRow` family, and the one the server was already answering. `canEdit`
534
- * has been computed, shipped and fetched per AsDetail attribute since row rights landed — it was
535
- * simply never read for the row path, so the form offered an edit the save would undo.
536
- *
537
- * ⚠️ Apply this **read-only, never hidden**. A row the caller may not edit must stay fully
538
- * readable; hiding the inputs would hide the data, which is a worse answer than showing it
539
- * uneditable.
540
- */
541
- class CanEditDetailRowPipe {
542
- transform(attr, permissions) {
543
- const perms = permissions[attr.name];
544
- // Fail closed, for the same reason as its two siblings: an absent entry means the row type's
545
- // permissions were never fetched, not that the user may edit. And the save path enforces
546
- // `Edit/{RowType}` independently -- it silently restores the stored row and warns -- so
547
- // defaulting to true offers an edit whose result is discarded.
548
- return perms ? perms.canEdit : false;
549
- }
550
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: CanEditDetailRowPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
551
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: CanEditDetailRowPipe, isStandalone: true, name: "canEditDetailRow" });
552
- }
553
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: CanEditDetailRowPipe, decorators: [{
554
- type: Pipe,
555
- args: [{ name: 'canEditDetailRow', standalone: true, pure: true }]
556
- }] });
557
-
558
- class LookupDisplayTypePipe {
559
- transform(attr, lookupRefOptions) {
560
- const lookupRef = attr.lookupReferenceType ? lookupRefOptions[attr.lookupReferenceType] : null;
561
- return lookupRef?.displayType ?? ELookupDisplayType.Dropdown;
562
- }
563
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: LookupDisplayTypePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
564
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: LookupDisplayTypePipe, isStandalone: true, name: "lookupDisplayType" });
565
- }
566
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: LookupDisplayTypePipe, decorators: [{
567
- type: Pipe,
568
- args: [{ name: 'lookupDisplayType', standalone: true, pure: true }]
569
- }] });
570
-
571
- class LookupDisplayValuePipe {
572
- transform(attr, formData, lookupRefOptions) {
573
- const currentValue = formData[attr.name];
574
- if (currentValue == null || currentValue === '')
575
- return '';
576
- const lookupRef = attr.lookupReferenceType ? lookupRefOptions[attr.lookupReferenceType] : null;
577
- const options = lookupRef?.values.filter(v => v.isActive) || [];
578
- const selected = options.find(o => o.key === String(currentValue));
579
- if (!selected)
580
- return String(currentValue);
581
- return resolveTranslation(selected.values) || selected.key;
582
- }
583
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: LookupDisplayValuePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
584
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: LookupDisplayValuePipe, isStandalone: true, name: "lookupDisplayValue" });
585
- }
586
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: LookupDisplayValuePipe, decorators: [{
587
- type: Pipe,
588
- args: [{ name: 'lookupDisplayValue', standalone: true, pure: true }]
589
- }] });
590
-
591
- class LookupOptionsPipe {
592
- transform(attr, lookupRefOptions) {
593
- const lookupRef = attr.lookupReferenceType ? lookupRefOptions[attr.lookupReferenceType] : null;
594
- return lookupRef?.values.filter(v => v.isActive) || [];
595
- }
596
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: LookupOptionsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
597
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: LookupOptionsPipe, isStandalone: true, name: "lookupOptions" });
598
- }
599
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: LookupOptionsPipe, decorators: [{
600
- type: Pipe,
601
- args: [{ name: 'lookupOptions', standalone: true, pure: true }]
602
- }] });
603
-
604
- class InlineRefOptionsPipe {
605
- transform(parentAttr, col, asDetailRefOptions) {
606
- return asDetailRefOptions[parentAttr.name]?.[col.name] || [];
607
- }
608
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: InlineRefOptionsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
609
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: InlineRefOptionsPipe, isStandalone: true, name: "inlineRefOptions" });
610
- }
611
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: InlineRefOptionsPipe, decorators: [{
612
- type: Pipe,
613
- args: [{ name: 'inlineRefOptions', standalone: true, pure: true }]
614
- }] });
615
-
616
- class ErrorForAttributePipe {
617
- transform(attrName, validationErrors) {
618
- const error = validationErrors.find(e => e.attributeName === attrName);
619
- return error ? resolveTranslation(error.errorMessage) : null;
620
- }
621
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ErrorForAttributePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
622
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: ErrorForAttributePipe, isStandalone: true, name: "errorForAttribute" });
623
- }
624
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ErrorForAttributePipe, decorators: [{
625
- type: Pipe,
626
- args: [{ name: 'errorForAttribute', standalone: true, pure: true }]
627
- }] });
628
-
629
- class IconNamePipe {
630
- transform(value, fallback) {
631
- const iconClass = value || fallback;
632
- // Strip 'bi-' prefix if present
633
- return iconClass.startsWith('bi-') ? iconClass.substring(3) : iconClass;
634
- }
635
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: IconNamePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
636
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: IconNamePipe, isStandalone: true, name: "iconName" });
637
- }
638
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: IconNamePipe, decorators: [{
639
- type: Pipe,
640
- args: [{ name: 'iconName', standalone: true, pure: true }]
641
- }] });
642
-
643
- /**
644
- * Resolves an attribute to a list of flat row dicts for the detail-page table.
645
- * AsDetail array attributes carry their data as nested PersistentObjects in
646
- * <c>attr.objects</c>, not <c>attr.value</c> — the server stopped putting flat
647
- * dicts in <c>value</c> when AsDetail moved to its dedicated wire shape. Without
648
- * this branch, the detail page rendered AsDetail arrays as empty tables even
649
- * when the edit page (which reads <c>attr.objects</c> directly) showed rows.
650
- */
651
- class ArrayValuePipe {
652
- transform(attrName, item) {
653
- const attr = item?.attributes.find(a => a.name === attrName);
654
- if (!attr)
655
- return [];
656
- if (attr.dataType === 'AsDetail' && attr.isArray && Array.isArray(attr.objects)) {
657
- return attr.objects.map(po => nestedPoToDisplayRow(po));
658
- }
659
- if (Array.isArray(attr.value))
660
- return attr.value;
661
- return [];
662
- }
663
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ArrayValuePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
664
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: ArrayValuePipe, isStandalone: true, name: "arrayValue" });
665
- }
666
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ArrayValuePipe, decorators: [{
667
- type: Pipe,
668
- args: [{ name: 'arrayValue', standalone: true, pure: true }]
669
- }] });
670
-
671
- /**
672
- * The display text of one query-grid cell.
673
- *
674
- * The attribute-shaped sibling of this ({@link AttributeValuePipe}) still serves detail and edit
675
- * pages, which do work in attributes. They are deliberately not one pipe: a query row is a flat
676
- * projection with no nested objects and no per-row metadata, so the fallbacks that make sense
677
- * there — reaching into `attr.object`, recomputing a breadcrumb template client-side — are not
678
- * merely unnecessary here, they are unreachable. Sharing the code would mean carrying branches
679
- * that can never fire and inviting the next reader to feed one shape into the other.
680
- */
681
- class QueryCellValuePipe {
682
- transform(column, item, lookupRefOptions) {
683
- const cell = valueFor(item, column.name);
684
- if (!cell)
685
- return '';
686
- // A resolved reference display wins: the server can resolve breadcrumb templates this side
687
- // cannot (a template may name a computed property `[IgnoreProperty]` keeps out of the model).
688
- // Except the CLR type name, which is the server's placeholder for a template that rendered
689
- // blank, not a label (#384). `asDetailType` is undefined on every other kind of column, so
690
- // nothing else is filtered.
691
- const resolved = resolvedBreadcrumb(cell.breadcrumb, column.asDetailType);
692
- if (resolved)
693
- return resolved;
694
- if (column.dataType === 'AsDetail') {
695
- // An array cell carries a child COUNT rather than the children, so the wording — and its
696
- // pluralisation — is decided here, where the language is. A single-child cell carries the
697
- // child object (for a renderer to read) and is displayed by the server-resolved breadcrumb
698
- // above, never by stringifying it here.
699
- if (!column.isArray)
700
- return '';
701
- const count = typeof cell.value === 'number' ? cell.value : 0;
702
- return count === 0 ? '' : `${count} item${count !== 1 ? 's' : ''}`;
703
- }
704
- if (column.lookupReferenceType && cell.value != null && cell.value !== '') {
705
- const lookupRef = lookupRefOptions[column.lookupReferenceType];
706
- const option = lookupRef?.values.find(v => v.key === String(cell.value));
707
- if (option)
708
- return resolveTranslation(option.values) || option.key;
709
- }
710
- // Null rather than '' so the cell can tell "false" from "unset" and render an indeterminate
711
- // checkbox instead of an unchecked one.
712
- if (column.dataType === 'boolean')
713
- return cell.value ?? null;
714
- // Dates are parsed here for the same reason booleans are passed through above: the cell needs
715
- // the value, not a rendering of it. Both grids feed `spark-grid-cell`, so both have to agree on
716
- // the type or the same `datetime` column formats one way in a query grid and another in an
717
- // AsDetail table. Unparseable input keeps its own text rather than becoming "Invalid Date".
718
- if (column.dataType === 'date' || column.dataType === 'datetime') {
719
- if (cell.value == null || cell.value === '')
720
- return null;
721
- if (cell.value instanceof Date)
722
- return Number.isNaN(cell.value.getTime()) ? null : cell.value;
723
- const parsed = new Date(cell.value);
724
- return Number.isNaN(parsed.getTime()) ? String(cell.value) : parsed;
725
- }
726
- return cell.value ?? '';
727
- }
728
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: QueryCellValuePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
729
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: QueryCellValuePipe, isStandalone: true, name: "queryCellValue" });
730
- }
731
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: QueryCellValuePipe, decorators: [{
732
- type: Pipe,
733
- args: [{ name: 'queryCellValue', standalone: true, pure: true }]
734
- }] });
735
- /**
736
- * Resolves a multi-reference column (`dataType === 'Reference'`, `isArray === true`) to chips.
737
- *
738
- * The cell's `value` carries the id array and `breadcrumbs` the server-resolved id → label map,
739
- * falling back to the id itself when a label is missing — the same display rule as a single
740
- * reference, applied per id.
741
- */
742
- class QueryReferenceChipsPipe {
743
- transform(column, item) {
744
- const cell = valueFor(item, column.name);
745
- if (!cell || !Array.isArray(cell.value))
746
- return [];
747
- const breadcrumbs = cell.breadcrumbs ?? {};
748
- return cell.value
749
- .filter(v => v != null && v !== '')
750
- .map(v => {
751
- const id = String(v);
752
- return { id, label: breadcrumbs[id] || id };
753
- });
754
- }
755
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: QueryReferenceChipsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
756
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: QueryReferenceChipsPipe, isStandalone: true, name: "queryReferenceChips" });
757
- }
758
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: QueryReferenceChipsPipe, decorators: [{
759
- type: Pipe,
760
- args: [{ name: 'queryReferenceChips', standalone: true, pure: true }]
761
- }] });
762
-
763
- /**
764
- * Generated bundle index. Do not edit.
765
- */
766
-
168
+ var AttributeValuePipe = class AttributeValuePipe {
169
+ transform(attrName, item, entityType, lookupRefOptions, allEntityTypes) {
170
+ if (!item) return "";
171
+ const attr = item.attributes.find((a) => a.name === attrName);
172
+ if (!attr) return "";
173
+ if (attr.breadcrumb) return attr.breadcrumb;
174
+ const attrDef = entityType?.attributes.find((a) => a.name === attrName);
175
+ if (attrDef?.dataType === "AsDetail") {
176
+ if (attr.isArray) {
177
+ const count = attr.objects?.length ?? 0;
178
+ if (count === 0) return "";
179
+ return `${count} item${count !== 1 ? "s" : ""}`;
180
+ }
181
+ if (attr.object) {
182
+ const resolved = resolvedBreadcrumb(attr.object.breadcrumb, attrDef.asDetailType);
183
+ if (resolved) return resolved;
184
+ return this.formatAsDetailValue(attrDef, nestedPoToDict(attr.object), allEntityTypes);
185
+ }
186
+ }
187
+ if (attrDef?.lookupReferenceType && attr.value != null && attr.value !== "") {
188
+ const lookupRef = lookupRefOptions[attrDef.lookupReferenceType];
189
+ if (lookupRef) {
190
+ const option = lookupRef.values.find((v) => v.key === String(attr.value));
191
+ if (option) return resolveTranslation(option.values) || option.key;
192
+ }
193
+ }
194
+ if (attrDef?.dataType === "boolean") return attr.value ?? null;
195
+ return attr.value ?? "";
196
+ }
197
+ formatAsDetailValue(attrDef, value, allEntityTypes) {
198
+ const asDetailType = allEntityTypes.find((t) => t.clrType === attrDef.asDetailType);
199
+ if (asDetailType?.breadcrumb) {
200
+ const result = applyFieldTemplate(asDetailType.breadcrumb, value);
201
+ if (result && result.trim()) return result;
202
+ }
203
+ return Object.entries(value).filter(([k, v]) => !isReservedAsDetailKey(k) && v != null && typeof v !== "object" && String(v).trim() !== "").map(([, v]) => v).join(", ");
204
+ }
205
+ static ɵfac = i0.ɵɵngDeclareFactory({
206
+ minVersion: "12.0.0",
207
+ version: "22.2.0",
208
+ ngImport: i0,
209
+ type: AttributeValuePipe,
210
+ deps: [],
211
+ target: i0.ɵɵFactoryTarget.Pipe
212
+ });
213
+ static ɵpipe = i0.ɵɵngDeclarePipe({
214
+ minVersion: "14.0.0",
215
+ version: "22.2.0",
216
+ ngImport: i0,
217
+ type: AttributeValuePipe,
218
+ isStandalone: true,
219
+ name: "attributeValue"
220
+ });
221
+ };
222
+ i0.ɵɵngDeclareClassMetadata({
223
+ minVersion: "12.0.0",
224
+ version: "22.2.0",
225
+ ngImport: i0,
226
+ type: AttributeValuePipe,
227
+ decorators: [{
228
+ type: Pipe,
229
+ args: [{
230
+ name: "attributeValue",
231
+ standalone: true,
232
+ pure: true
233
+ }]
234
+ }]
235
+ });
236
+ var RawAttributeValuePipe = class RawAttributeValuePipe {
237
+ transform(attrName, item) {
238
+ return item?.attributes.find((a) => a.name === attrName)?.value;
239
+ }
240
+ static ɵfac = i0.ɵɵngDeclareFactory({
241
+ minVersion: "12.0.0",
242
+ version: "22.2.0",
243
+ ngImport: i0,
244
+ type: RawAttributeValuePipe,
245
+ deps: [],
246
+ target: i0.ɵɵFactoryTarget.Pipe
247
+ });
248
+ static ɵpipe = i0.ɵɵngDeclarePipe({
249
+ minVersion: "14.0.0",
250
+ version: "22.2.0",
251
+ ngImport: i0,
252
+ type: RawAttributeValuePipe,
253
+ isStandalone: true,
254
+ name: "rawAttributeValue"
255
+ });
256
+ };
257
+ i0.ɵɵngDeclareClassMetadata({
258
+ minVersion: "12.0.0",
259
+ version: "22.2.0",
260
+ ngImport: i0,
261
+ type: RawAttributeValuePipe,
262
+ decorators: [{
263
+ type: Pipe,
264
+ args: [{
265
+ name: "rawAttributeValue",
266
+ standalone: true,
267
+ pure: true
268
+ }]
269
+ }]
270
+ });
271
+ var ReferenceDisplayValuePipe = class ReferenceDisplayValuePipe {
272
+ lang = inject(SparkLanguageService);
273
+ transform(attr, formData, referenceOptions) {
274
+ const selectedId = formData[attr.name];
275
+ if (!selectedId) return this.lang.t("common.notSelected");
276
+ return (referenceOptions[attr.name] || []).find((o) => o.id === selectedId)?.breadcrumb || selectedId;
277
+ }
278
+ static ɵfac = i0.ɵɵngDeclareFactory({
279
+ minVersion: "12.0.0",
280
+ version: "22.2.0",
281
+ ngImport: i0,
282
+ type: ReferenceDisplayValuePipe,
283
+ deps: [],
284
+ target: i0.ɵɵFactoryTarget.Pipe
285
+ });
286
+ static ɵpipe = i0.ɵɵngDeclarePipe({
287
+ minVersion: "14.0.0",
288
+ version: "22.2.0",
289
+ ngImport: i0,
290
+ type: ReferenceDisplayValuePipe,
291
+ isStandalone: true,
292
+ name: "referenceDisplayValue"
293
+ });
294
+ };
295
+ i0.ɵɵngDeclareClassMetadata({
296
+ minVersion: "12.0.0",
297
+ version: "22.2.0",
298
+ ngImport: i0,
299
+ type: ReferenceDisplayValuePipe,
300
+ decorators: [{
301
+ type: Pipe,
302
+ args: [{
303
+ name: "referenceDisplayValue",
304
+ standalone: true,
305
+ pure: true
306
+ }]
307
+ }]
308
+ });
309
+ var ReferenceAttrValuePipe = class ReferenceAttrValuePipe {
310
+ transform(item, attrName) {
311
+ const cell = valueFor(item, attrName);
312
+ if (!cell) return "";
313
+ if (cell.breadcrumb) return cell.breadcrumb;
314
+ return cell.value ?? "";
315
+ }
316
+ static ɵfac = i0.ɵɵngDeclareFactory({
317
+ minVersion: "12.0.0",
318
+ version: "22.2.0",
319
+ ngImport: i0,
320
+ type: ReferenceAttrValuePipe,
321
+ deps: [],
322
+ target: i0.ɵɵFactoryTarget.Pipe
323
+ });
324
+ static ɵpipe = i0.ɵɵngDeclarePipe({
325
+ minVersion: "14.0.0",
326
+ version: "22.2.0",
327
+ ngImport: i0,
328
+ type: ReferenceAttrValuePipe,
329
+ isStandalone: true,
330
+ name: "referenceAttrValue"
331
+ });
332
+ };
333
+ i0.ɵɵngDeclareClassMetadata({
334
+ minVersion: "12.0.0",
335
+ version: "22.2.0",
336
+ ngImport: i0,
337
+ type: ReferenceAttrValuePipe,
338
+ decorators: [{
339
+ type: Pipe,
340
+ args: [{
341
+ name: "referenceAttrValue",
342
+ standalone: true,
343
+ pure: true
344
+ }]
345
+ }]
346
+ });
347
+ var ReferenceLinkRoutePipe = class ReferenceLinkRoutePipe {
348
+ transform(referenceClrType, referenceId, allEntityTypes) {
349
+ if (!referenceId || !referenceClrType) return null;
350
+ const targetType = allEntityTypes.find((t) => t.clrType === referenceClrType);
351
+ if (!targetType) return null;
352
+ if (targetType.canRead === false) return null;
353
+ return [
354
+ "/po",
355
+ targetType.alias || targetType.id,
356
+ referenceId
357
+ ];
358
+ }
359
+ static ɵfac = i0.ɵɵngDeclareFactory({
360
+ minVersion: "12.0.0",
361
+ version: "22.2.0",
362
+ ngImport: i0,
363
+ type: ReferenceLinkRoutePipe,
364
+ deps: [],
365
+ target: i0.ɵɵFactoryTarget.Pipe
366
+ });
367
+ static ɵpipe = i0.ɵɵngDeclarePipe({
368
+ minVersion: "14.0.0",
369
+ version: "22.2.0",
370
+ ngImport: i0,
371
+ type: ReferenceLinkRoutePipe,
372
+ isStandalone: true,
373
+ name: "referenceLinkRoute"
374
+ });
375
+ };
376
+ i0.ɵɵngDeclareClassMetadata({
377
+ minVersion: "12.0.0",
378
+ version: "22.2.0",
379
+ ngImport: i0,
380
+ type: ReferenceLinkRoutePipe,
381
+ decorators: [{
382
+ type: Pipe,
383
+ args: [{
384
+ name: "referenceLinkRoute",
385
+ standalone: true,
386
+ pure: true
387
+ }]
388
+ }]
389
+ });
390
+ var ReferenceChipsPipe = class ReferenceChipsPipe {
391
+ transform(attrName, item) {
392
+ const attr = item?.attributes.find((a) => a.name === attrName);
393
+ if (!attr || !Array.isArray(attr.value)) return [];
394
+ const breadcrumbs = attr.breadcrumbs ?? {};
395
+ return attr.value.filter((v) => v != null && v !== "").map((v) => {
396
+ const id = String(v);
397
+ return {
398
+ id,
399
+ label: breadcrumbs[id] || id
400
+ };
401
+ });
402
+ }
403
+ static ɵfac = i0.ɵɵngDeclareFactory({
404
+ minVersion: "12.0.0",
405
+ version: "22.2.0",
406
+ ngImport: i0,
407
+ type: ReferenceChipsPipe,
408
+ deps: [],
409
+ target: i0.ɵɵFactoryTarget.Pipe
410
+ });
411
+ static ɵpipe = i0.ɵɵngDeclarePipe({
412
+ minVersion: "14.0.0",
413
+ version: "22.2.0",
414
+ ngImport: i0,
415
+ type: ReferenceChipsPipe,
416
+ isStandalone: true,
417
+ name: "referenceChips"
418
+ });
419
+ };
420
+ i0.ɵɵngDeclareClassMetadata({
421
+ minVersion: "12.0.0",
422
+ version: "22.2.0",
423
+ ngImport: i0,
424
+ type: ReferenceChipsPipe,
425
+ decorators: [{
426
+ type: Pipe,
427
+ args: [{
428
+ name: "referenceChips",
429
+ standalone: true,
430
+ pure: true
431
+ }]
432
+ }]
433
+ });
434
+ var RouterLinkPipe = class RouterLinkPipe {
435
+ transform(unit) {
436
+ if (unit.type === "query") return ["/query", unit.alias || unit.queryId];
437
+ else if (unit.type === "persistentObject") {
438
+ const type = unit.alias || unit.persistentObjectId;
439
+ return unit.objectId ? [
440
+ "/po",
441
+ type,
442
+ unit.objectId
443
+ ] : ["/po", type];
444
+ } else if (unit.type === "url") return null;
445
+ return ["/"];
446
+ }
447
+ static ɵfac = i0.ɵɵngDeclareFactory({
448
+ minVersion: "12.0.0",
449
+ version: "22.2.0",
450
+ ngImport: i0,
451
+ type: RouterLinkPipe,
452
+ deps: [],
453
+ target: i0.ɵɵFactoryTarget.Pipe
454
+ });
455
+ static ɵpipe = i0.ɵɵngDeclarePipe({
456
+ minVersion: "14.0.0",
457
+ version: "22.2.0",
458
+ ngImport: i0,
459
+ type: RouterLinkPipe,
460
+ isStandalone: true,
461
+ name: "routerLink"
462
+ });
463
+ };
464
+ i0.ɵɵngDeclareClassMetadata({
465
+ minVersion: "12.0.0",
466
+ version: "22.2.0",
467
+ ngImport: i0,
468
+ type: RouterLinkPipe,
469
+ decorators: [{
470
+ type: Pipe,
471
+ args: [{
472
+ name: "routerLink",
473
+ standalone: true,
474
+ pure: true
475
+ }]
476
+ }]
477
+ });
478
+ var AsDetailTypePipe = class AsDetailTypePipe {
479
+ transform(attr, asDetailTypes) {
480
+ return asDetailTypes[attr.name] || null;
481
+ }
482
+ static ɵfac = i0.ɵɵngDeclareFactory({
483
+ minVersion: "12.0.0",
484
+ version: "22.2.0",
485
+ ngImport: i0,
486
+ type: AsDetailTypePipe,
487
+ deps: [],
488
+ target: i0.ɵɵFactoryTarget.Pipe
489
+ });
490
+ static ɵpipe = i0.ɵɵngDeclarePipe({
491
+ minVersion: "14.0.0",
492
+ version: "22.2.0",
493
+ ngImport: i0,
494
+ type: AsDetailTypePipe,
495
+ isStandalone: true,
496
+ name: "asDetailType"
497
+ });
498
+ };
499
+ i0.ɵɵngDeclareClassMetadata({
500
+ minVersion: "12.0.0",
501
+ version: "22.2.0",
502
+ ngImport: i0,
503
+ type: AsDetailTypePipe,
504
+ decorators: [{
505
+ type: Pipe,
506
+ args: [{
507
+ name: "asDetailType",
508
+ standalone: true,
509
+ pure: true
510
+ }]
511
+ }]
512
+ });
513
+ var AsDetailColumnsPipe = class AsDetailColumnsPipe {
514
+ transform(attr, asDetailTypes) {
515
+ const type = asDetailTypes[attr.name];
516
+ if (!type) return [];
517
+ return type.attributes.filter((a) => a.isVisible).sort((a, b) => a.order - b.order);
518
+ }
519
+ static ɵfac = i0.ɵɵngDeclareFactory({
520
+ minVersion: "12.0.0",
521
+ version: "22.2.0",
522
+ ngImport: i0,
523
+ type: AsDetailColumnsPipe,
524
+ deps: [],
525
+ target: i0.ɵɵFactoryTarget.Pipe
526
+ });
527
+ static ɵpipe = i0.ɵɵngDeclarePipe({
528
+ minVersion: "14.0.0",
529
+ version: "22.2.0",
530
+ ngImport: i0,
531
+ type: AsDetailColumnsPipe,
532
+ isStandalone: true,
533
+ name: "asDetailColumns"
534
+ });
535
+ };
536
+ i0.ɵɵngDeclareClassMetadata({
537
+ minVersion: "12.0.0",
538
+ version: "22.2.0",
539
+ ngImport: i0,
540
+ type: AsDetailColumnsPipe,
541
+ decorators: [{
542
+ type: Pipe,
543
+ args: [{
544
+ name: "asDetailColumns",
545
+ standalone: true,
546
+ pure: true
547
+ }]
548
+ }]
549
+ });
550
+ var AsDetailCellValuePipe = class AsDetailCellValuePipe {
551
+ transform(row, parentAttr, col, asDetailRefOptions) {
552
+ const value = row[col.name];
553
+ switch (col.dataType) {
554
+ case "boolean": return typeof value === "boolean" ? value : null;
555
+ case "number":
556
+ case "decimal": {
557
+ if (value == null || value === "") return null;
558
+ const asNumber = typeof value === "number" ? value : Number(value);
559
+ return Number.isNaN(asNumber) ? String(value) : asNumber;
560
+ }
561
+ case "date":
562
+ case "datetime": {
563
+ if (value == null || value === "") return null;
564
+ if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value;
565
+ const parsed = new Date(value);
566
+ return Number.isNaN(parsed.getTime()) ? String(value) : parsed;
567
+ }
568
+ }
569
+ if (value == null) return "";
570
+ if (col.dataType === "Reference" && col.query) {
571
+ const serverBreadcrumb = row[AS_DETAIL_BREADCRUMBS_KEY]?.[col.name];
572
+ if (serverBreadcrumb) return serverBreadcrumb;
573
+ const parentOptions = asDetailRefOptions[parentAttr.name];
574
+ if (parentOptions) {
575
+ const options = parentOptions[col.name];
576
+ if (options) {
577
+ const match = options.find((o) => o.id === value);
578
+ if (match) return match.breadcrumb || String(value);
579
+ }
580
+ }
581
+ }
582
+ if (col.dataType === "AsDetail" && typeof value === "object") return selfBreadcrumb(value, col.asDetailType) ?? "";
583
+ return String(value);
584
+ }
585
+ static ɵfac = i0.ɵɵngDeclareFactory({
586
+ minVersion: "12.0.0",
587
+ version: "22.2.0",
588
+ ngImport: i0,
589
+ type: AsDetailCellValuePipe,
590
+ deps: [],
591
+ target: i0.ɵɵFactoryTarget.Pipe
592
+ });
593
+ static ɵpipe = i0.ɵɵngDeclarePipe({
594
+ minVersion: "14.0.0",
595
+ version: "22.2.0",
596
+ ngImport: i0,
597
+ type: AsDetailCellValuePipe,
598
+ isStandalone: true,
599
+ name: "asDetailCellValue"
600
+ });
601
+ };
602
+ i0.ɵɵngDeclareClassMetadata({
603
+ minVersion: "12.0.0",
604
+ version: "22.2.0",
605
+ ngImport: i0,
606
+ type: AsDetailCellValuePipe,
607
+ decorators: [{
608
+ type: Pipe,
609
+ args: [{
610
+ name: "asDetailCellValue",
611
+ standalone: true,
612
+ pure: true
613
+ }]
614
+ }]
615
+ });
616
+ var AsDetailDisplayValuePipe = class AsDetailDisplayValuePipe {
617
+ lang = inject(SparkLanguageService);
618
+ transform(attr, formData, asDetailTypes) {
619
+ const value = formData[attr.name];
620
+ if (!value) return this.lang.t("common.notSet");
621
+ const asDetailType = asDetailTypes[attr.name] || null;
622
+ const resolved = selfBreadcrumb(value, asDetailType?.name);
623
+ if (resolved) return resolved;
624
+ if (asDetailType?.breadcrumb) {
625
+ const result = applyFieldTemplate(asDetailType.breadcrumb, value);
626
+ if (result && result.trim()) return result;
627
+ }
628
+ return this.lang.t("common.clickToEdit");
629
+ }
630
+ static ɵfac = i0.ɵɵngDeclareFactory({
631
+ minVersion: "12.0.0",
632
+ version: "22.2.0",
633
+ ngImport: i0,
634
+ type: AsDetailDisplayValuePipe,
635
+ deps: [],
636
+ target: i0.ɵɵFactoryTarget.Pipe
637
+ });
638
+ static ɵpipe = i0.ɵɵngDeclarePipe({
639
+ minVersion: "14.0.0",
640
+ version: "22.2.0",
641
+ ngImport: i0,
642
+ type: AsDetailDisplayValuePipe,
643
+ isStandalone: true,
644
+ name: "asDetailDisplayValue"
645
+ });
646
+ };
647
+ i0.ɵɵngDeclareClassMetadata({
648
+ minVersion: "12.0.0",
649
+ version: "22.2.0",
650
+ ngImport: i0,
651
+ type: AsDetailDisplayValuePipe,
652
+ decorators: [{
653
+ type: Pipe,
654
+ args: [{
655
+ name: "asDetailDisplayValue",
656
+ standalone: true,
657
+ pure: true
658
+ }]
659
+ }]
660
+ });
661
+ var CanCreateDetailRowPipe = class CanCreateDetailRowPipe {
662
+ transform(attr, permissions) {
663
+ const perms = permissions[attr.name];
664
+ return perms ? perms.canCreate : false;
665
+ }
666
+ static ɵfac = i0.ɵɵngDeclareFactory({
667
+ minVersion: "12.0.0",
668
+ version: "22.2.0",
669
+ ngImport: i0,
670
+ type: CanCreateDetailRowPipe,
671
+ deps: [],
672
+ target: i0.ɵɵFactoryTarget.Pipe
673
+ });
674
+ static ɵpipe = i0.ɵɵngDeclarePipe({
675
+ minVersion: "14.0.0",
676
+ version: "22.2.0",
677
+ ngImport: i0,
678
+ type: CanCreateDetailRowPipe,
679
+ isStandalone: true,
680
+ name: "canCreateDetailRow"
681
+ });
682
+ };
683
+ i0.ɵɵngDeclareClassMetadata({
684
+ minVersion: "12.0.0",
685
+ version: "22.2.0",
686
+ ngImport: i0,
687
+ type: CanCreateDetailRowPipe,
688
+ decorators: [{
689
+ type: Pipe,
690
+ args: [{
691
+ name: "canCreateDetailRow",
692
+ standalone: true,
693
+ pure: true
694
+ }]
695
+ }]
696
+ });
697
+ var CanDeleteDetailRowPipe = class CanDeleteDetailRowPipe {
698
+ transform(attr, permissions) {
699
+ const perms = permissions[attr.name];
700
+ return perms ? perms.canDelete : false;
701
+ }
702
+ static ɵfac = i0.ɵɵngDeclareFactory({
703
+ minVersion: "12.0.0",
704
+ version: "22.2.0",
705
+ ngImport: i0,
706
+ type: CanDeleteDetailRowPipe,
707
+ deps: [],
708
+ target: i0.ɵɵFactoryTarget.Pipe
709
+ });
710
+ static ɵpipe = i0.ɵɵngDeclarePipe({
711
+ minVersion: "14.0.0",
712
+ version: "22.2.0",
713
+ ngImport: i0,
714
+ type: CanDeleteDetailRowPipe,
715
+ isStandalone: true,
716
+ name: "canDeleteDetailRow"
717
+ });
718
+ };
719
+ i0.ɵɵngDeclareClassMetadata({
720
+ minVersion: "12.0.0",
721
+ version: "22.2.0",
722
+ ngImport: i0,
723
+ type: CanDeleteDetailRowPipe,
724
+ decorators: [{
725
+ type: Pipe,
726
+ args: [{
727
+ name: "canDeleteDetailRow",
728
+ standalone: true,
729
+ pure: true
730
+ }]
731
+ }]
732
+ });
733
+ var CanEditDetailRowPipe = class CanEditDetailRowPipe {
734
+ transform(attr, permissions) {
735
+ const perms = permissions[attr.name];
736
+ return perms ? perms.canEdit : false;
737
+ }
738
+ static ɵfac = i0.ɵɵngDeclareFactory({
739
+ minVersion: "12.0.0",
740
+ version: "22.2.0",
741
+ ngImport: i0,
742
+ type: CanEditDetailRowPipe,
743
+ deps: [],
744
+ target: i0.ɵɵFactoryTarget.Pipe
745
+ });
746
+ static ɵpipe = i0.ɵɵngDeclarePipe({
747
+ minVersion: "14.0.0",
748
+ version: "22.2.0",
749
+ ngImport: i0,
750
+ type: CanEditDetailRowPipe,
751
+ isStandalone: true,
752
+ name: "canEditDetailRow"
753
+ });
754
+ };
755
+ i0.ɵɵngDeclareClassMetadata({
756
+ minVersion: "12.0.0",
757
+ version: "22.2.0",
758
+ ngImport: i0,
759
+ type: CanEditDetailRowPipe,
760
+ decorators: [{
761
+ type: Pipe,
762
+ args: [{
763
+ name: "canEditDetailRow",
764
+ standalone: true,
765
+ pure: true
766
+ }]
767
+ }]
768
+ });
769
+ var LookupDisplayTypePipe = class LookupDisplayTypePipe {
770
+ transform(attr, lookupRefOptions) {
771
+ return (attr.lookupReferenceType ? lookupRefOptions[attr.lookupReferenceType] : null)?.displayType ?? ELookupDisplayType.Dropdown;
772
+ }
773
+ static ɵfac = i0.ɵɵngDeclareFactory({
774
+ minVersion: "12.0.0",
775
+ version: "22.2.0",
776
+ ngImport: i0,
777
+ type: LookupDisplayTypePipe,
778
+ deps: [],
779
+ target: i0.ɵɵFactoryTarget.Pipe
780
+ });
781
+ static ɵpipe = i0.ɵɵngDeclarePipe({
782
+ minVersion: "14.0.0",
783
+ version: "22.2.0",
784
+ ngImport: i0,
785
+ type: LookupDisplayTypePipe,
786
+ isStandalone: true,
787
+ name: "lookupDisplayType"
788
+ });
789
+ };
790
+ i0.ɵɵngDeclareClassMetadata({
791
+ minVersion: "12.0.0",
792
+ version: "22.2.0",
793
+ ngImport: i0,
794
+ type: LookupDisplayTypePipe,
795
+ decorators: [{
796
+ type: Pipe,
797
+ args: [{
798
+ name: "lookupDisplayType",
799
+ standalone: true,
800
+ pure: true
801
+ }]
802
+ }]
803
+ });
804
+ var LookupDisplayValuePipe = class LookupDisplayValuePipe {
805
+ transform(attr, formData, lookupRefOptions) {
806
+ const currentValue = formData[attr.name];
807
+ if (currentValue == null || currentValue === "") return "";
808
+ const selected = ((attr.lookupReferenceType ? lookupRefOptions[attr.lookupReferenceType] : null)?.values.filter((v) => v.isActive) || []).find((o) => o.key === String(currentValue));
809
+ if (!selected) return String(currentValue);
810
+ return resolveTranslation(selected.values) || selected.key;
811
+ }
812
+ static ɵfac = i0.ɵɵngDeclareFactory({
813
+ minVersion: "12.0.0",
814
+ version: "22.2.0",
815
+ ngImport: i0,
816
+ type: LookupDisplayValuePipe,
817
+ deps: [],
818
+ target: i0.ɵɵFactoryTarget.Pipe
819
+ });
820
+ static ɵpipe = i0.ɵɵngDeclarePipe({
821
+ minVersion: "14.0.0",
822
+ version: "22.2.0",
823
+ ngImport: i0,
824
+ type: LookupDisplayValuePipe,
825
+ isStandalone: true,
826
+ name: "lookupDisplayValue"
827
+ });
828
+ };
829
+ i0.ɵɵngDeclareClassMetadata({
830
+ minVersion: "12.0.0",
831
+ version: "22.2.0",
832
+ ngImport: i0,
833
+ type: LookupDisplayValuePipe,
834
+ decorators: [{
835
+ type: Pipe,
836
+ args: [{
837
+ name: "lookupDisplayValue",
838
+ standalone: true,
839
+ pure: true
840
+ }]
841
+ }]
842
+ });
843
+ var LookupOptionsPipe = class LookupOptionsPipe {
844
+ transform(attr, lookupRefOptions) {
845
+ return (attr.lookupReferenceType ? lookupRefOptions[attr.lookupReferenceType] : null)?.values.filter((v) => v.isActive) || [];
846
+ }
847
+ static ɵfac = i0.ɵɵngDeclareFactory({
848
+ minVersion: "12.0.0",
849
+ version: "22.2.0",
850
+ ngImport: i0,
851
+ type: LookupOptionsPipe,
852
+ deps: [],
853
+ target: i0.ɵɵFactoryTarget.Pipe
854
+ });
855
+ static ɵpipe = i0.ɵɵngDeclarePipe({
856
+ minVersion: "14.0.0",
857
+ version: "22.2.0",
858
+ ngImport: i0,
859
+ type: LookupOptionsPipe,
860
+ isStandalone: true,
861
+ name: "lookupOptions"
862
+ });
863
+ };
864
+ i0.ɵɵngDeclareClassMetadata({
865
+ minVersion: "12.0.0",
866
+ version: "22.2.0",
867
+ ngImport: i0,
868
+ type: LookupOptionsPipe,
869
+ decorators: [{
870
+ type: Pipe,
871
+ args: [{
872
+ name: "lookupOptions",
873
+ standalone: true,
874
+ pure: true
875
+ }]
876
+ }]
877
+ });
878
+ var InlineRefOptionsPipe = class InlineRefOptionsPipe {
879
+ transform(parentAttr, col, asDetailRefOptions) {
880
+ return asDetailRefOptions[parentAttr.name]?.[col.name] || [];
881
+ }
882
+ static ɵfac = i0.ɵɵngDeclareFactory({
883
+ minVersion: "12.0.0",
884
+ version: "22.2.0",
885
+ ngImport: i0,
886
+ type: InlineRefOptionsPipe,
887
+ deps: [],
888
+ target: i0.ɵɵFactoryTarget.Pipe
889
+ });
890
+ static ɵpipe = i0.ɵɵngDeclarePipe({
891
+ minVersion: "14.0.0",
892
+ version: "22.2.0",
893
+ ngImport: i0,
894
+ type: InlineRefOptionsPipe,
895
+ isStandalone: true,
896
+ name: "inlineRefOptions"
897
+ });
898
+ };
899
+ i0.ɵɵngDeclareClassMetadata({
900
+ minVersion: "12.0.0",
901
+ version: "22.2.0",
902
+ ngImport: i0,
903
+ type: InlineRefOptionsPipe,
904
+ decorators: [{
905
+ type: Pipe,
906
+ args: [{
907
+ name: "inlineRefOptions",
908
+ standalone: true,
909
+ pure: true
910
+ }]
911
+ }]
912
+ });
913
+ var ErrorForAttributePipe = class ErrorForAttributePipe {
914
+ transform(attrName, validationErrors) {
915
+ const error = validationErrors.find((e) => e.attributeName === attrName);
916
+ return error ? resolveTranslation(error.errorMessage) : null;
917
+ }
918
+ static ɵfac = i0.ɵɵngDeclareFactory({
919
+ minVersion: "12.0.0",
920
+ version: "22.2.0",
921
+ ngImport: i0,
922
+ type: ErrorForAttributePipe,
923
+ deps: [],
924
+ target: i0.ɵɵFactoryTarget.Pipe
925
+ });
926
+ static ɵpipe = i0.ɵɵngDeclarePipe({
927
+ minVersion: "14.0.0",
928
+ version: "22.2.0",
929
+ ngImport: i0,
930
+ type: ErrorForAttributePipe,
931
+ isStandalone: true,
932
+ name: "errorForAttribute"
933
+ });
934
+ };
935
+ i0.ɵɵngDeclareClassMetadata({
936
+ minVersion: "12.0.0",
937
+ version: "22.2.0",
938
+ ngImport: i0,
939
+ type: ErrorForAttributePipe,
940
+ decorators: [{
941
+ type: Pipe,
942
+ args: [{
943
+ name: "errorForAttribute",
944
+ standalone: true,
945
+ pure: true
946
+ }]
947
+ }]
948
+ });
949
+ var IconNamePipe = class IconNamePipe {
950
+ transform(value, fallback) {
951
+ const iconClass = value || fallback;
952
+ return iconClass.startsWith("bi-") ? iconClass.substring(3) : iconClass;
953
+ }
954
+ static ɵfac = i0.ɵɵngDeclareFactory({
955
+ minVersion: "12.0.0",
956
+ version: "22.2.0",
957
+ ngImport: i0,
958
+ type: IconNamePipe,
959
+ deps: [],
960
+ target: i0.ɵɵFactoryTarget.Pipe
961
+ });
962
+ static ɵpipe = i0.ɵɵngDeclarePipe({
963
+ minVersion: "14.0.0",
964
+ version: "22.2.0",
965
+ ngImport: i0,
966
+ type: IconNamePipe,
967
+ isStandalone: true,
968
+ name: "iconName"
969
+ });
970
+ };
971
+ i0.ɵɵngDeclareClassMetadata({
972
+ minVersion: "12.0.0",
973
+ version: "22.2.0",
974
+ ngImport: i0,
975
+ type: IconNamePipe,
976
+ decorators: [{
977
+ type: Pipe,
978
+ args: [{
979
+ name: "iconName",
980
+ standalone: true,
981
+ pure: true
982
+ }]
983
+ }]
984
+ });
985
+ var ArrayValuePipe = class ArrayValuePipe {
986
+ transform(attrName, item) {
987
+ const attr = item?.attributes.find((a) => a.name === attrName);
988
+ if (!attr) return [];
989
+ if (attr.dataType === "AsDetail" && attr.isArray && Array.isArray(attr.objects)) return attr.objects.map((po) => nestedPoToDisplayRow(po));
990
+ if (Array.isArray(attr.value)) return attr.value;
991
+ return [];
992
+ }
993
+ static ɵfac = i0.ɵɵngDeclareFactory({
994
+ minVersion: "12.0.0",
995
+ version: "22.2.0",
996
+ ngImport: i0,
997
+ type: ArrayValuePipe,
998
+ deps: [],
999
+ target: i0.ɵɵFactoryTarget.Pipe
1000
+ });
1001
+ static ɵpipe = i0.ɵɵngDeclarePipe({
1002
+ minVersion: "14.0.0",
1003
+ version: "22.2.0",
1004
+ ngImport: i0,
1005
+ type: ArrayValuePipe,
1006
+ isStandalone: true,
1007
+ name: "arrayValue"
1008
+ });
1009
+ };
1010
+ i0.ɵɵngDeclareClassMetadata({
1011
+ minVersion: "12.0.0",
1012
+ version: "22.2.0",
1013
+ ngImport: i0,
1014
+ type: ArrayValuePipe,
1015
+ decorators: [{
1016
+ type: Pipe,
1017
+ args: [{
1018
+ name: "arrayValue",
1019
+ standalone: true,
1020
+ pure: true
1021
+ }]
1022
+ }]
1023
+ });
1024
+ var QueryCellValuePipe = class QueryCellValuePipe {
1025
+ transform(column, item, lookupRefOptions) {
1026
+ const cell = valueFor(item, column.name);
1027
+ if (!cell) return "";
1028
+ const resolved = resolvedBreadcrumb(cell.breadcrumb, column.asDetailType);
1029
+ if (resolved) return resolved;
1030
+ if (column.dataType === "AsDetail") {
1031
+ if (!column.isArray) return "";
1032
+ const count = typeof cell.value === "number" ? cell.value : 0;
1033
+ return count === 0 ? "" : `${count} item${count !== 1 ? "s" : ""}`;
1034
+ }
1035
+ if (column.lookupReferenceType && cell.value != null && cell.value !== "") {
1036
+ const option = lookupRefOptions[column.lookupReferenceType]?.values.find((v) => v.key === String(cell.value));
1037
+ if (option) return resolveTranslation(option.values) || option.key;
1038
+ }
1039
+ if (column.dataType === "boolean") return cell.value ?? null;
1040
+ if (column.dataType === "date" || column.dataType === "datetime") {
1041
+ if (cell.value == null || cell.value === "") return null;
1042
+ if (cell.value instanceof Date) return Number.isNaN(cell.value.getTime()) ? null : cell.value;
1043
+ const parsed = new Date(cell.value);
1044
+ return Number.isNaN(parsed.getTime()) ? String(cell.value) : parsed;
1045
+ }
1046
+ return cell.value ?? "";
1047
+ }
1048
+ static ɵfac = i0.ɵɵngDeclareFactory({
1049
+ minVersion: "12.0.0",
1050
+ version: "22.2.0",
1051
+ ngImport: i0,
1052
+ type: QueryCellValuePipe,
1053
+ deps: [],
1054
+ target: i0.ɵɵFactoryTarget.Pipe
1055
+ });
1056
+ static ɵpipe = i0.ɵɵngDeclarePipe({
1057
+ minVersion: "14.0.0",
1058
+ version: "22.2.0",
1059
+ ngImport: i0,
1060
+ type: QueryCellValuePipe,
1061
+ isStandalone: true,
1062
+ name: "queryCellValue"
1063
+ });
1064
+ };
1065
+ i0.ɵɵngDeclareClassMetadata({
1066
+ minVersion: "12.0.0",
1067
+ version: "22.2.0",
1068
+ ngImport: i0,
1069
+ type: QueryCellValuePipe,
1070
+ decorators: [{
1071
+ type: Pipe,
1072
+ args: [{
1073
+ name: "queryCellValue",
1074
+ standalone: true,
1075
+ pure: true
1076
+ }]
1077
+ }]
1078
+ });
1079
+ var QueryReferenceChipsPipe = class QueryReferenceChipsPipe {
1080
+ transform(column, item) {
1081
+ const cell = valueFor(item, column.name);
1082
+ if (!cell || !Array.isArray(cell.value)) return [];
1083
+ const breadcrumbs = cell.breadcrumbs ?? {};
1084
+ return cell.value.filter((v) => v != null && v !== "").map((v) => {
1085
+ const id = String(v);
1086
+ return {
1087
+ id,
1088
+ label: breadcrumbs[id] || id
1089
+ };
1090
+ });
1091
+ }
1092
+ static ɵfac = i0.ɵɵngDeclareFactory({
1093
+ minVersion: "12.0.0",
1094
+ version: "22.2.0",
1095
+ ngImport: i0,
1096
+ type: QueryReferenceChipsPipe,
1097
+ deps: [],
1098
+ target: i0.ɵɵFactoryTarget.Pipe
1099
+ });
1100
+ static ɵpipe = i0.ɵɵngDeclarePipe({
1101
+ minVersion: "14.0.0",
1102
+ version: "22.2.0",
1103
+ ngImport: i0,
1104
+ type: QueryReferenceChipsPipe,
1105
+ isStandalone: true,
1106
+ name: "queryReferenceChips"
1107
+ });
1108
+ };
1109
+ i0.ɵɵngDeclareClassMetadata({
1110
+ minVersion: "12.0.0",
1111
+ version: "22.2.0",
1112
+ ngImport: i0,
1113
+ type: QueryReferenceChipsPipe,
1114
+ decorators: [{
1115
+ type: Pipe,
1116
+ args: [{
1117
+ name: "queryReferenceChips",
1118
+ standalone: true,
1119
+ pure: true
1120
+ }]
1121
+ }]
1122
+ });
767
1123
  export { ArrayValuePipe, AsDetailCellValuePipe, AsDetailColumnsPipe, AsDetailDisplayValuePipe, AsDetailTypePipe, AttributeValuePipe, CanCreateDetailRowPipe, CanDeleteDetailRowPipe, CanEditDetailRowPipe, ErrorForAttributePipe, IconNamePipe, InlineRefOptionsPipe, InputTypePipe, LookupDisplayTypePipe, LookupDisplayValuePipe, LookupOptionsPipe, ParsedDatePipe, QueryCellValuePipe, QueryReferenceChipsPipe, RawAttributeValuePipe, ReferenceAttrValuePipe, ReferenceChipsPipe, ReferenceDisplayValuePipe, ReferenceLinkRoutePipe, ResolveTranslationPipe, RouterLinkPipe, TranslateKeyPipe };
768
- //# sourceMappingURL=mintplayer-ng-spark-pipes.mjs.map
1124
+
1125
+ //# sourceMappingURL=mintplayer-ng-spark-pipes.mjs.map