@mmlogic/components 0.5.14 → 0.5.15
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-mjS630f1.js → cell-renderer-CLVKTVVQ.js} +105 -1
- package/dist/cjs/{client-layout-CqVuJumR.js → client-layout-Eg2VwW-7.js} +2 -0
- package/dist/cjs/index.cjs.js +2 -1
- 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 → mrd-boolean-field_28.cjs.entry.js} +1022 -335
- package/dist/cjs/mrd-merge-view.cjs.entry.js +4 -4
- package/dist/collection/collection-manifest.json +3 -0
- package/dist/collection/components/fields/mrd-textarea-field/mrd-textarea-field.js +47 -2
- package/dist/collection/components/form/mrd-form/mrd-form.css +29 -0
- package/dist/collection/components/form/mrd-form/mrd-form.js +44 -8
- package/dist/collection/components/layout/mrd-layout-section/mrd-layout-section.js +126 -13
- package/dist/collection/components/memo/mrd-memo-container/mrd-memo-container.css +204 -0
- package/dist/collection/components/memo/mrd-memo-container/mrd-memo-container.js +694 -0
- package/dist/collection/components/memo/mrd-memo-list/mrd-memo-list.css +150 -0
- package/dist/collection/components/memo/mrd-memo-list/mrd-memo-list.js +511 -0
- package/dist/collection/components/memo/mrd-memo-view/mrd-memo-view.css +108 -0
- package/dist/collection/components/memo/mrd-memo-view/mrd-memo-view.js +204 -0
- package/dist/collection/components/merge/mrd-merge-view/mrd-merge-view.js +2 -2
- package/dist/collection/components/table/mrd-table/mrd-table.js +9 -6
- package/dist/collection/dev/app.js +17 -0
- package/dist/collection/types/client-layout.js +1 -0
- package/dist/collection/utils/i18n.js +104 -0
- package/dist/collection/utils/query-params.js +9 -0
- package/dist/components/client-layout.js +1 -1
- package/dist/components/i18n.js +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/mrd-form.js +1 -1
- package/dist/components/mrd-layout-section.js +1 -1
- package/dist/components/mrd-memo-container.d.ts +11 -0
- package/dist/components/mrd-memo-container.js +1 -0
- package/dist/components/mrd-memo-container2.js +1 -0
- package/dist/components/mrd-memo-list.d.ts +11 -0
- package/dist/components/mrd-memo-list.js +1 -0
- package/dist/components/mrd-memo-list2.js +1 -0
- package/dist/components/mrd-memo-view.d.ts +11 -0
- package/dist/components/mrd-memo-view.js +1 -0
- package/dist/components/mrd-memo-view2.js +1 -0
- package/dist/components/mrd-merge-view.js +1 -1
- package/dist/components/mrd-table2.js +1 -1
- package/dist/components/mrd-textarea-field2.js +1 -1
- package/dist/components/query-params.js +1 -1
- package/dist/components/table-query.js +1 -0
- package/dist/esm/{cell-renderer-BDY8UXkH.js → cell-renderer-4NKEzZWw.js} +105 -1
- package/dist/esm/{client-layout-Bc42CfJB.js → client-layout-BJkVeSq6.js} +2 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/esm/mosterdcomponents.js +1 -1
- package/dist/esm/{mrd-boolean-field_25.entry.js → mrd-boolean-field_28.entry.js} +1020 -336
- package/dist/esm/mrd-merge-view.entry.js +4 -4
- package/dist/mosterdcomponents/index.esm.js +1 -1
- package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -1
- package/dist/mosterdcomponents/{p-Bc42CfJB.js → p-BJkVeSq6.js} +1 -1
- package/dist/mosterdcomponents/p-BMx6VAJ6.js +1 -0
- package/dist/mosterdcomponents/p-d64ba1f2.entry.js +3 -0
- package/dist/mosterdcomponents/{p-e8b0880f.entry.js → p-e68dfbb0.entry.js} +1 -1
- package/dist/types/components/fields/mrd-textarea-field/mrd-textarea-field.d.ts +10 -0
- package/dist/types/components/form/mrd-form/mrd-form.d.ts +6 -0
- package/dist/types/components/layout/mrd-layout-section/mrd-layout-section.d.ts +20 -1
- package/dist/types/components/memo/mrd-memo-container/mrd-memo-container.d.ts +152 -0
- package/dist/types/components/memo/mrd-memo-list/mrd-memo-list.d.ts +79 -0
- package/dist/types/components/memo/mrd-memo-view/mrd-memo-view.d.ts +33 -0
- package/dist/types/components.d.ts +528 -1
- package/dist/types/types/client-layout.d.ts +1 -0
- package/dist/types/utils/query-params.d.ts +16 -0
- package/package.json +1 -1
- package/dist/mosterdcomponents/cell-renderer-B8u5BCK-.js.map +0 -1
- package/dist/mosterdcomponents/client-layout-Bc42CfJB.js.map +0 -1
- package/dist/mosterdcomponents/document-attachments-BufPmMRv.js.map +0 -1
- package/dist/mosterdcomponents/field-helpers-CNQcI3Hf.js.map +0 -1
- package/dist/mosterdcomponents/file-upload-common-C9wp47CB.js.map +0 -1
- package/dist/mosterdcomponents/format-gcecItcD.js.map +0 -1
- package/dist/mosterdcomponents/i18n-ydNM87-Q.js.map +0 -1
- package/dist/mosterdcomponents/index-1ayBojyN.js.map +0 -1
- package/dist/mosterdcomponents/index-DhffneUF.js.map +0 -1
- package/dist/mosterdcomponents/index.esm.js.map +0 -1
- package/dist/mosterdcomponents/mosterdcomponents.esm.js.map +0 -1
- package/dist/mosterdcomponents/p-Dkm4WxMy.js +0 -1
- package/dist/mosterdcomponents/p-c834951a.entry.js +0 -3
- package/dist/mosterdcomponents/purify.es-_duHfPgC.js.map +0 -1
- package/dist/mosterdcomponents/query-params-BZbQoeYF.js.map +0 -1
- package/dist/mosterdcomponents/quill-C9pgw_k-.js.map +0 -1
- package/dist/mosterdcomponents/validation-CjjTt66G.js.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var index = require('./index-DVbdkYO3.js');
|
|
4
|
-
var cellRenderer = require('./cell-renderer-
|
|
5
|
-
var clientLayout = require('./client-layout-
|
|
4
|
+
var cellRenderer = require('./cell-renderer-CLVKTVVQ.js');
|
|
5
|
+
var clientLayout = require('./client-layout-Eg2VwW-7.js');
|
|
6
6
|
|
|
7
7
|
const mrdBooleanFieldCss = () => `.sc-mrd-boolean-field-h{display:block}.mrd-boolean-field.sc-mrd-boolean-field{display:flex;align-items:center;width:100%}.mrd-boolean-field__toggle-label.sc-mrd-boolean-field{display:flex;align-items:center;gap:var(--mrd-space-3);cursor:pointer;user-select:none}.mrd-boolean-field__checkbox.sc-mrd-boolean-field{position:absolute;opacity:0;width:0;height:0;pointer-events:none}.mrd-boolean-field__checkbox.sc-mrd-boolean-field:checked+.mrd-boolean-field__toggle.sc-mrd-boolean-field{background-color:var(--mrd-color-primary)}.mrd-boolean-field__checkbox.sc-mrd-boolean-field:checked+.mrd-boolean-field__toggle.sc-mrd-boolean-field::after{transform:translateX(20px)}.mrd-boolean-field__checkbox.sc-mrd-boolean-field:focus+.mrd-boolean-field__toggle.sc-mrd-boolean-field{box-shadow:var(--mrd-shadow-focus)}.mrd-boolean-field__checkbox.sc-mrd-boolean-field:disabled+.mrd-boolean-field__toggle.sc-mrd-boolean-field{opacity:0.5;cursor:not-allowed}.mrd-boolean-field__toggle.sc-mrd-boolean-field{position:relative;display:inline-block;width:44px;height:24px;background-color:var(--mrd-color-neutral-300);border-radius:var(--mrd-border-radius-full);transition:background-color var(--mrd-transition);flex-shrink:0}.mrd-boolean-field__toggle.sc-mrd-boolean-field::after{content:"";position:absolute;top:2px;left:2px;width:20px;height:20px;background-color:var(--mrd-color-white);border-radius:50%;transition:transform var(--mrd-transition);box-shadow:var(--mrd-shadow-sm)}.mrd-boolean-field__text.sc-mrd-boolean-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-color-neutral-800)}.mrd-boolean-field__text--required.sc-mrd-boolean-field::after{content:" *";color:var(--mrd-color-danger)}`;
|
|
8
8
|
|
|
@@ -522,6 +522,15 @@ function buildListPath(opts) {
|
|
|
522
522
|
}
|
|
523
523
|
return `/${(_c = opts.dataClass) !== null && _c !== void 0 ? _c : ''}`;
|
|
524
524
|
}
|
|
525
|
+
/** The `mrdAction` detail for a toolbar "create" action: `parentPath` locates the
|
|
526
|
+
* RELATED_VIEW's parent (`/{fromClass}/{parentId}`) so the host can route to
|
|
527
|
+
* `.../{parentPath}/{dataClass}/new`; `null` for a top-level VIEW. Shared by
|
|
528
|
+
* mrd-table and mrd-memo-container so both toolbars build an identical payload. */
|
|
529
|
+
function buildCreateActionDetail(opts) {
|
|
530
|
+
var _a, _b;
|
|
531
|
+
const parentPath = opts.isRelatedView ? `/${(_a = opts.fromClass) !== null && _a !== void 0 ? _a : ''}/${opts.parentId}` : null;
|
|
532
|
+
return Object.assign({ action: 'create', dataClass: (_b = opts.dataClass) !== null && _b !== void 0 ? _b : '', parentPath }, (opts.basicType ? { basicType: opts.basicType } : {}));
|
|
533
|
+
}
|
|
525
534
|
|
|
526
535
|
/**
|
|
527
536
|
* Tree model and pure tree logic for mrd-document-list.
|
|
@@ -4444,13 +4453,14 @@ const MrdFileField = class {
|
|
|
4444
4453
|
};
|
|
4445
4454
|
MrdFileField.style = mrdFileFieldCss();
|
|
4446
4455
|
|
|
4447
|
-
const mrdFormCss = () => `.sc-mrd-form-h{display:block}.mrd-form.sc-mrd-form{font-family:var(--mrd-font-family);width:100%}.mrd-form__title.sc-mrd-form{font-size:var(--mrd-font-size-2xl);font-weight:var(--mrd-font-weight-bold);color:var(--mrd-color-neutral-900);margin:0 0 var(--mrd-space-6) 0}.mrd-form__body.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-5)}.mrd-form__field.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-form__field-error.sc-mrd-form{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-form__section.sc-mrd-form{border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);padding:var(--mrd-space-4) var(--mrd-space-5);margin:0}.mrd-form__section-legend.sc-mrd-form{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-700);padding:0 var(--mrd-space-2)}.mrd-form__section-body.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-4);margin-top:var(--mrd-space-2)}.mrd-form__group.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-2)}.mrd-form__group-label.sc-mrd-form{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-500);text-transform:uppercase;letter-spacing:0.05em}.mrd-form__group-body.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-4);padding-left:var(--mrd-space-4);border-left:3px solid var(--mrd-color-neutral-200)}.mrd-form__footer.sc-mrd-form{margin-top:var(--mrd-space-8);padding-top:var(--mrd-space-5);border-top:var(--mrd-border-width) solid var(--mrd-border-color);display:flex;justify-content:flex-end;gap:var(--mrd-space-3)}.mrd-form__submit.sc-mrd-form{display:inline-flex;align-items:center;justify-content:center;height:var(--mrd-input-height);padding:0 var(--mrd-space-6);background-color:var(--mrd-color-primary);color:var(--mrd-color-white);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-medium);border:none;border-radius:var(--mrd-border-radius);cursor:pointer;transition:background-color var(--mrd-transition)}.mrd-form__submit.sc-mrd-form:hover{background-color:var(--mrd-color-primary-hover)}.mrd-form__submit.sc-mrd-form:focus{outline:none;box-shadow:var(--mrd-shadow-focus)}.mrd-form__submit.sc-mrd-form:active{background-color:var(--mrd-color-primary-dark)}.mrd-form__cancel.sc-mrd-form{display:inline-flex;align-items:center;justify-content:center;height:var(--mrd-input-height);padding:0 var(--mrd-space-6);background-color:transparent;color:var(--mrd-color-neutral-600);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-medium);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);cursor:pointer;transition:background-color var(--mrd-transition), color var(--mrd-transition)}.mrd-form__cancel.sc-mrd-form:hover{background-color:var(--mrd-color-neutral-100);color:var(--mrd-color-neutral-800)}.mrd-form__cancel.sc-mrd-form:focus{outline:none;box-shadow:var(--mrd-shadow-focus)}.mrd-form__cancel.sc-mrd-form:active{background-color:var(--mrd-color-neutral-200)}`;
|
|
4456
|
+
const mrdFormCss = () => `.sc-mrd-form-h{display:block}.mrd-form.sc-mrd-form{font-family:var(--mrd-font-family);width:100%}.mrd-form__title.sc-mrd-form{font-size:var(--mrd-font-size-2xl);font-weight:var(--mrd-font-weight-bold);color:var(--mrd-color-neutral-900);margin:0 0 var(--mrd-space-6) 0}.mrd-form__body.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-5)}.mrd-form__field.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-form__field-error.sc-mrd-form{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-form__section.sc-mrd-form{border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);padding:var(--mrd-space-4) var(--mrd-space-5);margin:0}.mrd-form__section-legend.sc-mrd-form{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-700);padding:0 var(--mrd-space-2)}.mrd-form__section-body.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-4);margin-top:var(--mrd-space-2)}.mrd-form__group.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-2)}.mrd-form__group-label.sc-mrd-form{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-500);text-transform:uppercase;letter-spacing:0.05em}.mrd-form__group-body.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-4);padding-left:var(--mrd-space-4);border-left:3px solid var(--mrd-color-neutral-200)}.mrd-form__footer.sc-mrd-form{margin-top:var(--mrd-space-8);padding-top:var(--mrd-space-5);border-top:var(--mrd-border-width) solid var(--mrd-border-color);display:flex;justify-content:flex-end;gap:var(--mrd-space-3)}.mrd-form__submit.sc-mrd-form{display:inline-flex;align-items:center;justify-content:center;height:var(--mrd-input-height);padding:0 var(--mrd-space-6);background-color:var(--mrd-color-primary);color:var(--mrd-color-white);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-medium);border:none;border-radius:var(--mrd-border-radius);cursor:pointer;transition:background-color var(--mrd-transition)}.mrd-form__submit.sc-mrd-form:hover{background-color:var(--mrd-color-primary-hover)}.mrd-form__submit.sc-mrd-form:focus{outline:none;box-shadow:var(--mrd-shadow-focus)}.mrd-form__submit.sc-mrd-form:active{background-color:var(--mrd-color-primary-dark)}.mrd-form__cancel.sc-mrd-form{display:inline-flex;align-items:center;justify-content:center;height:var(--mrd-input-height);padding:0 var(--mrd-space-6);background-color:transparent;color:var(--mrd-color-neutral-600);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-medium);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);cursor:pointer;transition:background-color var(--mrd-transition), color var(--mrd-transition)}.mrd-form__cancel.sc-mrd-form:hover{background-color:var(--mrd-color-neutral-100);color:var(--mrd-color-neutral-800)}.mrd-form__cancel.sc-mrd-form:focus{outline:none;box-shadow:var(--mrd-shadow-focus)}.mrd-form__cancel.sc-mrd-form:active{background-color:var(--mrd-color-neutral-200)}.mrd-form__delete.sc-mrd-form{display:inline-flex;align-items:center;justify-content:center;height:var(--mrd-input-height);padding:0 var(--mrd-space-6);margin-right:auto;background-color:transparent;color:var(--mrd-color-danger);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-medium);border:var(--mrd-border-width) solid var(--mrd-color-danger);border-radius:var(--mrd-border-radius);cursor:pointer;transition:background-color var(--mrd-transition), color var(--mrd-transition)}.mrd-form__delete.sc-mrd-form:hover{background-color:var(--mrd-color-danger-light);color:var(--mrd-color-danger-dark)}.mrd-form__delete.sc-mrd-form:focus{outline:none;box-shadow:0 0 0 3px var(--mrd-color-danger-light)}.mrd-form__delete.sc-mrd-form:active{background-color:var(--mrd-color-danger-light);border-color:var(--mrd-color-danger-dark)}`;
|
|
4448
4457
|
|
|
4449
4458
|
const MrdForm = class {
|
|
4450
4459
|
constructor(hostRef) {
|
|
4451
4460
|
index.registerInstance(this, hostRef);
|
|
4452
4461
|
this.mrdSubmit = index.createEvent(this, "mrdSubmit");
|
|
4453
4462
|
this.mrdCancel = index.createEvent(this, "mrdCancel");
|
|
4463
|
+
this.mrdDelete = index.createEvent(this, "mrdDelete");
|
|
4454
4464
|
this.mrdSearch = index.createEvent(this, "mrdSearch");
|
|
4455
4465
|
this.mrdFetchAll = index.createEvent(this, "mrdFetchAll");
|
|
4456
4466
|
this.mrdUpload = index.createEvent(this, "mrdUpload");
|
|
@@ -4477,6 +4487,11 @@ const MrdForm = class {
|
|
|
4477
4487
|
this.referenceClass = '';
|
|
4478
4488
|
/** When true, a cancel button is shown next to the submit button. */
|
|
4479
4489
|
this.showCancel = false;
|
|
4490
|
+
/** When true, a delete button is shown next to the submit button (edit mode only —
|
|
4491
|
+
* the host decides when a delete affordance makes sense, e.g. only for an existing
|
|
4492
|
+
* record). Deletion itself (confirmation, the actual API call) is entirely the
|
|
4493
|
+
* host's responsibility; mrd-form only emits the request via mrdDelete. */
|
|
4494
|
+
this.showDelete = false;
|
|
4480
4495
|
/**
|
|
4481
4496
|
* The currently logged-in user, resolved by the host via /accounts/me.
|
|
4482
4497
|
* Used to pre-fill RELATION fields whose defaultValue is "@me".
|
|
@@ -4764,15 +4779,11 @@ const MrdForm = class {
|
|
|
4764
4779
|
normalizeRelationValue(value) {
|
|
4765
4780
|
if (value == null || value === '')
|
|
4766
4781
|
return null;
|
|
4767
|
-
if (typeof value === 'string')
|
|
4768
|
-
return value || null;
|
|
4769
4782
|
if (Array.isArray(value)) {
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
if (typeof value === 'object' && 'id' in value) {
|
|
4773
|
-
return value.id || null;
|
|
4783
|
+
const hrefs = value.map(v => this.getHref(v)).filter(v => v !== '');
|
|
4784
|
+
return hrefs.length ? hrefs : null;
|
|
4774
4785
|
}
|
|
4775
|
-
return null;
|
|
4786
|
+
return this.getHref(value) || null;
|
|
4776
4787
|
}
|
|
4777
4788
|
deepEqual(a, b) {
|
|
4778
4789
|
if (a === b)
|
|
@@ -4845,7 +4856,7 @@ const MrdForm = class {
|
|
|
4845
4856
|
return index.h(index.Host, null);
|
|
4846
4857
|
}
|
|
4847
4858
|
const dir = this.locale.startsWith('ar') ? 'rtl' : 'ltr';
|
|
4848
|
-
return (index.h(index.Host, null, index.h("form", { class: "mrd-form", dir: dir, onSubmit: this.handleSubmit, noValidate: true }, this.layout.title && index.h("h2", { class: "mrd-form__title" }, this.layout.title), index.h("div", { class: "mrd-form__body" }, this.renderItems(this.layout.items)), index.h("div", { class: "mrd-form__footer" }, index.h("button", { type: "submit", class: "mrd-form__submit" }, cellRenderer.t('submit', this.locale)), this.showCancel && (index.h("button", { type: "button", class: "mrd-form__cancel", onClick: () => this.mrdCancel.emit() }, cellRenderer.t('cancel', this.locale)))))));
|
|
4859
|
+
return (index.h(index.Host, null, index.h("form", { class: "mrd-form", dir: dir, onSubmit: this.handleSubmit, noValidate: true }, this.layout.title && index.h("h2", { class: "mrd-form__title" }, this.layout.title), index.h("div", { class: "mrd-form__body" }, this.renderItems(this.layout.items)), index.h("div", { class: "mrd-form__footer" }, this.showDelete && (index.h("button", { type: "button", class: "mrd-form__delete", onClick: () => this.mrdDelete.emit() }, cellRenderer.t('delete', this.locale))), index.h("button", { type: "submit", class: "mrd-form__submit" }, cellRenderer.t('submit', this.locale)), this.showCancel && (index.h("button", { type: "button", class: "mrd-form__cancel", onClick: () => this.mrdCancel.emit() }, cellRenderer.t('cancel', this.locale)))))));
|
|
4849
4860
|
}
|
|
4850
4861
|
static get watchers() { return {
|
|
4851
4862
|
"values": [{
|
|
@@ -5339,6 +5350,7 @@ const MrdLayoutSection = class {
|
|
|
5339
5350
|
this.mrdLoadViewAggregations = index.createEvent(this, "mrdLoadViewAggregations");
|
|
5340
5351
|
this.mrdLoadViewDistinct = index.createEvent(this, "mrdLoadViewDistinct");
|
|
5341
5352
|
this.mrdUpdateObject = index.createEvent(this, "mrdUpdateObject");
|
|
5353
|
+
this.mrdDeleteObject = index.createEvent(this, "mrdDeleteObject");
|
|
5342
5354
|
this.mrdViewUpload = index.createEvent(this, "mrdViewUpload");
|
|
5343
5355
|
this.mrdCreateObject = index.createEvent(this, "mrdCreateObject");
|
|
5344
5356
|
/** Items from one layout entry in ClientDashboardMetadata.layouts[]. */
|
|
@@ -5357,6 +5369,11 @@ const MrdLayoutSection = class {
|
|
|
5357
5369
|
* create ("+") action and the documents view's New folder / Upload are disabled
|
|
5358
5370
|
* with a tooltip explaining why, so it's clear at a glance the user can't mutate data. */
|
|
5359
5371
|
this.readOnly = false;
|
|
5372
|
+
/** The active account's linked person record (userProfile.links.person), if any.
|
|
5373
|
+
* Threaded to mrd-memo-container so a top-level memo VIEW (no parent record to
|
|
5374
|
+
* attach a new memo to) can still offer "New memo" by falling back to the
|
|
5375
|
+
* account's own record as the container. */
|
|
5376
|
+
this.me = null;
|
|
5360
5377
|
this.searchQueryMap = {};
|
|
5361
5378
|
this.searchResultsMap = {};
|
|
5362
5379
|
this.imagePreviewUrl = null;
|
|
@@ -5410,6 +5427,14 @@ const MrdLayoutSection = class {
|
|
|
5410
5427
|
await table.init();
|
|
5411
5428
|
}
|
|
5412
5429
|
}
|
|
5430
|
+
// mrd-memo-container's card mode has no <mrd-table> — mrd-memo-list needs the
|
|
5431
|
+
// same init() call to request its first page.
|
|
5432
|
+
const memoLists = this.el.querySelectorAll('mrd-memo-list[data-view]');
|
|
5433
|
+
for (const list of Array.from(memoLists)) {
|
|
5434
|
+
if (typeof list.init === 'function') {
|
|
5435
|
+
await list.init();
|
|
5436
|
+
}
|
|
5437
|
+
}
|
|
5413
5438
|
}
|
|
5414
5439
|
emitLoadImages() {
|
|
5415
5440
|
for (const item of flattenItems(this.items)) {
|
|
@@ -5443,12 +5468,18 @@ const MrdLayoutSection = class {
|
|
|
5443
5468
|
return;
|
|
5444
5469
|
}
|
|
5445
5470
|
const table = this.el.querySelector(`mrd-table[data-view="${name}"]`);
|
|
5446
|
-
if (
|
|
5471
|
+
if (table) {
|
|
5472
|
+
if (totalElements !== undefined) {
|
|
5473
|
+
table.totalElements = totalElements;
|
|
5474
|
+
}
|
|
5475
|
+
await table.setPage(page, rows, hasNext);
|
|
5447
5476
|
return;
|
|
5448
|
-
if (totalElements !== undefined) {
|
|
5449
|
-
table.totalElements = totalElements;
|
|
5450
5477
|
}
|
|
5451
|
-
|
|
5478
|
+
// Cards mode: mrd-memo-container mounts mrd-memo-list instead of mrd-table.
|
|
5479
|
+
const memoList = this.el.querySelector(`mrd-memo-list[data-view="${name}"]`);
|
|
5480
|
+
if (memoList) {
|
|
5481
|
+
await memoList.setPage(page, rows, hasNext);
|
|
5482
|
+
}
|
|
5452
5483
|
}
|
|
5453
5484
|
/** Inject aggregation totals into an embedded mrd-table for a VIEW or RELATED_VIEW item. */
|
|
5454
5485
|
async setViewAggregations(name, data) {
|
|
@@ -5471,11 +5502,18 @@ const MrdLayoutSection = class {
|
|
|
5471
5502
|
await list.setFileReference(uri);
|
|
5472
5503
|
}
|
|
5473
5504
|
/** Inject the created document's href after a file-drop create, so the
|
|
5474
|
-
* optimistic row becomes navigable (see mrdCreateObject).
|
|
5505
|
+
* optimistic row becomes navigable (see mrdCreateObject). For a memo
|
|
5506
|
+
* quick-create there is no optimistic row to resolve — simply reload the
|
|
5507
|
+
* container's current body so the new memo shows up. */
|
|
5475
5508
|
async setViewCreatedObject(name, href) {
|
|
5476
5509
|
const list = this.el.querySelector(`mrd-document-list[data-doclist="${name}"]`);
|
|
5477
|
-
if (list === null || list === void 0 ? void 0 : list.setCreatedHref)
|
|
5510
|
+
if (list === null || list === void 0 ? void 0 : list.setCreatedHref) {
|
|
5478
5511
|
await list.setCreatedHref(href);
|
|
5512
|
+
return;
|
|
5513
|
+
}
|
|
5514
|
+
const memoContainer = this.el.querySelector(`mrd-memo-container[data-view="${name}"]`);
|
|
5515
|
+
if (memoContainer === null || memoContainer === void 0 ? void 0 : memoContainer.refresh)
|
|
5516
|
+
await memoContainer.refresh();
|
|
5479
5517
|
}
|
|
5480
5518
|
/** Provide a resolved URL for an IMAGE field. Shows as thumbnail; clicking opens the lightbox. */
|
|
5481
5519
|
async setImagePreview(fieldName, url) {
|
|
@@ -5537,7 +5575,7 @@ const MrdLayoutSection = class {
|
|
|
5537
5575
|
return (index.h("div", { class: "mrd-layout-section__search", key: `search-${dataClass}` }, index.h("div", { class: "mrd-layout-section__search-wrap" }, index.h("svg", { class: "mrd-layout-section__search-icon", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true" }, index.h("path", { "fill-rule": "evenodd", d: "M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z", "clip-rule": "evenodd" })), index.h("input", { class: "mrd-layout-section__search-input", type: "text", value: query, placeholder: (_c = item.label) !== null && _c !== void 0 ? _c : '', onInput: e => this.handleSearchInput(dataClass, e.target.value) })), results.length > 0 && (index.h("ul", { class: "mrd-layout-section__search-results" }, results.map(r => (index.h("li", { key: r.id, class: "mrd-layout-section__search-result" }, index.h("button", { class: "mrd-layout-section__search-result-btn", onClick: () => this.mrdNavigate.emit({ href: r.id, label: r.label }) }, index.h("span", { class: "mrd-layout-section__search-result-label" }, r.label), r.description && index.h("span", { class: "mrd-layout-section__search-result-desc" }, r.description)))))))));
|
|
5538
5576
|
}
|
|
5539
5577
|
renderRelatedView(item) {
|
|
5540
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
5578
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
5541
5579
|
const key = viewKeyFor(item);
|
|
5542
5580
|
if (!key)
|
|
5543
5581
|
return null;
|
|
@@ -5550,13 +5588,12 @@ const MrdLayoutSection = class {
|
|
|
5550
5588
|
// The API publishes `archetypes` on the VIEW/RELATED_VIEW item itself
|
|
5551
5589
|
// (sibling of `view`), not inside `view`.
|
|
5552
5590
|
const docArchetype = clientLayout.resolveArchetype((_g = item.archetypes) !== null && _g !== void 0 ? _g : (_h = item.view) === null || _h === void 0 ? void 0 : _h.archetypes, clientLayout.ARCHETYPE_DOCUMENT);
|
|
5591
|
+
const memoArchetype = !docArchetype ? clientLayout.resolveArchetype((_j = item.archetypes) !== null && _j !== void 0 ? _j : (_k = item.view) === null || _k === void 0 ? void 0 : _k.archetypes, clientLayout.ARCHETYPE_MEMO) : undefined;
|
|
5553
5592
|
// Canonical parent href for single-container seeding: use the RELATED_VIEW's
|
|
5554
5593
|
// fromClass (base class) rather than the route class, so polymorphic subtypes
|
|
5555
5594
|
// resolve to the same container the documents actually reference.
|
|
5556
5595
|
const containerHref = buildContainerHref(item, selfHref, parentId);
|
|
5557
|
-
return (index.h("div", { class: "mrd-layout-section__related-view", key: `view-${key}` }, showTitle && item.label && index.h("h3", { class: "mrd-layout-section__related-view-title" }, item.label), docArchetype
|
|
5558
|
-
? this.renderDocumentContainer(item, key, parentId, docArchetype, containerHref)
|
|
5559
|
-
: this.renderTable(item, key, parentId)));
|
|
5596
|
+
return (index.h("div", { class: "mrd-layout-section__related-view", key: `view-${key}` }, showTitle && item.label && index.h("h3", { class: "mrd-layout-section__related-view-title" }, item.label), docArchetype && this.renderDocumentContainer(item, key, parentId, docArchetype, containerHref), memoArchetype && this.renderMemoContainer(item, key, parentId, memoArchetype, containerHref), !docArchetype && !memoArchetype && this.renderTable(item, key, parentId)));
|
|
5560
5597
|
}
|
|
5561
5598
|
/** Document collection view: owns the view-switch + collection actions and
|
|
5562
5599
|
* swaps between the folder tree and the flat table. Events are re-emitted to
|
|
@@ -5594,6 +5631,33 @@ const MrdLayoutSection = class {
|
|
|
5594
5631
|
this.mrdCreateObject.emit(Object.assign({ name: key }, e.detail));
|
|
5595
5632
|
} }));
|
|
5596
5633
|
}
|
|
5634
|
+
/** Memo collection view: owns the view-switch + "New memo" and swaps between
|
|
5635
|
+
* the card list and the flat table, mirroring renderDocumentContainer(). */
|
|
5636
|
+
renderMemoContainer(item, key, parentId, archetype, containerHref) {
|
|
5637
|
+
var _a, _b, _c, _d;
|
|
5638
|
+
const labelsListItems = (_d = (_c = (_b = (_a = item.view) === null || _a === void 0 ? void 0 : _a.values) === null || _b === void 0 ? void 0 : _b.find(v => { var _a; return v.name === ((_a = archetype.slots) === null || _a === void 0 ? void 0 : _a.labels); })) === null || _c === void 0 ? void 0 : _c.listItems) !== null && _d !== void 0 ? _d : null;
|
|
5639
|
+
return (index.h("mrd-memo-container", { "data-view": key, item: item, archetype: archetype, parentId: parentId, containerHref: containerHref, viewKey: key, locale: this.locale, readOnly: this.readOnly, me: this.me, labelsListItems: labelsListItems, onMrdLoadPage: (e) => {
|
|
5640
|
+
e.stopPropagation();
|
|
5641
|
+
this.mrdLoadViewPage.emit(Object.assign({ name: key }, e.detail));
|
|
5642
|
+
}, onMrdLoadAggregations: (e) => {
|
|
5643
|
+
var _a;
|
|
5644
|
+
e.stopPropagation();
|
|
5645
|
+
this.mrdLoadViewAggregations.emit(Object.assign({ name: key, dataClass: (_a = item.dataClass) !== null && _a !== void 0 ? _a : key }, e.detail));
|
|
5646
|
+
}, onMrdAction: (e) => {
|
|
5647
|
+
var _a;
|
|
5648
|
+
e.stopPropagation();
|
|
5649
|
+
this.mrdViewAction.emit(Object.assign({ name: key, dataClass: (_a = item.dataClass) !== null && _a !== void 0 ? _a : key }, e.detail));
|
|
5650
|
+
}, onMrdCreateObject: (e) => {
|
|
5651
|
+
e.stopPropagation();
|
|
5652
|
+
this.mrdCreateObject.emit(Object.assign({ name: key }, e.detail));
|
|
5653
|
+
}, onMrdUpdateObject: (e) => {
|
|
5654
|
+
e.stopPropagation();
|
|
5655
|
+
this.mrdUpdateObject.emit(e.detail);
|
|
5656
|
+
}, onMrdDeleteObject: (e) => {
|
|
5657
|
+
e.stopPropagation();
|
|
5658
|
+
this.mrdDeleteObject.emit(e.detail);
|
|
5659
|
+
} }));
|
|
5660
|
+
}
|
|
5597
5661
|
renderTable(item, key, parentId) {
|
|
5598
5662
|
return (index.h("mrd-table", { "data-view": key, item: item, parentId: parentId, locale: this.locale, readOnly: this.readOnly, onMrdLoadPage: (e) => this.handleViewLoadPage(e, key), onMrdLoadAggregations: (e) => {
|
|
5599
5663
|
var _a;
|
|
@@ -5695,11 +5759,24 @@ const MrdLayoutSection = class {
|
|
|
5695
5759
|
...this.relatedItems().map(it => this.renderItem(it)),
|
|
5696
5760
|
];
|
|
5697
5761
|
}
|
|
5762
|
+
/** Single-memo view: the record's own type carries commons.memo. Renders a
|
|
5763
|
+
* recognisable memo (title/body prominent, author/date subtle) instead of
|
|
5764
|
+
* generic fields, keeping any related views/searches below it. */
|
|
5765
|
+
renderMemoObject(archetype) {
|
|
5766
|
+
var _a, _b;
|
|
5767
|
+
const labelsListItems = (_b = (_a = this.items.find(it => { var _a; return it.name === ((_a = archetype.slots) === null || _a === void 0 ? void 0 : _a.labels); })) === null || _a === void 0 ? void 0 : _a.listItems) !== null && _b !== void 0 ? _b : null;
|
|
5768
|
+
return [
|
|
5769
|
+
index.h("mrd-memo-view", { archetype: archetype, data: this.data, locale: this.locale, labelsListItems: labelsListItems, onMrdNavigate: (e) => { e.stopPropagation(); this.mrdNavigate.emit(e.detail); } }),
|
|
5770
|
+
...this.relatedItems().map(it => this.renderItem(it)),
|
|
5771
|
+
];
|
|
5772
|
+
}
|
|
5698
5773
|
render() {
|
|
5699
5774
|
const docArchetype = clientLayout.resolveArchetype(this.archetypes, clientLayout.ARCHETYPE_DOCUMENT);
|
|
5700
5775
|
const invoiceArchetype = !docArchetype ? clientLayout.resolveArchetype(this.archetypes, clientLayout.ARCHETYPE_INVOICE) : undefined;
|
|
5701
5776
|
const emailArchetype = !docArchetype && !invoiceArchetype ? clientLayout.resolveArchetype(this.archetypes, clientLayout.ARCHETYPE_EMAIL) : undefined;
|
|
5702
|
-
|
|
5777
|
+
const memoArchetype = !docArchetype && !invoiceArchetype && !emailArchetype ? clientLayout.resolveArchetype(this.archetypes, clientLayout.ARCHETYPE_MEMO) : undefined;
|
|
5778
|
+
const anyArchetype = docArchetype || invoiceArchetype || emailArchetype || memoArchetype;
|
|
5779
|
+
return (index.h(index.Host, { key: '730654d745992b9607f15fcaf2bb54a725429e4d' }, index.h("div", { key: '72a2e7bb767992aa6f206a10f8b2a3a572e86115', class: "mrd-layout-section" }, docArchetype && this.renderDocumentObject(docArchetype), invoiceArchetype && this.renderInvoiceObject(invoiceArchetype), emailArchetype && this.renderEmailObject(emailArchetype), memoArchetype && this.renderMemoObject(memoArchetype), !anyArchetype && this.items.map(item => this.renderItem(item))), this.renderImageModal()));
|
|
5703
5780
|
}
|
|
5704
5781
|
get el() { return index.getElement(this); }
|
|
5705
5782
|
static get watchers() { return {
|
|
@@ -5823,153 +5900,916 @@ const MrdLongtextField = class {
|
|
|
5823
5900
|
};
|
|
5824
5901
|
MrdLongtextField.style = mrdLongtextFieldCss();
|
|
5825
5902
|
|
|
5826
|
-
const
|
|
5903
|
+
const mrdMemoContainerCss = () => `.sc-mrd-memo-container-h{display:block}.mrd-memo-container__toolbar.sc-mrd-memo-container{display:flex;align-items:center;justify-content:flex-end;gap:var(--mrd-space-2);padding:var(--mrd-space-2) 0;border-bottom:1px solid var(--mrd-color-neutral-100)}.mrd-memo-container__action.sc-mrd-memo-container{display:inline-flex;align-items:center;gap:var(--mrd-space-2);height:1.625rem;padding:0 var(--mrd-space-3);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-700);background:var(--mrd-color-white);border:1px solid var(--mrd-color-neutral-200);border-radius:var(--mrd-border-radius);cursor:pointer;transition:background var(--mrd-transition-fast), border-color var(--mrd-transition-fast)}.mrd-memo-container__action.sc-mrd-memo-container svg.sc-mrd-memo-container{width:1rem;height:1rem}.mrd-memo-container__action.sc-mrd-memo-container:hover:not(:disabled){background:var(--mrd-color-neutral-50);border-color:var(--mrd-color-neutral-300)}.mrd-memo-container__action.sc-mrd-memo-container:disabled{opacity:0.5;cursor:not-allowed}.mrd-memo-container__seg.sc-mrd-memo-container{display:inline-flex;gap:2px;padding:2px;background:var(--mrd-color-neutral-100);border-radius:var(--mrd-border-radius)}.mrd-memo-container__seg-btn.sc-mrd-memo-container{width:1.875rem;height:1.625rem;display:grid;place-items:center;border:none;background:none;border-radius:var(--mrd-border-radius-sm);color:var(--mrd-color-neutral-500);cursor:pointer;transition:color var(--mrd-transition-fast), background var(--mrd-transition-fast)}.mrd-memo-container__seg-btn.sc-mrd-memo-container:hover{color:var(--mrd-color-neutral-800)}.mrd-memo-container__seg-btn[aria-pressed=true].sc-mrd-memo-container{background:var(--mrd-color-white);color:var(--mrd-color-primary-dark);box-shadow:var(--mrd-shadow-sm)}.mrd-memo-container__seg-btn.sc-mrd-memo-container svg.sc-mrd-memo-container{width:1rem;height:1rem}.mrd-memo-container__body.sc-mrd-memo-container{padding-top:var(--mrd-space-3)}.mrd-memo-container__modal-backdrop.sc-mrd-memo-container{position:fixed;inset:0;background:rgba(0, 0, 0, 0.6);z-index:300;display:flex;align-items:center;justify-content:center;padding:var(--mrd-space-4)}.mrd-memo-container__modal.sc-mrd-memo-container{width:100%;max-width:960px;max-height:90vh;overflow-y:auto;display:flex;flex-direction:column;gap:var(--mrd-space-4);background:var(--mrd-color-white);border-radius:var(--mrd-border-radius-md);padding:var(--mrd-space-5);box-shadow:var(--mrd-shadow-lg)}.mrd-memo-container__modal-title.sc-mrd-memo-container{font-size:var(--mrd-font-size-lg);font-weight:var(--mrd-font-weight-bold);color:var(--mrd-color-neutral-900);margin:0}.mrd-memo-container__modal-field.sc-mrd-memo-container{display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-memo-container__modal-error.sc-mrd-memo-container{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-memo-container__modal-warning.sc-mrd-memo-container{margin:0;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-color-neutral-600)}.mrd-memo-container__modal-actions.sc-mrd-memo-container{display:flex;justify-content:flex-end;gap:var(--mrd-space-3);margin-top:var(--mrd-space-2);padding-top:var(--mrd-space-4);border-top:var(--mrd-border-width) solid var(--mrd-border-color)}.mrd-memo-container__modal-delete.sc-mrd-memo-container{display:inline-flex;align-items:center;justify-content:center;height:var(--mrd-input-height);padding:0 var(--mrd-space-6);margin-right:auto;background-color:transparent;color:var(--mrd-color-danger);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-medium);border:var(--mrd-border-width) solid var(--mrd-color-danger);border-radius:var(--mrd-border-radius);cursor:pointer;transition:background-color var(--mrd-transition), color var(--mrd-transition)}.mrd-memo-container__modal-delete.sc-mrd-memo-container:hover{background-color:var(--mrd-color-danger-light);color:var(--mrd-color-danger-dark)}.mrd-memo-container__modal-delete-confirm.sc-mrd-memo-container{display:inline-flex;align-items:center;justify-content:center;height:var(--mrd-input-height);padding:0 var(--mrd-space-6);background-color:var(--mrd-color-danger);color:var(--mrd-color-white);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-medium);border:none;border-radius:var(--mrd-border-radius);cursor:pointer;transition:background-color var(--mrd-transition)}.mrd-memo-container__modal-delete-confirm.sc-mrd-memo-container:hover{background-color:var(--mrd-color-danger-dark)}.mrd-memo-container__modal-cancel.sc-mrd-memo-container{display:inline-flex;align-items:center;justify-content:center;height:var(--mrd-input-height);padding:0 var(--mrd-space-6);background-color:transparent;color:var(--mrd-color-neutral-600);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-medium);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);cursor:pointer;transition:background-color var(--mrd-transition), color var(--mrd-transition)}.mrd-memo-container__modal-cancel.sc-mrd-memo-container:hover{background-color:var(--mrd-color-neutral-100);color:var(--mrd-color-neutral-800)}.mrd-memo-container__modal-submit.sc-mrd-memo-container{display:inline-flex;align-items:center;justify-content:center;height:var(--mrd-input-height);padding:0 var(--mrd-space-6);background-color:var(--mrd-color-primary);color:var(--mrd-color-white);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-medium);border:none;border-radius:var(--mrd-border-radius);cursor:pointer;transition:background-color var(--mrd-transition)}.mrd-memo-container__modal-submit.sc-mrd-memo-container:hover{background-color:var(--mrd-color-primary-hover)}`;
|
|
5827
5904
|
|
|
5828
|
-
const
|
|
5905
|
+
const MrdMemoContainer = class {
|
|
5829
5906
|
constructor(hostRef) {
|
|
5830
5907
|
index.registerInstance(this, hostRef);
|
|
5831
|
-
this.
|
|
5832
|
-
this.
|
|
5833
|
-
this.
|
|
5834
|
-
this.
|
|
5835
|
-
this.
|
|
5836
|
-
this.
|
|
5837
|
-
|
|
5838
|
-
this.
|
|
5908
|
+
this.mrdLoadPage = index.createEvent(this, "mrdLoadPage");
|
|
5909
|
+
this.mrdLoadAggregations = index.createEvent(this, "mrdLoadAggregations");
|
|
5910
|
+
this.mrdAction = index.createEvent(this, "mrdAction");
|
|
5911
|
+
this.mrdCreateObject = index.createEvent(this, "mrdCreateObject");
|
|
5912
|
+
this.mrdUpdateObject = index.createEvent(this, "mrdUpdateObject");
|
|
5913
|
+
this.mrdDeleteObject = index.createEvent(this, "mrdDeleteObject");
|
|
5914
|
+
/** The VIEW or RELATED_VIEW layout item (dataClass, fromClass, view config). */
|
|
5915
|
+
this.item = null;
|
|
5916
|
+
/** Parent record id — required for RELATED_VIEW path building. */
|
|
5917
|
+
this.parentId = '';
|
|
5918
|
+
/** Canonical parent href — set when this is a RELATED_VIEW embedded under a
|
|
5919
|
+
* parent record, which already gives a new memo something to attach to. */
|
|
5920
|
+
this.containerHref = '';
|
|
5921
|
+
/** Lookup key used for the embedded `data-view` attribute. */
|
|
5922
|
+
this.viewKey = '';
|
|
5839
5923
|
this.locale = navigator.language;
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
this.
|
|
5843
|
-
this
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
this.
|
|
5847
|
-
|
|
5924
|
+
/** listItems of the FIELD bound to the `labels` slot; forwarded to whichever
|
|
5925
|
+
* body is mounted and used to render the dialog's label checkboxes. */
|
|
5926
|
+
this.labelsListItems = null;
|
|
5927
|
+
/** When true, this dashboard is read-only: "New memo" is disabled with a
|
|
5928
|
+
* tooltip, cards/rows are not clickable, and the embedded table's own
|
|
5929
|
+
* create action is disabled too. */
|
|
5930
|
+
this.readOnly = false;
|
|
5931
|
+
/** The active account's linked person record (userProfile.links.person), if any.
|
|
5932
|
+
* Used both to gate "New memo" (see effectiveContainerHref) and, on submit, to
|
|
5933
|
+
* fill the author slot. */
|
|
5934
|
+
this.me = null;
|
|
5935
|
+
/** Active body: card list or flat table. */
|
|
5936
|
+
this.mode = 'cards';
|
|
5937
|
+
this.dialogOpen = false;
|
|
5938
|
+
/** Href of the memo being edited; null while creating. */
|
|
5939
|
+
this.editingHref = null;
|
|
5940
|
+
this.dialogBody = '';
|
|
5941
|
+
this.dialogTitle = '';
|
|
5942
|
+
this.dialogLabels = [];
|
|
5943
|
+
this.dialogImportant = false;
|
|
5944
|
+
this.dialogTouched = false;
|
|
5945
|
+
/** True while the dialog shows the delete confirmation step in place of the
|
|
5946
|
+
* form fields — mirrors mrd-merge-view's MergeConfirmStep (same panel,
|
|
5947
|
+
* swapped content) rather than stacking a second modal. */
|
|
5948
|
+
this.deleteConfirmOpen = false;
|
|
5949
|
+
/** Whether the currently mounted body has been init()'d. Reset on every mode switch. */
|
|
5950
|
+
this.listInited = false;
|
|
5951
|
+
this.tableInited = false;
|
|
5952
|
+
this.escapeHandler = null;
|
|
5953
|
+
this.openCreate = () => {
|
|
5954
|
+
if (!this.canAdd)
|
|
5955
|
+
return;
|
|
5956
|
+
this.editingHref = null;
|
|
5957
|
+
this.dialogBody = '';
|
|
5958
|
+
this.dialogTitle = '';
|
|
5959
|
+
this.dialogLabels = [];
|
|
5960
|
+
this.dialogImportant = false;
|
|
5961
|
+
this.dialogTouched = false;
|
|
5962
|
+
this.deleteConfirmOpen = false;
|
|
5963
|
+
this.dialogOpen = true;
|
|
5848
5964
|
};
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
if (this.
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
5857
|
-
|
|
5965
|
+
/** Opens the same dialog pre-filled from an existing memo row/record —
|
|
5966
|
+
* triggered by clicking a card or a table row. No separate detail page. */
|
|
5967
|
+
this.openEdit = (row) => {
|
|
5968
|
+
var _a, _b;
|
|
5969
|
+
if (this.readOnly)
|
|
5970
|
+
return;
|
|
5971
|
+
const href = (_b = (_a = row === null || row === void 0 ? void 0 : row._links) === null || _a === void 0 ? void 0 : _a.self) === null || _b === void 0 ? void 0 : _b.href;
|
|
5972
|
+
if (!href)
|
|
5973
|
+
return;
|
|
5974
|
+
this.editingHref = href;
|
|
5975
|
+
const bodyRaw = this.slotValue(row, 'body');
|
|
5976
|
+
this.dialogBody = bodyRaw != null ? String(bodyRaw) : '';
|
|
5977
|
+
const titleRaw = this.slotValue(row, 'title');
|
|
5978
|
+
this.dialogTitle = titleRaw != null ? String(titleRaw) : '';
|
|
5979
|
+
const labelsRaw = this.slotValue(row, 'labels');
|
|
5980
|
+
this.dialogLabels = Array.isArray(labelsRaw)
|
|
5981
|
+
? labelsRaw.map(String)
|
|
5982
|
+
: (labelsRaw != null && labelsRaw !== '' ? [String(labelsRaw)] : []);
|
|
5983
|
+
this.dialogImportant = !!this.slotValue(row, 'important');
|
|
5984
|
+
this.dialogTouched = false;
|
|
5985
|
+
this.deleteConfirmOpen = false;
|
|
5986
|
+
this.dialogOpen = true;
|
|
5987
|
+
};
|
|
5988
|
+
this.closeDialog = () => {
|
|
5989
|
+
this.dialogOpen = false;
|
|
5990
|
+
this.deleteConfirmOpen = false;
|
|
5991
|
+
};
|
|
5992
|
+
this.openDeleteConfirm = () => {
|
|
5993
|
+
this.deleteConfirmOpen = true;
|
|
5994
|
+
};
|
|
5995
|
+
this.cancelDeleteConfirm = () => {
|
|
5996
|
+
this.deleteConfirmOpen = false;
|
|
5997
|
+
};
|
|
5998
|
+
this.confirmDelete = () => {
|
|
5999
|
+
var _a;
|
|
6000
|
+
if (!this.editingHref)
|
|
6001
|
+
return;
|
|
6002
|
+
const href = this.editingHref;
|
|
6003
|
+
this.mrdDeleteObject.emit({ href });
|
|
6004
|
+
if (this.mode === 'cards') {
|
|
6005
|
+
(_a = this.listEl) === null || _a === void 0 ? void 0 : _a.removeRow(href);
|
|
5858
6006
|
}
|
|
5859
6007
|
else {
|
|
5860
|
-
this.
|
|
5861
|
-
}
|
|
5862
|
-
if (parsed !== null && validateRequired(raw)) {
|
|
5863
|
-
this.displayValue = this.formatForDisplay(parsed);
|
|
6008
|
+
this.refresh();
|
|
5864
6009
|
}
|
|
5865
|
-
this.
|
|
5866
|
-
this.
|
|
6010
|
+
this.deleteConfirmOpen = false;
|
|
6011
|
+
this.dialogOpen = false;
|
|
5867
6012
|
};
|
|
5868
|
-
this.
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
6013
|
+
this.submitDialog = () => {
|
|
6014
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
6015
|
+
this.dialogTouched = true;
|
|
6016
|
+
if (!this.dialogBody.trim())
|
|
6017
|
+
return;
|
|
6018
|
+
const slots = (_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) !== null && _b !== void 0 ? _b : {};
|
|
6019
|
+
if (this.editingHref) {
|
|
6020
|
+
// Every shown field is sent explicitly, even when cleared/unchecked —
|
|
6021
|
+
// this is a PATCH, so omitting a field would leave its old value intact.
|
|
6022
|
+
const values = { [(_c = slots.body) !== null && _c !== void 0 ? _c : 'body']: this.dialogBody };
|
|
6023
|
+
if (this.hasTitleSlot)
|
|
6024
|
+
values[(_d = slots.title) !== null && _d !== void 0 ? _d : 'title'] = this.dialogTitle.trim() || null;
|
|
6025
|
+
if (((_e = this.labelsListItems) !== null && _e !== void 0 ? _e : []).length)
|
|
6026
|
+
values[(_f = slots.labels) !== null && _f !== void 0 ? _f : 'labels'] = this.dialogLabels;
|
|
6027
|
+
if (this.hasImportantSlot)
|
|
6028
|
+
values[(_g = slots.important) !== null && _g !== void 0 ? _g : 'important'] = this.dialogImportant;
|
|
6029
|
+
this.mrdUpdateObject.emit({ href: this.editingHref, values });
|
|
6030
|
+
if (this.mode === 'cards') {
|
|
6031
|
+
(_h = this.listEl) === null || _h === void 0 ? void 0 : _h.patchRow(this.editingHref, values);
|
|
6032
|
+
}
|
|
6033
|
+
else {
|
|
6034
|
+
this.refresh();
|
|
6035
|
+
}
|
|
6036
|
+
}
|
|
6037
|
+
else {
|
|
6038
|
+
if (!this.canAdd)
|
|
6039
|
+
return;
|
|
6040
|
+
const values = {
|
|
6041
|
+
[(_j = slots.body) !== null && _j !== void 0 ? _j : 'body']: this.dialogBody,
|
|
6042
|
+
// now(), same token/format mrd-form's own defaultValue resolution uses.
|
|
6043
|
+
[(_k = slots.date) !== null && _k !== void 0 ? _k : 'date']: new Date().toISOString().replace(/\.\d{3}Z$/, 'Z'),
|
|
6044
|
+
};
|
|
6045
|
+
if (this.hasTitleSlot && this.dialogTitle.trim())
|
|
6046
|
+
values[(_l = slots.title) !== null && _l !== void 0 ? _l : 'title'] = this.dialogTitle.trim();
|
|
6047
|
+
if (((_m = this.labelsListItems) !== null && _m !== void 0 ? _m : []).length && this.dialogLabels.length)
|
|
6048
|
+
values[(_o = slots.labels) !== null && _o !== void 0 ? _o : 'labels'] = this.dialogLabels;
|
|
6049
|
+
if (this.hasImportantSlot && this.dialogImportant)
|
|
6050
|
+
values[(_p = slots.important) !== null && _p !== void 0 ? _p : 'important'] = true;
|
|
6051
|
+
if (this.meHref())
|
|
6052
|
+
values[(_q = slots.author) !== null && _q !== void 0 ? _q : 'author'] = this.meHref();
|
|
6053
|
+
// Always explicit — relation values are never inferred from the URL elsewhere
|
|
6054
|
+
// in this codebase (e.g. mrd-form's own submit payload), so don't assume it here.
|
|
6055
|
+
values[(_r = slots.container) !== null && _r !== void 0 ? _r : 'container'] = this.effectiveContainerHref;
|
|
6056
|
+
this.mrdCreateObject.emit({ path: this.buildCreatePath(), values });
|
|
5875
6057
|
}
|
|
6058
|
+
this.dialogOpen = false;
|
|
5876
6059
|
};
|
|
5877
6060
|
}
|
|
5878
|
-
|
|
5879
|
-
this.
|
|
5880
|
-
}
|
|
5881
|
-
/**
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
6061
|
+
disconnectedCallback() {
|
|
6062
|
+
this.unbindEscape();
|
|
6063
|
+
}
|
|
6064
|
+
/** Escape backs out of the delete-confirm step first (matches Cancel there),
|
|
6065
|
+
* or closes the whole dialog. Bound to `document` — bubbling from inside the
|
|
6066
|
+
* Quill editor is not reliable enough to rely on a local key handler. */
|
|
6067
|
+
dialogOpenChanged(open) {
|
|
6068
|
+
if (open) {
|
|
6069
|
+
this.escapeHandler = (e) => {
|
|
6070
|
+
if (e.key !== 'Escape')
|
|
6071
|
+
return;
|
|
6072
|
+
if (this.deleteConfirmOpen)
|
|
6073
|
+
this.cancelDeleteConfirm();
|
|
6074
|
+
else
|
|
6075
|
+
this.closeDialog();
|
|
6076
|
+
};
|
|
6077
|
+
document.addEventListener('keydown', this.escapeHandler);
|
|
6078
|
+
}
|
|
6079
|
+
else {
|
|
6080
|
+
this.unbindEscape();
|
|
6081
|
+
}
|
|
5889
6082
|
}
|
|
5890
|
-
|
|
5891
|
-
this.
|
|
5892
|
-
|
|
6083
|
+
unbindEscape() {
|
|
6084
|
+
if (this.escapeHandler) {
|
|
6085
|
+
document.removeEventListener('keydown', this.escapeHandler);
|
|
6086
|
+
this.escapeHandler = null;
|
|
6087
|
+
}
|
|
5893
6088
|
}
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
6089
|
+
/** Neither body self-loads: like mrd-table, both wait for init(). mrd-layout-section
|
|
6090
|
+
* init()s whichever is mounted at load time via its own querySelector pass; when the
|
|
6091
|
+
* user switches mode here, the freshly mounted body needs the same treatment. */
|
|
6092
|
+
componentDidRender() {
|
|
6093
|
+
var _a, _b;
|
|
6094
|
+
if (this.mode === 'cards' && this.listEl && !this.listInited) {
|
|
6095
|
+
this.listInited = true;
|
|
6096
|
+
const list = this.listEl;
|
|
6097
|
+
Promise.resolve((_a = list.componentOnReady) === null || _a === void 0 ? void 0 : _a.call(list)).then(() => list.init());
|
|
5900
6098
|
}
|
|
5901
|
-
if (this.
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
});
|
|
6099
|
+
if (this.mode === 'table' && this.tableEl && !this.tableInited) {
|
|
6100
|
+
this.tableInited = true;
|
|
6101
|
+
const table = this.tableEl;
|
|
6102
|
+
Promise.resolve((_b = table.componentOnReady) === null || _b === void 0 ? void 0 : _b.call(table)).then(() => table.init());
|
|
5906
6103
|
}
|
|
5907
|
-
|
|
6104
|
+
}
|
|
6105
|
+
setMode(mode) {
|
|
6106
|
+
if (mode === this.mode)
|
|
6107
|
+
return;
|
|
6108
|
+
this.listInited = false;
|
|
6109
|
+
this.tableInited = false;
|
|
6110
|
+
this.mode = mode;
|
|
6111
|
+
}
|
|
6112
|
+
/** Re-request page 0 of whichever body is currently mounted — called by
|
|
6113
|
+
* mrd-layout-section after a successful mrdCreateObject, and by this
|
|
6114
|
+
* component itself after an edit to a table row (which has no per-row
|
|
6115
|
+
* optimistic-patch method the way mrd-memo-list does). */
|
|
6116
|
+
async refresh() {
|
|
6117
|
+
if (this.mode === 'cards' && this.listEl) {
|
|
6118
|
+
await this.listEl.init();
|
|
6119
|
+
}
|
|
6120
|
+
else if (this.mode === 'table' && this.tableEl) {
|
|
6121
|
+
await this.tableEl.init();
|
|
6122
|
+
}
|
|
6123
|
+
}
|
|
6124
|
+
/** `me` is typed as RelationSearchResult ({ id, label }) but hosts differ on
|
|
6125
|
+
* which shape they actually populate: this repo's own dev preview resolves
|
|
6126
|
+
* it via /accounts/me as a real { id, label } RelationSearchResult, while
|
|
6127
|
+
* content-app feeds it from userProfile.links.person, the raw API link shape
|
|
6128
|
+
* ({ href, name }). Both occur in practice — same dual tolerance as
|
|
6129
|
+
* mrd-form's own getHref(). */
|
|
6130
|
+
meHref() {
|
|
6131
|
+
var _a, _b;
|
|
6132
|
+
const m = this.me;
|
|
6133
|
+
return (_b = (_a = m === null || m === void 0 ? void 0 : m.id) !== null && _a !== void 0 ? _a : m === null || m === void 0 ? void 0 : m.href) !== null && _b !== void 0 ? _b : '';
|
|
6134
|
+
}
|
|
6135
|
+
/** Value of a value-slot: reads row[field] via the slot→field map. */
|
|
6136
|
+
slotValue(row, slot) {
|
|
6137
|
+
var _a, _b;
|
|
6138
|
+
const field = (_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) === null || _b === void 0 ? void 0 : _b[slot];
|
|
6139
|
+
if (!field)
|
|
6140
|
+
return undefined;
|
|
6141
|
+
return row[field];
|
|
6142
|
+
}
|
|
6143
|
+
get hasTitleSlot() {
|
|
6144
|
+
var _a, _b;
|
|
6145
|
+
return !!((_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) === null || _b === void 0 ? void 0 : _b.title);
|
|
6146
|
+
}
|
|
6147
|
+
get hasImportantSlot() {
|
|
6148
|
+
var _a, _b;
|
|
6149
|
+
return !!((_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) === null || _b === void 0 ? void 0 : _b.important);
|
|
6150
|
+
}
|
|
6151
|
+
/** A parent record already gives a new memo somewhere to attach to (RELATED_VIEW);
|
|
6152
|
+
* otherwise fall back to the account's own linked person (top-level VIEW). */
|
|
6153
|
+
get effectiveContainerHref() {
|
|
6154
|
+
return this.containerHref || this.meHref();
|
|
6155
|
+
}
|
|
6156
|
+
/** The author slot is always filled from `me` (there is no author picker in
|
|
6157
|
+
* the dialog), so without it there is nothing valid to create — regardless
|
|
6158
|
+
* of whether a parent record already supplies a container. */
|
|
6159
|
+
get canAdd() {
|
|
6160
|
+
return !this.readOnly && !!this.meHref() && !!this.effectiveContainerHref;
|
|
6161
|
+
}
|
|
6162
|
+
/** Path for creating a new memo: `/{dataClass}` for a top-level VIEW, or
|
|
6163
|
+
* `/{fromClass}/{parentId}/{dataClass}` when nested under a parent record. */
|
|
6164
|
+
buildCreatePath() {
|
|
6165
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
6166
|
+
return buildListPath({
|
|
6167
|
+
isRelatedView: ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === clientLayout.ClientLayoutItemType.RELATED_VIEW,
|
|
6168
|
+
fromClass: (_b = this.item) === null || _b === void 0 ? void 0 : _b.fromClass,
|
|
6169
|
+
parentId: this.parentId,
|
|
6170
|
+
dataClass: (_f = (_d = (_c = this.item) === null || _c === void 0 ? void 0 : _c.filterClass) !== null && _d !== void 0 ? _d : (_e = this.item) === null || _e === void 0 ? void 0 : _e.dataClass) !== null && _f !== void 0 ? _f : (_g = this.item) === null || _g === void 0 ? void 0 : _g.relatedClass,
|
|
6171
|
+
});
|
|
6172
|
+
}
|
|
6173
|
+
renderToolbar() {
|
|
6174
|
+
return (index.h("div", { class: "mrd-memo-container__toolbar" }, this.mode === 'cards' && (index.h("button", { type: "button", class: "mrd-memo-container__action", disabled: !this.canAdd, title: this.readOnly ? cellRenderer.t('readonly_access', this.locale) : undefined, onClick: this.openCreate }, index.h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, index.h("path", { d: "M12 5v14M5 12h14" })), cellRenderer.t('memo_new', this.locale))), index.h("div", { class: "mrd-memo-container__seg", role: "group", "aria-label": cellRenderer.t('doc_view_switch', this.locale) }, index.h("button", { class: "mrd-memo-container__seg-btn", "aria-pressed": String(this.mode === 'cards'), title: cellRenderer.t('memo_view_cards', this.locale), "aria-label": cellRenderer.t('memo_view_cards', this.locale), onClick: () => this.setMode('cards') }, index.h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, index.h("rect", { x: "3", y: "4", width: "7", height: "7", rx: "1" }), index.h("rect", { x: "14", y: "4", width: "7", height: "7", rx: "1" }), index.h("rect", { x: "3", y: "15", width: "7", height: "5", rx: "1" }), index.h("rect", { x: "14", y: "15", width: "7", height: "5", rx: "1" }))), index.h("button", { class: "mrd-memo-container__seg-btn", "aria-pressed": String(this.mode === 'table'), title: cellRenderer.t('memo_view_table', this.locale), "aria-label": cellRenderer.t('memo_view_table', this.locale), onClick: () => this.setMode('table') }, index.h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, index.h("path", { d: "M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01" }))))));
|
|
6175
|
+
}
|
|
6176
|
+
renderDeleteConfirm() {
|
|
6177
|
+
return (index.h("div", null, index.h("h2", { class: "mrd-memo-container__modal-title" }, cellRenderer.t('memo_delete_confirm_title', this.locale)), index.h("p", { class: "mrd-memo-container__modal-warning" }, cellRenderer.t('memo_delete_confirm_body', this.locale)), index.h("div", { class: "mrd-memo-container__modal-actions" }, index.h("button", { type: "button", class: "mrd-memo-container__modal-cancel", onClick: this.cancelDeleteConfirm }, cellRenderer.t('cancel', this.locale)), index.h("button", { type: "button", class: "mrd-memo-container__modal-delete-confirm", onClick: this.confirmDelete }, cellRenderer.t('delete', this.locale)))));
|
|
6178
|
+
}
|
|
6179
|
+
renderForm() {
|
|
6180
|
+
var _a, _b, _c;
|
|
6181
|
+
const bodyMissing = this.dialogTouched && !this.dialogBody.trim();
|
|
6182
|
+
return [
|
|
6183
|
+
index.h("h2", { class: "mrd-memo-container__modal-title" }, cellRenderer.t(this.editingHref ? 'memo_edit' : 'memo_new', this.locale)),
|
|
6184
|
+
index.h("div", { class: "mrd-memo-container__modal-field" }, index.h("mrd-textarea-field", { key: (_a = this.editingHref) !== null && _a !== void 0 ? _a : 'new', name: "body", value: this.dialogBody, required: true, autofocus: true, locale: this.locale, onMrdChange: (e) => { this.dialogBody = e.detail.value; } }), bodyMissing && index.h("span", { class: "mrd-memo-container__modal-error" }, cellRenderer.t('required', this.locale))),
|
|
6185
|
+
this.hasTitleSlot && (index.h("div", { class: "mrd-memo-container__modal-field" }, index.h("mrd-text-field", { name: "title", label: cellRenderer.t('memo_field_title', this.locale), value: this.dialogTitle, locale: this.locale, onMrdChange: (e) => { this.dialogTitle = e.detail.value; } }))),
|
|
6186
|
+
!!((_b = this.labelsListItems) !== null && _b !== void 0 ? _b : []).length && (index.h("div", { class: "mrd-memo-container__modal-field" }, index.h("mrd-list-field", { name: "labels", label: cellRenderer.t('memo_field_labels', this.locale), value: this.dialogLabels, multiple: true, listItems: (_c = this.labelsListItems) !== null && _c !== void 0 ? _c : [], locale: this.locale, onMrdChange: (e) => {
|
|
6187
|
+
this.dialogLabels = Array.isArray(e.detail.value) ? e.detail.value : [e.detail.value].filter(Boolean);
|
|
6188
|
+
} }))),
|
|
6189
|
+
this.hasImportantSlot && (index.h("div", { class: "mrd-memo-container__modal-field" }, index.h("mrd-boolean-field", { name: "important", label: cellRenderer.t('memo_important', this.locale), value: this.dialogImportant, locale: this.locale, onMrdChange: (e) => { this.dialogImportant = e.detail.value; } }))),
|
|
6190
|
+
index.h("div", { class: "mrd-memo-container__modal-actions" }, this.editingHref && (index.h("button", { type: "button", class: "mrd-memo-container__modal-delete", onClick: this.openDeleteConfirm }, cellRenderer.t('delete', this.locale))), index.h("button", { type: "button", class: "mrd-memo-container__modal-cancel", onClick: this.closeDialog }, cellRenderer.t('cancel', this.locale)), index.h("button", { type: "button", class: "mrd-memo-container__modal-submit", onClick: this.submitDialog }, cellRenderer.t('submit', this.locale))),
|
|
6191
|
+
];
|
|
6192
|
+
}
|
|
6193
|
+
renderDialog() {
|
|
6194
|
+
if (!this.dialogOpen)
|
|
6195
|
+
return null;
|
|
6196
|
+
return (index.h("div", { class: "mrd-memo-container__modal-backdrop", onClick: this.closeDialog }, index.h("div", { class: "mrd-memo-container__modal", onClick: (e) => e.stopPropagation() }, this.deleteConfirmOpen ? this.renderDeleteConfirm() : this.renderForm())));
|
|
6197
|
+
}
|
|
6198
|
+
renderCards() {
|
|
6199
|
+
return (index.h("mrd-memo-list", { "data-view": this.viewKey, ref: el => (this.listEl = el), item: this.item, archetype: this.archetype, parentId: this.parentId, locale: this.locale, readOnly: this.readOnly, labelsListItems: this.labelsListItems, onMrdLoadPage: (e) => {
|
|
6200
|
+
e.stopPropagation();
|
|
6201
|
+
this.mrdLoadPage.emit(e.detail);
|
|
6202
|
+
}, onMrdEdit: (e) => {
|
|
6203
|
+
e.stopPropagation();
|
|
6204
|
+
this.openEdit(e.detail.row);
|
|
6205
|
+
} }));
|
|
6206
|
+
}
|
|
6207
|
+
renderTable() {
|
|
6208
|
+
return (index.h("mrd-table", { "data-view": this.viewKey, ref: el => (this.tableEl = el), item: this.item, parentId: this.parentId, locale: this.locale, readOnly: this.readOnly, onMrdLoadPage: (e) => {
|
|
6209
|
+
e.stopPropagation();
|
|
6210
|
+
this.mrdLoadPage.emit(e.detail);
|
|
6211
|
+
}, onMrdLoadAggregations: (e) => {
|
|
6212
|
+
e.stopPropagation();
|
|
6213
|
+
this.mrdLoadAggregations.emit(e.detail);
|
|
6214
|
+
}, onMrdRowClick: (e) => {
|
|
6215
|
+
e.stopPropagation();
|
|
6216
|
+
this.openEdit(e.detail.row);
|
|
6217
|
+
}, onMrdAction: (e) => {
|
|
6218
|
+
e.stopPropagation();
|
|
6219
|
+
this.mrdAction.emit(e.detail);
|
|
6220
|
+
} }));
|
|
5908
6221
|
}
|
|
5909
6222
|
render() {
|
|
5910
|
-
|
|
5911
|
-
const suffix = this.dataType === clientLayout.ClientLayoutItemFieldDataType.PERCENTAGE ? '%' :
|
|
5912
|
-
this.dataType === clientLayout.ClientLayoutItemFieldDataType.DECIMAL ? '' : '';
|
|
5913
|
-
return (index.h(index.Host, { key: '7343dbca882b5054f22de17672ac748a8e3eca11' }, index.h("div", { key: 'cef10b39515b48fc9c44e651910c6a0c2a847628', class: "mrd-number-field" }, index.h(FieldLabel, { key: '66f178cf20f1f2f0587bd9614db150d6ae63023e', base: "mrd-number-field", label: this.label, required: this.required }), index.h("div", { key: 'c57c22e663a570f6e5a70b07b817970f135e850c', class: "mrd-number-field__input-wrapper" }, index.h("input", { key: '388b20ac11fa4aaf78df124c858b579e12f53619', class: controlClass('mrd-number-field', hasError), type: "text", inputMode: "decimal", name: this.name, value: this.displayValue, placeholder: this.placeholder || (suffix ? `0${suffix}` : '0'), required: this.required, disabled: this.disabled, onInput: this.handleInput, onBlur: this.handleBlur, onFocus: this.handleFocus })), index.h(FieldError, { key: 'f99bb85668b047a97162ffee2582eb45dc0589ae', base: "mrd-number-field", error: this.error }))));
|
|
6223
|
+
return (index.h(index.Host, { key: 'cf5e9a23e1e8496d061c00218029ec49d92700fe' }, this.renderToolbar(), index.h("div", { key: '5a15a60ea4cc68c77a8928068f7d6d6c3cb91434', class: "mrd-memo-container__body" }, this.mode === 'cards' ? this.renderCards() : this.renderTable()), this.renderDialog()));
|
|
5914
6224
|
}
|
|
5915
6225
|
static get watchers() { return {
|
|
5916
|
-
"
|
|
5917
|
-
"
|
|
5918
|
-
}],
|
|
5919
|
-
"locale": [{
|
|
5920
|
-
"localeChanged": 0
|
|
6226
|
+
"dialogOpen": [{
|
|
6227
|
+
"dialogOpenChanged": 0
|
|
5921
6228
|
}]
|
|
5922
6229
|
}; }
|
|
5923
6230
|
};
|
|
5924
|
-
|
|
5925
|
-
|
|
5926
|
-
const mrdRelationFieldCss = () => `.sc-mrd-relation-field-h{display:block}.mrd-relation-field.sc-mrd-relation-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%;position:relative}.mrd-relation-field__label.sc-mrd-relation-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-relation-field__label--required.sc-mrd-relation-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-relation-field__select.sc-mrd-relation-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);outline:none;appearance:none;box-sizing:border-box}.mrd-relation-field__select.sc-mrd-relation-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-relation-field__select.sc-mrd-relation-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-relation-field__select.sc-mrd-relation-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-relation-field__select--error.sc-mrd-relation-field{border-color:var(--mrd-border-color-error)}.mrd-relation-field__select--error.sc-mrd-relation-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-relation-field__select.sc-mrd-relation-field{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right var(--mrd-space-3) center;padding-right:calc(var(--mrd-input-padding-x) + 1.5rem);cursor:pointer}.mrd-relation-field__search.sc-mrd-relation-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);outline:none;appearance:none;box-sizing:border-box}.mrd-relation-field__search.sc-mrd-relation-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-relation-field__search.sc-mrd-relation-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-relation-field__search.sc-mrd-relation-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-relation-field__search--error.sc-mrd-relation-field{border-color:var(--mrd-border-color-error)}.mrd-relation-field__search--error.sc-mrd-relation-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-relation-field__error.sc-mrd-relation-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-relation-field__tags.sc-mrd-relation-field{display:flex;flex-wrap:wrap;gap:var(--mrd-space-1);margin-bottom:var(--mrd-space-1)}.mrd-relation-field__tag.sc-mrd-relation-field{display:inline-flex;align-items:center;gap:var(--mrd-space-1);padding:var(--mrd-space-1) var(--mrd-space-2);background-color:var(--mrd-color-primary-light);color:var(--mrd-color-primary-dark);border-radius:var(--mrd-border-radius-full);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-medium)}.mrd-relation-field__tag-remove.sc-mrd-relation-field{background:none;border:none;cursor:pointer;color:var(--mrd-color-primary-dark);font-size:var(--mrd-font-size-xs);padding:0;line-height:1;opacity:0.7}.mrd-relation-field__tag-remove.sc-mrd-relation-field:hover{opacity:1}.mrd-relation-field__search-wrapper.sc-mrd-relation-field{position:relative;display:flex;align-items:center}.mrd-relation-field__spinner.sc-mrd-relation-field{position:absolute;right:var(--mrd-space-3);width:16px;height:16px;border:2px solid var(--mrd-color-neutral-200);border-top-color:var(--mrd-color-primary);border-radius:50%;animation:mrd-spin 0.7s linear infinite}.mrd-relation-field__results.sc-mrd-relation-field{position:absolute;top:calc(100% + var(--mrd-space-1));left:0;right:0;background-color:var(--mrd-color-white);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);box-shadow:var(--mrd-shadow-md);z-index:var(--mrd-z-dropdown);max-height:240px;overflow-y:auto}.mrd-relation-field__result-item.sc-mrd-relation-field{display:flex;flex-direction:column;padding:var(--mrd-space-2) var(--mrd-space-3);cursor:pointer;transition:background-color var(--mrd-transition-fast)}.mrd-relation-field__result-item.sc-mrd-relation-field:hover{background-color:var(--mrd-color-neutral-50)}.mrd-relation-field__result-item.sc-mrd-relation-field:not(:last-child){border-bottom:var(--mrd-border-width) solid var(--mrd-color-neutral-100)}.mrd-relation-field__result-item--highlighted.sc-mrd-relation-field{background-color:var(--mrd-color-primary-light)}.mrd-relation-field__result-label.sc-mrd-relation-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-color-neutral-800);font-weight:var(--mrd-font-weight-medium)}.mrd-relation-field__result-desc.sc-mrd-relation-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);margin-top:var(--mrd-space-1)}.mrd-relation-field__selected-value.sc-mrd-relation-field{display:flex;align-items:center;gap:var(--mrd-space-2);height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);background-color:var(--mrd-color-primary-light);border:var(--mrd-border-width) solid var(--mrd-color-primary);border-radius:var(--mrd-border-radius);box-sizing:border-box}.mrd-relation-field__selected-value--error.sc-mrd-relation-field{border-color:var(--mrd-border-color-error);background-color:var(--mrd-color-danger-light)}.mrd-relation-field__selected-name.sc-mrd-relation-field{flex:1;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-primary-dark);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mrd-relation-field__selected-clear.sc-mrd-relation-field{flex-shrink:0;background:none;border:none;cursor:pointer;color:var(--mrd-color-primary-dark);font-size:var(--mrd-font-size-sm);padding:0;line-height:1;opacity:0.6;transition:opacity var(--mrd-transition-fast)}.mrd-relation-field__selected-clear.sc-mrd-relation-field:hover{opacity:1}.mrd-relation-field__no-results.sc-mrd-relation-field{padding:var(--mrd-space-4);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-500);text-align:center}@keyframes mrd-spin{to{transform:rotate(360deg)}}`;
|
|
6231
|
+
MrdMemoContainer.style = mrdMemoContainerCss();
|
|
5927
6232
|
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
|
|
5934
|
-
|
|
5935
|
-
|
|
5936
|
-
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
|
|
5963
|
-
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
6233
|
+
/**
|
|
6234
|
+
* Pure sort/filter/aggregation query logic for mrd-table.
|
|
6235
|
+
* No component state — everything is passed in.
|
|
6236
|
+
*/
|
|
6237
|
+
const TEXT_TYPES = new Set(['TEXT', 'TEXTBLOCK', 'EMAIL', 'HYPERLINK']);
|
|
6238
|
+
const NUMERIC_TYPES = new Set(['INTEGER', 'DECIMAL', 'PERCENTAGE', 'CURRENCY']);
|
|
6239
|
+
const DATE_TYPES = new Set(['DATE', 'DATETIME', 'TIME']);
|
|
6240
|
+
const NO_FILTER_TYPES = new Set(['FILE', 'IMAGE']);
|
|
6241
|
+
/** Column types that cannot be sorted or filtered (not stored in PostgreSQL). */
|
|
6242
|
+
const NON_INTERACTIVE_TYPES = new Set(['LONGTEXT', 'JSON', 'FILE', 'IMAGE']);
|
|
6243
|
+
/** Wait this long (ms) after the user stops typing in the free-text search box
|
|
6244
|
+
* before firing the search request — mirrors REQUEST_DEBOUNCE_MS's purpose
|
|
6245
|
+
* (skip intermediate keystrokes) but is tuned for typing, not scrolling. */
|
|
6246
|
+
const SEARCH_DEBOUNCE_MS = 400;
|
|
6247
|
+
function parseDefaultSort(defaultSort) {
|
|
6248
|
+
var _a;
|
|
6249
|
+
if (!defaultSort)
|
|
6250
|
+
return { field: '', dir: 'asc' };
|
|
6251
|
+
const parts = defaultSort.split(',');
|
|
6252
|
+
return { field: parts[0].trim(), dir: ((_a = parts[1]) === null || _a === void 0 ? void 0 : _a.trim()) === 'desc' ? 'desc' : 'asc' };
|
|
6253
|
+
}
|
|
6254
|
+
/** Raw sort query-param value, e.g. "name" or "name,desc". */
|
|
6255
|
+
function buildSortParam(field, dir) {
|
|
6256
|
+
if (!field)
|
|
6257
|
+
return '';
|
|
6258
|
+
return dir === 'desc' ? `${field},desc` : field;
|
|
6259
|
+
}
|
|
6260
|
+
/** Query params for a page request: page + sort + filterClass + view filters + active column filters. */
|
|
6261
|
+
function buildTableQueryParams(opts) {
|
|
6262
|
+
var _a, _b;
|
|
6263
|
+
const p = new URLSearchParams();
|
|
6264
|
+
if (opts.page > 0)
|
|
6265
|
+
p.set('page', String(opts.page));
|
|
6266
|
+
if (opts.sort)
|
|
6267
|
+
p.set('sort', opts.sort);
|
|
6268
|
+
if (opts.filterClass)
|
|
6269
|
+
p.set('type', opts.filterClass);
|
|
6270
|
+
applyViewFilters(p, opts.viewFilters);
|
|
6271
|
+
if (opts.query)
|
|
6272
|
+
p.set('q', opts.query);
|
|
6273
|
+
for (const f of opts.activeFilters) {
|
|
6274
|
+
if (f.operator === 'isEmpty') {
|
|
6275
|
+
p.set(f.field, '');
|
|
6276
|
+
continue;
|
|
6277
|
+
}
|
|
6278
|
+
if (f.operator === 'isNotEmpty') {
|
|
6279
|
+
p.set(f.field + '_notempty', 'true');
|
|
6280
|
+
continue;
|
|
6281
|
+
}
|
|
6282
|
+
if (f.operator === 'startsWith') {
|
|
6283
|
+
p.set(f.field + '_startswith', String((_a = f.value) !== null && _a !== void 0 ? _a : ''));
|
|
6284
|
+
continue;
|
|
6285
|
+
}
|
|
6286
|
+
if ((_b = f.values) === null || _b === void 0 ? void 0 : _b.length) {
|
|
6287
|
+
p.set(f.field, f.values.join(','));
|
|
6288
|
+
continue;
|
|
6289
|
+
}
|
|
6290
|
+
if (f.value != null)
|
|
6291
|
+
p.set(f.field, String(f.value));
|
|
6292
|
+
if (f.from != null)
|
|
6293
|
+
p.set(f.field + '_from', String(f.from));
|
|
6294
|
+
if (f.to != null)
|
|
6295
|
+
p.set(f.field + '_to', String(f.to));
|
|
6296
|
+
}
|
|
6297
|
+
return p.toString();
|
|
6298
|
+
}
|
|
6299
|
+
/** Groups aggregate columns by function; null when the view has no aggregates. */
|
|
6300
|
+
function buildAggregationParams(columns) {
|
|
6301
|
+
var _a;
|
|
6302
|
+
const groups = { sum: [], avg: [], count: [] };
|
|
6303
|
+
for (const col of columns) {
|
|
6304
|
+
if (col.type !== 'FIELD' || !col.aggregate)
|
|
6305
|
+
continue;
|
|
6306
|
+
const fn = col.aggregate.toLowerCase();
|
|
6307
|
+
if (fn in groups)
|
|
6308
|
+
groups[fn].push((_a = col.name) !== null && _a !== void 0 ? _a : '');
|
|
6309
|
+
}
|
|
6310
|
+
const params = {};
|
|
6311
|
+
if (groups.sum.length)
|
|
6312
|
+
params.sum = groups.sum;
|
|
6313
|
+
if (groups.avg.length)
|
|
6314
|
+
params.avg = groups.avg;
|
|
6315
|
+
if (groups.count.length)
|
|
6316
|
+
params.count = groups.count;
|
|
6317
|
+
return Object.keys(params).length > 0 ? params : null;
|
|
6318
|
+
}
|
|
6319
|
+
/** Aggregation query string: the page-0 query params without page/sort, plus sum/avg/count. */
|
|
6320
|
+
function buildAggregationQs(basePageQs, columns) {
|
|
6321
|
+
var _a, _b, _c;
|
|
6322
|
+
const p = new URLSearchParams(basePageQs);
|
|
6323
|
+
p.delete('page');
|
|
6324
|
+
p.delete('sort');
|
|
6325
|
+
const groups = buildAggregationParams(columns);
|
|
6326
|
+
if ((_a = groups === null || groups === void 0 ? void 0 : groups.sum) === null || _a === void 0 ? void 0 : _a.length)
|
|
6327
|
+
p.set('sum', groups.sum.join(','));
|
|
6328
|
+
if ((_b = groups === null || groups === void 0 ? void 0 : groups.avg) === null || _b === void 0 ? void 0 : _b.length)
|
|
6329
|
+
p.set('avg', groups.avg.join(','));
|
|
6330
|
+
if ((_c = groups === null || groups === void 0 ? void 0 : groups.count) === null || _c === void 0 ? void 0 : _c.length)
|
|
6331
|
+
p.set('count', groups.count.join(','));
|
|
6332
|
+
return p.toString();
|
|
6333
|
+
}
|
|
6334
|
+
/** True when the pending filter actually constrains anything. */
|
|
6335
|
+
function filterHasValue(f) {
|
|
6336
|
+
if (f.operator === 'isEmpty' || f.operator === 'isNotEmpty')
|
|
6337
|
+
return true;
|
|
6338
|
+
if (f.values !== undefined && f.values.length > 0)
|
|
6339
|
+
return true;
|
|
6340
|
+
if (f.value != null && f.value !== '')
|
|
6341
|
+
return true;
|
|
6342
|
+
if (typeof f.value === 'boolean')
|
|
6343
|
+
return true;
|
|
6344
|
+
if (f.from != null && f.from !== '')
|
|
6345
|
+
return true;
|
|
6346
|
+
if (f.to != null && f.to !== '')
|
|
6347
|
+
return true;
|
|
6348
|
+
return false;
|
|
6349
|
+
}
|
|
6350
|
+
// ── DATETIME filters: the user edits local "YYYY-MM-DD" dates, the API stores UTC ISO ──
|
|
6351
|
+
/** UTC ISO string at the start (midnight) of the given local day. */
|
|
6352
|
+
function dateLocalToUTCStart(dateStr) {
|
|
6353
|
+
if (!dateStr)
|
|
6354
|
+
return dateStr;
|
|
6355
|
+
const [year, month, day] = dateStr.split('-').map(Number);
|
|
6356
|
+
return new Date(year, month - 1, day).toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
6357
|
+
}
|
|
6358
|
+
/** Start of the day AFTER the given local date (exclusive range end). */
|
|
6359
|
+
function dateLocalToUTCEndExclusive(dateStr) {
|
|
6360
|
+
if (!dateStr)
|
|
6361
|
+
return dateStr;
|
|
6362
|
+
const [year, month, day] = dateStr.split('-').map(Number);
|
|
6363
|
+
return new Date(year, month - 1, day + 1).toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
6364
|
+
}
|
|
6365
|
+
/** Stored UTC ISO string back to the local "YYYY-MM-DD" date. */
|
|
6366
|
+
function utcISOToLocalDate(utcStr) {
|
|
6367
|
+
if (!utcStr)
|
|
6368
|
+
return utcStr;
|
|
6369
|
+
const d = new Date(utcStr);
|
|
6370
|
+
if (isNaN(d.getTime()))
|
|
6371
|
+
return utcStr;
|
|
6372
|
+
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
|
6373
|
+
}
|
|
6374
|
+
/** The stored "to" is the exclusive end (next midnight); subtract a day to recover the entered date. */
|
|
6375
|
+
function utcISOToLocalDateExclusiveEnd(utcStr) {
|
|
6376
|
+
if (!utcStr)
|
|
6377
|
+
return utcStr;
|
|
6378
|
+
const d = new Date(utcStr);
|
|
6379
|
+
if (isNaN(d.getTime()))
|
|
6380
|
+
return utcStr;
|
|
6381
|
+
d.setDate(d.getDate() - 1);
|
|
6382
|
+
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
|
6383
|
+
}
|
|
6384
|
+
/** Applies the local→UTC conversion when a DATETIME filter is submitted.
|
|
6385
|
+
* Exact date → range covering the full local day. */
|
|
6386
|
+
function normalizeDatetimeFilter(f) {
|
|
6387
|
+
const normalized = Object.assign({}, f);
|
|
6388
|
+
if (f.dataType === 'DATETIME' && f.operator !== 'isEmpty' && f.operator !== 'isNotEmpty') {
|
|
6389
|
+
if (typeof normalized.value === 'string' && normalized.value) {
|
|
6390
|
+
normalized.from = dateLocalToUTCStart(normalized.value);
|
|
6391
|
+
normalized.to = dateLocalToUTCEndExclusive(normalized.value);
|
|
6392
|
+
normalized.value = undefined;
|
|
6393
|
+
}
|
|
6394
|
+
else {
|
|
6395
|
+
if (typeof normalized.from === 'string' && normalized.from)
|
|
6396
|
+
normalized.from = dateLocalToUTCStart(normalized.from);
|
|
6397
|
+
if (typeof normalized.to === 'string' && normalized.to)
|
|
6398
|
+
normalized.to = dateLocalToUTCEndExclusive(normalized.to);
|
|
6399
|
+
}
|
|
6400
|
+
}
|
|
6401
|
+
return normalized;
|
|
6402
|
+
}
|
|
6403
|
+
/** Converts a stored DATETIME filter back to local dates for the popup.
|
|
6404
|
+
* A range covering a single local day is restored to exact-date mode. */
|
|
6405
|
+
function datetimeFilterToDisplay(existing) {
|
|
6406
|
+
const display = Object.assign({}, existing);
|
|
6407
|
+
if (typeof display.from === 'string' && display.from)
|
|
6408
|
+
display.from = utcISOToLocalDate(display.from);
|
|
6409
|
+
if (typeof display.to === 'string' && display.to)
|
|
6410
|
+
display.to = utcISOToLocalDateExclusiveEnd(display.to);
|
|
6411
|
+
if (display.from && display.to && display.from === display.to) {
|
|
6412
|
+
return Object.assign(Object.assign({}, display), { value: display.from, from: undefined, to: undefined });
|
|
6413
|
+
}
|
|
6414
|
+
return display;
|
|
6415
|
+
}
|
|
6416
|
+
|
|
6417
|
+
const mrdMemoListCss = () => `@charset "UTF-8";.sc-mrd-memo-list-h{display:block}.mrd-memo-list.sc-mrd-memo-list{display:flex;flex-direction:column;gap:var(--mrd-space-3)}.mrd-memo-list__card.sc-mrd-memo-list{display:flex;flex-direction:column;gap:var(--mrd-space-2);width:100%;padding:var(--mrd-space-4);background:var(--mrd-color-white);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);font-family:var(--mrd-font-family);text-align:left;cursor:pointer;transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition)}.mrd-memo-list__card.sc-mrd-memo-list:hover{border-color:var(--mrd-color-primary);box-shadow:var(--mrd-shadow-sm, 0 1px 2px rgba(0, 0, 0, 0.06))}.mrd-memo-list__card.sc-mrd-memo-list:focus-visible{outline:none;box-shadow:var(--mrd-shadow-focus)}.mrd-memo-list__card--readonly.sc-mrd-memo-list{cursor:default}.mrd-memo-list__card--readonly.sc-mrd-memo-list:hover{border-color:var(--mrd-border-color);box-shadow:none}.mrd-memo-list__card-header.sc-mrd-memo-list{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--mrd-space-2)}.mrd-memo-list__card-title.sc-mrd-memo-list{font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-900)}.mrd-memo-list__card-important.sc-mrd-memo-list{display:inline-flex;flex-shrink:0;color:var(--mrd-color-warning)}.mrd-memo-list__card-important.sc-mrd-memo-list svg.sc-mrd-memo-list{width:1rem;height:1rem}.mrd-memo-list__card-body-wrap.sc-mrd-memo-list{display:flex;flex-direction:column;align-items:flex-start;gap:var(--mrd-space-1)}.mrd-memo-list__card-body.sc-mrd-memo-list{margin:0;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-600);line-height:var(--mrd-line-height-relaxed);word-break:break-word}.mrd-memo-list__card-body.sc-mrd-memo-list p.sc-mrd-memo-list,.mrd-memo-list__card-body.sc-mrd-memo-list ul.sc-mrd-memo-list,.mrd-memo-list__card-body.sc-mrd-memo-list ol.sc-mrd-memo-list{margin:0 0 var(--mrd-space-1) 0}.mrd-memo-list__card-body--clamped.sc-mrd-memo-list{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.mrd-memo-list__card-toggle.sc-mrd-memo-list{background:none;border:none;padding:0;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-primary);cursor:pointer}.mrd-memo-list__card-toggle.sc-mrd-memo-list:hover{text-decoration:underline}.mrd-memo-list__labels.sc-mrd-memo-list{display:flex;flex-wrap:wrap;gap:var(--mrd-space-2)}.mrd-memo-list__badge.sc-mrd-memo-list{display:inline-flex;align-items:center;height:1.25rem;padding:0 var(--mrd-space-2);border-radius:var(--mrd-border-radius-full, 999px);font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-medium)}.mrd-memo-list__badge--plain.sc-mrd-memo-list{background:var(--mrd-color-neutral-100);color:var(--mrd-color-neutral-600)}.mrd-memo-list__card-meta.sc-mrd-memo-list{display:flex;align-items:center;gap:var(--mrd-space-2);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-400)}.mrd-memo-list__card-author.sc-mrd-memo-list+.mrd-memo-list__card-date.sc-mrd-memo-list::before{content:"·";margin-right:var(--mrd-space-2)}.mrd-memo-list__empty.sc-mrd-memo-list{padding:var(--mrd-space-6);text-align:center;color:var(--mrd-color-neutral-400);font-size:var(--mrd-font-size-sm)}.mrd-memo-list__load-more.sc-mrd-memo-list{align-self:center;height:var(--mrd-input-height);padding:0 var(--mrd-space-6);background:transparent;color:var(--mrd-color-neutral-600);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-medium);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);cursor:pointer;transition:background-color var(--mrd-transition)}.mrd-memo-list__load-more.sc-mrd-memo-list:hover:not(:disabled){background-color:var(--mrd-color-neutral-100)}.mrd-memo-list__load-more.sc-mrd-memo-list:disabled{opacity:0.6;cursor:default}`;
|
|
6418
|
+
|
|
6419
|
+
/** Plain-text length above which a card's body is clamped with a show-more toggle. */
|
|
6420
|
+
const BODY_PREVIEW_THRESHOLD = 220;
|
|
6421
|
+
const MrdMemoList = class {
|
|
6422
|
+
constructor(hostRef) {
|
|
6423
|
+
index.registerInstance(this, hostRef);
|
|
6424
|
+
this.mrdLoadPage = index.createEvent(this, "mrdLoadPage");
|
|
6425
|
+
this.mrdEdit = index.createEvent(this, "mrdEdit");
|
|
6426
|
+
/** The VIEW or RELATED_VIEW layout item (dataClass, fromClass, view config). */
|
|
6427
|
+
this.item = null;
|
|
6428
|
+
/** Parent record id — required for RELATED_VIEW path building. */
|
|
6429
|
+
this.parentId = '';
|
|
6430
|
+
/** Records per page (must match API page size). */
|
|
6431
|
+
this.pageSize = 20;
|
|
6432
|
+
this.locale = navigator.language;
|
|
6433
|
+
/** When true, cards are not clickable (no mrdEdit) — matches mrd-table's own
|
|
6434
|
+
* readOnly gating on its create action. */
|
|
6435
|
+
this.readOnly = false;
|
|
6436
|
+
/** listItems of the FIELD bound to the `labels` slot, resolved by mrd-layout-section
|
|
6437
|
+
* from its own items array, same reason mrd-memo-view needs it. */
|
|
6438
|
+
this.labelsListItems = null;
|
|
6439
|
+
this.rows = [];
|
|
6440
|
+
this.loading = false;
|
|
6441
|
+
this.exhausted = false;
|
|
6442
|
+
this.started = false;
|
|
6443
|
+
this.expandedHrefs = new Set();
|
|
6444
|
+
this.nextPage = 0;
|
|
6445
|
+
this.loadMore = () => {
|
|
6446
|
+
if (this.loading || this.exhausted)
|
|
6447
|
+
return;
|
|
6448
|
+
this.emitLoadPage(this.nextPage);
|
|
6449
|
+
};
|
|
6450
|
+
this.toggleExpanded = (e, href) => {
|
|
6451
|
+
e.stopPropagation();
|
|
6452
|
+
const next = new Set(this.expandedHrefs);
|
|
6453
|
+
if (next.has(href))
|
|
6454
|
+
next.delete(href);
|
|
6455
|
+
else
|
|
6456
|
+
next.add(href);
|
|
6457
|
+
this.expandedHrefs = next;
|
|
6458
|
+
};
|
|
6459
|
+
}
|
|
6460
|
+
buildDataPath() {
|
|
6461
|
+
var _a, _b, _c, _d, _e;
|
|
6462
|
+
return buildListPath({
|
|
6463
|
+
isRelatedView: ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW',
|
|
6464
|
+
fromClass: (_b = this.item) === null || _b === void 0 ? void 0 : _b.fromClass,
|
|
6465
|
+
parentId: this.parentId,
|
|
6466
|
+
dataClass: (_d = (_c = this.item) === null || _c === void 0 ? void 0 : _c.dataClass) !== null && _d !== void 0 ? _d : (_e = this.item) === null || _e === void 0 ? void 0 : _e.relatedClass,
|
|
6467
|
+
});
|
|
6468
|
+
}
|
|
6469
|
+
sortParam() {
|
|
6470
|
+
var _a, _b, _c;
|
|
6471
|
+
const { field, dir } = parseDefaultSort((_c = (_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.view) === null || _b === void 0 ? void 0 : _b.defaultSort) !== null && _c !== void 0 ? _c : '');
|
|
6472
|
+
return buildSortParam(field, dir);
|
|
6473
|
+
}
|
|
6474
|
+
emitLoadPage(page) {
|
|
6475
|
+
var _a, _b, _c;
|
|
6476
|
+
this.loading = true;
|
|
6477
|
+
this.mrdLoadPage.emit({
|
|
6478
|
+
page,
|
|
6479
|
+
sort: this.sortParam(),
|
|
6480
|
+
path: this.buildDataPath(),
|
|
6481
|
+
qs: buildTableQueryParams({
|
|
6482
|
+
page,
|
|
6483
|
+
sort: this.sortParam(),
|
|
6484
|
+
filterClass: (_a = this.item) === null || _a === void 0 ? void 0 : _a.filterClass,
|
|
6485
|
+
viewFilters: (_c = (_b = this.item) === null || _b === void 0 ? void 0 : _b.view) === null || _c === void 0 ? void 0 : _c.filter,
|
|
6486
|
+
activeFilters: [],
|
|
6487
|
+
}),
|
|
6488
|
+
});
|
|
6489
|
+
}
|
|
6490
|
+
/** Reset and request page 0. Call after setting all props, mirrors mrd-table.init(). */
|
|
6491
|
+
async init() {
|
|
6492
|
+
this.rows = [];
|
|
6493
|
+
this.loading = false;
|
|
6494
|
+
this.exhausted = false;
|
|
6495
|
+
this.started = true;
|
|
6496
|
+
this.nextPage = 0;
|
|
6497
|
+
this.emitLoadPage(0);
|
|
6498
|
+
}
|
|
6499
|
+
/** Inject the rows for a page (0-based); page 0 replaces, later pages append. */
|
|
6500
|
+
async setPage(pageNumber, rows, hasNext) {
|
|
6501
|
+
this.loading = false;
|
|
6502
|
+
this.rows = pageNumber === 0 ? rows : [...this.rows, ...rows];
|
|
6503
|
+
this.nextPage = pageNumber + 1;
|
|
6504
|
+
this.exhausted = hasNext !== undefined ? !hasNext : rows.length < this.pageSize;
|
|
6505
|
+
}
|
|
6506
|
+
/** Optimistically merge an edit into the matching row — mrdUpdateObject's PATCH
|
|
6507
|
+
* is fire-and-forget on the host side, so this is what makes an edit visible
|
|
6508
|
+
* immediately rather than only after the next full reload. */
|
|
6509
|
+
async patchRow(href, values) {
|
|
6510
|
+
this.rows = this.rows.map(row => { var _a, _b; return ((_b = (_a = row === null || row === void 0 ? void 0 : row._links) === null || _a === void 0 ? void 0 : _a.self) === null || _b === void 0 ? void 0 : _b.href) === href ? Object.assign(Object.assign({}, row), values) : row; });
|
|
6511
|
+
}
|
|
6512
|
+
/** Optimistically drop a deleted row — mrdDeleteObject's DELETE is fire-and-
|
|
6513
|
+
* forget on the host side, same reasoning as patchRow(). */
|
|
6514
|
+
async removeRow(href) {
|
|
6515
|
+
this.rows = this.rows.filter(row => { var _a, _b; return ((_b = (_a = row === null || row === void 0 ? void 0 : row._links) === null || _a === void 0 ? void 0 : _a.self) === null || _b === void 0 ? void 0 : _b.href) !== href; });
|
|
6516
|
+
}
|
|
6517
|
+
/** Value of a value-slot: reads row[field] via the slot→field map. */
|
|
6518
|
+
slotValue(row, slot) {
|
|
6519
|
+
var _a, _b;
|
|
6520
|
+
const field = (_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) === null || _b === void 0 ? void 0 : _b[slot];
|
|
6521
|
+
if (!field)
|
|
6522
|
+
return undefined;
|
|
6523
|
+
return row[field];
|
|
6524
|
+
}
|
|
6525
|
+
/** Relation link for a relation-slot: reads row._links[field]. */
|
|
6526
|
+
slotLink(row, slot) {
|
|
6527
|
+
var _a, _b, _c;
|
|
6528
|
+
const field = (_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) === null || _b === void 0 ? void 0 : _b[slot];
|
|
6529
|
+
if (!field)
|
|
6530
|
+
return undefined;
|
|
6531
|
+
const links = ((_c = row === null || row === void 0 ? void 0 : row._links) !== null && _c !== void 0 ? _c : {});
|
|
6532
|
+
return links[field];
|
|
6533
|
+
}
|
|
6534
|
+
plainTextLength(row) {
|
|
6535
|
+
const raw = this.slotValue(row, 'body');
|
|
6536
|
+
if (raw == null || raw === '')
|
|
6537
|
+
return 0;
|
|
6538
|
+
return String(raw).replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim().length;
|
|
6539
|
+
}
|
|
6540
|
+
renderLabels(row) {
|
|
6541
|
+
const raw = this.slotValue(row, 'labels');
|
|
6542
|
+
const keys = Array.isArray(raw) ? raw.map(String) : (raw != null && raw !== '' ? [String(raw)] : []);
|
|
6543
|
+
if (!keys.length)
|
|
6544
|
+
return null;
|
|
6545
|
+
return (index.h("div", { class: "mrd-memo-list__labels" }, keys.map(key => {
|
|
6546
|
+
var _a, _b;
|
|
6547
|
+
const listItem = ((_a = this.labelsListItems) !== null && _a !== void 0 ? _a : []).find(li => li.key === key);
|
|
6548
|
+
const label = (_b = listItem === null || listItem === void 0 ? void 0 : listItem.label) !== null && _b !== void 0 ? _b : key;
|
|
6549
|
+
if ((listItem === null || listItem === void 0 ? void 0 : listItem.color) && (listItem === null || listItem === void 0 ? void 0 : listItem.backgroundColor)) {
|
|
6550
|
+
return (index.h("span", { key: key, class: "mrd-memo-list__badge", style: { color: listItem.color, backgroundColor: listItem.backgroundColor } }, label));
|
|
6551
|
+
}
|
|
6552
|
+
return index.h("span", { key: key, class: "mrd-memo-list__badge mrd-memo-list__badge--plain" }, label);
|
|
6553
|
+
})));
|
|
6554
|
+
}
|
|
6555
|
+
renderBody(row, href) {
|
|
6556
|
+
const raw = this.slotValue(row, 'body');
|
|
6557
|
+
if (raw == null || raw === '')
|
|
6558
|
+
return null;
|
|
6559
|
+
const expanded = this.expandedHrefs.has(href);
|
|
6560
|
+
const needsToggle = this.plainTextLength(row) > BODY_PREVIEW_THRESHOLD;
|
|
6561
|
+
return (index.h("div", { class: "mrd-memo-list__card-body-wrap" }, index.h("div", { class: {
|
|
6562
|
+
'mrd-memo-list__card-body': true,
|
|
6563
|
+
'mrd-memo-list__card-body--clamped': needsToggle && !expanded,
|
|
6564
|
+
}, innerHTML: purify.sanitize(String(raw)) }), needsToggle && (index.h("button", { type: "button", class: "mrd-memo-list__card-toggle", onClick: e => this.toggleExpanded(e, href) }, cellRenderer.t(expanded ? 'textblock_show_less' : 'textblock_show_more', this.locale)))));
|
|
6565
|
+
}
|
|
6566
|
+
renderCard(row, index$1) {
|
|
6567
|
+
var _a, _b, _c;
|
|
6568
|
+
const titleRaw = this.slotValue(row, 'title');
|
|
6569
|
+
const title = titleRaw != null && titleRaw !== '' ? String(titleRaw) : null;
|
|
6570
|
+
const dateRaw = this.slotValue(row, 'date');
|
|
6571
|
+
const author = this.slotLink(row, 'author');
|
|
6572
|
+
const important = !!this.slotValue(row, 'important');
|
|
6573
|
+
const href = (_c = (_b = (_a = row === null || row === void 0 ? void 0 : row._links) === null || _a === void 0 ? void 0 : _a.self) === null || _b === void 0 ? void 0 : _b.href) !== null && _c !== void 0 ? _c : '';
|
|
6574
|
+
return (index.h("div", { key: href || index$1, class: { 'mrd-memo-list__card': true, 'mrd-memo-list__card--readonly': this.readOnly }, role: this.readOnly ? undefined : 'button', tabIndex: this.readOnly ? undefined : 0, onClick: () => {
|
|
6575
|
+
if (!this.readOnly)
|
|
6576
|
+
this.mrdEdit.emit({ row });
|
|
6577
|
+
}, onKeyDown: e => {
|
|
6578
|
+
if (this.readOnly)
|
|
6579
|
+
return;
|
|
6580
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
6581
|
+
e.preventDefault();
|
|
6582
|
+
this.mrdEdit.emit({ row });
|
|
6583
|
+
}
|
|
6584
|
+
} }, index.h("div", { class: "mrd-memo-list__card-header" }, title && index.h("span", { class: "mrd-memo-list__card-title" }, title), important && (index.h("span", { class: "mrd-memo-list__card-important", title: cellRenderer.t('memo_important', this.locale) }, index.h("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true" }, index.h("path", { d: "M12 2l2.9 6.26L22 9.27l-5 4.87L18.18 21 12 17.27 5.82 21 7 14.14l-5-4.87 7.1-1.01z" }))))), this.renderBody(row, href), this.renderLabels(row), index.h("div", { class: "mrd-memo-list__card-meta" }, (author === null || author === void 0 ? void 0 : author.name) && index.h("span", { class: "mrd-memo-list__card-author" }, author.name), dateRaw != null && dateRaw !== '' && (index.h("span", { class: "mrd-memo-list__card-date" }, cellRenderer.formatDateTime(dateRaw, this.locale))))));
|
|
6585
|
+
}
|
|
6586
|
+
render() {
|
|
6587
|
+
return (index.h(index.Host, { key: 'c4c5ce4e96bf2aa754d85b260db8920fdde9311d' }, index.h("div", { key: '0db49511231edbf946f98734e0bab91cbdf31795', class: "mrd-memo-list" }, this.rows.map((row, i) => this.renderCard(row, i)), this.started && !this.loading && this.rows.length === 0 && (index.h("div", { key: '2a7a027673d01d63523ce252fe2fbff8ba0515fd', class: "mrd-memo-list__empty" }, cellRenderer.t('no_results', this.locale))), !this.exhausted && this.rows.length > 0 && (index.h("button", { key: '45dfd4a9ccab721d422935c48509d46989c9a360', type: "button", class: "mrd-memo-list__load-more", disabled: this.loading, onClick: this.loadMore }, cellRenderer.t('load_more', this.locale))))));
|
|
6588
|
+
}
|
|
6589
|
+
};
|
|
6590
|
+
MrdMemoList.style = mrdMemoListCss();
|
|
6591
|
+
|
|
6592
|
+
const mrdMemoViewCss = () => `@charset "UTF-8";.sc-mrd-memo-view-h{display:block}.mrd-memo-view.sc-mrd-memo-view{max-width:720px;display:flex;flex-direction:column;gap:var(--mrd-space-3)}.mrd-memo-view__header.sc-mrd-memo-view{display:flex;align-items:baseline;flex-wrap:wrap;gap:var(--mrd-space-3)}.mrd-memo-view__title.sc-mrd-memo-view{font-size:var(--mrd-font-size-2xl);font-weight:var(--mrd-font-weight-bold);color:var(--mrd-color-neutral-900);letter-spacing:-0.02em;margin:0}.mrd-memo-view__important.sc-mrd-memo-view{display:inline-flex;align-items:center;gap:var(--mrd-space-1);font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-warning);text-transform:uppercase;letter-spacing:0.04em}.mrd-memo-view__important.sc-mrd-memo-view svg.sc-mrd-memo-view{width:0.875rem;height:0.875rem}.mrd-memo-view__meta.sc-mrd-memo-view{display:flex;align-items:center;gap:var(--mrd-space-2);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-400)}.mrd-memo-view__meta-author.sc-mrd-memo-view{background:none;border:none;padding:0;font-family:var(--mrd-font-family);font-size:inherit;font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-500);cursor:pointer}.mrd-memo-view__meta-author.sc-mrd-memo-view:hover{color:var(--mrd-color-primary);text-decoration:underline}.mrd-memo-view__meta-date.sc-mrd-memo-view::before{content:"·";margin-right:var(--mrd-space-2)}.mrd-memo-view__meta-author.sc-mrd-memo-view+.mrd-memo-view__meta-date.sc-mrd-memo-view::before{content:"·"}.mrd-memo-view__labels.sc-mrd-memo-view{display:flex;flex-wrap:wrap;gap:var(--mrd-space-2)}.mrd-memo-view__badge.sc-mrd-memo-view{display:inline-flex;align-items:center;height:1.375rem;padding:0 var(--mrd-space-2);border-radius:var(--mrd-border-radius-full, 999px);font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-medium)}.mrd-memo-view__badge--plain.sc-mrd-memo-view{background:var(--mrd-color-neutral-100);color:var(--mrd-color-neutral-600)}.mrd-memo-view__container-link.sc-mrd-memo-view{align-self:flex-start;background:none;border:none;padding:0;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-primary);cursor:pointer}.mrd-memo-view__container-link.sc-mrd-memo-view:hover{text-decoration:underline}.mrd-memo-view__divider.sc-mrd-memo-view{height:var(--mrd-border-width);background:var(--mrd-color-neutral-200)}.mrd-memo-view__body.sc-mrd-memo-view{font-size:var(--mrd-font-size-base);color:var(--mrd-color-neutral-800);line-height:var(--mrd-line-height-relaxed);word-break:break-word}`;
|
|
6593
|
+
|
|
6594
|
+
const MrdMemoView = class {
|
|
6595
|
+
constructor(hostRef) {
|
|
6596
|
+
index.registerInstance(this, hostRef);
|
|
6597
|
+
this.mrdNavigate = index.createEvent(this, "mrdNavigate");
|
|
6598
|
+
/** The data record from the /data endpoint. Fields keyed by name; relations under `_links`. */
|
|
6599
|
+
this.data = {};
|
|
6600
|
+
this.locale = navigator.language;
|
|
6601
|
+
/** listItems of the FIELD bound to the `labels` slot, resolved by mrd-layout-section
|
|
6602
|
+
* from its own items array (archetype metadata does not publish listItems), so the
|
|
6603
|
+
* label badges get a real label/color instead of the raw stored key. */
|
|
6604
|
+
this.labelsListItems = null;
|
|
6605
|
+
}
|
|
6606
|
+
/** Value of a value-slot: reads data[field] via the slot→field map. */
|
|
6607
|
+
slotValue(slot) {
|
|
6608
|
+
var _a, _b;
|
|
6609
|
+
const field = (_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) === null || _b === void 0 ? void 0 : _b[slot];
|
|
6610
|
+
if (!field)
|
|
6611
|
+
return undefined;
|
|
6612
|
+
return this.data[field];
|
|
6613
|
+
}
|
|
6614
|
+
/** Relation link for a relation-slot: reads data._links[field]. */
|
|
6615
|
+
slotLink(slot) {
|
|
6616
|
+
var _a, _b, _c, _d;
|
|
6617
|
+
const field = (_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) === null || _b === void 0 ? void 0 : _b[slot];
|
|
6618
|
+
if (!field)
|
|
6619
|
+
return undefined;
|
|
6620
|
+
const links = ((_d = (_c = this.data) === null || _c === void 0 ? void 0 : _c._links) !== null && _d !== void 0 ? _d : {});
|
|
6621
|
+
return links[field];
|
|
6622
|
+
}
|
|
6623
|
+
renderAuthor() {
|
|
6624
|
+
const link = this.slotLink('author');
|
|
6625
|
+
if (!(link === null || link === void 0 ? void 0 : link.href) || !link.name)
|
|
6626
|
+
return null;
|
|
6627
|
+
return (index.h("button", { type: "button", class: "mrd-memo-view__meta-author", onClick: () => this.mrdNavigate.emit({ href: link.href, label: link.name }) }, link.name));
|
|
6628
|
+
}
|
|
6629
|
+
renderContainer() {
|
|
6630
|
+
const link = this.slotLink('container');
|
|
6631
|
+
if (!(link === null || link === void 0 ? void 0 : link.href) || !link.name)
|
|
6632
|
+
return null;
|
|
6633
|
+
return (index.h("button", { type: "button", class: "mrd-memo-view__container-link", onClick: () => this.mrdNavigate.emit({ href: link.href, label: link.name }) }, link.name));
|
|
6634
|
+
}
|
|
6635
|
+
renderLabels() {
|
|
6636
|
+
const raw = this.slotValue('labels');
|
|
6637
|
+
const keys = Array.isArray(raw) ? raw.map(String) : (raw != null && raw !== '' ? [String(raw)] : []);
|
|
6638
|
+
if (!keys.length)
|
|
6639
|
+
return null;
|
|
6640
|
+
return (index.h("div", { class: "mrd-memo-view__labels" }, keys.map(key => {
|
|
6641
|
+
var _a, _b;
|
|
6642
|
+
const listItem = ((_a = this.labelsListItems) !== null && _a !== void 0 ? _a : []).find(li => li.key === key);
|
|
6643
|
+
const label = (_b = listItem === null || listItem === void 0 ? void 0 : listItem.label) !== null && _b !== void 0 ? _b : key;
|
|
6644
|
+
if ((listItem === null || listItem === void 0 ? void 0 : listItem.color) && (listItem === null || listItem === void 0 ? void 0 : listItem.backgroundColor)) {
|
|
6645
|
+
return (index.h("span", { key: key, class: "mrd-memo-view__badge", style: { color: listItem.color, backgroundColor: listItem.backgroundColor } }, label));
|
|
6646
|
+
}
|
|
6647
|
+
return index.h("span", { key: key, class: "mrd-memo-view__badge mrd-memo-view__badge--plain" }, label);
|
|
6648
|
+
})));
|
|
6649
|
+
}
|
|
6650
|
+
renderBody() {
|
|
6651
|
+
const bodyRaw = this.slotValue('body');
|
|
6652
|
+
if (bodyRaw == null || bodyRaw === '')
|
|
6653
|
+
return null;
|
|
6654
|
+
return index.h("div", { class: "mrd-memo-view__body", innerHTML: purify.sanitize(String(bodyRaw)) });
|
|
6655
|
+
}
|
|
6656
|
+
render() {
|
|
6657
|
+
const titleRaw = this.slotValue('title');
|
|
6658
|
+
const title = titleRaw != null && titleRaw !== '' ? String(titleRaw) : null;
|
|
6659
|
+
const dateRaw = this.slotValue('date');
|
|
6660
|
+
const important = !!this.slotValue('important');
|
|
6661
|
+
return (index.h(index.Host, { key: '4d8ed14c54449fbcfddc94a34dcfb220338f8bba' }, index.h("div", { key: '0e0456277715607580e5373ada10706db1067c7d', class: "mrd-memo-view" }, index.h("div", { key: 'd5c548617eca9a99eb34409b2082be025cfce2f4', class: "mrd-memo-view__header" }, title && index.h("h1", { key: '2ecd2eae3f8fdba310679515aa2fe76e02f0c2b2', class: "mrd-memo-view__title" }, title), important && (index.h("span", { key: 'e5e8284310ab6040f1677bc1241d04d65784c2da', class: "mrd-memo-view__important", title: cellRenderer.t('memo_important', this.locale) }, index.h("svg", { key: 'babe987244b384330533721276b5392c9fe72c5a', viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true" }, index.h("path", { key: '511956710ae8e440328f9e477551ba1c2d478f1a', d: "M12 2l2.9 6.26L22 9.27l-5 4.87L18.18 21 12 17.27 5.82 21 7 14.14l-5-4.87 7.1-1.01z" })), cellRenderer.t('memo_important', this.locale)))), index.h("div", { key: '41c25e5376d94078debaf62121b8bdf400511d16', class: "mrd-memo-view__meta" }, this.renderAuthor(), dateRaw != null && dateRaw !== '' && (index.h("span", { key: 'caff8047249745ca98da77b374438e58d150ad7f', class: "mrd-memo-view__meta-date" }, cellRenderer.formatDateTime(dateRaw, this.locale)))), this.renderLabels(), this.renderContainer(), index.h("div", { key: 'bfa4c55458ea19fb920338df9478006b1883e606', class: "mrd-memo-view__divider" }), this.renderBody())));
|
|
6662
|
+
}
|
|
6663
|
+
};
|
|
6664
|
+
MrdMemoView.style = mrdMemoViewCss();
|
|
6665
|
+
|
|
6666
|
+
const mrdNumberFieldCss = () => `.sc-mrd-number-field-h{display:block}.mrd-number-field.sc-mrd-number-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-number-field__label.sc-mrd-number-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-number-field__label--required.sc-mrd-number-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-number-field__input-wrapper.sc-mrd-number-field{position:relative;display:flex;align-items:center}.mrd-number-field__input.sc-mrd-number-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);outline:none;appearance:none;box-sizing:border-box}.mrd-number-field__input.sc-mrd-number-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-number-field__input.sc-mrd-number-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-number-field__input.sc-mrd-number-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-number-field__input--error.sc-mrd-number-field{border-color:var(--mrd-border-color-error)}.mrd-number-field__input--error.sc-mrd-number-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-number-field__input.sc-mrd-number-field{text-align:right}.mrd-number-field__input.sc-mrd-number-field::placeholder{text-align:left}.mrd-number-field__error.sc-mrd-number-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
|
|
6667
|
+
|
|
6668
|
+
const MrdNumberField = class {
|
|
6669
|
+
constructor(hostRef) {
|
|
6670
|
+
index.registerInstance(this, hostRef);
|
|
6671
|
+
this.mrdChange = index.createEvent(this, "mrdChange");
|
|
6672
|
+
this.mrdBlur = index.createEvent(this, "mrdBlur");
|
|
6673
|
+
this.name = '';
|
|
6674
|
+
this.label = '';
|
|
6675
|
+
this.value = null;
|
|
6676
|
+
this.placeholder = '';
|
|
6677
|
+
this.required = false;
|
|
6678
|
+
this.disabled = false;
|
|
6679
|
+
this.locale = navigator.language;
|
|
6680
|
+
this.dataType = clientLayout.ClientLayoutItemFieldDataType.INTEGER;
|
|
6681
|
+
this.decimalPrecision = 2;
|
|
6682
|
+
this.displayValue = '';
|
|
6683
|
+
this.error = '';
|
|
6684
|
+
/** While focused the user owns the text; prop updates must not overwrite it. */
|
|
6685
|
+
this.focused = false;
|
|
6686
|
+
this.handleInput = (e) => {
|
|
6687
|
+
this.displayValue = e.target.value;
|
|
6688
|
+
};
|
|
6689
|
+
this.handleBlur = (e) => {
|
|
6690
|
+
this.focused = false;
|
|
6691
|
+
const raw = e.target.value;
|
|
6692
|
+
const parsed = cellRenderer.parseLocalizedNumber(raw, this.locale);
|
|
6693
|
+
if (this.required && (parsed === null || raw === '')) {
|
|
6694
|
+
this.error = cellRenderer.t('required', this.locale);
|
|
6695
|
+
}
|
|
6696
|
+
else if (raw !== '' && !validateNumber(parsed, this.dataType)) {
|
|
6697
|
+
this.error = cellRenderer.t('invalid_number', this.locale);
|
|
6698
|
+
}
|
|
6699
|
+
else {
|
|
6700
|
+
this.error = '';
|
|
6701
|
+
}
|
|
6702
|
+
if (parsed !== null && validateRequired(raw)) {
|
|
6703
|
+
this.displayValue = this.formatForDisplay(parsed);
|
|
6704
|
+
}
|
|
6705
|
+
this.mrdChange.emit({ name: this.name, value: parsed });
|
|
6706
|
+
this.mrdBlur.emit({ name: this.name, value: parsed });
|
|
6707
|
+
};
|
|
6708
|
+
this.handleFocus = () => {
|
|
6709
|
+
this.focused = true;
|
|
6710
|
+
// Drop the grouping separators while editing, but keep the locale's decimal
|
|
6711
|
+
// separator: String(1234.56) would be re-read as 123456 where '.' groups.
|
|
6712
|
+
const parsed = cellRenderer.parseLocalizedNumber(this.displayValue, this.locale);
|
|
6713
|
+
if (parsed !== null) {
|
|
6714
|
+
this.displayValue = cellRenderer.formatNumber(parsed, this.locale, { useGrouping: false, maximumFractionDigits: 20 });
|
|
6715
|
+
}
|
|
6716
|
+
};
|
|
6717
|
+
}
|
|
6718
|
+
componentWillLoad() {
|
|
6719
|
+
this.syncFromValue();
|
|
6720
|
+
}
|
|
6721
|
+
/** Edit mode loads the record after mount, so the incoming value must re-sync. */
|
|
6722
|
+
valueChanged() {
|
|
6723
|
+
if (!this.focused)
|
|
6724
|
+
this.syncFromValue();
|
|
6725
|
+
}
|
|
6726
|
+
localeChanged() {
|
|
6727
|
+
if (!this.focused)
|
|
6728
|
+
this.syncFromValue();
|
|
6729
|
+
}
|
|
6730
|
+
syncFromValue() {
|
|
6731
|
+
this.displayValue =
|
|
6732
|
+
this.value !== null && this.value !== undefined ? this.formatForDisplay(this.value) : '';
|
|
6733
|
+
}
|
|
6734
|
+
formatForDisplay(val) {
|
|
6735
|
+
if (this.dataType === clientLayout.ClientLayoutItemFieldDataType.PERCENTAGE) {
|
|
6736
|
+
return cellRenderer.formatNumber(val, this.locale, {
|
|
6737
|
+
minimumFractionDigits: 0,
|
|
6738
|
+
maximumFractionDigits: this.decimalPrecision,
|
|
6739
|
+
}) + '%';
|
|
6740
|
+
}
|
|
6741
|
+
if (this.dataType === clientLayout.ClientLayoutItemFieldDataType.DECIMAL) {
|
|
6742
|
+
return cellRenderer.formatNumber(val, this.locale, {
|
|
6743
|
+
minimumFractionDigits: this.decimalPrecision,
|
|
6744
|
+
maximumFractionDigits: this.decimalPrecision,
|
|
6745
|
+
});
|
|
6746
|
+
}
|
|
6747
|
+
return cellRenderer.formatNumber(val, this.locale, { maximumFractionDigits: 0 });
|
|
6748
|
+
}
|
|
6749
|
+
render() {
|
|
6750
|
+
const hasError = !!this.error;
|
|
6751
|
+
const suffix = this.dataType === clientLayout.ClientLayoutItemFieldDataType.PERCENTAGE ? '%' :
|
|
6752
|
+
this.dataType === clientLayout.ClientLayoutItemFieldDataType.DECIMAL ? '' : '';
|
|
6753
|
+
return (index.h(index.Host, { key: '7343dbca882b5054f22de17672ac748a8e3eca11' }, index.h("div", { key: 'cef10b39515b48fc9c44e651910c6a0c2a847628', class: "mrd-number-field" }, index.h(FieldLabel, { key: '66f178cf20f1f2f0587bd9614db150d6ae63023e', base: "mrd-number-field", label: this.label, required: this.required }), index.h("div", { key: 'c57c22e663a570f6e5a70b07b817970f135e850c', class: "mrd-number-field__input-wrapper" }, index.h("input", { key: '388b20ac11fa4aaf78df124c858b579e12f53619', class: controlClass('mrd-number-field', hasError), type: "text", inputMode: "decimal", name: this.name, value: this.displayValue, placeholder: this.placeholder || (suffix ? `0${suffix}` : '0'), required: this.required, disabled: this.disabled, onInput: this.handleInput, onBlur: this.handleBlur, onFocus: this.handleFocus })), index.h(FieldError, { key: 'f99bb85668b047a97162ffee2582eb45dc0589ae', base: "mrd-number-field", error: this.error }))));
|
|
6754
|
+
}
|
|
6755
|
+
static get watchers() { return {
|
|
6756
|
+
"value": [{
|
|
6757
|
+
"valueChanged": 0
|
|
6758
|
+
}],
|
|
6759
|
+
"locale": [{
|
|
6760
|
+
"localeChanged": 0
|
|
6761
|
+
}]
|
|
6762
|
+
}; }
|
|
6763
|
+
};
|
|
6764
|
+
MrdNumberField.style = mrdNumberFieldCss();
|
|
6765
|
+
|
|
6766
|
+
const mrdRelationFieldCss = () => `.sc-mrd-relation-field-h{display:block}.mrd-relation-field.sc-mrd-relation-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%;position:relative}.mrd-relation-field__label.sc-mrd-relation-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-relation-field__label--required.sc-mrd-relation-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-relation-field__select.sc-mrd-relation-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);outline:none;appearance:none;box-sizing:border-box}.mrd-relation-field__select.sc-mrd-relation-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-relation-field__select.sc-mrd-relation-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-relation-field__select.sc-mrd-relation-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-relation-field__select--error.sc-mrd-relation-field{border-color:var(--mrd-border-color-error)}.mrd-relation-field__select--error.sc-mrd-relation-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-relation-field__select.sc-mrd-relation-field{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right var(--mrd-space-3) center;padding-right:calc(var(--mrd-input-padding-x) + 1.5rem);cursor:pointer}.mrd-relation-field__search.sc-mrd-relation-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);outline:none;appearance:none;box-sizing:border-box}.mrd-relation-field__search.sc-mrd-relation-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-relation-field__search.sc-mrd-relation-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-relation-field__search.sc-mrd-relation-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-relation-field__search--error.sc-mrd-relation-field{border-color:var(--mrd-border-color-error)}.mrd-relation-field__search--error.sc-mrd-relation-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-relation-field__error.sc-mrd-relation-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-relation-field__tags.sc-mrd-relation-field{display:flex;flex-wrap:wrap;gap:var(--mrd-space-1);margin-bottom:var(--mrd-space-1)}.mrd-relation-field__tag.sc-mrd-relation-field{display:inline-flex;align-items:center;gap:var(--mrd-space-1);padding:var(--mrd-space-1) var(--mrd-space-2);background-color:var(--mrd-color-primary-light);color:var(--mrd-color-primary-dark);border-radius:var(--mrd-border-radius-full);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-medium)}.mrd-relation-field__tag-remove.sc-mrd-relation-field{background:none;border:none;cursor:pointer;color:var(--mrd-color-primary-dark);font-size:var(--mrd-font-size-xs);padding:0;line-height:1;opacity:0.7}.mrd-relation-field__tag-remove.sc-mrd-relation-field:hover{opacity:1}.mrd-relation-field__search-wrapper.sc-mrd-relation-field{position:relative;display:flex;align-items:center}.mrd-relation-field__spinner.sc-mrd-relation-field{position:absolute;right:var(--mrd-space-3);width:16px;height:16px;border:2px solid var(--mrd-color-neutral-200);border-top-color:var(--mrd-color-primary);border-radius:50%;animation:mrd-spin 0.7s linear infinite}.mrd-relation-field__results.sc-mrd-relation-field{position:absolute;top:calc(100% + var(--mrd-space-1));left:0;right:0;background-color:var(--mrd-color-white);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);box-shadow:var(--mrd-shadow-md);z-index:var(--mrd-z-dropdown);max-height:240px;overflow-y:auto}.mrd-relation-field__result-item.sc-mrd-relation-field{display:flex;flex-direction:column;padding:var(--mrd-space-2) var(--mrd-space-3);cursor:pointer;transition:background-color var(--mrd-transition-fast)}.mrd-relation-field__result-item.sc-mrd-relation-field:hover{background-color:var(--mrd-color-neutral-50)}.mrd-relation-field__result-item.sc-mrd-relation-field:not(:last-child){border-bottom:var(--mrd-border-width) solid var(--mrd-color-neutral-100)}.mrd-relation-field__result-item--highlighted.sc-mrd-relation-field{background-color:var(--mrd-color-primary-light)}.mrd-relation-field__result-label.sc-mrd-relation-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-color-neutral-800);font-weight:var(--mrd-font-weight-medium)}.mrd-relation-field__result-desc.sc-mrd-relation-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);margin-top:var(--mrd-space-1)}.mrd-relation-field__selected-value.sc-mrd-relation-field{display:flex;align-items:center;gap:var(--mrd-space-2);height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);background-color:var(--mrd-color-primary-light);border:var(--mrd-border-width) solid var(--mrd-color-primary);border-radius:var(--mrd-border-radius);box-sizing:border-box}.mrd-relation-field__selected-value--error.sc-mrd-relation-field{border-color:var(--mrd-border-color-error);background-color:var(--mrd-color-danger-light)}.mrd-relation-field__selected-name.sc-mrd-relation-field{flex:1;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-primary-dark);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mrd-relation-field__selected-clear.sc-mrd-relation-field{flex-shrink:0;background:none;border:none;cursor:pointer;color:var(--mrd-color-primary-dark);font-size:var(--mrd-font-size-sm);padding:0;line-height:1;opacity:0.6;transition:opacity var(--mrd-transition-fast)}.mrd-relation-field__selected-clear.sc-mrd-relation-field:hover{opacity:1}.mrd-relation-field__no-results.sc-mrd-relation-field{padding:var(--mrd-space-4);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-500);text-align:center}@keyframes mrd-spin{to{transform:rotate(360deg)}}`;
|
|
6767
|
+
|
|
6768
|
+
const MrdRelationField = class {
|
|
6769
|
+
constructor(hostRef) {
|
|
6770
|
+
index.registerInstance(this, hostRef);
|
|
6771
|
+
this.mrdChange = index.createEvent(this, "mrdChange");
|
|
6772
|
+
this.mrdBlur = index.createEvent(this, "mrdBlur");
|
|
6773
|
+
this.mrdSearch = index.createEvent(this, "mrdSearch");
|
|
6774
|
+
this.mrdFetchAll = index.createEvent(this, "mrdFetchAll");
|
|
6775
|
+
this.name = '';
|
|
6776
|
+
this.label = '';
|
|
6777
|
+
this.required = false;
|
|
6778
|
+
this.disabled = false;
|
|
6779
|
+
this.locale = navigator.language;
|
|
6780
|
+
this.relatedClass = '';
|
|
6781
|
+
/** When set, used instead of relatedClass for search queries (mostSignificantClass from API). */
|
|
6782
|
+
this.mostSignificantClass = '';
|
|
6783
|
+
this.displayType = clientLayout.ClientLayoutItemRelationDisplayType.SEARCH;
|
|
6784
|
+
this.multiple = false;
|
|
6785
|
+
this.dropdownValues = [];
|
|
6786
|
+
/** Plain href string/array for normal use; pass { id, label } objects to pre-fill a loaded record. */
|
|
6787
|
+
this.value = null;
|
|
6788
|
+
this.searchQuery = '';
|
|
6789
|
+
this.searchResults = [];
|
|
6790
|
+
this.allRecords = [];
|
|
6791
|
+
this.isLoading = false;
|
|
6792
|
+
this.selectedItems = [];
|
|
6793
|
+
this.showResults = false;
|
|
6794
|
+
this.error = '';
|
|
6795
|
+
this.highlightedIndex = -1;
|
|
6796
|
+
this.searchDebounce = null;
|
|
6797
|
+
this.handleKeyDown = (e) => {
|
|
6798
|
+
if (!this.showResults || this.searchResults.length === 0) {
|
|
6799
|
+
if (e.key === 'Escape') {
|
|
6800
|
+
this.showResults = false;
|
|
6801
|
+
this.highlightedIndex = -1;
|
|
6802
|
+
}
|
|
6803
|
+
return;
|
|
6804
|
+
}
|
|
6805
|
+
if (e.key === 'ArrowDown') {
|
|
6806
|
+
e.preventDefault();
|
|
6807
|
+
this.highlightedIndex = Math.min(this.highlightedIndex + 1, this.searchResults.length - 1);
|
|
6808
|
+
}
|
|
6809
|
+
else if (e.key === 'ArrowUp') {
|
|
6810
|
+
e.preventDefault();
|
|
6811
|
+
this.highlightedIndex = Math.max(this.highlightedIndex - 1, 0);
|
|
6812
|
+
}
|
|
5973
6813
|
else if (e.key === 'Enter') {
|
|
5974
6814
|
e.preventDefault();
|
|
5975
6815
|
if (this.highlightedIndex >= 0) {
|
|
@@ -6213,190 +7053,6 @@ const MrdSecretField = class {
|
|
|
6213
7053
|
};
|
|
6214
7054
|
MrdSecretField.style = mrdSecretFieldCss();
|
|
6215
7055
|
|
|
6216
|
-
/**
|
|
6217
|
-
* Pure sort/filter/aggregation query logic for mrd-table.
|
|
6218
|
-
* No component state — everything is passed in.
|
|
6219
|
-
*/
|
|
6220
|
-
const TEXT_TYPES = new Set(['TEXT', 'TEXTBLOCK', 'EMAIL', 'HYPERLINK']);
|
|
6221
|
-
const NUMERIC_TYPES = new Set(['INTEGER', 'DECIMAL', 'PERCENTAGE', 'CURRENCY']);
|
|
6222
|
-
const DATE_TYPES = new Set(['DATE', 'DATETIME', 'TIME']);
|
|
6223
|
-
const NO_FILTER_TYPES = new Set(['FILE', 'IMAGE']);
|
|
6224
|
-
/** Column types that cannot be sorted or filtered (not stored in PostgreSQL). */
|
|
6225
|
-
const NON_INTERACTIVE_TYPES = new Set(['LONGTEXT', 'JSON', 'FILE', 'IMAGE']);
|
|
6226
|
-
/** Wait this long (ms) after the user stops typing in the free-text search box
|
|
6227
|
-
* before firing the search request — mirrors REQUEST_DEBOUNCE_MS's purpose
|
|
6228
|
-
* (skip intermediate keystrokes) but is tuned for typing, not scrolling. */
|
|
6229
|
-
const SEARCH_DEBOUNCE_MS = 400;
|
|
6230
|
-
function parseDefaultSort(defaultSort) {
|
|
6231
|
-
var _a;
|
|
6232
|
-
if (!defaultSort)
|
|
6233
|
-
return { field: '', dir: 'asc' };
|
|
6234
|
-
const parts = defaultSort.split(',');
|
|
6235
|
-
return { field: parts[0].trim(), dir: ((_a = parts[1]) === null || _a === void 0 ? void 0 : _a.trim()) === 'desc' ? 'desc' : 'asc' };
|
|
6236
|
-
}
|
|
6237
|
-
/** Raw sort query-param value, e.g. "name" or "name,desc". */
|
|
6238
|
-
function buildSortParam(field, dir) {
|
|
6239
|
-
if (!field)
|
|
6240
|
-
return '';
|
|
6241
|
-
return dir === 'desc' ? `${field},desc` : field;
|
|
6242
|
-
}
|
|
6243
|
-
/** Query params for a page request: page + sort + filterClass + view filters + active column filters. */
|
|
6244
|
-
function buildTableQueryParams(opts) {
|
|
6245
|
-
var _a, _b;
|
|
6246
|
-
const p = new URLSearchParams();
|
|
6247
|
-
if (opts.page > 0)
|
|
6248
|
-
p.set('page', String(opts.page));
|
|
6249
|
-
if (opts.sort)
|
|
6250
|
-
p.set('sort', opts.sort);
|
|
6251
|
-
if (opts.filterClass)
|
|
6252
|
-
p.set('type', opts.filterClass);
|
|
6253
|
-
applyViewFilters(p, opts.viewFilters);
|
|
6254
|
-
if (opts.query)
|
|
6255
|
-
p.set('q', opts.query);
|
|
6256
|
-
for (const f of opts.activeFilters) {
|
|
6257
|
-
if (f.operator === 'isEmpty') {
|
|
6258
|
-
p.set(f.field, '');
|
|
6259
|
-
continue;
|
|
6260
|
-
}
|
|
6261
|
-
if (f.operator === 'isNotEmpty') {
|
|
6262
|
-
p.set(f.field + '_notempty', 'true');
|
|
6263
|
-
continue;
|
|
6264
|
-
}
|
|
6265
|
-
if (f.operator === 'startsWith') {
|
|
6266
|
-
p.set(f.field + '_startswith', String((_a = f.value) !== null && _a !== void 0 ? _a : ''));
|
|
6267
|
-
continue;
|
|
6268
|
-
}
|
|
6269
|
-
if ((_b = f.values) === null || _b === void 0 ? void 0 : _b.length) {
|
|
6270
|
-
p.set(f.field, f.values.join(','));
|
|
6271
|
-
continue;
|
|
6272
|
-
}
|
|
6273
|
-
if (f.value != null)
|
|
6274
|
-
p.set(f.field, String(f.value));
|
|
6275
|
-
if (f.from != null)
|
|
6276
|
-
p.set(f.field + '_from', String(f.from));
|
|
6277
|
-
if (f.to != null)
|
|
6278
|
-
p.set(f.field + '_to', String(f.to));
|
|
6279
|
-
}
|
|
6280
|
-
return p.toString();
|
|
6281
|
-
}
|
|
6282
|
-
/** Groups aggregate columns by function; null when the view has no aggregates. */
|
|
6283
|
-
function buildAggregationParams(columns) {
|
|
6284
|
-
var _a;
|
|
6285
|
-
const groups = { sum: [], avg: [], count: [] };
|
|
6286
|
-
for (const col of columns) {
|
|
6287
|
-
if (col.type !== 'FIELD' || !col.aggregate)
|
|
6288
|
-
continue;
|
|
6289
|
-
const fn = col.aggregate.toLowerCase();
|
|
6290
|
-
if (fn in groups)
|
|
6291
|
-
groups[fn].push((_a = col.name) !== null && _a !== void 0 ? _a : '');
|
|
6292
|
-
}
|
|
6293
|
-
const params = {};
|
|
6294
|
-
if (groups.sum.length)
|
|
6295
|
-
params.sum = groups.sum;
|
|
6296
|
-
if (groups.avg.length)
|
|
6297
|
-
params.avg = groups.avg;
|
|
6298
|
-
if (groups.count.length)
|
|
6299
|
-
params.count = groups.count;
|
|
6300
|
-
return Object.keys(params).length > 0 ? params : null;
|
|
6301
|
-
}
|
|
6302
|
-
/** Aggregation query string: the page-0 query params without page/sort, plus sum/avg/count. */
|
|
6303
|
-
function buildAggregationQs(basePageQs, columns) {
|
|
6304
|
-
var _a, _b, _c;
|
|
6305
|
-
const p = new URLSearchParams(basePageQs);
|
|
6306
|
-
p.delete('page');
|
|
6307
|
-
p.delete('sort');
|
|
6308
|
-
const groups = buildAggregationParams(columns);
|
|
6309
|
-
if ((_a = groups === null || groups === void 0 ? void 0 : groups.sum) === null || _a === void 0 ? void 0 : _a.length)
|
|
6310
|
-
p.set('sum', groups.sum.join(','));
|
|
6311
|
-
if ((_b = groups === null || groups === void 0 ? void 0 : groups.avg) === null || _b === void 0 ? void 0 : _b.length)
|
|
6312
|
-
p.set('avg', groups.avg.join(','));
|
|
6313
|
-
if ((_c = groups === null || groups === void 0 ? void 0 : groups.count) === null || _c === void 0 ? void 0 : _c.length)
|
|
6314
|
-
p.set('count', groups.count.join(','));
|
|
6315
|
-
return p.toString();
|
|
6316
|
-
}
|
|
6317
|
-
/** True when the pending filter actually constrains anything. */
|
|
6318
|
-
function filterHasValue(f) {
|
|
6319
|
-
if (f.operator === 'isEmpty' || f.operator === 'isNotEmpty')
|
|
6320
|
-
return true;
|
|
6321
|
-
if (f.values !== undefined && f.values.length > 0)
|
|
6322
|
-
return true;
|
|
6323
|
-
if (f.value != null && f.value !== '')
|
|
6324
|
-
return true;
|
|
6325
|
-
if (typeof f.value === 'boolean')
|
|
6326
|
-
return true;
|
|
6327
|
-
if (f.from != null && f.from !== '')
|
|
6328
|
-
return true;
|
|
6329
|
-
if (f.to != null && f.to !== '')
|
|
6330
|
-
return true;
|
|
6331
|
-
return false;
|
|
6332
|
-
}
|
|
6333
|
-
// ── DATETIME filters: the user edits local "YYYY-MM-DD" dates, the API stores UTC ISO ──
|
|
6334
|
-
/** UTC ISO string at the start (midnight) of the given local day. */
|
|
6335
|
-
function dateLocalToUTCStart(dateStr) {
|
|
6336
|
-
if (!dateStr)
|
|
6337
|
-
return dateStr;
|
|
6338
|
-
const [year, month, day] = dateStr.split('-').map(Number);
|
|
6339
|
-
return new Date(year, month - 1, day).toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
6340
|
-
}
|
|
6341
|
-
/** Start of the day AFTER the given local date (exclusive range end). */
|
|
6342
|
-
function dateLocalToUTCEndExclusive(dateStr) {
|
|
6343
|
-
if (!dateStr)
|
|
6344
|
-
return dateStr;
|
|
6345
|
-
const [year, month, day] = dateStr.split('-').map(Number);
|
|
6346
|
-
return new Date(year, month - 1, day + 1).toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
6347
|
-
}
|
|
6348
|
-
/** Stored UTC ISO string back to the local "YYYY-MM-DD" date. */
|
|
6349
|
-
function utcISOToLocalDate(utcStr) {
|
|
6350
|
-
if (!utcStr)
|
|
6351
|
-
return utcStr;
|
|
6352
|
-
const d = new Date(utcStr);
|
|
6353
|
-
if (isNaN(d.getTime()))
|
|
6354
|
-
return utcStr;
|
|
6355
|
-
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
|
6356
|
-
}
|
|
6357
|
-
/** The stored "to" is the exclusive end (next midnight); subtract a day to recover the entered date. */
|
|
6358
|
-
function utcISOToLocalDateExclusiveEnd(utcStr) {
|
|
6359
|
-
if (!utcStr)
|
|
6360
|
-
return utcStr;
|
|
6361
|
-
const d = new Date(utcStr);
|
|
6362
|
-
if (isNaN(d.getTime()))
|
|
6363
|
-
return utcStr;
|
|
6364
|
-
d.setDate(d.getDate() - 1);
|
|
6365
|
-
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
|
6366
|
-
}
|
|
6367
|
-
/** Applies the local→UTC conversion when a DATETIME filter is submitted.
|
|
6368
|
-
* Exact date → range covering the full local day. */
|
|
6369
|
-
function normalizeDatetimeFilter(f) {
|
|
6370
|
-
const normalized = Object.assign({}, f);
|
|
6371
|
-
if (f.dataType === 'DATETIME' && f.operator !== 'isEmpty' && f.operator !== 'isNotEmpty') {
|
|
6372
|
-
if (typeof normalized.value === 'string' && normalized.value) {
|
|
6373
|
-
normalized.from = dateLocalToUTCStart(normalized.value);
|
|
6374
|
-
normalized.to = dateLocalToUTCEndExclusive(normalized.value);
|
|
6375
|
-
normalized.value = undefined;
|
|
6376
|
-
}
|
|
6377
|
-
else {
|
|
6378
|
-
if (typeof normalized.from === 'string' && normalized.from)
|
|
6379
|
-
normalized.from = dateLocalToUTCStart(normalized.from);
|
|
6380
|
-
if (typeof normalized.to === 'string' && normalized.to)
|
|
6381
|
-
normalized.to = dateLocalToUTCEndExclusive(normalized.to);
|
|
6382
|
-
}
|
|
6383
|
-
}
|
|
6384
|
-
return normalized;
|
|
6385
|
-
}
|
|
6386
|
-
/** Converts a stored DATETIME filter back to local dates for the popup.
|
|
6387
|
-
* A range covering a single local day is restored to exact-date mode. */
|
|
6388
|
-
function datetimeFilterToDisplay(existing) {
|
|
6389
|
-
const display = Object.assign({}, existing);
|
|
6390
|
-
if (typeof display.from === 'string' && display.from)
|
|
6391
|
-
display.from = utcISOToLocalDate(display.from);
|
|
6392
|
-
if (typeof display.to === 'string' && display.to)
|
|
6393
|
-
display.to = utcISOToLocalDateExclusiveEnd(display.to);
|
|
6394
|
-
if (display.from && display.to && display.from === display.to) {
|
|
6395
|
-
return Object.assign(Object.assign({}, display), { value: display.from, from: undefined, to: undefined });
|
|
6396
|
-
}
|
|
6397
|
-
return display;
|
|
6398
|
-
}
|
|
6399
|
-
|
|
6400
7056
|
/**
|
|
6401
7057
|
* Stateless render parts of mrd-table. All state and handlers stay in the
|
|
6402
7058
|
* component; these components receive plain values and callbacks.
|
|
@@ -7274,16 +7930,19 @@ const MrdTable = class {
|
|
|
7274
7930
|
});
|
|
7275
7931
|
}
|
|
7276
7932
|
buildActionDetail(action, basicType) {
|
|
7277
|
-
var _a
|
|
7933
|
+
var _a;
|
|
7278
7934
|
if (action === 'export') {
|
|
7279
7935
|
return { action, path: this.buildExcelPath(), qs: this.buildQueryParams(0) };
|
|
7280
7936
|
}
|
|
7281
7937
|
if (action === 'create') {
|
|
7282
7938
|
const v = this.allViews[this.activeViewIdx];
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
: null
|
|
7286
|
-
|
|
7939
|
+
return buildCreateActionDetail({
|
|
7940
|
+
isRelatedView: ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW',
|
|
7941
|
+
fromClass: v === null || v === void 0 ? void 0 : v.fromClass,
|
|
7942
|
+
parentId: this.parentId,
|
|
7943
|
+
dataClass: v === null || v === void 0 ? void 0 : v.dataClass,
|
|
7944
|
+
basicType,
|
|
7945
|
+
});
|
|
7287
7946
|
}
|
|
7288
7947
|
return { action };
|
|
7289
7948
|
}
|
|
@@ -7975,12 +8634,29 @@ const MrdTextareaField = class {
|
|
|
7975
8634
|
this.required = false;
|
|
7976
8635
|
this.disabled = false;
|
|
7977
8636
|
this.locale = navigator.language;
|
|
8637
|
+
/** Focus the editor as soon as it's ready — opt-in, since auto-focusing every
|
|
8638
|
+
* textarea field on mount would be wrong for a regular multi-field form. */
|
|
8639
|
+
this.autofocus = false;
|
|
7978
8640
|
this.error = '';
|
|
7979
8641
|
this.editorReady = false;
|
|
7980
8642
|
}
|
|
7981
8643
|
componentDidLoad() {
|
|
7982
8644
|
this.initQuill();
|
|
7983
8645
|
}
|
|
8646
|
+
/** The host may reuse the same element for a different record (e.g. mrd-memo-
|
|
8647
|
+
* container's quick-create/edit dialog editing a second memo without the
|
|
8648
|
+
* dialog itself remounting) — Quill only reads `value` once at construction,
|
|
8649
|
+
* so re-apply it here when it changes to something the editor doesn't already
|
|
8650
|
+
* hold. Guarded against our own emitted mrdChange feeding back in as a no-op. */
|
|
8651
|
+
valueChanged(newValue) {
|
|
8652
|
+
if (!this.editorReady || !this.quill)
|
|
8653
|
+
return;
|
|
8654
|
+
if (newValue === this.getSanitizedHtml())
|
|
8655
|
+
return;
|
|
8656
|
+
this.quill.setText('');
|
|
8657
|
+
if (newValue)
|
|
8658
|
+
this.quill.clipboard.dangerouslyPasteHTML(newValue);
|
|
8659
|
+
}
|
|
7984
8660
|
async initQuill() {
|
|
7985
8661
|
try {
|
|
7986
8662
|
// Dynamically import Quill
|
|
@@ -8002,6 +8678,7 @@ const MrdTextareaField = class {
|
|
|
8002
8678
|
],
|
|
8003
8679
|
},
|
|
8004
8680
|
});
|
|
8681
|
+
this.quill = quill;
|
|
8005
8682
|
if (this.value) {
|
|
8006
8683
|
quill.clipboard.dangerouslyPasteHTML(this.value);
|
|
8007
8684
|
}
|
|
@@ -8017,6 +8694,8 @@ const MrdTextareaField = class {
|
|
|
8017
8694
|
}
|
|
8018
8695
|
});
|
|
8019
8696
|
this.editorReady = true;
|
|
8697
|
+
if (this.autofocus)
|
|
8698
|
+
quill.focus();
|
|
8020
8699
|
}
|
|
8021
8700
|
catch (err) {
|
|
8022
8701
|
console.error('Failed to load Quill editor:', err);
|
|
@@ -8028,9 +8707,14 @@ const MrdTextareaField = class {
|
|
|
8028
8707
|
return purify.sanitize(html);
|
|
8029
8708
|
}
|
|
8030
8709
|
render() {
|
|
8031
|
-
return (index.h(index.Host, { key: '
|
|
8710
|
+
return (index.h(index.Host, { key: '5dad54667601fce064107311e741e4e0dad94298' }, index.h("div", { key: 'bd7bd538155ec3172fa8cc1cf4cf66ad23d07a3b', class: "mrd-textarea-field" }, index.h(FieldLabel, { key: 'a3fe2c714340bbdcd3521e9782f87f3773c65e62', base: "mrd-textarea-field", label: this.label, required: this.required }), index.h("div", { key: 'a7a628f94bc628fd358c7fc876ee1bdd2c7ef520', class: controlClass('mrd-textarea-field', !!this.error, 'container') }, index.h("div", { key: '30ecd27d9e928094178f8f011524ff5633cb875e', class: "mrd-textarea-field__editor" })), index.h(FieldError, { key: '589d5cbf28c3ae1bdbe5f663aaf6cae840bdcffe', base: "mrd-textarea-field", error: this.error }))));
|
|
8032
8711
|
}
|
|
8033
8712
|
get el() { return index.getElement(this); }
|
|
8713
|
+
static get watchers() { return {
|
|
8714
|
+
"value": [{
|
|
8715
|
+
"valueChanged": 0
|
|
8716
|
+
}]
|
|
8717
|
+
}; }
|
|
8034
8718
|
};
|
|
8035
8719
|
MrdTextareaField.style = mrdTextareaFieldCss();
|
|
8036
8720
|
|
|
@@ -8082,6 +8766,9 @@ exports.mrd_invoice_view = MrdInvoiceView;
|
|
|
8082
8766
|
exports.mrd_layout_section = MrdLayoutSection;
|
|
8083
8767
|
exports.mrd_list_field = MrdListField;
|
|
8084
8768
|
exports.mrd_longtext_field = MrdLongtextField;
|
|
8769
|
+
exports.mrd_memo_container = MrdMemoContainer;
|
|
8770
|
+
exports.mrd_memo_list = MrdMemoList;
|
|
8771
|
+
exports.mrd_memo_view = MrdMemoView;
|
|
8085
8772
|
exports.mrd_number_field = MrdNumberField;
|
|
8086
8773
|
exports.mrd_relation_field = MrdRelationField;
|
|
8087
8774
|
exports.mrd_secret_field = MrdSecretField;
|