@mmlogic/components 0.5.12 → 0.5.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/cjs/{cell-renderer-pwUGEDql.js → cell-renderer-mjS630f1.js} +16 -0
  2. package/dist/cjs/loader.cjs.js +1 -1
  3. package/dist/cjs/mosterdcomponents.cjs.js +1 -1
  4. package/dist/cjs/mrd-boolean-field_25.cjs.entry.js +212 -45
  5. package/dist/cjs/mrd-merge-view.cjs.entry.js +1 -1
  6. package/dist/collection/components/documents/mrd-document-container/mrd-document-container.js +30 -4
  7. package/dist/collection/components/documents/mrd-document-list/mrd-document-list.js +55 -6
  8. package/dist/collection/components/layout/mrd-layout-section/mrd-layout-section.js +27 -3
  9. package/dist/collection/components/table/mrd-table/mrd-table.css +36 -0
  10. package/dist/collection/components/table/mrd-table/mrd-table.js +162 -26
  11. package/dist/collection/components/table/mrd-table/table-parts.js +14 -6
  12. package/dist/collection/components/table/mrd-table/table-query.js +6 -0
  13. package/dist/collection/dev/app.js +24 -0
  14. package/dist/collection/utils/i18n.js +16 -0
  15. package/dist/components/i18n.js +1 -1
  16. package/dist/components/mrd-document-container2.js +1 -1
  17. package/dist/components/mrd-document-list2.js +1 -1
  18. package/dist/components/mrd-layout-section.js +1 -1
  19. package/dist/components/mrd-table2.js +1 -1
  20. package/dist/esm/{cell-renderer-B8rJpnq8.js → cell-renderer-BDY8UXkH.js} +16 -0
  21. package/dist/esm/loader.js +1 -1
  22. package/dist/esm/mosterdcomponents.js +1 -1
  23. package/dist/esm/mrd-boolean-field_25.entry.js +212 -45
  24. package/dist/esm/mrd-merge-view.entry.js +1 -1
  25. package/dist/mosterdcomponents/cell-renderer-B8u5BCK-.js.map +1 -0
  26. package/dist/mosterdcomponents/client-layout-Bc42CfJB.js.map +1 -0
  27. package/dist/mosterdcomponents/document-attachments-BufPmMRv.js.map +1 -0
  28. package/dist/mosterdcomponents/field-helpers-CNQcI3Hf.js.map +1 -0
  29. package/dist/mosterdcomponents/file-upload-common-C9wp47CB.js.map +1 -0
  30. package/dist/mosterdcomponents/format-gcecItcD.js.map +1 -0
  31. package/dist/mosterdcomponents/i18n-ydNM87-Q.js.map +1 -0
  32. package/dist/mosterdcomponents/index-1ayBojyN.js.map +1 -0
  33. package/dist/mosterdcomponents/index-DhffneUF.js.map +1 -0
  34. package/dist/mosterdcomponents/index.esm.js.map +1 -0
  35. package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -1
  36. package/dist/mosterdcomponents/mosterdcomponents.esm.js.map +1 -0
  37. package/dist/mosterdcomponents/p-Dkm4WxMy.js +1 -0
  38. package/dist/mosterdcomponents/p-c834951a.entry.js +3 -0
  39. package/dist/mosterdcomponents/{p-e540de6a.entry.js → p-e8b0880f.entry.js} +1 -1
  40. package/dist/mosterdcomponents/purify.es-_duHfPgC.js.map +1 -0
  41. package/dist/mosterdcomponents/query-params-BZbQoeYF.js.map +1 -0
  42. package/dist/mosterdcomponents/quill-C9pgw_k-.js.map +1 -0
  43. package/dist/mosterdcomponents/validation-CjjTt66G.js.map +1 -0
  44. package/dist/types/components/documents/mrd-document-container/mrd-document-container.d.ts +4 -0
  45. package/dist/types/components/documents/mrd-document-list/mrd-document-list.d.ts +6 -1
  46. package/dist/types/components/layout/mrd-layout-section/mrd-layout-section.d.ts +4 -0
  47. package/dist/types/components/table/mrd-table/mrd-table.d.ts +52 -1
  48. package/dist/types/components/table/mrd-table/table-parts.d.ts +18 -0
  49. package/dist/types/components/table/mrd-table/table-query.d.ts +6 -0
  50. package/dist/types/components.d.ts +45 -1
  51. package/package.json +1 -1
  52. package/dist/mosterdcomponents/p-eb322d5c.entry.js +0 -3
  53. package/dist/mosterdcomponents/p-rTM1tU_M.js +0 -1
@@ -1,5 +1,5 @@
1
1
  import { r as registerInstance, c as createEvent, h, H as Host, g as getElement, w as writeTask } from './index-CDiBvvJU.js';
2
- import { t, p as parseLocalizedNumber, f as formatNumber, a as formatDate, b as formatDateTime, c as formatCurrency, C as CellRenderer, d as formatPercentage } from './cell-renderer-B8rJpnq8.js';
2
+ import { t, p as parseLocalizedNumber, f as formatNumber, a as formatDate, b as formatDateTime, c as formatCurrency, C as CellRenderer, d as formatPercentage } from './cell-renderer-BDY8UXkH.js';
3
3
  import { b as ClientLayoutItemFieldDataType, e as ClientLayoutNavigateBehaviour, a as ClientLayoutItemType, c as ClientLayoutItemRelationDisplayType, d as ClientLayoutItemRelationEditBehavior, r as resolveArchetype, A as ARCHETYPE_DOCUMENT, h as ARCHETYPE_INVOICE_LINE, f as ARCHETYPE_INVOICE, g as ARCHETYPE_EMAIL } from './client-layout-Bc42CfJB.js';
4
4
 
