@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
|
@@ -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
|
-
/**
|
|
1377
|
+
/** Legacy: view metadata map (ClientDashboardMetadata.views). Not needed in new flat format. */
|
|
1379
1378
|
this.views = {};
|
|
1380
|
-
/**
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
1423
|
-
|
|
1424
|
-
this.emitLoadViews();
|
|
1411
|
+
if (newVal && Object.keys(newVal).length > 0) {
|
|
1412
|
+
setTimeout(() => this.initEmbeddedTables(), 0);
|
|
1425
1413
|
}
|
|
1426
1414
|
}
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
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,21 +1455,17 @@ 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
|
|
1495
|
-
* Pass
|
|
1458
|
+
* Pass totalElements to update the pagination total (safe to pass on every page).
|
|
1459
|
+
* Pass hasNext (from _links.next presence) so the table can decide whether to emit aggregations.
|
|
1496
1460
|
*/
|
|
1497
|
-
async setViewPage(name, page, rows, totalElements,
|
|
1498
|
-
if (pageLinks) {
|
|
1499
|
-
this.viewLinksMap = Object.assign(Object.assign({}, this.viewLinksMap), { [name]: pageLinks });
|
|
1500
|
-
}
|
|
1461
|
+
async setViewPage(name, page, rows, totalElements, hasNext) {
|
|
1501
1462
|
const table = this.el.querySelector(`mrd-table[data-view="${name}"]`);
|
|
1502
1463
|
if (!table)
|
|
1503
1464
|
return;
|
|
1504
1465
|
if (totalElements !== undefined) {
|
|
1505
1466
|
table.totalElements = totalElements;
|
|
1506
|
-
await table.init();
|
|
1507
1467
|
}
|
|
1508
|
-
await table.setPage(page, rows);
|
|
1468
|
+
await table.setPage(page, rows, hasNext);
|
|
1509
1469
|
}
|
|
1510
1470
|
/** Inject aggregation totals into an embedded mrd-table for a VIEW or RELATED_VIEW item. */
|
|
1511
1471
|
async setViewAggregations(name, data) {
|
|
@@ -1639,63 +1599,36 @@ const MrdLayoutSection = class {
|
|
|
1639
1599
|
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
1600
|
}
|
|
1641
1601
|
renderRelatedView(item) {
|
|
1642
|
-
var _a, _b, _c, _d, _e, _f
|
|
1643
|
-
const
|
|
1644
|
-
|
|
1645
|
-
if (!name)
|
|
1602
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1603
|
+
const key = this.viewKeyFor(item);
|
|
1604
|
+
if (!key)
|
|
1646
1605
|
return null;
|
|
1647
|
-
|
|
1648
|
-
if (!viewConfig)
|
|
1606
|
+
if (!item.view)
|
|
1649
1607
|
return null;
|
|
1650
1608
|
const showTitle = (_a = item.showTitle) !== null && _a !== void 0 ? _a : false;
|
|
1651
|
-
|
|
1652
|
-
const
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
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) => {
|
|
1609
|
+
// Extract parentId from data._links.self.href for RELATED_VIEW path construction
|
|
1610
|
+
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 : '';
|
|
1611
|
+
const parentId = (_f = selfHref.split('/').filter(Boolean).pop()) !== null && _f !== void 0 ? _f : '';
|
|
1612
|
+
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) => {
|
|
1613
|
+
var _a;
|
|
1682
1614
|
e.stopPropagation();
|
|
1683
|
-
this.
|
|
1684
|
-
},
|
|
1685
|
-
var _a, _b, _c
|
|
1615
|
+
this.mrdLoadViewAggregations.emit(Object.assign({ name: key, dataClass: (_a = item.dataClass) !== null && _a !== void 0 ? _a : key }, e.detail));
|
|
1616
|
+
}, onMrdRowClick: (e) => {
|
|
1617
|
+
var _a, _b, _c;
|
|
1686
1618
|
e.stopPropagation();
|
|
1687
|
-
const
|
|
1688
|
-
|
|
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));
|
|
1619
|
+
const row = e.detail;
|
|
1620
|
+
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
1621
|
}, onMrdAction: (e) => {
|
|
1694
|
-
var _a
|
|
1622
|
+
var _a;
|
|
1695
1623
|
e.stopPropagation();
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1624
|
+
this.mrdViewAction.emit({
|
|
1625
|
+
name: key,
|
|
1626
|
+
action: e.detail.action,
|
|
1627
|
+
dataClass: (_a = item.dataClass) !== null && _a !== void 0 ? _a : key,
|
|
1628
|
+
path: e.detail.path,
|
|
1629
|
+
qs: e.detail.qs,
|
|
1630
|
+
parentPath: e.detail.parentPath,
|
|
1631
|
+
});
|
|
1699
1632
|
} })));
|
|
1700
1633
|
}
|
|
1701
1634
|
renderItem(item) {
|
|
@@ -1729,13 +1662,10 @@ const MrdLayoutSection = class {
|
|
|
1729
1662
|
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
1663
|
}
|
|
1731
1664
|
render() {
|
|
1732
|
-
return (index.h(index.Host, { key: '
|
|
1665
|
+
return (index.h(index.Host, { key: '0a3a58f5c80716bc0a7ba1b9468b721706d2ce4a' }, index.h("div", { key: '7cf63580c584811c1bb84b419e8d13026e432fba', class: "mrd-layout-section" }, this.items.map(item => this.renderItem(item))), this.renderImageModal()));
|
|
1733
1666
|
}
|
|
1734
1667
|
get el() { return index.getElement(this); }
|
|
1735
1668
|
static get watchers() { return {
|
|
1736
|
-
"links": [{
|
|
1737
|
-
"linksChanged": 0
|
|
1738
|
-
}],
|
|
1739
1669
|
"data": [{
|
|
1740
1670
|
"dataChanged": 0
|
|
1741
1671
|
}]
|
|
@@ -2201,9 +2131,7 @@ const MrdTable = class {
|
|
|
2201
2131
|
this.mrdLoadPage = index.createEvent(this, "mrdLoadPage");
|
|
2202
2132
|
this.mrdRowClick = index.createEvent(this, "mrdRowClick");
|
|
2203
2133
|
this.mrdAction = index.createEvent(this, "mrdAction");
|
|
2204
|
-
this.mrdFilter = index.createEvent(this, "mrdFilter");
|
|
2205
2134
|
this.mrdDownload = index.createEvent(this, "mrdDownload");
|
|
2206
|
-
this.mrdSwitchView = index.createEvent(this, "mrdSwitchView");
|
|
2207
2135
|
this.mrdLoadAggregations = index.createEvent(this, "mrdLoadAggregations");
|
|
2208
2136
|
// ── Non-state internals ────────────────────────────────────────────────────
|
|
2209
2137
|
this.pendingPages = new Set();
|
|
@@ -2211,7 +2139,10 @@ const MrdTable = class {
|
|
|
2211
2139
|
this.outsideClickHandler = null;
|
|
2212
2140
|
this.keydownHandler = null;
|
|
2213
2141
|
// ── Props ──────────────────────────────────────────────────────────────────
|
|
2214
|
-
|
|
2142
|
+
/** The VIEW or RELATED_VIEW layout item. Contains view config, dataClass, fromClass, actions etc. */
|
|
2143
|
+
this.item = null;
|
|
2144
|
+
/** Parent record id — required for RELATED_VIEW to build /{fromClass}/{parentId}/{dataClass}. */
|
|
2145
|
+
this.parentId = '';
|
|
2215
2146
|
/** Direct rows (non-paginated mode, used when totalElements === 0). */
|
|
2216
2147
|
this.rows = [];
|
|
2217
2148
|
this.locale = navigator.language;
|
|
@@ -2223,16 +2154,9 @@ const MrdTable = class {
|
|
|
2223
2154
|
this.rowHeight = 36;
|
|
2224
2155
|
/** Height of the scroll container in px. */
|
|
2225
2156
|
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
2157
|
// ── Internal state ─────────────────────────────────────────────────────────
|
|
2158
|
+
/** Index into allViews[] for the currently displayed view. 0 = primary, 1+ = alternatives. */
|
|
2159
|
+
this.activeViewIdx = 0;
|
|
2236
2160
|
this.loadedPages = new Map();
|
|
2237
2161
|
this.requestedPages = new Set();
|
|
2238
2162
|
this.renderStart = 0;
|
|
@@ -2258,10 +2182,16 @@ const MrdTable = class {
|
|
|
2258
2182
|
this.jsonModal = null;
|
|
2259
2183
|
/** Aggregation totals received from the host via setAggregations(). Null = not yet loaded. */
|
|
2260
2184
|
this.aggregations = null;
|
|
2185
|
+
/** Record count received via setAggregations().total; overrides totalElements for display. */
|
|
2186
|
+
this.aggregationsTotal = null;
|
|
2187
|
+
/** True when a fresh aggregations request is needed (set on init / filter change). */
|
|
2188
|
+
this.aggregationsPending = false;
|
|
2189
|
+
/** Lower bound on total derived from setPage() hasNext info; grows as pages load. */
|
|
2190
|
+
this.minKnownTotal = 0;
|
|
2261
2191
|
this.handleScroll = (e) => {
|
|
2262
2192
|
const scroller = e.currentTarget;
|
|
2263
2193
|
const scrollTop = scroller.scrollTop;
|
|
2264
|
-
const total = this.
|
|
2194
|
+
const total = this.baseTotal;
|
|
2265
2195
|
const visStart = Math.floor(scrollTop / this.rowHeight);
|
|
2266
2196
|
const visEnd = Math.min(visStart + this.visibleCount(), total - 1);
|
|
2267
2197
|
this.scrollTop = scrollTop;
|
|
@@ -2275,13 +2205,16 @@ const MrdTable = class {
|
|
|
2275
2205
|
totalElementsChanged(newVal) {
|
|
2276
2206
|
this.renderEnd = Math.min(this.renderEnd, Math.max(0, newVal - 1));
|
|
2277
2207
|
}
|
|
2278
|
-
/**
|
|
2279
|
-
|
|
2280
|
-
|
|
2208
|
+
/** Reset to primary view when the item prop is replaced from outside. */
|
|
2209
|
+
itemChanged(newVal) {
|
|
2210
|
+
var _a, _b;
|
|
2211
|
+
this.activeViewIdx = 0;
|
|
2212
|
+
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
2213
|
}
|
|
2282
2214
|
// ── Lifecycle ──────────────────────────────────────────────────────────────
|
|
2283
2215
|
componentWillLoad() {
|
|
2284
|
-
|
|
2216
|
+
var _a, _b, _c;
|
|
2217
|
+
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
2218
|
}
|
|
2286
2219
|
// ── Helpers ────────────────────────────────────────────────────────────────
|
|
2287
2220
|
applyDefaultSort(defaultSort) {
|
|
@@ -2313,14 +2246,19 @@ const MrdTable = class {
|
|
|
2313
2246
|
this.colWidths = [];
|
|
2314
2247
|
this.scrollTop = 0;
|
|
2315
2248
|
this.renderStart = 0;
|
|
2316
|
-
//
|
|
2317
|
-
//
|
|
2318
|
-
this.renderEnd =
|
|
2249
|
+
// Always fill the visible viewport on init — totalElements may be stale from a
|
|
2250
|
+
// previous view. setPage() clamps renderEnd when the page is shorter than pageSize.
|
|
2251
|
+
this.renderEnd = this.visibleCount() - 1;
|
|
2319
2252
|
const scroller = this.el.querySelector('.mrd-table__scroll');
|
|
2320
2253
|
if (scroller)
|
|
2321
2254
|
scroller.scrollTop = 0;
|
|
2322
2255
|
this.aggregations = null;
|
|
2323
|
-
this.
|
|
2256
|
+
this.aggregationsTotal = null;
|
|
2257
|
+
this.aggregationsPending = true;
|
|
2258
|
+
this.minKnownTotal = 0;
|
|
2259
|
+
// Always request page 0 — totalElements may be unknown (0) on first load.
|
|
2260
|
+
this.mrdLoadPage.emit({ page: 0, sort: this.sortParam(), path: this.buildDataPath(), qs: this.buildQueryParams(0) });
|
|
2261
|
+
this.requestedPages = new Set([0]);
|
|
2324
2262
|
}
|
|
2325
2263
|
/**
|
|
2326
2264
|
* Inject the rows for a given page (0-based).
|
|
@@ -2329,20 +2267,41 @@ const MrdTable = class {
|
|
|
2329
2267
|
* When the page contains fewer rows than pageSize it is the last page.
|
|
2330
2268
|
* renderEnd is clamped immediately so no loading-placeholder rows appear
|
|
2331
2269
|
* beyond the actual data — without requiring the host to update totalElements.
|
|
2270
|
+
*
|
|
2271
|
+
* Pass hasNext (from _links.next in the API response) for accurate last-page
|
|
2272
|
+
* detection even when rows.length === pageSize (exact multiple of page size).
|
|
2332
2273
|
*/
|
|
2333
|
-
async setPage(pageNumber, rows) {
|
|
2334
|
-
|
|
2274
|
+
async setPage(pageNumber, rows, hasNext) {
|
|
2275
|
+
const isLastPage = hasNext !== undefined ? !hasNext : rows.length < this.pageSize;
|
|
2276
|
+
if (isLastPage) {
|
|
2335
2277
|
// lastRowIdx is -1 when the page is empty; clamp renderEnd to -1 so the
|
|
2336
2278
|
// render loop does not execute and no shimmer rows appear.
|
|
2337
2279
|
const lastRowIdx = pageNumber * this.pageSize + rows.length - 1;
|
|
2338
2280
|
this.renderEnd = Math.min(this.renderEnd, lastRowIdx);
|
|
2281
|
+
// Exact total is known: update minKnownTotal so the scroll container has the right height.
|
|
2282
|
+
this.minKnownTotal = pageNumber * this.pageSize + rows.length;
|
|
2283
|
+
}
|
|
2284
|
+
else {
|
|
2285
|
+
// There is at least one more page — ensure the scrollbar covers at least that next page.
|
|
2286
|
+
this.minKnownTotal = Math.max(this.minKnownTotal, (pageNumber + 1) * this.pageSize + 1);
|
|
2339
2287
|
}
|
|
2340
2288
|
const next = new Map(this.loadedPages);
|
|
2341
2289
|
next.set(pageNumber, rows);
|
|
2342
2290
|
this.loadedPages = next;
|
|
2291
|
+
if (pageNumber === 0 && this.aggregationsPending) {
|
|
2292
|
+
this.aggregationsPending = false;
|
|
2293
|
+
const hasAggColumns = this.columns.some(c => c.type === 'FIELD' && c.aggregate);
|
|
2294
|
+
if (!isLastPage || hasAggColumns) {
|
|
2295
|
+
this.emitLoadAggregations();
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2343
2298
|
}
|
|
2344
2299
|
/** Inject aggregation totals returned by the /aggregations endpoint. */
|
|
2345
2300
|
async setAggregations(data) {
|
|
2301
|
+
var _a;
|
|
2302
|
+
const total = (_a = data.total) !== null && _a !== void 0 ? _a : (typeof data.count === 'number' ? data.count : undefined);
|
|
2303
|
+
if (total != null)
|
|
2304
|
+
this.aggregationsTotal = total;
|
|
2346
2305
|
this.aggregations = data;
|
|
2347
2306
|
}
|
|
2348
2307
|
// ── Lifecycle ──────────────────────────────────────────────────────────────
|
|
@@ -2373,6 +2332,147 @@ const MrdTable = class {
|
|
|
2373
2332
|
return '';
|
|
2374
2333
|
return this.sortDir === 'desc' ? `${this.sortField},desc` : this.sortField;
|
|
2375
2334
|
}
|
|
2335
|
+
/** Stable ordered list: primary view first, then alternatives (from the item prop). */
|
|
2336
|
+
get allViews() {
|
|
2337
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
2338
|
+
if (!this.item)
|
|
2339
|
+
return [];
|
|
2340
|
+
const it = this.item;
|
|
2341
|
+
return [
|
|
2342
|
+
{ 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 },
|
|
2343
|
+
...((_g = it.alternativeViews) !== null && _g !== void 0 ? _g : []).map(av => {
|
|
2344
|
+
var _a, _b, _c, _d;
|
|
2345
|
+
return ({
|
|
2346
|
+
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 : '',
|
|
2347
|
+
dataClass: av.dataClass,
|
|
2348
|
+
fromClass: av.fromClass,
|
|
2349
|
+
filterClass: av.filterClass,
|
|
2350
|
+
view: av.view,
|
|
2351
|
+
});
|
|
2352
|
+
}),
|
|
2353
|
+
];
|
|
2354
|
+
}
|
|
2355
|
+
/** Relative excel export path for the current view.
|
|
2356
|
+
* VIEW: /excel/{dataClass}
|
|
2357
|
+
* RELATED_VIEW: /excel/{fromClass}/{parentId}/{dataClass} */
|
|
2358
|
+
buildExcelPath() {
|
|
2359
|
+
var _a, _b, _c, _d;
|
|
2360
|
+
const v = this.allViews[this.activeViewIdx];
|
|
2361
|
+
if (!v)
|
|
2362
|
+
return '';
|
|
2363
|
+
if (((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW') {
|
|
2364
|
+
return `/excel/${(_b = v.fromClass) !== null && _b !== void 0 ? _b : ''}/${this.parentId}/${(_c = v.dataClass) !== null && _c !== void 0 ? _c : ''}`;
|
|
2365
|
+
}
|
|
2366
|
+
return `/excel/${(_d = v.dataClass) !== null && _d !== void 0 ? _d : ''}`;
|
|
2367
|
+
}
|
|
2368
|
+
buildActionDetail(action) {
|
|
2369
|
+
var _a, _b, _c;
|
|
2370
|
+
if (action === 'export') {
|
|
2371
|
+
return { action, path: this.buildExcelPath(), qs: this.buildQueryParams(0) };
|
|
2372
|
+
}
|
|
2373
|
+
if (action === 'create') {
|
|
2374
|
+
const v = this.allViews[this.activeViewIdx];
|
|
2375
|
+
const parentPath = ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW'
|
|
2376
|
+
? `/${(_b = v === null || v === void 0 ? void 0 : v.fromClass) !== null && _b !== void 0 ? _b : ''}/${this.parentId}`
|
|
2377
|
+
: null;
|
|
2378
|
+
return { action, dataClass: (_c = v === null || v === void 0 ? void 0 : v.dataClass) !== null && _c !== void 0 ? _c : '', parentPath };
|
|
2379
|
+
}
|
|
2380
|
+
return { action };
|
|
2381
|
+
}
|
|
2382
|
+
/** Relative data path for the current view, without query string.
|
|
2383
|
+
* VIEW: /{dataClass}
|
|
2384
|
+
* RELATED_VIEW: /{fromClass}/{parentId}/{dataClass} */
|
|
2385
|
+
buildDataPath() {
|
|
2386
|
+
var _a, _b, _c, _d;
|
|
2387
|
+
const v = this.allViews[this.activeViewIdx];
|
|
2388
|
+
if (!v)
|
|
2389
|
+
return '';
|
|
2390
|
+
if (((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW') {
|
|
2391
|
+
return `/${(_b = v.fromClass) !== null && _b !== void 0 ? _b : ''}/${this.parentId}/${(_c = v.dataClass) !== null && _c !== void 0 ? _c : ''}`;
|
|
2392
|
+
}
|
|
2393
|
+
return `/${(_d = v.dataClass) !== null && _d !== void 0 ? _d : ''}`;
|
|
2394
|
+
}
|
|
2395
|
+
/** Build query params for a page request from current sort, view filters, filterClass and active column filters. */
|
|
2396
|
+
buildQueryParams(page) {
|
|
2397
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
2398
|
+
const v = this.allViews[this.activeViewIdx];
|
|
2399
|
+
const p = new URLSearchParams();
|
|
2400
|
+
if (page > 0)
|
|
2401
|
+
p.set('page', String(page));
|
|
2402
|
+
const sort = this.sortParam();
|
|
2403
|
+
if (sort)
|
|
2404
|
+
p.set('sort', sort);
|
|
2405
|
+
const filterClass = v === null || v === void 0 ? void 0 : v.filterClass;
|
|
2406
|
+
if (filterClass)
|
|
2407
|
+
p.set('type', filterClass);
|
|
2408
|
+
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 : [])) {
|
|
2409
|
+
if (!f.name)
|
|
2410
|
+
continue;
|
|
2411
|
+
if (f.operator === 'EMPTY') {
|
|
2412
|
+
p.set(f.name, '');
|
|
2413
|
+
continue;
|
|
2414
|
+
}
|
|
2415
|
+
if (f.operator === 'NOT_EMPTY') {
|
|
2416
|
+
p.set(f.name + '_notempty', 'true');
|
|
2417
|
+
continue;
|
|
2418
|
+
}
|
|
2419
|
+
if (f.operator === 'STARTS_WITH') {
|
|
2420
|
+
p.set(f.name + '_startswith', String((_c = f.value) !== null && _c !== void 0 ? _c : ''));
|
|
2421
|
+
continue;
|
|
2422
|
+
}
|
|
2423
|
+
if (f.operator === 'FROM') {
|
|
2424
|
+
p.set(f.name + '_from', String((_d = f.value) !== null && _d !== void 0 ? _d : ''));
|
|
2425
|
+
continue;
|
|
2426
|
+
}
|
|
2427
|
+
if (f.operator === 'TO') {
|
|
2428
|
+
p.set(f.name + '_to', String((_e = f.value) !== null && _e !== void 0 ? _e : ''));
|
|
2429
|
+
continue;
|
|
2430
|
+
}
|
|
2431
|
+
if (f.value != null) {
|
|
2432
|
+
p.set(f.name, String(f.value));
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
for (const f of this.activeFilters.values()) {
|
|
2436
|
+
if (f.operator === 'isEmpty') {
|
|
2437
|
+
p.set(f.field, '');
|
|
2438
|
+
continue;
|
|
2439
|
+
}
|
|
2440
|
+
if (f.operator === 'isNotEmpty') {
|
|
2441
|
+
p.set(f.field + '_notempty', 'true');
|
|
2442
|
+
continue;
|
|
2443
|
+
}
|
|
2444
|
+
if (f.operator === 'startsWith') {
|
|
2445
|
+
p.set(f.field + '_startswith', String((_f = f.value) !== null && _f !== void 0 ? _f : ''));
|
|
2446
|
+
continue;
|
|
2447
|
+
}
|
|
2448
|
+
if ((_g = f.values) === null || _g === void 0 ? void 0 : _g.length) {
|
|
2449
|
+
p.set(f.field, f.values.join(','));
|
|
2450
|
+
continue;
|
|
2451
|
+
}
|
|
2452
|
+
if (f.value != null)
|
|
2453
|
+
p.set(f.field, String(f.value));
|
|
2454
|
+
if (f.from != null)
|
|
2455
|
+
p.set(f.field + '_from', String(f.from));
|
|
2456
|
+
if (f.to != null)
|
|
2457
|
+
p.set(f.field + '_to', String(f.to));
|
|
2458
|
+
}
|
|
2459
|
+
return p.toString();
|
|
2460
|
+
}
|
|
2461
|
+
get columns() {
|
|
2462
|
+
var _a, _b, _c;
|
|
2463
|
+
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 : []);
|
|
2464
|
+
}
|
|
2465
|
+
get tableActions() {
|
|
2466
|
+
var _a, _b;
|
|
2467
|
+
const raw = (_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.actions) !== null && _b !== void 0 ? _b : [];
|
|
2468
|
+
return (raw !== null && raw !== void 0 ? raw : []).reduce((acc, a) => {
|
|
2469
|
+
if (a === 'NEW')
|
|
2470
|
+
acc.push({ action: 'create', label: t('table_new_record', this.locale), icon: 'assets/sprites.svg#icon-plus', variant: 'primary' });
|
|
2471
|
+
if (a === 'EXPORT')
|
|
2472
|
+
acc.push({ action: 'export', label: t('table_export_excel', this.locale), icon: 'assets/sprites.svg#icon-file-excel' });
|
|
2473
|
+
return acc;
|
|
2474
|
+
}, []);
|
|
2475
|
+
}
|
|
2376
2476
|
colName(col) {
|
|
2377
2477
|
var _a;
|
|
2378
2478
|
return (_a = col.name) !== null && _a !== void 0 ? _a : '';
|
|
@@ -2383,6 +2483,25 @@ const MrdTable = class {
|
|
|
2383
2483
|
return 'RELATION';
|
|
2384
2484
|
return (_a = col.dataType) !== null && _a !== void 0 ? _a : 'TEXT';
|
|
2385
2485
|
}
|
|
2486
|
+
/** True when we have a reliable total: either from the aggregations response or because
|
|
2487
|
+
* a short page told us it was the last page (exact count from row length). */
|
|
2488
|
+
isTotalKnown() {
|
|
2489
|
+
if (this.aggregationsTotal != null)
|
|
2490
|
+
return true;
|
|
2491
|
+
for (const rows of this.loadedPages.values()) {
|
|
2492
|
+
if (rows.length < this.pageSize)
|
|
2493
|
+
return true;
|
|
2494
|
+
}
|
|
2495
|
+
return false;
|
|
2496
|
+
}
|
|
2497
|
+
/** Effective total: aggregations-response > totalElements prop > minKnownTotal from setPage(). */
|
|
2498
|
+
get baseTotal() {
|
|
2499
|
+
if (this.aggregationsTotal != null)
|
|
2500
|
+
return this.aggregationsTotal;
|
|
2501
|
+
if (this.totalElements > 0)
|
|
2502
|
+
return this.totalElements;
|
|
2503
|
+
return this.minKnownTotal;
|
|
2504
|
+
}
|
|
2386
2505
|
// ── Aggregation helpers ────────────────────────────────────────────────────
|
|
2387
2506
|
buildAggregationParams() {
|
|
2388
2507
|
var _a;
|
|
@@ -2403,17 +2522,32 @@ const MrdTable = class {
|
|
|
2403
2522
|
params.count = groups.count;
|
|
2404
2523
|
return Object.keys(params).length > 0 ? params : null;
|
|
2405
2524
|
}
|
|
2525
|
+
buildAggregationQs() {
|
|
2526
|
+
var _a, _b, _c;
|
|
2527
|
+
const p = new URLSearchParams(this.buildQueryParams(0));
|
|
2528
|
+
p.delete('page');
|
|
2529
|
+
p.delete('sort');
|
|
2530
|
+
const groups = this.buildAggregationParams();
|
|
2531
|
+
if ((_a = groups === null || groups === void 0 ? void 0 : groups.sum) === null || _a === void 0 ? void 0 : _a.length)
|
|
2532
|
+
p.set('sum', groups.sum.join(','));
|
|
2533
|
+
if ((_b = groups === null || groups === void 0 ? void 0 : groups.avg) === null || _b === void 0 ? void 0 : _b.length)
|
|
2534
|
+
p.set('avg', groups.avg.join(','));
|
|
2535
|
+
if ((_c = groups === null || groups === void 0 ? void 0 : groups.count) === null || _c === void 0 ? void 0 : _c.length)
|
|
2536
|
+
p.set('count', groups.count.join(','));
|
|
2537
|
+
return p.toString();
|
|
2538
|
+
}
|
|
2406
2539
|
emitLoadAggregations() {
|
|
2407
|
-
|
|
2408
|
-
if (params)
|
|
2409
|
-
this.mrdLoadAggregations.emit(params);
|
|
2540
|
+
this.mrdLoadAggregations.emit({ path: this.buildDataPath(), qs: this.buildQueryParams(0), aggQs: this.buildAggregationQs() });
|
|
2410
2541
|
}
|
|
2411
2542
|
renderAggregationValue(col) {
|
|
2412
|
-
var _a
|
|
2543
|
+
var _a;
|
|
2413
2544
|
if (col.type !== 'FIELD' || !col.aggregate || !this.aggregations)
|
|
2414
2545
|
return '';
|
|
2415
2546
|
const fn = col.aggregate.toLowerCase();
|
|
2416
|
-
const
|
|
2547
|
+
const aggData = this.aggregations[fn];
|
|
2548
|
+
const val = typeof aggData === 'object' && aggData !== null
|
|
2549
|
+
? aggData[(_a = col.name) !== null && _a !== void 0 ? _a : '']
|
|
2550
|
+
: undefined;
|
|
2417
2551
|
if (val == null)
|
|
2418
2552
|
return '';
|
|
2419
2553
|
const dt = col.dataType;
|
|
@@ -2438,9 +2572,10 @@ const MrdTable = class {
|
|
|
2438
2572
|
this.colWidths = [];
|
|
2439
2573
|
this.scrollTop = 0;
|
|
2440
2574
|
this.renderStart = 0;
|
|
2441
|
-
|
|
2442
|
-
//
|
|
2443
|
-
|
|
2575
|
+
this.minKnownTotal = 0;
|
|
2576
|
+
// Mirror init(): use visibleCount so the first page is always requested.
|
|
2577
|
+
// setPage() will clamp renderEnd down when the last page is shorter.
|
|
2578
|
+
this.renderEnd = this.visibleCount() - 1;
|
|
2444
2579
|
const scroller = this.el.querySelector('.mrd-table__scroll');
|
|
2445
2580
|
if (scroller)
|
|
2446
2581
|
scroller.scrollTop = 0;
|
|
@@ -2471,7 +2606,7 @@ const MrdTable = class {
|
|
|
2471
2606
|
for (let p = firstPage; p <= lastPage; p++) {
|
|
2472
2607
|
if (!this.loadedPages.has(p) && !next.has(p)) {
|
|
2473
2608
|
next.add(p);
|
|
2474
|
-
this.mrdLoadPage.emit({ page: p, sort: this.sortParam() });
|
|
2609
|
+
this.mrdLoadPage.emit({ page: p, sort: this.sortParam(), path: this.buildDataPath(), qs: this.buildQueryParams(p) });
|
|
2475
2610
|
changed = true;
|
|
2476
2611
|
}
|
|
2477
2612
|
}
|
|
@@ -2513,7 +2648,7 @@ const MrdTable = class {
|
|
|
2513
2648
|
if (pageEnd < this.renderStart || pageStart > this.renderEnd)
|
|
2514
2649
|
continue;
|
|
2515
2650
|
next.add(page);
|
|
2516
|
-
this.mrdLoadPage.emit({ page, sort: this.sortParam() });
|
|
2651
|
+
this.mrdLoadPage.emit({ page, sort: this.sortParam(), path: this.buildDataPath(), qs: this.buildQueryParams(page) });
|
|
2517
2652
|
changed = true;
|
|
2518
2653
|
}
|
|
2519
2654
|
this.pendingPages.clear();
|
|
@@ -2705,9 +2840,9 @@ const MrdTable = class {
|
|
|
2705
2840
|
}
|
|
2706
2841
|
this.activeFilters = next;
|
|
2707
2842
|
this.closeFilterPopup();
|
|
2708
|
-
this.mrdFilter.emit({ filters: Array.from(this.activeFilters.values()) });
|
|
2709
2843
|
this.aggregations = null;
|
|
2710
|
-
this.
|
|
2844
|
+
this.aggregationsTotal = null;
|
|
2845
|
+
this.aggregationsPending = true;
|
|
2711
2846
|
if (this.totalElements > 0) {
|
|
2712
2847
|
this.resetPages();
|
|
2713
2848
|
this.emitPagesForWindow(this.renderStart, this.renderEnd);
|
|
@@ -2720,9 +2855,9 @@ const MrdTable = class {
|
|
|
2720
2855
|
next.delete(name);
|
|
2721
2856
|
this.activeFilters = next;
|
|
2722
2857
|
this.closeFilterPopup();
|
|
2723
|
-
this.mrdFilter.emit({ filters: Array.from(this.activeFilters.values()) });
|
|
2724
2858
|
this.aggregations = null;
|
|
2725
|
-
this.
|
|
2859
|
+
this.aggregationsTotal = null;
|
|
2860
|
+
this.aggregationsPending = true;
|
|
2726
2861
|
if (this.totalElements > 0) {
|
|
2727
2862
|
this.resetPages();
|
|
2728
2863
|
this.emitPagesForWindow(this.renderStart, this.renderEnd);
|
|
@@ -2730,37 +2865,39 @@ const MrdTable = class {
|
|
|
2730
2865
|
}
|
|
2731
2866
|
clearAllFilters() {
|
|
2732
2867
|
this.activeFilters = new Map();
|
|
2733
|
-
this.mrdFilter.emit({ filters: [] });
|
|
2734
2868
|
this.aggregations = null;
|
|
2735
|
-
this.
|
|
2869
|
+
this.aggregationsTotal = null;
|
|
2870
|
+
this.aggregationsPending = true;
|
|
2736
2871
|
if (this.totalElements > 0) {
|
|
2737
2872
|
this.resetPages();
|
|
2738
2873
|
this.emitPagesForWindow(this.renderStart, this.renderEnd);
|
|
2739
2874
|
}
|
|
2740
2875
|
}
|
|
2741
2876
|
// ── View switcher ──────────────────────────────────────────────────────────
|
|
2742
|
-
handleViewSwitch(
|
|
2743
|
-
|
|
2877
|
+
handleViewSwitch(targetIdx) {
|
|
2878
|
+
var _a, _b;
|
|
2879
|
+
const target = this.allViews[targetIdx];
|
|
2880
|
+
if (!(target === null || target === void 0 ? void 0 : target.view))
|
|
2881
|
+
return;
|
|
2882
|
+
this.activeViewIdx = targetIdx;
|
|
2883
|
+
this.applyDefaultSort((_b = (_a = target.view) === null || _a === void 0 ? void 0 : _a.defaultSort) !== null && _b !== void 0 ? _b : '');
|
|
2884
|
+
this.activeFilters = new Map();
|
|
2885
|
+
this.init();
|
|
2744
2886
|
}
|
|
2745
2887
|
// ── Render: toolbar ────────────────────────────────────────────────────────
|
|
2746
2888
|
renderToolbar() {
|
|
2747
|
-
var _a, _b;
|
|
2748
2889
|
const filterCount = this.activeFilters.size;
|
|
2749
|
-
const
|
|
2750
|
-
const
|
|
2890
|
+
const actions = this.tableActions;
|
|
2891
|
+
const allViews = this.allViews;
|
|
2892
|
+
const hasActions = actions.length > 0;
|
|
2893
|
+
const hasViewSwitcher = allViews.length > 1;
|
|
2751
2894
|
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
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
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 => {
|
|
2895
|
+
const idx = parseInt(e.target.value, 10);
|
|
2896
|
+
if (!isNaN(idx) && idx !== this.activeViewIdx)
|
|
2897
|
+
this.handleViewSwitch(idx);
|
|
2898
|
+
} }, 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
2899
|
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(
|
|
2900
|
+
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
2901
|
? index.h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, index.h("use", { href: a.icon }))
|
|
2765
2902
|
: a.label, index.h("span", { class: "mrd-table__action-tooltip" }, a.label)));
|
|
2766
2903
|
})))));
|
|
@@ -2854,10 +2991,9 @@ const MrdTable = class {
|
|
|
2854
2991
|
return (index.h("div", { class: "mrd-table__filter-popup", style: { top: `${this.popupPos.top}px`, left: `${this.popupPos.left}px` }, onClick: (e) => e.stopPropagation() }, index.h("div", { class: "mrd-table__filter-popup-header" }, index.h("span", { class: "mrd-table__filter-popup-title" }, label), index.h("button", { class: "mrd-table__filter-close", onClick: () => this.closeFilterPopup() }, "\u2715")), index.h("div", { class: "mrd-table__filter-section" }, index.h("div", { class: "mrd-table__filter-section-label" }, t('filter_sorting', this.locale)), index.h("div", { class: "mrd-table__filter-sort-buttons" }, index.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)), index.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)))), index.h("div", { class: "mrd-table__filter-divider" }), index.h("div", { class: "mrd-table__filter-section" }, index.h("div", { class: "mrd-table__filter-section-label" }, t('filter_section', this.locale)), this.renderFilterEditor(col)), index.h("div", { class: "mrd-table__filter-popup-footer" }, index.h("button", { class: "mrd-table__filter-btn mrd-table__filter-btn--clear", onClick: () => this.clearFilter() }, t('filter_clear', this.locale)), index.h("button", { class: "mrd-table__filter-btn mrd-table__filter-btn--apply", onClick: () => this.applyFilter() }, t('filter_apply', this.locale)))));
|
|
2855
2992
|
}
|
|
2856
2993
|
// ── Render: footer ────────────────────────────────────────────────────────
|
|
2857
|
-
renderFooter(rowCount, effectiveTotal) {
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
if (total === 0) {
|
|
2994
|
+
renderFooter(rowCount, effectiveTotal, isTotalKnown = true) {
|
|
2995
|
+
// Non-paginated mode: totalElements=0 and no paginated data loaded yet
|
|
2996
|
+
if (this.totalElements === 0 && this.loadedPages.size === 0) {
|
|
2861
2997
|
const count = rowCount !== null && rowCount !== void 0 ? rowCount : 0;
|
|
2862
2998
|
if (count === 0)
|
|
2863
2999
|
return null;
|
|
@@ -2866,13 +3002,14 @@ const MrdTable = class {
|
|
|
2866
3002
|
// Paginated mode: only show once page 0 has loaded (avoids stale total during filter reset)
|
|
2867
3003
|
if (!this.loadedPages.has(0))
|
|
2868
3004
|
return null;
|
|
2869
|
-
//
|
|
2870
|
-
|
|
2871
|
-
const displayTotal = effectiveTotal !== null && effectiveTotal !== void 0 ? effectiveTotal : total;
|
|
3005
|
+
// effectiveTotal from render(); fall back to baseTotal when not provided.
|
|
3006
|
+
const displayTotal = effectiveTotal !== null && effectiveTotal !== void 0 ? effectiveTotal : this.baseTotal;
|
|
2872
3007
|
// Compute from/to independently so partial rows at top/bottom are included.
|
|
2873
3008
|
const from = Math.min(Math.floor(this.scrollTop / this.rowHeight) + 1, displayTotal);
|
|
2874
3009
|
const to = Math.min(Math.ceil((this.scrollTop + this.tableHeight) / this.rowHeight), displayTotal);
|
|
2875
|
-
|
|
3010
|
+
// Show '…' for the total until we have a reliable count (aggregations or last page loaded).
|
|
3011
|
+
const totalLabel = isTotalKnown ? String(displayTotal) : '…';
|
|
3012
|
+
return (index.h("div", { class: "mrd-table__footer" }, from, "\u2013", to, " ", t('table_of', this.locale), " ", totalLabel));
|
|
2876
3013
|
}
|
|
2877
3014
|
// ── Render: cell ──────────────────────────────────────────────────────────
|
|
2878
3015
|
renderCell(col, row) {
|
|
@@ -2931,7 +3068,9 @@ const MrdTable = class {
|
|
|
2931
3068
|
if (!((_a = this.columns) === null || _a === void 0 ? void 0 : _a.length))
|
|
2932
3069
|
return null;
|
|
2933
3070
|
// ── Non-paginated mode ──────────────────────────────────────────────────
|
|
2934
|
-
|
|
3071
|
+
// Only enter non-paginated mode when totalElements is 0 AND no paginated data
|
|
3072
|
+
// has been loaded yet — prevents the wrong branch when the host omits totalElements.
|
|
3073
|
+
if (this.totalElements === 0 && this.loadedPages.size === 0) {
|
|
2935
3074
|
return (index.h(index.Host, null, this.renderToolbar(), index.h("div", { class: "mrd-table" }, index.h("table", { class: "mrd-table__table" }, index.h("thead", null, index.h("tr", null, this.columns.map(col => {
|
|
2936
3075
|
var _a;
|
|
2937
3076
|
const name = this.colName(col);
|
|
@@ -2948,8 +3087,8 @@ const MrdTable = class {
|
|
|
2948
3087
|
// Derive the authoritative row count from loaded pages:
|
|
2949
3088
|
// if any loaded page is shorter than pageSize it is the last page,
|
|
2950
3089
|
// so the true total cannot exceed (pageNum * pageSize + pageRows.length).
|
|
2951
|
-
//
|
|
2952
|
-
let effectiveTotal = this.
|
|
3090
|
+
// aggregationsTotal (from setAggregations) takes priority over the totalElements prop.
|
|
3091
|
+
let effectiveTotal = this.baseTotal;
|
|
2953
3092
|
for (const [pageNum, pageRows] of this.loadedPages) {
|
|
2954
3093
|
if (pageRows.length < this.pageSize) {
|
|
2955
3094
|
effectiveTotal = Math.min(effectiveTotal, pageNum * this.pageSize + pageRows.length);
|
|
@@ -2986,7 +3125,7 @@ const MrdTable = class {
|
|
|
2986
3125
|
isFiltered ? 'mrd-table__header--filtered' : '',
|
|
2987
3126
|
].filter(Boolean).join(' ');
|
|
2988
3127
|
return (index.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 }, index.h("span", { class: "mrd-table__header-label" }, (_a = col.label) !== null && _a !== void 0 ? _a : ''), isInteractive && isActive && (index.h("span", { class: "mrd-table__sort-icon", "aria-hidden": "true" }, this.sortDir === 'asc' ? '▲' : '▼')), isInteractive && !isActive && !this.filterMode && (index.h("span", { class: "mrd-table__sort-icon", "aria-hidden": "true" }, "\u21C5")), isInteractive && isFiltered && this.renderFilterIcon()));
|
|
2989
|
-
}))), index.h("tbody", null, topSpacerHeight > 0 && (index.h("tr", { class: "mrd-table__spacer", style: { height: `${topSpacerHeight}px` } }, index.h("td", { colSpan: colCount }))), renderedRows, bottomSpacerHeight > 0 && (index.h("tr", { class: "mrd-table__spacer", style: { height: `${bottomSpacerHeight}px` } }, index.h("td", { colSpan: colCount })))), this.renderTotalsRow())), effectiveTotal === 0 && this.loadedPages.has(0) && (index.h("p", { class: "mrd-table__empty" }, t('no_results', this.locale))), effectiveTotal > 0 && this.renderFooter(undefined, effectiveTotal), this.renderFilterPopup(), this.renderTextblockModal()));
|
|
3128
|
+
}))), index.h("tbody", null, topSpacerHeight > 0 && (index.h("tr", { class: "mrd-table__spacer", style: { height: `${topSpacerHeight}px` } }, index.h("td", { colSpan: colCount }))), renderedRows, bottomSpacerHeight > 0 && (index.h("tr", { class: "mrd-table__spacer", style: { height: `${bottomSpacerHeight}px` } }, index.h("td", { colSpan: colCount })))), this.renderTotalsRow())), effectiveTotal === 0 && this.loadedPages.has(0) && (index.h("p", { class: "mrd-table__empty" }, t('no_results', this.locale))), effectiveTotal > 0 && this.renderFooter(undefined, effectiveTotal, this.isTotalKnown()), this.renderFilterPopup(), this.renderTextblockModal()));
|
|
2990
3129
|
}
|
|
2991
3130
|
renderFilterIcon() {
|
|
2992
3131
|
return (index.h("span", { class: "mrd-table__filter-icon", "aria-hidden": "true" }, index.h("svg", { viewBox: "0 0 24 24", width: "14", height: "14", fill: "currentColor" }, index.h("path", { d: "M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z" }))));
|
|
@@ -3006,8 +3145,8 @@ const MrdTable = class {
|
|
|
3006
3145
|
"totalElements": [{
|
|
3007
3146
|
"totalElementsChanged": 0
|
|
3008
3147
|
}],
|
|
3009
|
-
"
|
|
3010
|
-
"
|
|
3148
|
+
"item": [{
|
|
3149
|
+
"itemChanged": 0
|
|
3011
3150
|
}]
|
|
3012
3151
|
}; }
|
|
3013
3152
|
};
|