@mmlogic/components 0.5.2 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/dist/cjs/{cell-renderer-CmaO0CZT.js → cell-renderer-7KX9Qbml.js} +122 -1
  2. package/dist/cjs/{client-layout-RZ3Ix-4a.js → client-layout-CqVuJumR.js} +9 -0
  3. package/dist/cjs/{index-DzRfoAPz.js → index-DVbdkYO3.js} +468 -6
  4. package/dist/cjs/index.cjs.js +4 -1
  5. package/dist/cjs/loader.cjs.js +2 -2
  6. package/dist/cjs/mosterdcomponents.cjs.js +2 -2
  7. package/dist/cjs/{mrd-boolean-field_23.cjs.entry.js → mrd-boolean-field_25.cjs.entry.js} +5618 -5225
  8. package/dist/cjs/mrd-merge-view.cjs.entry.js +5 -5
  9. package/dist/collection/collection-manifest.json +2 -0
  10. package/dist/collection/components/documents/mrd-document-view/mrd-document-view.js +7 -8
  11. package/dist/collection/components/email/mrd-email-view/mrd-email-view.css +126 -0
  12. package/dist/collection/components/email/mrd-email-view/mrd-email-view.js +247 -0
  13. package/dist/collection/components/fields/file-upload-common.js +23 -7
  14. package/dist/collection/components/fields/mrd-boolean-field/mrd-boolean-field.js +1 -1
  15. package/dist/collection/components/fields/mrd-currency-field/mrd-currency-field.js +1 -1
  16. package/dist/collection/components/fields/mrd-date-field/mrd-date-field.js +1 -1
  17. package/dist/collection/components/fields/mrd-datetime-field/mrd-datetime-field.js +1 -1
  18. package/dist/collection/components/fields/mrd-email-field/mrd-email-field.js +1 -1
  19. package/dist/collection/components/fields/mrd-file-field/mrd-file-field.css +20 -1
  20. package/dist/collection/components/fields/mrd-file-field/mrd-file-field.js +108 -47
  21. package/dist/collection/components/fields/mrd-image-field/mrd-image-field.css +44 -0
  22. package/dist/collection/components/fields/mrd-image-field/mrd-image-field.js +126 -58
  23. package/dist/collection/components/fields/mrd-longtext-field/mrd-longtext-field.js +1 -1
  24. package/dist/collection/components/fields/mrd-number-field/mrd-number-field.js +1 -1
  25. package/dist/collection/components/fields/mrd-secret-field/mrd-secret-field.js +2 -2
  26. package/dist/collection/components/fields/mrd-text-field/mrd-text-field.js +1 -1
  27. package/dist/collection/components/fields/mrd-textarea-field/mrd-textarea-field.js +1 -1
  28. package/dist/collection/components/fields/mrd-time-field/mrd-time-field.js +1 -1
  29. package/dist/collection/components/form/mrd-field/mrd-field.js +5 -5
  30. package/dist/collection/components/form/mrd-form/mrd-form.js +55 -6
  31. package/dist/collection/components/invoice/mrd-invoice-view/mrd-invoice-view.css +145 -0
  32. package/dist/collection/components/invoice/mrd-invoice-view/mrd-invoice-view.js +281 -0
  33. package/dist/collection/components/layout/mrd-layout-section/field-value.js +5 -1
  34. package/dist/collection/components/layout/mrd-layout-section/mrd-layout-section.css +10 -0
  35. package/dist/collection/components/layout/mrd-layout-section/mrd-layout-section.js +38 -8
  36. package/dist/collection/components/merge/mrd-merge-view/mrd-merge-view.js +2 -2
  37. package/dist/collection/dev/api.js +20 -5
  38. package/dist/collection/dev/app.js +51 -13
  39. package/dist/collection/dev/example-data.js +126 -2
  40. package/dist/collection/types/client-layout.js +6 -0
  41. package/dist/collection/utils/document-attachments.js +27 -14
  42. package/dist/collection/utils/i18n.js +120 -0
  43. package/dist/components/cell-renderer.js +1 -1
  44. package/dist/components/client-layout.js +1 -1
  45. package/dist/components/document-attachments.js +1 -1
  46. package/dist/components/file-upload-common.js +1 -1
  47. package/dist/components/format.js +1 -1
  48. package/dist/components/i18n.js +1 -1
  49. package/dist/components/index.js +1 -1
  50. package/dist/components/mrd-boolean-field2.js +1 -1
  51. package/dist/components/mrd-currency-field2.js +1 -1
  52. package/dist/components/mrd-date-field2.js +1 -1
  53. package/dist/components/mrd-datetime-field2.js +1 -1
  54. package/dist/components/mrd-document-view2.js +1 -1
  55. package/dist/components/mrd-email-field2.js +1 -1
  56. package/dist/components/mrd-email-view.d.ts +11 -0
  57. package/dist/components/mrd-email-view.js +1 -0
  58. package/dist/components/mrd-email-view2.js +1 -0
  59. package/dist/components/mrd-field2.js +1 -1
  60. package/dist/components/mrd-file-field2.js +1 -1
  61. package/dist/components/mrd-form.js +1 -1
  62. package/dist/components/mrd-image-field2.js +1 -1
  63. package/dist/components/mrd-invoice-view.d.ts +11 -0
  64. package/dist/components/mrd-invoice-view.js +1 -0
  65. package/dist/components/mrd-invoice-view2.js +1 -0
  66. package/dist/components/mrd-layout-section.js +1 -1
  67. package/dist/components/mrd-longtext-field2.js +1 -1
  68. package/dist/components/mrd-merge-view.js +1 -1
  69. package/dist/components/mrd-number-field2.js +1 -1
  70. package/dist/components/mrd-secret-field2.js +1 -1
  71. package/dist/components/mrd-table2.js +1 -1
  72. package/dist/components/mrd-text-field2.js +1 -1
  73. package/dist/components/mrd-textarea-field2.js +1 -2
  74. package/dist/components/mrd-time-field2.js +1 -1
  75. package/dist/components/purify.es.js +2 -0
  76. package/dist/esm/{cell-renderer-D63AUZxa.js → cell-renderer-DIsNX9D7.js} +122 -2
  77. package/dist/esm/{client-layout-DCOAAH92.js → client-layout-Bc42CfJB.js} +7 -1
  78. package/dist/esm/{index-DiSe6vjv.js → index-CDiBvvJU.js} +468 -6
  79. package/dist/esm/index.js +1 -1
  80. package/dist/esm/loader.js +3 -3
  81. package/dist/esm/mosterdcomponents.js +3 -3
  82. package/dist/esm/{mrd-boolean-field_23.entry.js → mrd-boolean-field_25.entry.js} +5617 -5226
  83. package/dist/esm/mrd-merge-view.entry.js +5 -5
  84. package/dist/mosterdcomponents/index.esm.js +1 -1
  85. package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -1
  86. package/dist/mosterdcomponents/{p-2e16a7d0.entry.js → p-4e061416.entry.js} +1 -1
  87. package/dist/mosterdcomponents/p-910ebfee.entry.js +3 -0
  88. package/dist/mosterdcomponents/{p-DCOAAH92.js → p-Bc42CfJB.js} +1 -1
  89. package/dist/mosterdcomponents/p-CDiBvvJU.js +2 -0
  90. package/dist/mosterdcomponents/p-Ce2QDq0t.js +1 -0
  91. package/dist/types/components/documents/mrd-document-view/mrd-document-view.d.ts +2 -2
  92. package/dist/types/components/email/mrd-email-view/mrd-email-view.d.ts +52 -0
  93. package/dist/types/components/fields/file-upload-common.d.ts +19 -1
  94. package/dist/types/components/fields/mrd-file-field/mrd-file-field.d.ts +24 -10
  95. package/dist/types/components/fields/mrd-image-field/mrd-image-field.d.ts +27 -11
  96. package/dist/types/components/form/mrd-form/mrd-form.d.ts +16 -1
  97. package/dist/types/components/invoice/mrd-invoice-view/mrd-invoice-view.d.ts +60 -0
  98. package/dist/types/components/layout/mrd-layout-section/mrd-layout-section.d.ts +13 -0
  99. package/dist/types/components.d.ts +294 -19
  100. package/dist/types/types/client-layout.d.ts +6 -0
  101. package/dist/types/utils/document-attachments.d.ts +12 -5
  102. package/package.json +1 -1
  103. package/dist/mosterdcomponents/p-CnqDM0Gb.js +0 -1
  104. package/dist/mosterdcomponents/p-DiSe6vjv.js +0 -2
  105. package/dist/mosterdcomponents/p-b5f38707.entry.js +0 -3