5
5
  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)}`;
@@ -361,6 +361,10 @@ const MrdDocumentContainer = class {
361
361
  * on top, Finder-style. The table manages its own height. */
362
362
  this.height = 460;
363
363
  this.locale = navigator.language;
364
+ /** When true, this dashboard is read-only: New folder and Upload are disabled
365
+ * (with a tooltip explaining why) and the embedded table/list get it passed
366
+ * through so their own create/upload/drag-drop paths are disabled too. */
367
+ this.readOnly = false;
364
368
  /** Active body: folder tree or flat table. */
365
369
  this.mode = 'tree';
366
370
  /** Whether the folder tree currently has a valid target for "New folder". */
@@ -375,6 +379,8 @@ const MrdDocumentContainer = class {
375
379
  };
376
380
  this.pickFile = () => {
377
381
  var _a;
382
+ if (this.readOnly)
383
+ return;
378
384
  (_a = this.fileInputEl) === null || _a === void 0 ? void 0 : _a.click();
379
385
  };
380
386
  /** One file per upload, matching the drop handler. Reset the input afterwards
@@ -411,11 +417,11 @@ const MrdDocumentContainer = class {
411
417
  }
412
418
  // ── Toolbar ────────────────────────────────────────────────────────────────
413
419
  renderToolbar() {
414
- return (h("div", { class: "mrd-document-container__toolbar" }, this.mode === 'tree' && (h("button", { type: "button", class: "mrd-document-container__action", disabled: !this.canCreate, onClick: this.createFolder }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" }), h("path", { d: "M12 11v4M10 13h4" })), t('new_folder', this.locale))), this.mode === 'tree' && (h("button", { type: "button", class: "mrd-document-container__action", disabled: !this.canCreate, title: this.targetLabel ? `${t('doc_upload_to', this.locale)} ${this.targetLabel}` : undefined, onClick: this.pickFile }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }), h("path", { d: "M12 3v13M7 8l5-5 5 5" })), t('doc_upload', this.locale))), h("input", { type: "file", class: "mrd-document-container__file-input", ref: el => (this.fileInputEl = el), onChange: this.onFilePicked }), h("div", { class: "mrd-document-container__seg", role: "group", "aria-label": t('doc_view_switch', this.locale) }, h("button", { class: "mrd-document-container__seg-btn", "aria-pressed": String(this.mode === 'tree'), title: t('doc_view_tree', this.locale), "aria-label": t('doc_view_tree', this.locale), onClick: () => this.setMode('tree') }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M3 5h6M3 12h9M3 19h6" }), h("circle", { cx: "18", cy: "5", r: "1.6" }), h("circle", { cx: "18", cy: "19", r: "1.6" }), h("path", { d: "M16 12h4" }))), h("button", { class: "mrd-document-container__seg-btn", "aria-pressed": String(this.mode === 'list'), title: t('doc_view_list', this.locale), "aria-label": t('doc_view_list', this.locale), onClick: () => this.setMode('list') }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01" }))))));
420
+ return (h("div", { class: "mrd-document-container__toolbar" }, this.mode === 'tree' && (h("button", { type: "button", class: "mrd-document-container__action", disabled: this.readOnly || !this.canCreate, title: this.readOnly ? t('readonly_access', this.locale) : undefined, onClick: this.createFolder }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" }), h("path", { d: "M12 11v4M10 13h4" })), t('new_folder', this.locale))), this.mode === 'tree' && (h("button", { type: "button", class: "mrd-document-container__action", disabled: this.readOnly || !this.canCreate, title: this.readOnly ? t('readonly_access', this.locale) : (this.targetLabel ? `${t('doc_upload_to', this.locale)} ${this.targetLabel}` : undefined), onClick: this.pickFile }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }), h("path", { d: "M12 3v13M7 8l5-5 5 5" })), t('doc_upload', this.locale))), h("input", { type: "file", class: "mrd-document-container__file-input", ref: el => (this.fileInputEl = el), onChange: this.onFilePicked }), h("div", { class: "mrd-document-container__seg", role: "group", "aria-label": t('doc_view_switch', this.locale) }, h("button", { class: "mrd-document-container__seg-btn", "aria-pressed": String(this.mode === 'tree'), title: t('doc_view_tree', this.locale), "aria-label": t('doc_view_tree', this.locale), onClick: () => this.setMode('tree') }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M3 5h6M3 12h9M3 19h6" }), h("circle", { cx: "18", cy: "5", r: "1.6" }), h("circle", { cx: "18", cy: "19", r: "1.6" }), h("path", { d: "M16 12h4" }))), h("button", { class: "mrd-document-container__seg-btn", "aria-pressed": String(this.mode === 'list'), title: t('doc_view_list', this.locale), "aria-label": t('doc_view_list', this.locale), onClick: () => this.setMode('list') }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01" }))))));
415
421
  }
416
422
  // ── Bodies ───────────────────────────────────────────────────────────────
417
423
  renderTree() {
418
- return (h("mrd-document-list", { "data-doclist": this.viewKey, ref: el => (this.listEl = el), item: this.item, archetype: this.archetype, parentId: this.parentId, containerHref: this.containerHref, locale: this.locale, onMrdLoadDistinct: (e) => {
424
+ return (h("mrd-document-list", { "data-doclist": this.viewKey, ref: el => (this.listEl = el), item: this.item, archetype: this.archetype, parentId: this.parentId, containerHref: this.containerHref, locale: this.locale, readOnly: this.readOnly, onMrdLoadDistinct: (e) => {
419
425
  e.stopPropagation();
420
426
  this.mrdLoadDistinct.emit(e.detail);
421
427
  }, onMrdLoadPage: (e) => {
@@ -442,7 +448,7 @@ const MrdDocumentContainer = class {
442
448
  } }));
443
449
  }
444
450
  renderList() {
445
- return (h("mrd-table", { "data-view": this.viewKey, ref: el => (this.tableEl = el), item: this.item, parentId: this.parentId, locale: this.locale, onMrdLoadPage: (e) => {
451
+ return (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) => {
446
452
  e.stopPropagation();
447
453
  this.mrdLoadPage.emit(e.detail);
448
454
  }, onMrdLoadAggregations: (e) => {
@@ -466,7 +472,7 @@ const MrdDocumentContainer = class {
466
472
  }
467
473
  render() {
468
474
  const treeMode = this.mode === 'tree';
469
- return (h(Host, { key: 'ae948e2458d9087179e850b527802c489067d93f' }, this.renderToolbar(), h("div", { key: 'a04e1a78413aa794d0bda551aeb9c6245f1aafa2', class: {
475
+ return (h(Host, { key: '6792d49f08dd19f6c51e4b656df06bbd8bc14f3e' }, this.renderToolbar(), h("div", { key: '702f4c288f8c40bd2c5999beb392b9dfd022b0bc', class: {
470
476
  'mrd-document-container__body': true,
471
477
  'mrd-document-container__body--tree': treeMode,
472
478
  }, style: treeMode ? { height: `${this.height}px`, overflowY: 'auto' } : {} }, treeMode ? this.renderTree() : this.renderList())));
@@ -733,6 +739,11 @@ const MrdDocumentList = class {
733
739
  * accepts file drops and folder creation. */
734
740
  this.containerHref = '';
735
741
  this.locale = navigator.language;
742
+ /** When true, folder creation, file upload (button and drag-drop) and moving a
743
+ * document between folders are all disabled — a viewer-role user can browse
744
+ * but not mutate anything. Drives mrdCanCreate(false) so the host toolbar's
745
+ * New folder / Upload buttons stay disabled too. */
746
+ this.readOnly = false;
736
747
  this.containers = [];
737
748
  this.rootLoading = true;
738
749
  /** True when the single-container level is collapsed away (dossier context). */
@@ -775,6 +786,8 @@ const MrdDocumentList = class {
775
786
  /** The optimistic document row awaiting its self href from the create POST. */
776
787
  this.lastOptimisticDoc = null;
777
788
  this.startCreateFolder = () => {
789
+ if (this.readOnly)
790
+ return;
778
791
  const resolved = this.resolveTarget();
779
792
  if (!resolved || this.pendingNode)
780
793
  return;
@@ -814,6 +827,10 @@ const MrdDocumentList = class {
814
827
  // ── Drag & drop: move a document into another folder / container ────────────
815
828
  this.onDocDragStart = (e, doc, node) => {
816
829
  var _a, _b, _c;
830
+ if (this.readOnly) {
831
+ e.preventDefault();
832
+ return;
833
+ }
817
834
  this.dragDoc = doc;
818
835
  this.dragFromId = node.id;
819
836
  if (e.dataTransfer) {
@@ -833,6 +850,11 @@ const MrdDocumentList = class {
833
850
  * root drop-zone; a different node is highlighted (its own folder = no-op). */
834
851
  this.onNodeDragOver = (e, node) => {
835
852
  const file = this.isFileDrag(e);
853
+ if (this.readOnly) {
854
+ if (file)
855
+ e.preventDefault(); // swallow so the browser doesn't navigate to the dropped file
856
+ return;
857
+ }
836
858
  if (!this.dragDoc && !file)
837
859
  return;
838
860
  e.preventDefault();
@@ -848,6 +870,10 @@ const MrdDocumentList = class {
848
870
  this.dropTargetId = null;
849
871
  };
850
872
  this.onNodeDrop = (e, node, container) => {
873
+ if (this.readOnly) {
874
+ e.preventDefault();
875
+ return;
876
+ }
851
877
  if (this.isFileDrag(e)) {
852
878
  e.preventDefault();
853
879
  e.stopPropagation();
@@ -866,6 +892,11 @@ const MrdDocumentList = class {
866
892
  if (!this.singleContainer)
867
893
  return;
868
894
  const file = this.isFileDrag(e);
895
+ if (this.readOnly) {
896
+ if (file)
897
+ e.preventDefault(); // swallow so the browser doesn't navigate to the dropped file
898
+ return;
899
+ }
869
900
  if (!this.dragDoc && !file)
870
901
  return;
871
902
  e.preventDefault();
@@ -883,6 +914,10 @@ const MrdDocumentList = class {
883
914
  };
884
915
  this.onRootDrop = (e) => {
885
916
  this.rootDropActive = false;
917
+ if (this.readOnly) {
918
+ e.preventDefault();
919
+ return;
920
+ }
886
921
  if (!this.singleContainer)
887
922
  return;
888
923
  const only = this.containers[0];
@@ -1153,10 +1188,10 @@ const MrdDocumentList = class {
1153
1188
  return null;
1154
1189
  }
1155
1190
  get canCreateFolder() {
1156
- return !this.pendingNode && this.resolveTarget() !== null;
1191
+ return !this.readOnly && !this.pendingNode && this.resolveTarget() !== null;
1157
1192
  }
1158
1193
  /** Start creating a folder under the current target. Called by the host toolbar
1159
- * (mrd-document-container). No-op when there is no valid target. */
1194
+ * (mrd-document-container). No-op when there is no valid target, or read-only. */
1160
1195
  async createFolder() {
1161
1196
  this.startCreateFolder();
1162
1197
  }
@@ -1242,7 +1277,7 @@ const MrdDocumentList = class {
1242
1277
  * (mrd-document-container). No-op without a target, or while another upload
1243
1278
  * is still awaiting its setFileReference. */
1244
1279
  async uploadFile(file) {
1245
- if (!file || this.pendingUpload)
1280
+ if (this.readOnly || !file || this.pendingUpload)
1246
1281
  return;
1247
1282
  const resolved = this.resolveTarget();
1248
1283
  if (!resolved)
@@ -1383,7 +1418,7 @@ const MrdDocumentList = class {
1383
1418
  body = renderLoadingRow(ctx, 0);
1384
1419
  }
1385
1420
  else if (this.containers.length === 0) {
1386
- body = h("div", { key: '63604a99fc62d9108f61b8efc126c0cd3e8fc5ed', class: "mrd-document-list__empty" }, t('no_results', this.locale));
1421
+ body = h("div", { key: '5d473ec3a894361325a71deb14e7b52d0abc5f06', class: "mrd-document-list__empty" }, t('no_results', this.locale));
1387
1422
  }
1388
1423
  else if (this.singleContainer) {
1389
1424
  // Dossier context: render the single container's folder tree at the root.
@@ -1401,7 +1436,7 @@ const MrdDocumentList = class {
1401
1436
  else {
1402
1437
  body = this.containers.map(c => renderContainerNode(ctx, c, 0));
1403
1438
  }
1404
- return (h(Host, { key: '2a092e3a7483deb1fb30753b0c0428aaf75c303a' }, h("div", { key: '2b716c912a272b925a95133de5b1ff2abedd9dbc', class: 'mrd-document-list' + (this.rootDropActive ? ' mrd-document-list--drop-active' : ''), onDragOver: this.onRootDragOver, onDragLeave: this.onRootDragLeave, onDrop: this.onRootDrop }, body)));
1439
+ return (h(Host, { key: '757babf3ccabbb113ab2a24d632b2b9a02d3c08b' }, h("div", { key: '606c212687482efdc5666333678e2ea406709e75', class: 'mrd-document-list' + (this.rootDropActive ? ' mrd-document-list--drop-active' : ''), onDragOver: this.onRootDragOver, onDragLeave: this.onRootDragLeave, onDrop: this.onRootDrop }, body)));
1405
1440
  }
1406
1441
  get el() { return getElement(this); }
1407
1442
  };
@@ -5316,6 +5351,10 @@ const MrdLayoutSection = class {
5316
5351
  /** Top-level archetypes on the object dashboard. When it contains commons.document,
5317
5352
  * the record is rendered as a single-document view instead of generic fields. */
5318
5353
  this.archetypes = [];
5354
+ /** When true, this dashboard is read-only (viewer role): the embedded mrd-table's
5355
+ * create ("+") action and the documents view's New folder / Upload are disabled
5356
+ * with a tooltip explaining why, so it's clear at a glance the user can't mutate data. */
5357
+ this.readOnly = false;
5319
5358
  this.searchQueryMap = {};
5320
5359
  this.searchResultsMap = {};
5321
5360
  this.imagePreviewUrl = null;
@@ -5521,7 +5560,7 @@ const MrdLayoutSection = class {
5521
5560
  * swaps between the folder tree and the flat table. Events are re-emitted to
5522
5561
  * the host with the view key, exactly as the raw list/table events were. */
5523
5562
  renderDocumentContainer(item, key, parentId, archetype, containerHref) {
5524
- return (h("mrd-document-container", { item: item, archetype: archetype, parentId: parentId, containerHref: containerHref, viewKey: key, locale: this.locale, onMrdLoadDistinct: (e) => {
5563
+ return (h("mrd-document-container", { item: item, archetype: archetype, parentId: parentId, containerHref: containerHref, viewKey: key, locale: this.locale, readOnly: this.readOnly, onMrdLoadDistinct: (e) => {
5525
5564
  e.stopPropagation();
5526
5565
  this.mrdLoadViewDistinct.emit(Object.assign({ name: key }, e.detail));
5527
5566
  }, onMrdLoadPage: (e) => {
@@ -5554,7 +5593,7 @@ const MrdLayoutSection = class {
5554
5593
  } }));
5555
5594
  }
5556
5595
  renderTable(item, key, parentId) {
5557
- return (h("mrd-table", { "data-view": key, item: item, parentId: parentId, locale: this.locale, onMrdLoadPage: (e) => this.handleViewLoadPage(e, key), onMrdLoadAggregations: (e) => {
5596
+ return (h("mrd-table", { "data-view": key, item: item, parentId: parentId, locale: this.locale, readOnly: this.readOnly, onMrdLoadPage: (e) => this.handleViewLoadPage(e, key), onMrdLoadAggregations: (e) => {
5558
5597
  var _a;
5559
5598
  e.stopPropagation();
5560
5599
  this.mrdLoadViewAggregations.emit(Object.assign({ name: key, dataClass: (_a = item.dataClass) !== null && _a !== void 0 ? _a : key }, e.detail));
@@ -5658,7 +5697,7 @@ const MrdLayoutSection = class {
5658
5697
  const docArchetype = resolveArchetype(this.archetypes, ARCHETYPE_DOCUMENT);
5659
5698
  const invoiceArchetype = !docArchetype ? resolveArchetype(this.archetypes, ARCHETYPE_INVOICE) : undefined;
5660
5699
  const emailArchetype = !docArchetype && !invoiceArchetype ? resolveArchetype(this.archetypes, ARCHETYPE_EMAIL) : undefined;
5661
- return (h(Host, { key: 'ccae8e82b4dd549ab24239fe685a6830a508061d' }, h("div", { key: '4072cc4ecdd2b087c54a5515e653f7f713b2150f', class: "mrd-layout-section" }, docArchetype && this.renderDocumentObject(docArchetype), invoiceArchetype && this.renderInvoiceObject(invoiceArchetype), emailArchetype && this.renderEmailObject(emailArchetype), !docArchetype && !invoiceArchetype && !emailArchetype && this.items.map(item => this.renderItem(item))), this.renderImageModal()));
5700
+ return (h(Host, { key: '07b1d61b170a5ae971ba54eaf775e1787dea1642' }, h("div", { key: 'd146e0542b1de11bd130eb3d36d54e4faf055309', class: "mrd-layout-section" }, docArchetype && this.renderDocumentObject(docArchetype), invoiceArchetype && this.renderInvoiceObject(invoiceArchetype), emailArchetype && this.renderEmailObject(emailArchetype), !docArchetype && !invoiceArchetype && !emailArchetype && this.items.map(item => this.renderItem(item))), this.renderImageModal()));
5662
5701
  }
5663
5702
  get el() { return getElement(this); }
5664
5703
  static get watchers() { return {
@@ -6182,6 +6221,10 @@ const DATE_TYPES = new Set(['DATE', 'DATETIME', 'TIME']);
6182
6221
  const NO_FILTER_TYPES = new Set(['FILE', 'IMAGE']);
6183
6222
  /** Column types that cannot be sorted or filtered (not stored in PostgreSQL). */
6184
6223
  const NON_INTERACTIVE_TYPES = new Set(['LONGTEXT', 'JSON', 'FILE', 'IMAGE']);
6224
+ /** Wait this long (ms) after the user stops typing in the free-text search box
6225
+ * before firing the search request — mirrors REQUEST_DEBOUNCE_MS's purpose
6226
+ * (skip intermediate keystrokes) but is tuned for typing, not scrolling. */
6227
+ const SEARCH_DEBOUNCE_MS = 400;
6185
6228
  function parseDefaultSort(defaultSort) {
6186
6229
  var _a;
6187
6230
  if (!defaultSort)
@@ -6206,6 +6249,8 @@ function buildTableQueryParams(opts) {
6206
6249
  if (opts.filterClass)
6207
6250
  p.set('type', opts.filterClass);
6208
6251
  applyViewFilters(p, opts.viewFilters);
6252
+ if (opts.query)
6253
+ p.set('q', opts.query);
6209
6254
  for (const f of opts.activeFilters) {
6210
6255
  if (f.operator === 'isEmpty') {
6211
6256
  p.set(f.field, '');
@@ -6355,6 +6400,7 @@ function datetimeFilterToDisplay(existing) {
6355
6400
  * component; these components receive plain values and callbacks.
6356
6401
  */
6357
6402
  const FilterIcon = () => (h("span", { class: "mrd-table__filter-icon", "aria-hidden": "true" }, h("svg", { viewBox: "0 0 24 24", width: "14", height: "14", fill: "currentColor" }, h("path", { d: "M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z" }))));
6403
+ const SearchIcon = ({ class: cls }) => (h("svg", { class: cls, viewBox: "0 0 24 24", width: "16", height: "16", "aria-hidden": "true" }, h("path", { fill: "currentColor", d: "M15.5 14h-.79l-.28-.27a6.5 6.5 0 1 0-.7.7l.27.28v.79l5 4.99L20.49 19zM9.5 14A4.5 4.5 0 1 1 14 9.5 4.5 4.5 0 0 1 9.5 14" })));
6358
6404
  const TEXTBLOCK_MAX = 200;
6359
6405
  const TableCell = ({ col, row, locale, onDownload, onOpenTextblock, onOpenJson }) => {
6360
6406
  var _a, _b, _c;
@@ -6434,25 +6480,32 @@ const JsonModal = ({ html, locale, onClose }) => {
6434
6480
  return null;
6435
6481
  return (h("div", { class: "mrd-table__modal-backdrop", onClick: onClose, role: "dialog", "aria-modal": "true" }, h("div", { class: "mrd-table__modal", onClick: (e) => e.stopPropagation() }, h("button", { class: "mrd-table__modal-close", onClick: onClose, "aria-label": t('close', locale) }, "\u2715"), h("pre", { class: "mrd-table__modal-json", innerHTML: html }))));
6436
6482
  };
6437
- const Toolbar = ({ locale, filterCount, actions, views, activeViewIdx, viewPopoverOpen, createPickerOpen, createTypes, cb }) => {
6483
+ const Toolbar = ({ locale, filterCount, actions, views, activeViewIdx, viewPopoverOpen, createPickerOpen, createTypes, readOnly, searchEnabled, searchOpen, searchQuery, cb }) => {
6438
6484
  var _a;
6439
6485
  const hasActions = actions.length > 0;
6440
6486
  const hasViewSwitcher = views.length > 1;
6441
- return (h("div", { class: "mrd-table__toolbar" }, h("div", { class: "mrd-table__toolbar-left" }, filterCount > 0 && (h("button", { class: "mrd-table__action mrd-table__action--secondary mrd-table__filter-clear", onClick: cb.onClearAllFilters }, h("svg", { class: "mrd-table__action-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, h("path", { fill: "currentColor", d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" })), h("span", { class: "mrd-table__filter-clear-label" }, t('table_filter_clear_all', locale), " (", filterCount, ")")))), hasViewSwitcher && (h("div", { class: "mrd-table__toolbar-center" }, h("div", { class: "mrd-table__view-switcher" }, h("button", { class: "mrd-table__view-arrow", "aria-label": "Previous view", onClick: () => cb.onViewSwitch((activeViewIdx - 1 + views.length) % views.length) }, "\u25C0"), h("div", { class: "mrd-table__view-title-wrap" }, h("button", { class: "mrd-table__view-title", onClick: (e) => cb.onToggleViewPopover(e) }, (_a = views[activeViewIdx]) === null || _a === void 0 ? void 0 : _a.label), viewPopoverOpen && (h("div", { class: "mrd-table__view-popover", onClick: (e) => e.stopPropagation() }, views.map((v, i) => (h("button", { key: String(i), class: `mrd-table__view-popover-item${i === activeViewIdx ? ' mrd-table__view-popover-item--active' : ''}`, onClick: () => {
6487
+ return (h("div", { class: "mrd-table__toolbar" }, h("div", { class: "mrd-table__toolbar-left" }, searchEnabled && (searchOpen ? (h("span", { class: "mrd-table__search-box" }, h(SearchIcon, null), h("input", { type: "text", class: "mrd-table__search-input", value: searchQuery !== null && searchQuery !== void 0 ? searchQuery : '', placeholder: t('search_placeholder', locale), ref: cb.onSearchInputRef, onInput: (e) => cb.onSearchInput(e.target.value), onKeyDown: (e) => {
6488
+ if (e.key === 'Escape')
6489
+ cb.onCloseSearch();
6490
+ } }), h("button", { type: "button", class: "mrd-table__search-clear", "aria-label": t('clear', locale), onClick: cb.onCloseSearch }, "\u2715"))) : (h("button", { type: "button", class: "mrd-table__action mrd-table__action--secondary mrd-table__search-toggle", onClick: cb.onToggleSearch }, h(SearchIcon, { class: "mrd-table__action-icon" }), h("span", { class: "mrd-table__action-tooltip" }, t('table_search', locale))))), filterCount > 0 && (h("button", { class: "mrd-table__action mrd-table__action--secondary mrd-table__filter-clear", onClick: cb.onClearAllFilters }, h("svg", { class: "mrd-table__action-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, h("path", { fill: "currentColor", d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" })), h("span", { class: "mrd-table__filter-clear-label" }, t('table_filter_clear_all', locale), " (", filterCount, ")")))), hasViewSwitcher && (h("div", { class: "mrd-table__toolbar-center" }, h("div", { class: "mrd-table__view-switcher" }, h("button", { class: "mrd-table__view-arrow", "aria-label": "Previous view", onClick: () => cb.onViewSwitch((activeViewIdx - 1 + views.length) % views.length) }, "\u25C0"), h("div", { class: "mrd-table__view-title-wrap" }, h("button", { class: "mrd-table__view-title", onClick: (e) => cb.onToggleViewPopover(e) }, (_a = views[activeViewIdx]) === null || _a === void 0 ? void 0 : _a.label), viewPopoverOpen && (h("div", { class: "mrd-table__view-popover", onClick: (e) => e.stopPropagation() }, views.map((v, i) => (h("button", { key: String(i), class: `mrd-table__view-popover-item${i === activeViewIdx ? ' mrd-table__view-popover-item--active' : ''}`, onClick: () => {
6442
6491
  if (i !== activeViewIdx)
6443
6492
  cb.onViewSwitch(i);
6444
6493
  cb.onCloseViewPopover();
6445
6494
  } }, v.label)))))), h("button", { class: "mrd-table__view-arrow", "aria-label": "Next view", onClick: () => cb.onViewSwitch((activeViewIdx + 1) % views.length) }, "\u25B6")))), hasActions && (h("div", { class: "mrd-table__toolbar-right" }, actions.map(a => {
6446
6495
  var _a, _b;
6447
6496
  const pickerTypes = a.action === 'create' ? createTypes : null;
6497
+ // readOnly only ever disables 'create' (see mrd-table.tsx tableActions) — export,
6498
+ // sorting and filtering don't mutate data and stay available.
6499
+ const disabled = a.disabled || (readOnly && a.action === 'create');
6500
+ const tooltip = disabled && readOnly ? t('readonly_access', locale) : a.label;
6448
6501
  if (pickerTypes === null || pickerTypes === void 0 ? void 0 : pickerTypes.length) {
6449
- return (h("div", { class: "mrd-table__create-picker-wrap", key: `action-${a.action}` }, h("button", { class: `mrd-table__action mrd-table__action--${(_a = a.variant) !== null && _a !== void 0 ? _a : 'secondary'}`, onClick: cb.onToggleCreatePicker }, a.icon
6502
+ return (h("div", { class: "mrd-table__create-picker-wrap", key: `action-${a.action}` }, h("button", { class: `mrd-table__action mrd-table__action--${(_a = a.variant) !== null && _a !== void 0 ? _a : 'secondary'}`, disabled: disabled, onClick: cb.onToggleCreatePicker }, a.icon
6450
6503
  ? h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, h("use", { href: a.icon }))
6451
- : a.label, h("span", { class: "mrd-table__action-tooltip" }, a.label)), createPickerOpen && (h("div", { class: "mrd-table__create-picker" }, pickerTypes.map(ct => (h("button", { key: ct.type, class: "mrd-table__create-picker-item", onClick: () => cb.onCreate(ct.type) }, ct.label)))))));
6504
+ : a.label, h("span", { class: "mrd-table__action-tooltip" }, tooltip)), createPickerOpen && (h("div", { class: "mrd-table__create-picker" }, pickerTypes.map(ct => (h("button", { key: ct.type, class: "mrd-table__create-picker-item", onClick: () => cb.onCreate(ct.type) }, ct.label)))))));
6452
6505
  }
6453
- return (h("button", { key: `action-${a.action}`, class: `mrd-table__action mrd-table__action--${(_b = a.variant) !== null && _b !== void 0 ? _b : 'secondary'}`, disabled: a.disabled, onClick: () => cb.onAction(a.action) }, a.icon
6506
+ return (h("button", { key: `action-${a.action}`, class: `mrd-table__action mrd-table__action--${(_b = a.variant) !== null && _b !== void 0 ? _b : 'secondary'}`, disabled: disabled, onClick: () => cb.onAction(a.action) }, a.icon
6454
6507
  ? h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, h("use", { href: a.icon }))
6455
- : a.label, h("span", { class: "mrd-table__action-tooltip" }, a.label)));
6508
+ : a.label, h("span", { class: "mrd-table__action-tooltip" }, tooltip)));
6456
6509
  })))));
6457
6510
  };
6458
6511
 
@@ -6608,7 +6661,7 @@ function getStalePages(requestedAt, now, timeoutMs) {
6608
6661
  return stale;
6609
6662
  }
6610
6663
 
6611
- const mrdTableCss = () => `.sc-mrd-table-h{display:block;width:100%}.mrd-table.sc-mrd-table{overflow-x:auto}.mrd-table__scroll.sc-mrd-table{overflow-y:auto;overflow-x:auto;border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);overflow-anchor:none}.mrd-table__table.sc-mrd-table{width:auto;min-width:100%;border-collapse:collapse;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-900)}.mrd-table__scroll.sc-mrd-table .mrd-table__table.sc-mrd-table{min-width:max-content}.mrd-table__header.sc-mrd-table{position:sticky;top:0;z-index:1;background:var(--mrd-color-white);text-align:left;padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:2px solid var(--mrd-border-color);color:var(--mrd-color-neutral-600);font-weight:var(--mrd-font-weight-medium);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:var(--mrd-font-size-xs);text-transform:uppercase;letter-spacing:0.04em}.mrd-table__header--sortable.sc-mrd-table{cursor:pointer;user-select:none}.mrd-table__header--sortable.sc-mrd-table:hover{background:var(--mrd-color-neutral-50);color:var(--mrd-color-neutral-800)}.mrd-table__header--sorted-asc.sc-mrd-table,.mrd-table__header--sorted-desc.sc-mrd-table{color:var(--mrd-color-primary);border-bottom-color:var(--mrd-color-primary)}.mrd-table__header--filtered.sc-mrd-table{color:var(--mrd-color-primary);border-bottom-color:var(--mrd-color-primary)}.mrd-table__header-label.sc-mrd-table{margin-right:var(--mrd-space-1)}.mrd-table__col-resizer.sc-mrd-table{position:absolute;top:0;right:0;width:9px;height:100%;cursor:col-resize;touch-action:none;user-select:none}.mrd-table__col-resizer.sc-mrd-table::after{content:"";position:absolute;top:25%;right:4px;width:1px;height:50%;background:var(--mrd-border-color)}.mrd-table__col-resizer.sc-mrd-table:hover::after{width:2px;right:3px;background:var(--mrd-color-primary)}.mrd-table__col-resizer--active.sc-mrd-table::after{width:2px;right:3px;height:100%;top:0;background:var(--mrd-color-primary)}.mrd-table--resizing.sc-mrd-table{cursor:col-resize;user-select:none}.mrd-table__sort-icon.sc-mrd-table{font-size:0.85rem;opacity:0.4;vertical-align:middle}.mrd-table__header--sorted-asc.sc-mrd-table .mrd-table__sort-icon.sc-mrd-table,.mrd-table__header--sorted-desc.sc-mrd-table .mrd-table__sort-icon.sc-mrd-table{opacity:1;color:var(--mrd-color-primary)}.mrd-table__filter-icon.sc-mrd-table{display:inline-flex;align-items:center;vertical-align:middle;margin-left:var(--mrd-space-1);color:var(--mrd-color-primary)}.mrd-table__row.sc-mrd-table{border-bottom:1px solid var(--mrd-border-color)}.mrd-table__row.sc-mrd-table:hover{background:var(--mrd-color-neutral-200) !important}.mrd-table__row--clickable.sc-mrd-table{cursor:pointer}.mrd-table__row--loading.sc-mrd-table{background:transparent}.mrd-table__row--failed.sc-mrd-table{background:transparent}.mrd-table__spacer.sc-mrd-table{border:none}.mrd-table__spacer.sc-mrd-table td.sc-mrd-table{padding:0;border:none}.mrd-table__cell.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);vertical-align:top;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mrd-table__cell--numeric.sc-mrd-table{text-align:right;font-variant-numeric:tabular-nums}.mrd-table__cell--placeholder.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:1px solid var(--mrd-border-color)}.mrd-table__cell--failed.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:1px solid var(--mrd-border-color)}.mrd-table__placeholder-bar.sc-mrd-table{display:block;height:0.75rem;width:55%;border-radius:var(--mrd-border-radius-sm);background:linear-gradient(90deg, var(--mrd-color-neutral-200) 25%, var(--mrd-color-neutral-100) 50%, var(--mrd-color-neutral-200) 75%);background-size:200% 100%;animation:mrd-shimmer 1.4s ease infinite}.mrd-table__retry-button.sc-mrd-table{border:none;background:none;padding:0;color:var(--mrd-color-danger);font-size:inherit;cursor:pointer;text-decoration:underline}.mrd-table__toolbar.sc-mrd-table{display:flex;align-items:center;justify-content:space-between;padding-bottom:var(--mrd-space-2)}.mrd-table__toolbar-left.sc-mrd-table,.mrd-table__toolbar-right.sc-mrd-table{display:flex;gap:var(--mrd-space-2);align-items:center}.mrd-table__toolbar-center.sc-mrd-table{flex:1;display:flex;justify-content:center;align-items:center;gap:var(--mrd-space-1)}.mrd-table__view-switcher.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1)}.mrd-table__view-arrow.sc-mrd-table{background:none;border:none;cursor:pointer;padding:0 var(--mrd-space-1);color:var(--mrd-color-neutral-500);font-size:var(--mrd-font-size-xs);line-height:1}.mrd-table__view-arrow.sc-mrd-table:hover{color:var(--mrd-color-neutral-800)}.mrd-table__view-title-wrap.sc-mrd-table{position:relative}.mrd-table__view-title.sc-mrd-table{font-size:var(--mrd-font-size-sm);font-weight:600;color:var(--mrd-color-neutral-800);font-family:var(--mrd-font-family);background:none;border:none;outline:none;cursor:pointer;padding:0 var(--mrd-space-1);max-width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mrd-table__view-title.sc-mrd-table:hover{color:var(--mrd-color-primary)}.mrd-table__view-popover.sc-mrd-table{position:absolute;top:calc(100% + var(--mrd-space-1));left:50%;transform:translateX(-50%);background:var(--mrd-color-white);border:1px solid var(--mrd-color-neutral-200);border-radius:var(--mrd-radius-md);box-shadow:var(--mrd-shadow-md);z-index:100;min-width:160px;padding:var(--mrd-space-1) 0}.mrd-table__view-popover-item.sc-mrd-table{display:block;width:100%;text-align:left;background:none;border:none;cursor:pointer;padding:var(--mrd-space-2) var(--mrd-space-3);font-size:var(--mrd-font-size-sm);font-family:var(--mrd-font-family);color:var(--mrd-color-neutral-700);white-space:nowrap}.mrd-table__view-popover-item.sc-mrd-table:hover{background:var(--mrd-color-neutral-50)}.mrd-table__view-popover-item--active.sc-mrd-table{font-weight:600;color:var(--mrd-color-primary)}.mrd-table__action.sc-mrd-table{position:relative;display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;background:transparent;border:1px solid transparent;border-radius:var(--mrd-border-radius);cursor:pointer;color:var(--mrd-color-neutral-400);transition:background-color 0.15s, border-color 0.15s, color 0.15s}.mrd-table__action.sc-mrd-table:hover{background-color:var(--mrd-color-neutral-100);border-color:var(--mrd-color-neutral-300);color:var(--mrd-color-neutral-700)}.mrd-table__action.sc-mrd-table:hover .mrd-table__action-tooltip.sc-mrd-table{display:block}.mrd-table__action.sc-mrd-table:disabled{opacity:0.4;cursor:not-allowed}.mrd-table__action--primary.sc-mrd-table{color:var(--mrd-color-neutral-500)}.mrd-table__action--primary.sc-mrd-table:hover{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__action--danger.sc-mrd-table{color:var(--mrd-color-error)}.mrd-table__action--danger.sc-mrd-table:hover{background-color:var(--mrd-color-error-light, #fef2f2);border-color:var(--mrd-color-error)}.mrd-table__action-icon.sc-mrd-table{width:1.25rem;height:1.25rem;pointer-events:none;fill:currentColor}.mrd-table__action-tooltip.sc-mrd-table{display:none;position:absolute;bottom:calc(100% + 6px);right:0;padding:var(--mrd-space-1) var(--mrd-space-2);font-size:var(--mrd-font-size-xs);white-space:nowrap;background:var(--mrd-color-tooltip, #fffce1);color:var(--mrd-color-neutral-900);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-sm, var(--mrd-border-radius));pointer-events:none;z-index:10}.mrd-table__create-picker-wrap.sc-mrd-table{position:relative}.mrd-table__create-picker.sc-mrd-table{position:absolute;right:0;top:calc(100% + 4px);background:var(--mrd-color-white, #fff);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);box-shadow:var(--mrd-shadow-md, 0 4px 12px rgba(0, 0, 0, 0.12));z-index:10;min-width:10rem;padding:var(--mrd-space-1) 0}.mrd-table__create-picker-item.sc-mrd-table{display:block;width:100%;text-align:left;padding:var(--mrd-space-2) var(--mrd-space-3);background:none;border:none;cursor:pointer;font-size:var(--mrd-font-size-sm);font-family:var(--mrd-font-family);color:var(--mrd-color-neutral-800)}.mrd-table__create-picker-item.sc-mrd-table:hover{background:var(--mrd-color-neutral-50);color:var(--mrd-color-neutral-900)}.mrd-table__filter-clear.sc-mrd-table{width:auto;gap:var(--mrd-space-1);padding:0 var(--mrd-space-2);color:var(--mrd-color-primary);border-color:var(--mrd-color-primary)}.mrd-table__filter-clear.sc-mrd-table:hover{color:var(--mrd-color-primary);border-color:var(--mrd-color-primary)}.mrd-table__filter-clear-label.sc-mrd-table{font-size:var(--mrd-font-size-sm);white-space:nowrap}.mrd-table__filter-popup.sc-mrd-table{position:fixed;width:280px;background:var(--mrd-color-white);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);box-shadow:var(--mrd-shadow-md, 0 4px 12px rgba(0, 0, 0, 0.12));z-index:var(--mrd-z-dropdown, 200);font-size:var(--mrd-font-size-sm)}.mrd-table__filter-popup-header.sc-mrd-table{display:flex;align-items:center;justify-content:space-between;padding:var(--mrd-space-2) var(--mrd-space-3);border-bottom:1px solid var(--mrd-border-color)}.mrd-table__filter-popup-title.sc-mrd-table{font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-800);font-size:var(--mrd-font-size-sm)}.mrd-table__filter-close.sc-mrd-table{background:transparent;border:none;cursor:pointer;color:var(--mrd-color-neutral-500);font-size:0.9rem;padding:2px 4px;border-radius:3px;line-height:1}.mrd-table__filter-close.sc-mrd-table:hover{background:var(--mrd-color-neutral-100);color:var(--mrd-color-neutral-800)}.mrd-table__filter-section.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-3)}.mrd-table__filter-section-label.sc-mrd-table{font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-medium);text-transform:uppercase;letter-spacing:0.04em;color:var(--mrd-color-neutral-500);margin-bottom:var(--mrd-space-2)}.mrd-table__filter-sort-buttons.sc-mrd-table{display:flex;gap:var(--mrd-space-2)}.mrd-table__filter-sort-btn.sc-mrd-table{flex:1;padding:var(--mrd-space-1) var(--mrd-space-2);background:transparent;border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);cursor:pointer;font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-700)}.mrd-table__filter-sort-btn.sc-mrd-table:hover{background:var(--mrd-color-neutral-100)}.mrd-table__filter-sort-btn--active.sc-mrd-table{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__filter-divider.sc-mrd-table{height:1px;background:var(--mrd-border-color);margin:0}.mrd-table__filter-editor.sc-mrd-table{display:flex;flex-direction:column;gap:var(--mrd-space-2)}.mrd-table__filter-select.sc-mrd-table,.mrd-table__filter-input.sc-mrd-table{width:100%;padding:var(--mrd-space-1) var(--mrd-space-2);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-900);background:var(--mrd-color-white);box-sizing:border-box}.mrd-table__filter-select.sc-mrd-table:focus,.mrd-table__filter-input.sc-mrd-table:focus{outline:none;border-color:var(--mrd-color-primary);box-shadow:0 0 0 2px rgba(0, 0, 0, 0.06)}.mrd-table__filter-range.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1)}.mrd-table__filter-range.sc-mrd-table .mrd-table__filter-input.sc-mrd-table{flex:1;min-width:0}.mrd-table__filter-range--stacked.sc-mrd-table{flex-direction:column;align-items:stretch;gap:var(--mrd-space-2)}.mrd-table__filter-range-sep.sc-mrd-table{color:var(--mrd-color-neutral-400);flex-shrink:0}.mrd-table__filter-range-label.sc-mrd-table{font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);margin-bottom:2px}.mrd-table__filter-radio-group.sc-mrd-table{display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-table__filter-radio-group--inline.sc-mrd-table{flex-direction:row;gap:var(--mrd-space-3)}.mrd-table__filter-radio-label.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1);cursor:pointer;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800)}.mrd-table__filter-list.sc-mrd-table{display:flex;flex-direction:column;gap:var(--mrd-space-1);max-height:180px;overflow-y:auto}.mrd-table__filter-list-controls.sc-mrd-table{display:flex;gap:var(--mrd-space-2);margin-bottom:var(--mrd-space-1)}.mrd-table__filter-list-btn.sc-mrd-table{font-size:var(--mrd-font-size-xs);color:var(--mrd-color-primary);background:transparent;border:none;cursor:pointer;padding:0;text-decoration:underline}.mrd-table__filter-checkbox-label.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1);cursor:pointer;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800)}.mrd-table__filter-no-support.sc-mrd-table{font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-500);margin:0;font-style:italic}.mrd-table__filter-popup-footer.sc-mrd-table{display:flex;justify-content:flex-end;gap:var(--mrd-space-2);padding:var(--mrd-space-2) var(--mrd-space-3);border-top:1px solid var(--mrd-border-color)}.mrd-table__filter-btn.sc-mrd-table{padding:var(--mrd-space-1) var(--mrd-space-3);border-radius:var(--mrd-border-radius);border:1px solid var(--mrd-border-color);font-size:var(--mrd-font-size-sm);cursor:pointer}.mrd-table__filter-btn--clear.sc-mrd-table{background:transparent;color:var(--mrd-color-neutral-600)}.mrd-table__filter-btn--clear.sc-mrd-table:hover{background:var(--mrd-color-neutral-100)}.mrd-table__filter-btn--apply.sc-mrd-table{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__filter-btn--apply.sc-mrd-table:hover{background:var(--mrd-color-primary-dark, var(--mrd-color-primary));border-color:var(--mrd-color-primary-dark, var(--mrd-color-primary))}.mrd-table__totals-row.sc-mrd-table{border-top:2px solid var(--mrd-border-color)}.mrd-table__totals-cell.sc-mrd-table{position:sticky;bottom:0;z-index:2;padding:var(--mrd-space-2) var(--mrd-space-4);background:var(--mrd-color-white);font-weight:var(--mrd-font-weight-medium);font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;border-top:2px solid var(--mrd-border-color)}.mrd-table__totals-cell--numeric.sc-mrd-table{text-align:right}.mrd-table__footer.sc-mrd-table{padding:var(--mrd-space-1) var(--mrd-space-2);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);text-align:right}.mrd-table__empty.sc-mrd-table{padding:var(--mrd-space-4) var(--mrd-space-3);color:var(--mrd-color-neutral-500);font-size:var(--mrd-font-size-sm);text-align:center;margin:0}.mrd-table__file-btn.sc-mrd-table{display:inline-flex;align-items:center;gap:var(--mrd-space-1);background:none;border:none;padding:0;cursor:pointer;color:var(--mrd-color-primary);font-size:var(--mrd-font-size-sm);font-family:inherit;max-width:100%;overflow:hidden}.mrd-table__file-btn.sc-mrd-table:hover{text-decoration:underline;color:var(--mrd-color-primary-dark)}.mrd-table__file-icon.sc-mrd-table{flex-shrink:0;width:1rem;height:1rem}.mrd-table__textblock-btn.sc-mrd-table{display:inline;background:none;border:none;padding:0 0 0 var(--mrd-space-1);cursor:pointer;color:var(--mrd-color-primary);font-size:var(--mrd-font-size-sm);font-family:inherit;line-height:inherit;vertical-align:middle}.mrd-table__textblock-btn.sc-mrd-table:hover{color:var(--mrd-color-primary-dark)}.mrd-table__modal-backdrop.sc-mrd-table{position:fixed;inset:0;background:rgba(0, 0, 0, 0.4);z-index:var(--mrd-z-modal, 300);display:flex;align-items:center;justify-content:center}.mrd-table__modal.sc-mrd-table{background:#fff;border-radius:var(--mrd-radius-md, 0.5rem);padding:var(--mrd-space-6);max-width:min(600px, 90vw);max-height:70vh;overflow-y:auto;position:relative;box-shadow:var(--mrd-shadow-lg)}.mrd-table__modal-close.sc-mrd-table{position:absolute;top:var(--mrd-space-3);right:var(--mrd-space-3);background:none;border:none;cursor:pointer;font-size:1.25rem;line-height:1;color:var(--mrd-color-text-muted, #6b7280);padding:0}.mrd-table__modal-close.sc-mrd-table:hover{color:var(--mrd-color-text, #111827)}.mrd-table__modal-text.sc-mrd-table{margin:0;padding-right:var(--mrd-space-6);white-space:pre-wrap;word-break:break-word;font-size:var(--mrd-font-size-sm);line-height:1.6}.mrd-table__json-preview.sc-mrd-table{font-family:var(--mrd-font-family-mono);font-size:var(--mrd-font-size-xs);overflow:hidden;white-space:nowrap;text-overflow:ellipsis;display:inline-block;max-width:calc(100% - 1.5rem);vertical-align:middle}.mrd-table__modal-json.sc-mrd-table{margin:0;padding-right:var(--mrd-space-6);font-family:var(--mrd-font-family-mono);font-size:var(--mrd-font-size-xs);white-space:pre-wrap;word-break:break-word;line-height:1.6;background:none;border:none}@keyframes mrd-shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}`;
6664
+ const mrdTableCss = () => `.sc-mrd-table-h{display:block;width:100%}.mrd-table.sc-mrd-table{overflow-x:auto}.mrd-table__scroll.sc-mrd-table{overflow-y:auto;overflow-x:auto;border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);overflow-anchor:none}.mrd-table__table.sc-mrd-table{width:auto;min-width:100%;border-collapse:collapse;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-900)}.mrd-table__scroll.sc-mrd-table .mrd-table__table.sc-mrd-table{min-width:max-content}.mrd-table__header.sc-mrd-table{position:sticky;top:0;z-index:1;background:var(--mrd-color-white);text-align:left;padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:2px solid var(--mrd-border-color);color:var(--mrd-color-neutral-600);font-weight:var(--mrd-font-weight-medium);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:var(--mrd-font-size-xs);text-transform:uppercase;letter-spacing:0.04em}.mrd-table__header--sortable.sc-mrd-table{cursor:pointer;user-select:none}.mrd-table__header--sortable.sc-mrd-table:hover{background:var(--mrd-color-neutral-50);color:var(--mrd-color-neutral-800)}.mrd-table__header--sorted-asc.sc-mrd-table,.mrd-table__header--sorted-desc.sc-mrd-table{color:var(--mrd-color-primary);border-bottom-color:var(--mrd-color-primary)}.mrd-table__header--filtered.sc-mrd-table{color:var(--mrd-color-primary);border-bottom-color:var(--mrd-color-primary)}.mrd-table__header-label.sc-mrd-table{margin-right:var(--mrd-space-1)}.mrd-table__col-resizer.sc-mrd-table{position:absolute;top:0;right:0;width:9px;height:100%;cursor:col-resize;touch-action:none;user-select:none}.mrd-table__col-resizer.sc-mrd-table::after{content:"";position:absolute;top:25%;right:4px;width:1px;height:50%;background:var(--mrd-border-color)}.mrd-table__col-resizer.sc-mrd-table:hover::after{width:2px;right:3px;background:var(--mrd-color-primary)}.mrd-table__col-resizer--active.sc-mrd-table::after{width:2px;right:3px;height:100%;top:0;background:var(--mrd-color-primary)}.mrd-table--resizing.sc-mrd-table{cursor:col-resize;user-select:none}.mrd-table__sort-icon.sc-mrd-table{font-size:0.85rem;opacity:0.4;vertical-align:middle}.mrd-table__header--sorted-asc.sc-mrd-table .mrd-table__sort-icon.sc-mrd-table,.mrd-table__header--sorted-desc.sc-mrd-table .mrd-table__sort-icon.sc-mrd-table{opacity:1;color:var(--mrd-color-primary)}.mrd-table__filter-icon.sc-mrd-table{display:inline-flex;align-items:center;vertical-align:middle;margin-left:var(--mrd-space-1);color:var(--mrd-color-primary)}.mrd-table__row.sc-mrd-table{border-bottom:1px solid var(--mrd-border-color)}.mrd-table__row.sc-mrd-table:hover{background:var(--mrd-color-neutral-200) !important}.mrd-table__row--clickable.sc-mrd-table{cursor:pointer}.mrd-table__row--loading.sc-mrd-table{background:transparent}.mrd-table__row--failed.sc-mrd-table{background:transparent}.mrd-table__spacer.sc-mrd-table{border:none}.mrd-table__spacer.sc-mrd-table td.sc-mrd-table{padding:0;border:none}.mrd-table__cell.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);vertical-align:top;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mrd-table__cell--numeric.sc-mrd-table{text-align:right;font-variant-numeric:tabular-nums}.mrd-table__cell--placeholder.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:1px solid var(--mrd-border-color)}.mrd-table__cell--failed.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:1px solid var(--mrd-border-color)}.mrd-table__placeholder-bar.sc-mrd-table{display:block;height:0.75rem;width:55%;border-radius:var(--mrd-border-radius-sm);background:linear-gradient(90deg, var(--mrd-color-neutral-200) 25%, var(--mrd-color-neutral-100) 50%, var(--mrd-color-neutral-200) 75%);background-size:200% 100%;animation:mrd-shimmer 1.4s ease infinite}.mrd-table__retry-button.sc-mrd-table{border:none;background:none;padding:0;color:var(--mrd-color-danger);font-size:inherit;cursor:pointer;text-decoration:underline}.mrd-table__toolbar.sc-mrd-table{display:flex;align-items:center;justify-content:space-between;padding-bottom:var(--mrd-space-2)}.mrd-table__toolbar-left.sc-mrd-table,.mrd-table__toolbar-right.sc-mrd-table{display:flex;gap:var(--mrd-space-2);align-items:center}.mrd-table__toolbar-center.sc-mrd-table{flex:1;display:flex;justify-content:center;align-items:center;gap:var(--mrd-space-1)}.mrd-table__view-switcher.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1)}.mrd-table__view-arrow.sc-mrd-table{background:none;border:none;cursor:pointer;padding:0 var(--mrd-space-1);color:var(--mrd-color-neutral-500);font-size:var(--mrd-font-size-xs);line-height:1}.mrd-table__view-arrow.sc-mrd-table:hover{color:var(--mrd-color-neutral-800)}.mrd-table__view-title-wrap.sc-mrd-table{position:relative}.mrd-table__view-title.sc-mrd-table{font-size:var(--mrd-font-size-sm);font-weight:600;color:var(--mrd-color-neutral-800);font-family:var(--mrd-font-family);background:none;border:none;outline:none;cursor:pointer;padding:0 var(--mrd-space-1);max-width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mrd-table__view-title.sc-mrd-table:hover{color:var(--mrd-color-primary)}.mrd-table__view-popover.sc-mrd-table{position:absolute;top:calc(100% + var(--mrd-space-1));left:50%;transform:translateX(-50%);background:var(--mrd-color-white);border:1px solid var(--mrd-color-neutral-200);border-radius:var(--mrd-radius-md);box-shadow:var(--mrd-shadow-md);z-index:100;min-width:160px;padding:var(--mrd-space-1) 0}.mrd-table__view-popover-item.sc-mrd-table{display:block;width:100%;text-align:left;background:none;border:none;cursor:pointer;padding:var(--mrd-space-2) var(--mrd-space-3);font-size:var(--mrd-font-size-sm);font-family:var(--mrd-font-family);color:var(--mrd-color-neutral-700);white-space:nowrap}.mrd-table__view-popover-item.sc-mrd-table:hover{background:var(--mrd-color-neutral-50)}.mrd-table__view-popover-item--active.sc-mrd-table{font-weight:600;color:var(--mrd-color-primary)}.mrd-table__action.sc-mrd-table{position:relative;display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;background:transparent;border:1px solid transparent;border-radius:var(--mrd-border-radius);cursor:pointer;color:var(--mrd-color-neutral-400);transition:background-color 0.15s, border-color 0.15s, color 0.15s}.mrd-table__action.sc-mrd-table:hover{background-color:var(--mrd-color-neutral-100);border-color:var(--mrd-color-neutral-300);color:var(--mrd-color-neutral-700)}.mrd-table__action.sc-mrd-table:hover .mrd-table__action-tooltip.sc-mrd-table{display:block}.mrd-table__action.sc-mrd-table:disabled{opacity:0.4;cursor:not-allowed}.mrd-table__action--primary.sc-mrd-table{color:var(--mrd-color-neutral-500)}.mrd-table__action--primary.sc-mrd-table:hover{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__action--danger.sc-mrd-table{color:var(--mrd-color-error)}.mrd-table__action--danger.sc-mrd-table:hover{background-color:var(--mrd-color-error-light, #fef2f2);border-color:var(--mrd-color-error)}.mrd-table__action-icon.sc-mrd-table{width:1.25rem;height:1.25rem;pointer-events:none;fill:currentColor}.mrd-table__action-tooltip.sc-mrd-table{display:none;position:absolute;bottom:calc(100% + 6px);right:0;padding:var(--mrd-space-1) var(--mrd-space-2);font-size:var(--mrd-font-size-xs);white-space:nowrap;background:var(--mrd-color-tooltip, #fffce1);color:var(--mrd-color-neutral-900);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-sm, var(--mrd-border-radius));pointer-events:none;z-index:10}.mrd-table__search-box.sc-mrd-table{display:inline-flex;align-items:center;gap:var(--mrd-space-1);height:2rem;padding:0 var(--mrd-space-2);border:1px solid var(--mrd-border-color-focus, var(--mrd-color-primary));border-radius:var(--mrd-border-radius);background:var(--mrd-color-white, #fff);box-shadow:var(--mrd-shadow-focus, none);color:var(--mrd-color-neutral-400)}.mrd-table__search-input.sc-mrd-table{border:none;outline:none;background:transparent;font-size:var(--mrd-font-size-sm);font-family:var(--mrd-font-family);color:var(--mrd-color-neutral-800);width:12rem}.mrd-table__search-clear.sc-mrd-table{display:inline-flex;align-items:center;justify-content:center;background:none;border:none;padding:0;cursor:pointer;color:var(--mrd-color-neutral-400);font-size:var(--mrd-font-size-xs);line-height:1}.mrd-table__search-clear.sc-mrd-table:hover{color:var(--mrd-color-neutral-700)}.mrd-table__create-picker-wrap.sc-mrd-table{position:relative}.mrd-table__create-picker.sc-mrd-table{position:absolute;right:0;top:calc(100% + 4px);background:var(--mrd-color-white, #fff);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);box-shadow:var(--mrd-shadow-md, 0 4px 12px rgba(0, 0, 0, 0.12));z-index:10;min-width:10rem;padding:var(--mrd-space-1) 0}.mrd-table__create-picker-item.sc-mrd-table{display:block;width:100%;text-align:left;padding:var(--mrd-space-2) var(--mrd-space-3);background:none;border:none;cursor:pointer;font-size:var(--mrd-font-size-sm);font-family:var(--mrd-font-family);color:var(--mrd-color-neutral-800)}.mrd-table__create-picker-item.sc-mrd-table:hover{background:var(--mrd-color-neutral-50);color:var(--mrd-color-neutral-900)}.mrd-table__filter-clear.sc-mrd-table{width:auto;gap:var(--mrd-space-1);padding:0 var(--mrd-space-2);color:var(--mrd-color-primary);border-color:var(--mrd-color-primary)}.mrd-table__filter-clear.sc-mrd-table:hover{color:var(--mrd-color-primary);border-color:var(--mrd-color-primary)}.mrd-table__filter-clear-label.sc-mrd-table{font-size:var(--mrd-font-size-sm);white-space:nowrap}.mrd-table__filter-popup.sc-mrd-table{position:fixed;width:280px;background:var(--mrd-color-white);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);box-shadow:var(--mrd-shadow-md, 0 4px 12px rgba(0, 0, 0, 0.12));z-index:var(--mrd-z-dropdown, 200);font-size:var(--mrd-font-size-sm)}.mrd-table__filter-popup-header.sc-mrd-table{display:flex;align-items:center;justify-content:space-between;padding:var(--mrd-space-2) var(--mrd-space-3);border-bottom:1px solid var(--mrd-border-color)}.mrd-table__filter-popup-title.sc-mrd-table{font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-800);font-size:var(--mrd-font-size-sm)}.mrd-table__filter-close.sc-mrd-table{background:transparent;border:none;cursor:pointer;color:var(--mrd-color-neutral-500);font-size:0.9rem;padding:2px 4px;border-radius:3px;line-height:1}.mrd-table__filter-close.sc-mrd-table:hover{background:var(--mrd-color-neutral-100);color:var(--mrd-color-neutral-800)}.mrd-table__filter-section.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-3)}.mrd-table__filter-section-label.sc-mrd-table{font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-medium);text-transform:uppercase;letter-spacing:0.04em;color:var(--mrd-color-neutral-500);margin-bottom:var(--mrd-space-2)}.mrd-table__filter-sort-buttons.sc-mrd-table{display:flex;gap:var(--mrd-space-2)}.mrd-table__filter-sort-btn.sc-mrd-table{flex:1;padding:var(--mrd-space-1) var(--mrd-space-2);background:transparent;border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);cursor:pointer;font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-700)}.mrd-table__filter-sort-btn.sc-mrd-table:hover{background:var(--mrd-color-neutral-100)}.mrd-table__filter-sort-btn--active.sc-mrd-table{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__filter-divider.sc-mrd-table{height:1px;background:var(--mrd-border-color);margin:0}.mrd-table__filter-editor.sc-mrd-table{display:flex;flex-direction:column;gap:var(--mrd-space-2)}.mrd-table__filter-select.sc-mrd-table,.mrd-table__filter-input.sc-mrd-table{width:100%;padding:var(--mrd-space-1) var(--mrd-space-2);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-900);background:var(--mrd-color-white);box-sizing:border-box}.mrd-table__filter-select.sc-mrd-table:focus,.mrd-table__filter-input.sc-mrd-table:focus{outline:none;border-color:var(--mrd-color-primary);box-shadow:0 0 0 2px rgba(0, 0, 0, 0.06)}.mrd-table__filter-range.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1)}.mrd-table__filter-range.sc-mrd-table .mrd-table__filter-input.sc-mrd-table{flex:1;min-width:0}.mrd-table__filter-range--stacked.sc-mrd-table{flex-direction:column;align-items:stretch;gap:var(--mrd-space-2)}.mrd-table__filter-range-sep.sc-mrd-table{color:var(--mrd-color-neutral-400);flex-shrink:0}.mrd-table__filter-range-label.sc-mrd-table{font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);margin-bottom:2px}.mrd-table__filter-radio-group.sc-mrd-table{display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-table__filter-radio-group--inline.sc-mrd-table{flex-direction:row;gap:var(--mrd-space-3)}.mrd-table__filter-radio-label.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1);cursor:pointer;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800)}.mrd-table__filter-list.sc-mrd-table{display:flex;flex-direction:column;gap:var(--mrd-space-1);max-height:180px;overflow-y:auto}.mrd-table__filter-list-controls.sc-mrd-table{display:flex;gap:var(--mrd-space-2);margin-bottom:var(--mrd-space-1)}.mrd-table__filter-list-btn.sc-mrd-table{font-size:var(--mrd-font-size-xs);color:var(--mrd-color-primary);background:transparent;border:none;cursor:pointer;padding:0;text-decoration:underline}.mrd-table__filter-checkbox-label.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1);cursor:pointer;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800)}.mrd-table__filter-no-support.sc-mrd-table{font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-500);margin:0;font-style:italic}.mrd-table__filter-popup-footer.sc-mrd-table{display:flex;justify-content:flex-end;gap:var(--mrd-space-2);padding:var(--mrd-space-2) var(--mrd-space-3);border-top:1px solid var(--mrd-border-color)}.mrd-table__filter-btn.sc-mrd-table{padding:var(--mrd-space-1) var(--mrd-space-3);border-radius:var(--mrd-border-radius);border:1px solid var(--mrd-border-color);font-size:var(--mrd-font-size-sm);cursor:pointer}.mrd-table__filter-btn--clear.sc-mrd-table{background:transparent;color:var(--mrd-color-neutral-600)}.mrd-table__filter-btn--clear.sc-mrd-table:hover{background:var(--mrd-color-neutral-100)}.mrd-table__filter-btn--apply.sc-mrd-table{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__filter-btn--apply.sc-mrd-table:hover{background:var(--mrd-color-primary-dark, var(--mrd-color-primary));border-color:var(--mrd-color-primary-dark, var(--mrd-color-primary))}.mrd-table__totals-row.sc-mrd-table{border-top:2px solid var(--mrd-border-color)}.mrd-table__totals-cell.sc-mrd-table{position:sticky;bottom:0;z-index:2;padding:var(--mrd-space-2) var(--mrd-space-4);background:var(--mrd-color-white);font-weight:var(--mrd-font-weight-medium);font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;border-top:2px solid var(--mrd-border-color)}.mrd-table__totals-cell--numeric.sc-mrd-table{text-align:right}.mrd-table__footer.sc-mrd-table{padding:var(--mrd-space-1) var(--mrd-space-2);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);text-align:right}.mrd-table__empty.sc-mrd-table{padding:var(--mrd-space-4) var(--mrd-space-3);color:var(--mrd-color-neutral-500);font-size:var(--mrd-font-size-sm);text-align:center;margin:0}.mrd-table__file-btn.sc-mrd-table{display:inline-flex;align-items:center;gap:var(--mrd-space-1);background:none;border:none;padding:0;cursor:pointer;color:var(--mrd-color-primary);font-size:var(--mrd-font-size-sm);font-family:inherit;max-width:100%;overflow:hidden}.mrd-table__file-btn.sc-mrd-table:hover{text-decoration:underline;color:var(--mrd-color-primary-dark)}.mrd-table__file-icon.sc-mrd-table{flex-shrink:0;width:1rem;height:1rem}.mrd-table__textblock-btn.sc-mrd-table{display:inline;background:none;border:none;padding:0 0 0 var(--mrd-space-1);cursor:pointer;color:var(--mrd-color-primary);font-size:var(--mrd-font-size-sm);font-family:inherit;line-height:inherit;vertical-align:middle}.mrd-table__textblock-btn.sc-mrd-table:hover{color:var(--mrd-color-primary-dark)}.mrd-table__modal-backdrop.sc-mrd-table{position:fixed;inset:0;background:rgba(0, 0, 0, 0.4);z-index:var(--mrd-z-modal, 300);display:flex;align-items:center;justify-content:center}.mrd-table__modal.sc-mrd-table{background:#fff;border-radius:var(--mrd-radius-md, 0.5rem);padding:var(--mrd-space-6);max-width:min(600px, 90vw);max-height:70vh;overflow-y:auto;position:relative;box-shadow:var(--mrd-shadow-lg)}.mrd-table__modal-close.sc-mrd-table{position:absolute;top:var(--mrd-space-3);right:var(--mrd-space-3);background:none;border:none;cursor:pointer;font-size:1.25rem;line-height:1;color:var(--mrd-color-text-muted, #6b7280);padding:0}.mrd-table__modal-close.sc-mrd-table:hover{color:var(--mrd-color-text, #111827)}.mrd-table__modal-text.sc-mrd-table{margin:0;padding-right:var(--mrd-space-6);white-space:pre-wrap;word-break:break-word;font-size:var(--mrd-font-size-sm);line-height:1.6}.mrd-table__json-preview.sc-mrd-table{font-family:var(--mrd-font-family-mono);font-size:var(--mrd-font-size-xs);overflow:hidden;white-space:nowrap;text-overflow:ellipsis;display:inline-block;max-width:calc(100% - 1.5rem);vertical-align:middle}.mrd-table__modal-json.sc-mrd-table{margin:0;padding-right:var(--mrd-space-6);font-family:var(--mrd-font-family-mono);font-size:var(--mrd-font-size-xs);white-space:pre-wrap;word-break:break-word;line-height:1.6;background:none;border:none}@keyframes mrd-shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}`;
6612
6665
 
6613
6666
  /** How often (ms) to scan outstanding page requests for staleness. */
6614
6667
  const STALE_CHECK_INTERVAL_MS = 2000;
@@ -6639,6 +6692,17 @@ const MrdTable = class {
6639
6692
  this.keydownHandler = null;
6640
6693
  this.createPickerClickHandler = null;
6641
6694
  this.viewPopoverClickHandler = null;
6695
+ /** Debounce timer for the free-text search box — separate from debounceTimer
6696
+ * (pending-page requests), since typing and scrolling debounce independently. */
6697
+ this.searchDebounceTimer = null;
6698
+ /** The rendered search <input>, captured so it can be focused the instant it mounts. */
6699
+ this.searchInputEl = null;
6700
+ /** Set by toggleSearch() when the box just expanded; consumed and cleared in componentDidRender(). */
6701
+ this.searchNeedsFocus = false;
6702
+ /** Column filters stashed by stashFiltersForSearch() while the search box is open — the
6703
+ * backend can't combine `q` with column filters. Restored by restoreFiltersAfterSearch()
6704
+ * on close, unless the user applied a fresh filter of their own in the meantime. */
6705
+ this.stashedFilters = null;
6642
6706
  /** Watches the host for gaining a box (e.g. its tab pane being shown) — see componentDidLoad. */
6643
6707
  this.resizeObserver = null;
6644
6708
  /** Guards against scheduling more than one column-width measurement per freeze. */
@@ -6673,6 +6737,10 @@ const MrdTable = class {
6673
6737
  /** Time (ms) to wait for setPage() before retrying a page request; after
6674
6738
  * MAX_RETRY_ATTEMPTS retries the page is marked failed (see failedPages). */
6675
6739
  this.requestTimeoutMs = REQUEST_TIMEOUT_MS;
6740
+ /** When true, the toolbar's create ("+") action is disabled (with a tooltip
6741
+ * explaining why) so a viewer-role user can see at a glance that this dashboard
6742
+ * is read-only. Sorting, filtering and export stay available — those don't mutate data. */
6743
+ this.readOnly = false;
6676
6744
  // ── Internal state ─────────────────────────────────────────────────────────
6677
6745
  /** Index into allViews[] for the currently displayed view. 0 = primary, 1+ = alternatives. */
6678
6746
  this.activeViewIdx = 0;
@@ -6689,6 +6757,10 @@ const MrdTable = class {
6689
6757
  this.sortDir = 'asc';
6690
6758
  /** Active filters keyed by field name. */
6691
6759
  this.activeFilters = new Map();
6760
+ /** True while the toolbar's magnifying glass is expanded into the search input. */
6761
+ this.searchOpen = false;
6762
+ /** Current free-text search query — sent as `q` on every mrdLoadPage/aggregations request. */
6763
+ this.searchQuery = '';
6692
6764
  /** Field name of the currently open filter popup (null = closed). */
6693
6765
  this.openFilterCol = null;
6694
6766
  /** Filter state being edited in the open popup. */
@@ -6742,6 +6814,11 @@ const MrdTable = class {
6742
6814
  this.colWidthMeasureScheduled = false;
6743
6815
  this.colWidthsUserSet = false;
6744
6816
  this.fixedContentMeasured = false;
6817
+ // A new item is a different table (possibly not even a VIEW any more) — a leftover
6818
+ // query from the old one should not silently keep filtering it.
6819
+ this.searchOpen = false;
6820
+ this.searchQuery = '';
6821
+ this.stashedFilters = null;
6745
6822
  }
6746
6823
  // ── Lifecycle ──────────────────────────────────────────────────────────────
6747
6824
  componentWillLoad() {
@@ -6849,7 +6926,12 @@ const MrdTable = class {
6849
6926
  if (pageNumber === 0 && this.aggregationsPending) {
6850
6927
  this.aggregationsPending = false;
6851
6928
  const hasAggColumns = this.columns.some(c => c.type === 'FIELD' && c.aggregate);
6852
- if (!isLastPage || hasAggColumns) {
6929
+ // The aggregations endpoint doesn't support the `q` free-text param, so a request
6930
+ // sent while searching would silently return unfiltered totals. Leave aggregations
6931
+ // (and aggregationsTotal) at null instead — TotalsRow already renders nothing when
6932
+ // aggregations is null, so the totals row just disappears for the duration of the
6933
+ // search rather than showing numbers that don't match the filtered rows.
6934
+ if (!this.searchQuery && (!isLastPage || hasAggColumns)) {
6853
6935
  this.emitLoadAggregations();
6854
6936
  }
6855
6937
  }
@@ -6888,10 +6970,18 @@ const MrdTable = class {
6888
6970
  document.removeEventListener('click', this.viewPopoverClickHandler);
6889
6971
  this.viewPopoverClickHandler = null;
6890
6972
  }
6973
+ if (this.searchDebounceTimer !== null) {
6974
+ clearTimeout(this.searchDebounceTimer);
6975
+ this.searchDebounceTimer = null;
6976
+ }
6891
6977
  }
6892
6978
  componentDidRender() {
6893
6979
  this.freezeColWidths();
6894
6980
  this.growToFixedContent();
6981
+ if (this.searchNeedsFocus && this.searchInputEl) {
6982
+ this.searchInputEl.focus();
6983
+ this.searchNeedsFocus = false;
6984
+ }
6895
6985
  }
6896
6986
  /** Freeze the column widths once the first data page has rendered.
6897
6987
  *
@@ -7210,7 +7300,13 @@ const MrdTable = class {
7210
7300
  dataClass: v.dataClass,
7211
7301
  });
7212
7302
  }
7213
- /** Build query params for a page request from current sort, view filters, filterClass and active column filters. */
7303
+ /** Build query params for a page request from current sort, view filters, filterClass and active column filters.
7304
+ *
7305
+ * `q` and column filters are mutually exclusive on the backend — combining them breaks
7306
+ * the search. stashFiltersForSearch() already empties activeFilters for the duration of
7307
+ * a search, but this guard is the actual guarantee: even if a filter is applied through
7308
+ * a column header while the search box is still open (before the query is cleared),
7309
+ * activeFilters is dropped from the request rather than sent alongside `q`. */
7214
7310
  buildQueryParams(page) {
7215
7311
  var _a;
7216
7312
  const v = this.allViews[this.activeViewIdx];
@@ -7219,7 +7315,8 @@ const MrdTable = class {
7219
7315
  sort: this.sortParam(),
7220
7316
  filterClass: v === null || v === void 0 ? void 0 : v.filterClass,
7221
7317
  viewFilters: (_a = v === null || v === void 0 ? void 0 : v.view) === null || _a === void 0 ? void 0 : _a.filter,
7222
- activeFilters: this.activeFilters.values(),
7318
+ activeFilters: this.searchQuery ? [] : this.activeFilters.values(),
7319
+ query: this.searchQuery,
7223
7320
  });
7224
7321
  }
7225
7322
  /** True when the table is in paginated / virtual-scroll mode rather than driven by the
@@ -7242,7 +7339,7 @@ const MrdTable = class {
7242
7339
  const raw = (_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.actions) !== null && _b !== void 0 ? _b : [];
7243
7340
  return (raw !== null && raw !== void 0 ? raw : []).reduce((acc, a) => {
7244
7341
  if (a === 'NEW')
7245
- acc.push({ action: 'create', label: t('table_new_record', this.locale), icon: 'assets/sprites.svg#icon-plus', variant: 'primary' });
7342
+ acc.push({ action: 'create', label: t('table_new_record', this.locale), icon: 'assets/sprites.svg#icon-plus', variant: 'primary', disabled: this.readOnly });
7246
7343
  if (a === 'EXPORT')
7247
7344
  acc.push({ action: 'export', label: t('table_export_excel', this.locale), icon: 'assets/sprites.svg#icon-file-excel' });
7248
7345
  return acc;
@@ -7525,6 +7622,18 @@ const MrdTable = class {
7525
7622
  const current = (_b = (_a = this.pendingFilter) === null || _a === void 0 ? void 0 : _a.values) !== null && _b !== void 0 ? _b : [];
7526
7623
  this.pendingFilter = Object.assign(Object.assign({}, this.pendingFilter), { values: checked ? [...current, key] : current.filter(k => k !== key) });
7527
7624
  }
7625
+ /** Common reload after activeFilters or searchQuery changed: drop stale aggregations
7626
+ * (the next setPage(0) re-requests them, guarded against `q` in setPage() itself) and
7627
+ * re-fetch page 0. Shared by the filter popup, clear-all, and free-text search. */
7628
+ reloadAfterQueryChange() {
7629
+ this.aggregations = null;
7630
+ this.aggregationsTotal = null;
7631
+ this.aggregationsPending = true;
7632
+ if (this.isPaginated) {
7633
+ this.resetPages();
7634
+ this.emitPagesForWindow(this.renderStart, this.renderEnd);
7635
+ }
7636
+ }
7528
7637
  applyFilter() {
7529
7638
  const f = this.pendingFilter;
7530
7639
  if (!(f === null || f === void 0 ? void 0 : f.field)) {
@@ -7541,13 +7650,7 @@ const MrdTable = class {
7541
7650
  }
7542
7651
  this.activeFilters = next;
7543
7652
  this.closeFilterPopup();
7544
- this.aggregations = null;
7545
- this.aggregationsTotal = null;
7546
- this.aggregationsPending = true;
7547
- if (this.isPaginated) {
7548
- this.resetPages();
7549
- this.emitPagesForWindow(this.renderStart, this.renderEnd);
7550
- }
7653
+ this.reloadAfterQueryChange();
7551
7654
  }
7552
7655
  clearFilter() {
7553
7656
  const name = this.openFilterCol;
@@ -7556,24 +7659,81 @@ const MrdTable = class {
7556
7659
  next.delete(name);
7557
7660
  this.activeFilters = next;
7558
7661
  this.closeFilterPopup();
7559
- this.aggregations = null;
7560
- this.aggregationsTotal = null;
7561
- this.aggregationsPending = true;
7562
- if (this.isPaginated) {
7563
- this.resetPages();
7564
- this.emitPagesForWindow(this.renderStart, this.renderEnd);
7565
- }
7662
+ this.reloadAfterQueryChange();
7566
7663
  }
7567
7664
  clearAllFilters() {
7568
7665
  this.activeFilters = new Map();
7569
- this.aggregations = null;
7570
- this.aggregationsTotal = null;
7571
- this.aggregationsPending = true;
7572
- if (this.isPaginated) {
7573
- this.resetPages();
7574
- this.emitPagesForWindow(this.renderStart, this.renderEnd);
7666
+ this.reloadAfterQueryChange();
7667
+ }
7668
+ // ── Free-text search ───────────────────────────────────────────────────────
7669
+ /** Search is a VIEW-only affordance — a RELATED_VIEW table is already scoped to
7670
+ * its parent record, so a free-text box there would invite confusion about what
7671
+ * it searches across. */
7672
+ get searchEnabled() {
7673
+ var _a;
7674
+ return ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'VIEW';
7675
+ }
7676
+ toggleSearch() {
7677
+ if (this.searchOpen) {
7678
+ this.closeSearch();
7679
+ }
7680
+ else {
7681
+ this.searchOpen = true;
7682
+ this.searchNeedsFocus = true;
7683
+ this.stashFiltersForSearch();
7575
7684
  }
7576
7685
  }
7686
+ /** Collapses the box back to the icon. Clearing a non-empty query and restoring any
7687
+ * stashed filters can each independently require a reload — reloadAfterQueryChange()
7688
+ * is called at most once here regardless of how many of the two actually changed. */
7689
+ closeSearch() {
7690
+ this.searchOpen = false;
7691
+ if (this.searchDebounceTimer !== null) {
7692
+ clearTimeout(this.searchDebounceTimer);
7693
+ this.searchDebounceTimer = null;
7694
+ }
7695
+ const hadQuery = this.searchQuery !== '';
7696
+ this.searchQuery = '';
7697
+ const filtersRestored = this.restoreFiltersAfterSearch();
7698
+ if (hadQuery || filtersRestored)
7699
+ this.reloadAfterQueryChange();
7700
+ }
7701
+ handleSearchInput(value) {
7702
+ this.searchQuery = value;
7703
+ if (this.searchDebounceTimer !== null)
7704
+ clearTimeout(this.searchDebounceTimer);
7705
+ this.searchDebounceTimer = setTimeout(() => this.applySearch(), SEARCH_DEBOUNCE_MS);
7706
+ }
7707
+ /** Reloads from page 0 with the current searchQuery, same reset as applyFilter(). */
7708
+ applySearch() {
7709
+ this.searchDebounceTimer = null;
7710
+ this.reloadAfterQueryChange();
7711
+ }
7712
+ /** Column filters and the free-text `q` param are mutually exclusive on the backend —
7713
+ * sending both breaks the search. Opening the search box stashes any active filters
7714
+ * and clears them (the header filter icons and the clear-all button disappear along
7715
+ * with activeFilters, so there is nothing extra to hide) and reloads unfiltered. */
7716
+ stashFiltersForSearch() {
7717
+ if (this.activeFilters.size === 0)
7718
+ return;
7719
+ this.stashedFilters = this.activeFilters;
7720
+ this.activeFilters = new Map();
7721
+ this.reloadAfterQueryChange();
7722
+ }
7723
+ /** Restores filters stashed by stashFiltersForSearch(), unless the user applied a fresh
7724
+ * filter of their own while the search box was open — that explicit choice wins over
7725
+ * reinstating the old one. Returns whether activeFilters actually changed, so the
7726
+ * caller can decide whether a reload is needed. */
7727
+ restoreFiltersAfterSearch() {
7728
+ if (!this.stashedFilters)
7729
+ return false;
7730
+ const stashed = this.stashedFilters;
7731
+ this.stashedFilters = null;
7732
+ if (this.activeFilters.size > 0)
7733
+ return false;
7734
+ this.activeFilters = stashed;
7735
+ return true;
7736
+ }
7577
7737
  // ── View switcher ──────────────────────────────────────────────────────────
7578
7738
  handleViewSwitch(targetIdx) {
7579
7739
  var _a, _b;
@@ -7583,6 +7743,9 @@ const MrdTable = class {
7583
7743
  this.activeViewIdx = targetIdx;
7584
7744
  this.applyDefaultSort((_b = (_a = target.view) === null || _a === void 0 ? void 0 : _a.defaultSort) !== null && _b !== void 0 ? _b : '');
7585
7745
  this.activeFilters = new Map();
7746
+ this.searchOpen = false;
7747
+ this.searchQuery = '';
7748
+ this.stashedFilters = null;
7586
7749
  this.init();
7587
7750
  }
7588
7751
  toggleViewPopover(e) {
@@ -7605,7 +7768,7 @@ const MrdTable = class {
7605
7768
  // ── Render: toolbar ────────────────────────────────────────────────────────
7606
7769
  renderToolbar() {
7607
7770
  var _a;
7608
- return (h(Toolbar, { locale: this.locale, filterCount: this.activeFilters.size, actions: this.tableActions, views: this.allViews, activeViewIdx: this.activeViewIdx, viewPopoverOpen: this.viewPopoverOpen, createPickerOpen: this.createPickerOpen, createTypes: (_a = this.item) === null || _a === void 0 ? void 0 : _a.createTypes, cb: {
7771
+ return (h(Toolbar, { locale: this.locale, filterCount: this.activeFilters.size, actions: this.tableActions, views: this.allViews, activeViewIdx: this.activeViewIdx, viewPopoverOpen: this.viewPopoverOpen, createPickerOpen: this.createPickerOpen, createTypes: (_a = this.item) === null || _a === void 0 ? void 0 : _a.createTypes, readOnly: this.readOnly, searchEnabled: this.searchEnabled, searchOpen: this.searchOpen, searchQuery: this.searchQuery, cb: {
7609
7772
  onClearAllFilters: () => this.clearAllFilters(),
7610
7773
  onViewSwitch: idx => this.handleViewSwitch(idx),
7611
7774
  onToggleViewPopover: e => this.toggleViewPopover(e),
@@ -7616,6 +7779,10 @@ const MrdTable = class {
7616
7779
  this.closeCreatePicker();
7617
7780
  },
7618
7781
  onAction: action => this.mrdAction.emit(this.buildActionDetail(action)),
7782
+ onToggleSearch: () => this.toggleSearch(),
7783
+ onSearchInput: value => this.handleSearchInput(value),
7784
+ onCloseSearch: () => this.closeSearch(),
7785
+ onSearchInputRef: el => (this.searchInputEl = el !== null && el !== void 0 ? el : null),
7619
7786
  } }));
7620
7787
  }
7621
7788
  // ── Render: filter popup ───────────────────────────────────────────────────