@mintplayer/ng-spark 22.24.0 → 22.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -0
- package/fesm2022/mintplayer-ng-spark-client-operations.mjs +5 -3
- package/fesm2022/mintplayer-ng-spark-client-operations.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-contributions.mjs +721 -0
- package/fesm2022/mintplayer-ng-spark-contributions.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-grid.mjs +131 -4
- package/fesm2022/mintplayer-ng-spark-grid.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-history.mjs +1 -14
- package/fesm2022/mintplayer-ng-spark-history.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-models.mjs +41 -2
- package/fesm2022/mintplayer-ng-spark-models.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-moderation.mjs +4 -4
- package/fesm2022/mintplayer-ng-spark-moderation.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-panels.mjs +9 -1
- package/fesm2022/mintplayer-ng-spark-panels.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-pipes.mjs +39 -3
- package/fesm2022/mintplayer-ng-spark-pipes.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-create.mjs +16 -12
- package/fesm2022/mintplayer-ng-spark-po-create.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs +15 -6
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-edit.mjs +926 -16
- package/fesm2022/mintplayer-ng-spark-po-edit.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-form.mjs +142 -30
- package/fesm2022/mintplayer-ng-spark-po-form.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-query-list.mjs +60 -5
- package/fesm2022/mintplayer-ng-spark-query-list.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-renderers.mjs +28 -1
- package/fesm2022/mintplayer-ng-spark-renderers.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs +2 -0
- package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-services.mjs +3 -2
- package/fesm2022/mintplayer-ng-spark-services.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-shell.mjs +31 -13
- package/fesm2022/mintplayer-ng-spark-shell.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark.mjs +4 -1
- package/fesm2022/mintplayer-ng-spark.mjs.map +1 -1
- package/package.json +7 -2
- package/types/mintplayer-ng-spark-client-operations.d.ts +7 -1
- package/types/mintplayer-ng-spark-contributions.d.ts +231 -0
- package/types/mintplayer-ng-spark-grid.d.ts +35 -3
- package/types/mintplayer-ng-spark-history.d.ts +3 -10
- package/types/mintplayer-ng-spark-models.d.ts +60 -3
- package/types/mintplayer-ng-spark-panels.d.ts +36 -1
- package/types/mintplayer-ng-spark-pipes.d.ts +12 -1
- package/types/mintplayer-ng-spark-po-create.d.ts +10 -0
- package/types/mintplayer-ng-spark-po-detail.d.ts +4 -1
- package/types/mintplayer-ng-spark-po-edit.d.ts +305 -1
- package/types/mintplayer-ng-spark-po-form.d.ts +84 -15
- package/types/mintplayer-ng-spark-query-list.d.ts +26 -1
- package/types/mintplayer-ng-spark-renderers.d.ts +44 -2
- package/types/mintplayer-ng-spark-services.d.ts +10 -1
- package/types/mintplayer-ng-spark-shell.d.ts +24 -9
- package/types/mintplayer-ng-spark.d.ts +12 -0
|
@@ -1,26 +1,774 @@
|
|
|
1
1
|
import * as i0 from "@angular/core";
|
|
2
|
-
import { ChangeDetectionStrategy, Component, computed, inject, output, signal } from "@angular/core";
|
|
2
|
+
import { ChangeDetectionStrategy, Component, LOCALE_ID, computed, effect, inject, input, output, signal, untracked, viewChild } from "@angular/core";
|
|
3
3
|
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
|
4
|
-
import { CommonModule } from "@angular/common";
|
|
4
|
+
import { CommonModule, NgTemplateOutlet, formatDate } from "@angular/common";
|
|
5
5
|
import { ActivatedRoute, Router } from "@angular/router";
|
|
6
6
|
import { Color } from "@mintplayer/ng-bootstrap";
|
|
7
7
|
import { BsAlertComponent } from "@mintplayer/ng-bootstrap/alert";
|
|
8
8
|
import { BsContainerComponent } from "@mintplayer/ng-bootstrap/container";
|
|
9
9
|
import { BsSpinnerComponent } from "@mintplayer/ng-bootstrap/spinner";
|
|
10
|
+
import { SPARK_CONFIG } from "@mintplayer/ng-spark";
|
|
10
11
|
import { SparkLanguageService, SparkService } from "@mintplayer/ng-spark/services";
|
|
11
12
|
import { SparkPoFormComponent } from "@mintplayer/ng-spark/po-form";
|
|
12
|
-
import { ResolveTranslationPipe, TranslateKeyPipe } from "@mintplayer/ng-spark/pipes";
|
|
13
|
-
import { ShowedOn, applyOverlay, dictToNestedPo, fromDateInputValue, hasShowedOnFlag, isDateDataType, nestedPoToDict, toDateInputValue, wireDatesEqual } from "@mintplayer/ng-spark/models";
|
|
13
|
+
import { QueryCellValuePipe, QueryReferenceChipsPipe, ResolveTranslationPipe, TranslateKeyPipe } from "@mintplayer/ng-spark/pipes";
|
|
14
|
+
import { AS_DETAIL_ROW_KEY, ShowedOn, applyOverlay, dictToNestedPo, formValuesEqual, fromDateInputValue, hasShowedOnFlag, isDateDataType, isReservedAsDetailKey, nestedPoToDict, rowMetadata, selfBreadcrumb, toDateInputValue, valueFor, wireDatesEqual } from "@mintplayer/ng-spark/models";
|
|
15
|
+
import { BsModalBodyDirective, BsModalDirective, BsModalFooterDirective, BsModalHeaderDirective, BsModalHostComponent } from "@mintplayer/ng-bootstrap/modal";
|
|
16
|
+
import { BsButtonTypeDirective } from "@mintplayer/ng-bootstrap/button-type";
|
|
17
|
+
import { SparkGridCellComponent, SparkGridRenderers } from "@mintplayer/ng-spark/grid";
|
|
18
|
+
import { cellValue } from "@mintplayer/ng-spark/renderers";
|
|
19
|
+
const CONTRIBUTION_ROW_METADATA = "contribution";
|
|
20
|
+
function contributionRowIsOwn(row) {
|
|
21
|
+
const facts = rowMetadata(row, CONTRIBUTION_ROW_METADATA);
|
|
22
|
+
return facts && typeof facts.own === "boolean" ? facts.own : void 0;
|
|
23
|
+
}
|
|
24
|
+
function mergeThreeWay(base, mine, theirs, schema, choices = {}) {
|
|
25
|
+
const ctx = {
|
|
26
|
+
resolve: schema.resolve,
|
|
27
|
+
choices,
|
|
28
|
+
conflicts: [],
|
|
29
|
+
theirChanges: [],
|
|
30
|
+
contributionNotices: []
|
|
31
|
+
};
|
|
32
|
+
return {
|
|
33
|
+
merged: mergeObject(schema.attributes, base ?? {}, mine ?? {}, theirs ?? {}, "", void 0, void 0, ctx),
|
|
34
|
+
conflicts: ctx.conflicts,
|
|
35
|
+
theirChanges: ctx.theirChanges,
|
|
36
|
+
contributionNotices: ctx.contributionNotices
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function mergeObject(attributes, base, mine, theirs, prefix, root, rowLabel, ctx) {
|
|
40
|
+
const merged = { ...theirs };
|
|
41
|
+
for (const attribute of attributes) {
|
|
42
|
+
const at = {
|
|
43
|
+
path: prefix ? `${prefix}.${attribute.name}` : attribute.name,
|
|
44
|
+
attribute,
|
|
45
|
+
rootAttribute: root ?? attribute,
|
|
46
|
+
group: prefix,
|
|
47
|
+
rowLabel
|
|
48
|
+
};
|
|
49
|
+
merged[attribute.name] = mergeAttribute(at, base[attribute.name], mine[attribute.name], theirs[attribute.name], ctx);
|
|
50
|
+
}
|
|
51
|
+
return merged;
|
|
52
|
+
}
|
|
53
|
+
function mergeAttribute(at, base, mine, theirs, ctx) {
|
|
54
|
+
if (at.attribute.isReadOnly) return theirs;
|
|
55
|
+
if (at.attribute.dataType === "AsDetail" && at.attribute.asDetailType) {
|
|
56
|
+
const rowType = ctx.resolve(at.attribute.asDetailType);
|
|
57
|
+
if (rowType) {
|
|
58
|
+
const typed = {
|
|
59
|
+
...at,
|
|
60
|
+
rowType: {
|
|
61
|
+
attributes: rowType.attributes ?? [],
|
|
62
|
+
name: rowType.name
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
if (at.attribute.isArray) return mergeRows(typed, rowType.attributes ?? [], rowType.name, asRows(base), asRows(mine), asRows(theirs), ctx);
|
|
66
|
+
if (isPlainObject(base) && isPlainObject(mine) && isPlainObject(theirs) && !formValuesEqual(mine, base) && !formValuesEqual(theirs, base)) return mergeObject(rowType.attributes ?? [], base, mine, theirs, at.path, at.rootAttribute, at.rowLabel, ctx);
|
|
67
|
+
return mergeValue(typed, "value", base, mine, theirs, ctx);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return mergeValue(at, "value", base, mine, theirs, ctx);
|
|
71
|
+
}
|
|
72
|
+
function mergeValue(at, kind, base, mine, theirs, ctx) {
|
|
73
|
+
const mineChanged = !formValuesEqual(mine, base);
|
|
74
|
+
const theirsChanged = !formValuesEqual(theirs, base);
|
|
75
|
+
if (!mineChanged) {
|
|
76
|
+
if (theirsChanged) ctx.theirChanges.push({
|
|
77
|
+
path: at.path,
|
|
78
|
+
attribute: at.attribute,
|
|
79
|
+
rootAttribute: at.rootAttribute
|
|
80
|
+
});
|
|
81
|
+
return theirs;
|
|
82
|
+
}
|
|
83
|
+
if (!theirsChanged || formValuesEqual(mine, theirs)) return theirsChanged ? theirs : mine;
|
|
84
|
+
return conflict(at, kind, base, mine, theirs, ctx);
|
|
85
|
+
}
|
|
86
|
+
function conflict(at, kind, base, mine, theirs, ctx) {
|
|
87
|
+
ctx.conflicts.push({
|
|
88
|
+
path: at.path,
|
|
89
|
+
kind,
|
|
90
|
+
attribute: at.attribute,
|
|
91
|
+
rootAttribute: at.rootAttribute,
|
|
92
|
+
group: at.group,
|
|
93
|
+
rowLabel: at.rowLabel,
|
|
94
|
+
...at.rowType ? {
|
|
95
|
+
rowAttributes: at.rowType.attributes,
|
|
96
|
+
rowTypeName: at.rowType.name
|
|
97
|
+
} : {},
|
|
98
|
+
base,
|
|
99
|
+
mine,
|
|
100
|
+
theirs
|
|
101
|
+
});
|
|
102
|
+
return ctx.choices[at.path] === "mine" ? mine : theirs;
|
|
103
|
+
}
|
|
104
|
+
function mergeRows(at, rowAttributes, rowTypeName, base, mine, theirs, ctx) {
|
|
105
|
+
const baseByKey = byKey(base);
|
|
106
|
+
const mineByKey = byKey(mine);
|
|
107
|
+
const merged = [];
|
|
108
|
+
const seen = /* @__PURE__ */ new Set();
|
|
109
|
+
const mergeOne = (key, b, m, t) => {
|
|
110
|
+
const rowPath = `${at.path}[${key}]`;
|
|
111
|
+
const label = selfBreadcrumb(t ?? m ?? b, rowTypeName) ?? key;
|
|
112
|
+
const row = mergeRow({
|
|
113
|
+
...at,
|
|
114
|
+
path: rowPath,
|
|
115
|
+
rowLabel: label
|
|
116
|
+
}, rowAttributes, b, m, t, ctx);
|
|
117
|
+
if (row !== void 0) merged.push(row);
|
|
118
|
+
};
|
|
119
|
+
for (const t of theirs) {
|
|
120
|
+
const key = rowKey(t);
|
|
121
|
+
if (key === void 0) {
|
|
122
|
+
merged.push(t);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (seen.has(key)) continue;
|
|
126
|
+
seen.add(key);
|
|
127
|
+
mergeOne(key, baseByKey.get(key), mineByKey.get(key), t);
|
|
128
|
+
}
|
|
129
|
+
for (const m of mine) {
|
|
130
|
+
const key = rowKey(m);
|
|
131
|
+
if (key === void 0) {
|
|
132
|
+
merged.push(m);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (seen.has(key)) continue;
|
|
136
|
+
seen.add(key);
|
|
137
|
+
mergeOne(key, baseByKey.get(key), m, void 0);
|
|
138
|
+
}
|
|
139
|
+
return merged;
|
|
140
|
+
}
|
|
141
|
+
function mergeRow(at, rowAttributes, base, mine, theirs, ctx) {
|
|
142
|
+
if (contributionRowIsOwn(theirs ?? base) === false && !formValuesEqual(mine, base) && !formValuesEqual(theirs, base)) {
|
|
143
|
+
ctx.theirChanges.push({
|
|
144
|
+
path: at.path,
|
|
145
|
+
attribute: at.attribute,
|
|
146
|
+
rootAttribute: at.rootAttribute
|
|
147
|
+
});
|
|
148
|
+
ctx.contributionNotices.push({
|
|
149
|
+
path: at.path,
|
|
150
|
+
attribute: at.attribute,
|
|
151
|
+
rowLabel: at.rowLabel ?? at.path
|
|
152
|
+
});
|
|
153
|
+
return theirs;
|
|
154
|
+
}
|
|
155
|
+
if (base === void 0) {
|
|
156
|
+
if (mine !== void 0 && theirs !== void 0) return formValuesEqual(mine, theirs) ? theirs : conflict(at, "row", void 0, mine, theirs, ctx);
|
|
157
|
+
if (theirs !== void 0) {
|
|
158
|
+
ctx.theirChanges.push({
|
|
159
|
+
path: at.path,
|
|
160
|
+
attribute: at.attribute,
|
|
161
|
+
rootAttribute: at.rootAttribute
|
|
162
|
+
});
|
|
163
|
+
return theirs;
|
|
164
|
+
}
|
|
165
|
+
return mine;
|
|
166
|
+
}
|
|
167
|
+
if (mine === void 0 && theirs === void 0) return void 0;
|
|
168
|
+
if (mine === void 0) {
|
|
169
|
+
if (formValuesEqual(theirs, base)) return void 0;
|
|
170
|
+
return conflict(at, "row", base, void 0, theirs, ctx);
|
|
171
|
+
}
|
|
172
|
+
if (theirs === void 0) {
|
|
173
|
+
if (formValuesEqual(mine, base)) {
|
|
174
|
+
ctx.theirChanges.push({
|
|
175
|
+
path: at.path,
|
|
176
|
+
attribute: at.attribute,
|
|
177
|
+
rootAttribute: at.rootAttribute
|
|
178
|
+
});
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
return conflict(at, "row", base, mine, void 0, ctx);
|
|
182
|
+
}
|
|
183
|
+
return mergeObject(rowAttributes, base, mine, theirs, at.path, at.rootAttribute, at.rowLabel, ctx);
|
|
184
|
+
}
|
|
185
|
+
function rowKey(row) {
|
|
186
|
+
const key = row?.[AS_DETAIL_ROW_KEY];
|
|
187
|
+
return typeof key === "string" && key !== "" ? key : void 0;
|
|
188
|
+
}
|
|
189
|
+
function byKey(rows) {
|
|
190
|
+
const map = /* @__PURE__ */ new Map();
|
|
191
|
+
for (const row of rows) {
|
|
192
|
+
const key = rowKey(row);
|
|
193
|
+
if (key !== void 0 && !map.has(key)) map.set(key, row);
|
|
194
|
+
}
|
|
195
|
+
return map;
|
|
196
|
+
}
|
|
197
|
+
function asRows(value) {
|
|
198
|
+
return Array.isArray(value) ? value.filter(isPlainObject) : [];
|
|
199
|
+
}
|
|
200
|
+
function isPlainObject(value) {
|
|
201
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
202
|
+
}
|
|
203
|
+
const cellValuePipe = new QueryCellValuePipe();
|
|
204
|
+
const chipsPipe = new QueryReferenceChipsPipe();
|
|
205
|
+
var SparkPoConflictDialogComponent = class SparkPoConflictDialogComponent {
|
|
206
|
+
language = inject(SparkLanguageService);
|
|
207
|
+
gridRenderers = inject(SparkGridRenderers);
|
|
208
|
+
conflicts = input([], ...ngDevMode ? [{ debugName: "conflicts" }] : /* istanbul ignore next */ []);
|
|
209
|
+
referenceLabels = input({}, ...ngDevMode ? [{ debugName: "referenceLabels" }] : /* istanbul ignore next */ []);
|
|
210
|
+
audit = input(null, ...ngDevMode ? [{ debugName: "audit" }] : /* istanbul ignore next */ []);
|
|
211
|
+
theyChanged = input(null, ...ngDevMode ? [{ debugName: "theyChanged" }] : /* istanbul ignore next */ []);
|
|
212
|
+
resolved = output();
|
|
213
|
+
cancelled = output();
|
|
214
|
+
colors = Color;
|
|
215
|
+
choices = signal({}, ...ngDevMode ? [{ debugName: "choices" }] : /* istanbul ignore next */ []);
|
|
216
|
+
lookupOptions = signal({}, ...ngDevMode ? [{ debugName: "lookupOptions" }] : /* istanbul ignore next */ []);
|
|
217
|
+
complete = computed(() => {
|
|
218
|
+
const choices = this.choices();
|
|
219
|
+
return this.conflicts().every((c) => choices[c.path] !== void 0);
|
|
220
|
+
}, ...ngDevMode ? [{ debugName: "complete" }] : /* istanbul ignore next */ []);
|
|
221
|
+
groups = computed(() => {
|
|
222
|
+
const lookups = this.lookupOptions();
|
|
223
|
+
const labels = this.referenceLabels();
|
|
224
|
+
const groups = /* @__PURE__ */ new Map();
|
|
225
|
+
for (const conflict of this.conflicts()) {
|
|
226
|
+
const key = conflict.kind === "row" ? conflict.path : conflict.group;
|
|
227
|
+
let group = groups.get(key);
|
|
228
|
+
if (!group) {
|
|
229
|
+
group = key === "" ? {
|
|
230
|
+
key,
|
|
231
|
+
entries: []
|
|
232
|
+
} : {
|
|
233
|
+
key,
|
|
234
|
+
attribute: conflict.rootAttribute,
|
|
235
|
+
rowLabel: conflict.kind === "row" ? void 0 : conflict.rowLabel,
|
|
236
|
+
entries: []
|
|
237
|
+
};
|
|
238
|
+
groups.set(key, group);
|
|
239
|
+
}
|
|
240
|
+
group.entries.push({
|
|
241
|
+
conflict,
|
|
242
|
+
mine: this.sideCell(conflict, conflict.mine, conflict.theirs, labels, lookups),
|
|
243
|
+
theirs: this.sideCell(conflict, conflict.theirs, conflict.mine, labels, lookups)
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
return [...groups.values()];
|
|
247
|
+
}, ...ngDevMode ? [{ debugName: "groups" }] : /* istanbul ignore next */ []);
|
|
248
|
+
constructor() {
|
|
249
|
+
effect(() => {
|
|
250
|
+
const conflicts = this.conflicts();
|
|
251
|
+
untracked(() => {
|
|
252
|
+
this.choices.set({});
|
|
253
|
+
const attributes = conflicts.flatMap((c) => [...c.kind === "value" ? [c.attribute] : [], ...c.rowAttributes ?? []]);
|
|
254
|
+
this.gridRenderers.loadLookupOptions(attributes).then((o) => this.lookupOptions.set(o), () => this.lookupOptions.set({}));
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
choose(path, side) {
|
|
259
|
+
this.choices.update((c) => ({
|
|
260
|
+
...c,
|
|
261
|
+
[path]: side
|
|
262
|
+
}));
|
|
263
|
+
}
|
|
264
|
+
chooseAll(side) {
|
|
265
|
+
const all = {};
|
|
266
|
+
for (const c of this.conflicts()) all[c.path] = side;
|
|
267
|
+
this.choices.set(all);
|
|
268
|
+
}
|
|
269
|
+
apply() {
|
|
270
|
+
if (!this.complete()) return;
|
|
271
|
+
this.resolved.emit(this.choices());
|
|
272
|
+
}
|
|
273
|
+
sideCell(conflict, value, other, labels, lookups) {
|
|
274
|
+
if (!(conflict.kind === "row" || conflict.attribute.dataType === "AsDetail")) return this.cell(conflict.attribute, value, labels, lookups);
|
|
275
|
+
const cell = this.cell(conflict.attribute, void 0, labels, lookups);
|
|
276
|
+
if (value === void 0 || value === null) {
|
|
277
|
+
cell.text = value === void 0 && conflict.kind === "row" ? this.language.t("common.conflictRowRemoved") : "-";
|
|
278
|
+
return cell;
|
|
279
|
+
}
|
|
280
|
+
if (!conflict.rowAttributes || typeof value !== "object" || Array.isArray(value)) {
|
|
281
|
+
cell.text = summarize(value) || "-";
|
|
282
|
+
return cell;
|
|
283
|
+
}
|
|
284
|
+
const row = value;
|
|
285
|
+
const otherRow = typeof other === "object" && other !== null && !Array.isArray(other) ? other : void 0;
|
|
286
|
+
cell.fields = conflict.rowAttributes.filter((a) => a.isVisible !== false).sort((a, b) => (a.order ?? 0) - (b.order ?? 0)).map((attribute) => ({
|
|
287
|
+
attribute,
|
|
288
|
+
cell: this.cell(attribute, row[attribute.name], labels, lookups),
|
|
289
|
+
differs: otherRow !== void 0 && !formValuesEqual(row[attribute.name], otherRow[attribute.name])
|
|
290
|
+
}));
|
|
291
|
+
return cell;
|
|
292
|
+
}
|
|
293
|
+
cell(attribute, value, labels, lookups) {
|
|
294
|
+
const column = attribute;
|
|
295
|
+
const wire = isDateDataType(attribute.dataType) ? fromDateInputValue(attribute.dataType, value) : value;
|
|
296
|
+
const isReference = attribute.dataType === "Reference";
|
|
297
|
+
const breadcrumb = isReference && typeof wire === "string" ? labels[wire] : void 0;
|
|
298
|
+
const breadcrumbs = isReference && Array.isArray(wire) ? Object.fromEntries(wire.filter((id) => typeof id === "string" && id in labels).map((id) => [id, labels[id]])) : void 0;
|
|
299
|
+
const item = {
|
|
300
|
+
id: "",
|
|
301
|
+
name: "",
|
|
302
|
+
objectTypeId: "",
|
|
303
|
+
attributes: [{
|
|
304
|
+
id: attribute.id,
|
|
305
|
+
name: attribute.name,
|
|
306
|
+
dataType: attribute.dataType,
|
|
307
|
+
isArray: attribute.isArray,
|
|
308
|
+
isRequired: false,
|
|
309
|
+
isVisible: true,
|
|
310
|
+
isReadOnly: true,
|
|
311
|
+
order: 0,
|
|
312
|
+
rules: [],
|
|
313
|
+
value: wire,
|
|
314
|
+
breadcrumb,
|
|
315
|
+
breadcrumbs
|
|
316
|
+
}]
|
|
317
|
+
};
|
|
318
|
+
const cell = {
|
|
319
|
+
column,
|
|
320
|
+
display: "",
|
|
321
|
+
rendererValue: null,
|
|
322
|
+
chips: [],
|
|
323
|
+
item
|
|
324
|
+
};
|
|
325
|
+
if (value === void 0 && attribute.dataType === "AsDetail") return cell;
|
|
326
|
+
if (attribute.dataType === "AsDetail" || typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
327
|
+
cell.text = summarize(value) || "-";
|
|
328
|
+
return cell;
|
|
329
|
+
}
|
|
330
|
+
const row = item;
|
|
331
|
+
const display = cellValuePipe.transform(column, row, lookups);
|
|
332
|
+
cell.display = attribute.dataType !== "boolean" && (display == null || display === "") ? "-" : display;
|
|
333
|
+
cell.rendererValue = cellValue(valueFor(row, attribute.name));
|
|
334
|
+
cell.chips = chipsPipe.transform(column, row);
|
|
335
|
+
return cell;
|
|
336
|
+
}
|
|
337
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
338
|
+
minVersion: "12.0.0",
|
|
339
|
+
version: "22.2.0",
|
|
340
|
+
ngImport: i0,
|
|
341
|
+
type: SparkPoConflictDialogComponent,
|
|
342
|
+
deps: [],
|
|
343
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
344
|
+
});
|
|
345
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
346
|
+
minVersion: "17.0.0",
|
|
347
|
+
version: "22.2.0",
|
|
348
|
+
type: SparkPoConflictDialogComponent,
|
|
349
|
+
isStandalone: true,
|
|
350
|
+
selector: "spark-po-conflict-dialog",
|
|
351
|
+
inputs: {
|
|
352
|
+
conflicts: {
|
|
353
|
+
classPropertyName: "conflicts",
|
|
354
|
+
publicName: "conflicts",
|
|
355
|
+
isSignal: true,
|
|
356
|
+
isRequired: false,
|
|
357
|
+
transformFunction: null
|
|
358
|
+
},
|
|
359
|
+
referenceLabels: {
|
|
360
|
+
classPropertyName: "referenceLabels",
|
|
361
|
+
publicName: "referenceLabels",
|
|
362
|
+
isSignal: true,
|
|
363
|
+
isRequired: false,
|
|
364
|
+
transformFunction: null
|
|
365
|
+
},
|
|
366
|
+
audit: {
|
|
367
|
+
classPropertyName: "audit",
|
|
368
|
+
publicName: "audit",
|
|
369
|
+
isSignal: true,
|
|
370
|
+
isRequired: false,
|
|
371
|
+
transformFunction: null
|
|
372
|
+
},
|
|
373
|
+
theyChanged: {
|
|
374
|
+
classPropertyName: "theyChanged",
|
|
375
|
+
publicName: "theyChanged",
|
|
376
|
+
isSignal: true,
|
|
377
|
+
isRequired: false,
|
|
378
|
+
transformFunction: null
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
outputs: {
|
|
382
|
+
resolved: "resolved",
|
|
383
|
+
cancelled: "cancelled"
|
|
384
|
+
},
|
|
385
|
+
ngImport: i0,
|
|
386
|
+
template: `
|
|
387
|
+
<bs-modal [isOpen]="conflicts().length > 0" (isOpenChange)="!$event && cancelled.emit()">
|
|
388
|
+
<div *bsModal>
|
|
389
|
+
<div bsModalHeader>
|
|
390
|
+
<h5 class="modal-title">{{ 'common.conflictTitle' | t }}</h5>
|
|
391
|
+
</div>
|
|
392
|
+
<div bsModalBody class="spark-conflict-dialog">
|
|
393
|
+
<p>{{ 'common.conflictIntro' | t }}</p>
|
|
394
|
+
@if (audit()) {
|
|
395
|
+
<p class="text-muted spark-conflict-audit">{{ audit() }}</p>
|
|
396
|
+
}
|
|
397
|
+
@if (theyChanged()) {
|
|
398
|
+
<p class="text-muted spark-conflict-they-changed">{{ theyChanged() }}</p>
|
|
399
|
+
}
|
|
400
|
+
@for (group of groups(); track group.key) {
|
|
401
|
+
<div class="mb-3 spark-conflict-group">
|
|
402
|
+
@if (group.attribute) {
|
|
403
|
+
<h6>
|
|
404
|
+
<span>{{ group.attribute.label | resolveTranslation:group.attribute.name }}</span>
|
|
405
|
+
@if (group.rowLabel) {
|
|
406
|
+
<span> — {{ group.rowLabel }}</span>
|
|
407
|
+
}
|
|
408
|
+
</h6>
|
|
409
|
+
}
|
|
410
|
+
<table class="table table-sm align-middle mb-0">
|
|
411
|
+
<thead>
|
|
412
|
+
<tr>
|
|
413
|
+
<th>{{ 'common.conflictField' | t }}</th>
|
|
414
|
+
<th>{{ 'common.conflictMine' | t }}</th>
|
|
415
|
+
<th>{{ 'common.conflictTheirs' | t }}</th>
|
|
416
|
+
</tr>
|
|
417
|
+
</thead>
|
|
418
|
+
<tbody>
|
|
419
|
+
@for (entry of group.entries; track entry.conflict.path) {
|
|
420
|
+
<tr class="spark-conflict" [attr.data-path]="entry.conflict.path">
|
|
421
|
+
<th scope="row">
|
|
422
|
+
@if (entry.conflict.kind === 'row') {
|
|
423
|
+
{{ entry.conflict.rowLabel }}
|
|
424
|
+
} @else {
|
|
425
|
+
{{ entry.conflict.attribute.label | resolveTranslation:entry.conflict.attribute.name }}
|
|
426
|
+
}
|
|
427
|
+
</th>
|
|
428
|
+
<td class="spark-conflict-mine-value">
|
|
429
|
+
<label class="d-flex gap-2 align-items-start">
|
|
430
|
+
<input type="radio" class="form-check-input spark-conflict-mine" [name]="entry.conflict.path"
|
|
431
|
+
[checked]="choices()[entry.conflict.path] === 'mine'" (change)="choose(entry.conflict.path, 'mine')" />
|
|
432
|
+
<ng-container [ngTemplateOutlet]="side" [ngTemplateOutletContext]="{ $implicit: entry.mine }" />
|
|
433
|
+
</label>
|
|
434
|
+
</td>
|
|
435
|
+
<td class="spark-conflict-theirs-value">
|
|
436
|
+
<label class="d-flex gap-2 align-items-start">
|
|
437
|
+
<input type="radio" class="form-check-input spark-conflict-theirs" [name]="entry.conflict.path"
|
|
438
|
+
[checked]="choices()[entry.conflict.path] === 'theirs'" (change)="choose(entry.conflict.path, 'theirs')" />
|
|
439
|
+
<ng-container [ngTemplateOutlet]="side" [ngTemplateOutletContext]="{ $implicit: entry.theirs }" />
|
|
440
|
+
</label>
|
|
441
|
+
</td>
|
|
442
|
+
</tr>
|
|
443
|
+
}
|
|
444
|
+
</tbody>
|
|
445
|
+
</table>
|
|
446
|
+
</div>
|
|
447
|
+
}
|
|
448
|
+
</div>
|
|
449
|
+
<div bsModalFooter>
|
|
450
|
+
<button type="button" class="spark-conflict-all-mine" [color]="colors.secondary" (click)="chooseAll('mine')">{{ 'common.conflictKeepAllMine' | t }}</button>
|
|
451
|
+
<button type="button" class="spark-conflict-all-theirs" [color]="colors.secondary" (click)="chooseAll('theirs')">{{ 'common.conflictTakeAllTheirs' | t }}</button>
|
|
452
|
+
<button type="button" class="spark-conflict-cancel" [color]="colors.secondary" (click)="cancelled.emit()">{{ 'common.cancel' | t }}</button>
|
|
453
|
+
<button type="button" class="spark-conflict-apply" [color]="colors.primary" [disabled]="!complete()" (click)="apply()">{{ 'common.conflictApply' | t }}</button>
|
|
454
|
+
</div>
|
|
455
|
+
</div>
|
|
456
|
+
</bs-modal>
|
|
457
|
+
|
|
458
|
+
<!-- One side's value. A row is its attributes cell by cell, the ones the other side differs in marked. -->
|
|
459
|
+
<ng-template #side let-cell>
|
|
460
|
+
@if (cell.fields) {
|
|
461
|
+
<table class="table table-sm table-borderless mb-0 spark-conflict-row-cells">
|
|
462
|
+
<tbody>
|
|
463
|
+
@for (field of cell.fields; track field.attribute.name) {
|
|
464
|
+
<tr [class.spark-conflict-differs]="field.differs" [attr.data-attribute]="field.attribute.name">
|
|
465
|
+
<th scope="row" class="fw-normal text-muted pe-2">{{ field.attribute.label | resolveTranslation:field.attribute.name }}</th>
|
|
466
|
+
<td [class.fw-bold]="field.differs">
|
|
467
|
+
<ng-container [ngTemplateOutlet]="value" [ngTemplateOutletContext]="{ $implicit: field.cell }" />
|
|
468
|
+
</td>
|
|
469
|
+
</tr>
|
|
470
|
+
}
|
|
471
|
+
</tbody>
|
|
472
|
+
</table>
|
|
473
|
+
} @else {
|
|
474
|
+
<span><ng-container [ngTemplateOutlet]="value" [ngTemplateOutletContext]="{ $implicit: cell }" /></span>
|
|
475
|
+
}
|
|
476
|
+
</ng-template>
|
|
477
|
+
<ng-template #value let-cell>
|
|
478
|
+
@if (cell.text !== undefined) { {{ cell.text }} } @else {
|
|
479
|
+
<spark-grid-cell [column]="cell.column" [display]="cell.display" [rendererValue]="cell.rendererValue"
|
|
480
|
+
[item]="cell.item" [chips]="cell.chips" />
|
|
481
|
+
}
|
|
482
|
+
</ng-template>
|
|
483
|
+
`,
|
|
484
|
+
isInline: true,
|
|
485
|
+
dependencies: [
|
|
486
|
+
{
|
|
487
|
+
kind: "directive",
|
|
488
|
+
type: NgTemplateOutlet,
|
|
489
|
+
selector: "[ngTemplateOutlet]",
|
|
490
|
+
inputs: [
|
|
491
|
+
"ngTemplateOutletContext",
|
|
492
|
+
"ngTemplateOutlet",
|
|
493
|
+
"ngTemplateOutletInjector"
|
|
494
|
+
]
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
kind: "component",
|
|
498
|
+
type: BsModalHostComponent,
|
|
499
|
+
selector: "bs-modal",
|
|
500
|
+
inputs: [
|
|
501
|
+
"isOpen",
|
|
502
|
+
"closeOnEscape",
|
|
503
|
+
"scrollable"
|
|
504
|
+
],
|
|
505
|
+
outputs: ["isOpenChange"]
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
kind: "directive",
|
|
509
|
+
type: BsModalDirective,
|
|
510
|
+
selector: "[bsModal]"
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
kind: "directive",
|
|
514
|
+
type: BsModalHeaderDirective,
|
|
515
|
+
selector: "[bsModalHeader]"
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
kind: "directive",
|
|
519
|
+
type: BsModalBodyDirective,
|
|
520
|
+
selector: "[bsModalBody]"
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
kind: "directive",
|
|
524
|
+
type: BsModalFooterDirective,
|
|
525
|
+
selector: "[bsModalFooter]"
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
kind: "directive",
|
|
529
|
+
type: BsButtonTypeDirective,
|
|
530
|
+
selector: "button[color],input[type=\"button\"][color],input[type=\"submit\"][color],a[color]",
|
|
531
|
+
inputs: ["color"]
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
kind: "component",
|
|
535
|
+
type: SparkGridCellComponent,
|
|
536
|
+
selector: "spark-grid-cell",
|
|
537
|
+
inputs: [
|
|
538
|
+
"column",
|
|
539
|
+
"display",
|
|
540
|
+
"rendererValue",
|
|
541
|
+
"item",
|
|
542
|
+
"chips",
|
|
543
|
+
"link"
|
|
544
|
+
]
|
|
545
|
+
},
|
|
546
|
+
{
|
|
547
|
+
kind: "pipe",
|
|
548
|
+
type: ResolveTranslationPipe,
|
|
549
|
+
name: "resolveTranslation"
|
|
550
|
+
},
|
|
551
|
+
{
|
|
552
|
+
kind: "pipe",
|
|
553
|
+
type: TranslateKeyPipe,
|
|
554
|
+
name: "t"
|
|
555
|
+
}
|
|
556
|
+
],
|
|
557
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
558
|
+
});
|
|
559
|
+
};
|
|
560
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
561
|
+
minVersion: "12.0.0",
|
|
562
|
+
version: "22.2.0",
|
|
563
|
+
ngImport: i0,
|
|
564
|
+
type: SparkPoConflictDialogComponent,
|
|
565
|
+
decorators: [{
|
|
566
|
+
type: Component,
|
|
567
|
+
args: [{
|
|
568
|
+
selector: "spark-po-conflict-dialog",
|
|
569
|
+
imports: [
|
|
570
|
+
NgTemplateOutlet,
|
|
571
|
+
BsModalHostComponent,
|
|
572
|
+
BsModalDirective,
|
|
573
|
+
BsModalHeaderDirective,
|
|
574
|
+
BsModalBodyDirective,
|
|
575
|
+
BsModalFooterDirective,
|
|
576
|
+
BsButtonTypeDirective,
|
|
577
|
+
SparkGridCellComponent,
|
|
578
|
+
ResolveTranslationPipe,
|
|
579
|
+
TranslateKeyPipe
|
|
580
|
+
],
|
|
581
|
+
template: `
|
|
582
|
+
<bs-modal [isOpen]="conflicts().length > 0" (isOpenChange)="!$event && cancelled.emit()">
|
|
583
|
+
<div *bsModal>
|
|
584
|
+
<div bsModalHeader>
|
|
585
|
+
<h5 class="modal-title">{{ 'common.conflictTitle' | t }}</h5>
|
|
586
|
+
</div>
|
|
587
|
+
<div bsModalBody class="spark-conflict-dialog">
|
|
588
|
+
<p>{{ 'common.conflictIntro' | t }}</p>
|
|
589
|
+
@if (audit()) {
|
|
590
|
+
<p class="text-muted spark-conflict-audit">{{ audit() }}</p>
|
|
591
|
+
}
|
|
592
|
+
@if (theyChanged()) {
|
|
593
|
+
<p class="text-muted spark-conflict-they-changed">{{ theyChanged() }}</p>
|
|
594
|
+
}
|
|
595
|
+
@for (group of groups(); track group.key) {
|
|
596
|
+
<div class="mb-3 spark-conflict-group">
|
|
597
|
+
@if (group.attribute) {
|
|
598
|
+
<h6>
|
|
599
|
+
<span>{{ group.attribute.label | resolveTranslation:group.attribute.name }}</span>
|
|
600
|
+
@if (group.rowLabel) {
|
|
601
|
+
<span> — {{ group.rowLabel }}</span>
|
|
602
|
+
}
|
|
603
|
+
</h6>
|
|
604
|
+
}
|
|
605
|
+
<table class="table table-sm align-middle mb-0">
|
|
606
|
+
<thead>
|
|
607
|
+
<tr>
|
|
608
|
+
<th>{{ 'common.conflictField' | t }}</th>
|
|
609
|
+
<th>{{ 'common.conflictMine' | t }}</th>
|
|
610
|
+
<th>{{ 'common.conflictTheirs' | t }}</th>
|
|
611
|
+
</tr>
|
|
612
|
+
</thead>
|
|
613
|
+
<tbody>
|
|
614
|
+
@for (entry of group.entries; track entry.conflict.path) {
|
|
615
|
+
<tr class="spark-conflict" [attr.data-path]="entry.conflict.path">
|
|
616
|
+
<th scope="row">
|
|
617
|
+
@if (entry.conflict.kind === 'row') {
|
|
618
|
+
{{ entry.conflict.rowLabel }}
|
|
619
|
+
} @else {
|
|
620
|
+
{{ entry.conflict.attribute.label | resolveTranslation:entry.conflict.attribute.name }}
|
|
621
|
+
}
|
|
622
|
+
</th>
|
|
623
|
+
<td class="spark-conflict-mine-value">
|
|
624
|
+
<label class="d-flex gap-2 align-items-start">
|
|
625
|
+
<input type="radio" class="form-check-input spark-conflict-mine" [name]="entry.conflict.path"
|
|
626
|
+
[checked]="choices()[entry.conflict.path] === 'mine'" (change)="choose(entry.conflict.path, 'mine')" />
|
|
627
|
+
<ng-container [ngTemplateOutlet]="side" [ngTemplateOutletContext]="{ $implicit: entry.mine }" />
|
|
628
|
+
</label>
|
|
629
|
+
</td>
|
|
630
|
+
<td class="spark-conflict-theirs-value">
|
|
631
|
+
<label class="d-flex gap-2 align-items-start">
|
|
632
|
+
<input type="radio" class="form-check-input spark-conflict-theirs" [name]="entry.conflict.path"
|
|
633
|
+
[checked]="choices()[entry.conflict.path] === 'theirs'" (change)="choose(entry.conflict.path, 'theirs')" />
|
|
634
|
+
<ng-container [ngTemplateOutlet]="side" [ngTemplateOutletContext]="{ $implicit: entry.theirs }" />
|
|
635
|
+
</label>
|
|
636
|
+
</td>
|
|
637
|
+
</tr>
|
|
638
|
+
}
|
|
639
|
+
</tbody>
|
|
640
|
+
</table>
|
|
641
|
+
</div>
|
|
642
|
+
}
|
|
643
|
+
</div>
|
|
644
|
+
<div bsModalFooter>
|
|
645
|
+
<button type="button" class="spark-conflict-all-mine" [color]="colors.secondary" (click)="chooseAll('mine')">{{ 'common.conflictKeepAllMine' | t }}</button>
|
|
646
|
+
<button type="button" class="spark-conflict-all-theirs" [color]="colors.secondary" (click)="chooseAll('theirs')">{{ 'common.conflictTakeAllTheirs' | t }}</button>
|
|
647
|
+
<button type="button" class="spark-conflict-cancel" [color]="colors.secondary" (click)="cancelled.emit()">{{ 'common.cancel' | t }}</button>
|
|
648
|
+
<button type="button" class="spark-conflict-apply" [color]="colors.primary" [disabled]="!complete()" (click)="apply()">{{ 'common.conflictApply' | t }}</button>
|
|
649
|
+
</div>
|
|
650
|
+
</div>
|
|
651
|
+
</bs-modal>
|
|
652
|
+
|
|
653
|
+
<!-- One side's value. A row is its attributes cell by cell, the ones the other side differs in marked. -->
|
|
654
|
+
<ng-template #side let-cell>
|
|
655
|
+
@if (cell.fields) {
|
|
656
|
+
<table class="table table-sm table-borderless mb-0 spark-conflict-row-cells">
|
|
657
|
+
<tbody>
|
|
658
|
+
@for (field of cell.fields; track field.attribute.name) {
|
|
659
|
+
<tr [class.spark-conflict-differs]="field.differs" [attr.data-attribute]="field.attribute.name">
|
|
660
|
+
<th scope="row" class="fw-normal text-muted pe-2">{{ field.attribute.label | resolveTranslation:field.attribute.name }}</th>
|
|
661
|
+
<td [class.fw-bold]="field.differs">
|
|
662
|
+
<ng-container [ngTemplateOutlet]="value" [ngTemplateOutletContext]="{ $implicit: field.cell }" />
|
|
663
|
+
</td>
|
|
664
|
+
</tr>
|
|
665
|
+
}
|
|
666
|
+
</tbody>
|
|
667
|
+
</table>
|
|
668
|
+
} @else {
|
|
669
|
+
<span><ng-container [ngTemplateOutlet]="value" [ngTemplateOutletContext]="{ $implicit: cell }" /></span>
|
|
670
|
+
}
|
|
671
|
+
</ng-template>
|
|
672
|
+
<ng-template #value let-cell>
|
|
673
|
+
@if (cell.text !== undefined) { {{ cell.text }} } @else {
|
|
674
|
+
<spark-grid-cell [column]="cell.column" [display]="cell.display" [rendererValue]="cell.rendererValue"
|
|
675
|
+
[item]="cell.item" [chips]="cell.chips" />
|
|
676
|
+
}
|
|
677
|
+
</ng-template>
|
|
678
|
+
`,
|
|
679
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
680
|
+
}]
|
|
681
|
+
}],
|
|
682
|
+
ctorParameters: () => [],
|
|
683
|
+
propDecorators: {
|
|
684
|
+
conflicts: [{
|
|
685
|
+
type: i0.Input,
|
|
686
|
+
args: [{
|
|
687
|
+
isSignal: true,
|
|
688
|
+
alias: "conflicts",
|
|
689
|
+
required: false
|
|
690
|
+
}]
|
|
691
|
+
}],
|
|
692
|
+
referenceLabels: [{
|
|
693
|
+
type: i0.Input,
|
|
694
|
+
args: [{
|
|
695
|
+
isSignal: true,
|
|
696
|
+
alias: "referenceLabels",
|
|
697
|
+
required: false
|
|
698
|
+
}]
|
|
699
|
+
}],
|
|
700
|
+
audit: [{
|
|
701
|
+
type: i0.Input,
|
|
702
|
+
args: [{
|
|
703
|
+
isSignal: true,
|
|
704
|
+
alias: "audit",
|
|
705
|
+
required: false
|
|
706
|
+
}]
|
|
707
|
+
}],
|
|
708
|
+
theyChanged: [{
|
|
709
|
+
type: i0.Input,
|
|
710
|
+
args: [{
|
|
711
|
+
isSignal: true,
|
|
712
|
+
alias: "theyChanged",
|
|
713
|
+
required: false
|
|
714
|
+
}]
|
|
715
|
+
}],
|
|
716
|
+
resolved: [{
|
|
717
|
+
type: i0.Output,
|
|
718
|
+
args: ["resolved"]
|
|
719
|
+
}],
|
|
720
|
+
cancelled: [{
|
|
721
|
+
type: i0.Output,
|
|
722
|
+
args: ["cancelled"]
|
|
723
|
+
}]
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
function summarize(value) {
|
|
727
|
+
if (value === null || value === void 0) return "";
|
|
728
|
+
if (Array.isArray(value)) return value.map(summarize).filter((s) => s !== "").join("; ");
|
|
729
|
+
if (typeof value === "object") return Object.entries(value).filter(([key]) => !isReservedAsDetailKey(key)).map(([, v]) => summarize(v)).filter((s) => s !== "").join(", ");
|
|
730
|
+
return String(value);
|
|
731
|
+
}
|
|
732
|
+
function addReferenceLabelsOf(po, into) {
|
|
733
|
+
for (const attr of po?.attributes ?? []) {
|
|
734
|
+
if (attr.object) addReferenceLabelsOf(attr.object, into);
|
|
735
|
+
for (const row of attr.objects ?? []) addReferenceLabelsOf(row, into);
|
|
736
|
+
for (const [id, label] of Object.entries(attr.breadcrumbs ?? {})) add(into, id, label);
|
|
737
|
+
if (typeof attr.value === "string") add(into, attr.value, attr.breadcrumb);
|
|
738
|
+
}
|
|
739
|
+
return into;
|
|
740
|
+
}
|
|
741
|
+
function addReferenceLabelsOfOptions(options, into) {
|
|
742
|
+
for (const list of options) for (const item of list ?? []) if (item.id) add(into, item.id, item.breadcrumb);
|
|
743
|
+
return into;
|
|
744
|
+
}
|
|
745
|
+
function add(into, id, label) {
|
|
746
|
+
if (id === "" || id in into || typeof label !== "string" || label.trim() === "") return;
|
|
747
|
+
into[id] = label;
|
|
748
|
+
}
|
|
14
749
|
var SparkPoEditComponent = class SparkPoEditComponent {
|
|
15
750
|
route = inject(ActivatedRoute);
|
|
16
751
|
router = inject(Router);
|
|
17
752
|
sparkService = inject(SparkService);
|
|
18
753
|
language = inject(SparkLanguageService);
|
|
754
|
+
showChangedBy = inject(SPARK_CONFIG, { optional: true })?.conflictDialog?.showChangedBy === true;
|
|
19
755
|
saved = output();
|
|
20
756
|
cancelled = output();
|
|
21
757
|
colors = Color;
|
|
22
758
|
entityType = signal(null, ...ngDevMode ? [{ debugName: "entityType" }] : /* istanbul ignore next */ []);
|
|
23
759
|
item = signal(null, ...ngDevMode ? [{ debugName: "item" }] : /* istanbul ignore next */ []);
|
|
760
|
+
formEntityType = computed(() => {
|
|
761
|
+
const type = this.entityType();
|
|
762
|
+
const readOnlyHere = new Set((this.item()?.attributes ?? []).filter((a) => a.isReadOnly).map((a) => a.name));
|
|
763
|
+
if (!type || readOnlyHere.size === 0) return type;
|
|
764
|
+
return {
|
|
765
|
+
...type,
|
|
766
|
+
attributes: type.attributes.map((a) => readOnlyHere.has(a.name) && !a.isReadOnly ? {
|
|
767
|
+
...a,
|
|
768
|
+
isReadOnly: true
|
|
769
|
+
} : a)
|
|
770
|
+
};
|
|
771
|
+
}, ...ngDevMode ? [{ debugName: "formEntityType" }] : /* istanbul ignore next */ []);
|
|
24
772
|
type = "";
|
|
25
773
|
id = "";
|
|
26
774
|
formData = signal({}, ...ngDevMode ? [{ debugName: "formData" }] : /* istanbul ignore next */ []);
|
|
@@ -29,6 +777,19 @@ var SparkPoEditComponent = class SparkPoEditComponent {
|
|
|
29
777
|
isSaving = signal(false, ...ngDevMode ? [{ debugName: "isSaving" }] : /* istanbul ignore next */ []);
|
|
30
778
|
allEntityTypes = signal([], ...ngDevMode ? [{ debugName: "allEntityTypes" }] : /* istanbul ignore next */ []);
|
|
31
779
|
generalErrors = computed(() => this.validationErrors().filter((e) => !e.attributeName), ...ngDevMode ? [{ debugName: "generalErrors" }] : /* istanbul ignore next */ []);
|
|
780
|
+
conflictNoticeText = signal(null, ...ngDevMode ? [{ debugName: "conflictNoticeText" }] : /* istanbul ignore next */ []);
|
|
781
|
+
conflictNotice = computed(() => {
|
|
782
|
+
const text = this.conflictNoticeText();
|
|
783
|
+
if (!text) return null;
|
|
784
|
+
const item = this.item();
|
|
785
|
+
const audit = item ? this.auditLine(item) : null;
|
|
786
|
+
return audit ? `${text} ${audit}` : text;
|
|
787
|
+
}, ...ngDevMode ? [{ debugName: "conflictNotice" }] : /* istanbul ignore next */ []);
|
|
788
|
+
pendingConflict = signal(null, ...ngDevMode ? [{ debugName: "pendingConflict" }] : /* istanbul ignore next */ []);
|
|
789
|
+
pendingConflicts = computed(() => this.pendingConflict()?.result.conflicts ?? [], ...ngDevMode ? [{ debugName: "pendingConflicts" }] : /* istanbul ignore next */ []);
|
|
790
|
+
changedByName = signal(null, ...ngDevMode ? [{ debugName: "changedByName" }] : /* istanbul ignore next */ []);
|
|
791
|
+
form = viewChild(SparkPoFormComponent, ...ngDevMode ? [{ debugName: "form" }] : /* istanbul ignore next */ []);
|
|
792
|
+
locale = inject(LOCALE_ID);
|
|
32
793
|
constructor() {
|
|
33
794
|
this.route.paramMap.pipe(takeUntilDestroyed()).subscribe((params) => this.onParamsChange(params));
|
|
34
795
|
}
|
|
@@ -52,8 +813,10 @@ var SparkPoEditComponent = class SparkPoEditComponent {
|
|
|
52
813
|
}
|
|
53
814
|
}
|
|
54
815
|
initFormData() {
|
|
816
|
+
this.formData.set(this.formDataFrom(this.item()));
|
|
817
|
+
}
|
|
818
|
+
formDataFrom(currentItem) {
|
|
55
819
|
const data = {};
|
|
56
|
-
const currentItem = this.item();
|
|
57
820
|
this.getEditableAttributes().forEach((attr) => {
|
|
58
821
|
const itemAttr = currentItem?.attributes.find((a) => a.name === attr.name);
|
|
59
822
|
if (attr.dataType === "Reference") data[attr.name] = itemAttr?.value ?? null;
|
|
@@ -64,7 +827,7 @@ var SparkPoEditComponent = class SparkPoEditComponent {
|
|
|
64
827
|
else if (isDateDataType(attr.dataType)) data[attr.name] = toDateInputValue(attr.dataType, itemAttr?.value);
|
|
65
828
|
else data[attr.name] = itemAttr?.value ?? "";
|
|
66
829
|
});
|
|
67
|
-
|
|
830
|
+
return data;
|
|
68
831
|
}
|
|
69
832
|
resolveEntityType() {
|
|
70
833
|
const cache = this.allEntityTypes();
|
|
@@ -73,12 +836,13 @@ var SparkPoEditComponent = class SparkPoEditComponent {
|
|
|
73
836
|
}
|
|
74
837
|
getEditableAttributes() {
|
|
75
838
|
const overlay = this.refreshOverlay();
|
|
76
|
-
return this.
|
|
839
|
+
return this.formEntityType()?.attributes.map((a) => applyOverlay(a, overlay[a.name])).filter((a) => a.isVisible && !a.isReadOnly && hasShowedOnFlag(a.showedOn, ShowedOn.PersistentObject)).sort((a, b) => a.order - b.order) || [];
|
|
77
840
|
}
|
|
78
841
|
async onSave() {
|
|
79
842
|
const currentItem = this.item();
|
|
80
843
|
if (!this.entityType() || !currentItem) return;
|
|
81
844
|
this.validationErrors.set([]);
|
|
845
|
+
this.conflictNoticeText.set(null);
|
|
82
846
|
this.isSaving.set(true);
|
|
83
847
|
const resolver = this.resolveEntityType();
|
|
84
848
|
const attributes = currentItem.attributes.map((attr) => {
|
|
@@ -147,12 +911,14 @@ var SparkPoEditComponent = class SparkPoEditComponent {
|
|
|
147
911
|
const error = e;
|
|
148
912
|
const errors = error.error?.result?.errors ?? error.error?.errors;
|
|
149
913
|
if (error.status === 400 && errors) this.validationErrors.set(errors);
|
|
150
|
-
else if (error.status === 409)
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
914
|
+
else if (error.status === 409) {
|
|
915
|
+
this.validationErrors.set([{
|
|
916
|
+
attributeName: "",
|
|
917
|
+
errorMessage: { en: this.language.t("common.concurrencyConflict") },
|
|
918
|
+
ruleType: "error"
|
|
919
|
+
}]);
|
|
920
|
+
await this.resolveConcurrencyConflict();
|
|
921
|
+
} else this.validationErrors.set([{
|
|
156
922
|
attributeName: "",
|
|
157
923
|
errorMessage: { en: error.error?.result?.error || error.error?.error || error.message || "An unexpected error occurred" },
|
|
158
924
|
ruleType: "error"
|
|
@@ -167,6 +933,120 @@ var SparkPoEditComponent = class SparkPoEditComponent {
|
|
|
167
933
|
this.id
|
|
168
934
|
]);
|
|
169
935
|
}
|
|
936
|
+
async resolveConcurrencyConflict() {
|
|
937
|
+
const base = this.item();
|
|
938
|
+
if (!base) return;
|
|
939
|
+
let theirs;
|
|
940
|
+
try {
|
|
941
|
+
theirs = await this.sparkService.get(this.type, this.id);
|
|
942
|
+
} catch {
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
this.changedByName.set(null);
|
|
946
|
+
if (this.showChangedBy) this.lookUpChangedBy(theirs);
|
|
947
|
+
const attributes = this.getEditableAttributes();
|
|
948
|
+
const baseForm = this.formDataFrom(base);
|
|
949
|
+
const theirsForm = this.formDataFrom(theirs);
|
|
950
|
+
const mine = structuredClone(this.formData());
|
|
951
|
+
const schema = {
|
|
952
|
+
attributes,
|
|
953
|
+
resolve: this.resolveEntityType()
|
|
954
|
+
};
|
|
955
|
+
const result = mergeThreeWay(baseForm, mine, theirsForm, schema);
|
|
956
|
+
if (result.conflicts.length === 0) {
|
|
957
|
+
this.rebase(theirs, result.merged, result.theirChanges, "common.conflictMerged", result.contributionNotices);
|
|
958
|
+
return;
|
|
959
|
+
}
|
|
960
|
+
this.pendingConflict.set({
|
|
961
|
+
loaded: base,
|
|
962
|
+
theirs,
|
|
963
|
+
base: baseForm,
|
|
964
|
+
mine,
|
|
965
|
+
theirsForm,
|
|
966
|
+
schema,
|
|
967
|
+
result
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
conflictReferenceLabels = computed(() => {
|
|
971
|
+
const pending = this.pendingConflict();
|
|
972
|
+
if (!pending) return {};
|
|
973
|
+
const labels = {};
|
|
974
|
+
addReferenceLabelsOf(pending.theirs, labels);
|
|
975
|
+
addReferenceLabelsOf(pending.loaded, labels);
|
|
976
|
+
const form = this.form();
|
|
977
|
+
if (form) {
|
|
978
|
+
addReferenceLabelsOfOptions(Object.values(form.referenceOptions()), labels);
|
|
979
|
+
for (const columns of Object.values(form.asDetailReferenceOptions())) addReferenceLabelsOfOptions(Object.values(columns), labels);
|
|
980
|
+
}
|
|
981
|
+
return labels;
|
|
982
|
+
}, ...ngDevMode ? [{ debugName: "conflictReferenceLabels" }] : /* istanbul ignore next */ []);
|
|
983
|
+
async lookUpChangedBy(theirs) {
|
|
984
|
+
this.changedByName.set(null);
|
|
985
|
+
const typeId = this.entityType()?.id;
|
|
986
|
+
if (!typeId) return;
|
|
987
|
+
try {
|
|
988
|
+
if ((await this.sparkService.getPermissions(typeId))?.canViewHistory !== true) return;
|
|
989
|
+
const revisions = await this.sparkService.postEnvelope("/po/revisions", {
|
|
990
|
+
objectTypeId: typeId,
|
|
991
|
+
id: this.id,
|
|
992
|
+
take: 1
|
|
993
|
+
});
|
|
994
|
+
const latest = Array.isArray(revisions) ? revisions[0] : void 0;
|
|
995
|
+
if (!latest || typeof latest.userName !== "string" || latest.userName === "") return;
|
|
996
|
+
if (latest.isCurrent !== true || theirs.etag && latest.changeVector !== theirs.etag) return;
|
|
997
|
+
const by = modifiedBy(theirs);
|
|
998
|
+
if (by && latest.userId && latest.userId !== by) return;
|
|
999
|
+
this.changedByName.set({
|
|
1000
|
+
etag: theirs.etag,
|
|
1001
|
+
name: latest.userName
|
|
1002
|
+
});
|
|
1003
|
+
} catch {}
|
|
1004
|
+
}
|
|
1005
|
+
onConflictResolved(choices) {
|
|
1006
|
+
const pending = this.pendingConflict();
|
|
1007
|
+
if (!pending) return;
|
|
1008
|
+
const result = mergeThreeWay(pending.base, pending.mine, pending.theirsForm, pending.schema, choices);
|
|
1009
|
+
this.pendingConflict.set(null);
|
|
1010
|
+
this.rebase(pending.theirs, result.merged, result.theirChanges, "common.conflictResolved", result.contributionNotices);
|
|
1011
|
+
}
|
|
1012
|
+
onConflictCancelled() {
|
|
1013
|
+
this.pendingConflict.set(null);
|
|
1014
|
+
}
|
|
1015
|
+
rebase(theirs, merged, theirChanges, noticeKey, contributionNotices = []) {
|
|
1016
|
+
this.item.set(theirs);
|
|
1017
|
+
this.formData.set(structuredClone(merged));
|
|
1018
|
+
this.validationErrors.set([]);
|
|
1019
|
+
const fields = [...new Map(theirChanges.map((c) => [c.rootAttribute.name, c.rootAttribute])).values()].map((a) => this.language.resolve(a.label) || a.name);
|
|
1020
|
+
const text = fields.length > 0 ? this.language.t(noticeKey).replace("{fields}", fields.join(", ")) : this.language.t(`${noticeKey}NoFields`);
|
|
1021
|
+
const rows = [...new Set(contributionNotices.map((n) => n.rowLabel))];
|
|
1022
|
+
const contributions = rows.length > 0 ? " " + this.language.t("contributions.theirsKept").replace("{rows}", rows.join(", ")) : "";
|
|
1023
|
+
this.conflictNoticeText.set(text + contributions);
|
|
1024
|
+
}
|
|
1025
|
+
theyChanged = computed(() => {
|
|
1026
|
+
const pending = this.pendingConflict();
|
|
1027
|
+
if (!pending || pending.result.theirChanges.length === 0) return null;
|
|
1028
|
+
const fields = [...new Map(pending.result.theirChanges.map((c) => [c.rootAttribute.name, c.rootAttribute])).values()].map((a) => this.language.resolve(a.label) || a.name);
|
|
1029
|
+
return this.language.t("common.conflictTheyChanged").replace("{fields}", fields.join(", "));
|
|
1030
|
+
}, ...ngDevMode ? [{ debugName: "theyChanged" }] : /* istanbul ignore next */ []);
|
|
1031
|
+
conflictAudit = computed(() => {
|
|
1032
|
+
const pending = this.pendingConflict();
|
|
1033
|
+
return pending ? this.auditLine(pending.theirs) : null;
|
|
1034
|
+
}, ...ngDevMode ? [{ debugName: "conflictAudit" }] : /* istanbul ignore next */ []);
|
|
1035
|
+
auditLine(po) {
|
|
1036
|
+
const resolved = this.changedByName();
|
|
1037
|
+
const at = po.attributes.find((a) => a.name === "ModifiedAt")?.value;
|
|
1038
|
+
const user = this.showChangedBy && resolved && resolved.etag === po.etag ? resolved.name : null;
|
|
1039
|
+
let time = null;
|
|
1040
|
+
if (at) try {
|
|
1041
|
+
time = formatDate(at, "medium", this.locale);
|
|
1042
|
+
} catch {
|
|
1043
|
+
time = String(at);
|
|
1044
|
+
}
|
|
1045
|
+
if (user && time) return this.language.t("common.conflictChangedByAt").replace("{user}", user).replace("{time}", time);
|
|
1046
|
+
if (user) return this.language.t("common.conflictChangedBy").replace("{user}", user);
|
|
1047
|
+
if (time) return this.language.t("common.conflictChangedAt").replace("{time}", time);
|
|
1048
|
+
return null;
|
|
1049
|
+
}
|
|
170
1050
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
171
1051
|
minVersion: "12.0.0",
|
|
172
1052
|
version: "22.2.0",
|
|
@@ -185,8 +1065,15 @@ var SparkPoEditComponent = class SparkPoEditComponent {
|
|
|
185
1065
|
saved: "saved",
|
|
186
1066
|
cancelled: "cancelled"
|
|
187
1067
|
},
|
|
1068
|
+
viewQueries: [{
|
|
1069
|
+
propertyName: "form",
|
|
1070
|
+
first: true,
|
|
1071
|
+
predicate: SparkPoFormComponent,
|
|
1072
|
+
descendants: true,
|
|
1073
|
+
isSignal: true
|
|
1074
|
+
}],
|
|
188
1075
|
ngImport: i0,
|
|
189
|
-
template: "<bs-container>\n<div class=\"container\">\n @for (error of generalErrors(); track error.errorMessage) {\n <bs-alert [type]=\"colors.danger\" class=\"mb-3\">\n {{ error.errorMessage | resolveTranslation }}\n </bs-alert>\n }\n\n @if (entityType(); as et) {\n @if (item()) {\n <h2 class=\"mb-4\">{{ 'common.edit' | t }} {{ (et.description | resolveTranslation) || et.name }}</h2>\n\n <spark-po-form\n [entityType]=\"et\"\n [(formData)]=\"formData\"\n [(refreshOverlay)]=\"refreshOverlay\"\n [objectTypeId]=\"type\"\n [objectId]=\"id\"\n [validationErrors]=\"validationErrors()\"\n [showButtons]=\"true\"\n [isSaving]=\"isSaving()\"\n [parentId]=\"id\"\n [parentType]=\"type\"\n (save)=\"onSave()\"\n (cancel)=\"onCancel()\">\n </spark-po-form>\n }\n } @else {\n <div class=\"text-center p-5\">\n <bs-spinner />\n </div>\n }\n</div>\n</bs-container>\n",
|
|
1076
|
+
template: "<bs-container>\n<div class=\"container\">\n @for (error of generalErrors(); track error.errorMessage) {\n <bs-alert [type]=\"colors.danger\" class=\"mb-3\">\n {{ error.errorMessage | resolveTranslation }}\n </bs-alert>\n }\n\n @if (conflictNotice(); as notice) {\n <bs-alert [type]=\"colors.info\" class=\"mb-3 spark-conflict-notice\">\n {{ notice }}\n </bs-alert>\n }\n\n <spark-po-conflict-dialog\n [conflicts]=\"pendingConflicts()\"\n [referenceLabels]=\"conflictReferenceLabels()\"\n [audit]=\"conflictAudit()\"\n [theyChanged]=\"theyChanged()\"\n (resolved)=\"onConflictResolved($event)\"\n (cancelled)=\"onConflictCancelled()\" />\n\n @if (entityType(); as et) {\n @if (item()) {\n <h2 class=\"mb-4\">{{ 'common.edit' | t }} {{ (et.description | resolveTranslation) || et.name }}</h2>\n\n <spark-po-form\n [entityType]=\"formEntityType() ?? et\"\n [(formData)]=\"formData\"\n [(refreshOverlay)]=\"refreshOverlay\"\n [objectTypeId]=\"type\"\n [objectId]=\"id\"\n [validationErrors]=\"validationErrors()\"\n [showButtons]=\"true\"\n [isSaving]=\"isSaving()\"\n [parentId]=\"id\"\n [parentType]=\"type\"\n (save)=\"onSave()\"\n (cancel)=\"onCancel()\">\n </spark-po-form>\n }\n } @else {\n <div class=\"text-center p-5\">\n <bs-spinner />\n </div>\n }\n</div>\n</bs-container>\n",
|
|
190
1077
|
dependencies: [
|
|
191
1078
|
{
|
|
192
1079
|
kind: "ngmodule",
|
|
@@ -226,6 +1113,8 @@ var SparkPoEditComponent = class SparkPoEditComponent {
|
|
|
226
1113
|
"isSaving",
|
|
227
1114
|
"parentId",
|
|
228
1115
|
"parentType",
|
|
1116
|
+
"referenceParentId",
|
|
1117
|
+
"referenceParentType",
|
|
229
1118
|
"objectTypeId",
|
|
230
1119
|
"objectId",
|
|
231
1120
|
"triggerPathPrefix",
|
|
@@ -240,6 +1129,18 @@ var SparkPoEditComponent = class SparkPoEditComponent {
|
|
|
240
1129
|
"refreshOverlayChange"
|
|
241
1130
|
]
|
|
242
1131
|
},
|
|
1132
|
+
{
|
|
1133
|
+
kind: "component",
|
|
1134
|
+
type: SparkPoConflictDialogComponent,
|
|
1135
|
+
selector: "spark-po-conflict-dialog",
|
|
1136
|
+
inputs: [
|
|
1137
|
+
"conflicts",
|
|
1138
|
+
"referenceLabels",
|
|
1139
|
+
"audit",
|
|
1140
|
+
"theyChanged"
|
|
1141
|
+
],
|
|
1142
|
+
outputs: ["resolved", "cancelled"]
|
|
1143
|
+
},
|
|
243
1144
|
{
|
|
244
1145
|
kind: "pipe",
|
|
245
1146
|
type: ResolveTranslationPipe,
|
|
@@ -269,11 +1170,12 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
269
1170
|
BsContainerComponent,
|
|
270
1171
|
BsSpinnerComponent,
|
|
271
1172
|
SparkPoFormComponent,
|
|
1173
|
+
SparkPoConflictDialogComponent,
|
|
272
1174
|
ResolveTranslationPipe,
|
|
273
1175
|
TranslateKeyPipe
|
|
274
1176
|
],
|
|
275
1177
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
276
|
-
template: "<bs-container>\n<div class=\"container\">\n @for (error of generalErrors(); track error.errorMessage) {\n <bs-alert [type]=\"colors.danger\" class=\"mb-3\">\n {{ error.errorMessage | resolveTranslation }}\n </bs-alert>\n }\n\n @if (entityType(); as et) {\n @if (item()) {\n <h2 class=\"mb-4\">{{ 'common.edit' | t }} {{ (et.description | resolveTranslation) || et.name }}</h2>\n\n <spark-po-form\n [entityType]=\"et\"\n [(formData)]=\"formData\"\n [(refreshOverlay)]=\"refreshOverlay\"\n [objectTypeId]=\"type\"\n [objectId]=\"id\"\n [validationErrors]=\"validationErrors()\"\n [showButtons]=\"true\"\n [isSaving]=\"isSaving()\"\n [parentId]=\"id\"\n [parentType]=\"type\"\n (save)=\"onSave()\"\n (cancel)=\"onCancel()\">\n </spark-po-form>\n }\n } @else {\n <div class=\"text-center p-5\">\n <bs-spinner />\n </div>\n }\n</div>\n</bs-container>\n"
|
|
1178
|
+
template: "<bs-container>\n<div class=\"container\">\n @for (error of generalErrors(); track error.errorMessage) {\n <bs-alert [type]=\"colors.danger\" class=\"mb-3\">\n {{ error.errorMessage | resolveTranslation }}\n </bs-alert>\n }\n\n @if (conflictNotice(); as notice) {\n <bs-alert [type]=\"colors.info\" class=\"mb-3 spark-conflict-notice\">\n {{ notice }}\n </bs-alert>\n }\n\n <spark-po-conflict-dialog\n [conflicts]=\"pendingConflicts()\"\n [referenceLabels]=\"conflictReferenceLabels()\"\n [audit]=\"conflictAudit()\"\n [theyChanged]=\"theyChanged()\"\n (resolved)=\"onConflictResolved($event)\"\n (cancelled)=\"onConflictCancelled()\" />\n\n @if (entityType(); as et) {\n @if (item()) {\n <h2 class=\"mb-4\">{{ 'common.edit' | t }} {{ (et.description | resolveTranslation) || et.name }}</h2>\n\n <spark-po-form\n [entityType]=\"formEntityType() ?? et\"\n [(formData)]=\"formData\"\n [(refreshOverlay)]=\"refreshOverlay\"\n [objectTypeId]=\"type\"\n [objectId]=\"id\"\n [validationErrors]=\"validationErrors()\"\n [showButtons]=\"true\"\n [isSaving]=\"isSaving()\"\n [parentId]=\"id\"\n [parentType]=\"type\"\n (save)=\"onSave()\"\n (cancel)=\"onCancel()\">\n </spark-po-form>\n }\n } @else {\n <div class=\"text-center p-5\">\n <bs-spinner />\n </div>\n }\n</div>\n</bs-container>\n"
|
|
277
1179
|
}]
|
|
278
1180
|
}],
|
|
279
1181
|
ctorParameters: () => [],
|
|
@@ -285,9 +1187,17 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
285
1187
|
cancelled: [{
|
|
286
1188
|
type: i0.Output,
|
|
287
1189
|
args: ["cancelled"]
|
|
1190
|
+
}],
|
|
1191
|
+
form: [{
|
|
1192
|
+
type: i0.ViewChild,
|
|
1193
|
+
args: [i0.forwardRef(() => SparkPoFormComponent), { isSignal: true }]
|
|
288
1194
|
}]
|
|
289
1195
|
}
|
|
290
1196
|
});
|
|
291
|
-
|
|
1197
|
+
function modifiedBy(po) {
|
|
1198
|
+
const by = po.attributes.find((a) => a.name === "ModifiedBy")?.value;
|
|
1199
|
+
return typeof by === "string" && by !== "" ? by : null;
|
|
1200
|
+
}
|
|
1201
|
+
export { CONTRIBUTION_ROW_METADATA, SparkPoConflictDialogComponent, SparkPoEditComponent, addReferenceLabelsOf, addReferenceLabelsOfOptions, contributionRowIsOwn, mergeThreeWay };
|
|
292
1202
|
|
|
293
1203
|
//# sourceMappingURL=mintplayer-ng-spark-po-edit.mjs.map
|