@mmlogic/components 0.5.2 → 0.5.4
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/{cell-renderer-CmaO0CZT.js → cell-renderer-Coy-aD3k.js} +146 -1
- package/dist/cjs/{client-layout-RZ3Ix-4a.js → client-layout-CqVuJumR.js} +9 -0
- package/dist/cjs/{index-DzRfoAPz.js → index-DVbdkYO3.js} +468 -6
- package/dist/cjs/index.cjs.js +4 -1
- package/dist/cjs/loader.cjs.js +2 -2
- package/dist/cjs/mosterdcomponents.cjs.js +2 -2
- package/dist/cjs/{mrd-boolean-field_23.cjs.entry.js → mrd-boolean-field_25.cjs.entry.js} +5696 -5229
- package/dist/cjs/mrd-merge-view.cjs.entry.js +5 -5
- package/dist/collection/collection-manifest.json +2 -0
- package/dist/collection/components/documents/mrd-document-container/mrd-document-container.css +3 -0
- package/dist/collection/components/documents/mrd-document-container/mrd-document-container.js +23 -3
- package/dist/collection/components/documents/mrd-document-list/mrd-document-list.js +76 -2
- package/dist/collection/components/documents/mrd-document-view/mrd-document-view.js +7 -8
- package/dist/collection/components/email/mrd-email-view/mrd-email-view.css +126 -0
- package/dist/collection/components/email/mrd-email-view/mrd-email-view.js +247 -0
- package/dist/collection/components/fields/file-upload-common.js +23 -7
- package/dist/collection/components/fields/mrd-boolean-field/mrd-boolean-field.js +1 -1
- package/dist/collection/components/fields/mrd-currency-field/mrd-currency-field.js +1 -1
- package/dist/collection/components/fields/mrd-date-field/mrd-date-field.js +1 -1
- package/dist/collection/components/fields/mrd-datetime-field/mrd-datetime-field.js +1 -1
- package/dist/collection/components/fields/mrd-email-field/mrd-email-field.js +1 -1
- package/dist/collection/components/fields/mrd-file-field/mrd-file-field.css +20 -1
- package/dist/collection/components/fields/mrd-file-field/mrd-file-field.js +108 -47
- package/dist/collection/components/fields/mrd-image-field/mrd-image-field.css +44 -0
- package/dist/collection/components/fields/mrd-image-field/mrd-image-field.js +126 -58
- package/dist/collection/components/fields/mrd-longtext-field/mrd-longtext-field.js +1 -1
- package/dist/collection/components/fields/mrd-number-field/mrd-number-field.js +1 -1
- package/dist/collection/components/fields/mrd-relation-field/mrd-relation-field.js +13 -3
- package/dist/collection/components/fields/mrd-secret-field/mrd-secret-field.js +2 -2
- package/dist/collection/components/fields/mrd-text-field/mrd-text-field.js +1 -1
- package/dist/collection/components/fields/mrd-textarea-field/mrd-textarea-field.js +1 -1
- package/dist/collection/components/fields/mrd-time-field/mrd-time-field.js +1 -1
- package/dist/collection/components/form/mrd-field/mrd-field.js +5 -5
- package/dist/collection/components/form/mrd-form/mrd-form.js +63 -10
- package/dist/collection/components/invoice/mrd-invoice-view/mrd-invoice-view.css +145 -0
- package/dist/collection/components/invoice/mrd-invoice-view/mrd-invoice-view.js +281 -0
- package/dist/collection/components/layout/mrd-layout-section/field-value.js +9 -3
- package/dist/collection/components/layout/mrd-layout-section/layout-helpers.js +6 -0
- package/dist/collection/components/layout/mrd-layout-section/mrd-layout-section.css +14 -0
- package/dist/collection/components/layout/mrd-layout-section/mrd-layout-section.js +45 -15
- package/dist/collection/components/merge/mrd-merge-view/mrd-merge-view.js +2 -2
- package/dist/collection/dev/api.js +20 -5
- package/dist/collection/dev/app.js +51 -13
- package/dist/collection/dev/example-data.js +132 -3
- package/dist/collection/types/client-layout.js +6 -0
- package/dist/collection/utils/document-attachments.js +27 -14
- package/dist/collection/utils/i18n.js +144 -0
- package/dist/components/cell-renderer.js +1 -1
- package/dist/components/client-layout.js +1 -1
- package/dist/components/document-attachments.js +1 -1
- package/dist/components/file-upload-common.js +1 -1
- package/dist/components/format.js +1 -1
- package/dist/components/i18n.js +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/mrd-boolean-field2.js +1 -1
- package/dist/components/mrd-currency-field2.js +1 -1
- package/dist/components/mrd-date-field2.js +1 -1
- package/dist/components/mrd-datetime-field2.js +1 -1
- package/dist/components/mrd-document-container2.js +1 -1
- package/dist/components/mrd-document-list2.js +1 -1
- package/dist/components/mrd-document-view2.js +1 -1
- package/dist/components/mrd-email-field2.js +1 -1
- package/dist/components/mrd-email-view.d.ts +11 -0
- package/dist/components/mrd-email-view.js +1 -0
- package/dist/components/mrd-email-view2.js +1 -0
- package/dist/components/mrd-field2.js +1 -1
- package/dist/components/mrd-file-field2.js +1 -1
- package/dist/components/mrd-form.js +1 -1
- package/dist/components/mrd-image-field2.js +1 -1
- package/dist/components/mrd-invoice-view.d.ts +11 -0
- package/dist/components/mrd-invoice-view.js +1 -0
- package/dist/components/mrd-invoice-view2.js +1 -0
- package/dist/components/mrd-layout-section.js +1 -1
- package/dist/components/mrd-longtext-field2.js +1 -1
- package/dist/components/mrd-merge-view.js +1 -1
- package/dist/components/mrd-number-field2.js +1 -1
- package/dist/components/mrd-relation-field2.js +1 -1
- package/dist/components/mrd-secret-field2.js +1 -1
- package/dist/components/mrd-table2.js +1 -1
- package/dist/components/mrd-text-field2.js +1 -1
- package/dist/components/mrd-textarea-field2.js +1 -2
- package/dist/components/mrd-time-field2.js +1 -1
- package/dist/components/purify.es.js +2 -0
- package/dist/esm/{cell-renderer-D63AUZxa.js → cell-renderer-C2FLUrMN.js} +146 -2
- package/dist/esm/{client-layout-DCOAAH92.js → client-layout-Bc42CfJB.js} +7 -1
- package/dist/esm/{index-DiSe6vjv.js → index-CDiBvvJU.js} +468 -6
- package/dist/esm/index.js +1 -1
- package/dist/esm/loader.js +3 -3
- package/dist/esm/mosterdcomponents.js +3 -3
- package/dist/esm/{mrd-boolean-field_23.entry.js → mrd-boolean-field_25.entry.js} +5695 -5230
- package/dist/esm/mrd-merge-view.entry.js +5 -5
- package/dist/mosterdcomponents/index.esm.js +1 -1
- package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -1
- package/dist/mosterdcomponents/{p-2e16a7d0.entry.js → p-4ea5b97c.entry.js} +1 -1
- package/dist/mosterdcomponents/p-8736313b.entry.js +3 -0
- package/dist/mosterdcomponents/{p-DCOAAH92.js → p-Bc42CfJB.js} +1 -1
- package/dist/mosterdcomponents/p-BgsPVesg.js +1 -0
- package/dist/mosterdcomponents/p-CDiBvvJU.js +2 -0
- package/dist/types/components/documents/mrd-document-container/mrd-document-container.d.ts +7 -0
- package/dist/types/components/documents/mrd-document-list/mrd-document-list.d.ts +17 -0
- package/dist/types/components/documents/mrd-document-view/mrd-document-view.d.ts +2 -2
- package/dist/types/components/email/mrd-email-view/mrd-email-view.d.ts +52 -0
- package/dist/types/components/fields/file-upload-common.d.ts +19 -1
- package/dist/types/components/fields/mrd-file-field/mrd-file-field.d.ts +24 -10
- package/dist/types/components/fields/mrd-image-field/mrd-image-field.d.ts +27 -11
- package/dist/types/components/fields/mrd-relation-field/mrd-relation-field.d.ts +7 -0
- package/dist/types/components/form/mrd-form/mrd-form.d.ts +19 -3
- package/dist/types/components/invoice/mrd-invoice-view/mrd-invoice-view.d.ts +60 -0
- package/dist/types/components/layout/mrd-layout-section/layout-helpers.d.ts +3 -0
- package/dist/types/components/layout/mrd-layout-section/mrd-layout-section.d.ts +13 -0
- package/dist/types/components.d.ts +303 -19
- package/dist/types/types/client-layout.d.ts +13 -0
- package/dist/types/utils/document-attachments.d.ts +12 -5
- package/package.json +1 -1
- package/dist/mosterdcomponents/p-CnqDM0Gb.js +0 -1
- package/dist/mosterdcomponents/p-DiSe6vjv.js +0 -2
- package/dist/mosterdcomponents/p-b5f38707.entry.js +0 -3
|
@@ -19,7 +19,21 @@ async function apiRequest(method, path, token, body) {
|
|
|
19
19
|
const text = await resp.text();
|
|
20
20
|
let json;
|
|
21
21
|
try { json = JSON.parse(text); } catch (_) { json = text; }
|
|
22
|
-
return { status: resp.status, ok: resp.ok, body: json };
|
|
22
|
+
return { status: resp.status, ok: resp.ok, body: json, location: resp.headers.get('Location') };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Write (POST/PATCH) that returns no body — only a Location header
|
|
27
|
+
* (create/patch/merge on /data/**, per TASK-0203). Follows the Location
|
|
28
|
+
* header with a GET to hand callers the current record, mirroring
|
|
29
|
+
* content-app's ApiClientService create/update methods.
|
|
30
|
+
*/
|
|
31
|
+
async function apiWriteAndFetch(method, path, token, payload) {
|
|
32
|
+
const write = await apiRequest(method, path, token, payload);
|
|
33
|
+
if (!write.ok) return write;
|
|
34
|
+
const href = write.location || path;
|
|
35
|
+
const { body } = await apiRequest('GET', href, token);
|
|
36
|
+
return { ...write, body };
|
|
23
37
|
}
|
|
24
38
|
|
|
25
39
|
/** Resolve a file/image reference href to a signed, directly-usable URL.
|
|
@@ -95,7 +109,7 @@ async function apiFetchPage(token, baseHref, pageNumber, sort = '') {
|
|
|
95
109
|
}
|
|
96
110
|
|
|
97
111
|
async function apiSubmitForm(token, tenantCode, pluralName, values) {
|
|
98
|
-
const { status, ok, body } = await
|
|
112
|
+
const { status, ok, body } = await apiWriteAndFetch('POST', `/data/${tenantCode}/${pluralName}`, token, values);
|
|
99
113
|
return { status, ok, body };
|
|
100
114
|
}
|
|
101
115
|
|
|
@@ -150,11 +164,12 @@ async function apiSearchMergeCandidates(token, tenantCode, mostSignificantClass,
|
|
|
150
164
|
|
|
151
165
|
/**
|
|
152
166
|
* Merge two DataObjects of the same basic type. Mirrors DataController.merge():
|
|
153
|
-
* POST {winnerHref}/merge with { loser: loserHref, patch }. Returns
|
|
154
|
-
*
|
|
167
|
+
* POST {winnerHref}/merge with { loser: loserHref, patch }. Returns no body
|
|
168
|
+
* (204 + Location, per TASK-0203) — follows Location with a GET for the
|
|
169
|
+
* patched winner record.
|
|
155
170
|
*/
|
|
156
171
|
async function apiMerge(token, winnerHref, loserHref, patch) {
|
|
157
|
-
const { ok, status, body } = await
|
|
172
|
+
const { ok, status, body } = await apiWriteAndFetch('POST', `${winnerHref}/merge`, token, { loser: loserHref, patch });
|
|
158
173
|
if (!ok) throw new Error(`${status}: ${typeof body === 'string' ? body : JSON.stringify(body)}`);
|
|
159
174
|
return body;
|
|
160
175
|
}
|
|
@@ -266,6 +266,41 @@ function initFilePreviewTab() {
|
|
|
266
266
|
section.addEventListener('mrdDownload', (e) => logEvent('mrdDownload', e.detail));
|
|
267
267
|
section.addEventListener('mrdNavigate', (e) => logEvent('mrdNavigate', e.detail));
|
|
268
268
|
});
|
|
269
|
+
|
|
270
|
+
// Invoice View demo (commons.invoice archetype, TASK-0199) — the `lines`
|
|
271
|
+
// RELATED_VIEW is rendered inside mrd-invoice-view via slot="lines", but the
|
|
272
|
+
// page/sort data-loading stays owned by mrd-layout-section, exactly like any
|
|
273
|
+
// other RELATED_VIEW: answer mrdLoadViewPage the same way the Detail View tab
|
|
274
|
+
// does for appointments/share classes.
|
|
275
|
+
const invoiceSection = document.getElementById('invoice-view');
|
|
276
|
+
const invoicePreviewEl = document.getElementById('invoice-view-preview');
|
|
277
|
+
invoiceSection.items = window.EXAMPLE_INVOICE_ITEMS;
|
|
278
|
+
invoiceSection.data = window.EXAMPLE_INVOICE_DATA;
|
|
279
|
+
invoiceSection.archetypes = [window.EXAMPLE_INVOICE_ARCHETYPE];
|
|
280
|
+
invoiceSection.addEventListener('mrdLoadViewPage', async (e) => {
|
|
281
|
+
const { name, page } = e.detail;
|
|
282
|
+
logEvent('mrdLoadViewPage', e.detail);
|
|
283
|
+
await invoiceSection.setViewPage(name, page, window.EXAMPLE_INVOICE_LINES, window.EXAMPLE_INVOICE_LINES.length);
|
|
284
|
+
});
|
|
285
|
+
invoiceSection.addEventListener('mrdAttachments', (e) => {
|
|
286
|
+
logEvent('mrdAttachments', e.detail);
|
|
287
|
+
renderAttachmentPreview(invoicePreviewEl, e.detail.attachments);
|
|
288
|
+
});
|
|
289
|
+
invoiceSection.addEventListener('mrdDownload', (e) => logEvent('mrdDownload', e.detail));
|
|
290
|
+
invoiceSection.addEventListener('mrdNavigate', (e) => logEvent('mrdNavigate', e.detail));
|
|
291
|
+
|
|
292
|
+
// Email View demo (commons.email archetype, TASK-0199) — fully read-only, no
|
|
293
|
+
// RELATED_VIEW/table involved.
|
|
294
|
+
const emailSection = document.getElementById('email-view');
|
|
295
|
+
const emailPreviewEl = document.getElementById('email-view-preview');
|
|
296
|
+
emailSection.data = window.EXAMPLE_EMAIL_DATA;
|
|
297
|
+
emailSection.archetypes = [window.EXAMPLE_EMAIL_ARCHETYPE];
|
|
298
|
+
emailSection.addEventListener('mrdAttachments', (e) => {
|
|
299
|
+
logEvent('mrdAttachments', e.detail);
|
|
300
|
+
renderAttachmentPreview(emailPreviewEl, e.detail.attachments);
|
|
301
|
+
});
|
|
302
|
+
emailSection.addEventListener('mrdDownload', (e) => logEvent('mrdDownload', e.detail));
|
|
303
|
+
emailSection.addEventListener('mrdNavigate', (e) => logEvent('mrdNavigate', e.detail));
|
|
269
304
|
}
|
|
270
305
|
|
|
271
306
|
/* =====================================================================
|
|
@@ -620,7 +655,7 @@ async function renderSection(index) {
|
|
|
620
655
|
try {
|
|
621
656
|
const result = await apiRequest('POST', `${_baseHref}${path}`, authGetToken(), values);
|
|
622
657
|
if (result.ok) {
|
|
623
|
-
const href = result.
|
|
658
|
+
const href = result.location;
|
|
624
659
|
if (href) await section.setViewCreatedObject(name, href);
|
|
625
660
|
} else {
|
|
626
661
|
console.error('[mrdCreateObject] mislukt', result.status, result.body);
|
|
@@ -873,17 +908,20 @@ async function renderForm(layout, record = null, selfHref = null, containerEl =
|
|
|
873
908
|
if (_meUser) form.me = _meUser;
|
|
874
909
|
form.values = record ? initialValues : {};
|
|
875
910
|
|
|
876
|
-
// Upload
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
}
|
|
886
|
-
})
|
|
911
|
+
// Upload each selected file immediately (fires once per file for `multiple` fields);
|
|
912
|
+
// pass `file` back into setFieldValue so mrd-form can resolve the right array entry.
|
|
913
|
+
// The resolved value is { href, fileName } — same shape mrd-table/mrd-layout-section
|
|
914
|
+
// already expect when reading FILE/IMAGE data back — so the filename displays correctly
|
|
915
|
+
// instead of falling back to the upload URI's UUID.
|
|
916
|
+
form.addEventListener('mrdUpload', async (e) => {
|
|
917
|
+
const { name, file } = e.detail;
|
|
918
|
+
try {
|
|
919
|
+
const uri = await apiUploadFile(authGetToken(), _selectedTenant, file);
|
|
920
|
+
await form.setFieldValue(name, { href: uri, fileName: file.name }, file);
|
|
921
|
+
} catch (err) {
|
|
922
|
+
console.error(`[upload] mislukt voor veld "${name}":`, err);
|
|
923
|
+
}
|
|
924
|
+
});
|
|
887
925
|
|
|
888
926
|
form.addEventListener('mrdSubmit', async (e) => {
|
|
889
927
|
document.getElementById('panel-response').innerHTML =
|
|
@@ -922,7 +960,7 @@ async function renderForm(layout, record = null, selfHref = null, containerEl =
|
|
|
922
960
|
renderResponse(200, 'Geen wijzigingen.');
|
|
923
961
|
return;
|
|
924
962
|
}
|
|
925
|
-
const result = await
|
|
963
|
+
const result = await apiWriteAndFetch('PATCH', selfHref, authGetToken(), patch);
|
|
926
964
|
renderResponse(result.status, result.body);
|
|
927
965
|
} else {
|
|
928
966
|
// POST mode: new record
|
|
@@ -69,7 +69,7 @@ window.EXAMPLE_LAYOUT = {
|
|
|
69
69
|
label: "Assets",
|
|
70
70
|
items: [
|
|
71
71
|
{ type: "FIELD", name: "projectLogo", label: "Project Logo", dataType: "IMAGE", required: false, accept: "image/*", maxSize: 5242880 },
|
|
72
|
-
{ type: "FIELD", name: "attachments", label: "Attachments", dataType: "FILE", required: false, accept: ".pdf,.doc,.docx,.zip", maxSize: 10485760 }
|
|
72
|
+
{ type: "FIELD", name: "attachments", label: "Attachments", dataType: "FILE", required: false, accept: ".pdf,.doc,.docx,.zip", maxSize: 10485760, multiple: true }
|
|
73
73
|
]
|
|
74
74
|
},
|
|
75
75
|
{ type: "RELATION", name: "projectManager", label: "Project Manager", relatedClass: "Employee", displayType: "SEARCH", required: true, multiple: false },
|
|
@@ -91,7 +91,15 @@ window.EXAMPLE_VALUES = {
|
|
|
91
91
|
budget: { amount: 150000, currency: "EUR" },
|
|
92
92
|
isPublic: true,
|
|
93
93
|
startDate: "2026-01-15",
|
|
94
|
-
contactEmail: "team@mosterd.nl"
|
|
94
|
+
contactEmail: "team@mosterd.nl",
|
|
95
|
+
// FILE/IMAGE values from the API are { href, fileName } — same shape as everywhere
|
|
96
|
+
// else in this library (mrd-table, mrd-document-view) — so the field shows the real
|
|
97
|
+
// filename instead of the href's UUID.
|
|
98
|
+
projectLogo: { href: "/uploads/proj-9f2c/logo.png", fileName: "mosterd-logo.png" },
|
|
99
|
+
attachments: [
|
|
100
|
+
{ href: "/uploads/proj-9f2c/9f2c-contract.pdf", fileName: "contract-2026.pdf" },
|
|
101
|
+
{ href: "/uploads/proj-9f2c/1a3b-invoice.pdf", fileName: "invoice-042.pdf" },
|
|
102
|
+
],
|
|
95
103
|
};
|
|
96
104
|
|
|
97
105
|
// ─── Companies detail view demo ────────────────────────────────────────────────
|
|
@@ -215,7 +223,9 @@ window.EXAMPLE_COMPANY_METADATA = {
|
|
|
215
223
|
{ type: 'FIELD', label: 'legal form extended', name: 'legalFormExtended', dataType: 'TEXT', required: false },
|
|
216
224
|
{ type: 'FIELD', label: 'rsin', name: 'rsin', dataType: 'TEXT', required: false },
|
|
217
225
|
{ type: 'FIELD', label: 'start date', name: 'startDate', dataType: 'DATE', required: false },
|
|
218
|
-
|
|
226
|
+
// showEmpty demo (TASK-0231): endDate is null on EXAMPLE_COMPANY, so it
|
|
227
|
+
// stays visible with a placeholder instead of being hidden.
|
|
228
|
+
{ type: 'FIELD', label: 'end date', name: 'endDate', dataType: 'DATE', required: false, showEmpty: true },
|
|
219
229
|
{ type: 'FIELD', label: 'primary activity description', name: 'primaryActivityDescription', dataType: 'TEXT', required: false },
|
|
220
230
|
{ type: 'FIELD', label: 'primary activity code', name: 'primaryActivityCode', dataType: 'TEXT', required: false },
|
|
221
231
|
{ type: 'FIELD', label: 'total employees', name: 'totalEmployees', dataType: 'INTEGER', required: false },
|
|
@@ -235,6 +245,9 @@ window.EXAMPLE_COMPANY_METADATA = {
|
|
|
235
245
|
{ type: 'FIELD', label: 'mailing postal code', name: 'mailingPostalCode', dataType: 'TEXT', required: false },
|
|
236
246
|
{ type: 'FIELD', label: 'mailing city', name: 'mailingCity', dataType: 'TEXT', required: false },
|
|
237
247
|
{ type: 'RELATION', label: 'country', name: 'country', relatedClass: 'commons.country', mostSignificantClass: 'countries', required: false },
|
|
248
|
+
// showEmpty demo (TASK-0231): no `parentCompany` link on EXAMPLE_COMPANY,
|
|
249
|
+
// so the relation still renders with a placeholder value.
|
|
250
|
+
{ type: 'RELATION', label: 'parent company', name: 'parentCompany', relatedClass: 'commons.company', mostSignificantClass: 'companies', required: false, showEmpty: true },
|
|
238
251
|
],
|
|
239
252
|
},
|
|
240
253
|
{
|
|
@@ -441,3 +454,119 @@ window.EXAMPLE_DOCUMENT_DATA = {
|
|
|
441
454
|
dossier: { href: '/data/demo/dossiers/42', name: 'Acme Corp — Dossier 2026' },
|
|
442
455
|
},
|
|
443
456
|
};
|
|
457
|
+
|
|
458
|
+
// ─── Invoice View demo (commons.invoice archetype, TASK-0199) ────────────────
|
|
459
|
+
// Exercises mrd-invoice-view via mrd-layout-section's archetype path. `lines`
|
|
460
|
+
// is a real RELATED_VIEW item bound to the commons.invoiceLine archetype — it
|
|
461
|
+
// is rendered *inside* mrd-invoice-view via slot="lines" (mrd-layout-section
|
|
462
|
+
// still owns the table's own page/sort wiring, see renderInvoiceObject()).
|
|
463
|
+
|
|
464
|
+
window.EXAMPLE_INVOICE_ARCHETYPE = {
|
|
465
|
+
archetype: 'commons.invoice',
|
|
466
|
+
slots: {
|
|
467
|
+
invoiceNumber: 'invoiceNumber', invoiceDate: 'invoiceDate', dueDate: 'dueDate',
|
|
468
|
+
netAmount: 'netAmount', taxAmount: 'taxAmount', amount: 'amount', status: 'status',
|
|
469
|
+
customer: 'customer', supplier: 'supplier', lines: 'lines', attachments: 'attachments', container: 'dossier',
|
|
470
|
+
},
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
window.EXAMPLE_INVOICE_ITEMS = [
|
|
474
|
+
{
|
|
475
|
+
type: 'FIELD', name: 'status', label: 'Status', dataType: 'LIST', required: false,
|
|
476
|
+
listItems: [
|
|
477
|
+
{ key: 'draft', label: 'Concept', color: '#6b7280', backgroundColor: '#f3f4f6' },
|
|
478
|
+
{ key: 'sent', label: 'Verzonden', color: '#1d4ed8', backgroundColor: '#dbeafe' },
|
|
479
|
+
{ key: 'paid', label: 'Betaald', color: '#15803d', backgroundColor: '#dcfce7' },
|
|
480
|
+
],
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
type: 'RELATED_VIEW', label: 'Factuurregels', name: 'lines',
|
|
484
|
+
relatedClass: 'demo.invoiceLine', fromClass: 'demo.invoice', showTitle: true,
|
|
485
|
+
archetypes: [{ archetype: 'commons.invoiceLine', slots: { description: 'description', quantity: 'quantity', unitPrice: 'unitPrice', amount: 'amount' } }],
|
|
486
|
+
view: {
|
|
487
|
+
name: null,
|
|
488
|
+
defaultView: true,
|
|
489
|
+
values: [
|
|
490
|
+
{ type: 'FIELD', label: 'Omschrijving', name: 'description', dataType: 'TEXT', required: true },
|
|
491
|
+
{ type: 'FIELD', label: 'Aantal', name: 'quantity', dataType: 'DECIMAL', required: true },
|
|
492
|
+
{ type: 'FIELD', label: 'Prijs', name: 'unitPrice', dataType: 'CURRENCY', required: true },
|
|
493
|
+
{ type: 'FIELD', label: 'Bedrag', name: 'amount', dataType: 'CURRENCY', required: true, aggregate: 'sum' },
|
|
494
|
+
],
|
|
495
|
+
type: 'demo.invoiceLine',
|
|
496
|
+
singularLabel: 'Factuurregel',
|
|
497
|
+
pluralLabel: 'Factuurregels',
|
|
498
|
+
},
|
|
499
|
+
},
|
|
500
|
+
];
|
|
501
|
+
|
|
502
|
+
window.EXAMPLE_INVOICE_DATA = {
|
|
503
|
+
invoiceNumber: 'INV-2026-0142',
|
|
504
|
+
invoiceDate: '2026-06-01',
|
|
505
|
+
dueDate: '2026-06-30',
|
|
506
|
+
status: 'sent',
|
|
507
|
+
netAmount: { amount: 1000, currency: 'EUR' },
|
|
508
|
+
taxAmount: { amount: 210, currency: 'EUR' },
|
|
509
|
+
amount: { amount: 1210, currency: 'EUR' },
|
|
510
|
+
attachments: [
|
|
511
|
+
{ href: '/data/demo/invoices/142/attachments/0', fileName: 'invoice-142.pdf', mimeType: 'application/pdf' },
|
|
512
|
+
],
|
|
513
|
+
_links: {
|
|
514
|
+
self: { href: '/data/demo/invoices/142' },
|
|
515
|
+
customer: { href: '/data/demo/entities/acme', name: 'Acme Corp.' },
|
|
516
|
+
supplier: { href: '/data/demo/entities/mosterd', name: 'Mosterd B.V.' },
|
|
517
|
+
dossier: { href: '/data/demo/dossiers/42', name: 'Acme Corp — Dossier 2026' },
|
|
518
|
+
},
|
|
519
|
+
};
|
|
520
|
+
|
|
521
|
+
window.EXAMPLE_INVOICE_LINES = [
|
|
522
|
+
{
|
|
523
|
+
description: 'Consultancy — juni 2026',
|
|
524
|
+
quantity: 10,
|
|
525
|
+
unitPrice: { amount: 80, currency: 'EUR' },
|
|
526
|
+
amount: { amount: 800, currency: 'EUR' },
|
|
527
|
+
_links: { self: { href: '/data/demo/invoiceLines/1' } },
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
description: 'Projectmanagement',
|
|
531
|
+
quantity: 4,
|
|
532
|
+
unitPrice: { amount: 50, currency: 'EUR' },
|
|
533
|
+
amount: { amount: 200, currency: 'EUR' },
|
|
534
|
+
_links: { self: { href: '/data/demo/invoiceLines/2' } },
|
|
535
|
+
},
|
|
536
|
+
];
|
|
537
|
+
|
|
538
|
+
// ─── Email View demo (commons.email archetype, TASK-0199) ────────────────────
|
|
539
|
+
// Exercises mrd-email-view via mrd-layout-section's archetype path. Fully
|
|
540
|
+
// read-only — no RELATED_VIEW/table involved.
|
|
541
|
+
|
|
542
|
+
window.EXAMPLE_EMAIL_ARCHETYPE = {
|
|
543
|
+
archetype: 'commons.email',
|
|
544
|
+
slots: {
|
|
545
|
+
subject: 'subject', date: 'date', from: 'from', to: 'to', cc: 'cc',
|
|
546
|
+
bodyHtml: 'bodyHtml', bodyText: 'bodyText', headers: 'headers',
|
|
547
|
+
attachments: 'attachments', container: 'dossier',
|
|
548
|
+
},
|
|
549
|
+
};
|
|
550
|
+
|
|
551
|
+
window.EXAMPLE_EMAIL_DATA = {
|
|
552
|
+
subject: 'RE: Contract 2026 — laatste versie bijgevoegd',
|
|
553
|
+
date: '2026-06-02T14:32:00',
|
|
554
|
+
bodyHtml: '<p>Beste Jan,</p><p>Bijgaand de laatste versie van het contract, inclusief de besproken wijzigingen in artikel 4.</p><p>Met vriendelijke groet,<br>Anne</p>',
|
|
555
|
+
headers: 'Message-ID: <abc123@mail.example.com>\nReceived: from mail.example.com by mx.mosterd.com',
|
|
556
|
+
attachments: [
|
|
557
|
+
{ href: '/data/demo/emails/9/attachments/0', fileName: 'contract-2026-v3.pdf', mimeType: 'application/pdf' },
|
|
558
|
+
{ href: '/data/demo/emails/9/attachments/1', fileName: 'wijzigingen.docx' },
|
|
559
|
+
],
|
|
560
|
+
_links: {
|
|
561
|
+
from: { href: '/data/demo/entities/anne', name: 'Anne de Vries <anne@mosterd.com>' },
|
|
562
|
+
to: {
|
|
563
|
+
href: '/data/demo/entities/jan', name: 'Jan Bakker <jan@acme.com>',
|
|
564
|
+
values: [{ href: '/data/demo/entities/jan', name: 'Jan Bakker <jan@acme.com>' }],
|
|
565
|
+
},
|
|
566
|
+
cc: {
|
|
567
|
+
href: '/data/demo/entities/pietcc', name: 'Piet Claassen <piet@acme.com>',
|
|
568
|
+
values: [{ href: '/data/demo/entities/pietcc', name: 'Piet Claassen <piet@acme.com>' }],
|
|
569
|
+
},
|
|
570
|
+
dossier: { href: '/data/demo/dossiers/42', name: 'Acme Corp — Dossier 2026' },
|
|
571
|
+
},
|
|
572
|
+
};
|
|
@@ -72,6 +72,12 @@ export var ClientLayoutNavigateBehaviour;
|
|
|
72
72
|
})(ClientLayoutNavigateBehaviour || (ClientLayoutNavigateBehaviour = {}));
|
|
73
73
|
/** Well-known archetype ids the client renders specially. */
|
|
74
74
|
export const ARCHETYPE_DOCUMENT = 'commons.document';
|
|
75
|
+
export const ARCHETYPE_INVOICE = 'commons.invoice';
|
|
76
|
+
export const ARCHETYPE_EMAIL = 'commons.email';
|
|
77
|
+
/** Bound by a `commons.invoice`'s `lines` relation target class. Used to find the
|
|
78
|
+
* RELATED_VIEW item for the line items generically, by archetype id rather than
|
|
79
|
+
* by name/class string. */
|
|
80
|
+
export const ARCHETYPE_INVOICE_LINE = 'commons.invoiceLine';
|
|
75
81
|
/**
|
|
76
82
|
* Find a binding for `archetypeId` in a published `archetypes` list.
|
|
77
83
|
* Returns `undefined` when the archetype is absent — callers fall back to the
|
|
@@ -1,20 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Extract
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* Extract an archetype's file slot from a data record as a `DocumentAttachment[]` —
|
|
3
|
+
* empty when the slot is unmapped or has no value. `slot` defaults to `'file'` (the
|
|
4
|
+
* commons.document single-file slot); pass `'attachments'` for the multi-file slots
|
|
5
|
+
* on commons.email / commons.invoice. A single-object slot value yields a one-entry
|
|
6
|
+
* array, an array-valued slot yields one entry per item.
|
|
7
|
+
* Shared by mrd-document-view / mrd-invoice-view / mrd-email-view (on load/data-change)
|
|
8
|
+
* and mrd-document-container (row-click prefetch on mrdNavigate), so all report the
|
|
9
|
+
* exact same shape.
|
|
6
10
|
*/
|
|
7
|
-
export function attachmentsFromRecord(archetype, record) {
|
|
8
|
-
var _a
|
|
9
|
-
const field = (_a = archetype === null || archetype === void 0 ? void 0 : archetype.slots) === null || _a === void 0 ? void 0 : _a[
|
|
11
|
+
export function attachmentsFromRecord(archetype, record, slot = 'file') {
|
|
12
|
+
var _a;
|
|
13
|
+
const field = (_a = archetype === null || archetype === void 0 ? void 0 : archetype.slots) === null || _a === void 0 ? void 0 : _a[slot];
|
|
10
14
|
if (!field)
|
|
11
15
|
return [];
|
|
12
|
-
const
|
|
13
|
-
if (!
|
|
16
|
+
const raw = record === null || record === void 0 ? void 0 : record[field];
|
|
17
|
+
if (!raw)
|
|
14
18
|
return [];
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
const items = Array.isArray(raw) ? raw : [raw];
|
|
20
|
+
return items.filter(Boolean).map(item => {
|
|
21
|
+
var _a, _b, _c;
|
|
22
|
+
return ({
|
|
23
|
+
href: item.href,
|
|
24
|
+
fileName: (_a = item.fileName) !== null && _a !== void 0 ? _a : String(item),
|
|
25
|
+
mimeType: (_c = (_b = item.mimeType) !== null && _b !== void 0 ? _b : item.contentType) !== null && _c !== void 0 ? _c : undefined,
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/** Dedup key for the componentDidLoad/@Watch('data') "emit mrdAttachments only on
|
|
30
|
+
* change" guard shared by mrd-document-view / mrd-invoice-view / mrd-email-view. */
|
|
31
|
+
export function attachmentsKey(attachments) {
|
|
32
|
+
return attachments.map(a => a.href).join('|');
|
|
20
33
|
}
|