@mmlogic/components 0.3.6 → 0.3.8

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 (161) hide show
  1. package/dist/cjs/app-globals-V2Kpy_OQ.js +5 -0
  2. package/dist/cjs/index-BPj2cBXs.js +1570 -0
  3. package/dist/cjs/index.cjs.js +66 -0
  4. package/dist/cjs/loader.cjs.js +13 -0
  5. package/dist/cjs/mosterdcomponents.cjs.js +25 -0
  6. package/dist/cjs/mrd-boolean-field_20.cjs.entry.js +3961 -0
  7. package/dist/cjs/quill-DmFfnC1f.js +16272 -0
  8. package/dist/collection/collection-manifest.json +32 -0
  9. package/dist/collection/components/mrd-boolean-field/mrd-boolean-field.js +199 -0
  10. package/dist/collection/components/mrd-boolean-field/mrd-boolean-field.scss +77 -0
  11. package/dist/collection/components/mrd-currency-field/mrd-currency-field.js +248 -0
  12. package/dist/collection/components/mrd-currency-field/mrd-currency-field.scss +100 -0
  13. package/dist/collection/components/mrd-date-field/mrd-date-field.js +206 -0
  14. package/dist/collection/components/mrd-date-field/mrd-date-field.scss +66 -0
  15. package/dist/collection/components/mrd-datetime-field/mrd-datetime-field.js +240 -0
  16. package/dist/collection/components/mrd-datetime-field/mrd-datetime-field.scss +66 -0
  17. package/dist/collection/components/mrd-email-field/mrd-email-field.js +230 -0
  18. package/dist/collection/components/mrd-email-field/mrd-email-field.scss +69 -0
  19. package/dist/{mosterdcomponents/mrd-field.entry.js → collection/components/mrd-field/mrd-field.js} +179 -28
  20. package/dist/collection/components/mrd-field/mrd-field.scss +118 -0
  21. package/dist/collection/components/mrd-file-field/mrd-file-field.js +341 -0
  22. package/dist/collection/components/mrd-file-field/mrd-file-field.scss +153 -0
  23. package/dist/{mosterdcomponents/mrd-form.entry.js → collection/components/mrd-form/mrd-form.js} +308 -31
  24. package/dist/collection/components/mrd-form/mrd-form.scss +148 -0
  25. package/dist/collection/components/mrd-hyperlink-field/mrd-hyperlink-field.js +291 -0
  26. package/dist/collection/components/mrd-hyperlink-field/mrd-hyperlink-field.scss +91 -0
  27. package/dist/collection/components/mrd-image-field/mrd-image-field.js +356 -0
  28. package/dist/collection/components/mrd-image-field/mrd-image-field.scss +190 -0
  29. package/dist/{mosterdcomponents/mrd-layout-section.entry.js → collection/components/mrd-layout-section/mrd-layout-section.js} +420 -33
  30. package/dist/collection/components/mrd-layout-section/mrd-layout-section.scss +445 -0
  31. package/dist/collection/components/mrd-list-field/mrd-list-field.js +313 -0
  32. package/dist/collection/components/mrd-list-field/mrd-list-field.scss +109 -0
  33. package/dist/collection/components/mrd-longtext-field/mrd-longtext-field.js +227 -0
  34. package/dist/collection/components/mrd-longtext-field/mrd-longtext-field.scss +78 -0
  35. package/dist/collection/components/mrd-number-field/mrd-number-field.js +316 -0
  36. package/dist/collection/components/mrd-number-field/mrd-number-field.scss +77 -0
  37. package/dist/collection/components/mrd-relation-field/mrd-relation-field.js +707 -0
  38. package/dist/collection/components/mrd-relation-field/mrd-relation-field.scss +266 -0
  39. package/dist/collection/components/mrd-secret-field/mrd-secret-field.js +229 -0
  40. package/dist/collection/components/mrd-secret-field/mrd-secret-field.scss +73 -0
  41. package/dist/{mosterdcomponents/mrd-table.entry.js → collection/components/mrd-table/mrd-table.js} +394 -32
  42. package/dist/collection/components/mrd-table/mrd-table.scss +809 -0
  43. package/dist/collection/components/mrd-text-field/mrd-text-field.js +227 -0
  44. package/dist/collection/components/mrd-text-field/mrd-text-field.scss +69 -0
  45. package/dist/collection/components/mrd-textarea-field/mrd-textarea-field.js +267 -0
  46. package/dist/collection/components/mrd-textarea-field/mrd-textarea-field.scss +79 -0
  47. package/dist/collection/components/mrd-time-field/mrd-time-field.js +206 -0
  48. package/dist/collection/components/mrd-time-field/mrd-time-field.scss +66 -0
  49. package/dist/collection/dev/api.js +145 -0
  50. package/dist/collection/dev/app.js +890 -0
  51. package/dist/collection/dev/auth.js +156 -0
  52. package/dist/collection/dev/example-data.js +403 -0
  53. package/dist/collection/dev/sprites.svg +55 -0
  54. package/dist/collection/index.js +1 -0
  55. package/dist/collection/types/client-layout.js +64 -0
  56. package/dist/collection/types/index.js +1 -0
  57. package/dist/{mosterdcomponents/cell-renderer-CbRwLOo8.js → collection/utils/cell-renderer.js} +3 -9
  58. package/dist/{mosterdcomponents/format-BAfsQfy1.js → collection/utils/format.js} +7 -12
  59. package/dist/{mosterdcomponents/i18n-hoGGKbKU.js → collection/utils/i18n.js} +1 -6
  60. package/dist/{mosterdcomponents/validation-ixb43cqU.js → collection/utils/validation.js} +5 -12
  61. package/dist/components/client-layout.js +1 -0
  62. package/dist/components/format.js +1 -0
  63. package/dist/components/i18n.js +1 -0
  64. package/dist/components/index.js +1 -0
  65. package/dist/components/mrd-boolean-field.js +1 -0
  66. package/dist/components/mrd-boolean-field2.js +1 -0
  67. package/dist/components/mrd-currency-field.js +1 -0
  68. package/dist/components/mrd-currency-field2.js +1 -0
  69. package/dist/components/mrd-date-field.js +1 -0
  70. package/dist/components/mrd-date-field2.js +1 -0
  71. package/dist/components/mrd-datetime-field.js +1 -0
  72. package/dist/components/mrd-datetime-field2.js +1 -0
  73. package/dist/components/mrd-email-field.js +1 -0
  74. package/dist/components/mrd-email-field2.js +1 -0
  75. package/dist/components/mrd-field.js +1 -0
  76. package/dist/components/mrd-field2.js +1 -0
  77. package/dist/components/mrd-file-field.js +1 -0
  78. package/dist/components/mrd-file-field2.js +1 -0
  79. package/dist/components/mrd-form.js +1 -0
  80. package/dist/components/mrd-hyperlink-field.js +1 -0
  81. package/dist/components/mrd-hyperlink-field2.js +1 -0
  82. package/dist/components/mrd-image-field.js +1 -0
  83. package/dist/components/mrd-image-field2.js +1 -0
  84. package/dist/components/mrd-layout-section.js +1 -0
  85. package/dist/components/mrd-list-field.js +1 -0
  86. package/dist/components/mrd-list-field2.js +1 -0
  87. package/dist/components/mrd-longtext-field.js +1 -0
  88. package/dist/components/mrd-longtext-field2.js +1 -0
  89. package/dist/components/mrd-number-field.js +1 -0
  90. package/dist/components/mrd-number-field2.js +1 -0
  91. package/dist/components/mrd-relation-field.js +1 -0
  92. package/dist/components/mrd-relation-field2.js +1 -0
  93. package/dist/components/mrd-secret-field.js +1 -0
  94. package/dist/components/mrd-secret-field2.js +1 -0
  95. package/dist/components/mrd-table.js +1 -0
  96. package/dist/components/mrd-table2.js +1 -0
  97. package/dist/components/mrd-text-field.js +1 -0
  98. package/dist/components/mrd-text-field2.js +1 -0
  99. package/dist/components/mrd-textarea-field.js +1 -0
  100. package/dist/components/mrd-textarea-field2.js +1 -0
  101. package/dist/components/mrd-time-field.js +1 -0
  102. package/dist/components/mrd-time-field2.js +1 -0
  103. package/dist/components/quill.js +1 -0
  104. package/dist/components/validation.js +1 -0
  105. package/dist/esm/app-globals-DQuL1Twl.js +3 -0
  106. package/dist/esm/index-_tsCCkAi.js +1561 -0
  107. package/dist/{mosterdcomponents/client-layout-D88nn5zf.js → esm/index.js} +1 -4
  108. package/dist/esm/loader.js +11 -0
  109. package/dist/esm/mosterdcomponents.js +21 -0
  110. package/dist/esm/mrd-boolean-field_20.entry.js +3940 -0
  111. package/dist/{mosterdcomponents/quill-C9pgw_k-.js → esm/quill-CiuCgGz_.js} +1347 -16232
  112. package/dist/index.cjs.js +1 -0
  113. package/dist/index.js +1 -0
  114. package/dist/mosterdcomponents/index-6yQUNVww.js.map +1 -0
  115. package/dist/mosterdcomponents/index.esm.js +1 -5
  116. package/dist/mosterdcomponents/mosterdcomponents.css +1 -180
  117. package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -50
  118. package/dist/mosterdcomponents/p-7bfaee51.entry.js +1 -0
  119. package/dist/mosterdcomponents/p-CiuCgGz_.js +1 -0
  120. package/dist/mosterdcomponents/p-DQuL1Twl.js +1 -0
  121. package/dist/mosterdcomponents/p-_tsCCkAi.js +2 -0
  122. package/package.json +1 -1
  123. package/dist/mosterdcomponents/index-B_tPFIvS.js +0 -4585
  124. package/dist/mosterdcomponents/index-B_tPFIvS.js.map +0 -1
  125. package/dist/mosterdcomponents/index-I5SuYv7a.js +0 -4
  126. package/dist/mosterdcomponents/mrd-boolean-field.entry.js +0 -37
  127. package/dist/mosterdcomponents/mrd-boolean-field.entry.js.map +0 -1
  128. package/dist/mosterdcomponents/mrd-currency-field.entry.js +0 -67
  129. package/dist/mosterdcomponents/mrd-currency-field.entry.js.map +0 -1
  130. package/dist/mosterdcomponents/mrd-date-field.entry.js +0 -46
  131. package/dist/mosterdcomponents/mrd-date-field.entry.js.map +0 -1
  132. package/dist/mosterdcomponents/mrd-datetime-field.entry.js +0 -78
  133. package/dist/mosterdcomponents/mrd-datetime-field.entry.js.map +0 -1
  134. package/dist/mosterdcomponents/mrd-email-field.entry.js +0 -50
  135. package/dist/mosterdcomponents/mrd-email-field.entry.js.map +0 -1
  136. package/dist/mosterdcomponents/mrd-field.entry.js.map +0 -1
  137. package/dist/mosterdcomponents/mrd-file-field.entry.js +0 -108
  138. package/dist/mosterdcomponents/mrd-file-field.entry.js.map +0 -1
  139. package/dist/mosterdcomponents/mrd-form.entry.js.map +0 -1
  140. package/dist/mosterdcomponents/mrd-hyperlink-field.entry.js +0 -87
  141. package/dist/mosterdcomponents/mrd-hyperlink-field.entry.js.map +0 -1
  142. package/dist/mosterdcomponents/mrd-image-field.entry.js +0 -122
  143. package/dist/mosterdcomponents/mrd-image-field.entry.js.map +0 -1
  144. package/dist/mosterdcomponents/mrd-layout-section.entry.js.map +0 -1
  145. package/dist/mosterdcomponents/mrd-list-field.entry.js +0 -107
  146. package/dist/mosterdcomponents/mrd-list-field.entry.js.map +0 -1
  147. package/dist/mosterdcomponents/mrd-longtext-field.entry.js +0 -47
  148. package/dist/mosterdcomponents/mrd-longtext-field.entry.js.map +0 -1
  149. package/dist/mosterdcomponents/mrd-number-field.entry.js +0 -87
  150. package/dist/mosterdcomponents/mrd-number-field.entry.js.map +0 -1
  151. package/dist/mosterdcomponents/mrd-relation-field.entry.js +0 -267
  152. package/dist/mosterdcomponents/mrd-relation-field.entry.js.map +0 -1
  153. package/dist/mosterdcomponents/mrd-secret-field.entry.js +0 -49
  154. package/dist/mosterdcomponents/mrd-secret-field.entry.js.map +0 -1
  155. package/dist/mosterdcomponents/mrd-table.entry.js.map +0 -1
  156. package/dist/mosterdcomponents/mrd-text-field.entry.js +0 -47
  157. package/dist/mosterdcomponents/mrd-text-field.entry.js.map +0 -1
  158. package/dist/mosterdcomponents/mrd-textarea-field.entry.js +0 -86
  159. package/dist/mosterdcomponents/mrd-textarea-field.entry.js.map +0 -1
  160. package/dist/mosterdcomponents/mrd-time-field.entry.js +0 -46
  161. package/dist/mosterdcomponents/mrd-time-field.entry.js.map +0 -1
