@mmlogic/components 0.5.3 → 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-7KX9Qbml.js → cell-renderer-Coy-aD3k.js} +24 -0
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/mosterdcomponents.cjs.js +1 -1
- package/dist/cjs/mrd-boolean-field_25.cjs.entry.js +97 -23
- package/dist/cjs/mrd-merge-view.cjs.entry.js +1 -1
- 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/fields/mrd-relation-field/mrd-relation-field.js +13 -3
- package/dist/collection/components/form/mrd-form/mrd-form.js +8 -4
- package/dist/collection/components/layout/mrd-layout-section/field-value.js +4 -2
- 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 +4 -0
- package/dist/collection/components/layout/mrd-layout-section/mrd-layout-section.js +8 -8
- package/dist/collection/dev/example-data.js +6 -1
- package/dist/collection/utils/i18n.js +24 -0
- package/dist/components/i18n.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-form.js +1 -1
- package/dist/components/mrd-layout-section.js +1 -1
- package/dist/components/mrd-relation-field2.js +1 -1
- package/dist/esm/{cell-renderer-DIsNX9D7.js → cell-renderer-C2FLUrMN.js} +24 -0
- package/dist/esm/loader.js +1 -1
- package/dist/esm/mosterdcomponents.js +1 -1
- package/dist/esm/mrd-boolean-field_25.entry.js +97 -23
- package/dist/esm/mrd-merge-view.entry.js +1 -1
- package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -1
- package/dist/mosterdcomponents/{p-4e061416.entry.js → p-4ea5b97c.entry.js} +1 -1
- package/dist/mosterdcomponents/p-8736313b.entry.js +3 -0
- package/dist/mosterdcomponents/p-BgsPVesg.js +1 -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/fields/mrd-relation-field/mrd-relation-field.d.ts +7 -0
- package/dist/types/components/form/mrd-form/mrd-form.d.ts +3 -2
- package/dist/types/components/layout/mrd-layout-section/layout-helpers.d.ts +3 -0
- package/dist/types/components.d.ts +9 -0
- package/dist/types/types/client-layout.d.ts +7 -0
- package/package.json +1 -1
- package/dist/mosterdcomponents/p-910ebfee.entry.js +0 -3
- package/dist/mosterdcomponents/p-Ce2QDq0t.js +0 -1
package/dist/collection/components/documents/mrd-document-container/mrd-document-container.js
CHANGED
|
@@ -32,12 +32,28 @@ export class MrdDocumentContainer {
|
|
|
32
32
|
this.mode = 'tree';
|
|
33
33
|
/** Whether the folder tree currently has a valid target for "New folder". */
|
|
34
34
|
this.canCreate = false;
|
|
35
|
+
/** Name of that target (folder path, or the container's label), for the upload tooltip. */
|
|
36
|
+
this.targetLabel = '';
|
|
35
37
|
/** Whether the currently mounted table has been init()'d. Reset on every mode switch. */
|
|
36
38
|
this.tableInited = false;
|
|
37
39
|
this.createFolder = () => {
|
|
38
40
|
var _a;
|
|
39
41
|
(_a = this.listEl) === null || _a === void 0 ? void 0 : _a.createFolder();
|
|
40
42
|
};
|
|
43
|
+
this.pickFile = () => {
|
|
44
|
+
var _a;
|
|
45
|
+
(_a = this.fileInputEl) === null || _a === void 0 ? void 0 : _a.click();
|
|
46
|
+
};
|
|
47
|
+
/** One file per upload, matching the drop handler. Reset the input afterwards
|
|
48
|
+
* so picking the same file twice in a row still fires a change event. */
|
|
49
|
+
this.onFilePicked = (e) => {
|
|
50
|
+
var _a, _b;
|
|
51
|
+
const input = e.target;
|
|
52
|
+
const file = (_a = input.files) === null || _a === void 0 ? void 0 : _a[0];
|
|
53
|
+
if (file)
|
|
54
|
+
(_b = this.listEl) === null || _b === void 0 ? void 0 : _b.uploadFile(file);
|
|
55
|
+
input.value = '';
|
|
56
|
+
};
|
|
41
57
|
}
|
|
42
58
|
/** The embedded table does not self-load: like every mrd-table it waits for the
|
|
43
59
|
* host to call init() (which emits mrdLoadPage, and — once page 0 lands —
|
|
@@ -62,7 +78,7 @@ export class MrdDocumentContainer {
|
|
|
62
78
|
}
|
|
63
79
|
// ── Toolbar ────────────────────────────────────────────────────────────────
|
|
64
80
|
renderToolbar() {
|
|
65
|
-
return (h("div", { class: "mrd-document-container__toolbar" }, this.mode === 'tree' && (h("button", { type: "button", class: "mrd-document-container__action", disabled: !this.canCreate, onClick: this.createFolder }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" }), h("path", { d: "M12 11v4M10 13h4" })), t('new_folder', this.locale))), h("div", { class: "mrd-document-container__seg", role: "group", "aria-label": t('doc_view_switch', this.locale) }, h("button", { class: "mrd-document-container__seg-btn", "aria-pressed": String(this.mode === 'tree'), title: t('doc_view_tree', this.locale), "aria-label": t('doc_view_tree', this.locale), onClick: () => this.setMode('tree') }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M3 5h6M3 12h9M3 19h6" }), h("circle", { cx: "18", cy: "5", r: "1.6" }), h("circle", { cx: "18", cy: "19", r: "1.6" }), h("path", { d: "M16 12h4" }))), h("button", { class: "mrd-document-container__seg-btn", "aria-pressed": String(this.mode === 'list'), title: t('doc_view_list', this.locale), "aria-label": t('doc_view_list', this.locale), onClick: () => this.setMode('list') }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01" }))))));
|
|
81
|
+
return (h("div", { class: "mrd-document-container__toolbar" }, this.mode === 'tree' && (h("button", { type: "button", class: "mrd-document-container__action", disabled: !this.canCreate, onClick: this.createFolder }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" }), h("path", { d: "M12 11v4M10 13h4" })), t('new_folder', this.locale))), this.mode === 'tree' && (h("button", { type: "button", class: "mrd-document-container__action", disabled: !this.canCreate, title: this.targetLabel ? `${t('doc_upload_to', this.locale)} ${this.targetLabel}` : undefined, onClick: this.pickFile }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }), h("path", { d: "M12 3v13M7 8l5-5 5 5" })), t('doc_upload', this.locale))), h("input", { type: "file", class: "mrd-document-container__file-input", ref: el => (this.fileInputEl = el), onChange: this.onFilePicked }), h("div", { class: "mrd-document-container__seg", role: "group", "aria-label": t('doc_view_switch', this.locale) }, h("button", { class: "mrd-document-container__seg-btn", "aria-pressed": String(this.mode === 'tree'), title: t('doc_view_tree', this.locale), "aria-label": t('doc_view_tree', this.locale), onClick: () => this.setMode('tree') }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M3 5h6M3 12h9M3 19h6" }), h("circle", { cx: "18", cy: "5", r: "1.6" }), h("circle", { cx: "18", cy: "19", r: "1.6" }), h("path", { d: "M16 12h4" }))), h("button", { class: "mrd-document-container__seg-btn", "aria-pressed": String(this.mode === 'list'), title: t('doc_view_list', this.locale), "aria-label": t('doc_view_list', this.locale), onClick: () => this.setMode('list') }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01" }))))));
|
|
66
82
|
}
|
|
67
83
|
// ── Bodies ───────────────────────────────────────────────────────────────
|
|
68
84
|
renderTree() {
|
|
@@ -78,6 +94,9 @@ export class MrdDocumentContainer {
|
|
|
78
94
|
}, onMrdCanCreate: (e) => {
|
|
79
95
|
e.stopPropagation();
|
|
80
96
|
this.canCreate = e.detail;
|
|
97
|
+
}, onMrdTargetLabel: (e) => {
|
|
98
|
+
e.stopPropagation();
|
|
99
|
+
this.targetLabel = e.detail;
|
|
81
100
|
}, onMrdUpdateObject: (e) => {
|
|
82
101
|
e.stopPropagation();
|
|
83
102
|
this.mrdUpdateObject.emit(e.detail);
|
|
@@ -114,7 +133,7 @@ export class MrdDocumentContainer {
|
|
|
114
133
|
}
|
|
115
134
|
render() {
|
|
116
135
|
const treeMode = this.mode === 'tree';
|
|
117
|
-
return (h(Host, { key: '
|
|
136
|
+
return (h(Host, { key: 'ae948e2458d9087179e850b527802c489067d93f' }, this.renderToolbar(), h("div", { key: 'a04e1a78413aa794d0bda551aeb9c6245f1aafa2', class: {
|
|
118
137
|
'mrd-document-container__body': true,
|
|
119
138
|
'mrd-document-container__body--tree': treeMode,
|
|
120
139
|
}, style: treeMode ? { height: `${this.height}px`, overflowY: 'auto' } : {} }, treeMode ? this.renderTree() : this.renderList())));
|
|
@@ -287,7 +306,8 @@ export class MrdDocumentContainer {
|
|
|
287
306
|
static get states() {
|
|
288
307
|
return {
|
|
289
308
|
"mode": {},
|
|
290
|
-
"canCreate": {}
|
|
309
|
+
"canCreate": {},
|
|
310
|
+
"targetLabel": {}
|
|
291
311
|
};
|
|
292
312
|
}
|
|
293
313
|
static get events() {
|
|
@@ -64,6 +64,8 @@ export class MrdDocumentList {
|
|
|
64
64
|
this.newFolderSeq = 0;
|
|
65
65
|
/** Last emitted canCreateFolder value, to only emit mrdCanCreate on change. */
|
|
66
66
|
this.lastCanCreate = false;
|
|
67
|
+
/** Last emitted upload-target label, to only emit mrdTargetLabel on change. */
|
|
68
|
+
this.lastTargetLabel = '';
|
|
67
69
|
// ── Drag & drop (move a document into another folder) ──────────────────────
|
|
68
70
|
/** The document row currently being dragged. */
|
|
69
71
|
this.dragDoc = null;
|
|
@@ -237,6 +239,22 @@ export class MrdDocumentList {
|
|
|
237
239
|
this.lastCanCreate = can;
|
|
238
240
|
this.mrdCanCreate.emit(can);
|
|
239
241
|
}
|
|
242
|
+
const label = this.targetLabel;
|
|
243
|
+
if (label !== this.lastTargetLabel) {
|
|
244
|
+
this.lastTargetLabel = label;
|
|
245
|
+
this.mrdTargetLabel.emit(label);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/** Human-readable name of the node a new folder or upload lands in — the
|
|
249
|
+
* folder path when one is selected, otherwise the container's own label.
|
|
250
|
+
* Empty when there is no target at all. */
|
|
251
|
+
get targetLabel() {
|
|
252
|
+
var _a;
|
|
253
|
+
const resolved = this.resolveTarget();
|
|
254
|
+
if (!resolved)
|
|
255
|
+
return '';
|
|
256
|
+
const { target, container } = resolved;
|
|
257
|
+
return (_a = folderStringOf(target, container)) !== null && _a !== void 0 ? _a : target.label;
|
|
240
258
|
}
|
|
241
259
|
// ── Slot field names ─────────────────────────────────────────────────────
|
|
242
260
|
get containerField() {
|
|
@@ -510,12 +528,28 @@ export class MrdDocumentList {
|
|
|
510
528
|
this.dropTargetId = null;
|
|
511
529
|
if (!file)
|
|
512
530
|
return;
|
|
531
|
+
this.beginUpload(file, node, container);
|
|
532
|
+
}
|
|
533
|
+
/** Shared by the file drop and the host toolbar's upload button. */
|
|
534
|
+
beginUpload(file, node, container) {
|
|
513
535
|
this.pendingUpload = { file, node, container };
|
|
514
536
|
node.open = true;
|
|
515
537
|
this.uploadingNodeId = node.id;
|
|
516
538
|
this.bump();
|
|
517
539
|
this.mrdUpload.emit({ file });
|
|
518
540
|
}
|
|
541
|
+
/** Upload a file into the current target — the selected folder/container, or
|
|
542
|
+
* the only container when there is just one. Called by the host toolbar
|
|
543
|
+
* (mrd-document-container). No-op without a target, or while another upload
|
|
544
|
+
* is still awaiting its setFileReference. */
|
|
545
|
+
async uploadFile(file) {
|
|
546
|
+
if (!file || this.pendingUpload)
|
|
547
|
+
return;
|
|
548
|
+
const resolved = this.resolveTarget();
|
|
549
|
+
if (!resolved)
|
|
550
|
+
return;
|
|
551
|
+
this.beginUpload(file, resolved.target, resolved.container);
|
|
552
|
+
}
|
|
519
553
|
/** Host callback with the uploaded file reference. Builds the create payload
|
|
520
554
|
* from the archetype slots and requests the new document. */
|
|
521
555
|
async setFileReference(uri) {
|
|
@@ -650,7 +684,7 @@ export class MrdDocumentList {
|
|
|
650
684
|
body = renderLoadingRow(ctx, 0);
|
|
651
685
|
}
|
|
652
686
|
else if (this.containers.length === 0) {
|
|
653
|
-
body = h("div", { key: '
|
|
687
|
+
body = h("div", { key: '63604a99fc62d9108f61b8efc126c0cd3e8fc5ed', class: "mrd-document-list__empty" }, t('no_results', this.locale));
|
|
654
688
|
}
|
|
655
689
|
else if (this.singleContainer) {
|
|
656
690
|
// Dossier context: render the single container's folder tree at the root.
|
|
@@ -668,7 +702,7 @@ export class MrdDocumentList {
|
|
|
668
702
|
else {
|
|
669
703
|
body = this.containers.map(c => renderContainerNode(ctx, c, 0));
|
|
670
704
|
}
|
|
671
|
-
return (h(Host, { key: '
|
|
705
|
+
return (h(Host, { key: '2a092e3a7483deb1fb30753b0c0428aaf75c303a' }, h("div", { key: '2b716c912a272b925a95133de5b1ff2abedd9dbc', class: 'mrd-document-list' + (this.rootDropActive ? ' mrd-document-list--drop-active' : ''), onDragOver: this.onRootDragOver, onDragLeave: this.onRootDragLeave, onDrop: this.onRootDrop }, body)));
|
|
672
706
|
}
|
|
673
707
|
static get is() { return "mrd-document-list"; }
|
|
674
708
|
static get encapsulation() { return "scoped"; }
|
|
@@ -880,6 +914,21 @@ export class MrdDocumentList {
|
|
|
880
914
|
"resolved": "boolean",
|
|
881
915
|
"references": {}
|
|
882
916
|
}
|
|
917
|
+
}, {
|
|
918
|
+
"method": "mrdTargetLabel",
|
|
919
|
+
"name": "mrdTargetLabel",
|
|
920
|
+
"bubbles": true,
|
|
921
|
+
"cancelable": true,
|
|
922
|
+
"composed": true,
|
|
923
|
+
"docs": {
|
|
924
|
+
"tags": [],
|
|
925
|
+
"text": "Emitted whenever the current target changes: the folder path a new folder or\nupload lands in, or the container's label when no folder is selected. Empty\nwhen there is no target. Lets a host toolbar name the destination."
|
|
926
|
+
},
|
|
927
|
+
"complexType": {
|
|
928
|
+
"original": "string",
|
|
929
|
+
"resolved": "string",
|
|
930
|
+
"references": {}
|
|
931
|
+
}
|
|
883
932
|
}, {
|
|
884
933
|
"method": "mrdUpdateObject",
|
|
885
934
|
"name": "mrdUpdateObject",
|
|
@@ -1023,6 +1072,31 @@ export class MrdDocumentList {
|
|
|
1023
1072
|
"tags": []
|
|
1024
1073
|
}
|
|
1025
1074
|
},
|
|
1075
|
+
"uploadFile": {
|
|
1076
|
+
"complexType": {
|
|
1077
|
+
"signature": "(file: File) => Promise<void>",
|
|
1078
|
+
"parameters": [{
|
|
1079
|
+
"name": "file",
|
|
1080
|
+
"type": "File",
|
|
1081
|
+
"docs": ""
|
|
1082
|
+
}],
|
|
1083
|
+
"references": {
|
|
1084
|
+
"Promise": {
|
|
1085
|
+
"location": "global",
|
|
1086
|
+
"id": "global::Promise"
|
|
1087
|
+
},
|
|
1088
|
+
"File": {
|
|
1089
|
+
"location": "global",
|
|
1090
|
+
"id": "global::File"
|
|
1091
|
+
}
|
|
1092
|
+
},
|
|
1093
|
+
"return": "Promise<void>"
|
|
1094
|
+
},
|
|
1095
|
+
"docs": {
|
|
1096
|
+
"text": "Upload a file into the current target \u2014 the selected folder/container, or\nthe only container when there is just one. Called by the host toolbar\n(mrd-document-container). No-op without a target, or while another upload\nis still awaiting its setFileReference.",
|
|
1097
|
+
"tags": []
|
|
1098
|
+
}
|
|
1099
|
+
},
|
|
1026
1100
|
"setFileReference": {
|
|
1027
1101
|
"complexType": {
|
|
1028
1102
|
"signature": "(uri: string) => Promise<void>",
|
|
@@ -121,16 +121,22 @@ export class MrdRelationField {
|
|
|
121
121
|
async setAllRecords(records) {
|
|
122
122
|
this.allRecords = records;
|
|
123
123
|
}
|
|
124
|
+
/** Href of the current single value. Accepts both a RelationSearchResult
|
|
125
|
+
* (`id`) and the raw API link shape (`{ href, name }`) a host puts in the
|
|
126
|
+
* form values for edit mode — same tolerance as `toSearchResult()`. */
|
|
124
127
|
getValueHref() {
|
|
125
|
-
var _a, _b, _c;
|
|
128
|
+
var _a, _b, _c, _d;
|
|
126
129
|
const v = Array.isArray(this.value) ? ((_a = this.value[0]) !== null && _a !== void 0 ? _a : '') : ((_b = this.value) !== null && _b !== void 0 ? _b : '');
|
|
127
130
|
if (!v)
|
|
128
131
|
return '';
|
|
129
132
|
if (typeof v === 'object')
|
|
130
|
-
return (_c = v.id) !== null && _c !== void 0 ? _c : '';
|
|
133
|
+
return (_d = (_c = v.id) !== null && _c !== void 0 ? _c : v.href) !== null && _d !== void 0 ? _d : '';
|
|
131
134
|
return v;
|
|
132
135
|
}
|
|
133
|
-
|
|
136
|
+
/** Push the current value onto the rendered <select>. Options and value arrive
|
|
137
|
+
* independently in edit mode (fetched records vs. the async `values` prop), so
|
|
138
|
+
* this runs on both — whichever lands last completes the preselection. */
|
|
139
|
+
syncDropdownSelection() {
|
|
134
140
|
if (this.editBehavior !== ClientLayoutItemRelationEditBehavior.DROPDOWN)
|
|
135
141
|
return;
|
|
136
142
|
const current = this.getValueHref();
|
|
@@ -146,6 +152,9 @@ export class MrdRelationField {
|
|
|
146
152
|
select.value = current;
|
|
147
153
|
}, 0);
|
|
148
154
|
}
|
|
155
|
+
allRecordsChanged() {
|
|
156
|
+
this.syncDropdownSelection();
|
|
157
|
+
}
|
|
149
158
|
async setSearchResults(results) {
|
|
150
159
|
this.searchResults = results;
|
|
151
160
|
this.isLoading = false;
|
|
@@ -197,6 +206,7 @@ export class MrdRelationField {
|
|
|
197
206
|
// (host pre-fill). Plain href strings from user interaction are ignored.
|
|
198
207
|
valueChanged(newValue) {
|
|
199
208
|
this.applyValuePrefill(newValue);
|
|
209
|
+
this.syncDropdownSelection();
|
|
200
210
|
}
|
|
201
211
|
componentDidLoad() {
|
|
202
212
|
// Only emit when there is no commonRelation dependency — the form orchestrates those.
|
|
@@ -253,15 +253,19 @@ export class MrdForm {
|
|
|
253
253
|
}
|
|
254
254
|
}
|
|
255
255
|
}
|
|
256
|
-
/** Extract a plain href string from a form value
|
|
257
|
-
*
|
|
256
|
+
/** Extract a plain href string from a form value: a string, a
|
|
257
|
+
* RelationSearchResult-like object (`id`), or the raw API link shape
|
|
258
|
+
* (`{ href, name }`) hosts spread into `values` for edit mode. */
|
|
258
259
|
getHref(value) {
|
|
260
|
+
var _a, _b;
|
|
259
261
|
if (!value)
|
|
260
262
|
return '';
|
|
261
263
|
if (typeof value === 'string')
|
|
262
264
|
return value;
|
|
263
|
-
if (typeof value === 'object'
|
|
264
|
-
|
|
265
|
+
if (typeof value === 'object') {
|
|
266
|
+
const v = value;
|
|
267
|
+
return (_b = (_a = v.id) !== null && _a !== void 0 ? _a : v.href) !== null && _b !== void 0 ? _b : '';
|
|
268
|
+
}
|
|
265
269
|
return '';
|
|
266
270
|
}
|
|
267
271
|
collectFields(items) {
|
|
@@ -3,6 +3,7 @@ import { ClientLayoutItemFieldDataType } from "../../../types/client-layout";
|
|
|
3
3
|
import { CellRenderer } from "../../../utils/cell-renderer";
|
|
4
4
|
import { t } from "../../../utils/i18n";
|
|
5
5
|
import { formatDate } from "../../../utils/format";
|
|
6
|
+
import { showsEmpty } from "./layout-helpers";
|
|
6
7
|
/** FILE and IMAGE cells share the same download button. */
|
|
7
8
|
function downloadLink(ctx, href, fileName, label) {
|
|
8
9
|
return (h("button", { class: "mrd-layout-section__download-link", onClick: () => href && ctx.on.download({ href, fileName }) }, h("svg", { class: "mrd-layout-section__file-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, h("path", { fill: "currentColor", d: "M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm-1 7V3.5L18.5 9H13zm-3 8l-3-3 1.41-1.41L10 14.17l4.59-4.58L16 11l-6 6z" })), label));
|
|
@@ -106,10 +107,11 @@ export function renderField(ctx, item) {
|
|
|
106
107
|
if (item.header) {
|
|
107
108
|
return (h("h1", { class: "mrd-layout-section__field-header", key: item.name }, typeof renderedValue === 'string' ? renderedValue : rawValue != null ? String(rawValue) : item.label));
|
|
108
109
|
}
|
|
109
|
-
|
|
110
|
+
const isEmpty = renderedValue == null;
|
|
111
|
+
if (isEmpty && !showsEmpty(item))
|
|
110
112
|
return null;
|
|
111
113
|
const isBlock = item.dataType === ClientLayoutItemFieldDataType.TEXTBLOCK
|
|
112
114
|
|| item.dataType === ClientLayoutItemFieldDataType.LONGTEXT
|
|
113
115
|
|| item.dataType === ClientLayoutItemFieldDataType.JSON;
|
|
114
|
-
return (h("div", { class: `mrd-layout-section__field${isBlock ? ' mrd-layout-section__field--block' : ''}`, key: item.name }, h("span", { class: "mrd-layout-section__field-label" }, item.label), h("span", { class: "mrd-layout-section__field-value" }, renderedValue, renderHistoryBadge(ctx, item, raw))));
|
|
116
|
+
return (h("div", { class: `mrd-layout-section__field${isBlock ? ' mrd-layout-section__field--block' : ''}${isEmpty ? ' mrd-layout-section__field--empty' : ''}`, key: item.name }, h("span", { class: "mrd-layout-section__field-label" }, item.label), h("span", { class: "mrd-layout-section__field-value" }, isEmpty ? t('value_empty', ctx.locale) : renderedValue, renderHistoryBadge(ctx, item, raw))));
|
|
115
117
|
}
|
|
@@ -6,6 +6,12 @@ export function viewKeyFor(item) {
|
|
|
6
6
|
return (_b = (_a = item.relatedClass) !== null && _a !== void 0 ? _a : item.name) !== null && _b !== void 0 ? _b : '';
|
|
7
7
|
return (_d = (_c = item.dataClass) !== null && _c !== void 0 ? _c : item.name) !== null && _d !== void 0 ? _d : '';
|
|
8
8
|
}
|
|
9
|
+
/** Whether a FIELD/RELATION item stays visible on an OBJECT_DASHBOARD when it
|
|
10
|
+
* has no value. Reads the flat API flag, falling back to the nested wrappers. */
|
|
11
|
+
export function showsEmpty(item) {
|
|
12
|
+
var _a, _b, _c, _d, _e;
|
|
13
|
+
return (_e = (_c = (_a = item.showEmpty) !== null && _a !== void 0 ? _a : (_b = item.field) === null || _b === void 0 ? void 0 : _b.showEmpty) !== null && _c !== void 0 ? _c : (_d = item.relation) === null || _d === void 0 ? void 0 : _d.showEmpty) !== null && _e !== void 0 ? _e : false;
|
|
14
|
+
}
|
|
9
15
|
/** Depth-first flatten of the SECTION/GROUP tree. */
|
|
10
16
|
export function flattenItems(items) {
|
|
11
17
|
const result = [];
|
|
@@ -33,6 +33,10 @@
|
|
|
33
33
|
align-items: center;
|
|
34
34
|
gap: var(--mrd-space-1);
|
|
35
35
|
}
|
|
36
|
+
.mrd-layout-section__field--empty .mrd-layout-section__field-value {
|
|
37
|
+
color: var(--mrd-color-neutral-400);
|
|
38
|
+
font-weight: var(--mrd-font-weight-normal);
|
|
39
|
+
}
|
|
36
40
|
.mrd-layout-section__history-wrap {
|
|
37
41
|
position: relative;
|
|
38
42
|
display: inline-flex;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Host, h } from "@stencil/core";
|
|
2
2
|
import { ClientLayoutItemType, ClientLayoutItemFieldDataType, ClientLayoutNavigateBehaviour, resolveArchetype, ARCHETYPE_DOCUMENT, ARCHETYPE_INVOICE, ARCHETYPE_EMAIL, ARCHETYPE_INVOICE_LINE, } from "../../../types/client-layout";
|
|
3
|
-
import {
|
|
3
|
+
import { t } from "../../../utils/i18n";
|
|
4
|
+
import { viewKeyFor, flattenItems, buildContainerHref, showsEmpty } from "./layout-helpers";
|
|
4
5
|
import { renderField } from "./field-value";
|
|
5
6
|
export class MrdLayoutSection {
|
|
6
7
|
constructor() {
|
|
@@ -173,19 +174,18 @@ export class MrdLayoutSection {
|
|
|
173
174
|
return null;
|
|
174
175
|
const links = ((_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a._links) !== null && _b !== void 0 ? _b : {});
|
|
175
176
|
const link = links[item.name];
|
|
176
|
-
if (!link)
|
|
177
|
-
return null;
|
|
178
177
|
const makeBtn = (href, name) => (h("button", { key: href, class: "mrd-layout-section__relation-link", onClick: () => this.mrdNavigate.emit({ href, label: name }) }, name));
|
|
179
178
|
let valueContent;
|
|
180
|
-
if ((_c = link.values) === null || _c === void 0 ? void 0 : _c.length) {
|
|
179
|
+
if ((_c = link === null || link === void 0 ? void 0 : link.values) === null || _c === void 0 ? void 0 : _c.length) {
|
|
181
180
|
valueContent = link.values.map(v => makeBtn(v.href, v.name));
|
|
182
181
|
}
|
|
183
|
-
else if (link.name) {
|
|
182
|
+
else if (link === null || link === void 0 ? void 0 : link.name) {
|
|
184
183
|
valueContent = makeBtn(link.href, link.name);
|
|
185
184
|
}
|
|
186
|
-
|
|
185
|
+
const isEmpty = !valueContent;
|
|
186
|
+
if (isEmpty && !showsEmpty(item))
|
|
187
187
|
return null;
|
|
188
|
-
return (h("div", { class:
|
|
188
|
+
return (h("div", { class: `mrd-layout-section__field${isEmpty ? ' mrd-layout-section__field--empty' : ''}`, key: item.name }, h("span", { class: "mrd-layout-section__field-label" }, item.label), h("span", { class: "mrd-layout-section__field-value" }, isEmpty ? t('value_empty', this.locale) : valueContent)));
|
|
189
189
|
}
|
|
190
190
|
renderSearch(item) {
|
|
191
191
|
var _a, _b, _c;
|
|
@@ -359,7 +359,7 @@ export class MrdLayoutSection {
|
|
|
359
359
|
const docArchetype = resolveArchetype(this.archetypes, ARCHETYPE_DOCUMENT);
|
|
360
360
|
const invoiceArchetype = !docArchetype ? resolveArchetype(this.archetypes, ARCHETYPE_INVOICE) : undefined;
|
|
361
361
|
const emailArchetype = !docArchetype && !invoiceArchetype ? resolveArchetype(this.archetypes, ARCHETYPE_EMAIL) : undefined;
|
|
362
|
-
return (h(Host, { key: '
|
|
362
|
+
return (h(Host, { key: 'ccae8e82b4dd549ab24239fe685a6830a508061d' }, h("div", { key: '4072cc4ecdd2b087c54a5515e653f7f713b2150f', 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()));
|
|
363
363
|
}
|
|
364
364
|
static get is() { return "mrd-layout-section"; }
|
|
365
365
|
static get encapsulation() { return "scoped"; }
|
|
@@ -223,7 +223,9 @@ window.EXAMPLE_COMPANY_METADATA = {
|
|
|
223
223
|
{ type: 'FIELD', label: 'legal form extended', name: 'legalFormExtended', dataType: 'TEXT', required: false },
|
|
224
224
|
{ type: 'FIELD', label: 'rsin', name: 'rsin', dataType: 'TEXT', required: false },
|
|
225
225
|
{ type: 'FIELD', label: 'start date', name: 'startDate', dataType: 'DATE', required: false },
|
|
226
|
-
|
|
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 },
|
|
227
229
|
{ type: 'FIELD', label: 'primary activity description', name: 'primaryActivityDescription', dataType: 'TEXT', required: false },
|
|
228
230
|
{ type: 'FIELD', label: 'primary activity code', name: 'primaryActivityCode', dataType: 'TEXT', required: false },
|
|
229
231
|
{ type: 'FIELD', label: 'total employees', name: 'totalEmployees', dataType: 'INTEGER', required: false },
|
|
@@ -243,6 +245,9 @@ window.EXAMPLE_COMPANY_METADATA = {
|
|
|
243
245
|
{ type: 'FIELD', label: 'mailing postal code', name: 'mailingPostalCode', dataType: 'TEXT', required: false },
|
|
244
246
|
{ type: 'FIELD', label: 'mailing city', name: 'mailingCity', dataType: 'TEXT', required: false },
|
|
245
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 },
|
|
246
251
|
],
|
|
247
252
|
},
|
|
248
253
|
{
|
|
@@ -27,6 +27,7 @@ const translations = {
|
|
|
27
27
|
// mrd-table footer
|
|
28
28
|
table_of: 'van',
|
|
29
29
|
download: 'Downloaden',
|
|
30
|
+
value_empty: '—',
|
|
30
31
|
// mrd-table toolbar
|
|
31
32
|
table_filter: 'Filteren',
|
|
32
33
|
table_filter_hide: 'Filter verbergen',
|
|
@@ -36,6 +37,8 @@ const translations = {
|
|
|
36
37
|
table_export_excel: 'Exporteer naar Excel',
|
|
37
38
|
doc_view_switch: 'Weergave wisselen',
|
|
38
39
|
doc_view_tree: 'Boomweergave',
|
|
40
|
+
doc_upload: 'Uploaden',
|
|
41
|
+
doc_upload_to: 'Uploaden naar',
|
|
39
42
|
doc_view_list: 'Lijstweergave',
|
|
40
43
|
// mrd-table filter popup
|
|
41
44
|
filter_sorting: 'Sortering',
|
|
@@ -129,6 +132,7 @@ const translations = {
|
|
|
129
132
|
// mrd-table footer
|
|
130
133
|
table_of: 'of',
|
|
131
134
|
download: 'Download',
|
|
135
|
+
value_empty: '—',
|
|
132
136
|
// mrd-table toolbar
|
|
133
137
|
table_filter: 'Filter',
|
|
134
138
|
table_filter_hide: 'Hide filter',
|
|
@@ -138,6 +142,8 @@ const translations = {
|
|
|
138
142
|
table_export_excel: 'Export to Excel',
|
|
139
143
|
doc_view_switch: 'Switch view',
|
|
140
144
|
doc_view_tree: 'Tree view',
|
|
145
|
+
doc_upload: 'Upload',
|
|
146
|
+
doc_upload_to: 'Upload to',
|
|
141
147
|
doc_view_list: 'List view',
|
|
142
148
|
// mrd-table filter popup
|
|
143
149
|
filter_sorting: 'Sorting',
|
|
@@ -231,6 +237,7 @@ const translations = {
|
|
|
231
237
|
// mrd-table footer
|
|
232
238
|
table_of: 'من أصل',
|
|
233
239
|
download: 'تنزيل',
|
|
240
|
+
value_empty: '—',
|
|
234
241
|
// mrd-table toolbar
|
|
235
242
|
table_filter: 'تصفية',
|
|
236
243
|
table_filter_hide: 'إخفاء التصفية',
|
|
@@ -240,6 +247,8 @@ const translations = {
|
|
|
240
247
|
table_export_excel: 'تصدير إلى Excel',
|
|
241
248
|
doc_view_switch: 'تبديل العرض',
|
|
242
249
|
doc_view_tree: 'عرض شجري',
|
|
250
|
+
doc_upload: 'رفع',
|
|
251
|
+
doc_upload_to: 'رفع إلى',
|
|
243
252
|
doc_view_list: 'عرض القائمة',
|
|
244
253
|
// mrd-table filter popup
|
|
245
254
|
filter_sorting: 'الترتيب',
|
|
@@ -327,6 +336,7 @@ const translations = {
|
|
|
327
336
|
// mrd-table footer
|
|
328
337
|
table_of: 'sur',
|
|
329
338
|
download: 'Télécharger',
|
|
339
|
+
value_empty: '—',
|
|
330
340
|
// mrd-table toolbar
|
|
331
341
|
table_filter: 'Filtrer',
|
|
332
342
|
table_filter_hide: 'Masquer le filtre',
|
|
@@ -336,6 +346,8 @@ const translations = {
|
|
|
336
346
|
table_export_excel: 'Exporter vers Excel',
|
|
337
347
|
doc_view_switch: 'Changer de vue',
|
|
338
348
|
doc_view_tree: 'Vue arborescente',
|
|
349
|
+
doc_upload: 'Téléverser',
|
|
350
|
+
doc_upload_to: 'Téléverser vers',
|
|
339
351
|
doc_view_list: 'Vue liste',
|
|
340
352
|
// mrd-table filter popup
|
|
341
353
|
filter_sorting: 'Tri',
|
|
@@ -423,6 +435,7 @@ const translations = {
|
|
|
423
435
|
// mrd-table footer
|
|
424
436
|
table_of: 'von',
|
|
425
437
|
download: 'Herunterladen',
|
|
438
|
+
value_empty: '—',
|
|
426
439
|
// mrd-table toolbar
|
|
427
440
|
table_filter: 'Filtern',
|
|
428
441
|
table_filter_hide: 'Filter ausblenden',
|
|
@@ -432,6 +445,8 @@ const translations = {
|
|
|
432
445
|
table_export_excel: 'Als Excel exportieren',
|
|
433
446
|
doc_view_switch: 'Ansicht wechseln',
|
|
434
447
|
doc_view_tree: 'Baumansicht',
|
|
448
|
+
doc_upload: 'Hochladen',
|
|
449
|
+
doc_upload_to: 'Hochladen nach',
|
|
435
450
|
doc_view_list: 'Listenansicht',
|
|
436
451
|
// mrd-table filter popup
|
|
437
452
|
filter_sorting: 'Sortierung',
|
|
@@ -519,6 +534,7 @@ const translations = {
|
|
|
519
534
|
// mrd-table footer
|
|
520
535
|
table_of: 'de',
|
|
521
536
|
download: 'Descargar',
|
|
537
|
+
value_empty: '—',
|
|
522
538
|
// mrd-table toolbar
|
|
523
539
|
table_filter: 'Filtrar',
|
|
524
540
|
table_filter_hide: 'Ocultar filtro',
|
|
@@ -528,6 +544,8 @@ const translations = {
|
|
|
528
544
|
table_export_excel: 'Exportar a Excel',
|
|
529
545
|
doc_view_switch: 'Cambiar vista',
|
|
530
546
|
doc_view_tree: 'Vista de árbol',
|
|
547
|
+
doc_upload: 'Subir',
|
|
548
|
+
doc_upload_to: 'Subir a',
|
|
531
549
|
doc_view_list: 'Vista de lista',
|
|
532
550
|
// mrd-table filter popup
|
|
533
551
|
filter_sorting: 'Ordenación',
|
|
@@ -615,6 +633,7 @@ const translations = {
|
|
|
615
633
|
// mrd-table footer
|
|
616
634
|
table_of: 'di',
|
|
617
635
|
download: 'Scarica',
|
|
636
|
+
value_empty: '—',
|
|
618
637
|
// mrd-table toolbar
|
|
619
638
|
table_filter: 'Filtra',
|
|
620
639
|
table_filter_hide: 'Nascondi filtro',
|
|
@@ -624,6 +643,8 @@ const translations = {
|
|
|
624
643
|
table_export_excel: 'Esporta in Excel',
|
|
625
644
|
doc_view_switch: 'Cambia vista',
|
|
626
645
|
doc_view_tree: 'Vista ad albero',
|
|
646
|
+
doc_upload: 'Carica',
|
|
647
|
+
doc_upload_to: 'Carica in',
|
|
627
648
|
doc_view_list: 'Vista elenco',
|
|
628
649
|
// mrd-table filter popup
|
|
629
650
|
filter_sorting: 'Ordinamento',
|
|
@@ -711,6 +732,7 @@ const translations = {
|
|
|
711
732
|
// mrd-table footer
|
|
712
733
|
table_of: 'з',
|
|
713
734
|
download: 'Завантажити',
|
|
735
|
+
value_empty: '—',
|
|
714
736
|
// mrd-table toolbar
|
|
715
737
|
table_filter: 'Фільтрувати',
|
|
716
738
|
table_filter_hide: 'Сховати фільтр',
|
|
@@ -720,6 +742,8 @@ const translations = {
|
|
|
720
742
|
table_export_excel: 'Експортувати до Excel',
|
|
721
743
|
doc_view_switch: 'Змінити вигляд',
|
|
722
744
|
doc_view_tree: 'Деревоподібний вигляд',
|
|
745
|
+
doc_upload: 'Завантажити',
|
|
746
|
+
doc_upload_to: 'Завантажити до',
|
|
723
747
|
doc_view_list: 'Список',
|
|
724
748
|
// mrd-table filter popup
|
|
725
749
|
filter_sorting: 'Сортування',
|