@mmlogic/components 0.2.0 → 0.3.0

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.
@@ -1366,7 +1366,6 @@ const MrdLayoutSection = class {
1366
1366
  this.mrdNavigate = index.createEvent(this, "mrdNavigate");
1367
1367
  this.mrdSearch = index.createEvent(this, "mrdSearch");
1368
1368
  this.mrdDownload = index.createEvent(this, "mrdDownload");
1369
- this.mrdLoadView = index.createEvent(this, "mrdLoadView");
1370
1369
  this.mrdLoadViewPage = index.createEvent(this, "mrdLoadViewPage");
1371
1370
  this.mrdLoadImage = index.createEvent(this, "mrdLoadImage");
1372
1371
  this.mrdViewAction = index.createEvent(this, "mrdViewAction");
@@ -1375,24 +1374,19 @@ const MrdLayoutSection = class {
1375
1374
  this.items = [];
1376
1375
  /** Record data object; keys are field names, _links holds relation and related-view links. */
1377
1376
  this.data = {};
1378
- /** View metadata map (ClientDashboardMetadata.views) for RELATED_VIEW and VIEW items. */
1377
+ /** Legacy: view metadata map (ClientDashboardMetadata.views). Not needed in new flat format. */
1379
1378
  this.views = {};
1380
- /** Top-level _links from ClientDashboardMetadata; used to resolve hrefs for VIEW items. */
1379
+ /** Legacy: top-level _links from ClientDashboardMetadata. Not needed in new flat format. */
1381
1380
  this.links = {};
1382
1381
  this.locale = navigator.language;
1383
1382
  this.searchQueryMap = {};
1384
1383
  this.searchResultsMap = {};
1385
1384
  this.imagePreviewUrl = null;
1386
1385
  this.imagePreviews = {};
1387
- this.activeViewMap = {};
1388
- this.viewLinksMap = {};
1389
- this.activeFiltersMap = {};
1390
1386
  this.searchTimers = {};
1391
1387
  this.handleViewLoadPage = (e, name) => {
1392
- var _a;
1393
1388
  e.stopPropagation();
1394
- const filters = (_a = this.activeFiltersMap[name]) !== null && _a !== void 0 ? _a : [];
1395
- this.mrdLoadViewPage.emit({ name, page: e.detail.page, sort: e.detail.sort, filters });
1389
+ this.mrdLoadViewPage.emit({ name, page: e.detail.page, sort: e.detail.sort, path: e.detail.path, qs: e.detail.qs });
1396
1390
  };
1397
1391
  this.handleSearchInput = (dataClass, query) => {
1398
1392
  this.searchQueryMap = Object.assign(Object.assign({}, this.searchQueryMap), { [dataClass]: query });
@@ -1409,59 +1403,29 @@ const MrdLayoutSection = class {
1409
1403
  }
1410
1404
  componentDidLoad() {
1411
1405
  setTimeout(() => {
1412
- this.emitLoadViews();
1406
+ this.initEmbeddedTables();
1413
1407
  this.emitLoadImages();
1414
1408
  }, 0);
1415
1409
  }
1416
- linksChanged(newVal) {
1417
- if (Object.keys(newVal !== null && newVal !== void 0 ? newVal : {}).length > 0) {
1418
- this.emitLoadViews();
1419
- }
1420
- }
1421
1410
  dataChanged(newVal) {
1422
- var _a;
1423
- if (newVal && Object.keys((_a = newVal === null || newVal === void 0 ? void 0 : newVal._links) !== null && _a !== void 0 ? _a : {}).length > 0) {
1424
- this.emitLoadViews();
1411
+ if (newVal && Object.keys(newVal).length > 0) {
1412
+ setTimeout(() => this.initEmbeddedTables(), 0);
1425
1413
  }
1426
1414
  }
1427
- resolveViewFilters(viewConfig) {
1428
- var _a;
1429
- return ((_a = viewConfig.filter) !== null && _a !== void 0 ? _a : []).map(f => {
1430
- var _a, _b, _c, _d;
1431
- const base = { field: f.name, dataType: 'TEXT' };
1432
- switch (f.operator) {
1433
- case 'FROM': return Object.assign(Object.assign({}, base), { from: (_a = f.value) !== null && _a !== void 0 ? _a : null });
1434
- case 'TO': return Object.assign(Object.assign({}, base), { to: (_b = f.value) !== null && _b !== void 0 ? _b : null });
1435
- case 'STARTS_WITH': return Object.assign(Object.assign({}, base), { operator: 'startsWith', value: (_c = f.value) !== null && _c !== void 0 ? _c : null });
1436
- case 'NOT_EMPTY': return Object.assign(Object.assign({}, base), { operator: 'isNotEmpty' });
1437
- case 'EMPTY': return Object.assign(Object.assign({}, base), { operator: 'isEmpty' });
1438
- default: return Object.assign(Object.assign({}, base), { operator: 'equals', value: (_d = f.value) !== null && _d !== void 0 ? _d : null });
1439
- }
1440
- });
1441
- }
1442
- emitLoadViews() {
1443
- var _a, _b, _c, _d, _e, _f, _g;
1444
- const dataLinks = ((_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a._links) !== null && _b !== void 0 ? _b : {});
1445
- for (const item of this.flattenItems(this.items)) {
1446
- if (item.type === index$1.ClientLayoutItemType.RELATED_VIEW && item.name) {
1447
- const viewConfig = this.views[item.name];
1448
- if (!viewConfig)
1449
- continue;
1450
- const href = (_d = dataLinks[(_c = item.relatedClass) !== null && _c !== void 0 ? _c : '']) === null || _d === void 0 ? void 0 : _d.href;
1451
- this.mrdLoadView.emit({ name: item.name, href, viewConfig, sort: (_e = viewConfig.defaultSort) !== null && _e !== void 0 ? _e : '', filters: this.resolveViewFilters(viewConfig) });
1452
- }
1453
- else if (item.type === index$1.ClientLayoutItemType.VIEW) {
1454
- const viewName = item.name;
1455
- if (!viewName)
1456
- continue;
1457
- const viewConfig = this.views[viewName];
1458
- if (!viewConfig)
1459
- continue;
1460
- const href = (_f = this.links[viewName]) === null || _f === void 0 ? void 0 : _f.href;
1461
- this.mrdLoadView.emit({ name: viewName, href, viewConfig, sort: (_g = viewConfig.defaultSort) !== null && _g !== void 0 ? _g : '', filters: this.resolveViewFilters(viewConfig) });
1415
+ async initEmbeddedTables() {
1416
+ const tables = this.el.querySelectorAll('mrd-table[data-view]');
1417
+ for (const table of Array.from(tables)) {
1418
+ if (typeof table.init === 'function') {
1419
+ await table.init();
1462
1420
  }
1463
1421
  }
1464
1422
  }
1423
+ viewKeyFor(item) {
1424
+ var _a, _b, _c, _d;
1425
+ if (item.type === index$1.ClientLayoutItemType.RELATED_VIEW)
1426
+ return (_b = (_a = item.relatedClass) !== null && _a !== void 0 ? _a : item.name) !== null && _b !== void 0 ? _b : '';
1427
+ return (_d = (_c = item.dataClass) !== null && _c !== void 0 ? _c : item.name) !== null && _d !== void 0 ? _d : '';
1428
+ }
1465
1429
  emitLoadImages() {
1466
1430
  for (const item of this.flattenItems(this.items)) {
1467
1431
  if (item.type === index$1.ClientLayoutItemType.FIELD && item.dataType === index$1.ClientLayoutItemFieldDataType.IMAGE) {
@@ -1491,19 +1455,14 @@ const MrdLayoutSection = class {
1491
1455
  }
1492
1456
  /**
1493
1457
  * Inject data into an embedded mrd-table for a RELATED_VIEW or VIEW item.
1494
- * Pass totalElements on page 0 to initialise the table; omit on subsequent pages.
1495
- * Pass pageLinks (_links from the page response) on page 0 to enable action hrefs in mrdViewAction.
1458
+ * Pass totalElements to update the pagination total (safe to pass on every page).
1496
1459
  */
1497
- async setViewPage(name, page, rows, totalElements, pageLinks) {
1498
- if (pageLinks) {
1499
- this.viewLinksMap = Object.assign(Object.assign({}, this.viewLinksMap), { [name]: pageLinks });
1500
- }
1460
+ async setViewPage(name, page, rows, totalElements) {
1501
1461
  const table = this.el.querySelector(`mrd-table[data-view="${name}"]`);
1502
1462
  if (!table)
1503
1463
  return;
1504
1464
  if (totalElements !== undefined) {
1505
1465
  table.totalElements = totalElements;
1506
- await table.init();
1507
1466
  }
1508
1467
  await table.setPage(page, rows);
1509
1468
  }
@@ -1639,63 +1598,36 @@ const MrdLayoutSection = class {
1639
1598
  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)))))))));
1640
1599
  }
1641
1600
  renderRelatedView(item) {
1642
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
1643
- const isRelated = item.type === index$1.ClientLayoutItemType.RELATED_VIEW;
1644
- const name = item.name;
1645
- if (!name)
1601
+ var _a, _b, _c, _d, _e, _f;
1602
+ const key = this.viewKeyFor(item);
1603
+ if (!key)
1646
1604
  return null;
1647
- const viewConfig = this.views[name];
1648
- if (!viewConfig)
1605
+ if (!item.view)
1649
1606
  return null;
1650
1607
  const showTitle = (_a = item.showTitle) !== null && _a !== void 0 ? _a : false;
1651
- const activeName = (_b = this.activeViewMap[name]) !== null && _b !== void 0 ? _b : name;
1652
- const activeViewConfig = (_c = this.views[activeName]) !== null && _c !== void 0 ? _c : viewConfig;
1653
- // Build the full view list (original + alternatives) so the switcher can always go back.
1654
- const originalLabel = (_f = (_e = (_d = viewConfig.pluralLabel) !== null && _d !== void 0 ? _d : viewConfig.singularLabel) !== null && _e !== void 0 ? _e : item.label) !== null && _f !== void 0 ? _f : name;
1655
- const allViews = [{ name, label: originalLabel }, ...((_g = item.alternativeViews) !== null && _g !== void 0 ? _g : [])];
1656
- const activeEntry = allViews.find(v => v.name === activeName);
1657
- const viewLabel = (_k = (_j = (_h = activeEntry === null || activeEntry === void 0 ? void 0 : activeEntry.label) !== null && _h !== void 0 ? _h : activeViewConfig.pluralLabel) !== null && _j !== void 0 ? _j : activeViewConfig.singularLabel) !== null && _k !== void 0 ? _k : '';
1658
- const altViews = allViews.filter(v => v.name !== activeName);
1659
- const rawActions = (_l = item.actions) !== null && _l !== void 0 ? _l : ['NEW', 'EXPORT'];
1660
- const tableActions = rawActions.reduce((acc, a) => {
1661
- if (a === 'NEW')
1662
- acc.push({ action: 'create', label: t('table_new_record', this.locale), icon: 'assets/sprites.svg#icon-plus', variant: 'primary' });
1663
- if (a === 'EXPORT')
1664
- acc.push({ action: 'export', label: t('table_export_excel', this.locale), icon: 'assets/sprites.svg#icon-file-excel' });
1665
- return acc;
1666
- }, []);
1667
- return (index.h("div", { class: "mrd-layout-section__related-view", key: `view-${name}` }, showTitle && item.label && index.h("h3", { class: "mrd-layout-section__related-view-title" }, item.label), index.h("mrd-table", { "data-view": name, columns: activeViewConfig.values, locale: this.locale, defaultSort: (_m = activeViewConfig.defaultSort) !== null && _m !== void 0 ? _m : '', viewLabel: viewLabel, alternativeViews: altViews, actions: tableActions, onMrdLoadPage: (e) => this.handleViewLoadPage(e, name), onMrdSwitchView: (e) => {
1668
- var _a, _b, _c, _d, _e, _f, _g, _h;
1669
- e.stopPropagation();
1670
- const newViewName = e.detail.name;
1671
- const newViewConfig = this.views[newViewName];
1672
- if (!newViewConfig)
1673
- return;
1674
- this.activeViewMap = Object.assign(Object.assign({}, this.activeViewMap), { [name]: newViewName });
1675
- this.activeFiltersMap = Object.assign(Object.assign({}, this.activeFiltersMap), { [name]: [] });
1676
- const dataLinks = ((_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a._links) !== null && _b !== void 0 ? _b : {});
1677
- const href = isRelated
1678
- ? (_d = dataLinks[(_c = item.relatedClass) !== null && _c !== void 0 ? _c : '']) === null || _d === void 0 ? void 0 : _d.href
1679
- : ((_f = (_e = this.links[newViewName]) === null || _e === void 0 ? void 0 : _e.href) !== null && _f !== void 0 ? _f : (_g = this.links[name]) === null || _g === void 0 ? void 0 : _g.href);
1680
- this.mrdLoadView.emit({ name, href, viewConfig: newViewConfig, sort: (_h = newViewConfig.defaultSort) !== null && _h !== void 0 ? _h : '', filters: this.resolveViewFilters(newViewConfig) });
1681
- }, onMrdFilter: (e) => {
1608
+ // Extract parentId from data._links.self.href for RELATED_VIEW path construction
1609
+ const selfHref = (_e = (_d = (_c = (_b = this.data) === null || _b === void 0 ? void 0 : _b._links) === null || _c === void 0 ? void 0 : _c.self) === null || _d === void 0 ? void 0 : _d.href) !== null && _e !== void 0 ? _e : '';
1610
+ const parentId = (_f = selfHref.split('/').filter(Boolean).pop()) !== null && _f !== void 0 ? _f : '';
1611
+ 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), index.h("mrd-table", { "data-view": key, item: item, parentId: parentId, locale: this.locale, onMrdLoadPage: (e) => this.handleViewLoadPage(e, key), onMrdLoadAggregations: (e) => {
1612
+ var _a;
1682
1613
  e.stopPropagation();
1683
- this.activeFiltersMap = Object.assign(Object.assign({}, this.activeFiltersMap), { [name]: e.detail.filters });
1684
- }, onMrdLoadAggregations: (e) => {
1685
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
1614
+ this.mrdLoadViewAggregations.emit(Object.assign({ name: key, dataClass: (_a = item.dataClass) !== null && _a !== void 0 ? _a : key }, e.detail));
1615
+ }, onMrdRowClick: (e) => {
1616
+ var _a, _b, _c;
1686
1617
  e.stopPropagation();
1687
- const dataLinks = ((_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a._links) !== null && _b !== void 0 ? _b : {});
1688
- const href = isRelated
1689
- ? (_d = dataLinks[(_c = item.relatedClass) !== null && _c !== void 0 ? _c : '']) === null || _d === void 0 ? void 0 : _d.href
1690
- : ((_g = (_f = this.links[(_e = this.activeViewMap[name]) !== null && _e !== void 0 ? _e : name]) === null || _f === void 0 ? void 0 : _f.href) !== null && _g !== void 0 ? _g : (_h = this.links[name]) === null || _h === void 0 ? void 0 : _h.href);
1691
- const filters = (_j = this.activeFiltersMap[name]) !== null && _j !== void 0 ? _j : [];
1692
- this.mrdLoadViewAggregations.emit(Object.assign({ name, href, filters }, e.detail));
1618
+ const row = e.detail;
1619
+ this.mrdNavigate.emit({ 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, label: (_c = row === null || row === void 0 ? void 0 : row.name) !== null && _c !== void 0 ? _c : '' });
1693
1620
  }, onMrdAction: (e) => {
1694
- var _a, _b, _c;
1621
+ var _a;
1695
1622
  e.stopPropagation();
1696
- const pl = (_a = this.viewLinksMap[name]) !== null && _a !== void 0 ? _a : {};
1697
- const href = e.detail.action === 'export' ? (_b = pl['excel']) === null || _b === void 0 ? void 0 : _b.href : (_c = pl['self']) === null || _c === void 0 ? void 0 : _c.href;
1698
- this.mrdViewAction.emit({ name, action: e.detail.action, href });
1623
+ this.mrdViewAction.emit({
1624
+ name: key,
1625
+ action: e.detail.action,
1626
+ dataClass: (_a = item.dataClass) !== null && _a !== void 0 ? _a : key,
1627
+ path: e.detail.path,
1628
+ qs: e.detail.qs,
1629
+ parentPath: e.detail.parentPath,
1630
+ });
1699
1631
  } })));
1700
1632
  }
1701
1633
  renderItem(item) {
@@ -1729,13 +1661,10 @@ const MrdLayoutSection = class {
1729
1661
  return (index.h("div", { class: "mrd-layout-section__modal-backdrop", onClick: () => { this.imagePreviewUrl = null; } }, index.h("div", { class: "mrd-layout-section__modal", onClick: (e) => e.stopPropagation() }, index.h("button", { class: "mrd-layout-section__modal-close", onClick: () => { this.imagePreviewUrl = null; } }, "\u2715"), index.h("img", { class: "mrd-layout-section__modal-image", src: this.imagePreviewUrl, alt: "" }))));
1730
1662
  }
1731
1663
  render() {
1732
- return (index.h(index.Host, { key: '7a91a541e056965dc79d74a50827e8c270c33a0d' }, index.h("div", { key: 'bcf4a2e81e704d136fb437cd2cb22acb4a05a8b3', class: "mrd-layout-section" }, this.items.map(item => this.renderItem(item))), this.renderImageModal()));
1664
+ return (index.h(index.Host, { key: 'a7b6514d19cf79261396d9aaf03f459600037566' }, index.h("div", { key: '331f0558ef3eddf5a9b4332f7ec45c58b52dd8c3', class: "mrd-layout-section" }, this.items.map(item => this.renderItem(item))), this.renderImageModal()));
1733
1665
  }
1734
1666
  get el() { return index.getElement(this); }
1735
1667
  static get watchers() { return {
1736
- "links": [{
1737
- "linksChanged": 0
1738
- }],
1739
1668
  "data": [{
1740
1669
  "dataChanged": 0
1741
1670
  }]
@@ -2201,9 +2130,7 @@ const MrdTable = class {
2201
2130
  this.mrdLoadPage = index.createEvent(this, "mrdLoadPage");
2202
2131
  this.mrdRowClick = index.createEvent(this, "mrdRowClick");
2203
2132
  this.mrdAction = index.createEvent(this, "mrdAction");
2204
- this.mrdFilter = index.createEvent(this, "mrdFilter");
2205
2133
  this.mrdDownload = index.createEvent(this, "mrdDownload");
2206
- this.mrdSwitchView = index.createEvent(this, "mrdSwitchView");
2207
2134
  this.mrdLoadAggregations = index.createEvent(this, "mrdLoadAggregations");
2208
2135
  // ── Non-state internals ────────────────────────────────────────────────────
2209
2136
  this.pendingPages = new Set();
@@ -2211,7 +2138,10 @@ const MrdTable = class {
2211
2138
  this.outsideClickHandler = null;
2212
2139
  this.keydownHandler = null;
2213
2140
  // ── Props ──────────────────────────────────────────────────────────────────
2214
- this.columns = [];
2141
+ /** The VIEW or RELATED_VIEW layout item. Contains view config, dataClass, fromClass, actions etc. */
2142
+ this.item = null;
2143
+ /** Parent record id — required for RELATED_VIEW to build /{fromClass}/{parentId}/{dataClass}. */
2144
+ this.parentId = '';
2215
2145
  /** Direct rows (non-paginated mode, used when totalElements === 0). */
2216
2146
  this.rows = [];
2217
2147
  this.locale = navigator.language;
@@ -2223,16 +2153,9 @@ const MrdTable = class {
2223
2153
  this.rowHeight = 36;
2224
2154
  /** Height of the scroll container in px. */
2225
2155
  this.tableHeight = 500;
2226
- /** Initial sort applied on load, e.g. "timestamp,desc" or "name".
2227
- * Parsed by init() into sortField + sortDir. */
2228
- this.defaultSort = '';
2229
- /** Toolbar action buttons rendered above the table. */
2230
- this.actions = [];
2231
- /** Display label of the current view — shown in the toolbar center as a view picker trigger. */
2232
- this.viewLabel = '';
2233
- /** Alternative views available for this table; renders a dropdown when non-empty. */
2234
- this.alternativeViews = [];
2235
2156
  // ── Internal state ─────────────────────────────────────────────────────────
2157
+ /** Index into allViews[] for the currently displayed view. 0 = primary, 1+ = alternatives. */
2158
+ this.activeViewIdx = 0;
2236
2159
  this.loadedPages = new Map();
2237
2160
  this.requestedPages = new Set();
2238
2161
  this.renderStart = 0;
@@ -2275,13 +2198,16 @@ const MrdTable = class {
2275
2198
  totalElementsChanged(newVal) {
2276
2199
  this.renderEnd = Math.min(this.renderEnd, Math.max(0, newVal - 1));
2277
2200
  }
2278
- /** Apply defaultSort when the prop changes (e.g. after a view switch). */
2279
- defaultSortChanged(newVal) {
2280
- this.applyDefaultSort(newVal);
2201
+ /** Reset to primary view when the item prop is replaced from outside. */
2202
+ itemChanged(newVal) {
2203
+ var _a, _b;
2204
+ this.activeViewIdx = 0;
2205
+ this.applyDefaultSort((_b = (_a = newVal === null || newVal === void 0 ? void 0 : newVal.view) === null || _a === void 0 ? void 0 : _a.defaultSort) !== null && _b !== void 0 ? _b : '');
2281
2206
  }
2282
2207
  // ── Lifecycle ──────────────────────────────────────────────────────────────
2283
2208
  componentWillLoad() {
2284
- this.applyDefaultSort(this.defaultSort);
2209
+ var _a, _b, _c;
2210
+ this.applyDefaultSort((_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 : '');
2285
2211
  }
2286
2212
  // ── Helpers ────────────────────────────────────────────────────────────────
2287
2213
  applyDefaultSort(defaultSort) {
@@ -2313,14 +2239,17 @@ const MrdTable = class {
2313
2239
  this.colWidths = [];
2314
2240
  this.scrollTop = 0;
2315
2241
  this.renderStart = 0;
2316
- // No BUFFER on init — only request what fits the visible area (page 0).
2317
- // BUFFER is applied during scroll to pre-fetch the next page proactively.
2318
- this.renderEnd = Math.max(0, Math.min(this.visibleCount() - 1, this.totalElements - 1));
2242
+ // Always fill the visible viewport on init — totalElements may be stale from a
2243
+ // previous view. setPage() clamps renderEnd when the page is shorter than pageSize.
2244
+ this.renderEnd = this.visibleCount() - 1;
2319
2245
  const scroller = this.el.querySelector('.mrd-table__scroll');
2320
2246
  if (scroller)
2321
2247
  scroller.scrollTop = 0;
2322
2248
  this.aggregations = null;
2323
2249
  this.emitLoadAggregations();
2250
+ // Always request page 0 — totalElements may be unknown (0) on first load.
2251
+ this.mrdLoadPage.emit({ page: 0, sort: this.sortParam(), path: this.buildDataPath(), qs: this.buildQueryParams(0) });
2252
+ this.requestedPages = new Set([0]);
2324
2253
  }
2325
2254
  /**
2326
2255
  * Inject the rows for a given page (0-based).
@@ -2373,6 +2302,147 @@ const MrdTable = class {
2373
2302
  return '';
2374
2303
  return this.sortDir === 'desc' ? `${this.sortField},desc` : this.sortField;
2375
2304
  }
2305
+ /** Stable ordered list: primary view first, then alternatives (from the item prop). */
2306
+ get allViews() {
2307
+ var _a, _b, _c, _d, _e, _f, _g;
2308
+ if (!this.item)
2309
+ return [];
2310
+ const it = this.item;
2311
+ return [
2312
+ { label: (_e = (_d = (_c = (_a = it.label) !== null && _a !== void 0 ? _a : (_b = it.view) === null || _b === void 0 ? void 0 : _b.pluralLabel) !== null && _c !== void 0 ? _c : it.dataClass) !== null && _d !== void 0 ? _d : it.relatedClass) !== null && _e !== void 0 ? _e : '', dataClass: (_f = it.dataClass) !== null && _f !== void 0 ? _f : it.relatedClass, fromClass: it.fromClass, filterClass: it.filterClass, view: it.view },
2313
+ ...((_g = it.alternativeViews) !== null && _g !== void 0 ? _g : []).map(av => {
2314
+ var _a, _b, _c, _d;
2315
+ return ({
2316
+ label: (_d = (_c = (_a = av.label) !== null && _a !== void 0 ? _a : (_b = av.view) === null || _b === void 0 ? void 0 : _b.pluralLabel) !== null && _c !== void 0 ? _c : av.dataClass) !== null && _d !== void 0 ? _d : '',
2317
+ dataClass: av.dataClass,
2318
+ fromClass: av.fromClass,
2319
+ filterClass: av.filterClass,
2320
+ view: av.view,
2321
+ });
2322
+ }),
2323
+ ];
2324
+ }
2325
+ /** Relative excel export path for the current view.
2326
+ * VIEW: /excel/{dataClass}
2327
+ * RELATED_VIEW: /excel/{fromClass}/{parentId}/{dataClass} */
2328
+ buildExcelPath() {
2329
+ var _a, _b, _c, _d;
2330
+ const v = this.allViews[this.activeViewIdx];
2331
+ if (!v)
2332
+ return '';
2333
+ if (((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW') {
2334
+ return `/excel/${(_b = v.fromClass) !== null && _b !== void 0 ? _b : ''}/${this.parentId}/${(_c = v.dataClass) !== null && _c !== void 0 ? _c : ''}`;
2335
+ }
2336
+ return `/excel/${(_d = v.dataClass) !== null && _d !== void 0 ? _d : ''}`;
2337
+ }
2338
+ buildActionDetail(action) {
2339
+ var _a, _b, _c;
2340
+ if (action === 'export') {
2341
+ return { action, path: this.buildExcelPath(), qs: this.buildQueryParams(0) };
2342
+ }
2343
+ if (action === 'create') {
2344
+ const v = this.allViews[this.activeViewIdx];
2345
+ const parentPath = ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW'
2346
+ ? `/${(_b = v === null || v === void 0 ? void 0 : v.fromClass) !== null && _b !== void 0 ? _b : ''}/${this.parentId}`
2347
+ : null;
2348
+ return { action, dataClass: (_c = v === null || v === void 0 ? void 0 : v.dataClass) !== null && _c !== void 0 ? _c : '', parentPath };
2349
+ }
2350
+ return { action };
2351
+ }
2352
+ /** Relative data path for the current view, without query string.
2353
+ * VIEW: /{dataClass}
2354
+ * RELATED_VIEW: /{fromClass}/{parentId}/{dataClass} */
2355
+ buildDataPath() {
2356
+ var _a, _b, _c, _d;
2357
+ const v = this.allViews[this.activeViewIdx];
2358
+ if (!v)
2359
+ return '';
2360
+ if (((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW') {
2361
+ return `/${(_b = v.fromClass) !== null && _b !== void 0 ? _b : ''}/${this.parentId}/${(_c = v.dataClass) !== null && _c !== void 0 ? _c : ''}`;
2362
+ }
2363
+ return `/${(_d = v.dataClass) !== null && _d !== void 0 ? _d : ''}`;
2364
+ }
2365
+ /** Build query params for a page request from current sort, view filters, filterClass and active column filters. */
2366
+ buildQueryParams(page) {
2367
+ var _a, _b, _c, _d, _e, _f, _g;
2368
+ const v = this.allViews[this.activeViewIdx];
2369
+ const p = new URLSearchParams();
2370
+ if (page > 0)
2371
+ p.set('page', String(page));
2372
+ const sort = this.sortParam();
2373
+ if (sort)
2374
+ p.set('sort', sort);
2375
+ const filterClass = v === null || v === void 0 ? void 0 : v.filterClass;
2376
+ if (filterClass)
2377
+ p.set('type', filterClass);
2378
+ for (const f of ((_b = (_a = v === null || v === void 0 ? void 0 : v.view) === null || _a === void 0 ? void 0 : _a.filter) !== null && _b !== void 0 ? _b : [])) {
2379
+ if (!f.name)
2380
+ continue;
2381
+ if (f.operator === 'EMPTY') {
2382
+ p.set(f.name, '');
2383
+ continue;
2384
+ }
2385
+ if (f.operator === 'NOT_EMPTY') {
2386
+ p.set(f.name + '_notempty', 'true');
2387
+ continue;
2388
+ }
2389
+ if (f.operator === 'STARTS_WITH') {
2390
+ p.set(f.name + '_startswith', String((_c = f.value) !== null && _c !== void 0 ? _c : ''));
2391
+ continue;
2392
+ }
2393
+ if (f.operator === 'FROM') {
2394
+ p.set(f.name + '_from', String((_d = f.value) !== null && _d !== void 0 ? _d : ''));
2395
+ continue;
2396
+ }
2397
+ if (f.operator === 'TO') {
2398
+ p.set(f.name + '_to', String((_e = f.value) !== null && _e !== void 0 ? _e : ''));
2399
+ continue;
2400
+ }
2401
+ if (f.value != null) {
2402
+ p.set(f.name, String(f.value));
2403
+ }
2404
+ }
2405
+ for (const f of this.activeFilters.values()) {
2406
+ if (f.operator === 'isEmpty') {
2407
+ p.set(f.field, '');
2408
+ continue;
2409
+ }
2410
+ if (f.operator === 'isNotEmpty') {
2411
+ p.set(f.field + '_notempty', 'true');
2412
+ continue;
2413
+ }
2414
+ if (f.operator === 'startsWith') {
2415
+ p.set(f.field + '_startswith', String((_f = f.value) !== null && _f !== void 0 ? _f : ''));
2416
+ continue;
2417
+ }
2418
+ if ((_g = f.values) === null || _g === void 0 ? void 0 : _g.length) {
2419
+ p.set(f.field, f.values.join(','));
2420
+ continue;
2421
+ }
2422
+ if (f.value != null)
2423
+ p.set(f.field, String(f.value));
2424
+ if (f.from != null)
2425
+ p.set(f.field + '_from', String(f.from));
2426
+ if (f.to != null)
2427
+ p.set(f.field + '_to', String(f.to));
2428
+ }
2429
+ return p.toString();
2430
+ }
2431
+ get columns() {
2432
+ var _a, _b, _c;
2433
+ return ((_c = (_b = (_a = this.allViews[this.activeViewIdx]) === null || _a === void 0 ? void 0 : _a.view) === null || _b === void 0 ? void 0 : _b.values) !== null && _c !== void 0 ? _c : []);
2434
+ }
2435
+ get tableActions() {
2436
+ var _a, _b;
2437
+ const raw = (_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.actions) !== null && _b !== void 0 ? _b : [];
2438
+ return (raw !== null && raw !== void 0 ? raw : []).reduce((acc, a) => {
2439
+ if (a === 'NEW')
2440
+ acc.push({ action: 'create', label: t('table_new_record', this.locale), icon: 'assets/sprites.svg#icon-plus', variant: 'primary' });
2441
+ if (a === 'EXPORT')
2442
+ acc.push({ action: 'export', label: t('table_export_excel', this.locale), icon: 'assets/sprites.svg#icon-file-excel' });
2443
+ return acc;
2444
+ }, []);
2445
+ }
2376
2446
  colName(col) {
2377
2447
  var _a;
2378
2448
  return (_a = col.name) !== null && _a !== void 0 ? _a : '';
@@ -2404,9 +2474,9 @@ const MrdTable = class {
2404
2474
  return Object.keys(params).length > 0 ? params : null;
2405
2475
  }
2406
2476
  emitLoadAggregations() {
2407
- const params = this.buildAggregationParams();
2408
- if (params)
2409
- this.mrdLoadAggregations.emit(params);
2477
+ const aggParams = this.buildAggregationParams();
2478
+ if (aggParams)
2479
+ this.mrdLoadAggregations.emit(Object.assign(Object.assign({}, aggParams), { path: this.buildDataPath(), qs: this.buildQueryParams(0) }));
2410
2480
  }
2411
2481
  renderAggregationValue(col) {
2412
2482
  var _a, _b;
@@ -2471,7 +2541,7 @@ const MrdTable = class {
2471
2541
  for (let p = firstPage; p <= lastPage; p++) {
2472
2542
  if (!this.loadedPages.has(p) && !next.has(p)) {
2473
2543
  next.add(p);
2474
- this.mrdLoadPage.emit({ page: p, sort: this.sortParam() });
2544
+ this.mrdLoadPage.emit({ page: p, sort: this.sortParam(), path: this.buildDataPath(), qs: this.buildQueryParams(p) });
2475
2545
  changed = true;
2476
2546
  }
2477
2547
  }
@@ -2513,7 +2583,7 @@ const MrdTable = class {
2513
2583
  if (pageEnd < this.renderStart || pageStart > this.renderEnd)
2514
2584
  continue;
2515
2585
  next.add(page);
2516
- this.mrdLoadPage.emit({ page, sort: this.sortParam() });
2586
+ this.mrdLoadPage.emit({ page, sort: this.sortParam(), path: this.buildDataPath(), qs: this.buildQueryParams(page) });
2517
2587
  changed = true;
2518
2588
  }
2519
2589
  this.pendingPages.clear();
@@ -2705,7 +2775,6 @@ const MrdTable = class {
2705
2775
  }
2706
2776
  this.activeFilters = next;
2707
2777
  this.closeFilterPopup();
2708
- this.mrdFilter.emit({ filters: Array.from(this.activeFilters.values()) });
2709
2778
  this.aggregations = null;
2710
2779
  this.emitLoadAggregations();
2711
2780
  if (this.totalElements > 0) {
@@ -2720,7 +2789,6 @@ const MrdTable = class {
2720
2789
  next.delete(name);
2721
2790
  this.activeFilters = next;
2722
2791
  this.closeFilterPopup();
2723
- this.mrdFilter.emit({ filters: Array.from(this.activeFilters.values()) });
2724
2792
  this.aggregations = null;
2725
2793
  this.emitLoadAggregations();
2726
2794
  if (this.totalElements > 0) {
@@ -2730,7 +2798,6 @@ const MrdTable = class {
2730
2798
  }
2731
2799
  clearAllFilters() {
2732
2800
  this.activeFilters = new Map();
2733
- this.mrdFilter.emit({ filters: [] });
2734
2801
  this.aggregations = null;
2735
2802
  this.emitLoadAggregations();
2736
2803
  if (this.totalElements > 0) {
@@ -2739,28 +2806,30 @@ const MrdTable = class {
2739
2806
  }
2740
2807
  }
2741
2808
  // ── View switcher ──────────────────────────────────────────────────────────
2742
- handleViewSwitch(view) {
2743
- this.mrdSwitchView.emit({ name: view.name, class: view.class });
2809
+ handleViewSwitch(targetIdx) {
2810
+ var _a, _b;
2811
+ const target = this.allViews[targetIdx];
2812
+ if (!(target === null || target === void 0 ? void 0 : target.view))
2813
+ return;
2814
+ this.activeViewIdx = targetIdx;
2815
+ this.applyDefaultSort((_b = (_a = target.view) === null || _a === void 0 ? void 0 : _a.defaultSort) !== null && _b !== void 0 ? _b : '');
2816
+ this.activeFilters = new Map();
2817
+ this.init();
2744
2818
  }
2745
2819
  // ── Render: toolbar ────────────────────────────────────────────────────────
2746
2820
  renderToolbar() {
2747
- var _a, _b;
2748
2821
  const filterCount = this.activeFilters.size;
2749
- const hasActions = ((_a = this.actions) === null || _a === void 0 ? void 0 : _a.length) > 0;
2750
- const hasViewSwitcher = !!this.viewLabel && ((_b = this.alternativeViews) === null || _b === void 0 ? void 0 : _b.length) > 0;
2822
+ const actions = this.tableActions;
2823
+ const allViews = this.allViews;
2824
+ const hasActions = actions.length > 0;
2825
+ const hasViewSwitcher = allViews.length > 1;
2751
2826
  return (index.h("div", { class: "mrd-table__toolbar" }, index.h("div", { class: "mrd-table__toolbar-left" }, index.h("button", { class: `mrd-table__action mrd-table__action--secondary mrd-table__filter-toggle${this.filterMode ? ' mrd-table__filter-toggle--active' : ''}`, onClick: () => this.handleFilterToggle() }, index.h("svg", { class: "mrd-table__action-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, index.h("path", { fill: "currentColor", d: "M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z" })), filterCount > 0 && index.h("span", { class: "mrd-table__filter-badge" }, filterCount), index.h("span", { class: "mrd-table__action-tooltip" }, this.filterMode ? t('table_filter_hide', this.locale) : t('table_filter', this.locale), filterCount > 0 ? ` (${filterCount} ${t('table_filter_active', this.locale)})` : '')), filterCount > 0 && (index.h("button", { class: "mrd-table__action mrd-table__action--secondary", onClick: () => this.clearAllFilters() }, index.h("svg", { class: "mrd-table__action-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, index.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" })), index.h("span", { class: "mrd-table__action-tooltip" }, t('table_filter_clear_all', this.locale))))), hasViewSwitcher && (index.h("div", { class: "mrd-table__toolbar-center" }, index.h("select", { class: "mrd-table__view-select", onChange: (e) => {
2752
- const sel = e.target;
2753
- const view = this.alternativeViews.find(v => v.name === sel.value);
2754
- if (view) {
2755
- sel.selectedIndex = 0;
2756
- this.handleViewSwitch(view);
2757
- }
2758
- } }, index.h("option", { value: "" }, this.viewLabel), this.alternativeViews.map(v => {
2759
- var _a;
2760
- return (index.h("option", { value: v.name }, (_a = v.label) !== null && _a !== void 0 ? _a : v.name));
2761
- })))), hasActions && (index.h("div", { class: "mrd-table__toolbar-right" }, this.actions.map(a => {
2827
+ const idx = parseInt(e.target.value, 10);
2828
+ if (!isNaN(idx) && idx !== this.activeViewIdx)
2829
+ this.handleViewSwitch(idx);
2830
+ } }, allViews.map((v, i) => (index.h("option", { value: String(i), selected: i === this.activeViewIdx }, v.label)))))), hasActions && (index.h("div", { class: "mrd-table__toolbar-right" }, actions.map(a => {
2762
2831
  var _a;
2763
- return (index.h("button", { class: `mrd-table__action mrd-table__action--${(_a = a.variant) !== null && _a !== void 0 ? _a : 'secondary'}`, disabled: a.disabled, onClick: () => this.mrdAction.emit({ action: a.action }) }, a.icon
2832
+ return (index.h("button", { class: `mrd-table__action mrd-table__action--${(_a = a.variant) !== null && _a !== void 0 ? _a : 'secondary'}`, disabled: a.disabled, onClick: () => this.mrdAction.emit(this.buildActionDetail(a.action)) }, a.icon
2764
2833
  ? index.h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, index.h("use", { href: a.icon }))
2765
2834
  : a.label, index.h("span", { class: "mrd-table__action-tooltip" }, a.label)));
2766
2835
  })))));
@@ -3006,8 +3075,8 @@ const MrdTable = class {
3006
3075
  "totalElements": [{
3007
3076
  "totalElementsChanged": 0
3008
3077
  }],
3009
- "defaultSort": [{
3010
- "defaultSortChanged": 0
3078
+ "item": [{
3079
+ "itemChanged": 0
3011
3080
  }]
3012
3081
  }; }
3013
3082
  };