@mintplayer/ng-spark 0.1.1 → 0.2.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/fesm2022/mintplayer-ng-spark-icon.mjs +35 -0
- package/fesm2022/mintplayer-ng-spark-icon.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-models.mjs +48 -0
- package/fesm2022/mintplayer-ng-spark-models.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-pipes.mjs +427 -0
- package/fesm2022/mintplayer-ng-spark-pipes.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-po-create.mjs +121 -0
- package/fesm2022/mintplayer-ng-spark-po-create.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs +368 -0
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-po-edit.mjs +139 -0
- package/fesm2022/mintplayer-ng-spark-po-edit.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-po-form.mjs +393 -0
- package/fesm2022/mintplayer-ng-spark-po-form.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-query-list.mjs +392 -0
- package/fesm2022/mintplayer-ng-spark-query-list.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-renderers.mjs +25 -0
- package/fesm2022/mintplayer-ng-spark-renderers.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs +87 -0
- package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-routes.mjs +31 -0
- package/fesm2022/mintplayer-ng-spark-routes.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-services.mjs +348 -0
- package/fesm2022/mintplayer-ng-spark-services.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark.mjs +17 -2262
- package/fesm2022/mintplayer-ng-spark.mjs.map +1 -1
- package/package.json +49 -1
- package/types/mintplayer-ng-spark-icon.d.ts +13 -0
- package/types/mintplayer-ng-spark-models.d.ts +275 -0
- package/types/mintplayer-ng-spark-pipes.d.ts +143 -0
- package/types/mintplayer-ng-spark-po-create.d.ts +29 -0
- package/types/mintplayer-ng-spark-po-detail.d.ts +88 -0
- package/types/mintplayer-ng-spark-po-edit.d.ts +31 -0
- package/types/mintplayer-ng-spark-po-form.d.ts +84 -0
- package/types/mintplayer-ng-spark-query-list.d.ts +60 -0
- package/types/mintplayer-ng-spark-renderers.d.ts +68 -0
- package/types/mintplayer-ng-spark-retry-action-modal.d.ts +14 -0
- package/types/mintplayer-ng-spark-routes.d.ts +12 -0
- package/types/mintplayer-ng-spark-services.d.ts +100 -0
- package/types/mintplayer-ng-spark.d.ts +3 -855
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, input, model, output, signal, computed, effect, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import * as i1 from '@angular/common';
|
|
4
|
+
import { CommonModule, NgTemplateOutlet, NgComponentOutlet } from '@angular/common';
|
|
5
|
+
import * as i2 from '@angular/forms';
|
|
6
|
+
import { FormsModule } from '@angular/forms';
|
|
7
|
+
import { Color } from '@mintplayer/ng-bootstrap';
|
|
8
|
+
import { BsCardComponent, BsCardHeaderComponent } from '@mintplayer/ng-bootstrap/card';
|
|
9
|
+
import { BsFormComponent, BsFormControlDirective } from '@mintplayer/ng-bootstrap/form';
|
|
10
|
+
import { BsGridComponent, BsGridRowDirective, BsGridColumnDirective, BsGridColDirective, BsColFormLabelDirective } from '@mintplayer/ng-bootstrap/grid';
|
|
11
|
+
import { BsInputGroupComponent } from '@mintplayer/ng-bootstrap/input-group';
|
|
12
|
+
import { BsButtonTypeDirective } from '@mintplayer/ng-bootstrap/button-type';
|
|
13
|
+
import { BsSelectComponent, BsSelectOption } from '@mintplayer/ng-bootstrap/select';
|
|
14
|
+
import { BsModalHostComponent, BsModalDirective, BsModalHeaderDirective, BsModalBodyDirective, BsModalFooterDirective } from '@mintplayer/ng-bootstrap/modal';
|
|
15
|
+
import { DatatableSettings, BsDatatableComponent, BsDatatableColumnDirective, BsRowTemplateDirective } from '@mintplayer/ng-bootstrap/datatable';
|
|
16
|
+
import { BsToggleButtonComponent } from '@mintplayer/ng-bootstrap/toggle-button';
|
|
17
|
+
import { BsSpinnerComponent } from '@mintplayer/ng-bootstrap/spinner';
|
|
18
|
+
import { BsTabControlComponent, BsTabPageComponent, BsTabPageHeaderDirective } from '@mintplayer/ng-bootstrap/tab-control';
|
|
19
|
+
import { BsTableComponent } from '@mintplayer/ng-bootstrap/table';
|
|
20
|
+
import { SparkService, SparkLanguageService } from '@mintplayer/ng-spark/services';
|
|
21
|
+
import { TranslateKeyPipe, ResolveTranslationPipe, InputTypePipe, LookupDisplayValuePipe, LookupDisplayTypePipe, LookupOptionsPipe, ReferenceDisplayValuePipe, AsDetailDisplayValuePipe, AsDetailTypePipe, AsDetailColumnsPipe, AsDetailCellValuePipe, CanCreateDetailRowPipe, CanDeleteDetailRowPipe, InlineRefOptionsPipe, ReferenceAttrValuePipe, ErrorForAttributePipe } from '@mintplayer/ng-spark/pipes';
|
|
22
|
+
import { ELookupDisplayType, hasShowedOnFlag, ShowedOn, resolveTranslation } from '@mintplayer/ng-spark/models';
|
|
23
|
+
import { SparkIconComponent } from '@mintplayer/ng-spark/icon';
|
|
24
|
+
import { SPARK_ATTRIBUTE_RENDERERS } from '@mintplayer/ng-spark/renderers';
|
|
25
|
+
|
|
26
|
+
class SparkPoFormComponent {
|
|
27
|
+
sparkService = inject(SparkService);
|
|
28
|
+
translations = inject(SparkLanguageService);
|
|
29
|
+
rendererRegistry = inject(SPARK_ATTRIBUTE_RENDERERS);
|
|
30
|
+
entityType = input(null, ...(ngDevMode ? [{ debugName: "entityType" }] : []));
|
|
31
|
+
formData = model({}, ...(ngDevMode ? [{ debugName: "formData" }] : []));
|
|
32
|
+
validationErrors = input([], ...(ngDevMode ? [{ debugName: "validationErrors" }] : []));
|
|
33
|
+
showButtons = input(false, ...(ngDevMode ? [{ debugName: "showButtons" }] : []));
|
|
34
|
+
isSaving = input(false, ...(ngDevMode ? [{ debugName: "isSaving" }] : []));
|
|
35
|
+
parentId = input(undefined, ...(ngDevMode ? [{ debugName: "parentId" }] : []));
|
|
36
|
+
parentType = input(undefined, ...(ngDevMode ? [{ debugName: "parentType" }] : []));
|
|
37
|
+
save = output();
|
|
38
|
+
cancel = output();
|
|
39
|
+
colors = Color;
|
|
40
|
+
referenceOptions = signal({}, ...(ngDevMode ? [{ debugName: "referenceOptions" }] : []));
|
|
41
|
+
asDetailTypes = signal({}, ...(ngDevMode ? [{ debugName: "asDetailTypes" }] : []));
|
|
42
|
+
lookupReferenceOptions = signal({}, ...(ngDevMode ? [{ debugName: "lookupReferenceOptions" }] : []));
|
|
43
|
+
// Modal state for AsDetail object editing
|
|
44
|
+
editingAsDetailAttr = signal(null, ...(ngDevMode ? [{ debugName: "editingAsDetailAttr" }] : []));
|
|
45
|
+
asDetailFormData = signal({}, ...(ngDevMode ? [{ debugName: "asDetailFormData" }] : []));
|
|
46
|
+
showAsDetailModal = signal(false, ...(ngDevMode ? [{ debugName: "showAsDetailModal" }] : []));
|
|
47
|
+
editingArrayIndex = signal(null, ...(ngDevMode ? [{ debugName: "editingArrayIndex" }] : []));
|
|
48
|
+
// Permissions for array AsDetail entity types
|
|
49
|
+
asDetailPermissions = signal({}, ...(ngDevMode ? [{ debugName: "asDetailPermissions" }] : []));
|
|
50
|
+
// Reference options for columns within array AsDetail types (keyed by parent attr name, then column name)
|
|
51
|
+
asDetailReferenceOptions = signal({}, ...(ngDevMode ? [{ debugName: "asDetailReferenceOptions" }] : []));
|
|
52
|
+
// Modal state for Reference selection
|
|
53
|
+
editingReferenceAttr = signal(null, ...(ngDevMode ? [{ debugName: "editingReferenceAttr" }] : []));
|
|
54
|
+
showReferenceModal = signal(false, ...(ngDevMode ? [{ debugName: "showReferenceModal" }] : []));
|
|
55
|
+
referenceModalItems = signal([], ...(ngDevMode ? [{ debugName: "referenceModalItems" }] : []));
|
|
56
|
+
referenceModalEntityType = signal(null, ...(ngDevMode ? [{ debugName: "referenceModalEntityType" }] : []));
|
|
57
|
+
referenceModalPagination = signal(undefined, ...(ngDevMode ? [{ debugName: "referenceModalPagination" }] : []));
|
|
58
|
+
referenceModalSettings = signal(new DatatableSettings({
|
|
59
|
+
perPage: { values: [10, 25, 50], selected: 10 },
|
|
60
|
+
page: { values: [1], selected: 1 },
|
|
61
|
+
sortColumns: []
|
|
62
|
+
}), ...(ngDevMode ? [{ debugName: "referenceModalSettings" }] : []));
|
|
63
|
+
referenceSearchTerm = '';
|
|
64
|
+
// Modal state for LookupReference selection (Modal display type)
|
|
65
|
+
editingLookupAttr = signal(null, ...(ngDevMode ? [{ debugName: "editingLookupAttr" }] : []));
|
|
66
|
+
showLookupModal = signal(false, ...(ngDevMode ? [{ debugName: "showLookupModal" }] : []));
|
|
67
|
+
lookupModalItems = signal([], ...(ngDevMode ? [{ debugName: "lookupModalItems" }] : []));
|
|
68
|
+
lookupSearchTerm = signal('', ...(ngDevMode ? [{ debugName: "lookupSearchTerm" }] : []));
|
|
69
|
+
ELookupDisplayType = ELookupDisplayType;
|
|
70
|
+
editableAttributes = computed(() => {
|
|
71
|
+
return this.entityType()?.attributes
|
|
72
|
+
.filter(a => a.isVisible && !a.isReadOnly && hasShowedOnFlag(a.showedOn, ShowedOn.PersistentObject))
|
|
73
|
+
.sort((a, b) => a.order - b.order) || [];
|
|
74
|
+
}, ...(ngDevMode ? [{ debugName: "editableAttributes" }] : []));
|
|
75
|
+
static DEFAULT_TAB = { id: '__default__', name: 'Algemeen', label: { nl: 'Algemeen', en: 'General' }, order: 0 };
|
|
76
|
+
ungroupedAttributes = computed(() => {
|
|
77
|
+
const attrs = this.editableAttributes();
|
|
78
|
+
const groupIds = new Set((this.entityType()?.groups || []).map(g => g.id));
|
|
79
|
+
return attrs.filter(a => !a.group || !groupIds.has(a.group));
|
|
80
|
+
}, ...(ngDevMode ? [{ debugName: "ungroupedAttributes" }] : []));
|
|
81
|
+
resolvedTabs = computed(() => {
|
|
82
|
+
const et = this.entityType();
|
|
83
|
+
const definedTabs = et?.tabs?.length ? [...et.tabs].sort((a, b) => a.order - b.order) : [];
|
|
84
|
+
const hasUngroupedAttrs = this.ungroupedAttributes().length > 0;
|
|
85
|
+
const hasUntabbedGroups = (et?.groups || []).some(g => !g.tab);
|
|
86
|
+
if (hasUngroupedAttrs || hasUntabbedGroups || definedTabs.length === 0) {
|
|
87
|
+
return [SparkPoFormComponent.DEFAULT_TAB, ...definedTabs];
|
|
88
|
+
}
|
|
89
|
+
return definedTabs;
|
|
90
|
+
}, ...(ngDevMode ? [{ debugName: "resolvedTabs" }] : []));
|
|
91
|
+
groupsForTab(tab) {
|
|
92
|
+
const groups = this.entityType()?.groups || [];
|
|
93
|
+
if (tab.id === '__default__') {
|
|
94
|
+
return groups.filter(g => !g.tab).sort((a, b) => a.order - b.order);
|
|
95
|
+
}
|
|
96
|
+
return groups.filter(g => g.tab === tab.id).sort((a, b) => a.order - b.order);
|
|
97
|
+
}
|
|
98
|
+
attrsForGroup(group) {
|
|
99
|
+
return this.editableAttributes().filter(a => a.group === group.id);
|
|
100
|
+
}
|
|
101
|
+
referenceVisibleAttributes = computed(() => {
|
|
102
|
+
return this.referenceModalEntityType()?.attributes
|
|
103
|
+
.filter(a => a.isVisible)
|
|
104
|
+
.sort((a, b) => a.order - b.order) || [];
|
|
105
|
+
}, ...(ngDevMode ? [{ debugName: "referenceVisibleAttributes" }] : []));
|
|
106
|
+
filteredLookupItems = computed(() => {
|
|
107
|
+
if (!this.lookupSearchTerm().trim()) {
|
|
108
|
+
return this.lookupModalItems();
|
|
109
|
+
}
|
|
110
|
+
const term = this.lookupSearchTerm().toLowerCase().trim();
|
|
111
|
+
return this.lookupModalItems().filter(item => {
|
|
112
|
+
const translation = resolveTranslation(item.values);
|
|
113
|
+
return translation.toLowerCase().includes(term) || item.key.toLowerCase().includes(term);
|
|
114
|
+
});
|
|
115
|
+
}, ...(ngDevMode ? [{ debugName: "filteredLookupItems" }] : []));
|
|
116
|
+
constructor() {
|
|
117
|
+
effect(() => {
|
|
118
|
+
const et = this.entityType();
|
|
119
|
+
const _pid = this.parentId();
|
|
120
|
+
const _ptype = this.parentType();
|
|
121
|
+
if (et) {
|
|
122
|
+
this.loadReferenceOptions();
|
|
123
|
+
this.loadAsDetailTypes();
|
|
124
|
+
this.loadLookupReferenceOptions();
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
toRecord(entries) {
|
|
129
|
+
const result = {};
|
|
130
|
+
for (const [key, value] of entries) {
|
|
131
|
+
result[key] = value;
|
|
132
|
+
}
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
async loadReferenceOptions() {
|
|
136
|
+
const refAttrs = this.editableAttributes().filter(a => a.dataType === 'Reference' && a.query);
|
|
137
|
+
if (refAttrs.length === 0)
|
|
138
|
+
return;
|
|
139
|
+
const entries = await Promise.all(refAttrs.filter(a => a.query).map(async (attr) => {
|
|
140
|
+
const result = await this.sparkService.executeQueryByName(attr.query, {
|
|
141
|
+
parentId: this.parentId(),
|
|
142
|
+
parentType: this.parentType(),
|
|
143
|
+
});
|
|
144
|
+
return [attr.name, result.data];
|
|
145
|
+
}));
|
|
146
|
+
this.referenceOptions.set(this.toRecord(entries));
|
|
147
|
+
}
|
|
148
|
+
async loadAsDetailTypes() {
|
|
149
|
+
const asDetailAttrs = this.editableAttributes().filter(a => a.dataType === 'AsDetail' && a.asDetailType);
|
|
150
|
+
if (asDetailAttrs.length === 0)
|
|
151
|
+
return;
|
|
152
|
+
const types = await this.sparkService.getEntityTypes();
|
|
153
|
+
const newAsDetailTypes = {};
|
|
154
|
+
for (const attr of asDetailAttrs) {
|
|
155
|
+
const asDetailType = types.find(t => t.clrType === attr.asDetailType);
|
|
156
|
+
if (asDetailType) {
|
|
157
|
+
newAsDetailTypes[attr.name] = asDetailType;
|
|
158
|
+
if (attr.isArray) {
|
|
159
|
+
const perms = await this.sparkService.getPermissions(asDetailType.id);
|
|
160
|
+
this.asDetailPermissions.update(prev => ({ ...prev, [attr.name]: perms }));
|
|
161
|
+
const refCols = asDetailType.attributes.filter(a => a.dataType === 'Reference' && a.query);
|
|
162
|
+
if (refCols.length > 0) {
|
|
163
|
+
const refEntries = await Promise.all(refCols.filter(c => c.query).map(async (col) => {
|
|
164
|
+
const result = await this.sparkService.executeQueryByName(col.query, {
|
|
165
|
+
parentId: this.parentId(),
|
|
166
|
+
parentType: this.parentType(),
|
|
167
|
+
});
|
|
168
|
+
return [col.name, result.data];
|
|
169
|
+
}));
|
|
170
|
+
this.asDetailReferenceOptions.update(prev => ({ ...prev, [attr.name]: this.toRecord(refEntries) }));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
this.asDetailTypes.set(newAsDetailTypes);
|
|
176
|
+
}
|
|
177
|
+
async loadLookupReferenceOptions() {
|
|
178
|
+
const lookupAttrs = this.editableAttributes().filter(a => a.lookupReferenceType);
|
|
179
|
+
if (lookupAttrs.length === 0)
|
|
180
|
+
return;
|
|
181
|
+
const lookupNames = [...new Set(lookupAttrs.map(a => a.lookupReferenceType))];
|
|
182
|
+
const entries = await Promise.all(lookupNames.map(async (name) => {
|
|
183
|
+
const ref = await this.sparkService.getLookupReference(name);
|
|
184
|
+
return [name, ref];
|
|
185
|
+
}));
|
|
186
|
+
this.lookupReferenceOptions.set(this.toRecord(entries));
|
|
187
|
+
}
|
|
188
|
+
getReferenceOptions(attr) {
|
|
189
|
+
return this.referenceOptions()[attr.name] || [];
|
|
190
|
+
}
|
|
191
|
+
getLookupOptions(attr) {
|
|
192
|
+
const lookupRef = attr.lookupReferenceType ? this.lookupReferenceOptions()[attr.lookupReferenceType] : null;
|
|
193
|
+
return lookupRef?.values.filter(v => v.isActive) || [];
|
|
194
|
+
}
|
|
195
|
+
// LookupReference modal methods
|
|
196
|
+
openLookupSelector(attr) {
|
|
197
|
+
this.editingLookupAttr.set(attr);
|
|
198
|
+
this.lookupSearchTerm.set('');
|
|
199
|
+
this.lookupModalItems.set(this.getLookupOptions(attr));
|
|
200
|
+
this.showLookupModal.set(true);
|
|
201
|
+
}
|
|
202
|
+
selectLookupItem(item) {
|
|
203
|
+
const attr = this.editingLookupAttr();
|
|
204
|
+
if (attr) {
|
|
205
|
+
const data = { ...this.formData() };
|
|
206
|
+
data[attr.name] = item.key;
|
|
207
|
+
this.formData.set(data);
|
|
208
|
+
}
|
|
209
|
+
this.closeLookupModal();
|
|
210
|
+
}
|
|
211
|
+
closeLookupModal() {
|
|
212
|
+
this.showLookupModal.set(false);
|
|
213
|
+
this.editingLookupAttr.set(null);
|
|
214
|
+
this.lookupModalItems.set([]);
|
|
215
|
+
this.lookupSearchTerm.set('');
|
|
216
|
+
}
|
|
217
|
+
getEditRendererComponent(attr) {
|
|
218
|
+
if (!attr.renderer)
|
|
219
|
+
return null;
|
|
220
|
+
const reg = this.rendererRegistry.find(r => r.name === attr.renderer);
|
|
221
|
+
return reg?.editComponent ?? null;
|
|
222
|
+
}
|
|
223
|
+
getEditRendererInputs(attr) {
|
|
224
|
+
return {
|
|
225
|
+
value: this.formData()[attr.name],
|
|
226
|
+
attribute: attr,
|
|
227
|
+
options: attr.rendererOptions,
|
|
228
|
+
valueChange: (newValue) => {
|
|
229
|
+
const data = { ...this.formData() };
|
|
230
|
+
data[attr.name] = newValue;
|
|
231
|
+
this.formData.set(data);
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
hasError(attrName) {
|
|
236
|
+
return this.validationErrors().some(e => e.attributeName === attrName);
|
|
237
|
+
}
|
|
238
|
+
onFieldChange() {
|
|
239
|
+
this.formData.set({ ...this.formData() });
|
|
240
|
+
}
|
|
241
|
+
onSave() {
|
|
242
|
+
this.save.emit();
|
|
243
|
+
}
|
|
244
|
+
onCancel() {
|
|
245
|
+
this.cancel.emit();
|
|
246
|
+
}
|
|
247
|
+
// AsDetail object modal methods
|
|
248
|
+
openAsDetailEditor(attr) {
|
|
249
|
+
this.editingAsDetailAttr.set(attr);
|
|
250
|
+
this.editingArrayIndex.set(null);
|
|
251
|
+
this.asDetailFormData.set({ ...(this.formData()[attr.name] || {}) });
|
|
252
|
+
this.showAsDetailModal.set(true);
|
|
253
|
+
}
|
|
254
|
+
saveAsDetailObject() {
|
|
255
|
+
const attr = this.editingAsDetailAttr();
|
|
256
|
+
if (attr) {
|
|
257
|
+
const data = { ...this.formData() };
|
|
258
|
+
if (attr.isArray) {
|
|
259
|
+
const arr = [...(data[attr.name] || [])];
|
|
260
|
+
const idx = this.editingArrayIndex();
|
|
261
|
+
if (idx !== null) {
|
|
262
|
+
arr[idx] = { ...this.asDetailFormData() };
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
arr.push({ ...this.asDetailFormData() });
|
|
266
|
+
}
|
|
267
|
+
data[attr.name] = arr;
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
data[attr.name] = { ...this.asDetailFormData() };
|
|
271
|
+
}
|
|
272
|
+
this.formData.set(data);
|
|
273
|
+
}
|
|
274
|
+
this.closeAsDetailModal();
|
|
275
|
+
}
|
|
276
|
+
closeAsDetailModal() {
|
|
277
|
+
this.showAsDetailModal.set(false);
|
|
278
|
+
this.editingAsDetailAttr.set(null);
|
|
279
|
+
this.editingArrayIndex.set(null);
|
|
280
|
+
this.asDetailFormData.set({});
|
|
281
|
+
}
|
|
282
|
+
// Inline AsDetail methods
|
|
283
|
+
addInlineRow(attr) {
|
|
284
|
+
const data = { ...this.formData() };
|
|
285
|
+
const arr = [...(data[attr.name] || [])];
|
|
286
|
+
arr.push({});
|
|
287
|
+
data[attr.name] = arr;
|
|
288
|
+
this.formData.set(data);
|
|
289
|
+
}
|
|
290
|
+
// Array AsDetail methods
|
|
291
|
+
addArrayItem(attr) {
|
|
292
|
+
this.editingAsDetailAttr.set(attr);
|
|
293
|
+
this.editingArrayIndex.set(null);
|
|
294
|
+
this.asDetailFormData.set({});
|
|
295
|
+
this.showAsDetailModal.set(true);
|
|
296
|
+
}
|
|
297
|
+
editArrayItem(attr, index) {
|
|
298
|
+
this.editingAsDetailAttr.set(attr);
|
|
299
|
+
this.editingArrayIndex.set(index);
|
|
300
|
+
const arr = this.formData()[attr.name] || [];
|
|
301
|
+
this.asDetailFormData.set({ ...(arr[index] || {}) });
|
|
302
|
+
this.showAsDetailModal.set(true);
|
|
303
|
+
}
|
|
304
|
+
removeArrayItem(attr, index) {
|
|
305
|
+
const data = { ...this.formData() };
|
|
306
|
+
const arr = [...(data[attr.name] || [])];
|
|
307
|
+
arr.splice(index, 1);
|
|
308
|
+
data[attr.name] = arr;
|
|
309
|
+
this.formData.set(data);
|
|
310
|
+
}
|
|
311
|
+
// Reference modal methods
|
|
312
|
+
async openReferenceSelector(attr) {
|
|
313
|
+
this.editingReferenceAttr.set(attr);
|
|
314
|
+
this.referenceSearchTerm = '';
|
|
315
|
+
this.referenceModalItems.set(this.getReferenceOptions(attr));
|
|
316
|
+
const types = await this.sparkService.getEntityTypes();
|
|
317
|
+
this.referenceModalEntityType.set(types.find(t => t.clrType === attr.referenceType) || null);
|
|
318
|
+
this.referenceModalSettings.set(new DatatableSettings({
|
|
319
|
+
perPage: { values: [10, 25, 50], selected: 10 },
|
|
320
|
+
page: { values: [1], selected: 1 },
|
|
321
|
+
sortColumns: []
|
|
322
|
+
}));
|
|
323
|
+
this.applyReferenceFilter();
|
|
324
|
+
this.showReferenceModal.set(true);
|
|
325
|
+
}
|
|
326
|
+
onReferenceSearchChange() {
|
|
327
|
+
this.referenceModalSettings().page.selected = 1;
|
|
328
|
+
this.applyReferenceFilter();
|
|
329
|
+
}
|
|
330
|
+
applyReferenceFilter() {
|
|
331
|
+
let filteredItems = this.referenceModalItems();
|
|
332
|
+
if (this.referenceSearchTerm.trim()) {
|
|
333
|
+
const term = this.referenceSearchTerm.toLowerCase().trim();
|
|
334
|
+
filteredItems = this.referenceModalItems().filter(item => {
|
|
335
|
+
if (item.name?.toLowerCase().includes(term))
|
|
336
|
+
return true;
|
|
337
|
+
if (item.breadcrumb?.toLowerCase().includes(term))
|
|
338
|
+
return true;
|
|
339
|
+
return item.attributes.some(attr => {
|
|
340
|
+
const value = attr.breadcrumb || attr.value;
|
|
341
|
+
if (value == null)
|
|
342
|
+
return false;
|
|
343
|
+
return String(value).toLowerCase().includes(term);
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
const totalPages = Math.ceil(filteredItems.length / this.referenceModalSettings().perPage.selected) || 1;
|
|
348
|
+
this.referenceModalPagination.set({
|
|
349
|
+
data: filteredItems,
|
|
350
|
+
totalRecords: filteredItems.length,
|
|
351
|
+
totalPages: totalPages,
|
|
352
|
+
perPage: this.referenceModalSettings().perPage.selected,
|
|
353
|
+
page: this.referenceModalSettings().page.selected
|
|
354
|
+
});
|
|
355
|
+
this.referenceModalSettings().page.values = Array.from({ length: totalPages }, (_, i) => i + 1);
|
|
356
|
+
if (this.referenceModalSettings().page.selected > totalPages) {
|
|
357
|
+
this.referenceModalSettings().page.selected = 1;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
clearReferenceSearch() {
|
|
361
|
+
this.referenceSearchTerm = '';
|
|
362
|
+
this.onReferenceSearchChange();
|
|
363
|
+
}
|
|
364
|
+
selectReferenceItem(item) {
|
|
365
|
+
const attr = this.editingReferenceAttr();
|
|
366
|
+
if (attr) {
|
|
367
|
+
const data = { ...this.formData() };
|
|
368
|
+
data[attr.name] = item.id;
|
|
369
|
+
this.formData.set(data);
|
|
370
|
+
}
|
|
371
|
+
this.closeReferenceModal();
|
|
372
|
+
}
|
|
373
|
+
closeReferenceModal() {
|
|
374
|
+
this.showReferenceModal.set(false);
|
|
375
|
+
this.editingReferenceAttr.set(null);
|
|
376
|
+
this.referenceModalItems.set([]);
|
|
377
|
+
this.referenceModalEntityType.set(null);
|
|
378
|
+
this.referenceSearchTerm = '';
|
|
379
|
+
}
|
|
380
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: SparkPoFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
381
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: SparkPoFormComponent, isStandalone: true, selector: "spark-po-form", inputs: { entityType: { classPropertyName: "entityType", publicName: "entityType", isSignal: true, isRequired: false, transformFunction: null }, formData: { classPropertyName: "formData", publicName: "formData", isSignal: true, isRequired: false, transformFunction: null }, validationErrors: { classPropertyName: "validationErrors", publicName: "validationErrors", isSignal: true, isRequired: false, transformFunction: null }, showButtons: { classPropertyName: "showButtons", publicName: "showButtons", isSignal: true, isRequired: false, transformFunction: null }, isSaving: { classPropertyName: "isSaving", publicName: "isSaving", isSignal: true, isRequired: false, transformFunction: null }, parentId: { classPropertyName: "parentId", publicName: "parentId", isSignal: true, isRequired: false, transformFunction: null }, parentType: { classPropertyName: "parentType", publicName: "parentType", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { formData: "formDataChange", save: "save", cancel: "cancel" }, ngImport: i0, template: "<bs-form>\n @if (entityType()) {\n <bs-grid>\n <bs-tab-control>\n @for (tab of resolvedTabs(); track tab.id) {\n <bs-tab-page>\n <ng-template bsTabPageHeader>{{ tab.label | resolveTranslation:tab.name }}</ng-template>\n <ng-container *ngTemplateOutlet=\"tabContent; context: { $implicit: tab }\"></ng-container>\n </bs-tab-page>\n }\n </bs-tab-control>\n\n <ng-template #tabContent let-tab>\n @if (tab.id === '__default__') {\n @if (ungroupedAttributes().length > 0) {\n <bs-card class=\"d-block m-3\">\n <div class=\"p-3\">\n @for (attr of ungroupedAttributes(); track attr.id) {\n <ng-container *ngTemplateOutlet=\"attrField; context: { $implicit: attr }\"></ng-container>\n }\n </div>\n </bs-card>\n }\n }\n @for (group of groupsForTab(tab); track group.id) {\n @if (attrsForGroup(group); as groupAttrs) {\n @if (groupAttrs.length > 0) {\n <bs-card class=\"d-block m-3\">\n @if (group.label) {\n <bs-card-header>{{ group.label | resolveTranslation:group.name }}</bs-card-header>\n }\n <div class=\"p-3\">\n @for (attr of groupAttrs; track attr.id) {\n <ng-container *ngTemplateOutlet=\"attrField; context: { $implicit: attr }\"></ng-container>\n }\n </div>\n </bs-card>\n }\n }\n }\n </ng-template>\n\n <ng-template #attrField let-attr>\n <div bsRow class=\"mb-3\">\n <label [md]=\"4\" bsColFormLabel [for]=\"attr.name\">\n {{ attr.label | resolveTranslation:attr.name }}\n @if (attr.isRequired) {\n <span class=\"text-danger\">*</span>\n }\n </label>\n <div [md]=\"8\">\n @if (attr.dataType === 'boolean') {\n <bs-toggle-button\n [ngModel]=\"formData()[attr.name]\"\n (ngModelChange)=\"formData()[attr.name] = $event; onFieldChange()\">\n </bs-toggle-button>\n } @else if (attr.lookupReferenceType) {\n @if ((attr | lookupDisplayType:lookupReferenceOptions()) === ELookupDisplayType.Modal) {\n <bs-input-group>\n <input\n type=\"text\"\n [id]=\"attr.name\"\n [value]=\"attr | lookupDisplayValue:formData():lookupReferenceOptions()\"\n readonly\n [class.is-invalid]=\"hasError(attr.name)\">\n <button\n type=\"button\"\n bsInputGroupBtn\n [color]=\"colors.secondary\"\n (click)=\"openLookupSelector(attr)\">\n ...\n </button>\n </bs-input-group>\n } @else {\n <bs-select\n [ngModel]=\"formData()[attr.name]\"\n (ngModelChange)=\"formData()[attr.name] = $event; onFieldChange()\"\n [id]=\"attr.name\"\n [class.is-invalid]=\"hasError(attr.name)\">\n <option [ngValue]=\"null\">{{ 'common.selectPlaceholder' | t }}</option>\n @for (option of (attr | lookupOptions:lookupReferenceOptions()); track option.key) {\n <option [ngValue]=\"option.key\">\n {{ option.values | resolveTranslation:option.key }}\n </option>\n }\n </bs-select>\n }\n } @else if (attr.dataType === 'Reference') {\n <bs-input-group>\n <input\n type=\"text\"\n [id]=\"attr.name\"\n [value]=\"attr | referenceDisplayValue:formData():referenceOptions()\"\n readonly\n [class.is-invalid]=\"hasError(attr.name)\">\n <button\n type=\"button\"\n bsInputGroupBtn\n [color]=\"colors.secondary\"\n (click)=\"openReferenceSelector(attr)\">\n ...\n </button>\n </bs-input-group>\n } @else if (attr.dataType === 'AsDetail' && attr.isArray && attr.editMode === 'inline') {\n <bs-table [isResponsive]=\"true\" class=\"mb-1\">\n <thead>\n <tr>\n @for (col of (attr | asDetailColumns:asDetailTypes()); track col.name) {\n <th>{{ col.label | resolveTranslation:col.name }}</th>\n }\n <th style=\"width: 50px\"></th>\n </tr>\n </thead>\n <tbody class=\"align-middle\">\n @for (row of formData()[attr.name] || []; track $index) {\n <tr>\n @for (col of (attr | asDetailColumns:asDetailTypes()); track col.name) {\n <td>\n @if (col.dataType === 'boolean') {\n <bs-toggle-button\n [(ngModel)]=\"row[col.name]\"\n (ngModelChange)=\"onFieldChange()\">\n </bs-toggle-button>\n } @else if (col.dataType === 'Reference' && col.query) {\n <bs-select\n [(ngModel)]=\"row[col.name]\"\n (ngModelChange)=\"onFieldChange()\">\n <option [ngValue]=\"null\">{{ 'common.selectPlaceholder' | t }}</option>\n @for (option of (attr | inlineRefOptions:col:asDetailReferenceOptions()); track option.id) {\n <option [ngValue]=\"option.id\">\n {{ option.breadcrumb || option.name || option.id }}\n </option>\n }\n </bs-select>\n } @else {\n <input\n [type]=\"col.dataType | inputType\"\n [(ngModel)]=\"row[col.name]\"\n [required]=\"col.isRequired\"\n [step]=\"col.dataType === 'decimal' ? '0.01' : '1'\"\n (ngModelChange)=\"onFieldChange()\">\n }\n </td>\n }\n <td class=\"text-nowrap\">\n @if (attr | canDeleteDetailRow:asDetailPermissions()) {\n <button type=\"button\" [color]=\"colors.secondary\" (click)=\"removeArrayItem(attr, $index)\">\n <spark-icon name=\"trash\" />\n </button>\n }\n </td>\n </tr>\n } @empty {\n <tr>\n <td [attr.colspan]=\"(attr | asDetailColumns:asDetailTypes()).length + 1\" class=\"text-center text-muted\">\n {{ 'common.noItemsFound' | t }}\n </td>\n </tr>\n }\n </tbody>\n </bs-table>\n @if (attr | canCreateDetailRow:asDetailPermissions()) {\n <button type=\"button\" [color]=\"colors.primary\" class=\"w-100 rounded-0\" (click)=\"addInlineRow(attr)\">\n <spark-icon name=\"plus\" /> {{ 'common.add' | t }}\n </button>\n }\n } @else if (attr.dataType === 'AsDetail' && attr.isArray) {\n <bs-table [isResponsive]=\"true\" class=\"mb-1\">\n <thead>\n <tr>\n @for (col of (attr | asDetailColumns:asDetailTypes()); track col.name) {\n <th>{{ col.label | resolveTranslation:col.name }}</th>\n }\n <th style=\"width: 80px\"></th>\n </tr>\n </thead>\n <tbody class=\"align-middle\">\n @for (row of formData()[attr.name] || []; track $index) {\n <tr>\n @for (col of (attr | asDetailColumns:asDetailTypes()); track col.name) {\n <td>{{ row | asDetailCellValue:attr:col:asDetailReferenceOptions() }}</td>\n }\n <td class=\"text-nowrap\">\n <button type=\"button\" class=\"btn btn-sm btn-outline-secondary me-1\" (click)=\"editArrayItem(attr, $index)\">\n <spark-icon name=\"pencil\" />\n </button>\n @if (attr | canDeleteDetailRow:asDetailPermissions()) {\n <button type=\"button\" class=\"btn btn-sm btn-outline-danger\" (click)=\"removeArrayItem(attr, $index)\">\n <spark-icon name=\"trash\" />\n </button>\n }\n </td>\n </tr>\n } @empty {\n <tr>\n <td [attr.colspan]=\"(attr | asDetailColumns:asDetailTypes()).length + 1\" class=\"text-center text-muted\">\n {{ 'common.noItemsFound' | t }}\n </td>\n </tr>\n }\n </tbody>\n </bs-table>\n @if (attr | canCreateDetailRow:asDetailPermissions()) {\n <button type=\"button\" [color]=\"colors.primary\" class=\"w-100 rounded-0\" (click)=\"addArrayItem(attr)\">\n <spark-icon name=\"plus\" /> {{ 'common.add' | t }}\n </button>\n }\n } @else if (attr.dataType === 'AsDetail') {\n <bs-input-group>\n <input\n type=\"text\"\n [id]=\"attr.name\"\n [value]=\"attr | asDetailDisplayValue:formData():asDetailTypes()\"\n readonly\n [class.is-invalid]=\"hasError(attr.name)\">\n <button\n type=\"button\"\n bsInputGroupBtn\n [color]=\"colors.secondary\"\n (click)=\"openAsDetailEditor(attr)\">\n <spark-icon name=\"pencil\" />\n </button>\n </bs-input-group>\n } @else if (getEditRendererComponent(attr); as editComp) {\n <ng-container *ngComponentOutlet=\"editComp; inputs: getEditRendererInputs(attr)\"></ng-container>\n } @else {\n <input\n [type]=\"attr.dataType | inputType\"\n [id]=\"attr.name\"\n [ngModel]=\"formData()[attr.name]\"\n (ngModelChange)=\"formData()[attr.name] = $event; onFieldChange()\"\n [name]=\"attr.name\"\n [required]=\"attr.isRequired\"\n [step]=\"attr.dataType === 'decimal' ? '0.01' : '1'\"\n [class.is-invalid]=\"hasError(attr.name)\">\n }\n @if (attr.name | errorForAttribute:validationErrors(); as errorMsg) {\n <div class=\"invalid-feedback d-block\">\n {{ errorMsg }}\n </div>\n }\n </div>\n </div>\n </ng-template>\n\n @if (showButtons()) {\n <div bsRow class=\"mt-4\">\n <div [md]=\"4\"></div>\n <div [md]=\"8\" class=\"d-flex justify-content-end gap-2\">\n <button type=\"button\" [color]=\"colors.secondary\" (click)=\"onCancel()\" [disabled]=\"isSaving()\">{{ 'common.cancel' | t }}</button>\n <button type=\"submit\" [color]=\"colors.primary\" [disabled]=\"isSaving()\" (click)=\"onSave()\">\n @if (isSaving()) {\n <bs-spinner class=\"me-1\" />\n }\n {{ 'common.save' | t }}\n </button>\n </div>\n </div>\n }\n </bs-grid>\n}\n\n<!-- Modal for editing AsDetail objects -->\n<bs-modal [isOpen]=\"showAsDetailModal()\" (isOpenChange)=\"!$event && closeAsDetailModal()\">\n <div *bsModal>\n <div bsModalHeader>\n <h5 class=\"modal-title\">{{ 'common.edit' | t }} {{ editingAsDetailAttr()?.label | resolveTranslation:editingAsDetailAttr()?.name }}</h5>\n </div>\n\n @if (editingAsDetailAttr(); as attr) {\n <div bsModalBody>\n <spark-po-form\n [entityType]=\"attr | asDetailType:asDetailTypes()\"\n [(formData)]=\"asDetailFormData\"\n [parentId]=\"parentId()\"\n [parentType]=\"parentType()\">\n </spark-po-form>\n </div>\n }\n\n <div bsModalFooter>\n <button type=\"button\" [color]=\"colors.secondary\" (click)=\"closeAsDetailModal()\">{{ 'common.cancel' | t }}</button>\n <button type=\"button\" [color]=\"colors.primary\" (click)=\"saveAsDetailObject()\">{{ 'common.save' | t }}</button>\n </div>\n </div>\n</bs-modal>\n\n<!-- Modal for selecting Reference items -->\n<bs-modal [isOpen]=\"showReferenceModal()\" (isOpenChange)=\"!$event && closeReferenceModal()\">\n <div *bsModal class=\"reference-modal\">\n <div bsModalHeader>\n <h5 class=\"modal-title\">{{ 'common.select' | t }} {{ editingReferenceAttr()?.label | resolveTranslation:editingReferenceAttr()?.name }}</h5>\n </div>\n\n <div bsModalBody>\n @if (referenceModalEntityType()) {\n <!-- Search box -->\n <bs-grid>\n <div bsRow class=\"mb-3\">\n <div [md]=\"6\">\n <bs-input-group>\n <span class=\"input-group-text\">\n <spark-icon name=\"search\" />\n </span>\n <input\n type=\"text\"\n [placeholder]=\"'common.search' | t\"\n [(ngModel)]=\"referenceSearchTerm\"\n (ngModelChange)=\"onReferenceSearchChange()\">\n @if (referenceSearchTerm) {\n <button\n type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"clearReferenceSearch()\">\n <spark-icon name=\"x-lg\" />\n </button>\n }\n </bs-input-group>\n </div>\n <div [md]=\"6\" class=\"text-end\">\n @if (referenceSearchTerm && referenceModalPagination()) {\n <span class=\"text-muted\">\n {{ referenceModalPagination()!.totalRecords }} {{ referenceModalPagination()!.totalRecords === 1 ? ('common.resultFound' | t) : ('common.resultsFound' | t) }}\n </span>\n }\n </div>\n </div>\n </bs-grid>\n\n <bs-datatable [(settings)]=\"referenceModalSettings\" (settingsChange)=\"applyReferenceFilter()\">\n @for (attr of referenceVisibleAttributes(); track attr.id) {\n <div *bsDatatableColumn=\"attr.name; sortable: true\">\n {{ attr.label | resolveTranslation:attr.name }}\n </div>\n }\n\n <tr *bsRowTemplate=\"let item of referenceModalPagination()\" (click)=\"selectReferenceItem(item)\" style=\"cursor: pointer;\">\n @for (attr of referenceVisibleAttributes(); track attr.id) {\n <td>{{ item | referenceAttrValue:attr.name }}</td>\n }\n </tr>\n </bs-datatable>\n } @else {\n <div class=\"text-center p-3\">\n <bs-spinner />\n </div>\n }\n </div>\n\n <div bsModalFooter>\n <button type=\"button\" [color]=\"colors.secondary\" (click)=\"closeReferenceModal()\">{{ 'common.cancel' | t }}</button>\n </div>\n </div>\n</bs-modal>\n\n<!-- Modal for selecting LookupReference items -->\n<bs-modal [isOpen]=\"showLookupModal()\" (isOpenChange)=\"!$event && closeLookupModal()\">\n <div *bsModal>\n <div bsModalHeader>\n <h5 class=\"modal-title\">{{ 'common.select' | t }} {{ editingLookupAttr()?.label | resolveTranslation:editingLookupAttr()?.name }}</h5>\n </div>\n\n <div bsModalBody>\n <!-- Search box -->\n <bs-grid>\n <div bsRow class=\"mb-3\">\n <div [col]>\n <bs-input-group>\n <span class=\"input-group-text\">\n <spark-icon name=\"search\" />\n </span>\n <input\n type=\"text\"\n [placeholder]=\"'common.search' | t\"\n [ngModel]=\"lookupSearchTerm()\"\n (ngModelChange)=\"lookupSearchTerm.set($event)\">\n @if (lookupSearchTerm()) {\n <button\n type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"lookupSearchTerm.set('')\">\n <spark-icon name=\"x-lg\" />\n </button>\n }\n </bs-input-group>\n </div>\n </div>\n </bs-grid>\n\n <!-- List of items -->\n <bs-table [striped]=\"true\" [hover]=\"true\">\n <tbody class=\"align-middle\">\n @for (item of filteredLookupItems(); track item.key) {\n <tr\n [class.table-primary]=\"formData()[editingLookupAttr()?.name ?? ''] === item.key\"\n (click)=\"selectLookupItem(item)\"\n style=\"cursor: pointer;\">\n <td>{{ item.values | resolveTranslation:item.key }}</td>\n </tr>\n } @empty {\n <tr>\n <td class=\"text-center text-muted\">{{ 'common.noItemsFound' | t }}</td>\n </tr>\n }\n </tbody>\n </bs-table>\n </div>\n\n <div bsModalFooter>\n <button type=\"button\" [color]=\"colors.secondary\" (click)=\"closeLookupModal()\">{{ 'common.cancel' | t }}</button>\n </div>\n </div>\n</bs-modal>\n</bs-form>\n", dependencies: [{ kind: "component", type: SparkPoFormComponent, selector: "spark-po-form", inputs: ["entityType", "formData", "validationErrors", "showButtons", "isSaving", "parentId", "parentType"], outputs: ["formDataChange", "save", "cancel"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BsCardComponent, selector: "bs-card", inputs: ["rounded"] }, { kind: "component", type: BsCardHeaderComponent, selector: "bs-card-header", inputs: ["noPadding"] }, { kind: "component", type: BsFormComponent, selector: "bs-form", inputs: ["action", "method"], outputs: ["submitted"] }, { kind: "directive", type: BsFormControlDirective, selector: "bs-form input:not(.no-form-control), bs-form textarea:not(.no-form-control)" }, { kind: "component", type: BsGridComponent, selector: "bs-grid", inputs: ["stopFullWidthAt"] }, { kind: "directive", type: BsGridRowDirective, selector: "[bsRow]" }, { kind: "directive", type: BsGridColumnDirective, selector: "[xxs],[xs],[sm],[md],[lg],[xl],[xxl]", inputs: ["xxs", "xs", "sm", "md", "lg", "xl", "xxl"] }, { kind: "directive", type: BsGridColDirective, selector: "[col]", inputs: ["col"] }, { kind: "directive", type: BsColFormLabelDirective, selector: "[bsColFormLabel]" }, { kind: "directive", type: BsButtonTypeDirective, selector: "button[color],input[type=\"button\"][color],input[type=\"submit\"][color],a[color]", inputs: ["color"] }, { kind: "component", type: BsInputGroupComponent, selector: "bs-input-group" }, { kind: "component", type: BsSelectComponent, selector: "bs-select", inputs: ["identifier", "size", "multiple", "numberVisible", "disabled"] }, { kind: "directive", type: BsSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "component", type: BsModalHostComponent, selector: "bs-modal", inputs: ["isOpen", "closeOnEscape"], outputs: ["isOpenChange"] }, { kind: "directive", type: BsModalDirective, selector: "[bsModal]" }, { kind: "directive", type: BsModalHeaderDirective, selector: "[bsModalHeader]" }, { kind: "directive", type: BsModalBodyDirective, selector: "[bsModalBody]" }, { kind: "directive", type: BsModalFooterDirective, selector: "[bsModalFooter]" }, { kind: "component", type: BsDatatableComponent, selector: "bs-datatable", inputs: ["data"], outputs: ["dataChange"] }, { kind: "directive", type: BsDatatableColumnDirective, selector: "[bsDatatableColumn]", inputs: ["bsDatatableColumn", "bsDatatableColumnSortable"] }, { kind: "directive", type: BsRowTemplateDirective, selector: "[bsRowTemplate]", inputs: ["bsRowTemplateOf"] }, { kind: "component", type: BsTableComponent, selector: "bs-table", inputs: ["isResponsive", "striped", "hover"] }, { kind: "component", type: BsToggleButtonComponent, selector: "bs-toggle-button", inputs: ["type", "isToggled", "name", "value", "group"], outputs: ["isToggledChange"] }, { kind: "component", type: BsSpinnerComponent, selector: "bs-spinner", inputs: ["type", "color"] }, { kind: "component", type: BsTabControlComponent, selector: "bs-tab-control", inputs: ["border", "restrictDragging", "selectFirstTab", "tabsPosition", "allowDragDrop"] }, { kind: "component", type: BsTabPageComponent, selector: "bs-tab-page", inputs: ["disabled"] }, { kind: "directive", type: BsTabPageHeaderDirective, selector: "[bsTabPageHeader]" }, { kind: "component", type: SparkIconComponent, selector: "spark-icon", inputs: ["name"] }, { kind: "pipe", type: TranslateKeyPipe, name: "t" }, { kind: "pipe", type: ResolveTranslationPipe, name: "resolveTranslation" }, { kind: "pipe", type: InputTypePipe, name: "inputType" }, { kind: "pipe", type: LookupDisplayValuePipe, name: "lookupDisplayValue" }, { kind: "pipe", type: LookupDisplayTypePipe, name: "lookupDisplayType" }, { kind: "pipe", type: LookupOptionsPipe, name: "lookupOptions" }, { kind: "pipe", type: ReferenceDisplayValuePipe, name: "referenceDisplayValue" }, { kind: "pipe", type: AsDetailDisplayValuePipe, name: "asDetailDisplayValue" }, { kind: "pipe", type: AsDetailTypePipe, name: "asDetailType" }, { kind: "pipe", type: AsDetailColumnsPipe, name: "asDetailColumns" }, { kind: "pipe", type: AsDetailCellValuePipe, name: "asDetailCellValue" }, { kind: "pipe", type: CanCreateDetailRowPipe, name: "canCreateDetailRow" }, { kind: "pipe", type: CanDeleteDetailRowPipe, name: "canDeleteDetailRow" }, { kind: "pipe", type: InlineRefOptionsPipe, name: "inlineRefOptions" }, { kind: "pipe", type: ReferenceAttrValuePipe, name: "referenceAttrValue" }, { kind: "pipe", type: ErrorForAttributePipe, name: "errorForAttribute" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
382
|
+
}
|
|
383
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: SparkPoFormComponent, decorators: [{
|
|
384
|
+
type: Component,
|
|
385
|
+
args: [{ selector: 'spark-po-form', imports: [CommonModule, NgTemplateOutlet, NgComponentOutlet, FormsModule, BsCardComponent, BsCardHeaderComponent, BsFormComponent, BsFormControlDirective, BsGridComponent, BsGridRowDirective, BsGridColumnDirective, BsGridColDirective, BsColFormLabelDirective, BsButtonTypeDirective, BsInputGroupComponent, BsSelectComponent, BsSelectOption, BsModalHostComponent, BsModalDirective, BsModalHeaderDirective, BsModalBodyDirective, BsModalFooterDirective, BsDatatableComponent, BsDatatableColumnDirective, BsRowTemplateDirective, BsTableComponent, BsToggleButtonComponent, BsSpinnerComponent, BsTabControlComponent, BsTabPageComponent, BsTabPageHeaderDirective, SparkIconComponent, SparkPoFormComponent, TranslateKeyPipe, ResolveTranslationPipe, InputTypePipe, LookupDisplayValuePipe, LookupDisplayTypePipe, LookupOptionsPipe, ReferenceDisplayValuePipe, AsDetailDisplayValuePipe, AsDetailTypePipe, AsDetailColumnsPipe, AsDetailCellValuePipe, CanCreateDetailRowPipe, CanDeleteDetailRowPipe, InlineRefOptionsPipe, ReferenceAttrValuePipe, ErrorForAttributePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<bs-form>\n @if (entityType()) {\n <bs-grid>\n <bs-tab-control>\n @for (tab of resolvedTabs(); track tab.id) {\n <bs-tab-page>\n <ng-template bsTabPageHeader>{{ tab.label | resolveTranslation:tab.name }}</ng-template>\n <ng-container *ngTemplateOutlet=\"tabContent; context: { $implicit: tab }\"></ng-container>\n </bs-tab-page>\n }\n </bs-tab-control>\n\n <ng-template #tabContent let-tab>\n @if (tab.id === '__default__') {\n @if (ungroupedAttributes().length > 0) {\n <bs-card class=\"d-block m-3\">\n <div class=\"p-3\">\n @for (attr of ungroupedAttributes(); track attr.id) {\n <ng-container *ngTemplateOutlet=\"attrField; context: { $implicit: attr }\"></ng-container>\n }\n </div>\n </bs-card>\n }\n }\n @for (group of groupsForTab(tab); track group.id) {\n @if (attrsForGroup(group); as groupAttrs) {\n @if (groupAttrs.length > 0) {\n <bs-card class=\"d-block m-3\">\n @if (group.label) {\n <bs-card-header>{{ group.label | resolveTranslation:group.name }}</bs-card-header>\n }\n <div class=\"p-3\">\n @for (attr of groupAttrs; track attr.id) {\n <ng-container *ngTemplateOutlet=\"attrField; context: { $implicit: attr }\"></ng-container>\n }\n </div>\n </bs-card>\n }\n }\n }\n </ng-template>\n\n <ng-template #attrField let-attr>\n <div bsRow class=\"mb-3\">\n <label [md]=\"4\" bsColFormLabel [for]=\"attr.name\">\n {{ attr.label | resolveTranslation:attr.name }}\n @if (attr.isRequired) {\n <span class=\"text-danger\">*</span>\n }\n </label>\n <div [md]=\"8\">\n @if (attr.dataType === 'boolean') {\n <bs-toggle-button\n [ngModel]=\"formData()[attr.name]\"\n (ngModelChange)=\"formData()[attr.name] = $event; onFieldChange()\">\n </bs-toggle-button>\n } @else if (attr.lookupReferenceType) {\n @if ((attr | lookupDisplayType:lookupReferenceOptions()) === ELookupDisplayType.Modal) {\n <bs-input-group>\n <input\n type=\"text\"\n [id]=\"attr.name\"\n [value]=\"attr | lookupDisplayValue:formData():lookupReferenceOptions()\"\n readonly\n [class.is-invalid]=\"hasError(attr.name)\">\n <button\n type=\"button\"\n bsInputGroupBtn\n [color]=\"colors.secondary\"\n (click)=\"openLookupSelector(attr)\">\n ...\n </button>\n </bs-input-group>\n } @else {\n <bs-select\n [ngModel]=\"formData()[attr.name]\"\n (ngModelChange)=\"formData()[attr.name] = $event; onFieldChange()\"\n [id]=\"attr.name\"\n [class.is-invalid]=\"hasError(attr.name)\">\n <option [ngValue]=\"null\">{{ 'common.selectPlaceholder' | t }}</option>\n @for (option of (attr | lookupOptions:lookupReferenceOptions()); track option.key) {\n <option [ngValue]=\"option.key\">\n {{ option.values | resolveTranslation:option.key }}\n </option>\n }\n </bs-select>\n }\n } @else if (attr.dataType === 'Reference') {\n <bs-input-group>\n <input\n type=\"text\"\n [id]=\"attr.name\"\n [value]=\"attr | referenceDisplayValue:formData():referenceOptions()\"\n readonly\n [class.is-invalid]=\"hasError(attr.name)\">\n <button\n type=\"button\"\n bsInputGroupBtn\n [color]=\"colors.secondary\"\n (click)=\"openReferenceSelector(attr)\">\n ...\n </button>\n </bs-input-group>\n } @else if (attr.dataType === 'AsDetail' && attr.isArray && attr.editMode === 'inline') {\n <bs-table [isResponsive]=\"true\" class=\"mb-1\">\n <thead>\n <tr>\n @for (col of (attr | asDetailColumns:asDetailTypes()); track col.name) {\n <th>{{ col.label | resolveTranslation:col.name }}</th>\n }\n <th style=\"width: 50px\"></th>\n </tr>\n </thead>\n <tbody class=\"align-middle\">\n @for (row of formData()[attr.name] || []; track $index) {\n <tr>\n @for (col of (attr | asDetailColumns:asDetailTypes()); track col.name) {\n <td>\n @if (col.dataType === 'boolean') {\n <bs-toggle-button\n [(ngModel)]=\"row[col.name]\"\n (ngModelChange)=\"onFieldChange()\">\n </bs-toggle-button>\n } @else if (col.dataType === 'Reference' && col.query) {\n <bs-select\n [(ngModel)]=\"row[col.name]\"\n (ngModelChange)=\"onFieldChange()\">\n <option [ngValue]=\"null\">{{ 'common.selectPlaceholder' | t }}</option>\n @for (option of (attr | inlineRefOptions:col:asDetailReferenceOptions()); track option.id) {\n <option [ngValue]=\"option.id\">\n {{ option.breadcrumb || option.name || option.id }}\n </option>\n }\n </bs-select>\n } @else {\n <input\n [type]=\"col.dataType | inputType\"\n [(ngModel)]=\"row[col.name]\"\n [required]=\"col.isRequired\"\n [step]=\"col.dataType === 'decimal' ? '0.01' : '1'\"\n (ngModelChange)=\"onFieldChange()\">\n }\n </td>\n }\n <td class=\"text-nowrap\">\n @if (attr | canDeleteDetailRow:asDetailPermissions()) {\n <button type=\"button\" [color]=\"colors.secondary\" (click)=\"removeArrayItem(attr, $index)\">\n <spark-icon name=\"trash\" />\n </button>\n }\n </td>\n </tr>\n } @empty {\n <tr>\n <td [attr.colspan]=\"(attr | asDetailColumns:asDetailTypes()).length + 1\" class=\"text-center text-muted\">\n {{ 'common.noItemsFound' | t }}\n </td>\n </tr>\n }\n </tbody>\n </bs-table>\n @if (attr | canCreateDetailRow:asDetailPermissions()) {\n <button type=\"button\" [color]=\"colors.primary\" class=\"w-100 rounded-0\" (click)=\"addInlineRow(attr)\">\n <spark-icon name=\"plus\" /> {{ 'common.add' | t }}\n </button>\n }\n } @else if (attr.dataType === 'AsDetail' && attr.isArray) {\n <bs-table [isResponsive]=\"true\" class=\"mb-1\">\n <thead>\n <tr>\n @for (col of (attr | asDetailColumns:asDetailTypes()); track col.name) {\n <th>{{ col.label | resolveTranslation:col.name }}</th>\n }\n <th style=\"width: 80px\"></th>\n </tr>\n </thead>\n <tbody class=\"align-middle\">\n @for (row of formData()[attr.name] || []; track $index) {\n <tr>\n @for (col of (attr | asDetailColumns:asDetailTypes()); track col.name) {\n <td>{{ row | asDetailCellValue:attr:col:asDetailReferenceOptions() }}</td>\n }\n <td class=\"text-nowrap\">\n <button type=\"button\" class=\"btn btn-sm btn-outline-secondary me-1\" (click)=\"editArrayItem(attr, $index)\">\n <spark-icon name=\"pencil\" />\n </button>\n @if (attr | canDeleteDetailRow:asDetailPermissions()) {\n <button type=\"button\" class=\"btn btn-sm btn-outline-danger\" (click)=\"removeArrayItem(attr, $index)\">\n <spark-icon name=\"trash\" />\n </button>\n }\n </td>\n </tr>\n } @empty {\n <tr>\n <td [attr.colspan]=\"(attr | asDetailColumns:asDetailTypes()).length + 1\" class=\"text-center text-muted\">\n {{ 'common.noItemsFound' | t }}\n </td>\n </tr>\n }\n </tbody>\n </bs-table>\n @if (attr | canCreateDetailRow:asDetailPermissions()) {\n <button type=\"button\" [color]=\"colors.primary\" class=\"w-100 rounded-0\" (click)=\"addArrayItem(attr)\">\n <spark-icon name=\"plus\" /> {{ 'common.add' | t }}\n </button>\n }\n } @else if (attr.dataType === 'AsDetail') {\n <bs-input-group>\n <input\n type=\"text\"\n [id]=\"attr.name\"\n [value]=\"attr | asDetailDisplayValue:formData():asDetailTypes()\"\n readonly\n [class.is-invalid]=\"hasError(attr.name)\">\n <button\n type=\"button\"\n bsInputGroupBtn\n [color]=\"colors.secondary\"\n (click)=\"openAsDetailEditor(attr)\">\n <spark-icon name=\"pencil\" />\n </button>\n </bs-input-group>\n } @else if (getEditRendererComponent(attr); as editComp) {\n <ng-container *ngComponentOutlet=\"editComp; inputs: getEditRendererInputs(attr)\"></ng-container>\n } @else {\n <input\n [type]=\"attr.dataType | inputType\"\n [id]=\"attr.name\"\n [ngModel]=\"formData()[attr.name]\"\n (ngModelChange)=\"formData()[attr.name] = $event; onFieldChange()\"\n [name]=\"attr.name\"\n [required]=\"attr.isRequired\"\n [step]=\"attr.dataType === 'decimal' ? '0.01' : '1'\"\n [class.is-invalid]=\"hasError(attr.name)\">\n }\n @if (attr.name | errorForAttribute:validationErrors(); as errorMsg) {\n <div class=\"invalid-feedback d-block\">\n {{ errorMsg }}\n </div>\n }\n </div>\n </div>\n </ng-template>\n\n @if (showButtons()) {\n <div bsRow class=\"mt-4\">\n <div [md]=\"4\"></div>\n <div [md]=\"8\" class=\"d-flex justify-content-end gap-2\">\n <button type=\"button\" [color]=\"colors.secondary\" (click)=\"onCancel()\" [disabled]=\"isSaving()\">{{ 'common.cancel' | t }}</button>\n <button type=\"submit\" [color]=\"colors.primary\" [disabled]=\"isSaving()\" (click)=\"onSave()\">\n @if (isSaving()) {\n <bs-spinner class=\"me-1\" />\n }\n {{ 'common.save' | t }}\n </button>\n </div>\n </div>\n }\n </bs-grid>\n}\n\n<!-- Modal for editing AsDetail objects -->\n<bs-modal [isOpen]=\"showAsDetailModal()\" (isOpenChange)=\"!$event && closeAsDetailModal()\">\n <div *bsModal>\n <div bsModalHeader>\n <h5 class=\"modal-title\">{{ 'common.edit' | t }} {{ editingAsDetailAttr()?.label | resolveTranslation:editingAsDetailAttr()?.name }}</h5>\n </div>\n\n @if (editingAsDetailAttr(); as attr) {\n <div bsModalBody>\n <spark-po-form\n [entityType]=\"attr | asDetailType:asDetailTypes()\"\n [(formData)]=\"asDetailFormData\"\n [parentId]=\"parentId()\"\n [parentType]=\"parentType()\">\n </spark-po-form>\n </div>\n }\n\n <div bsModalFooter>\n <button type=\"button\" [color]=\"colors.secondary\" (click)=\"closeAsDetailModal()\">{{ 'common.cancel' | t }}</button>\n <button type=\"button\" [color]=\"colors.primary\" (click)=\"saveAsDetailObject()\">{{ 'common.save' | t }}</button>\n </div>\n </div>\n</bs-modal>\n\n<!-- Modal for selecting Reference items -->\n<bs-modal [isOpen]=\"showReferenceModal()\" (isOpenChange)=\"!$event && closeReferenceModal()\">\n <div *bsModal class=\"reference-modal\">\n <div bsModalHeader>\n <h5 class=\"modal-title\">{{ 'common.select' | t }} {{ editingReferenceAttr()?.label | resolveTranslation:editingReferenceAttr()?.name }}</h5>\n </div>\n\n <div bsModalBody>\n @if (referenceModalEntityType()) {\n <!-- Search box -->\n <bs-grid>\n <div bsRow class=\"mb-3\">\n <div [md]=\"6\">\n <bs-input-group>\n <span class=\"input-group-text\">\n <spark-icon name=\"search\" />\n </span>\n <input\n type=\"text\"\n [placeholder]=\"'common.search' | t\"\n [(ngModel)]=\"referenceSearchTerm\"\n (ngModelChange)=\"onReferenceSearchChange()\">\n @if (referenceSearchTerm) {\n <button\n type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"clearReferenceSearch()\">\n <spark-icon name=\"x-lg\" />\n </button>\n }\n </bs-input-group>\n </div>\n <div [md]=\"6\" class=\"text-end\">\n @if (referenceSearchTerm && referenceModalPagination()) {\n <span class=\"text-muted\">\n {{ referenceModalPagination()!.totalRecords }} {{ referenceModalPagination()!.totalRecords === 1 ? ('common.resultFound' | t) : ('common.resultsFound' | t) }}\n </span>\n }\n </div>\n </div>\n </bs-grid>\n\n <bs-datatable [(settings)]=\"referenceModalSettings\" (settingsChange)=\"applyReferenceFilter()\">\n @for (attr of referenceVisibleAttributes(); track attr.id) {\n <div *bsDatatableColumn=\"attr.name; sortable: true\">\n {{ attr.label | resolveTranslation:attr.name }}\n </div>\n }\n\n <tr *bsRowTemplate=\"let item of referenceModalPagination()\" (click)=\"selectReferenceItem(item)\" style=\"cursor: pointer;\">\n @for (attr of referenceVisibleAttributes(); track attr.id) {\n <td>{{ item | referenceAttrValue:attr.name }}</td>\n }\n </tr>\n </bs-datatable>\n } @else {\n <div class=\"text-center p-3\">\n <bs-spinner />\n </div>\n }\n </div>\n\n <div bsModalFooter>\n <button type=\"button\" [color]=\"colors.secondary\" (click)=\"closeReferenceModal()\">{{ 'common.cancel' | t }}</button>\n </div>\n </div>\n</bs-modal>\n\n<!-- Modal for selecting LookupReference items -->\n<bs-modal [isOpen]=\"showLookupModal()\" (isOpenChange)=\"!$event && closeLookupModal()\">\n <div *bsModal>\n <div bsModalHeader>\n <h5 class=\"modal-title\">{{ 'common.select' | t }} {{ editingLookupAttr()?.label | resolveTranslation:editingLookupAttr()?.name }}</h5>\n </div>\n\n <div bsModalBody>\n <!-- Search box -->\n <bs-grid>\n <div bsRow class=\"mb-3\">\n <div [col]>\n <bs-input-group>\n <span class=\"input-group-text\">\n <spark-icon name=\"search\" />\n </span>\n <input\n type=\"text\"\n [placeholder]=\"'common.search' | t\"\n [ngModel]=\"lookupSearchTerm()\"\n (ngModelChange)=\"lookupSearchTerm.set($event)\">\n @if (lookupSearchTerm()) {\n <button\n type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"lookupSearchTerm.set('')\">\n <spark-icon name=\"x-lg\" />\n </button>\n }\n </bs-input-group>\n </div>\n </div>\n </bs-grid>\n\n <!-- List of items -->\n <bs-table [striped]=\"true\" [hover]=\"true\">\n <tbody class=\"align-middle\">\n @for (item of filteredLookupItems(); track item.key) {\n <tr\n [class.table-primary]=\"formData()[editingLookupAttr()?.name ?? ''] === item.key\"\n (click)=\"selectLookupItem(item)\"\n style=\"cursor: pointer;\">\n <td>{{ item.values | resolveTranslation:item.key }}</td>\n </tr>\n } @empty {\n <tr>\n <td class=\"text-center text-muted\">{{ 'common.noItemsFound' | t }}</td>\n </tr>\n }\n </tbody>\n </bs-table>\n </div>\n\n <div bsModalFooter>\n <button type=\"button\" [color]=\"colors.secondary\" (click)=\"closeLookupModal()\">{{ 'common.cancel' | t }}</button>\n </div>\n </div>\n</bs-modal>\n</bs-form>\n" }]
|
|
386
|
+
}], ctorParameters: () => [], propDecorators: { entityType: [{ type: i0.Input, args: [{ isSignal: true, alias: "entityType", required: false }] }], formData: [{ type: i0.Input, args: [{ isSignal: true, alias: "formData", required: false }] }, { type: i0.Output, args: ["formDataChange"] }], validationErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationErrors", required: false }] }], showButtons: [{ type: i0.Input, args: [{ isSignal: true, alias: "showButtons", required: false }] }], isSaving: [{ type: i0.Input, args: [{ isSignal: true, alias: "isSaving", required: false }] }], parentId: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentId", required: false }] }], parentType: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentType", required: false }] }], save: [{ type: i0.Output, args: ["save"] }], cancel: [{ type: i0.Output, args: ["cancel"] }] } });
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Generated bundle index. Do not edit.
|
|
390
|
+
*/
|
|
391
|
+
|
|
392
|
+
export { SparkPoFormComponent };
|
|
393
|
+
//# sourceMappingURL=mintplayer-ng-spark-po-form.mjs.map
|