@mmlogic/components 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/mosterdcomponents.cjs.js +1 -1
- package/dist/cjs/mrd-boolean-field_16.cjs.entry.js +204 -30
- package/dist/collection/components/mrd-field/mrd-field.js +35 -16
- package/dist/collection/components/mrd-form/mrd-form.js +238 -3
- package/dist/collection/components/mrd-form/mrd-form.scss +32 -0
- package/dist/collection/components/mrd-relation-field/mrd-relation-field.js +121 -12
- package/dist/collection/dev/api.js +198 -0
- package/dist/collection/dev/app.js +521 -0
- package/dist/collection/dev/auth.js +156 -0
- package/dist/collection/dev/example-data.js +256 -0
- package/dist/components/mrd-field2.js +1 -1
- package/dist/components/mrd-form.js +1 -1
- package/dist/components/mrd-relation-field2.js +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/esm/mosterdcomponents.js +1 -1
- package/dist/esm/mrd-boolean-field_16.entry.js +205 -31
- package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -1
- package/dist/mosterdcomponents/p-2a8cb2eb.entry.js +1 -0
- package/dist/types/components/mrd-field/mrd-field.d.ts +9 -0
- package/dist/types/components/mrd-form/mrd-form.d.ts +52 -0
- package/dist/types/components/mrd-relation-field/mrd-relation-field.d.ts +14 -1
- package/dist/types/components.d.ts +50 -2
- package/dist/types/types/client-layout.d.ts +1 -0
- package/package.json +1 -1
- package/dist/mosterdcomponents/p-45c40269.entry.js +0 -1
|
@@ -1,25 +1,72 @@
|
|
|
1
1
|
import { Host, h } from "@stencil/core";
|
|
2
|
-
import { ClientLayoutItemType } from "../../types";
|
|
2
|
+
import { ClientLayoutItemType, ClientLayoutItemRelationEditBehavior } from "../../types";
|
|
3
3
|
import { t } from "../../utils/i18n";
|
|
4
4
|
import { validateRequired } from "../../utils/validation";
|
|
5
5
|
export class MrdForm {
|
|
6
6
|
constructor() {
|
|
7
7
|
this.locale = navigator.language;
|
|
8
8
|
this.values = {};
|
|
9
|
+
/**
|
|
10
|
+
* Absolute href of the parent/reference object (e.g. the clientAgreement href
|
|
11
|
+
* when creating an invoice from within a client agreement).
|
|
12
|
+
* Combined with `referenceClass`, mrd-form will automatically pre-fill the
|
|
13
|
+
* matching relation field so dependent DROPDOWN fields can be fetched on load
|
|
14
|
+
* — without the host app needing to know anything about the form layout.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Absolute href of the parent/reference object (e.g. the clientAgreement href
|
|
18
|
+
* when creating an invoice from within a client agreement).
|
|
19
|
+
* Combined with `referenceClass`, mrd-form will automatically pre-fill the
|
|
20
|
+
* matching relation field so dependent DROPDOWN fields can be fetched on load.
|
|
21
|
+
*/
|
|
22
|
+
this.referenceHref = '';
|
|
23
|
+
/**
|
|
24
|
+
* The `mostSignificantClass` of the parent/reference object
|
|
25
|
+
* (e.g. `'clientAgreements'`). Used to locate the matching RELATION field.
|
|
26
|
+
*/
|
|
27
|
+
this.referenceClass = '';
|
|
28
|
+
/** When true, a cancel button is shown next to the submit button. */
|
|
29
|
+
this.showCancel = false;
|
|
9
30
|
this.formValues = {};
|
|
10
31
|
this.errors = {};
|
|
11
32
|
this.submitted = false;
|
|
12
33
|
this.handleFieldChange = (e) => {
|
|
13
34
|
const { name, value } = e.detail;
|
|
35
|
+
const prevHref = this.getHref(this.formValues[name]);
|
|
14
36
|
this.formValues = Object.assign(Object.assign({}, this.formValues), { [name]: value });
|
|
15
37
|
if (this.errors[name]) {
|
|
16
38
|
this.errors = Object.assign(Object.assign({}, this.errors), { [name]: '' });
|
|
17
39
|
}
|
|
40
|
+
// When a field changes, check if it is the commonRelation dependency for any
|
|
41
|
+
// DROPDOWN relation. If so, reset the dependent field and re-fetch its options.
|
|
42
|
+
// Skip when the effective href did not change (e.g. mrdBlur fires after mrdChange
|
|
43
|
+
// with the same value, which would otherwise trigger a duplicate fetch).
|
|
44
|
+
const newHref = this.getHref(value);
|
|
45
|
+
if (newHref === prevHref)
|
|
46
|
+
return;
|
|
47
|
+
for (const rel of this.collectDependentDropdowns()) {
|
|
48
|
+
if (rel.commonRelation !== name)
|
|
49
|
+
continue;
|
|
50
|
+
// Clear the dependent field's current selection (options have changed)
|
|
51
|
+
this.formValues = Object.assign(Object.assign({}, this.formValues), { [rel.name]: null });
|
|
52
|
+
this.mrdFetchAll.emit({
|
|
53
|
+
name: rel.name,
|
|
54
|
+
relatedClass: rel.relatedClass,
|
|
55
|
+
mostSignificantClass: rel.mostSignificantClass,
|
|
56
|
+
commonRelation: rel.commonRelation,
|
|
57
|
+
filter: rel.commonRelation,
|
|
58
|
+
filterValue: newHref, // empty string when dependency was cleared → host should clear the list
|
|
59
|
+
});
|
|
60
|
+
}
|
|
18
61
|
};
|
|
19
62
|
this.handleSearch = (e) => {
|
|
20
63
|
e.stopPropagation();
|
|
21
64
|
this.mrdSearch.emit(e.detail);
|
|
22
65
|
};
|
|
66
|
+
this.handleFetchAll = (e) => {
|
|
67
|
+
e.stopPropagation();
|
|
68
|
+
this.mrdFetchAll.emit(e.detail);
|
|
69
|
+
};
|
|
23
70
|
this.handleSubmit = (e) => {
|
|
24
71
|
e.preventDefault();
|
|
25
72
|
this.submitted = true;
|
|
@@ -32,12 +79,71 @@ export class MrdForm {
|
|
|
32
79
|
var _a;
|
|
33
80
|
this.formValues = Object.assign({}, ((_a = this.values) !== null && _a !== void 0 ? _a : {}));
|
|
34
81
|
}
|
|
82
|
+
componentDidLoad() {
|
|
83
|
+
// Apply reference pre-fill and emit mrdFetchAll for dependent DROPDOWN fields.
|
|
84
|
+
// Deferred so Angular/host prop bindings are settled before we read them.
|
|
85
|
+
setTimeout(() => {
|
|
86
|
+
this.applyReferenceValue();
|
|
87
|
+
this.emitDependentFetchAll();
|
|
88
|
+
}, 0);
|
|
89
|
+
}
|
|
35
90
|
/** Sync formValues when the values prop is set from outside after mount
|
|
36
91
|
* (e.g. when pre-filling an existing record in edit mode). */
|
|
37
92
|
valuesChanged(newValues) {
|
|
38
93
|
this.formValues = Object.assign({}, (newValues !== null && newValues !== void 0 ? newValues : {}));
|
|
94
|
+
this.applyReferenceValue();
|
|
39
95
|
this.errors = {};
|
|
40
96
|
this.submitted = false;
|
|
97
|
+
// Re-check DROPDOWN dependencies now that formValues are updated
|
|
98
|
+
setTimeout(() => this.emitDependentFetchAll(), 0);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* When referenceHref + referenceClass are set, find the matching layout field
|
|
102
|
+
* and inject its value into formValues. This allows dependent DROPDOWN fields
|
|
103
|
+
* (those with commonRelation pointing to that field) to be fetched on load
|
|
104
|
+
* without the host app doing any form-domain logic.
|
|
105
|
+
*
|
|
106
|
+
* Two lookup strategies:
|
|
107
|
+
* 1. Find a RELATION whose mostSignificantClass matches referenceClass.
|
|
108
|
+
* 2. Fallback: find a DROPDOWN whose commonRelation field is absent from the
|
|
109
|
+
* layout (API omitted it because it is implied by the reference context).
|
|
110
|
+
*/
|
|
111
|
+
applyReferenceValue() {
|
|
112
|
+
if (!this.referenceHref || !this.referenceClass)
|
|
113
|
+
return;
|
|
114
|
+
const fieldName = this.resolveReferenceFieldName();
|
|
115
|
+
if (!fieldName)
|
|
116
|
+
return;
|
|
117
|
+
// Only set when not already present (don't overwrite an explicit value)
|
|
118
|
+
if (!this.formValues[fieldName]) {
|
|
119
|
+
this.formValues = Object.assign(Object.assign({}, this.formValues), { [fieldName]: this.referenceHref });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
resolveReferenceFieldName() {
|
|
123
|
+
var _a, _b;
|
|
124
|
+
const allItems = this.collectFields((_b = (_a = this.layout) === null || _a === void 0 ? void 0 : _a.items) !== null && _b !== void 0 ? _b : []);
|
|
125
|
+
// Strategy 1: direct match on mostSignificantClass
|
|
126
|
+
const direct = allItems.find(item => {
|
|
127
|
+
var _a;
|
|
128
|
+
return item.type === ClientLayoutItemType.RELATION &&
|
|
129
|
+
((_a = item.relation) === null || _a === void 0 ? void 0 : _a.mostSignificantClass) === this.referenceClass;
|
|
130
|
+
});
|
|
131
|
+
if (direct === null || direct === void 0 ? void 0 : direct.relation)
|
|
132
|
+
return direct.relation.name;
|
|
133
|
+
// Strategy 2: a DROPDOWN whose commonRelation field was omitted from the layout
|
|
134
|
+
const layoutRelationNames = new Set(allItems
|
|
135
|
+
.filter(item => item.type === ClientLayoutItemType.RELATION)
|
|
136
|
+
.map(item => item.relation.name));
|
|
137
|
+
for (const item of allItems) {
|
|
138
|
+
const rel = item.relation;
|
|
139
|
+
if (item.type === ClientLayoutItemType.RELATION &&
|
|
140
|
+
(rel === null || rel === void 0 ? void 0 : rel.editBehavior) === ClientLayoutItemRelationEditBehavior.DROPDOWN &&
|
|
141
|
+
rel.commonRelation &&
|
|
142
|
+
!layoutRelationNames.has(rel.commonRelation)) {
|
|
143
|
+
return rel.commonRelation;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
41
147
|
}
|
|
42
148
|
async setFieldValue(name, value) {
|
|
43
149
|
this.formValues = Object.assign(Object.assign({}, this.formValues), { [name]: value });
|
|
@@ -45,6 +151,45 @@ export class MrdForm {
|
|
|
45
151
|
this.errors = Object.assign(Object.assign({}, this.errors), { [name]: '' });
|
|
46
152
|
}
|
|
47
153
|
}
|
|
154
|
+
/** Collect all RELATION items that use editBehavior=DROPDOWN with a commonRelation. */
|
|
155
|
+
collectDependentDropdowns() {
|
|
156
|
+
var _a, _b;
|
|
157
|
+
return this.collectFields((_b = (_a = this.layout) === null || _a === void 0 ? void 0 : _a.items) !== null && _b !== void 0 ? _b : [])
|
|
158
|
+
.filter(item => {
|
|
159
|
+
var _a;
|
|
160
|
+
return item.type === ClientLayoutItemType.RELATION &&
|
|
161
|
+
((_a = item.relation) === null || _a === void 0 ? void 0 : _a.editBehavior) === ClientLayoutItemRelationEditBehavior.DROPDOWN &&
|
|
162
|
+
!!item.relation.commonRelation;
|
|
163
|
+
})
|
|
164
|
+
.map(item => item.relation);
|
|
165
|
+
}
|
|
166
|
+
/** Emit mrdFetchAll for every dependent DROPDOWN whose filter value is currently set. */
|
|
167
|
+
emitDependentFetchAll() {
|
|
168
|
+
for (const rel of this.collectDependentDropdowns()) {
|
|
169
|
+
const filterValue = this.getHref(this.formValues[rel.commonRelation]);
|
|
170
|
+
if (filterValue) {
|
|
171
|
+
this.mrdFetchAll.emit({
|
|
172
|
+
name: rel.name,
|
|
173
|
+
relatedClass: rel.relatedClass,
|
|
174
|
+
mostSignificantClass: rel.mostSignificantClass,
|
|
175
|
+
commonRelation: rel.commonRelation,
|
|
176
|
+
filter: rel.commonRelation,
|
|
177
|
+
filterValue,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/** Extract a plain href string from a form value, which can be a string or
|
|
183
|
+
* a RelationSearchResult-like object with an `id` field. */
|
|
184
|
+
getHref(value) {
|
|
185
|
+
if (!value)
|
|
186
|
+
return '';
|
|
187
|
+
if (typeof value === 'string')
|
|
188
|
+
return value;
|
|
189
|
+
if (typeof value === 'object' && 'id' in value)
|
|
190
|
+
return value.id;
|
|
191
|
+
return '';
|
|
192
|
+
}
|
|
48
193
|
collectFields(items) {
|
|
49
194
|
const fields = [];
|
|
50
195
|
for (const item of items) {
|
|
@@ -114,7 +259,7 @@ export class MrdForm {
|
|
|
114
259
|
}
|
|
115
260
|
const fieldName = (_d = (_b = (_a = item.field) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : (_c = item.relation) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : '';
|
|
116
261
|
const fieldValue = this.formValues[fieldName];
|
|
117
|
-
return (h("div", { class: "mrd-form__field" }, h("mrd-field", { item: item, locale: this.locale, value: fieldValue, onMrdChange: this.handleFieldChange, onMrdBlur: this.handleFieldChange, onMrdSearch: this.handleSearch }), this.errors[fieldName] && (h("span", { class: "mrd-form__field-error" }, this.errors[fieldName]))));
|
|
262
|
+
return (h("div", { class: "mrd-form__field" }, h("mrd-field", { item: item, locale: this.locale, value: fieldValue, onMrdChange: this.handleFieldChange, onMrdBlur: this.handleFieldChange, onMrdSearch: this.handleSearch, onMrdFetchAll: this.handleFetchAll }), this.errors[fieldName] && (h("span", { class: "mrd-form__field-error" }, this.errors[fieldName]))));
|
|
118
263
|
});
|
|
119
264
|
}
|
|
120
265
|
render() {
|
|
@@ -122,7 +267,7 @@ export class MrdForm {
|
|
|
122
267
|
return h(Host, null);
|
|
123
268
|
}
|
|
124
269
|
const dir = this.locale.startsWith('ar') ? 'rtl' : 'ltr';
|
|
125
|
-
return (h(Host, null, h("form", { class: "mrd-form", dir: dir, onSubmit: this.handleSubmit, noValidate: true }, this.layout.title && h("h2", { class: "mrd-form__title" }, this.layout.title), h("div", { class: "mrd-form__body" }, this.renderItems(this.layout.items)), h("div", { class: "mrd-form__footer" }, h("button", { type: "submit", class: "mrd-form__submit" }, t('submit', this.locale))))));
|
|
270
|
+
return (h(Host, null, h("form", { class: "mrd-form", dir: dir, onSubmit: this.handleSubmit, noValidate: true }, this.layout.title && h("h2", { class: "mrd-form__title" }, this.layout.title), h("div", { class: "mrd-form__body" }, this.renderItems(this.layout.items)), h("div", { class: "mrd-form__footer" }, h("button", { type: "submit", class: "mrd-form__submit" }, t('submit', this.locale)), this.showCancel && (h("button", { type: "button", class: "mrd-form__cancel", onClick: () => this.mrdCancel.emit() }, t('cancel', this.locale)))))));
|
|
126
271
|
}
|
|
127
272
|
static get is() { return "mrd-form"; }
|
|
128
273
|
static get encapsulation() { return "scoped"; }
|
|
@@ -204,6 +349,66 @@ export class MrdForm {
|
|
|
204
349
|
"getter": false,
|
|
205
350
|
"setter": false,
|
|
206
351
|
"defaultValue": "{}"
|
|
352
|
+
},
|
|
353
|
+
"referenceHref": {
|
|
354
|
+
"type": "string",
|
|
355
|
+
"mutable": false,
|
|
356
|
+
"complexType": {
|
|
357
|
+
"original": "string",
|
|
358
|
+
"resolved": "string",
|
|
359
|
+
"references": {}
|
|
360
|
+
},
|
|
361
|
+
"required": false,
|
|
362
|
+
"optional": false,
|
|
363
|
+
"docs": {
|
|
364
|
+
"tags": [],
|
|
365
|
+
"text": "Absolute href of the parent/reference object (e.g. the clientAgreement href\nwhen creating an invoice from within a client agreement).\nCombined with `referenceClass`, mrd-form will automatically pre-fill the\nmatching relation field so dependent DROPDOWN fields can be fetched on load."
|
|
366
|
+
},
|
|
367
|
+
"getter": false,
|
|
368
|
+
"setter": false,
|
|
369
|
+
"reflect": false,
|
|
370
|
+
"attribute": "reference-href",
|
|
371
|
+
"defaultValue": "''"
|
|
372
|
+
},
|
|
373
|
+
"referenceClass": {
|
|
374
|
+
"type": "string",
|
|
375
|
+
"mutable": false,
|
|
376
|
+
"complexType": {
|
|
377
|
+
"original": "string",
|
|
378
|
+
"resolved": "string",
|
|
379
|
+
"references": {}
|
|
380
|
+
},
|
|
381
|
+
"required": false,
|
|
382
|
+
"optional": false,
|
|
383
|
+
"docs": {
|
|
384
|
+
"tags": [],
|
|
385
|
+
"text": "The `mostSignificantClass` of the parent/reference object\n(e.g. `'clientAgreements'`). Used to locate the matching RELATION field."
|
|
386
|
+
},
|
|
387
|
+
"getter": false,
|
|
388
|
+
"setter": false,
|
|
389
|
+
"reflect": false,
|
|
390
|
+
"attribute": "reference-class",
|
|
391
|
+
"defaultValue": "''"
|
|
392
|
+
},
|
|
393
|
+
"showCancel": {
|
|
394
|
+
"type": "boolean",
|
|
395
|
+
"mutable": false,
|
|
396
|
+
"complexType": {
|
|
397
|
+
"original": "boolean",
|
|
398
|
+
"resolved": "boolean",
|
|
399
|
+
"references": {}
|
|
400
|
+
},
|
|
401
|
+
"required": false,
|
|
402
|
+
"optional": false,
|
|
403
|
+
"docs": {
|
|
404
|
+
"tags": [],
|
|
405
|
+
"text": "When true, a cancel button is shown next to the submit button."
|
|
406
|
+
},
|
|
407
|
+
"getter": false,
|
|
408
|
+
"setter": false,
|
|
409
|
+
"reflect": false,
|
|
410
|
+
"attribute": "show-cancel",
|
|
411
|
+
"defaultValue": "false"
|
|
207
412
|
}
|
|
208
413
|
};
|
|
209
414
|
}
|
|
@@ -235,6 +440,21 @@ export class MrdForm {
|
|
|
235
440
|
}
|
|
236
441
|
}
|
|
237
442
|
}
|
|
443
|
+
}, {
|
|
444
|
+
"method": "mrdCancel",
|
|
445
|
+
"name": "mrdCancel",
|
|
446
|
+
"bubbles": true,
|
|
447
|
+
"cancelable": true,
|
|
448
|
+
"composed": true,
|
|
449
|
+
"docs": {
|
|
450
|
+
"tags": [],
|
|
451
|
+
"text": ""
|
|
452
|
+
},
|
|
453
|
+
"complexType": {
|
|
454
|
+
"original": "void",
|
|
455
|
+
"resolved": "void",
|
|
456
|
+
"references": {}
|
|
457
|
+
}
|
|
238
458
|
}, {
|
|
239
459
|
"method": "mrdSearch",
|
|
240
460
|
"name": "mrdSearch",
|
|
@@ -250,6 +470,21 @@ export class MrdForm {
|
|
|
250
470
|
"resolved": "{ query: string; relatedClass: string; }",
|
|
251
471
|
"references": {}
|
|
252
472
|
}
|
|
473
|
+
}, {
|
|
474
|
+
"method": "mrdFetchAll",
|
|
475
|
+
"name": "mrdFetchAll",
|
|
476
|
+
"bubbles": true,
|
|
477
|
+
"cancelable": true,
|
|
478
|
+
"composed": true,
|
|
479
|
+
"docs": {
|
|
480
|
+
"tags": [],
|
|
481
|
+
"text": ""
|
|
482
|
+
},
|
|
483
|
+
"complexType": {
|
|
484
|
+
"original": "{ name: string; relatedClass: string; mostSignificantClass?: string; commonRelation?: string; filter?: string; filterValue?: string }",
|
|
485
|
+
"resolved": "{ name: string; relatedClass: string; mostSignificantClass?: string | undefined; commonRelation?: string | undefined; filter?: string | undefined; filterValue?: string | undefined; }",
|
|
486
|
+
"references": {}
|
|
487
|
+
}
|
|
253
488
|
}];
|
|
254
489
|
}
|
|
255
490
|
static get methods() {
|
|
@@ -83,6 +83,7 @@
|
|
|
83
83
|
border-top: var(--mrd-border-width) solid var(--mrd-border-color);
|
|
84
84
|
display: flex;
|
|
85
85
|
justify-content: flex-end;
|
|
86
|
+
gap: var(--mrd-space-3);
|
|
86
87
|
}
|
|
87
88
|
|
|
88
89
|
.mrd-form__submit {
|
|
@@ -114,3 +115,34 @@
|
|
|
114
115
|
.mrd-form__submit:active {
|
|
115
116
|
background-color: var(--mrd-color-primary-dark);
|
|
116
117
|
}
|
|
118
|
+
|
|
119
|
+
.mrd-form__cancel {
|
|
120
|
+
display: inline-flex;
|
|
121
|
+
align-items: center;
|
|
122
|
+
justify-content: center;
|
|
123
|
+
height: var(--mrd-input-height);
|
|
124
|
+
padding: 0 var(--mrd-space-6);
|
|
125
|
+
background-color: transparent;
|
|
126
|
+
color: var(--mrd-color-neutral-600);
|
|
127
|
+
font-family: var(--mrd-font-family);
|
|
128
|
+
font-size: var(--mrd-font-size-base);
|
|
129
|
+
font-weight: var(--mrd-font-weight-medium);
|
|
130
|
+
border: var(--mrd-border-width) solid var(--mrd-border-color);
|
|
131
|
+
border-radius: var(--mrd-border-radius);
|
|
132
|
+
cursor: pointer;
|
|
133
|
+
transition: background-color var(--mrd-transition), color var(--mrd-transition);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.mrd-form__cancel:hover {
|
|
137
|
+
background-color: var(--mrd-color-neutral-100);
|
|
138
|
+
color: var(--mrd-color-neutral-800);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.mrd-form__cancel:focus {
|
|
142
|
+
outline: none;
|
|
143
|
+
box-shadow: var(--mrd-shadow-focus);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.mrd-form__cancel:active {
|
|
147
|
+
background-color: var(--mrd-color-neutral-200);
|
|
148
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Host, h } from "@stencil/core";
|
|
2
2
|
import { t } from "../../utils/i18n";
|
|
3
3
|
import { validateRequired } from "../../utils/validation";
|
|
4
|
-
import { ClientLayoutItemRelationDisplayType } from "../../types";
|
|
4
|
+
import { ClientLayoutItemRelationDisplayType, ClientLayoutItemRelationEditBehavior } from "../../types";
|
|
5
5
|
export class MrdRelationField {
|
|
6
6
|
constructor() {
|
|
7
7
|
this.name = '';
|
|
@@ -19,6 +19,7 @@ export class MrdRelationField {
|
|
|
19
19
|
this.value = null;
|
|
20
20
|
this.searchQuery = '';
|
|
21
21
|
this.searchResults = [];
|
|
22
|
+
this.allRecords = [];
|
|
22
23
|
this.isLoading = false;
|
|
23
24
|
this.selectedItems = [];
|
|
24
25
|
this.showResults = false;
|
|
@@ -127,6 +128,9 @@ export class MrdRelationField {
|
|
|
127
128
|
this.mrdBlur.emit({ name: this.name, value: val });
|
|
128
129
|
};
|
|
129
130
|
}
|
|
131
|
+
async setAllRecords(records) {
|
|
132
|
+
this.allRecords = records;
|
|
133
|
+
}
|
|
130
134
|
async setSearchResults(results) {
|
|
131
135
|
this.searchResults = results;
|
|
132
136
|
this.isLoading = false;
|
|
@@ -140,24 +144,41 @@ export class MrdRelationField {
|
|
|
140
144
|
var _a;
|
|
141
145
|
// Pre-fill selectedItems when value is passed as { id, label } objects
|
|
142
146
|
// (e.g. when editing an existing record fetched from the API).
|
|
143
|
-
if (
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
if (this.value) {
|
|
148
|
+
if (Array.isArray(this.value)) {
|
|
149
|
+
if (this.value.length > 0 && typeof this.value[0] === 'object') {
|
|
150
|
+
this.selectedItems = this.value;
|
|
151
|
+
this.searchQuery = '';
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
else if (typeof this.value === 'object') {
|
|
155
|
+
this.selectedItems = [this.value];
|
|
156
|
+
this.searchQuery = (_a = this.value.label) !== null && _a !== void 0 ? _a : '';
|
|
149
157
|
}
|
|
150
158
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
159
|
+
}
|
|
160
|
+
componentDidLoad() {
|
|
161
|
+
// Only emit when there is no commonRelation dependency — the form orchestrates those.
|
|
162
|
+
if (this.editBehavior === ClientLayoutItemRelationEditBehavior.DROPDOWN && !this.commonRelation) {
|
|
163
|
+
// Defer to next tick so parent event listeners are registered after DOM patching
|
|
164
|
+
setTimeout(() => {
|
|
165
|
+
this.mrdFetchAll.emit({
|
|
166
|
+
name: this.name,
|
|
167
|
+
relatedClass: this.relatedClass,
|
|
168
|
+
mostSignificantClass: this.mostSignificantClass || undefined,
|
|
169
|
+
});
|
|
170
|
+
}, 0);
|
|
154
171
|
}
|
|
155
172
|
}
|
|
156
173
|
render() {
|
|
157
|
-
var _a, _b;
|
|
174
|
+
var _a, _b, _c, _d;
|
|
158
175
|
const hasError = !!this.error;
|
|
159
|
-
if (this.
|
|
176
|
+
if (this.editBehavior === ClientLayoutItemRelationEditBehavior.DROPDOWN) {
|
|
160
177
|
const currentValue = Array.isArray(this.value) ? ((_a = this.value[0]) !== null && _a !== void 0 ? _a : '') : ((_b = this.value) !== null && _b !== void 0 ? _b : '');
|
|
178
|
+
return (h(Host, null, h("div", { class: "mrd-relation-field" }, this.label && (h("label", { class: `mrd-relation-field__label${this.required ? ' mrd-relation-field__label--required' : ''}` }, this.label)), h("select", { class: `mrd-relation-field__select${hasError ? ' mrd-relation-field__select--error' : ''}`, name: this.name, required: this.required, disabled: this.disabled, onChange: this.handleDropdownChange }, h("option", { value: "" }, t('select_placeholder', this.locale)), this.allRecords.map(record => (h("option", { key: record.id, value: record.id, selected: record.id === currentValue }, record.label)))), hasError && h("span", { class: "mrd-relation-field__error" }, this.error))));
|
|
179
|
+
}
|
|
180
|
+
if (this.displayType === ClientLayoutItemRelationDisplayType.DROPDOWN) {
|
|
181
|
+
const currentValue = Array.isArray(this.value) ? ((_c = this.value[0]) !== null && _c !== void 0 ? _c : '') : ((_d = this.value) !== null && _d !== void 0 ? _d : '');
|
|
161
182
|
return (h(Host, null, h("div", { class: "mrd-relation-field" }, this.label && (h("label", { class: `mrd-relation-field__label${this.required ? ' mrd-relation-field__label--required' : ''}` }, this.label)), h("select", { class: `mrd-relation-field__select${hasError ? ' mrd-relation-field__select--error' : ''}`, name: this.name, required: this.required, disabled: this.disabled, onChange: this.handleDropdownChange }, h("option", { value: "" }, t('select_placeholder', this.locale)), this.dropdownValues.map(dv => (h("option", { key: dv.key, value: dv.key, selected: dv.key === currentValue }, dv.label)))), hasError && h("span", { class: "mrd-relation-field__error" }, this.error))));
|
|
162
183
|
}
|
|
163
184
|
// SEARCH mode
|
|
@@ -349,6 +370,51 @@ export class MrdRelationField {
|
|
|
349
370
|
"attribute": "display-type",
|
|
350
371
|
"defaultValue": "ClientLayoutItemRelationDisplayType.SEARCH"
|
|
351
372
|
},
|
|
373
|
+
"editBehavior": {
|
|
374
|
+
"type": "string",
|
|
375
|
+
"mutable": false,
|
|
376
|
+
"complexType": {
|
|
377
|
+
"original": "ClientLayoutItemRelationEditBehavior | null",
|
|
378
|
+
"resolved": "ClientLayoutItemRelationEditBehavior.CHECKBOX | ClientLayoutItemRelationEditBehavior.DROPDOWN | ClientLayoutItemRelationEditBehavior.SEARCH | null | undefined",
|
|
379
|
+
"references": {
|
|
380
|
+
"ClientLayoutItemRelationEditBehavior": {
|
|
381
|
+
"location": "import",
|
|
382
|
+
"path": "../../types",
|
|
383
|
+
"id": "src/types/index.ts::ClientLayoutItemRelationEditBehavior",
|
|
384
|
+
"referenceLocation": "ClientLayoutItemRelationEditBehavior"
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
},
|
|
388
|
+
"required": false,
|
|
389
|
+
"optional": true,
|
|
390
|
+
"docs": {
|
|
391
|
+
"tags": [],
|
|
392
|
+
"text": ""
|
|
393
|
+
},
|
|
394
|
+
"getter": false,
|
|
395
|
+
"setter": false,
|
|
396
|
+
"reflect": false,
|
|
397
|
+
"attribute": "edit-behavior"
|
|
398
|
+
},
|
|
399
|
+
"commonRelation": {
|
|
400
|
+
"type": "string",
|
|
401
|
+
"mutable": false,
|
|
402
|
+
"complexType": {
|
|
403
|
+
"original": "string",
|
|
404
|
+
"resolved": "string | undefined",
|
|
405
|
+
"references": {}
|
|
406
|
+
},
|
|
407
|
+
"required": false,
|
|
408
|
+
"optional": true,
|
|
409
|
+
"docs": {
|
|
410
|
+
"tags": [],
|
|
411
|
+
"text": ""
|
|
412
|
+
},
|
|
413
|
+
"getter": false,
|
|
414
|
+
"setter": false,
|
|
415
|
+
"reflect": false,
|
|
416
|
+
"attribute": "common-relation"
|
|
417
|
+
},
|
|
352
418
|
"multiple": {
|
|
353
419
|
"type": "boolean",
|
|
354
420
|
"mutable": false,
|
|
@@ -427,6 +493,7 @@ export class MrdRelationField {
|
|
|
427
493
|
return {
|
|
428
494
|
"searchQuery": {},
|
|
429
495
|
"searchResults": {},
|
|
496
|
+
"allRecords": {},
|
|
430
497
|
"isLoading": {},
|
|
431
498
|
"selectedItems": {},
|
|
432
499
|
"showResults": {},
|
|
@@ -480,10 +547,52 @@ export class MrdRelationField {
|
|
|
480
547
|
"resolved": "{ query: string; relatedClass: string; }",
|
|
481
548
|
"references": {}
|
|
482
549
|
}
|
|
550
|
+
}, {
|
|
551
|
+
"method": "mrdFetchAll",
|
|
552
|
+
"name": "mrdFetchAll",
|
|
553
|
+
"bubbles": true,
|
|
554
|
+
"cancelable": true,
|
|
555
|
+
"composed": true,
|
|
556
|
+
"docs": {
|
|
557
|
+
"tags": [],
|
|
558
|
+
"text": ""
|
|
559
|
+
},
|
|
560
|
+
"complexType": {
|
|
561
|
+
"original": "{ name: string; relatedClass: string; mostSignificantClass?: string; commonRelation?: string; filter?: string; filterValue?: string }",
|
|
562
|
+
"resolved": "{ name: string; relatedClass: string; mostSignificantClass?: string | undefined; commonRelation?: string | undefined; filter?: string | undefined; filterValue?: string | undefined; }",
|
|
563
|
+
"references": {}
|
|
564
|
+
}
|
|
483
565
|
}];
|
|
484
566
|
}
|
|
485
567
|
static get methods() {
|
|
486
568
|
return {
|
|
569
|
+
"setAllRecords": {
|
|
570
|
+
"complexType": {
|
|
571
|
+
"signature": "(records: RelationSearchResult[]) => Promise<void>",
|
|
572
|
+
"parameters": [{
|
|
573
|
+
"name": "records",
|
|
574
|
+
"type": "RelationSearchResult[]",
|
|
575
|
+
"docs": ""
|
|
576
|
+
}],
|
|
577
|
+
"references": {
|
|
578
|
+
"Promise": {
|
|
579
|
+
"location": "global",
|
|
580
|
+
"id": "global::Promise"
|
|
581
|
+
},
|
|
582
|
+
"RelationSearchResult": {
|
|
583
|
+
"location": "import",
|
|
584
|
+
"path": "../../types",
|
|
585
|
+
"id": "src/types/index.ts::RelationSearchResult",
|
|
586
|
+
"referenceLocation": "RelationSearchResult"
|
|
587
|
+
}
|
|
588
|
+
},
|
|
589
|
+
"return": "Promise<void>"
|
|
590
|
+
},
|
|
591
|
+
"docs": {
|
|
592
|
+
"text": "",
|
|
593
|
+
"tags": []
|
|
594
|
+
}
|
|
595
|
+
},
|
|
487
596
|
"setSearchResults": {
|
|
488
597
|
"complexType": {
|
|
489
598
|
"signature": "(results: RelationSearchResult[]) => Promise<void>",
|