@mmlogic/components 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/mosterdcomponents.cjs.js +1 -1
- package/dist/cjs/mrd-boolean-field_19.cjs.entry.js +323 -184
- package/dist/collection/components/mrd-layout-section/mrd-layout-section.js +61 -177
- package/dist/collection/components/mrd-table/mrd-table.js +325 -214
- package/dist/collection/dev/api.js +23 -6
- package/dist/collection/dev/app.js +358 -268
- package/dist/components/mrd-layout-section.js +1 -1
- package/dist/components/mrd-table2.js +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/esm/mosterdcomponents.js +1 -1
- package/dist/esm/mrd-boolean-field_19.entry.js +323 -184
- package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -1
- package/dist/mosterdcomponents/p-af4c247e.entry.js +1 -0
- package/dist/types/components/mrd-layout-section/mrd-layout-section.d.ts +18 -32
- package/dist/types/components/mrd-table/mrd-table.d.ts +54 -29
- package/dist/types/components.d.ts +42 -88
- package/dist/types/types/client-layout.d.ts +18 -17
- package/package.json +1 -1
- package/dist/mosterdcomponents/p-61ef0232.entry.js +0 -1
|
@@ -1364,7 +1364,6 @@ const MrdLayoutSection = class {
|
|
|
1364
1364
|
this.mrdNavigate = createEvent(this, "mrdNavigate");
|
|
1365
1365
|
this.mrdSearch = createEvent(this, "mrdSearch");
|
|
1366
1366
|
this.mrdDownload = createEvent(this, "mrdDownload");
|
|
1367
|
-
this.mrdLoadView = createEvent(this, "mrdLoadView");
|
|
1368
1367
|
this.mrdLoadViewPage = createEvent(this, "mrdLoadViewPage");
|
|
1369
1368
|
this.mrdLoadImage = createEvent(this, "mrdLoadImage");
|
|
1370
1369
|
this.mrdViewAction = createEvent(this, "mrdViewAction");
|
|
@@ -1373,24 +1372,19 @@ const MrdLayoutSection = class {
|
|
|
1373
1372
|
this.items = [];
|
|
1374
1373
|
/** Record data object; keys are field names, _links holds relation and related-view links. */
|
|
1375
1374
|
this.data = {};
|
|
1376
|
-
/**
|
|
1375
|
+
/** Legacy: view metadata map (ClientDashboardMetadata.views). Not needed in new flat format. */
|
|
1377
1376
|
this.views = {};
|
|
1378
|
-
/**
|
|
1377
|
+
/** Legacy: top-level _links from ClientDashboardMetadata. Not needed in new flat format. */
|
|
1379
1378
|
this.links = {};
|
|
1380
1379
|
this.locale = navigator.language;
|
|
1381
1380
|
this.searchQueryMap = {};
|
|
1382
1381
|
this.searchResultsMap = {};
|
|
1383
1382
|
this.imagePreviewUrl = null;
|
|
1384
1383
|
this.imagePreviews = {};
|
|
1385
|
-
this.activeViewMap = {};
|
|
1386
|
-
this.viewLinksMap = {};
|
|
1387
|
-
this.activeFiltersMap = {};
|
|
1388
1384
|
this.searchTimers = {};
|
|
1389
1385
|
this.handleViewLoadPage = (e, name) => {
|
|
1390
|
-
var _a;
|
|
1391
1386
|
e.stopPropagation();
|
|
1392
|
-
|
|
1393
|
-
this.mrdLoadViewPage.emit({ name, page: e.detail.page, sort: e.detail.sort, filters });
|
|
1387
|
+
this.mrdLoadViewPage.emit({ name, page: e.detail.page, sort: e.detail.sort, path: e.detail.path, qs: e.detail.qs });
|
|
1394
1388
|
};
|
|
1395
1389
|
this.handleSearchInput = (dataClass, query) => {
|
|
1396
1390
|
this.searchQueryMap = Object.assign(Object.assign({}, this.searchQueryMap), { [dataClass]: query });
|
|
@@ -1407,59 +1401,29 @@ const MrdLayoutSection = class {
|
|
|
1407
1401
|
}
|
|
1408
1402
|
componentDidLoad() {
|
|
1409
1403
|
setTimeout(() => {
|
|
1410
|
-
this.
|
|
1404
|
+
this.initEmbeddedTables();
|
|
1411
1405
|
this.emitLoadImages();
|
|
1412
1406
|
}, 0);
|
|
1413
1407
|
}
|
|
1414
|
-
linksChanged(newVal) {
|
|
1415
|
-
if (Object.keys(newVal !== null && newVal !== void 0 ? newVal : {}).length > 0) {
|
|
1416
|
-
this.emitLoadViews();
|
|
1417
|
-
}
|
|
1418
|
-
}
|
|
1419
1408
|
dataChanged(newVal) {
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
this.emitLoadViews();
|
|
1409
|
+
if (newVal && Object.keys(newVal).length > 0) {
|
|
1410
|
+
setTimeout(() => this.initEmbeddedTables(), 0);
|
|
1423
1411
|
}
|
|
1424
1412
|
}
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
switch (f.operator) {
|
|
1431
|
-
case 'FROM': return Object.assign(Object.assign({}, base), { from: (_a = f.value) !== null && _a !== void 0 ? _a : null });
|
|
1432
|
-
case 'TO': return Object.assign(Object.assign({}, base), { to: (_b = f.value) !== null && _b !== void 0 ? _b : null });
|
|
1433
|
-
case 'STARTS_WITH': return Object.assign(Object.assign({}, base), { operator: 'startsWith', value: (_c = f.value) !== null && _c !== void 0 ? _c : null });
|
|
1434
|
-
case 'NOT_EMPTY': return Object.assign(Object.assign({}, base), { operator: 'isNotEmpty' });
|
|
1435
|
-
case 'EMPTY': return Object.assign(Object.assign({}, base), { operator: 'isEmpty' });
|
|
1436
|
-
default: return Object.assign(Object.assign({}, base), { operator: 'equals', value: (_d = f.value) !== null && _d !== void 0 ? _d : null });
|
|
1437
|
-
}
|
|
1438
|
-
});
|
|
1439
|
-
}
|
|
1440
|
-
emitLoadViews() {
|
|
1441
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
1442
|
-
const dataLinks = ((_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a._links) !== null && _b !== void 0 ? _b : {});
|
|
1443
|
-
for (const item of this.flattenItems(this.items)) {
|
|
1444
|
-
if (item.type === ClientLayoutItemType.RELATED_VIEW && item.name) {
|
|
1445
|
-
const viewConfig = this.views[item.name];
|
|
1446
|
-
if (!viewConfig)
|
|
1447
|
-
continue;
|
|
1448
|
-
const href = (_d = dataLinks[(_c = item.relatedClass) !== null && _c !== void 0 ? _c : '']) === null || _d === void 0 ? void 0 : _d.href;
|
|
1449
|
-
this.mrdLoadView.emit({ name: item.name, href, viewConfig, sort: (_e = viewConfig.defaultSort) !== null && _e !== void 0 ? _e : '', filters: this.resolveViewFilters(viewConfig) });
|
|
1450
|
-
}
|
|
1451
|
-
else if (item.type === ClientLayoutItemType.VIEW) {
|
|
1452
|
-
const viewName = item.name;
|
|
1453
|
-
if (!viewName)
|
|
1454
|
-
continue;
|
|
1455
|
-
const viewConfig = this.views[viewName];
|
|
1456
|
-
if (!viewConfig)
|
|
1457
|
-
continue;
|
|
1458
|
-
const href = (_f = this.links[viewName]) === null || _f === void 0 ? void 0 : _f.href;
|
|
1459
|
-
this.mrdLoadView.emit({ name: viewName, href, viewConfig, sort: (_g = viewConfig.defaultSort) !== null && _g !== void 0 ? _g : '', filters: this.resolveViewFilters(viewConfig) });
|
|
1413
|
+
async initEmbeddedTables() {
|
|
1414
|
+
const tables = this.el.querySelectorAll('mrd-table[data-view]');
|
|
1415
|
+
for (const table of Array.from(tables)) {
|
|
1416
|
+
if (typeof table.init === 'function') {
|
|
1417
|
+
await table.init();
|
|
1460
1418
|
}
|
|
1461
1419
|
}
|
|
1462
1420
|
}
|
|
1421
|
+
viewKeyFor(item) {
|
|
1422
|
+
var _a, _b, _c, _d;
|
|
1423
|
+
if (item.type === ClientLayoutItemType.RELATED_VIEW)
|
|
1424
|
+
return (_b = (_a = item.relatedClass) !== null && _a !== void 0 ? _a : item.name) !== null && _b !== void 0 ? _b : '';
|
|
1425
|
+
return (_d = (_c = item.dataClass) !== null && _c !== void 0 ? _c : item.name) !== null && _d !== void 0 ? _d : '';
|
|
1426
|
+
}
|
|
1463
1427
|
emitLoadImages() {
|
|
1464
1428
|
for (const item of this.flattenItems(this.items)) {
|
|
1465
1429
|
if (item.type === ClientLayoutItemType.FIELD && item.dataType === ClientLayoutItemFieldDataType.IMAGE) {
|
|
@@ -1489,21 +1453,17 @@ const MrdLayoutSection = class {
|
|
|
1489
1453
|
}
|
|
1490
1454
|
/**
|
|
1491
1455
|
* Inject data into an embedded mrd-table for a RELATED_VIEW or VIEW item.
|
|
1492
|
-
* Pass totalElements
|
|
1493
|
-
* Pass
|
|
1456
|
+
* Pass totalElements to update the pagination total (safe to pass on every page).
|
|
1457
|
+
* Pass hasNext (from _links.next presence) so the table can decide whether to emit aggregations.
|
|
1494
1458
|
*/
|
|
1495
|
-
async setViewPage(name, page, rows, totalElements,
|
|
1496
|
-
if (pageLinks) {
|
|
1497
|
-
this.viewLinksMap = Object.assign(Object.assign({}, this.viewLinksMap), { [name]: pageLinks });
|
|
1498
|
-
}
|
|
1459
|
+
async setViewPage(name, page, rows, totalElements, hasNext) {
|
|
1499
1460
|
const table = this.el.querySelector(`mrd-table[data-view="${name}"]`);
|
|
1500
1461
|
if (!table)
|
|
1501
1462
|
return;
|
|
1502
1463
|
if (totalElements !== undefined) {
|
|
1503
1464
|
table.totalElements = totalElements;
|
|
1504
|
-
await table.init();
|
|
1505
1465
|
}
|
|
1506
|
-
await table.setPage(page, rows);
|
|
1466
|
+
await table.setPage(page, rows, hasNext);
|
|
1507
1467
|
}
|
|
1508
1468
|
/** Inject aggregation totals into an embedded mrd-table for a VIEW or RELATED_VIEW item. */
|
|
1509
1469
|
async setViewAggregations(name, data) {
|
|
@@ -1637,63 +1597,36 @@ const MrdLayoutSection = class {
|
|
|
1637
1597
|
return (h("div", { class: "mrd-layout-section__search", key: `search-${dataClass}` }, h("div", { class: "mrd-layout-section__search-wrap" }, 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" }, 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" })), 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 && (h("ul", { class: "mrd-layout-section__search-results" }, results.map(r => (h("li", { key: r.id, class: "mrd-layout-section__search-result" }, h("button", { class: "mrd-layout-section__search-result-btn", onClick: () => this.mrdNavigate.emit({ href: r.id, label: r.label }) }, h("span", { class: "mrd-layout-section__search-result-label" }, r.label), r.description && h("span", { class: "mrd-layout-section__search-result-desc" }, r.description)))))))));
|
|
1638
1598
|
}
|
|
1639
1599
|
renderRelatedView(item) {
|
|
1640
|
-
var _a, _b, _c, _d, _e, _f
|
|
1641
|
-
const
|
|
1642
|
-
|
|
1643
|
-
if (!name)
|
|
1600
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1601
|
+
const key = this.viewKeyFor(item);
|
|
1602
|
+
if (!key)
|
|
1644
1603
|
return null;
|
|
1645
|
-
|
|
1646
|
-
if (!viewConfig)
|
|
1604
|
+
if (!item.view)
|
|
1647
1605
|
return null;
|
|
1648
1606
|
const showTitle = (_a = item.showTitle) !== null && _a !== void 0 ? _a : false;
|
|
1649
|
-
|
|
1650
|
-
const
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
const activeEntry = allViews.find(v => v.name === activeName);
|
|
1655
|
-
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 : '';
|
|
1656
|
-
const altViews = allViews.filter(v => v.name !== activeName);
|
|
1657
|
-
const rawActions = (_l = item.actions) !== null && _l !== void 0 ? _l : ['NEW', 'EXPORT'];
|
|
1658
|
-
const tableActions = rawActions.reduce((acc, a) => {
|
|
1659
|
-
if (a === 'NEW')
|
|
1660
|
-
acc.push({ action: 'create', label: t('table_new_record', this.locale), icon: 'assets/sprites.svg#icon-plus', variant: 'primary' });
|
|
1661
|
-
if (a === 'EXPORT')
|
|
1662
|
-
acc.push({ action: 'export', label: t('table_export_excel', this.locale), icon: 'assets/sprites.svg#icon-file-excel' });
|
|
1663
|
-
return acc;
|
|
1664
|
-
}, []);
|
|
1665
|
-
return (h("div", { class: "mrd-layout-section__related-view", key: `view-${name}` }, showTitle && item.label && h("h3", { class: "mrd-layout-section__related-view-title" }, item.label), 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) => {
|
|
1666
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1667
|
-
e.stopPropagation();
|
|
1668
|
-
const newViewName = e.detail.name;
|
|
1669
|
-
const newViewConfig = this.views[newViewName];
|
|
1670
|
-
if (!newViewConfig)
|
|
1671
|
-
return;
|
|
1672
|
-
this.activeViewMap = Object.assign(Object.assign({}, this.activeViewMap), { [name]: newViewName });
|
|
1673
|
-
this.activeFiltersMap = Object.assign(Object.assign({}, this.activeFiltersMap), { [name]: [] });
|
|
1674
|
-
const dataLinks = ((_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a._links) !== null && _b !== void 0 ? _b : {});
|
|
1675
|
-
const href = isRelated
|
|
1676
|
-
? (_d = dataLinks[(_c = item.relatedClass) !== null && _c !== void 0 ? _c : '']) === null || _d === void 0 ? void 0 : _d.href
|
|
1677
|
-
: ((_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);
|
|
1678
|
-
this.mrdLoadView.emit({ name, href, viewConfig: newViewConfig, sort: (_h = newViewConfig.defaultSort) !== null && _h !== void 0 ? _h : '', filters: this.resolveViewFilters(newViewConfig) });
|
|
1679
|
-
}, onMrdFilter: (e) => {
|
|
1607
|
+
// Extract parentId from data._links.self.href for RELATED_VIEW path construction
|
|
1608
|
+
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 : '';
|
|
1609
|
+
const parentId = (_f = selfHref.split('/').filter(Boolean).pop()) !== null && _f !== void 0 ? _f : '';
|
|
1610
|
+
return (h("div", { class: "mrd-layout-section__related-view", key: `view-${key}` }, showTitle && item.label && h("h3", { class: "mrd-layout-section__related-view-title" }, item.label), h("mrd-table", { "data-view": key, item: item, parentId: parentId, locale: this.locale, onMrdLoadPage: (e) => this.handleViewLoadPage(e, key), onMrdLoadAggregations: (e) => {
|
|
1611
|
+
var _a;
|
|
1680
1612
|
e.stopPropagation();
|
|
1681
|
-
this.
|
|
1682
|
-
},
|
|
1683
|
-
var _a, _b, _c
|
|
1613
|
+
this.mrdLoadViewAggregations.emit(Object.assign({ name: key, dataClass: (_a = item.dataClass) !== null && _a !== void 0 ? _a : key }, e.detail));
|
|
1614
|
+
}, onMrdRowClick: (e) => {
|
|
1615
|
+
var _a, _b, _c;
|
|
1684
1616
|
e.stopPropagation();
|
|
1685
|
-
const
|
|
1686
|
-
|
|
1687
|
-
? (_d = dataLinks[(_c = item.relatedClass) !== null && _c !== void 0 ? _c : '']) === null || _d === void 0 ? void 0 : _d.href
|
|
1688
|
-
: ((_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);
|
|
1689
|
-
const filters = (_j = this.activeFiltersMap[name]) !== null && _j !== void 0 ? _j : [];
|
|
1690
|
-
this.mrdLoadViewAggregations.emit(Object.assign({ name, href, filters }, e.detail));
|
|
1617
|
+
const row = e.detail;
|
|
1618
|
+
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 : '' });
|
|
1691
1619
|
}, onMrdAction: (e) => {
|
|
1692
|
-
var _a
|
|
1620
|
+
var _a;
|
|
1693
1621
|
e.stopPropagation();
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1622
|
+
this.mrdViewAction.emit({
|
|
1623
|
+
name: key,
|
|
1624
|
+
action: e.detail.action,
|
|
1625
|
+
dataClass: (_a = item.dataClass) !== null && _a !== void 0 ? _a : key,
|
|
1626
|
+
path: e.detail.path,
|
|
1627
|
+
qs: e.detail.qs,
|
|
1628
|
+
parentPath: e.detail.parentPath,
|
|
1629
|
+
});
|
|
1697
1630
|
} })));
|
|
1698
1631
|
}
|
|
1699
1632
|
renderItem(item) {
|
|
@@ -1727,13 +1660,10 @@ const MrdLayoutSection = class {
|
|
|
1727
1660
|
return (h("div", { class: "mrd-layout-section__modal-backdrop", onClick: () => { this.imagePreviewUrl = null; } }, h("div", { class: "mrd-layout-section__modal", onClick: (e) => e.stopPropagation() }, h("button", { class: "mrd-layout-section__modal-close", onClick: () => { this.imagePreviewUrl = null; } }, "\u2715"), h("img", { class: "mrd-layout-section__modal-image", src: this.imagePreviewUrl, alt: "" }))));
|
|
1728
1661
|
}
|
|
1729
1662
|
render() {
|
|
1730
|
-
return (h(Host, { key: '
|
|
1663
|
+
return (h(Host, { key: '0a3a58f5c80716bc0a7ba1b9468b721706d2ce4a' }, h("div", { key: '7cf63580c584811c1bb84b419e8d13026e432fba', class: "mrd-layout-section" }, this.items.map(item => this.renderItem(item))), this.renderImageModal()));
|
|
1731
1664
|
}
|
|
1732
1665
|
get el() { return getElement(this); }
|
|
1733
1666
|
static get watchers() { return {
|
|
1734
|
-
"links": [{
|
|
1735
|
-
"linksChanged": 0
|
|
1736
|
-
}],
|
|
1737
1667
|
"data": [{
|
|
1738
1668
|
"dataChanged": 0
|
|
1739
1669
|
}]
|
|
@@ -2199,9 +2129,7 @@ const MrdTable = class {
|
|
|
2199
2129
|
this.mrdLoadPage = createEvent(this, "mrdLoadPage");
|
|
2200
2130
|
this.mrdRowClick = createEvent(this, "mrdRowClick");
|
|
2201
2131
|
this.mrdAction = createEvent(this, "mrdAction");
|
|
2202
|
-
this.mrdFilter = createEvent(this, "mrdFilter");
|
|
2203
2132
|
this.mrdDownload = createEvent(this, "mrdDownload");
|
|
2204
|
-
this.mrdSwitchView = createEvent(this, "mrdSwitchView");
|
|
2205
2133
|
this.mrdLoadAggregations = createEvent(this, "mrdLoadAggregations");
|
|
2206
2134
|
// ── Non-state internals ────────────────────────────────────────────────────
|
|
2207
2135
|
this.pendingPages = new Set();
|
|
@@ -2209,7 +2137,10 @@ const MrdTable = class {
|
|
|
2209
2137
|
this.outsideClickHandler = null;
|
|
2210
2138
|
this.keydownHandler = null;
|
|
2211
2139
|
// ── Props ──────────────────────────────────────────────────────────────────
|
|
2212
|
-
|
|
2140
|
+
/** The VIEW or RELATED_VIEW layout item. Contains view config, dataClass, fromClass, actions etc. */
|
|
2141
|
+
this.item = null;
|
|
2142
|
+
/** Parent record id — required for RELATED_VIEW to build /{fromClass}/{parentId}/{dataClass}. */
|
|
2143
|
+
this.parentId = '';
|
|
2213
2144
|
/** Direct rows (non-paginated mode, used when totalElements === 0). */
|
|
2214
2145
|
this.rows = [];
|
|
2215
2146
|
this.locale = navigator.language;
|
|
@@ -2221,16 +2152,9 @@ const MrdTable = class {
|
|
|
2221
2152
|
this.rowHeight = 36;
|
|
2222
2153
|
/** Height of the scroll container in px. */
|
|
2223
2154
|
this.tableHeight = 500;
|
|
2224
|
-
/** Initial sort applied on load, e.g. "timestamp,desc" or "name".
|
|
2225
|
-
* Parsed by init() into sortField + sortDir. */
|
|
2226
|
-
this.defaultSort = '';
|
|
2227
|
-
/** Toolbar action buttons rendered above the table. */
|
|
2228
|
-
this.actions = [];
|
|
2229
|
-
/** Display label of the current view — shown in the toolbar center as a view picker trigger. */
|
|
2230
|
-
this.viewLabel = '';
|
|
2231
|
-
/** Alternative views available for this table; renders a dropdown when non-empty. */
|
|
2232
|
-
this.alternativeViews = [];
|
|
2233
2155
|
// ── Internal state ─────────────────────────────────────────────────────────
|
|
2156
|
+
/** Index into allViews[] for the currently displayed view. 0 = primary, 1+ = alternatives. */
|
|
2157
|
+
this.activeViewIdx = 0;
|
|
2234
2158
|
this.loadedPages = new Map();
|
|
2235
2159
|
this.requestedPages = new Set();
|
|
2236
2160
|
this.renderStart = 0;
|
|
@@ -2256,10 +2180,16 @@ const MrdTable = class {
|
|
|
2256
2180
|
this.jsonModal = null;
|
|
2257
2181
|
/** Aggregation totals received from the host via setAggregations(). Null = not yet loaded. */
|
|
2258
2182
|
this.aggregations = null;
|
|
2183
|
+
/** Record count received via setAggregations().total; overrides totalElements for display. */
|
|
2184
|
+
this.aggregationsTotal = null;
|
|
2185
|
+
/** True when a fresh aggregations request is needed (set on init / filter change). */
|
|
2186
|
+
this.aggregationsPending = false;
|
|
2187
|
+
/** Lower bound on total derived from setPage() hasNext info; grows as pages load. */
|
|
2188
|
+
this.minKnownTotal = 0;
|
|
2259
2189
|
this.handleScroll = (e) => {
|
|
2260
2190
|
const scroller = e.currentTarget;
|
|
2261
2191
|
const scrollTop = scroller.scrollTop;
|
|
2262
|
-
const total = this.
|
|
2192
|
+
const total = this.baseTotal;
|
|
2263
2193
|
const visStart = Math.floor(scrollTop / this.rowHeight);
|
|
2264
2194
|
const visEnd = Math.min(visStart + this.visibleCount(), total - 1);
|
|
2265
2195
|
this.scrollTop = scrollTop;
|
|
@@ -2273,13 +2203,16 @@ const MrdTable = class {
|
|
|
2273
2203
|
totalElementsChanged(newVal) {
|
|
2274
2204
|
this.renderEnd = Math.min(this.renderEnd, Math.max(0, newVal - 1));
|
|
2275
2205
|
}
|
|
2276
|
-
/**
|
|
2277
|
-
|
|
2278
|
-
|
|
2206
|
+
/** Reset to primary view when the item prop is replaced from outside. */
|
|
2207
|
+
itemChanged(newVal) {
|
|
2208
|
+
var _a, _b;
|
|
2209
|
+
this.activeViewIdx = 0;
|
|
2210
|
+
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 : '');
|
|
2279
2211
|
}
|
|
2280
2212
|
// ── Lifecycle ──────────────────────────────────────────────────────────────
|
|
2281
2213
|
componentWillLoad() {
|
|
2282
|
-
|
|
2214
|
+
var _a, _b, _c;
|
|
2215
|
+
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 : '');
|
|
2283
2216
|
}
|
|
2284
2217
|
// ── Helpers ────────────────────────────────────────────────────────────────
|
|
2285
2218
|
applyDefaultSort(defaultSort) {
|
|
@@ -2311,14 +2244,19 @@ const MrdTable = class {
|
|
|
2311
2244
|
this.colWidths = [];
|
|
2312
2245
|
this.scrollTop = 0;
|
|
2313
2246
|
this.renderStart = 0;
|
|
2314
|
-
//
|
|
2315
|
-
//
|
|
2316
|
-
this.renderEnd =
|
|
2247
|
+
// Always fill the visible viewport on init — totalElements may be stale from a
|
|
2248
|
+
// previous view. setPage() clamps renderEnd when the page is shorter than pageSize.
|
|
2249
|
+
this.renderEnd = this.visibleCount() - 1;
|
|
2317
2250
|
const scroller = this.el.querySelector('.mrd-table__scroll');
|
|
2318
2251
|
if (scroller)
|
|
2319
2252
|
scroller.scrollTop = 0;
|
|
2320
2253
|
this.aggregations = null;
|
|
2321
|
-
this.
|
|
2254
|
+
this.aggregationsTotal = null;
|
|
2255
|
+
this.aggregationsPending = true;
|
|
2256
|
+
this.minKnownTotal = 0;
|
|
2257
|
+
// Always request page 0 — totalElements may be unknown (0) on first load.
|
|
2258
|
+
this.mrdLoadPage.emit({ page: 0, sort: this.sortParam(), path: this.buildDataPath(), qs: this.buildQueryParams(0) });
|
|
2259
|
+
this.requestedPages = new Set([0]);
|
|
2322
2260
|
}
|
|
2323
2261
|
/**
|
|
2324
2262
|
* Inject the rows for a given page (0-based).
|
|
@@ -2327,20 +2265,41 @@ const MrdTable = class {
|
|
|
2327
2265
|
* When the page contains fewer rows than pageSize it is the last page.
|
|
2328
2266
|
* renderEnd is clamped immediately so no loading-placeholder rows appear
|
|
2329
2267
|
* beyond the actual data — without requiring the host to update totalElements.
|
|
2268
|
+
*
|
|
2269
|
+
* Pass hasNext (from _links.next in the API response) for accurate last-page
|
|
2270
|
+
* detection even when rows.length === pageSize (exact multiple of page size).
|
|
2330
2271
|
*/
|
|
2331
|
-
async setPage(pageNumber, rows) {
|
|
2332
|
-
|
|
2272
|
+
async setPage(pageNumber, rows, hasNext) {
|
|
2273
|
+
const isLastPage = hasNext !== undefined ? !hasNext : rows.length < this.pageSize;
|
|
2274
|
+
if (isLastPage) {
|
|
2333
2275
|
// lastRowIdx is -1 when the page is empty; clamp renderEnd to -1 so the
|
|
2334
2276
|
// render loop does not execute and no shimmer rows appear.
|
|
2335
2277
|
const lastRowIdx = pageNumber * this.pageSize + rows.length - 1;
|
|
2336
2278
|
this.renderEnd = Math.min(this.renderEnd, lastRowIdx);
|
|
2279
|
+
// Exact total is known: update minKnownTotal so the scroll container has the right height.
|
|
2280
|
+
this.minKnownTotal = pageNumber * this.pageSize + rows.length;
|
|
2281
|
+
}
|
|
2282
|
+
else {
|
|
2283
|
+
// There is at least one more page — ensure the scrollbar covers at least that next page.
|
|
2284
|
+
this.minKnownTotal = Math.max(this.minKnownTotal, (pageNumber + 1) * this.pageSize + 1);
|
|
2337
2285
|
}
|
|
2338
2286
|
const next = new Map(this.loadedPages);
|
|
2339
2287
|
next.set(pageNumber, rows);
|
|
2340
2288
|
this.loadedPages = next;
|
|
2289
|
+
if (pageNumber === 0 && this.aggregationsPending) {
|
|
2290
|
+
this.aggregationsPending = false;
|
|
2291
|
+
const hasAggColumns = this.columns.some(c => c.type === 'FIELD' && c.aggregate);
|
|
2292
|
+
if (!isLastPage || hasAggColumns) {
|
|
2293
|
+
this.emitLoadAggregations();
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2341
2296
|
}
|
|
2342
2297
|
/** Inject aggregation totals returned by the /aggregations endpoint. */
|
|
2343
2298
|
async setAggregations(data) {
|
|
2299
|
+
var _a;
|
|
2300
|
+
const total = (_a = data.total) !== null && _a !== void 0 ? _a : (typeof data.count === 'number' ? data.count : undefined);
|
|
2301
|
+
if (total != null)
|
|
2302
|
+
this.aggregationsTotal = total;
|
|
2344
2303
|
this.aggregations = data;
|
|
2345
2304
|
}
|
|
2346
2305
|
// ── Lifecycle ──────────────────────────────────────────────────────────────
|
|
@@ -2371,6 +2330,147 @@ const MrdTable = class {
|
|
|
2371
2330
|
return '';
|
|
2372
2331
|
return this.sortDir === 'desc' ? `${this.sortField},desc` : this.sortField;
|
|
2373
2332
|
}
|
|
2333
|
+
/** Stable ordered list: primary view first, then alternatives (from the item prop). */
|
|
2334
|
+
get allViews() {
|
|
2335
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
2336
|
+
if (!this.item)
|
|
2337
|
+
return [];
|
|
2338
|
+
const it = this.item;
|
|
2339
|
+
return [
|
|
2340
|
+
{ 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 },
|
|
2341
|
+
...((_g = it.alternativeViews) !== null && _g !== void 0 ? _g : []).map(av => {
|
|
2342
|
+
var _a, _b, _c, _d;
|
|
2343
|
+
return ({
|
|
2344
|
+
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 : '',
|
|
2345
|
+
dataClass: av.dataClass,
|
|
2346
|
+
fromClass: av.fromClass,
|
|
2347
|
+
filterClass: av.filterClass,
|
|
2348
|
+
view: av.view,
|
|
2349
|
+
});
|
|
2350
|
+
}),
|
|
2351
|
+
];
|
|
2352
|
+
}
|
|
2353
|
+
/** Relative excel export path for the current view.
|
|
2354
|
+
* VIEW: /excel/{dataClass}
|
|
2355
|
+
* RELATED_VIEW: /excel/{fromClass}/{parentId}/{dataClass} */
|
|
2356
|
+
buildExcelPath() {
|
|
2357
|
+
var _a, _b, _c, _d;
|
|
2358
|
+
const v = this.allViews[this.activeViewIdx];
|
|
2359
|
+
if (!v)
|
|
2360
|
+
return '';
|
|
2361
|
+
if (((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW') {
|
|
2362
|
+
return `/excel/${(_b = v.fromClass) !== null && _b !== void 0 ? _b : ''}/${this.parentId}/${(_c = v.dataClass) !== null && _c !== void 0 ? _c : ''}`;
|
|
2363
|
+
}
|
|
2364
|
+
return `/excel/${(_d = v.dataClass) !== null && _d !== void 0 ? _d : ''}`;
|
|
2365
|
+
}
|
|
2366
|
+
buildActionDetail(action) {
|
|
2367
|
+
var _a, _b, _c;
|
|
2368
|
+
if (action === 'export') {
|
|
2369
|
+
return { action, path: this.buildExcelPath(), qs: this.buildQueryParams(0) };
|
|
2370
|
+
}
|
|
2371
|
+
if (action === 'create') {
|
|
2372
|
+
const v = this.allViews[this.activeViewIdx];
|
|
2373
|
+
const parentPath = ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW'
|
|
2374
|
+
? `/${(_b = v === null || v === void 0 ? void 0 : v.fromClass) !== null && _b !== void 0 ? _b : ''}/${this.parentId}`
|
|
2375
|
+
: null;
|
|
2376
|
+
return { action, dataClass: (_c = v === null || v === void 0 ? void 0 : v.dataClass) !== null && _c !== void 0 ? _c : '', parentPath };
|
|
2377
|
+
}
|
|
2378
|
+
return { action };
|
|
2379
|
+
}
|
|
2380
|
+
/** Relative data path for the current view, without query string.
|
|
2381
|
+
* VIEW: /{dataClass}
|
|
2382
|
+
* RELATED_VIEW: /{fromClass}/{parentId}/{dataClass} */
|
|
2383
|
+
buildDataPath() {
|
|
2384
|
+
var _a, _b, _c, _d;
|
|
2385
|
+
const v = this.allViews[this.activeViewIdx];
|
|
2386
|
+
if (!v)
|
|
2387
|
+
return '';
|
|
2388
|
+
if (((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW') {
|
|
2389
|
+
return `/${(_b = v.fromClass) !== null && _b !== void 0 ? _b : ''}/${this.parentId}/${(_c = v.dataClass) !== null && _c !== void 0 ? _c : ''}`;
|
|
2390
|
+
}
|
|
2391
|
+
return `/${(_d = v.dataClass) !== null && _d !== void 0 ? _d : ''}`;
|
|
2392
|
+
}
|
|
2393
|
+
/** Build query params for a page request from current sort, view filters, filterClass and active column filters. */
|
|
2394
|
+
buildQueryParams(page) {
|
|
2395
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
2396
|
+
const v = this.allViews[this.activeViewIdx];
|
|
2397
|
+
const p = new URLSearchParams();
|
|
2398
|
+
if (page > 0)
|
|
2399
|
+
p.set('page', String(page));
|
|
2400
|
+
const sort = this.sortParam();
|
|
2401
|
+
if (sort)
|
|
2402
|
+
p.set('sort', sort);
|
|
2403
|
+
const filterClass = v === null || v === void 0 ? void 0 : v.filterClass;
|
|
2404
|
+
if (filterClass)
|
|
2405
|
+
p.set('type', filterClass);
|
|
2406
|
+
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 : [])) {
|
|
2407
|
+
if (!f.name)
|
|
2408
|
+
continue;
|
|
2409
|
+
if (f.operator === 'EMPTY') {
|
|
2410
|
+
p.set(f.name, '');
|
|
2411
|
+
continue;
|
|
2412
|
+
}
|
|
2413
|
+
if (f.operator === 'NOT_EMPTY') {
|
|
2414
|
+
p.set(f.name + '_notempty', 'true');
|
|
2415
|
+
continue;
|
|
2416
|
+
}
|
|
2417
|
+
if (f.operator === 'STARTS_WITH') {
|
|
2418
|
+
p.set(f.name + '_startswith', String((_c = f.value) !== null && _c !== void 0 ? _c : ''));
|
|
2419
|
+
continue;
|
|
2420
|
+
}
|
|
2421
|
+
if (f.operator === 'FROM') {
|
|
2422
|
+
p.set(f.name + '_from', String((_d = f.value) !== null && _d !== void 0 ? _d : ''));
|
|
2423
|
+
continue;
|
|
2424
|
+
}
|
|
2425
|
+
if (f.operator === 'TO') {
|
|
2426
|
+
p.set(f.name + '_to', String((_e = f.value) !== null && _e !== void 0 ? _e : ''));
|
|
2427
|
+
continue;
|
|
2428
|
+
}
|
|
2429
|
+
if (f.value != null) {
|
|
2430
|
+
p.set(f.name, String(f.value));
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
for (const f of this.activeFilters.values()) {
|
|
2434
|
+
if (f.operator === 'isEmpty') {
|
|
2435
|
+
p.set(f.field, '');
|
|
2436
|
+
continue;
|
|
2437
|
+
}
|
|
2438
|
+
if (f.operator === 'isNotEmpty') {
|
|
2439
|
+
p.set(f.field + '_notempty', 'true');
|
|
2440
|
+
continue;
|
|
2441
|
+
}
|
|
2442
|
+
if (f.operator === 'startsWith') {
|
|
2443
|
+
p.set(f.field + '_startswith', String((_f = f.value) !== null && _f !== void 0 ? _f : ''));
|
|
2444
|
+
continue;
|
|
2445
|
+
}
|
|
2446
|
+
if ((_g = f.values) === null || _g === void 0 ? void 0 : _g.length) {
|
|
2447
|
+
p.set(f.field, f.values.join(','));
|
|
2448
|
+
continue;
|
|
2449
|
+
}
|
|
2450
|
+
if (f.value != null)
|
|
2451
|
+
p.set(f.field, String(f.value));
|
|
2452
|
+
if (f.from != null)
|
|
2453
|
+
p.set(f.field + '_from', String(f.from));
|
|
2454
|
+
if (f.to != null)
|
|
2455
|
+
p.set(f.field + '_to', String(f.to));
|
|
2456
|
+
}
|
|
2457
|
+
return p.toString();
|
|
2458
|
+
}
|
|
2459
|
+
get columns() {
|
|
2460
|
+
var _a, _b, _c;
|
|
2461
|
+
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 : []);
|
|
2462
|
+
}
|
|
2463
|
+
get tableActions() {
|
|
2464
|
+
var _a, _b;
|
|
2465
|
+
const raw = (_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.actions) !== null && _b !== void 0 ? _b : [];
|
|
2466
|
+
return (raw !== null && raw !== void 0 ? raw : []).reduce((acc, a) => {
|
|
2467
|
+
if (a === 'NEW')
|
|
2468
|
+
acc.push({ action: 'create', label: t('table_new_record', this.locale), icon: 'assets/sprites.svg#icon-plus', variant: 'primary' });
|
|
2469
|
+
if (a === 'EXPORT')
|
|
2470
|
+
acc.push({ action: 'export', label: t('table_export_excel', this.locale), icon: 'assets/sprites.svg#icon-file-excel' });
|
|
2471
|
+
return acc;
|
|
2472
|
+
}, []);
|
|
2473
|
+
}
|
|
2374
2474
|
colName(col) {
|
|
2375
2475
|
var _a;
|
|
2376
2476
|
return (_a = col.name) !== null && _a !== void 0 ? _a : '';
|
|
@@ -2381,6 +2481,25 @@ const MrdTable = class {
|
|
|
2381
2481
|
return 'RELATION';
|
|
2382
2482
|
return (_a = col.dataType) !== null && _a !== void 0 ? _a : 'TEXT';
|
|
2383
2483
|
}
|
|
2484
|
+
/** True when we have a reliable total: either from the aggregations response or because
|
|
2485
|
+
* a short page told us it was the last page (exact count from row length). */
|
|
2486
|
+
isTotalKnown() {
|
|
2487
|
+
if (this.aggregationsTotal != null)
|
|
2488
|
+
return true;
|
|
2489
|
+
for (const rows of this.loadedPages.values()) {
|
|
2490
|
+
if (rows.length < this.pageSize)
|
|
2491
|
+
return true;
|
|
2492
|
+
}
|
|
2493
|
+
return false;
|
|
2494
|
+
}
|
|
2495
|
+
/** Effective total: aggregations-response > totalElements prop > minKnownTotal from setPage(). */
|
|
2496
|
+
get baseTotal() {
|
|
2497
|
+
if (this.aggregationsTotal != null)
|
|
2498
|
+
return this.aggregationsTotal;
|
|
2499
|
+
if (this.totalElements > 0)
|
|
2500
|
+
return this.totalElements;
|
|
2501
|
+
return this.minKnownTotal;
|
|
2502
|
+
}
|
|
2384
2503
|
// ── Aggregation helpers ────────────────────────────────────────────────────
|
|
2385
2504
|
buildAggregationParams() {
|
|
2386
2505
|
var _a;
|
|
@@ -2401,17 +2520,32 @@ const MrdTable = class {
|
|
|
2401
2520
|
params.count = groups.count;
|
|
2402
2521
|
return Object.keys(params).length > 0 ? params : null;
|
|
2403
2522
|
}
|
|
2523
|
+
buildAggregationQs() {
|
|
2524
|
+
var _a, _b, _c;
|
|
2525
|
+
const p = new URLSearchParams(this.buildQueryParams(0));
|
|
2526
|
+
p.delete('page');
|
|
2527
|
+
p.delete('sort');
|
|
2528
|
+
const groups = this.buildAggregationParams();
|
|
2529
|
+
if ((_a = groups === null || groups === void 0 ? void 0 : groups.sum) === null || _a === void 0 ? void 0 : _a.length)
|
|
2530
|
+
p.set('sum', groups.sum.join(','));
|
|
2531
|
+
if ((_b = groups === null || groups === void 0 ? void 0 : groups.avg) === null || _b === void 0 ? void 0 : _b.length)
|
|
2532
|
+
p.set('avg', groups.avg.join(','));
|
|
2533
|
+
if ((_c = groups === null || groups === void 0 ? void 0 : groups.count) === null || _c === void 0 ? void 0 : _c.length)
|
|
2534
|
+
p.set('count', groups.count.join(','));
|
|
2535
|
+
return p.toString();
|
|
2536
|
+
}
|
|
2404
2537
|
emitLoadAggregations() {
|
|
2405
|
-
|
|
2406
|
-
if (params)
|
|
2407
|
-
this.mrdLoadAggregations.emit(params);
|
|
2538
|
+
this.mrdLoadAggregations.emit({ path: this.buildDataPath(), qs: this.buildQueryParams(0), aggQs: this.buildAggregationQs() });
|
|
2408
2539
|
}
|
|
2409
2540
|
renderAggregationValue(col) {
|
|
2410
|
-
var _a
|
|
2541
|
+
var _a;
|
|
2411
2542
|
if (col.type !== 'FIELD' || !col.aggregate || !this.aggregations)
|
|
2412
2543
|
return '';
|
|
2413
2544
|
const fn = col.aggregate.toLowerCase();
|
|
2414
|
-
const
|
|
2545
|
+
const aggData = this.aggregations[fn];
|
|
2546
|
+
const val = typeof aggData === 'object' && aggData !== null
|
|
2547
|
+
? aggData[(_a = col.name) !== null && _a !== void 0 ? _a : '']
|
|
2548
|
+
: undefined;
|
|
2415
2549
|
if (val == null)
|
|
2416
2550
|
return '';
|
|
2417
2551
|
const dt = col.dataType;
|
|
@@ -2436,9 +2570,10 @@ const MrdTable = class {
|
|
|
2436
2570
|
this.colWidths = [];
|
|
2437
2571
|
this.scrollTop = 0;
|
|
2438
2572
|
this.renderStart = 0;
|
|
2439
|
-
|
|
2440
|
-
//
|
|
2441
|
-
|
|
2573
|
+
this.minKnownTotal = 0;
|
|
2574
|
+
// Mirror init(): use visibleCount so the first page is always requested.
|
|
2575
|
+
// setPage() will clamp renderEnd down when the last page is shorter.
|
|
2576
|
+
this.renderEnd = this.visibleCount() - 1;
|
|
2442
2577
|
const scroller = this.el.querySelector('.mrd-table__scroll');
|
|
2443
2578
|
if (scroller)
|
|
2444
2579
|
scroller.scrollTop = 0;
|
|
@@ -2469,7 +2604,7 @@ const MrdTable = class {
|
|
|
2469
2604
|
for (let p = firstPage; p <= lastPage; p++) {
|
|
2470
2605
|
if (!this.loadedPages.has(p) && !next.has(p)) {
|
|
2471
2606
|
next.add(p);
|
|
2472
|
-
this.mrdLoadPage.emit({ page: p, sort: this.sortParam() });
|
|
2607
|
+
this.mrdLoadPage.emit({ page: p, sort: this.sortParam(), path: this.buildDataPath(), qs: this.buildQueryParams(p) });
|
|
2473
2608
|
changed = true;
|
|
2474
2609
|
}
|
|
2475
2610
|
}
|
|
@@ -2511,7 +2646,7 @@ const MrdTable = class {
|
|
|
2511
2646
|
if (pageEnd < this.renderStart || pageStart > this.renderEnd)
|
|
2512
2647
|
continue;
|
|
2513
2648
|
next.add(page);
|
|
2514
|
-
this.mrdLoadPage.emit({ page, sort: this.sortParam() });
|
|
2649
|
+
this.mrdLoadPage.emit({ page, sort: this.sortParam(), path: this.buildDataPath(), qs: this.buildQueryParams(page) });
|
|
2515
2650
|
changed = true;
|
|
2516
2651
|
}
|
|
2517
2652
|
this.pendingPages.clear();
|
|
@@ -2703,9 +2838,9 @@ const MrdTable = class {
|
|
|
2703
2838
|
}
|
|
2704
2839
|
this.activeFilters = next;
|
|
2705
2840
|
this.closeFilterPopup();
|
|
2706
|
-
this.mrdFilter.emit({ filters: Array.from(this.activeFilters.values()) });
|
|
2707
2841
|
this.aggregations = null;
|
|
2708
|
-
this.
|
|
2842
|
+
this.aggregationsTotal = null;
|
|
2843
|
+
this.aggregationsPending = true;
|
|
2709
2844
|
if (this.totalElements > 0) {
|
|
2710
2845
|
this.resetPages();
|
|
2711
2846
|
this.emitPagesForWindow(this.renderStart, this.renderEnd);
|
|
@@ -2718,9 +2853,9 @@ const MrdTable = class {
|
|
|
2718
2853
|
next.delete(name);
|
|
2719
2854
|
this.activeFilters = next;
|
|
2720
2855
|
this.closeFilterPopup();
|
|
2721
|
-
this.mrdFilter.emit({ filters: Array.from(this.activeFilters.values()) });
|
|
2722
2856
|
this.aggregations = null;
|
|
2723
|
-
this.
|
|
2857
|
+
this.aggregationsTotal = null;
|
|
2858
|
+
this.aggregationsPending = true;
|
|
2724
2859
|
if (this.totalElements > 0) {
|
|
2725
2860
|
this.resetPages();
|
|
2726
2861
|
this.emitPagesForWindow(this.renderStart, this.renderEnd);
|
|
@@ -2728,37 +2863,39 @@ const MrdTable = class {
|
|
|
2728
2863
|
}
|
|
2729
2864
|
clearAllFilters() {
|
|
2730
2865
|
this.activeFilters = new Map();
|
|
2731
|
-
this.mrdFilter.emit({ filters: [] });
|
|
2732
2866
|
this.aggregations = null;
|
|
2733
|
-
this.
|
|
2867
|
+
this.aggregationsTotal = null;
|
|
2868
|
+
this.aggregationsPending = true;
|
|
2734
2869
|
if (this.totalElements > 0) {
|
|
2735
2870
|
this.resetPages();
|
|
2736
2871
|
this.emitPagesForWindow(this.renderStart, this.renderEnd);
|
|
2737
2872
|
}
|
|
2738
2873
|
}
|
|
2739
2874
|
// ── View switcher ──────────────────────────────────────────────────────────
|
|
2740
|
-
handleViewSwitch(
|
|
2741
|
-
|
|
2875
|
+
handleViewSwitch(targetIdx) {
|
|
2876
|
+
var _a, _b;
|
|
2877
|
+
const target = this.allViews[targetIdx];
|
|
2878
|
+
if (!(target === null || target === void 0 ? void 0 : target.view))
|
|
2879
|
+
return;
|
|
2880
|
+
this.activeViewIdx = targetIdx;
|
|
2881
|
+
this.applyDefaultSort((_b = (_a = target.view) === null || _a === void 0 ? void 0 : _a.defaultSort) !== null && _b !== void 0 ? _b : '');
|
|
2882
|
+
this.activeFilters = new Map();
|
|
2883
|
+
this.init();
|
|
2742
2884
|
}
|
|
2743
2885
|
// ── Render: toolbar ────────────────────────────────────────────────────────
|
|
2744
2886
|
renderToolbar() {
|
|
2745
|
-
var _a, _b;
|
|
2746
2887
|
const filterCount = this.activeFilters.size;
|
|
2747
|
-
const
|
|
2748
|
-
const
|
|
2888
|
+
const actions = this.tableActions;
|
|
2889
|
+
const allViews = this.allViews;
|
|
2890
|
+
const hasActions = actions.length > 0;
|
|
2891
|
+
const hasViewSwitcher = allViews.length > 1;
|
|
2749
2892
|
return (h("div", { class: "mrd-table__toolbar" }, h("div", { class: "mrd-table__toolbar-left" }, h("button", { class: `mrd-table__action mrd-table__action--secondary mrd-table__filter-toggle${this.filterMode ? ' mrd-table__filter-toggle--active' : ''}`, onClick: () => this.handleFilterToggle() }, h("svg", { class: "mrd-table__action-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, h("path", { fill: "currentColor", d: "M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z" })), filterCount > 0 && h("span", { class: "mrd-table__filter-badge" }, filterCount), 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 && (h("button", { class: "mrd-table__action mrd-table__action--secondary", onClick: () => this.clearAllFilters() }, 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__action-tooltip" }, t('table_filter_clear_all', this.locale))))), hasViewSwitcher && (h("div", { class: "mrd-table__toolbar-center" }, h("select", { class: "mrd-table__view-select", onChange: (e) => {
|
|
2750
|
-
const
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
this.handleViewSwitch(view);
|
|
2755
|
-
}
|
|
2756
|
-
} }, h("option", { value: "" }, this.viewLabel), this.alternativeViews.map(v => {
|
|
2757
|
-
var _a;
|
|
2758
|
-
return (h("option", { value: v.name }, (_a = v.label) !== null && _a !== void 0 ? _a : v.name));
|
|
2759
|
-
})))), hasActions && (h("div", { class: "mrd-table__toolbar-right" }, this.actions.map(a => {
|
|
2893
|
+
const idx = parseInt(e.target.value, 10);
|
|
2894
|
+
if (!isNaN(idx) && idx !== this.activeViewIdx)
|
|
2895
|
+
this.handleViewSwitch(idx);
|
|
2896
|
+
} }, allViews.map((v, i) => (h("option", { value: String(i), selected: i === this.activeViewIdx }, v.label)))))), hasActions && (h("div", { class: "mrd-table__toolbar-right" }, actions.map(a => {
|
|
2760
2897
|
var _a;
|
|
2761
|
-
return (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(
|
|
2898
|
+
return (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
|
|
2762
2899
|
? h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, h("use", { href: a.icon }))
|
|
2763
2900
|
: a.label, h("span", { class: "mrd-table__action-tooltip" }, a.label)));
|
|
2764
2901
|
})))));
|
|
@@ -2852,10 +2989,9 @@ const MrdTable = class {
|
|
|
2852
2989
|
return (h("div", { class: "mrd-table__filter-popup", style: { top: `${this.popupPos.top}px`, left: `${this.popupPos.left}px` }, onClick: (e) => e.stopPropagation() }, h("div", { class: "mrd-table__filter-popup-header" }, h("span", { class: "mrd-table__filter-popup-title" }, label), h("button", { class: "mrd-table__filter-close", onClick: () => this.closeFilterPopup() }, "\u2715")), h("div", { class: "mrd-table__filter-section" }, h("div", { class: "mrd-table__filter-section-label" }, t('filter_sorting', this.locale)), h("div", { class: "mrd-table__filter-sort-buttons" }, h("button", { class: `mrd-table__filter-sort-btn${sortActive && this.sortDir === 'asc' ? ' mrd-table__filter-sort-btn--active' : ''}`, onClick: () => this.applySort(col, 'asc') }, "\u25B2 ", t('filter_ascending', this.locale)), h("button", { class: `mrd-table__filter-sort-btn${sortActive && this.sortDir === 'desc' ? ' mrd-table__filter-sort-btn--active' : ''}`, onClick: () => this.applySort(col, 'desc') }, "\u25BC ", t('filter_descending', this.locale)))), h("div", { class: "mrd-table__filter-divider" }), h("div", { class: "mrd-table__filter-section" }, h("div", { class: "mrd-table__filter-section-label" }, t('filter_section', this.locale)), this.renderFilterEditor(col)), h("div", { class: "mrd-table__filter-popup-footer" }, h("button", { class: "mrd-table__filter-btn mrd-table__filter-btn--clear", onClick: () => this.clearFilter() }, t('filter_clear', this.locale)), h("button", { class: "mrd-table__filter-btn mrd-table__filter-btn--apply", onClick: () => this.applyFilter() }, t('filter_apply', this.locale)))));
|
|
2853
2990
|
}
|
|
2854
2991
|
// ── Render: footer ────────────────────────────────────────────────────────
|
|
2855
|
-
renderFooter(rowCount, effectiveTotal) {
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
if (total === 0) {
|
|
2992
|
+
renderFooter(rowCount, effectiveTotal, isTotalKnown = true) {
|
|
2993
|
+
// Non-paginated mode: totalElements=0 and no paginated data loaded yet
|
|
2994
|
+
if (this.totalElements === 0 && this.loadedPages.size === 0) {
|
|
2859
2995
|
const count = rowCount !== null && rowCount !== void 0 ? rowCount : 0;
|
|
2860
2996
|
if (count === 0)
|
|
2861
2997
|
return null;
|
|
@@ -2864,13 +3000,14 @@ const MrdTable = class {
|
|
|
2864
3000
|
// Paginated mode: only show once page 0 has loaded (avoids stale total during filter reset)
|
|
2865
3001
|
if (!this.loadedPages.has(0))
|
|
2866
3002
|
return null;
|
|
2867
|
-
//
|
|
2868
|
-
|
|
2869
|
-
const displayTotal = effectiveTotal !== null && effectiveTotal !== void 0 ? effectiveTotal : total;
|
|
3003
|
+
// effectiveTotal from render(); fall back to baseTotal when not provided.
|
|
3004
|
+
const displayTotal = effectiveTotal !== null && effectiveTotal !== void 0 ? effectiveTotal : this.baseTotal;
|
|
2870
3005
|
// Compute from/to independently so partial rows at top/bottom are included.
|
|
2871
3006
|
const from = Math.min(Math.floor(this.scrollTop / this.rowHeight) + 1, displayTotal);
|
|
2872
3007
|
const to = Math.min(Math.ceil((this.scrollTop + this.tableHeight) / this.rowHeight), displayTotal);
|
|
2873
|
-
|
|
3008
|
+
// Show '…' for the total until we have a reliable count (aggregations or last page loaded).
|
|
3009
|
+
const totalLabel = isTotalKnown ? String(displayTotal) : '…';
|
|
3010
|
+
return (h("div", { class: "mrd-table__footer" }, from, "\u2013", to, " ", t('table_of', this.locale), " ", totalLabel));
|
|
2874
3011
|
}
|
|
2875
3012
|
// ── Render: cell ──────────────────────────────────────────────────────────
|
|
2876
3013
|
renderCell(col, row) {
|
|
@@ -2929,7 +3066,9 @@ const MrdTable = class {
|
|
|
2929
3066
|
if (!((_a = this.columns) === null || _a === void 0 ? void 0 : _a.length))
|
|
2930
3067
|
return null;
|
|
2931
3068
|
// ── Non-paginated mode ──────────────────────────────────────────────────
|
|
2932
|
-
|
|
3069
|
+
// Only enter non-paginated mode when totalElements is 0 AND no paginated data
|
|
3070
|
+
// has been loaded yet — prevents the wrong branch when the host omits totalElements.
|
|
3071
|
+
if (this.totalElements === 0 && this.loadedPages.size === 0) {
|
|
2933
3072
|
return (h(Host, null, this.renderToolbar(), h("div", { class: "mrd-table" }, h("table", { class: "mrd-table__table" }, h("thead", null, h("tr", null, this.columns.map(col => {
|
|
2934
3073
|
var _a;
|
|
2935
3074
|
const name = this.colName(col);
|
|
@@ -2946,8 +3085,8 @@ const MrdTable = class {
|
|
|
2946
3085
|
// Derive the authoritative row count from loaded pages:
|
|
2947
3086
|
// if any loaded page is shorter than pageSize it is the last page,
|
|
2948
3087
|
// so the true total cannot exceed (pageNum * pageSize + pageRows.length).
|
|
2949
|
-
//
|
|
2950
|
-
let effectiveTotal = this.
|
|
3088
|
+
// aggregationsTotal (from setAggregations) takes priority over the totalElements prop.
|
|
3089
|
+
let effectiveTotal = this.baseTotal;
|
|
2951
3090
|
for (const [pageNum, pageRows] of this.loadedPages) {
|
|
2952
3091
|
if (pageRows.length < this.pageSize) {
|
|
2953
3092
|
effectiveTotal = Math.min(effectiveTotal, pageNum * this.pageSize + pageRows.length);
|
|
@@ -2984,7 +3123,7 @@ const MrdTable = class {
|
|
|
2984
3123
|
isFiltered ? 'mrd-table__header--filtered' : '',
|
|
2985
3124
|
].filter(Boolean).join(' ');
|
|
2986
3125
|
return (h("th", { class: cls, style: this.colWidths[idx] ? { width: `${this.colWidths[idx]}px` } : undefined, onClick: isInteractive ? ((e) => this.filterMode ? this.handleFilterOpen(col, e) : this.handleSortClick(col)) : undefined }, h("span", { class: "mrd-table__header-label" }, (_a = col.label) !== null && _a !== void 0 ? _a : ''), isInteractive && isActive && (h("span", { class: "mrd-table__sort-icon", "aria-hidden": "true" }, this.sortDir === 'asc' ? '▲' : '▼')), isInteractive && !isActive && !this.filterMode && (h("span", { class: "mrd-table__sort-icon", "aria-hidden": "true" }, "\u21C5")), isInteractive && isFiltered && this.renderFilterIcon()));
|
|
2987
|
-
}))), h("tbody", null, topSpacerHeight > 0 && (h("tr", { class: "mrd-table__spacer", style: { height: `${topSpacerHeight}px` } }, h("td", { colSpan: colCount }))), renderedRows, bottomSpacerHeight > 0 && (h("tr", { class: "mrd-table__spacer", style: { height: `${bottomSpacerHeight}px` } }, h("td", { colSpan: colCount })))), this.renderTotalsRow())), effectiveTotal === 0 && this.loadedPages.has(0) && (h("p", { class: "mrd-table__empty" }, t('no_results', this.locale))), effectiveTotal > 0 && this.renderFooter(undefined, effectiveTotal), this.renderFilterPopup(), this.renderTextblockModal()));
|
|
3126
|
+
}))), h("tbody", null, topSpacerHeight > 0 && (h("tr", { class: "mrd-table__spacer", style: { height: `${topSpacerHeight}px` } }, h("td", { colSpan: colCount }))), renderedRows, bottomSpacerHeight > 0 && (h("tr", { class: "mrd-table__spacer", style: { height: `${bottomSpacerHeight}px` } }, h("td", { colSpan: colCount })))), this.renderTotalsRow())), effectiveTotal === 0 && this.loadedPages.has(0) && (h("p", { class: "mrd-table__empty" }, t('no_results', this.locale))), effectiveTotal > 0 && this.renderFooter(undefined, effectiveTotal, this.isTotalKnown()), this.renderFilterPopup(), this.renderTextblockModal()));
|
|
2988
3127
|
}
|
|
2989
3128
|
renderFilterIcon() {
|
|
2990
3129
|
return (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" }))));
|
|
@@ -3004,8 +3143,8 @@ const MrdTable = class {
|
|
|
3004
3143
|
"totalElements": [{
|
|
3005
3144
|
"totalElementsChanged": 0
|
|
3006
3145
|
}],
|
|
3007
|
-
"
|
|
3008
|
-
"
|
|
3146
|
+
"item": [{
|
|
3147
|
+
"itemChanged": 0
|
|
3009
3148
|
}]
|
|
3010
3149
|
}; }
|
|
3011
3150
|
};
|