@@ -0,0 +1,206 @@
1
+ import { Host, h } from "@stencil/core";
2
+ import { t } from "../../utils/i18n";
3
+ import { validateRequired } from "../../utils/validation";
4
+ export class MrdTimeField {
5
+ constructor() {
6
+ this.name = '';
7
+ this.label = '';
8
+ this.value = '';
9
+ this.required = false;
10
+ this.disabled = false;
11
+ this.locale = navigator.language;
12
+ this.error = '';
13
+ this.handleChange = (e) => {
14
+ const val = e.target.value;
15
+ if (this.required && !validateRequired(val)) {
16
+ this.error = t('required', this.locale);
17
+ }
18
+ else {
19
+ this.error = '';
20
+ }
21
+ this.mrdChange.emit({ name: this.name, value: val });
22
+ };
23
+ this.handleBlur = (e) => {
24
+ const val = e.target.value;
25
+ this.mrdBlur.emit({ name: this.name, value: val });
26
+ };
27
+ }
28
+ render() {
29
+ const hasError = !!this.error;
30
+ return (h(Host, { key: 'c507996709437d8982f9175b286e25598997002d' }, h("div", { key: 'd5f1b7f14d26cae8298cd40491898b39044158f8', class: "mrd-time-field" }, this.label && (h("label", { key: '10976e18df09240e00b045314c4ddd3845d4bfdc', class: `mrd-time-field__label${this.required ? ' mrd-time-field__label--required' : ''}` }, this.label)), h("input", { key: 'bc557333f107a371a7005f9b56dd0395190e63d7', class: `mrd-time-field__input${hasError ? ' mrd-time-field__input--error' : ''}`, type: "time", name: this.name, value: this.value, required: this.required, disabled: this.disabled, onChange: this.handleChange, onBlur: this.handleBlur }), hasError && h("span", { key: 'b5a09c2aa063fa9e2fc3aba411e86b57d879c408', class: "mrd-time-field__error" }, this.error))));
31
+ }
32
+ static get is() { return "mrd-time-field"; }
33
+ static get encapsulation() { return "scoped"; }
34
+ static get originalStyleUrls() {
35
+ return {
36
+ "$": ["mrd-time-field.scss"]
37
+ };
38
+ }
39
+ static get styleUrls() {
40
+ return {
41
+ "$": ["mrd-time-field.css"]
42
+ };
43
+ }
44
+ static get properties() {
45
+ return {
46
+ "name": {
47
+ "type": "string",
48
+ "mutable": false,
49
+ "complexType": {
50
+ "original": "string",
51
+ "resolved": "string",
52
+ "references": {}
53
+ },
54
+ "required": false,
55
+ "optional": false,
56
+ "docs": {
57
+ "tags": [],
58
+ "text": ""
59
+ },
60
+ "getter": false,
61
+ "setter": false,
62
+ "reflect": false,
63
+ "attribute": "name",
64
+ "defaultValue": "''"
65
+ },
66
+ "label": {
67
+ "type": "string",
68
+ "mutable": false,
69
+ "complexType": {
70
+ "original": "string",
71
+ "resolved": "string",
72
+ "references": {}
73
+ },
74
+ "required": false,
75
+ "optional": false,
76
+ "docs": {
77
+ "tags": [],
78
+ "text": ""
79
+ },
80
+ "getter": false,
81
+ "setter": false,
82
+ "reflect": false,
83
+ "attribute": "label",
84
+ "defaultValue": "''"
85
+ },
86
+ "value": {
87
+ "type": "string",
88
+ "mutable": false,
89
+ "complexType": {
90
+ "original": "string",
91
+ "resolved": "string",
92
+ "references": {}
93
+ },
94
+ "required": false,
95
+ "optional": false,
96
+ "docs": {
97
+ "tags": [],
98
+ "text": ""
99
+ },
100
+ "getter": false,
101
+ "setter": false,
102
+ "reflect": false,
103
+ "attribute": "value",
104
+ "defaultValue": "''"
105
+ },
106
+ "required": {
107
+ "type": "boolean",
108
+ "mutable": false,
109
+ "complexType": {
110
+ "original": "boolean",
111
+ "resolved": "boolean",
112
+ "references": {}
113
+ },
114
+ "required": false,
115
+ "optional": false,
116
+ "docs": {
117
+ "tags": [],
118
+ "text": ""
119
+ },
120
+ "getter": false,
121
+ "setter": false,
122
+ "reflect": false,
123
+ "attribute": "required",
124
+ "defaultValue": "false"
125
+ },
126
+ "disabled": {
127
+ "type": "boolean",
128
+ "mutable": false,
129
+ "complexType": {
130
+ "original": "boolean",
131
+ "resolved": "boolean",
132
+ "references": {}
133
+ },
134
+ "required": false,
135
+ "optional": false,
136
+ "docs": {
137
+ "tags": [],
138
+ "text": ""
139
+ },
140
+ "getter": false,
141
+ "setter": false,
142
+ "reflect": false,
143
+ "attribute": "disabled",
144
+ "defaultValue": "false"
145
+ },
146
+ "locale": {
147
+ "type": "string",
148
+ "mutable": false,
149
+ "complexType": {
150
+ "original": "string",
151
+ "resolved": "string",
152
+ "references": {}
153
+ },
154
+ "required": false,
155
+ "optional": false,
156
+ "docs": {
157
+ "tags": [],
158
+ "text": ""
159
+ },
160
+ "getter": false,
161
+ "setter": false,
162
+ "reflect": false,
163
+ "attribute": "locale",
164
+ "defaultValue": "navigator.language"
165
+ }
166
+ };
167
+ }
168
+ static get states() {
169
+ return {
170
+ "error": {}
171
+ };
172
+ }
173
+ static get events() {
174
+ return [{
175
+ "method": "mrdChange",
176
+ "name": "mrdChange",
177
+ "bubbles": true,
178
+ "cancelable": true,
179
+ "composed": true,
180
+ "docs": {
181
+ "tags": [],
182
+ "text": ""
183
+ },
184
+ "complexType": {
185
+ "original": "{ name: string; value: string }",
186
+ "resolved": "{ name: string; value: string; }",
187
+ "references": {}
188
+ }
189
+ }, {
190
+ "method": "mrdBlur",
191
+ "name": "mrdBlur",
192
+ "bubbles": true,
193
+ "cancelable": true,
194
+ "composed": true,
195
+ "docs": {
196
+ "tags": [],
197
+ "text": ""
198
+ },
199
+ "complexType": {
200
+ "original": "{ name: string; value: string }",
201
+ "resolved": "{ name: string; value: string; }",
202
+ "references": {}
203
+ }
204
+ }];
205
+ }
206
+ }
@@ -0,0 +1,66 @@
1
+ :host {
2
+ display: block;
3
+ }
4
+
5
+ .mrd-time-field {
6
+ display: flex;
7
+ flex-direction: column;
8
+ gap: var(--mrd-space-1);
9
+ width: 100%;
10
+ }
11
+
12
+ .mrd-time-field__label {
13
+ display: block;
14
+ font-family: var(--mrd-font-family);
15
+ font-size: var(--mrd-label-font-size);
16
+ font-weight: var(--mrd-label-font-weight);
17
+ color: var(--mrd-label-color);
18
+ }
19
+
20
+ .mrd-time-field__label--required::after {
21
+ content: ' *';
22
+ color: var(--mrd-color-danger);
23
+ }
24
+
25
+ .mrd-time-field__input {
26
+ display: block;
27
+ width: 100%;
28
+ height: var(--mrd-input-height);
29
+ padding: var(--mrd-input-padding-y) var(--mrd-input-padding-x);
30
+ font-family: var(--mrd-font-family);
31
+ font-size: var(--mrd-font-size-base);
32
+ color: var(--mrd-input-color);
33
+ background-color: var(--mrd-input-bg);
34
+ border: var(--mrd-border-width) solid var(--mrd-border-color);
35
+ border-radius: var(--mrd-border-radius);
36
+ transition: border-color var(--mrd-transition), box-shadow var(--mrd-transition);
37
+ outline: none;
38
+ appearance: none;
39
+ box-sizing: border-box;
40
+ cursor: pointer;
41
+ }
42
+
43
+ .mrd-time-field__input:focus {
44
+ border-color: var(--mrd-border-color-focus);
45
+ box-shadow: var(--mrd-shadow-focus);
46
+ }
47
+
48
+ .mrd-time-field__input:disabled {
49
+ background-color: var(--mrd-input-bg-disabled);
50
+ cursor: not-allowed;
51
+ opacity: 0.7;
52
+ }
53
+
54
+ .mrd-time-field__input--error {
55
+ border-color: var(--mrd-border-color-error);
56
+ }
57
+
58
+ .mrd-time-field__input--error:focus {
59
+ box-shadow: var(--mrd-shadow-focus-error);
60
+ }
61
+
62
+ .mrd-time-field__error {
63
+ font-family: var(--mrd-font-family);
64
+ font-size: var(--mrd-error-font-size);
65
+ color: var(--mrd-error-color);
66
+ }
@@ -0,0 +1,145 @@
1
+ /* =====================================================================
2
+ API HELPERS
3
+ ===================================================================== */
4
+
5
+ const API_BASE = 'http://localhost:8080';
6
+
7
+ /**
8
+ * Generic fetch wrapper. Accepts both absolute URLs (from _links.self.href)
9
+ * and relative paths (prefixed with API_BASE).
10
+ */
11
+ async function apiRequest(method, path, token, body) {
12
+ const opts = {
13
+ method,
14
+ headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
15
+ };
16
+ if (body !== undefined) opts.body = JSON.stringify(body);
17
+ const url = path.startsWith('http') ? path : API_BASE + path;
18
+ const resp = await fetch(url, opts);
19
+ const text = await resp.text();
20
+ let json;
21
+ try { json = JSON.parse(text); } catch (_) { json = text; }
22
+ return { status: resp.status, ok: resp.ok, body: json };
23
+ }
24
+
25
+ async function apiFetchTenants(token) {
26
+ const { ok, status, body } = await apiRequest('GET', '/tenants', token);
27
+ if (!ok) throw new Error(`${status}: ${typeof body === 'string' ? body : JSON.stringify(body)}`);
28
+ return body; // array of { tenantCode, name, description, logo }
29
+ }
30
+
31
+ async function apiFetchTypes(token, tenantCode) {
32
+ const { ok, status, body } = await apiRequest('GET', `/metadata/${tenantCode}/types`, token);
33
+ if (!ok) throw new Error(`${status}: ${typeof body === 'string' ? body : JSON.stringify(body)}`);
34
+ return body; // array of { name, pluralName, type, ... }
35
+ }
36
+
37
+ async function apiFetchForm(token, tenantCode, pluralName, formHref = null) {
38
+ const path = formHref || `/metadata/${tenantCode}/form?types=${pluralName}`;
39
+ const { ok, status, body } = await apiRequest('GET', path, token);
40
+ if (!ok) throw new Error(`${status}: ${typeof body === 'string' ? body : JSON.stringify(body)}`);
41
+ const raw = (body && body.layouts && body.layouts.length > 0) ? body.layouts[0]
42
+ : (Array.isArray(body) && body.length > 0) ? body[0]
43
+ : body;
44
+ return mapApiLayoutToMrdForm(raw);
45
+ }
46
+
47
+ async function apiFetchDashboard(token, tenantCode, pluralName) {
48
+ const language = navigator.language;
49
+ const { ok, status, body } = await apiRequest('GET', `/metadata/${tenantCode}/dashboard/${pluralName}?language=${language}`, token);
50
+ if (!ok) throw new Error(`${status}: ${typeof body === 'string' ? body : JSON.stringify(body)}`);
51
+ return body; // { layouts, views, _links }
52
+ }
53
+
54
+ async function apiFetchClassDashboard(token, tenantCode, pluralName, name) {
55
+ const qs = new URLSearchParams({ language: navigator.language });
56
+ if (name) qs.set('name', name);
57
+ const { ok, status, body } = await apiRequest('GET', `/metadata/${tenantCode}/dashboard/${pluralName}?${qs}`, token);
58
+ if (!ok) throw new Error(`${status}: ${typeof body === 'string' ? body : JSON.stringify(body)}`);
59
+ return body;
60
+ }
61
+
62
+ async function apiFetchGeneralDashboard(token, tenantCode, name) {
63
+ const qs = new URLSearchParams({ language: navigator.language });
64
+ if (name) qs.set('name', name);
65
+ const { ok, status, body } = await apiRequest('GET', `/metadata/${tenantCode}/dashboard?${qs}`, token);
66
+ if (!ok) throw new Error(`${status}: ${typeof body === 'string' ? body : JSON.stringify(body)}`);
67
+ return body;
68
+ }
69
+
70
+ async function apiFetchNavigationPane(token, tenantCode, name) {
71
+ const qs = new URLSearchParams({ language: navigator.language });
72
+ if (name) qs.set('name', name);
73
+ const { ok, status, body } = await apiRequest('GET', `/metadata/${tenantCode}/navigationPane?${qs}`, token);
74
+ if (!ok) throw new Error(`${status}: ${typeof body === 'string' ? body : JSON.stringify(body)}`);
75
+ return body;
76
+ }
77
+
78
+
79
+ async function apiFetchPage(token, baseHref, pageNumber, sort = '') {
80
+ const sep = baseHref.includes('?') ? '&' : '?';
81
+ let url = `${baseHref}${sep}page=${pageNumber}`;
82
+ if (sort) url += `&sort=${encodeURIComponent(sort)}`;
83
+ const { ok, status, body } = await apiRequest('GET', url, token);
84
+ if (!ok) throw new Error(`${status}: ${typeof body === 'string' ? body : JSON.stringify(body)}`);
85
+ return body; // { _embedded, _links, page }
86
+ }
87
+
88
+ async function apiSubmitForm(token, tenantCode, pluralName, values) {
89
+ const { status, ok, body } = await apiRequest('POST', `/data/${tenantCode}/${pluralName}`, token, values);
90
+ return { status, ok, body };
91
+ }
92
+
93
+ async function apiUploadFile(token, tenantCode, file) {
94
+ // Step 1: obtain a one-time upload URL
95
+ const { ok, status, body } = await apiRequest('GET', `/data/${tenantCode}/upload`, token);
96
+ if (!ok) throw new Error(`Upload-URL ophalen mislukt (${status})`);
97
+ const uploadUrl = typeof body === 'string' ? body : String(body);
98
+
99
+ // Step 2: upload the file as multipart (no auth required)
100
+ const formData = new FormData();
101
+ formData.append('file', file);
102
+ const resp = await fetch(uploadUrl, { method: 'POST', body: formData });
103
+ if (!resp.ok) throw new Error(`Bestand uploaden mislukt (${resp.status})`);
104
+ const uris = await resp.json();
105
+ if (!Array.isArray(uris) || uris.length === 0) throw new Error('Geen binary URI ontvangen na upload');
106
+ return uris[0];
107
+ }
108
+
109
+ async function apiFetchMe(token, tenantCode) {
110
+ const { ok, body } = await apiRequest('GET', `/accounts/${tenantCode}/me`, token);
111
+ if (!ok) return null;
112
+ const href = body?.links?.person?.href;
113
+ const label = body?.links?.person?.name ?? body?.email ?? '';
114
+ if (!href || !label) return null;
115
+ return { id: href, label };
116
+ }
117
+
118
+ async function apiSearchRelation(token, tenantCode, mostSignificantClass, query) {
119
+ const q = encodeURIComponent(query);
120
+ const { ok, status, body } = await apiRequest('GET', `/data/${tenantCode}/${mostSignificantClass}?q=${q}`, token);
121
+ if (!ok) throw new Error(`${status}: ${typeof body === 'string' ? body : JSON.stringify(body)}`);
122
+ const items = (body._embedded && body._embedded[mostSignificantClass]) || [];
123
+ return items.map(item => ({
124
+ id: item._links.self.href,
125
+ label: item.name || item.label || '?',
126
+ }));
127
+ }
128
+
129
+ /* =====================================================================
130
+ LAYOUT MAPPERS
131
+ mrd-form and mrd-field now accept the flat API format directly.
132
+ No transformation needed — pass the raw layout through as-is.
133
+ ===================================================================== */
134
+
135
+ /**
136
+ * Extract a ClientLayout from the raw API form response.
137
+ * The API sends flat items (name, dataType, relatedClass at root level)
138
+ * which mrd-form/mrd-field read directly.
139
+ */
140
+ function mapApiLayoutToMrdForm(raw) {
141
+ if (!raw) return raw;
142
+ // Unwrap OBJECT_FORM_DASHBOARD: keep items at top level, drop type wrapper
143
+ if (Array.isArray(raw.items)) return raw;
144
+ return raw;
145
+ }