@@ -1,5 +1,5 @@
1
1
  import { Host, h } from "@stencil/core";
2
- import { ClientLayoutItemType, ClientLayoutItemFieldDataType, ClientLayoutNavigateBehaviour, resolveArchetype, ARCHETYPE_DOCUMENT, } from "../../../types/client-layout";
2
+ import { ClientLayoutItemType, ClientLayoutItemFieldDataType, ClientLayoutNavigateBehaviour, resolveArchetype, ARCHETYPE_DOCUMENT, ARCHETYPE_INVOICE, ARCHETYPE_EMAIL, ARCHETYPE_INVOICE_LINE, } from "../../../types/client-layout";
3
3
  import { viewKeyFor, flattenItems, buildContainerHref } from "./layout-helpers";
4
4
  import { renderField } from "./field-value";
5
5
  export class MrdLayoutSection {
@@ -313,23 +313,53 @@ export class MrdLayoutSection {
313
313
  return null;
314
314
  return (h("div", { class: "mrd-layout-section__modal-backdrop", onClick: () => { this.imagePreviewUrl = null; } }, h("div", { class: "mrd-layout-section__modal", onClick: (e) => e.stopPropagation() }, h("button", { class: "mrd-layout-section__modal-close", onClick: () => { this.imagePreviewUrl = null; } }, "\u2715"), h("img", { class: "mrd-layout-section__modal-image", src: this.imagePreviewUrl, alt: "" }))));
315
315
  }
316
+ /** Related VIEW/RELATED_VIEW/SEARCH items to keep rendering below an archetype's
317
+ * single-object view, excluding any item already consumed by that view itself
318
+ * (e.g. invoice's `lines`, see renderInvoiceObject). */
319
+ relatedItems(exclude) {
320
+ return this.items.filter(it => it !== exclude &&
321
+ (it.type === ClientLayoutItemType.VIEW || it.type === ClientLayoutItemType.RELATED_VIEW || it.type === ClientLayoutItemType.SEARCH));
322
+ }
316
323
  /** Single-document view: the record's own type carries commons.document. Renders
317
324
  * a recognisable document instead of generic fields, keeping any related views/
318
325
  * searches below it. */
319
326
  renderDocumentObject(archetype) {
320
- const related = this.items.filter(it => it.type === ClientLayoutItemType.VIEW ||
321
- it.type === ClientLayoutItemType.RELATED_VIEW ||
322
- it.type === ClientLayoutItemType.SEARCH);
323
327
  return [
324
328
  h("mrd-document-view", { archetype: archetype, data: this.data, locale: this.locale, onMrdNavigate: (e) => { e.stopPropagation(); this.mrdNavigate.emit(e.detail); }, onMrdDownload: (e) => { e.stopPropagation(); this.mrdDownload.emit(e.detail); }, onMrdAttachments: (e) => { e.stopPropagation(); this.mrdAttachments.emit(e.detail); } }),
325
- ...related.map(it => this.renderItem(it)),
329
+ ...this.relatedItems().map(it => this.renderItem(it)),
330
+ ];
331
+ }
332
+ /** Single-invoice view: the record's own type carries commons.invoice. The `lines`
333
+ * RELATED_VIEW (matched generically by the commons.invoiceLine archetype on the
334
+ * item, not by name) is rendered *inside* mrd-invoice-view via its `slot="lines"` —
335
+ * reusing the existing renderRelatedView()/renderTable() wiring unchanged, so all
336
+ * page/sort/aggregation state stays owned here, only the DOM placement moves. */
337
+ renderInvoiceObject(archetype) {
338
+ var _a, _b, _c;
339
+ const linesItem = (_a = this.items.find(it => {
340
+ var _a, _b;
341
+ return (it.type === ClientLayoutItemType.VIEW || it.type === ClientLayoutItemType.RELATED_VIEW) &&
342
+ !!resolveArchetype((_a = it.archetypes) !== null && _a !== void 0 ? _a : (_b = it.view) === null || _b === void 0 ? void 0 : _b.archetypes, ARCHETYPE_INVOICE_LINE);
343
+ })) !== null && _a !== void 0 ? _a : null;
344
+ const statusListItems = (_c = (_b = this.items.find(it => { var _a; return it.name === ((_a = archetype.slots) === null || _a === void 0 ? void 0 : _a.status); })) === null || _b === void 0 ? void 0 : _b.listItems) !== null && _c !== void 0 ? _c : null;
345
+ return [
346
+ h("mrd-invoice-view", { archetype: archetype, data: this.data, locale: this.locale, statusListItems: statusListItems, onMrdNavigate: (e) => { e.stopPropagation(); this.mrdNavigate.emit(e.detail); }, onMrdDownload: (e) => { e.stopPropagation(); this.mrdDownload.emit(e.detail); }, onMrdAttachments: (e) => { e.stopPropagation(); this.mrdAttachments.emit(e.detail); } }, linesItem && h("div", { slot: "lines" }, this.renderRelatedView(linesItem))),
347
+ ...this.relatedItems(linesItem).map(it => this.renderItem(it)),
348
+ ];
349
+ }
350
+ /** Single-email view: the record's own type carries commons.email. Fully read-only —
351
+ * emails have no editable child collection, so this mirrors renderDocumentObject. */
352
+ renderEmailObject(archetype) {
353
+ return [
354
+ h("mrd-email-view", { archetype: archetype, data: this.data, locale: this.locale, onMrdNavigate: (e) => { e.stopPropagation(); this.mrdNavigate.emit(e.detail); }, onMrdDownload: (e) => { e.stopPropagation(); this.mrdDownload.emit(e.detail); }, onMrdAttachments: (e) => { e.stopPropagation(); this.mrdAttachments.emit(e.detail); } }),
355
+ ...this.relatedItems().map(it => this.renderItem(it)),
326
356
  ];
327
357
  }
328
358
  render() {
329
359
  const docArchetype = resolveArchetype(this.archetypes, ARCHETYPE_DOCUMENT);
330
- return (h(Host, { key: '8585dae577d38e3c9517039b48aa9e798190937c' }, h("div", { key: '020b942996b1346bdc3bc89938e4b020823cfcea', class: "mrd-layout-section" }, docArchetype
331
- ? this.renderDocumentObject(docArchetype)
332
- : this.items.map(item => this.renderItem(item))), this.renderImageModal()));
360
+ const invoiceArchetype = !docArchetype ? resolveArchetype(this.archetypes, ARCHETYPE_INVOICE) : undefined;
361
+ const emailArchetype = !docArchetype && !invoiceArchetype ? resolveArchetype(this.archetypes, ARCHETYPE_EMAIL) : undefined;
362
+ return (h(Host, { key: '0078764a136e7ca9561632718c1b527ec3bc01c5' }, h("div", { key: '0c1428ce20bd7d2bbce467a36b6c25ffa0e6367e', class: "mrd-layout-section" }, docArchetype && this.renderDocumentObject(docArchetype), invoiceArchetype && this.renderInvoiceObject(invoiceArchetype), emailArchetype && this.renderEmailObject(emailArchetype), !docArchetype && !invoiceArchetype && !emailArchetype && this.items.map(item => this.renderItem(item))), this.renderImageModal()));
333
363
  }
334
364
  static get is() { return "mrd-layout-section"; }
335
365
  static get encapsulation() { return "scoped"; }
@@ -121,14 +121,14 @@ export class MrdMergeView {
121
121
  var _a, _b;
122
122
  let stepContent;
123
123
  if (this.step === 'search') {
124
- stepContent = (h(MergeSearchStep, { key: '4b79504f62f85274c9cd9681b6819c2318f4246a', locale: this.locale, searchQuery: this.searchQuery, searchResults: this.searchResults, isLoading: this.isLoading, onSearchInput: this.handleSearchInput, onSelect: this.handleSelect }));
124
+ stepContent = (h(MergeSearchStep, { key: '3adb36fb46aa7260641a46a2cf27cc0ef320876f', locale: this.locale, searchQuery: this.searchQuery, searchResults: this.searchResults, isLoading: this.isLoading, onSearchInput: this.handleSearchInput, onSelect: this.handleSelect }));
125
125
  }
126
126
  else {
127
127
  const diff = diffFields(this.fields, this.currentRecord, this.candidate);
128
128
  const bLabel = candidateLabel(this.candidate);
129
129
  stepContent = this.step === 'compare' ? (h(MergeCompareStep, { locale: this.locale, currentLabel: this.currentLabel, candidateLabel: bLabel, conflicts: diff.conflicts, autoFilled: diff.autoFilled, recordA: this.currentRecord, recordB: (_a = this.candidate) !== null && _a !== void 0 ? _a : {}, resolutions: this.resolutions, openHistoryKey: this.openHistoryKey, onResolve: this.handleResolve, onToggleHistory: this.handleToggleHistory, onChangeCandidate: this.handleChangeCandidate, onContinue: this.handleContinue })) : (h(MergeConfirmStep, { locale: this.locale, candidateLabel: bLabel, conflicts: diff.conflicts, autoFilled: diff.autoFilled, resolutions: this.resolutions, recordB: (_b = this.candidate) !== null && _b !== void 0 ? _b : {}, openHistoryKey: this.openHistoryKey, onToggleHistory: this.handleToggleHistory, onBack: this.handleBack, onConfirm: this.handleConfirm }));
130
130
  }
131
- return (h(Host, { key: 'f3fc046fa728646e2ff686d2eae30024da3121e1' }, h("div", { key: '55bef786973d22dce49be021cfb78588b119139c', class: "mrd-merge-view" }, stepContent)));
131
+ return (h(Host, { key: 'e33a6d66a220b28cc9533da78dc274e2d7ec5c4a' }, h("div", { key: 'b5fb1390d86192f9f6f15e3ccb89e2d21d9c7c8b', class: "mrd-merge-view" }, stepContent)));
132
132
  }
133
133
  static get is() { return "mrd-merge-view"; }
134
134
  static get encapsulation() { return "scoped"; }
@@ -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 apiRequest('POST', `/data/${tenantCode}/${pluralName}`, token, values);
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 the
154
- * patched winner record on success.
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 apiRequest('POST', `${winnerHref}/merge`, token, { loser: loserHref, patch });
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.body?._links?.self?.href;
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 files immediately on selection; write binary URI back via setFieldValue
877
- form.addEventListener('mrdChange', async (e) => {
878
- const { name, value } = e.detail;
879
- if (!(value instanceof File)) return;
880
- try {
881
- const uri = await apiUploadFile(authGetToken(), _selectedTenant, value);
882
- await form.setFieldValue(name, uri);
883
- } catch (err) {
884
- console.error(`[upload] mislukt voor veld "${name}":`, err);
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 apiRequest('PATCH', selfHref, authGetToken(), patch);
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 ────────────────────────────────────────────────
@@ -441,3 +449,119 @@ window.EXAMPLE_DOCUMENT_DATA = {
441
449
  dossier: { href: '/data/demo/dossiers/42', name: 'Acme Corp — Dossier 2026' },
442
450
  },
443
451
  };
452
+
453
+ // ─── Invoice View demo (commons.invoice archetype, TASK-0199) ────────────────
454
+ // Exercises mrd-invoice-view via mrd-layout-section's archetype path. `lines`
455
+ // is a real RELATED_VIEW item bound to the commons.invoiceLine archetype — it
456
+ // is rendered *inside* mrd-invoice-view via slot="lines" (mrd-layout-section
457
+ // still owns the table's own page/sort wiring, see renderInvoiceObject()).
458
+
459
+ window.EXAMPLE_INVOICE_ARCHETYPE = {
460
+ archetype: 'commons.invoice',
461
+ slots: {
462
+ invoiceNumber: 'invoiceNumber', invoiceDate: 'invoiceDate', dueDate: 'dueDate',
463
+ netAmount: 'netAmount', taxAmount: 'taxAmount', amount: 'amount', status: 'status',
464
+ customer: 'customer', supplier: 'supplier', lines: 'lines', attachments: 'attachments', container: 'dossier',
465
+ },
466
+ };
467
+
468
+ window.EXAMPLE_INVOICE_ITEMS = [
469
+ {
470
+ type: 'FIELD', name: 'status', label: 'Status', dataType: 'LIST', required: false,
471
+ listItems: [
472
+ { key: 'draft', label: 'Concept', color: '#6b7280', backgroundColor: '#f3f4f6' },
473
+ { key: 'sent', label: 'Verzonden', color: '#1d4ed8', backgroundColor: '#dbeafe' },
474
+ { key: 'paid', label: 'Betaald', color: '#15803d', backgroundColor: '#dcfce7' },
475
+ ],
476
+ },
477
+ {
478
+ type: 'RELATED_VIEW', label: 'Factuurregels', name: 'lines',
479
+ relatedClass: 'demo.invoiceLine', fromClass: 'demo.invoice', showTitle: true,
480
+ archetypes: [{ archetype: 'commons.invoiceLine', slots: { description: 'description', quantity: 'quantity', unitPrice: 'unitPrice', amount: 'amount' } }],
481
+ view: {
482
+ name: null,
483
+ defaultView: true,
484
+ values: [
485
+ { type: 'FIELD', label: 'Omschrijving', name: 'description', dataType: 'TEXT', required: true },
486
+ { type: 'FIELD', label: 'Aantal', name: 'quantity', dataType: 'DECIMAL', required: true },
487
+ { type: 'FIELD', label: 'Prijs', name: 'unitPrice', dataType: 'CURRENCY', required: true },
488
+ { type: 'FIELD', label: 'Bedrag', name: 'amount', dataType: 'CURRENCY', required: true, aggregate: 'sum' },
489
+ ],
490
+ type: 'demo.invoiceLine',
491
+ singularLabel: 'Factuurregel',
492
+ pluralLabel: 'Factuurregels',
493
+ },
494
+ },
495
+ ];
496
+
497
+ window.EXAMPLE_INVOICE_DATA = {
498
+ invoiceNumber: 'INV-2026-0142',
499
+ invoiceDate: '2026-06-01',
500
+ dueDate: '2026-06-30',
501
+ status: 'sent',
502
+ netAmount: { amount: 1000, currency: 'EUR' },
503
+ taxAmount: { amount: 210, currency: 'EUR' },
504
+ amount: { amount: 1210, currency: 'EUR' },
505
+ attachments: [
506
+ { href: '/data/demo/invoices/142/attachments/0', fileName: 'invoice-142.pdf', mimeType: 'application/pdf' },
507
+ ],
508
+ _links: {
509
+ self: { href: '/data/demo/invoices/142' },
510
+ customer: { href: '/data/demo/entities/acme', name: 'Acme Corp.' },
511
+ supplier: { href: '/data/demo/entities/mosterd', name: 'Mosterd B.V.' },
512
+ dossier: { href: '/data/demo/dossiers/42', name: 'Acme Corp — Dossier 2026' },
513
+ },
514
+ };
515
+
516
+ window.EXAMPLE_INVOICE_LINES = [
517
+ {
518
+ description: 'Consultancy — juni 2026',
519
+ quantity: 10,
520
+ unitPrice: { amount: 80, currency: 'EUR' },
521
+ amount: { amount: 800, currency: 'EUR' },
522
+ _links: { self: { href: '/data/demo/invoiceLines/1' } },
523
+ },
524
+ {
525
+ description: 'Projectmanagement',
526
+ quantity: 4,
527
+ unitPrice: { amount: 50, currency: 'EUR' },
528
+ amount: { amount: 200, currency: 'EUR' },
529
+ _links: { self: { href: '/data/demo/invoiceLines/2' } },
530
+ },
531
+ ];
532
+
533
+ // ─── Email View demo (commons.email archetype, TASK-0199) ────────────────────
534
+ // Exercises mrd-email-view via mrd-layout-section's archetype path. Fully
535
+ // read-only — no RELATED_VIEW/table involved.
536
+
537
+ window.EXAMPLE_EMAIL_ARCHETYPE = {
538
+ archetype: 'commons.email',
539
+ slots: {
540
+ subject: 'subject', date: 'date', from: 'from', to: 'to', cc: 'cc',
541
+ bodyHtml: 'bodyHtml', bodyText: 'bodyText', headers: 'headers',
542
+ attachments: 'attachments', container: 'dossier',
543
+ },
544
+ };
545
+
546
+ window.EXAMPLE_EMAIL_DATA = {
547
+ subject: 'RE: Contract 2026 — laatste versie bijgevoegd',
548
+ date: '2026-06-02T14:32:00',
549
+ 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>',
550
+ headers: 'Message-ID: <abc123@mail.example.com>\nReceived: from mail.example.com by mx.mosterd.com',
551
+ attachments: [
552
+ { href: '/data/demo/emails/9/attachments/0', fileName: 'contract-2026-v3.pdf', mimeType: 'application/pdf' },
553
+ { href: '/data/demo/emails/9/attachments/1', fileName: 'wijzigingen.docx' },
554
+ ],
555
+ _links: {
556
+ from: { href: '/data/demo/entities/anne', name: 'Anne de Vries <anne@mosterd.com>' },
557
+ to: {
558
+ href: '/data/demo/entities/jan', name: 'Jan Bakker <jan@acme.com>',
559
+ values: [{ href: '/data/demo/entities/jan', name: 'Jan Bakker <jan@acme.com>' }],
560
+ },
561
+ cc: {
562
+ href: '/data/demo/entities/pietcc', name: 'Piet Claassen <piet@acme.com>',
563
+ values: [{ href: '/data/demo/entities/pietcc', name: 'Piet Claassen <piet@acme.com>' }],
564
+ },
565
+ dossier: { href: '/data/demo/dossiers/42', name: 'Acme Corp — Dossier 2026' },
566
+ },
567
+ };
@@ -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 the `commons.document` archetype's file slot from a data record as a
3
- * `DocumentAttachment[]` — empty when the slot is unmapped or has no value.
4
- * Shared by mrd-document-view (on load/data-change) and mrd-document-container
5
- * (row-click prefetch on mrdNavigate), so both report the exact same shape.
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, _b, _c, _d;
9
- const field = (_a = archetype === null || archetype === void 0 ? void 0 : archetype.slots) === null || _a === void 0 ? void 0 : _a['file'];
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 fileRaw = record === null || record === void 0 ? void 0 : record[field];
13
- if (!fileRaw)
16
+ const raw = record === null || record === void 0 ? void 0 : record[field];
17
+ if (!raw)
14
18
  return [];
15
- return [{
16
- href: fileRaw.href,
17
- fileName: (_b = fileRaw.fileName) !== null && _b !== void 0 ? _b : String(fileRaw),
18
- mimeType: (_d = (_c = fileRaw.mimeType) !== null && _c !== void 0 ? _c : fileRaw.contentType) !== null && _d !== void 0 ? _d : undefined,
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
  }
@@ -85,6 +85,21 @@ const translations = {
85
85
  merge_confirm_heading: 'Bevestig samenvoegen',
86
86
  merge_confirm_warning: 'Dit kan niet ongedaan worden gemaakt: de kandidaat wordt definitief verwijderd.',
87
87
  merge_confirm_button: 'Samenvoegen bevestigen',
88
+ // mrd-invoice-view
89
+ invoice_title: 'Factuur',
90
+ invoice_date: 'Factuurdatum',
91
+ invoice_due_date: 'Vervaldatum',
92
+ invoice_subtotal: 'Subtotaal',
93
+ invoice_tax: 'BTW',
94
+ invoice_total: 'Totaal',
95
+ invoice_customer: 'Klant',
96
+ invoice_supplier: 'Leverancier',
97
+ // mrd-email-view
98
+ email_from: 'Van',
99
+ email_to: 'Aan',
100
+ email_cc: 'Cc',
101
+ email_date: 'Datum',
102
+ email_show_headers: 'Toon technische headers',
88
103
  },
89
104
  en: {
90
105
  required: 'This field is required',
@@ -172,6 +187,21 @@ const translations = {
172
187
  merge_confirm_heading: 'Confirm merge',
173
188
  merge_confirm_warning: 'This cannot be undone: the candidate will be permanently deleted.',
174
189
  merge_confirm_button: 'Confirm merge',
190
+ // mrd-invoice-view
191
+ invoice_title: 'Invoice',
192
+ invoice_date: 'Invoice date',
193
+ invoice_due_date: 'Due date',
194
+ invoice_subtotal: 'Subtotal',
195
+ invoice_tax: 'Tax',
196
+ invoice_total: 'Total',
197
+ invoice_customer: 'Customer',
198
+ invoice_supplier: 'Supplier',
199
+ // mrd-email-view
200
+ email_from: 'From',
201
+ email_to: 'To',
202
+ email_cc: 'Cc',
203
+ email_date: 'Date',
204
+ email_show_headers: 'Show technical headers',
175
205
  },
176
206
  ar: {
177
207
  required: 'هذا الحقل مطلوب',
@@ -253,6 +283,21 @@ const translations = {
253
283
  merge_confirm_heading: 'تأكيد الدمج',
254
284
  merge_confirm_warning: 'لا يمكن التراجع عن هذا الإجراء: سيتم حذف المرشح نهائياً.',
255
285
  merge_confirm_button: 'تأكيد الدمج',
286
+ // mrd-invoice-view
287
+ invoice_title: 'فاتورة',
288
+ invoice_date: 'تاريخ الفاتورة',
289
+ invoice_due_date: 'تاريخ الاستحقاق',
290
+ invoice_subtotal: 'المجموع الفرعي',
291
+ invoice_tax: 'الضريبة',
292
+ invoice_total: 'الإجمالي',
293
+ invoice_customer: 'العميل',
294
+ invoice_supplier: 'المورد',
295
+ // mrd-email-view
296
+ email_from: 'من',
297
+ email_to: 'إلى',
298
+ email_cc: 'نسخة',
299
+ email_date: 'التاريخ',
300
+ email_show_headers: 'إظهار الترويسات التقنية',
256
301
  },
257
302
  fr: {
258
303
  required: 'Ce champ est obligatoire',
@@ -334,6 +379,21 @@ const translations = {
334
379
  merge_confirm_heading: 'Confirmer la fusion',
335
380
  merge_confirm_warning: 'Cette action est irréversible : le candidat sera définitivement supprimé.',
336
381
  merge_confirm_button: 'Confirmer la fusion',
382
+ // mrd-invoice-view
383
+ invoice_title: 'Facture',
384
+ invoice_date: 'Date de facture',
385
+ invoice_due_date: "Date d'échéance",
386
+ invoice_subtotal: 'Sous-total',
387
+ invoice_tax: 'TVA',
388
+ invoice_total: 'Total',
389
+ invoice_customer: 'Client',
390
+ invoice_supplier: 'Fournisseur',
391
+ // mrd-email-view
392
+ email_from: 'De',
393
+ email_to: 'À',
394
+ email_cc: 'Cc',
395
+ email_date: 'Date',
396
+ email_show_headers: 'Afficher les en-têtes techniques',
337
397
  },
338
398
  de: {
339
399
  required: 'Dieses Feld ist erforderlich',
@@ -415,6 +475,21 @@ const translations = {
415
475
  merge_confirm_heading: 'Zusammenführung bestätigen',
416
476
  merge_confirm_warning: 'Dies kann nicht rückgängig gemacht werden: der Kandidat wird endgültig gelöscht.',
417
477
  merge_confirm_button: 'Zusammenführung bestätigen',
478
+ // mrd-invoice-view
479
+ invoice_title: 'Rechnung',
480
+ invoice_date: 'Rechnungsdatum',
481
+ invoice_due_date: 'Fälligkeitsdatum',
482
+ invoice_subtotal: 'Zwischensumme',
483
+ invoice_tax: 'MwSt.',
484
+ invoice_total: 'Gesamt',
485
+ invoice_customer: 'Kunde',
486
+ invoice_supplier: 'Lieferant',
487
+ // mrd-email-view
488
+ email_from: 'Von',
489
+ email_to: 'An',
490
+ email_cc: 'Cc',
491
+ email_date: 'Datum',
492
+ email_show_headers: 'Technische Header anzeigen',
418
493
  },
419
494
  es: {
420
495
  required: 'Este campo es obligatorio',
@@ -496,6 +571,21 @@ const translations = {
496
571
  merge_confirm_heading: 'Confirmar fusión',
497
572
  merge_confirm_warning: 'Esto no se puede deshacer: el candidato se eliminará permanentemente.',
498
573
  merge_confirm_button: 'Confirmar fusión',
574
+ // mrd-invoice-view
575
+ invoice_title: 'Factura',
576
+ invoice_date: 'Fecha de factura',
577
+ invoice_due_date: 'Fecha de vencimiento',
578
+ invoice_subtotal: 'Subtotal',
579
+ invoice_tax: 'Impuesto',
580
+ invoice_total: 'Total',
581
+ invoice_customer: 'Cliente',
582
+ invoice_supplier: 'Proveedor',
583
+ // mrd-email-view
584
+ email_from: 'De',
585
+ email_to: 'Para',
586
+ email_cc: 'Cc',
587
+ email_date: 'Fecha',
588
+ email_show_headers: 'Mostrar encabezados técnicos',
499
589
  },
500
590
  it: {
501
591
  required: 'Questo campo è obbligatorio',
@@ -577,6 +667,21 @@ const translations = {
577
667
  merge_confirm_heading: 'Conferma unione',
578
668
  merge_confirm_warning: "Questa azione non può essere annullata: il candidato verrà eliminato definitivamente.",
579
669
  merge_confirm_button: 'Conferma unione',
670
+ // mrd-invoice-view
671
+ invoice_title: 'Fattura',
672
+ invoice_date: 'Data fattura',
673
+ invoice_due_date: 'Data di scadenza',
674
+ invoice_subtotal: 'Subtotale',
675
+ invoice_tax: 'IVA',
676
+ invoice_total: 'Totale',
677
+ invoice_customer: 'Cliente',
678
+ invoice_supplier: 'Fornitore',
679
+ // mrd-email-view
680
+ email_from: 'Da',
681
+ email_to: 'A',
682
+ email_cc: 'Cc',
683
+ email_date: 'Data',
684
+ email_show_headers: 'Mostra intestazioni tecniche',
580
685
  },
581
686
  uk: {
582
687
  required: "Це поле обов'язкове",
@@ -658,6 +763,21 @@ const translations = {
658
763
  merge_confirm_heading: 'Підтвердити об\'єднання',
659
764
  merge_confirm_warning: 'Цю дію не можна скасувати: кандидат буде остаточно видалено.',
660
765
  merge_confirm_button: 'Підтвердити об\'єднання',
766
+ // mrd-invoice-view
767
+ invoice_title: 'Рахунок-фактура',
768
+ invoice_date: 'Дата рахунку',
769
+ invoice_due_date: 'Термін оплати',
770
+ invoice_subtotal: 'Проміжний підсумок',
771
+ invoice_tax: 'ПДВ',
772
+ invoice_total: 'Разом',
773
+ invoice_customer: 'Клієнт',
774
+ invoice_supplier: 'Постачальник',
775
+ // mrd-email-view
776
+ email_from: 'Від',
777
+ email_to: 'Кому',
778
+ email_cc: 'Копія',
779
+ email_date: 'Дата',
780
+ email_show_headers: 'Показати технічні заголовки',
661
781
  },
662
782
  };
663
783
  export function t(key, locale) {
@@ -1 +1 @@
1
- import{d as r,e,f as t,c as n,a as u,b as a}from"./format.js";import{a as l}from"./client-layout.js";class o{static render(r,e,t){var n,u,a,c;if(r.type===l.RELATION){const t=null!==(n=r.name)&&void 0!==n?n:"",l=null===(u=null==e?void 0:e._links)||void 0===u?void 0:u[t];return l?Array.isArray(l)?l.map((r=>{var e;return null!==(e=r.name)&&void 0!==e?e:""})).filter(Boolean).join(", "):null!==(a=l.name)&&void 0!==a?a:"":""}if(r.type!==l.FIELD)return"";const s=null!==(c=r.name)&&void 0!==c?c:"",i=r.dataType,d=r.listItems;let E=null==e?void 0:e[s];return r.historyEnabled&&null!=E&&"object"==typeof E&&!Array.isArray(E)&&"current"in E&&(E=E.current),null==E||""===E?"":(Array.isArray(E)?E:[E]).map((r=>o.renderValue(null!=i?i:"TEXT",r,null!=d?d:[],t))).filter((r=>""!==r)).join(", ")}static renderValue(l,o,c,s){var i,d;switch(l){case"INTEGER":return u(Number(o),s,{maximumFractionDigits:0});case"DECIMAL":return u(Number(o),s);case"PERCENTAGE":return a(Number(o),s);case"CURRENCY":{const{amount:r,currency:e}="object"==typeof o&&null!==o?o:{amount:o,currency:""};return e?n(Number(r),e,s):u(Number(r),s)}case"DATE":return t(o,s);case"DATETIME":return e(o,s);case"TIME":return r(o,s);case"BOOLEAN":return o?"✓":"";case"FILE":case"IMAGE":return"object"==typeof o&&null!==o&&null!==(i=o.fileName)&&void 0!==i?i:"";case"LIST":{const r=c.find((r=>r.key===String(o)));return null!==(d=null==r?void 0:r.label)&&void 0!==d?d:String(o)}case"TEXTBLOCK":{const r=String(o).replace(/<[^>]*>/g,""),e=document.createElement("textarea");return e.innerHTML=r,e.value.trim()}case"LONGTEXT":return String(o).replace(/[\r\n]+/g," ").trim();case"JSON":return("object"==typeof o?JSON.stringify(o):String(o)).replace(/[\r\n]+/g," ").trim();case"SECRET":return o?"••••••••":"";default:return String(o)}}static formatJson(r,e=!1){try{const t="string"==typeof r?JSON.parse(r):r;return(e?JSON.stringify(t):JSON.stringify(t,null,2)).replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,(r=>{let e="color:#2aa198";return/^"/.test(r)?e=/:$/.test(r)?"color:#881391":"color:#268bd2":/true|false/.test(r)?e="color:#b58900":/null/.test(r)&&(e="color:#dc322f"),`<span style="${e}">${r}</span>`}))}catch(e){return String(r)}}}export{o as C}
1
+ import{e as r,a as e,f as t,b as n,c as u,d as a}from"./format.js";import{a as l}from"./client-layout.js";class o{static render(r,e,t){var n,u,a,c;if(r.type===l.RELATION){const t=null!==(n=r.name)&&void 0!==n?n:"",l=null===(u=null==e?void 0:e._links)||void 0===u?void 0:u[t];return l?Array.isArray(l)?l.map((r=>{var e;return null!==(e=r.name)&&void 0!==e?e:""})).filter(Boolean).join(", "):null!==(a=l.name)&&void 0!==a?a:"":""}if(r.type!==l.FIELD)return"";const s=null!==(c=r.name)&&void 0!==c?c:"",i=r.dataType,d=r.listItems;let E=null==e?void 0:e[s];return r.historyEnabled&&null!=E&&"object"==typeof E&&!Array.isArray(E)&&"current"in E&&(E=E.current),null==E||""===E?"":(Array.isArray(E)?E:[E]).map((r=>o.renderValue(null!=i?i:"TEXT",r,null!=d?d:[],t))).filter((r=>""!==r)).join(", ")}static renderValue(l,o,c,s){var i,d;switch(l){case"INTEGER":return u(Number(o),s,{maximumFractionDigits:0});case"DECIMAL":return u(Number(o),s);case"PERCENTAGE":return a(Number(o),s);case"CURRENCY":{const{amount:r,currency:e}="object"==typeof o&&null!==o?o:{amount:o,currency:""};return e?n(Number(r),e,s):u(Number(r),s)}case"DATE":return t(o,s);case"DATETIME":return e(o,s);case"TIME":return r(o,s);case"BOOLEAN":return o?"✓":"";case"FILE":case"IMAGE":return"object"==typeof o&&null!==o&&null!==(i=o.fileName)&&void 0!==i?i:"";case"LIST":{const r=c.find((r=>r.key===String(o)));return null!==(d=null==r?void 0:r.label)&&void 0!==d?d:String(o)}case"TEXTBLOCK":{const r=String(o).replace(/<[^>]*>/g,""),e=document.createElement("textarea");return e.innerHTML=r,e.value.trim()}case"LONGTEXT":return String(o).replace(/[\r\n]+/g," ").trim();case"JSON":return("object"==typeof o?JSON.stringify(o):String(o)).replace(/[\r\n]+/g," ").trim();case"SECRET":return o?"••••••••":"";default:return String(o)}}static formatJson(r,e=!1){try{const t="string"==typeof r?JSON.parse(r):r;return(e?JSON.stringify(t):JSON.stringify(t,null,2)).replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,(r=>{let e="color:#2aa198";return/^"/.test(r)?e=/:$/.test(r)?"color:#881391":"color:#268bd2":/true|false/.test(r)?e="color:#b58900":/null/.test(r)&&(e="color:#dc322f"),`<span style="${e}">${r}</span>`}))}catch(e){return String(r)}}}export{o as C}
@@ -1 +1 @@
1
- var E,A,T,O,R,n;!function(E){E.OBJECT_FORM_DASHBOARD="OBJECT_FORM_DASHBOARD",E.CLASS_DASHBOARD="CLASS_DASHBOARD",E.GENERAL_DASHBOARD="GENERAL_DASHBOARD",E.NAVIGATION_PANE="NAVIGATION_PANE"}(E||(E={})),function(E){E.FIELD="FIELD",E.RELATION="RELATION",E.SECTION="SECTION",E.GROUP="GROUP",E.HEADER="HEADER",E.TEXT="TEXT",E.NAVIGATE="NAVIGATE",E.ACTION="ACTION",E.SEARCH="SEARCH",E.VIEW="VIEW",E.RELATED_VIEW="RELATED_VIEW",E.RELATED_OBJECT="RELATED_OBJECT"}(A||(A={})),function(E){E.TEXT="TEXT",E.TEXTBLOCK="TEXTBLOCK",E.INTEGER="INTEGER",E.DECIMAL="DECIMAL",E.PERCENTAGE="PERCENTAGE",E.CURRENCY="CURRENCY",E.BOOLEAN="BOOLEAN",E.DATE="DATE",E.DATETIME="DATETIME",E.TIME="TIME",E.EMAIL="EMAIL",E.HYPERLINK="HYPERLINK",E.LIST="LIST",E.FILE="FILE",E.IMAGE="IMAGE",E.LONGTEXT="LONGTEXT",E.JSON="JSON",E.SECRET="SECRET"}(T||(T={})),function(E){E.SEARCH="SEARCH",E.DROPDOWN="DROPDOWN",E.CHECKBOX="CHECKBOX"}(O||(O={})),function(E){E.SEARCH="SEARCH",E.DROPDOWN="DROPDOWN",E.CHECKBOX="CHECKBOX"}(R||(R={})),function(E){E.PAGE="PAGE",E.OVERLAY_PAGE="OVERLAY_PAGE"}(n||(n={}));const C="commons.document";function I(E,A){return(null!=E?E:[]).find((E=>E.archetype===A))}export{C as A,E as C,A as a,T as b,O as c,R as d,n as e,I as r}
1
+ var E,A,n,T,O,R;!function(E){E.OBJECT_FORM_DASHBOARD="OBJECT_FORM_DASHBOARD",E.CLASS_DASHBOARD="CLASS_DASHBOARD",E.GENERAL_DASHBOARD="GENERAL_DASHBOARD",E.NAVIGATION_PANE="NAVIGATION_PANE"}(E||(E={})),function(E){E.FIELD="FIELD",E.RELATION="RELATION",E.SECTION="SECTION",E.GROUP="GROUP",E.HEADER="HEADER",E.TEXT="TEXT",E.NAVIGATE="NAVIGATE",E.ACTION="ACTION",E.SEARCH="SEARCH",E.VIEW="VIEW",E.RELATED_VIEW="RELATED_VIEW",E.RELATED_OBJECT="RELATED_OBJECT"}(A||(A={})),function(E){E.TEXT="TEXT",E.TEXTBLOCK="TEXTBLOCK",E.INTEGER="INTEGER",E.DECIMAL="DECIMAL",E.PERCENTAGE="PERCENTAGE",E.CURRENCY="CURRENCY",E.BOOLEAN="BOOLEAN",E.DATE="DATE",E.DATETIME="DATETIME",E.TIME="TIME",E.EMAIL="EMAIL",E.HYPERLINK="HYPERLINK",E.LIST="LIST",E.FILE="FILE",E.IMAGE="IMAGE",E.LONGTEXT="LONGTEXT",E.JSON="JSON",E.SECRET="SECRET"}(n||(n={})),function(E){E.SEARCH="SEARCH",E.DROPDOWN="DROPDOWN",E.CHECKBOX="CHECKBOX"}(T||(T={})),function(E){E.SEARCH="SEARCH",E.DROPDOWN="DROPDOWN",E.CHECKBOX="CHECKBOX"}(O||(O={})),function(E){E.PAGE="PAGE",E.OVERLAY_PAGE="OVERLAY_PAGE"}(R||(R={}));const o="commons.document",C="commons.invoice",I="commons.email",D="commons.invoiceLine";function N(E,A){return(null!=E?E:[]).find((E=>E.archetype===A))}export{o as A,E as C,A as a,n as b,T as c,O as d,R as e,C as f,I as g,D as h,N as r}