@openziti/ziti-console-lib 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/styles/dark.css +16 -0
- package/assets/styles/global.scss +142 -65
- package/fesm2022/openziti-ziti-console-lib.mjs +2136 -176
- package/fesm2022/openziti-ziti-console-lib.mjs.map +1 -1
- package/index.d.ts +412 -41
- package/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1800,6 +1800,27 @@ class ListTableService {
|
|
|
1800
1800
|
pageSizeKey() {
|
|
1801
1801
|
return `lt_${this.tableId}_page_size`;
|
|
1802
1802
|
}
|
|
1803
|
+
treeVariantKey() {
|
|
1804
|
+
return `lt_${this.tableId}_tree_variant`;
|
|
1805
|
+
}
|
|
1806
|
+
/** Returns the saved tree layout ('card' | 'flat'), or `fallback` if none. */
|
|
1807
|
+
restoreTreeVariant(fallback) {
|
|
1808
|
+
try {
|
|
1809
|
+
const raw = localStorage.getItem(this.treeVariantKey());
|
|
1810
|
+
return raw === 'card' || raw === 'flat' ? raw : fallback;
|
|
1811
|
+
}
|
|
1812
|
+
catch {
|
|
1813
|
+
return fallback;
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
saveTreeVariant(variant) {
|
|
1817
|
+
try {
|
|
1818
|
+
localStorage.setItem(this.treeVariantKey(), variant);
|
|
1819
|
+
}
|
|
1820
|
+
catch {
|
|
1821
|
+
// ignore
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1803
1824
|
static pageSizeKeyFor(tableId) {
|
|
1804
1825
|
return `lt_${tableId}_page_size`;
|
|
1805
1826
|
}
|
|
@@ -1830,66 +1851,100 @@ class ListTableService {
|
|
|
1830
1851
|
* and order applied. Columns not present in the saved state keep their declared
|
|
1831
1852
|
* position (appended after the saved ones).
|
|
1832
1853
|
*/
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
// widths
|
|
1854
|
+
/** Parses a stored JSON value, or null when missing/unavailable/malformed. */
|
|
1855
|
+
readJson(key) {
|
|
1836
1856
|
try {
|
|
1837
|
-
const raw = localStorage.getItem(
|
|
1838
|
-
|
|
1839
|
-
const widths = JSON.parse(raw) || {};
|
|
1840
|
-
cols.forEach((c) => {
|
|
1841
|
-
if (widths[c.key] != null) {
|
|
1842
|
-
c.width = widths[c.key];
|
|
1843
|
-
}
|
|
1844
|
-
});
|
|
1845
|
-
}
|
|
1857
|
+
const raw = localStorage.getItem(key);
|
|
1858
|
+
return raw ? JSON.parse(raw) : null;
|
|
1846
1859
|
}
|
|
1847
1860
|
catch {
|
|
1848
|
-
|
|
1861
|
+
return null;
|
|
1849
1862
|
}
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1863
|
+
}
|
|
1864
|
+
/** Applies a widths map then a persisted order/visibility list onto a fresh copy of
|
|
1865
|
+
* `columns`. Shared by the top-level and per-depth restore paths. */
|
|
1866
|
+
mergePersistedColumns(columns, widths, state) {
|
|
1867
|
+
let cols = columns.map((c) => ({ ...c }));
|
|
1868
|
+
cols.forEach((c) => {
|
|
1869
|
+
if (widths[c.key] != null) {
|
|
1870
|
+
c.width = widths[c.key];
|
|
1871
|
+
}
|
|
1872
|
+
});
|
|
1873
|
+
if (state.length) {
|
|
1874
|
+
const ordered = [];
|
|
1875
|
+
state.forEach((s) => {
|
|
1876
|
+
const found = cols.find((c) => c.key === s.colId);
|
|
1877
|
+
if (found && !ordered.includes(found)) {
|
|
1878
|
+
if (s.hide != null) {
|
|
1879
|
+
found.hidden = s.hide;
|
|
1866
1880
|
}
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
if (!ordered.includes(c)) {
|
|
1870
|
-
ordered.push(c);
|
|
1881
|
+
if (s.width != null) {
|
|
1882
|
+
found.width = s.width;
|
|
1871
1883
|
}
|
|
1872
|
-
|
|
1873
|
-
if (ordered.length) {
|
|
1874
|
-
cols = ordered;
|
|
1884
|
+
ordered.push(found);
|
|
1875
1885
|
}
|
|
1876
|
-
}
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1886
|
+
});
|
|
1887
|
+
cols.forEach((c) => {
|
|
1888
|
+
if (!ordered.includes(c)) {
|
|
1889
|
+
ordered.push(c);
|
|
1890
|
+
}
|
|
1891
|
+
});
|
|
1892
|
+
cols = ordered;
|
|
1880
1893
|
}
|
|
1881
1894
|
return cols;
|
|
1882
1895
|
}
|
|
1896
|
+
/** Order + visibility + width entries for one set of columns. */
|
|
1897
|
+
columnStateEntries(columns) {
|
|
1898
|
+
return columns.map((c) => ({ colId: c.key, hide: !!c.hidden, width: c.width }));
|
|
1899
|
+
}
|
|
1900
|
+
applyPersistedState(columns) {
|
|
1901
|
+
const widths = this.readJson(this.widthsKey()) || {};
|
|
1902
|
+
const state = this.readJson(this.stateKey()) || [];
|
|
1903
|
+
return this.mergePersistedColumns(columns, widths, state);
|
|
1904
|
+
}
|
|
1883
1905
|
/** Persists the current order + visibility (and widths embedded in each entry). */
|
|
1884
1906
|
saveState(columns) {
|
|
1885
|
-
const state = columns.map((c) => ({ colId: c.key, hide: !!c.hidden, width: c.width }));
|
|
1886
1907
|
try {
|
|
1887
|
-
localStorage.setItem(this.stateKey(), JSON.stringify(
|
|
1908
|
+
localStorage.setItem(this.stateKey(), JSON.stringify(this.columnStateEntries(columns)));
|
|
1888
1909
|
}
|
|
1889
1910
|
catch {
|
|
1890
1911
|
// ignore
|
|
1891
1912
|
}
|
|
1892
1913
|
}
|
|
1914
|
+
// ---- nested (per-depth) child columns: same contract as above, keyed by level ----
|
|
1915
|
+
childStateKey() {
|
|
1916
|
+
return `lt_${this.tableId}_child_state`;
|
|
1917
|
+
}
|
|
1918
|
+
childWidthsKey() {
|
|
1919
|
+
return `lt_${this.tableId}_child_widths`;
|
|
1920
|
+
}
|
|
1921
|
+
/** Applies persisted order/visibility/width for one nested depth to its columns. */
|
|
1922
|
+
applyPersistedChildState(level, columns) {
|
|
1923
|
+
const widths = (this.readJson(this.childWidthsKey()) || {})[level] || {};
|
|
1924
|
+
const state = (this.readJson(this.childStateKey()) || {})[level] || [];
|
|
1925
|
+
return this.mergePersistedColumns(columns, widths, state);
|
|
1926
|
+
}
|
|
1927
|
+
saveChildState(level, columns) {
|
|
1928
|
+
try {
|
|
1929
|
+
const byLevel = this.readJson(this.childStateKey()) || {};
|
|
1930
|
+
byLevel[level] = this.columnStateEntries(columns);
|
|
1931
|
+
localStorage.setItem(this.childStateKey(), JSON.stringify(byLevel));
|
|
1932
|
+
}
|
|
1933
|
+
catch {
|
|
1934
|
+
// ignore
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
saveChildWidth(level, colId, width, columns) {
|
|
1938
|
+
try {
|
|
1939
|
+
const byLevel = this.readJson(this.childWidthsKey()) || {};
|
|
1940
|
+
byLevel[level] = { ...(byLevel[level] || {}), [colId]: width };
|
|
1941
|
+
localStorage.setItem(this.childWidthsKey(), JSON.stringify(byLevel));
|
|
1942
|
+
}
|
|
1943
|
+
catch {
|
|
1944
|
+
// ignore
|
|
1945
|
+
}
|
|
1946
|
+
this.saveChildState(level, columns);
|
|
1947
|
+
}
|
|
1893
1948
|
/** Persists a single column's width, then rewrites the ordered state. */
|
|
1894
1949
|
saveWidth(colId, width, columns) {
|
|
1895
1950
|
try {
|
|
@@ -1909,6 +1964,9 @@ class ListTableService {
|
|
|
1909
1964
|
localStorage.removeItem(this.stateKey());
|
|
1910
1965
|
localStorage.removeItem(this.widthsKey());
|
|
1911
1966
|
localStorage.removeItem(this.pageSizeKey());
|
|
1967
|
+
localStorage.removeItem(this.treeVariantKey());
|
|
1968
|
+
localStorage.removeItem(this.childStateKey());
|
|
1969
|
+
localStorage.removeItem(this.childWidthsKey());
|
|
1912
1970
|
}
|
|
1913
1971
|
catch {
|
|
1914
1972
|
// ignore
|
|
@@ -6602,11 +6660,11 @@ class NameCellComponent {
|
|
|
6602
6660
|
return val;
|
|
6603
6661
|
}
|
|
6604
6662
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: NameCellComponent, deps: [{ token: i4.Router }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6605
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: NameCellComponent, isStandalone: false, selector: "lib-name-cell", inputs: { row: "row", cellValue: "cellValue", cellConfig: "cellConfig" }, ngImport: i0, template: "<span class=\"cell-name-container\">\n <a href=\"./{{cellParams.pathRoot}}/{{item.id}}\" class=\"cell-name-link\" (click)=\"linkClicked($event)\">\n <div class=\"col cell-name-renderer\" data-id=\"{{item.id}}\">\n @if (cellParams.showIdentityIcons && item.edgeRouterConnectionStatus) {\n <div class=\"cell-status-container\">\n <span class=\"circle {{item.edgeRouterConnectionStatus}}\" title=\"Edge Router Connection Status\"></span>\n </div>\n }\n @if (cellParams.showIdentityIcons && !item.edgeRouterConnectionStatus) {\n <div class=\"cell-status-container\">\n <span class=\"circle {{item.hasApiSession}}\" title=\"Api Session\"></span>\n <span class=\"circle {{item.hasEdgeRouterConnection}}\" title=\"Edge Router Connected\"></span>\n </div>\n }\n @if (cellParams.showRouterIcons) {\n <div class=\"cell-status-container\">\n <span class=\"circle {{item.isVerified}}\" title=\"{{item.isVerified ? 'Verified' : 'Unverified'}}\"></span>\n <span class=\"circle {{item.isOnline}}\" title=\"{{item.isOnline ? 'Online' : 'Offline'}}\"></span>\n </div>\n }\n @if (namePrefix) {\n <div class=\"cell-name-prefix-wrap\" [matTooltip]=\"namePrefix.tooltip\" [matTooltipShowDelay]=\"0\">\n <span class=\"cell-name-prefix-icon\" [ngClass]=\"namePrefix.iconClass\"></span>\n </div>\n }\n <strong>{{cellText}}</strong>\n </div>\n </a>\n</span>\n", styles: [".cell-name-renderer{display:flex;flex-direction:row;align-items:center;gap:.3125rem}.cell-name-container{display:flex;flex-direction:row;flex-wrap:nowrap}.cell-name-link{display:inline-flex;align-items:center}.cell-status-container{position:relative;display:flex;align-items:center;justify-content:center;gap:.25rem}.cell-name-prefix-wrap{display:flex;align-items:center;justify-content:center}.cell-name-prefix-icon{color:var(--
|
|
6663
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: NameCellComponent, isStandalone: false, selector: "lib-name-cell", inputs: { row: "row", cellValue: "cellValue", cellConfig: "cellConfig" }, ngImport: i0, template: "<span class=\"cell-name-container\">\n <a href=\"./{{cellParams.pathRoot}}/{{item.id}}\" class=\"cell-name-link\" (click)=\"linkClicked($event)\">\n <div class=\"col cell-name-renderer\" data-id=\"{{item.id}}\">\n @if (cellParams.showIdentityIcons && item.edgeRouterConnectionStatus) {\n <div class=\"cell-status-container\">\n <span class=\"circle {{item.edgeRouterConnectionStatus}}\" title=\"Edge Router Connection Status\"></span>\n </div>\n }\n @if (cellParams.showIdentityIcons && !item.edgeRouterConnectionStatus) {\n <div class=\"cell-status-container\">\n <span class=\"circle {{item.hasApiSession}}\" title=\"Api Session\"></span>\n <span class=\"circle {{item.hasEdgeRouterConnection}}\" title=\"Edge Router Connected\"></span>\n </div>\n }\n @if (cellParams.showRouterIcons) {\n <div class=\"cell-status-container\">\n <span class=\"circle {{item.isVerified}}\" title=\"{{item.isVerified ? 'Verified' : 'Unverified'}}\"></span>\n <span class=\"circle {{item.isOnline}}\" title=\"{{item.isOnline ? 'Online' : 'Offline'}}\"></span>\n </div>\n }\n @if (namePrefix) {\n <div class=\"cell-name-prefix-wrap\" [matTooltip]=\"namePrefix.tooltip\" [matTooltipShowDelay]=\"0\">\n <span class=\"cell-name-prefix-icon\" [ngClass]=\"namePrefix.iconClass\"></span>\n </div>\n }\n <strong>{{cellText}}</strong>\n </div>\n </a>\n</span>\n", styles: [".cell-name-renderer{display:flex;flex-direction:row;align-items:center;gap:.3125rem}.cell-name-renderer strong{font-weight:600}.cell-name-container{display:flex;flex-direction:row;flex-wrap:nowrap}.cell-name-link{display:inline-flex;align-items:center}.cell-status-container{position:relative;display:flex;align-items:center;justify-content:center;gap:.25rem}.cell-name-prefix-wrap{display:flex;align-items:center;justify-content:center}.cell-name-prefix-icon{color:var(--lt-warning, #f5a93d);font-size:1rem}.circle.online{background-color:var(--lt-positive, #16a34a)}.circle.unknown{background-color:var(--lt-warning, #f5a93d)}\n"], dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] }); }
|
|
6606
6664
|
}
|
|
6607
6665
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: NameCellComponent, decorators: [{
|
|
6608
6666
|
type: Component,
|
|
6609
|
-
args: [{ selector: 'lib-name-cell', standalone: false, template: "<span class=\"cell-name-container\">\n <a href=\"./{{cellParams.pathRoot}}/{{item.id}}\" class=\"cell-name-link\" (click)=\"linkClicked($event)\">\n <div class=\"col cell-name-renderer\" data-id=\"{{item.id}}\">\n @if (cellParams.showIdentityIcons && item.edgeRouterConnectionStatus) {\n <div class=\"cell-status-container\">\n <span class=\"circle {{item.edgeRouterConnectionStatus}}\" title=\"Edge Router Connection Status\"></span>\n </div>\n }\n @if (cellParams.showIdentityIcons && !item.edgeRouterConnectionStatus) {\n <div class=\"cell-status-container\">\n <span class=\"circle {{item.hasApiSession}}\" title=\"Api Session\"></span>\n <span class=\"circle {{item.hasEdgeRouterConnection}}\" title=\"Edge Router Connected\"></span>\n </div>\n }\n @if (cellParams.showRouterIcons) {\n <div class=\"cell-status-container\">\n <span class=\"circle {{item.isVerified}}\" title=\"{{item.isVerified ? 'Verified' : 'Unverified'}}\"></span>\n <span class=\"circle {{item.isOnline}}\" title=\"{{item.isOnline ? 'Online' : 'Offline'}}\"></span>\n </div>\n }\n @if (namePrefix) {\n <div class=\"cell-name-prefix-wrap\" [matTooltip]=\"namePrefix.tooltip\" [matTooltipShowDelay]=\"0\">\n <span class=\"cell-name-prefix-icon\" [ngClass]=\"namePrefix.iconClass\"></span>\n </div>\n }\n <strong>{{cellText}}</strong>\n </div>\n </a>\n</span>\n", styles: [".cell-name-renderer{display:flex;flex-direction:row;align-items:center;gap:.3125rem}.cell-name-container{display:flex;flex-direction:row;flex-wrap:nowrap}.cell-name-link{display:inline-flex;align-items:center}.cell-status-container{position:relative;display:flex;align-items:center;justify-content:center;gap:.25rem}.cell-name-prefix-wrap{display:flex;align-items:center;justify-content:center}.cell-name-prefix-icon{color:var(--
|
|
6667
|
+
args: [{ selector: 'lib-name-cell', standalone: false, template: "<span class=\"cell-name-container\">\n <a href=\"./{{cellParams.pathRoot}}/{{item.id}}\" class=\"cell-name-link\" (click)=\"linkClicked($event)\">\n <div class=\"col cell-name-renderer\" data-id=\"{{item.id}}\">\n @if (cellParams.showIdentityIcons && item.edgeRouterConnectionStatus) {\n <div class=\"cell-status-container\">\n <span class=\"circle {{item.edgeRouterConnectionStatus}}\" title=\"Edge Router Connection Status\"></span>\n </div>\n }\n @if (cellParams.showIdentityIcons && !item.edgeRouterConnectionStatus) {\n <div class=\"cell-status-container\">\n <span class=\"circle {{item.hasApiSession}}\" title=\"Api Session\"></span>\n <span class=\"circle {{item.hasEdgeRouterConnection}}\" title=\"Edge Router Connected\"></span>\n </div>\n }\n @if (cellParams.showRouterIcons) {\n <div class=\"cell-status-container\">\n <span class=\"circle {{item.isVerified}}\" title=\"{{item.isVerified ? 'Verified' : 'Unverified'}}\"></span>\n <span class=\"circle {{item.isOnline}}\" title=\"{{item.isOnline ? 'Online' : 'Offline'}}\"></span>\n </div>\n }\n @if (namePrefix) {\n <div class=\"cell-name-prefix-wrap\" [matTooltip]=\"namePrefix.tooltip\" [matTooltipShowDelay]=\"0\">\n <span class=\"cell-name-prefix-icon\" [ngClass]=\"namePrefix.iconClass\"></span>\n </div>\n }\n <strong>{{cellText}}</strong>\n </div>\n </a>\n</span>\n", styles: [".cell-name-renderer{display:flex;flex-direction:row;align-items:center;gap:.3125rem}.cell-name-renderer strong{font-weight:600}.cell-name-container{display:flex;flex-direction:row;flex-wrap:nowrap}.cell-name-link{display:inline-flex;align-items:center}.cell-status-container{position:relative;display:flex;align-items:center;justify-content:center;gap:.25rem}.cell-name-prefix-wrap{display:flex;align-items:center;justify-content:center}.cell-name-prefix-icon{color:var(--lt-warning, #f5a93d);font-size:1rem}.circle.online{background-color:var(--lt-positive, #16a34a)}.circle.unknown{background-color:var(--lt-warning, #f5a93d)}\n"] }]
|
|
6610
6668
|
}], ctorParameters: () => [{ type: i4.Router }], propDecorators: { row: [{
|
|
6611
6669
|
type: Input
|
|
6612
6670
|
}], cellValue: [{
|
|
@@ -6750,11 +6808,11 @@ class BooleanCellComponent {
|
|
|
6750
6808
|
return this.value === true || this.value === 'true';
|
|
6751
6809
|
}
|
|
6752
6810
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: BooleanCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6753
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: BooleanCellComponent, isStandalone: false, selector: "lib-boolean-cell", inputs: { value: "value", trueLabel: "trueLabel" }, ngImport: i0, template: "@if (isTrue) {\n <span class=\"bool bool-true\">\n <svg class=\"bool-check\" viewBox=\"0 0 14 14\" width=\"12\" height=\"12\" aria-hidden=\"true\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M2.5 7.6 5.7 10.8 11.5 3.6\"/>\n </svg>\n <span class=\"bool-label\">{{ trueLabel }}</span>\n </span>\n}\n", styles: [":host{display:inline-flex;align-items:center}.bool-true{display:inline-flex;align-items:center;gap:.
|
|
6811
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: BooleanCellComponent, isStandalone: false, selector: "lib-boolean-cell", inputs: { value: "value", trueLabel: "trueLabel" }, ngImport: i0, template: "@if (isTrue) {\n <span class=\"bool bool-true\">\n <svg class=\"bool-check\" viewBox=\"0 0 14 14\" width=\"12\" height=\"12\" aria-hidden=\"true\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M2.5 7.6 5.7 10.8 11.5 3.6\"/>\n </svg>\n <span class=\"bool-label\">{{ trueLabel }}</span>\n </span>\n}\n", styles: [":host{display:inline-flex;align-items:center}.bool-true{display:inline-flex;align-items:center;gap:.3375rem;min-height:1.575rem;box-sizing:border-box;padding:.140625rem .5625rem .140625rem .421875rem;font-family:var(--lt-font);font-size:.73125rem;font-weight:500;line-height:1.2;color:var(--lt-positive-text, #166534);background:color-mix(in srgb,var(--lt-positive, #16a34a) 14%,transparent);border:1px solid color-mix(in srgb,var(--lt-positive, #16a34a) 42%,var(--background));border-radius:999px}.bool-check{flex:0 0 auto;display:block;width:.75rem;height:.75rem;color:var(--lt-positive, #16a34a)}\n"] }); }
|
|
6754
6812
|
}
|
|
6755
6813
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: BooleanCellComponent, decorators: [{
|
|
6756
6814
|
type: Component,
|
|
6757
|
-
args: [{ selector: 'lib-boolean-cell', standalone: false, template: "@if (isTrue) {\n <span class=\"bool bool-true\">\n <svg class=\"bool-check\" viewBox=\"0 0 14 14\" width=\"12\" height=\"12\" aria-hidden=\"true\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M2.5 7.6 5.7 10.8 11.5 3.6\"/>\n </svg>\n <span class=\"bool-label\">{{ trueLabel }}</span>\n </span>\n}\n", styles: [":host{display:inline-flex;align-items:center}.bool-true{display:inline-flex;align-items:center;gap:.
|
|
6815
|
+
args: [{ selector: 'lib-boolean-cell', standalone: false, template: "@if (isTrue) {\n <span class=\"bool bool-true\">\n <svg class=\"bool-check\" viewBox=\"0 0 14 14\" width=\"12\" height=\"12\" aria-hidden=\"true\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M2.5 7.6 5.7 10.8 11.5 3.6\"/>\n </svg>\n <span class=\"bool-label\">{{ trueLabel }}</span>\n </span>\n}\n", styles: [":host{display:inline-flex;align-items:center}.bool-true{display:inline-flex;align-items:center;gap:.3375rem;min-height:1.575rem;box-sizing:border-box;padding:.140625rem .5625rem .140625rem .421875rem;font-family:var(--lt-font);font-size:.73125rem;font-weight:500;line-height:1.2;color:var(--lt-positive-text, #166534);background:color-mix(in srgb,var(--lt-positive, #16a34a) 14%,transparent);border:1px solid color-mix(in srgb,var(--lt-positive, #16a34a) 42%,var(--background));border-radius:999px}.bool-check{flex:0 0 auto;display:block;width:.75rem;height:.75rem;color:var(--lt-positive, #16a34a)}\n"] }]
|
|
6758
6816
|
}], propDecorators: { value: [{
|
|
6759
6817
|
type: Input
|
|
6760
6818
|
}], trueLabel: [{
|
|
@@ -6777,7 +6835,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
6777
6835
|
limitations under the License.
|
|
6778
6836
|
*/
|
|
6779
6837
|
/**
|
|
6780
|
-
* Enrollment-token cell for the identities list. Shows a status chip (
|
|
6838
|
+
* Enrollment-token cell for the identities list. Shows a status chip (Token /
|
|
6781
6839
|
* Expired / —) that doubles as a dropdown of enrollment actions (Download JWT, Show
|
|
6782
6840
|
* QR, Re-issue). Actions are emitted via the cell context's `emitAction`, so they run
|
|
6783
6841
|
* through the same page handlers as the row ⋯ menu.
|
|
@@ -6795,7 +6853,14 @@ class TokenCellComponent {
|
|
|
6795
6853
|
return this.tokenExpired ? 'expired' : 'available';
|
|
6796
6854
|
}
|
|
6797
6855
|
get statusLabel() {
|
|
6798
|
-
return this.status === 'expired' ? 'Expired' : '
|
|
6856
|
+
return this.status === 'expired' ? 'Expired' : 'Token';
|
|
6857
|
+
}
|
|
6858
|
+
/** A cert-enrolled identity with no pending token can have its enrollment
|
|
6859
|
+
* re-issued. Reset enrollment acts on the cert authenticator, so this is gated
|
|
6860
|
+
* on cert specifically: password (updb) and external-IdP/JWT-signer identities
|
|
6861
|
+
* have no cert to reset and are left as the empty state. */
|
|
6862
|
+
get canReissue() {
|
|
6863
|
+
return this.status === 'none' && !!this.row?.authenticators?.cert?.id;
|
|
6799
6864
|
}
|
|
6800
6865
|
get actions() {
|
|
6801
6866
|
if (this.status === 'available') {
|
|
@@ -6845,11 +6910,11 @@ class TokenCellComponent {
|
|
|
6845
6910
|
return expiration ? moment$1(expiration).isBefore() : false;
|
|
6846
6911
|
}
|
|
6847
6912
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: TokenCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6848
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: TokenCellComponent, isStandalone: false, selector: "lib-token-cell", inputs: { row: "row", emitAction: "emitAction" }, viewQueries: [{ propertyName: "trigger", first: true, predicate: ["trigger"], descendants: true }], ngImport: i0, template: "@if (status !== 'none') {\n <button\n #trigger\n type=\"button\"\n class=\"token-chip {{ status }}\"\n [class.is-open]=\"open\"\n (click)=\"toggleMenu($event)\"\n aria-haspopup=\"menu\"\n [attr.aria-expanded]=\"open\"\n >\n <span class=\"token-chip-label\">{{ statusLabel }}</span>\n <svg class=\"token-caret\" viewBox=\"0 0 10 6\" width=\"9\" height=\"6\" aria-hidden=\"true\">\n <path fill=\"currentColor\" d=\"
|
|
6913
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: TokenCellComponent, isStandalone: false, selector: "lib-token-cell", inputs: { row: "row", emitAction: "emitAction" }, viewQueries: [{ propertyName: "trigger", first: true, predicate: ["trigger"], descendants: true }], ngImport: i0, template: "@if (status !== 'none') {\n <button\n #trigger\n type=\"button\"\n class=\"token-chip {{ status }}\"\n [class.is-open]=\"open\"\n (click)=\"toggleMenu($event)\"\n aria-haspopup=\"menu\"\n [attr.aria-expanded]=\"open\"\n >\n <span class=\"token-chip-label\">{{ statusLabel }}</span>\n <svg class=\"token-caret\" viewBox=\"0 0 10 6\" width=\"9\" height=\"6\" aria-hidden=\"true\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M1 1.5 5 5 9 1.5\"/>\n </svg>\n </button>\n\n @if (open) {\n <div class=\"token-menu\" [ngStyle]=\"{ left: menuLeft + 'px', top: menuTop + 'px' }\" (clickOutside)=\"closeMenu()\">\n @for (a of actions; track a.action) {\n <button type=\"button\" class=\"token-menu-item\" (click)=\"runAction(a.action, $event)\">\n <span class=\"token-menu-icon {{ a.icon }}\" aria-hidden=\"true\"></span>\n <span class=\"token-menu-label\">{{ a.label }}</span>\n </button>\n }\n </div>\n }\n} @else if (canReissue) {\n <button\n type=\"button\"\n class=\"token-chip reissue\"\n (click)=\"runAction('reset-enrollment', $event)\"\n aria-label=\"Reissue enrollment\"\n >\n <svg class=\"token-reissue-icon\" viewBox=\"0 0 16 16\" aria-hidden=\"true\"\n fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M12.5 5A5 5 0 0 0 3.5 6.5\"/>\n <path d=\"M3.5 11A5 5 0 0 0 12.5 9.5\"/>\n <path d=\"M12.5 2.5V5H10\"/>\n <path d=\"M3.5 13.5V11H6\"/>\n </svg>\n <span class=\"token-chip-label\">Reissue</span>\n </button>\n} @else {\n <span class=\"token-empty\">—</span>\n}\n", styles: [":host{display:inline-flex;align-items:center}.token-chip{display:inline-flex;align-items:center;gap:.3375rem;min-height:1.575rem;box-sizing:border-box;padding:.140625rem .5625rem;font-family:var(--lt-font);font-size:.73125rem;font-weight:500;line-height:1.2;border:1px solid transparent;border-radius:999px;cursor:pointer;white-space:nowrap;transition:filter .15s}.token-chip .token-caret{display:block;width:.5625rem;height:auto;opacity:.75}.token-chip:hover,.token-chip.is-open{filter:brightness(.96)}.token-chip.available{color:var(--lt-link);background:color-mix(in srgb,var(--lt-link) 14%,var(--lt-control-bg));border-color:color-mix(in srgb,var(--lt-link) 42%,var(--background))}.token-chip.expired,.token-chip.reissue{color:var(--lt-warning-text, #92400e);background:color-mix(in srgb,var(--lt-warning, #f5a93d) 20%,var(--lt-control-bg));border-color:color-mix(in srgb,var(--lt-warning, #f5a93d) 55%,var(--background))}.token-reissue-icon{flex:0 0 auto;display:block;width:.75rem;height:.75rem}.token-empty{color:var(--groupText)}.token-menu{position:fixed;z-index:1000;min-width:11rem;padding:.25rem;background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);box-shadow:var(--shadowLarge);animation:token-in .1s ease-out}@keyframes token-in{0%{opacity:0;transform:translateY(-.25rem)}to{opacity:1;transform:translateY(0)}}.token-menu-item{display:flex;align-items:center;gap:.5rem;width:100%;padding:.4375rem .5rem;font-family:var(--lt-font);font-size:.8125rem;color:var(--lt-cell-text);text-align:left;background:transparent;border:none;border-radius:var(--lt-radius);cursor:pointer}.token-menu-item:hover{background:var(--lt-row-hover);color:var(--lt-link)}.token-menu-item:hover .token-menu-icon{color:var(--lt-link)}.token-menu-icon{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:1rem;font-size:.9375rem;color:var(--lt-icon)}\n"], dependencies: [{ kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i1$4.ClickOutsideDirective, selector: "[clickOutside]", inputs: ["clickOutsideEnabled", "attachOutsideOnClick", "delayClickOutsideInit", "emitOnBlur", "exclude", "excludeBeforeClick", "clickOutsideEvents"], outputs: ["clickOutside"] }] }); }
|
|
6849
6914
|
}
|
|
6850
6915
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: TokenCellComponent, decorators: [{
|
|
6851
6916
|
type: Component,
|
|
6852
|
-
args: [{ selector: 'lib-token-cell', standalone: false, template: "@if (status !== 'none') {\n <button\n #trigger\n type=\"button\"\n class=\"token-chip {{ status }}\"\n [class.is-open]=\"open\"\n (click)=\"toggleMenu($event)\"\n aria-haspopup=\"menu\"\n [attr.aria-expanded]=\"open\"\n >\n <span class=\"token-chip-label\">{{ statusLabel }}</span>\n <svg class=\"token-caret\" viewBox=\"0 0 10 6\" width=\"9\" height=\"6\" aria-hidden=\"true\">\n <path fill=\"currentColor\" d=\"
|
|
6917
|
+
args: [{ selector: 'lib-token-cell', standalone: false, template: "@if (status !== 'none') {\n <button\n #trigger\n type=\"button\"\n class=\"token-chip {{ status }}\"\n [class.is-open]=\"open\"\n (click)=\"toggleMenu($event)\"\n aria-haspopup=\"menu\"\n [attr.aria-expanded]=\"open\"\n >\n <span class=\"token-chip-label\">{{ statusLabel }}</span>\n <svg class=\"token-caret\" viewBox=\"0 0 10 6\" width=\"9\" height=\"6\" aria-hidden=\"true\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M1 1.5 5 5 9 1.5\"/>\n </svg>\n </button>\n\n @if (open) {\n <div class=\"token-menu\" [ngStyle]=\"{ left: menuLeft + 'px', top: menuTop + 'px' }\" (clickOutside)=\"closeMenu()\">\n @for (a of actions; track a.action) {\n <button type=\"button\" class=\"token-menu-item\" (click)=\"runAction(a.action, $event)\">\n <span class=\"token-menu-icon {{ a.icon }}\" aria-hidden=\"true\"></span>\n <span class=\"token-menu-label\">{{ a.label }}</span>\n </button>\n }\n </div>\n }\n} @else if (canReissue) {\n <button\n type=\"button\"\n class=\"token-chip reissue\"\n (click)=\"runAction('reset-enrollment', $event)\"\n aria-label=\"Reissue enrollment\"\n >\n <svg class=\"token-reissue-icon\" viewBox=\"0 0 16 16\" aria-hidden=\"true\"\n fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M12.5 5A5 5 0 0 0 3.5 6.5\"/>\n <path d=\"M3.5 11A5 5 0 0 0 12.5 9.5\"/>\n <path d=\"M12.5 2.5V5H10\"/>\n <path d=\"M3.5 13.5V11H6\"/>\n </svg>\n <span class=\"token-chip-label\">Reissue</span>\n </button>\n} @else {\n <span class=\"token-empty\">—</span>\n}\n", styles: [":host{display:inline-flex;align-items:center}.token-chip{display:inline-flex;align-items:center;gap:.3375rem;min-height:1.575rem;box-sizing:border-box;padding:.140625rem .5625rem;font-family:var(--lt-font);font-size:.73125rem;font-weight:500;line-height:1.2;border:1px solid transparent;border-radius:999px;cursor:pointer;white-space:nowrap;transition:filter .15s}.token-chip .token-caret{display:block;width:.5625rem;height:auto;opacity:.75}.token-chip:hover,.token-chip.is-open{filter:brightness(.96)}.token-chip.available{color:var(--lt-link);background:color-mix(in srgb,var(--lt-link) 14%,var(--lt-control-bg));border-color:color-mix(in srgb,var(--lt-link) 42%,var(--background))}.token-chip.expired,.token-chip.reissue{color:var(--lt-warning-text, #92400e);background:color-mix(in srgb,var(--lt-warning, #f5a93d) 20%,var(--lt-control-bg));border-color:color-mix(in srgb,var(--lt-warning, #f5a93d) 55%,var(--background))}.token-reissue-icon{flex:0 0 auto;display:block;width:.75rem;height:.75rem}.token-empty{color:var(--groupText)}.token-menu{position:fixed;z-index:1000;min-width:11rem;padding:.25rem;background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);box-shadow:var(--shadowLarge);animation:token-in .1s ease-out}@keyframes token-in{0%{opacity:0;transform:translateY(-.25rem)}to{opacity:1;transform:translateY(0)}}.token-menu-item{display:flex;align-items:center;gap:.5rem;width:100%;padding:.4375rem .5rem;font-family:var(--lt-font);font-size:.8125rem;color:var(--lt-cell-text);text-align:left;background:transparent;border:none;border-radius:var(--lt-radius);cursor:pointer}.token-menu-item:hover{background:var(--lt-row-hover);color:var(--lt-link)}.token-menu-item:hover .token-menu-icon{color:var(--lt-link)}.token-menu-icon{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:1rem;font-size:.9375rem;color:var(--lt-icon)}\n"] }]
|
|
6853
6918
|
}], propDecorators: { row: [{
|
|
6854
6919
|
type: Input
|
|
6855
6920
|
}], emitAction: [{
|
|
@@ -6859,6 +6924,108 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
6859
6924
|
args: ['trigger']
|
|
6860
6925
|
}] } });
|
|
6861
6926
|
|
|
6927
|
+
/*
|
|
6928
|
+
Copyright NetFoundry Inc.
|
|
6929
|
+
|
|
6930
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6931
|
+
you may not use this file except in compliance with the License.
|
|
6932
|
+
You may obtain a copy of the License at
|
|
6933
|
+
|
|
6934
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
6935
|
+
|
|
6936
|
+
Unless required by applicable law or agreed to in writing, software
|
|
6937
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
6938
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
6939
|
+
See the License for the specific language governing permissions and
|
|
6940
|
+
limitations under the License.
|
|
6941
|
+
*/
|
|
6942
|
+
/**
|
|
6943
|
+
* Role/attribute chips for list-table attribute columns. Each chip reveals two
|
|
6944
|
+
* controls on hover: copy (puts the bare name on the clipboard) and filter (adds
|
|
6945
|
+
* the attribute to this column's filter). Filtering goes through the shared
|
|
6946
|
+
* DataTableFilterService so it stacks with, and stays in sync with, the column
|
|
6947
|
+
* header's filter dropdown.
|
|
6948
|
+
*/
|
|
6949
|
+
class AttributeCellComponent {
|
|
6950
|
+
set attributes(value) {
|
|
6951
|
+
this.chips = this.toChips(value);
|
|
6952
|
+
}
|
|
6953
|
+
constructor(filterService) {
|
|
6954
|
+
this.filterService = filterService;
|
|
6955
|
+
/** Column field; used as the filter's columnId so the filter icon drives the
|
|
6956
|
+
* same filter as the column header dropdown. */
|
|
6957
|
+
this.field = '';
|
|
6958
|
+
/** Column label, shown on the applied-filter tag. */
|
|
6959
|
+
this.filterLabel = '';
|
|
6960
|
+
this.chips = [];
|
|
6961
|
+
}
|
|
6962
|
+
toChips(value) {
|
|
6963
|
+
const list = Array.isArray(value) ? value : (value ? [value] : []);
|
|
6964
|
+
return list.reduce((chips, attr) => {
|
|
6965
|
+
const raw = String(attr?.name ?? attr ?? '').trim();
|
|
6966
|
+
if (raw) {
|
|
6967
|
+
const first = raw.charAt(0);
|
|
6968
|
+
const isNamed = first === '@';
|
|
6969
|
+
const bare = first === '#' || first === '@' ? raw.slice(1) : raw;
|
|
6970
|
+
const label = isNamed || first === '#' ? raw : '#' + raw;
|
|
6971
|
+
chips.push({ label, raw, bare, isNamed });
|
|
6972
|
+
}
|
|
6973
|
+
return chips;
|
|
6974
|
+
}, []);
|
|
6975
|
+
}
|
|
6976
|
+
async copy(chip, event) {
|
|
6977
|
+
event.stopPropagation();
|
|
6978
|
+
try {
|
|
6979
|
+
await navigator.clipboard.writeText(chip.bare);
|
|
6980
|
+
chip.copied = true;
|
|
6981
|
+
setTimeout(() => (chip.copied = false), 1200);
|
|
6982
|
+
}
|
|
6983
|
+
catch {
|
|
6984
|
+
// clipboard blocked (older browser or insecure context); nothing to do
|
|
6985
|
+
}
|
|
6986
|
+
}
|
|
6987
|
+
filter(chip, event) {
|
|
6988
|
+
event.stopPropagation();
|
|
6989
|
+
if (!this.field) {
|
|
6990
|
+
return;
|
|
6991
|
+
}
|
|
6992
|
+
const existing = this.filterService.filters.find((f) => f.columnId === this.field);
|
|
6993
|
+
const values = Array.isArray(existing?.value)
|
|
6994
|
+
? [...existing.value]
|
|
6995
|
+
: (existing?.value ? [existing.value] : []);
|
|
6996
|
+
// filter on the source value (prefix intact) so a named @entity does not match a
|
|
6997
|
+
// role of the same bare name, and so it stacks with the header dropdown's values
|
|
6998
|
+
if (values.includes(chip.raw)) {
|
|
6999
|
+
return;
|
|
7000
|
+
}
|
|
7001
|
+
values.push(chip.raw);
|
|
7002
|
+
// keep whatever all-of/any-of the filter already uses so adding a chip does
|
|
7003
|
+
// not quietly change the match mode
|
|
7004
|
+
const semantic = existing?.semantic === 'AllOf' ? 'AllOf' : 'AnyOf';
|
|
7005
|
+
const filter = {
|
|
7006
|
+
filterName: this.filterLabel,
|
|
7007
|
+
columnId: this.field,
|
|
7008
|
+
value: values,
|
|
7009
|
+
label: values.join(', '),
|
|
7010
|
+
type: 'ATTRIBUTE',
|
|
7011
|
+
semantic,
|
|
7012
|
+
};
|
|
7013
|
+
this.filterService.updateFilter(filter);
|
|
7014
|
+
}
|
|
7015
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: AttributeCellComponent, deps: [{ token: DataTableFilterService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7016
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: AttributeCellComponent, isStandalone: false, selector: "lib-attribute-cell", inputs: { attributes: "attributes", field: "field", filterLabel: "filterLabel" }, ngImport: i0, template: "@for (chip of chips; track chip.raw) {\n <span class=\"lt-chip\" [class.lt-chip-at]=\"chip.isNamed\">\n <span class=\"lt-chip-label\">{{ chip.label }}</span>\n <span class=\"lt-chip-actions\" (click)=\"$event.stopPropagation()\">\n <button\n type=\"button\"\n class=\"lt-chip-action\"\n [class.is-done]=\"chip.copied\"\n (click)=\"copy(chip, $event)\"\n [attr.aria-label]=\"'Copy ' + chip.bare\"\n title=\"Copy\"\n >\n @if (chip.copied) {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M3.5 8.5 7 12l5.5-7\"/>\n </svg>\n } @else {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"1.3\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8\" rx=\"1.3\"/>\n <path d=\"M10.5 5.5V3.3A1.3 1.3 0 0 0 9.2 2H3.3A1.3 1.3 0 0 0 2 3.3v5.9A1.3 1.3 0 0 0 3.3 10.5h2.2\"/>\n </svg>\n }\n </button>\n <button\n type=\"button\"\n class=\"lt-chip-action\"\n (click)=\"filter(chip, $event)\"\n [attr.aria-label]=\"'Filter by ' + chip.bare\"\n title=\"Filter\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"1.3\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M2 3.5h12l-4.6 5.4v3.6l-2.8 1.4V8.9z\"/>\n </svg>\n </button>\n </span>\n </span>\n}\n", styles: [":host{display:inline}.lt-chip{position:relative;--lt-chip-cover: color-mix(in srgb, var(--lt-link) 16%, var(--lt-row-bg, #f6f7fb))}.lt-chip.lt-chip-at{--lt-chip-cover: color-mix(in srgb, var(--secondary) 18%, var(--lt-row-bg, #f6f7fb))}.lt-chip-actions{position:absolute;top:0;right:0;bottom:0;display:flex;align-items:center;gap:.1875rem;padding-left:.875rem;padding-right:.3125rem;border-radius:inherit;opacity:0;pointer-events:none;transition:opacity .12s ease;background:linear-gradient(to right,transparent,var(--lt-chip-cover) 38%)}.lt-chip:hover .lt-chip-actions,.lt-chip:focus-within .lt-chip-actions{opacity:1;pointer-events:auto}.lt-chip-action{display:inline-flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;padding:0;color:var(--lt-link);background:var(--lt-control-bg);border:1px solid color-mix(in srgb,var(--lt-link) 40%,transparent);border-radius:.3125rem;cursor:pointer;transition:color .12s,background .12s,border-color .12s}.lt-chip-action svg{display:block;width:.875rem;height:.875rem}.lt-chip-action:hover{color:var(--lt-control-bg);background:var(--lt-link);border-color:var(--lt-link)}.lt-chip-action.is-done{color:var(--lt-positive, #16a34a);border-color:color-mix(in srgb,var(--lt-positive, #16a34a) 45%,transparent)}\n"] }); }
|
|
7017
|
+
}
|
|
7018
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: AttributeCellComponent, decorators: [{
|
|
7019
|
+
type: Component,
|
|
7020
|
+
args: [{ selector: 'lib-attribute-cell', standalone: false, template: "@for (chip of chips; track chip.raw) {\n <span class=\"lt-chip\" [class.lt-chip-at]=\"chip.isNamed\">\n <span class=\"lt-chip-label\">{{ chip.label }}</span>\n <span class=\"lt-chip-actions\" (click)=\"$event.stopPropagation()\">\n <button\n type=\"button\"\n class=\"lt-chip-action\"\n [class.is-done]=\"chip.copied\"\n (click)=\"copy(chip, $event)\"\n [attr.aria-label]=\"'Copy ' + chip.bare\"\n title=\"Copy\"\n >\n @if (chip.copied) {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M3.5 8.5 7 12l5.5-7\"/>\n </svg>\n } @else {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"1.3\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8\" rx=\"1.3\"/>\n <path d=\"M10.5 5.5V3.3A1.3 1.3 0 0 0 9.2 2H3.3A1.3 1.3 0 0 0 2 3.3v5.9A1.3 1.3 0 0 0 3.3 10.5h2.2\"/>\n </svg>\n }\n </button>\n <button\n type=\"button\"\n class=\"lt-chip-action\"\n (click)=\"filter(chip, $event)\"\n [attr.aria-label]=\"'Filter by ' + chip.bare\"\n title=\"Filter\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"1.3\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M2 3.5h12l-4.6 5.4v3.6l-2.8 1.4V8.9z\"/>\n </svg>\n </button>\n </span>\n </span>\n}\n", styles: [":host{display:inline}.lt-chip{position:relative;--lt-chip-cover: color-mix(in srgb, var(--lt-link) 16%, var(--lt-row-bg, #f6f7fb))}.lt-chip.lt-chip-at{--lt-chip-cover: color-mix(in srgb, var(--secondary) 18%, var(--lt-row-bg, #f6f7fb))}.lt-chip-actions{position:absolute;top:0;right:0;bottom:0;display:flex;align-items:center;gap:.1875rem;padding-left:.875rem;padding-right:.3125rem;border-radius:inherit;opacity:0;pointer-events:none;transition:opacity .12s ease;background:linear-gradient(to right,transparent,var(--lt-chip-cover) 38%)}.lt-chip:hover .lt-chip-actions,.lt-chip:focus-within .lt-chip-actions{opacity:1;pointer-events:auto}.lt-chip-action{display:inline-flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;padding:0;color:var(--lt-link);background:var(--lt-control-bg);border:1px solid color-mix(in srgb,var(--lt-link) 40%,transparent);border-radius:.3125rem;cursor:pointer;transition:color .12s,background .12s,border-color .12s}.lt-chip-action svg{display:block;width:.875rem;height:.875rem}.lt-chip-action:hover{color:var(--lt-control-bg);background:var(--lt-link);border-color:var(--lt-link)}.lt-chip-action.is-done{color:var(--lt-positive, #16a34a);border-color:color-mix(in srgb,var(--lt-positive, #16a34a) 45%,transparent)}\n"] }]
|
|
7021
|
+
}], ctorParameters: () => [{ type: DataTableFilterService }], propDecorators: { attributes: [{
|
|
7022
|
+
type: Input
|
|
7023
|
+
}], field: [{
|
|
7024
|
+
type: Input
|
|
7025
|
+
}], filterLabel: [{
|
|
7026
|
+
type: Input
|
|
7027
|
+
}] } });
|
|
7028
|
+
|
|
6862
7029
|
/*
|
|
6863
7030
|
Copyright NetFoundry Inc.
|
|
6864
7031
|
|
|
@@ -7253,27 +7420,6 @@ class IdentitiesPageService extends ListPageServiceClass {
|
|
|
7253
7420
|
: 'lt-type-other';
|
|
7254
7421
|
return `<span class="lt-type-badge ${cls}">${t}</span>`;
|
|
7255
7422
|
};
|
|
7256
|
-
// Light skinned role chips (the legacy rolesRenderer paints
|
|
7257
|
-
// heavy dark overlap chips; this stays scoped to the beta page).
|
|
7258
|
-
const rolesChipRenderer = (row) => {
|
|
7259
|
-
const colId = row?.column?.colId;
|
|
7260
|
-
const attrs = row?.data?.[colId + 'Display'] || row?.data?.[colId] || [];
|
|
7261
|
-
if (!attrs?.length) {
|
|
7262
|
-
return '';
|
|
7263
|
-
}
|
|
7264
|
-
return attrs.map((attr) => {
|
|
7265
|
-
const raw = String(attr?.name ?? attr ?? '').trim();
|
|
7266
|
-
if (!raw) {
|
|
7267
|
-
return '';
|
|
7268
|
-
}
|
|
7269
|
-
// named attributes (@) use the secondary color; role attributes (#)
|
|
7270
|
-
// the primary color, matching the tag selector's distinction
|
|
7271
|
-
const isNamed = raw.charAt(0) === '@';
|
|
7272
|
-
const label = isNamed ? raw : (raw.charAt(0) === '#' ? raw : '#' + raw);
|
|
7273
|
-
const cls = isNamed ? 'lt-chip lt-chip-at' : 'lt-chip';
|
|
7274
|
-
return `<span class="${cls}">${label}</span>`;
|
|
7275
|
-
}).join('');
|
|
7276
|
-
};
|
|
7277
7423
|
let tableColumns = [
|
|
7278
7424
|
{
|
|
7279
7425
|
key: 'name',
|
|
@@ -7316,7 +7462,12 @@ class IdentitiesPageService extends ListPageServiceClass {
|
|
|
7316
7462
|
label: 'Roles',
|
|
7317
7463
|
filterType: 'ATTRIBUTE',
|
|
7318
7464
|
headerParams: identityRolesHeaderComponentParams,
|
|
7319
|
-
|
|
7465
|
+
cell: AttributeCellComponent,
|
|
7466
|
+
cellInputs: (ctx) => ({
|
|
7467
|
+
attributes: ctx.row?.roleAttributesDisplay ?? ctx.row?.roleAttributes,
|
|
7468
|
+
field: ctx.colId,
|
|
7469
|
+
filterLabel: 'Roles',
|
|
7470
|
+
}),
|
|
7320
7471
|
onCellClick: (ctx) => {
|
|
7321
7472
|
if (this.hasSelectedText()) {
|
|
7322
7473
|
return;
|
|
@@ -7401,7 +7552,7 @@ class IdentitiesPageService extends ListPageServiceClass {
|
|
|
7401
7552
|
{
|
|
7402
7553
|
key: 'token',
|
|
7403
7554
|
field: 'token',
|
|
7404
|
-
label: '
|
|
7555
|
+
label: 'Enrollment',
|
|
7405
7556
|
cell: TokenCellComponent,
|
|
7406
7557
|
cellInputs: (ctx) => ({ row: ctx.row, emitAction: ctx.emitAction }),
|
|
7407
7558
|
resizable: true,
|
|
@@ -10169,6 +10320,11 @@ class ListTableHeaderComponent {
|
|
|
10169
10320
|
this.actionClicked = new EventEmitter();
|
|
10170
10321
|
this.tabClicked = new EventEmitter();
|
|
10171
10322
|
}
|
|
10323
|
+
/** Only show the tab strip when there is more than one visible tab; a lone tab
|
|
10324
|
+
* is just a redundant label, so the strip is hidden. */
|
|
10325
|
+
get showTabs() {
|
|
10326
|
+
return (this.tabs || []).filter((t) => !t?.hidden).length > 1;
|
|
10327
|
+
}
|
|
10172
10328
|
clickAction(value) {
|
|
10173
10329
|
this.actionClicked.emit(value);
|
|
10174
10330
|
}
|
|
@@ -10210,11 +10366,11 @@ class ListTableHeaderComponent {
|
|
|
10210
10366
|
return active === tab?.id || active === tab?.value || active === tab?.url || active === tab?.label;
|
|
10211
10367
|
}
|
|
10212
10368
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListTableHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
10213
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: ListTableHeaderComponent, isStandalone: false, selector: "lib-list-table-header", inputs: { title: "title", subtitle: "subtitle", createLabel: "createLabel", infoText: "infoText", tabs: "tabs", showAdd: "showAdd", blockCreate: "blockCreate", blockDelete: "blockDelete", tabsUseRouter: "tabsUseRouter", activeTab: "activeTab" }, outputs: { actionClicked: "actionClicked", tabClicked: "tabClicked" }, ngImport: i0, template: "<div class=\"lth\">\n <div class=\"lth-main\">\n <div class=\"lth-icon\" aria-hidden=\"true\">\n <ng-content select=\"[header-icon]\"></ng-content>\n </div>\n <div class=\"lth-titles\">\n <div class=\"lth-title-row\">\n <h1 class=\"lth-title\">{{ title }}</h1>\n @if (infoText) {\n <span class=\"lth-info\" [title]=\"infoText\" tabindex=\"0\" role=\"img\" [attr.aria-label]=\"infoText\">\n <span class=\"lth-info-badge\" aria-hidden=\"true\">i</span>\n </span>\n }\n </div>\n @if (subtitle) {\n <p class=\"lth-subtitle\">{{ subtitle }}</p>\n }\n </div>\n <div class=\"lth-actions\">\n @if (showAdd && !blockCreate) {\n <button type=\"button\" class=\"lth-create\" (click)=\"clickAction('add')\" data-action=\"add\" id=\"CreateButton\">\n <span class=\"lth-create-plus\" aria-hidden=\"true\">+</span>\n <span>{{ createLabel }}</span>\n </button>\n }\n @if (!showAdd && !blockDelete) {\n <button type=\"button\" class=\"lth-delete\" (click)=\"clickAction('delete')\" data-action=\"delete\" id=\"DeleteButton\">\n <span class=\"lth-delete-icon icon-minus\" aria-hidden=\"true\"></span>\n <span>Delete</span>\n </button>\n }\n </div>\n </div>\n @if (
|
|
10369
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: ListTableHeaderComponent, isStandalone: false, selector: "lib-list-table-header", inputs: { title: "title", subtitle: "subtitle", createLabel: "createLabel", infoText: "infoText", tabs: "tabs", showAdd: "showAdd", blockCreate: "blockCreate", blockDelete: "blockDelete", tabsUseRouter: "tabsUseRouter", activeTab: "activeTab" }, outputs: { actionClicked: "actionClicked", tabClicked: "tabClicked" }, ngImport: i0, template: "<div class=\"lth\">\n <div class=\"lth-main\">\n <div class=\"lth-icon\" aria-hidden=\"true\">\n <ng-content select=\"[header-icon]\"></ng-content>\n </div>\n <div class=\"lth-titles\">\n <div class=\"lth-title-row\">\n <h1 class=\"lth-title\">{{ title }}</h1>\n @if (infoText) {\n <span class=\"lth-info\" [title]=\"infoText\" tabindex=\"0\" role=\"img\" [attr.aria-label]=\"infoText\">\n <span class=\"lth-info-badge\" aria-hidden=\"true\">i</span>\n </span>\n }\n </div>\n @if (subtitle) {\n <p class=\"lth-subtitle\">{{ subtitle }}</p>\n }\n </div>\n <div class=\"lth-actions\">\n @if (showAdd && !blockCreate) {\n <button type=\"button\" class=\"lth-create\" (click)=\"clickAction('add')\" data-action=\"add\" id=\"CreateButton\">\n <span class=\"lth-create-plus\" aria-hidden=\"true\">+</span>\n <span>{{ createLabel }}</span>\n </button>\n }\n @if (!showAdd && !blockDelete) {\n <button type=\"button\" class=\"lth-delete\" (click)=\"clickAction('delete')\" data-action=\"delete\" id=\"DeleteButton\">\n <span class=\"lth-delete-icon icon-minus\" aria-hidden=\"true\"></span>\n <span>Delete</span>\n </button>\n }\n </div>\n </div>\n @if (showTabs) {\n <div class=\"lth-tabs\">\n @for (tab of tabs; track tab) {\n <a\n class=\"lth-tab\"\n [ngClass]=\"{ selected: tabSelected(tab) }\"\n [routerLink]=\"tabsUseRouter ? tab.url : null\"\n [hidden]=\"tab.hidden\"\n [attr.role]=\"tabsUseRouter ? null : 'button'\"\n [attr.tabindex]=\"tabsUseRouter ? null : 0\"\n (click)=\"onTabClick(tab)\"\n (keydown.enter)=\"tabsUseRouter ? null : onTabClick(tab)\"\n >{{ tab.label }}</a>\n }\n </div>\n }\n</div>\n", styles: [":host{display:block;width:100%}.lth{display:flex;flex-direction:column;gap:.875rem;padding-bottom:.625rem}.lth-main{display:flex;align-items:center;gap:.875rem}.lth-icon{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:2.75rem;height:2.75rem;border-radius:.75rem;color:var(--lt-header-icon, var(--primary));background:color-mix(in srgb,var(--lt-header-icon, var(--primary)) 12%,var(--background));border:1px solid color-mix(in srgb,var(--lt-header-icon, var(--primary)) 22%,var(--background))}.lth-icon svg,.lth-icon img{display:block;width:1.5rem;height:1.5rem}:host ::ng-deep .lth-icon [class^=icon-],:host ::ng-deep .lth-icon [class*=\" icon-\"]{font-size:1.5rem;line-height:1}:host ::ng-deep .lth-icon [class^=icon-]:before,:host ::ng-deep .lth-icon [class*=\" icon-\"]:before{color:var(--lt-header-icon, var(--primary))}.lth-titles{flex:1 1 auto;min-width:0}.lth-title-row{display:flex;align-items:center;gap:.5rem}.lth-title{margin:0;font-family:var(--lt-font, \"Open Sans\", sans-serif);font-size:1.5rem;font-weight:700;line-height:1.15;color:var(--tableText, var(--text))}.lth-info{display:inline-flex;align-items:center;justify-content:center;padding:.25rem;background:var(--background);border:1px solid var(--stroke);border-radius:.375rem;box-shadow:0 1px 2px #0000000f;cursor:help}.lth-info:hover{border-color:var(--groupText)}.lth-info-badge{display:inline-flex;align-items:center;justify-content:center;width:.9375rem;height:.9375rem;font-size:.625rem;font-weight:700;font-style:italic;font-family:Georgia,Times New Roman,serif;line-height:1;color:#fff;background:var(--dark);border-radius:50%}.lth-subtitle{margin:.125rem 0 0;font-family:var(--lt-font, \"Open Sans\", sans-serif);font-size:.8125rem;color:var(--groupText)}.lth-actions{flex:0 0 auto;display:flex;align-items:center;gap:.5rem}.lth-create{display:inline-flex;align-items:center;gap:.4375rem;height:2.5rem;padding:0 1rem;font-family:var(--lt-font, \"Open Sans\", sans-serif);font-size:.8125rem;font-weight:600;color:#fff;background:var(--primary);border:none;border-radius:var(--inputBorderRadius, .5rem);cursor:pointer;transition:filter .15s}.lth-create:hover{filter:brightness(1.06)}.lth-create-plus{font-size:1.125rem;line-height:1}.lth-delete{display:inline-flex;align-items:center;gap:.4375rem;height:2.5rem;padding:0 1rem;font-family:var(--lt-font, \"Open Sans\", sans-serif);font-size:.8125rem;font-weight:600;color:var(--redText, #9c0027);background:transparent;border:1px solid var(--redText, #9c0027);border-radius:var(--inputBorderRadius, .5rem);cursor:pointer;transition:background .15s}.lth-delete:hover{background:color-mix(in srgb,var(--redText, #9c0027) 8%,transparent)}.lth-tabs{display:flex;align-items:center;gap:1.25rem;border-bottom:1px solid var(--stroke)}.lth-tab{padding:.4375rem .125rem;font-family:var(--lt-font, \"Open Sans\", sans-serif);font-size:.8125rem;font-weight:600;color:var(--groupText);text-decoration:none;border-bottom:2px solid transparent;margin-bottom:-1px;cursor:pointer;transition:color .15s,border-color .15s}.lth-tab:hover{color:var(--text)}.lth-tab.selected{color:var(--primary);border-bottom-color:var(--primary)}\n"], dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] }); }
|
|
10214
10370
|
}
|
|
10215
10371
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListTableHeaderComponent, decorators: [{
|
|
10216
10372
|
type: Component,
|
|
10217
|
-
args: [{ selector: 'lib-list-table-header', standalone: false, template: "<div class=\"lth\">\n <div class=\"lth-main\">\n <div class=\"lth-icon\" aria-hidden=\"true\">\n <ng-content select=\"[header-icon]\"></ng-content>\n </div>\n <div class=\"lth-titles\">\n <div class=\"lth-title-row\">\n <h1 class=\"lth-title\">{{ title }}</h1>\n @if (infoText) {\n <span class=\"lth-info\" [title]=\"infoText\" tabindex=\"0\" role=\"img\" [attr.aria-label]=\"infoText\">\n <span class=\"lth-info-badge\" aria-hidden=\"true\">i</span>\n </span>\n }\n </div>\n @if (subtitle) {\n <p class=\"lth-subtitle\">{{ subtitle }}</p>\n }\n </div>\n <div class=\"lth-actions\">\n @if (showAdd && !blockCreate) {\n <button type=\"button\" class=\"lth-create\" (click)=\"clickAction('add')\" data-action=\"add\" id=\"CreateButton\">\n <span class=\"lth-create-plus\" aria-hidden=\"true\">+</span>\n <span>{{ createLabel }}</span>\n </button>\n }\n @if (!showAdd && !blockDelete) {\n <button type=\"button\" class=\"lth-delete\" (click)=\"clickAction('delete')\" data-action=\"delete\" id=\"DeleteButton\">\n <span class=\"lth-delete-icon icon-minus\" aria-hidden=\"true\"></span>\n <span>Delete</span>\n </button>\n }\n </div>\n </div>\n @if (
|
|
10373
|
+
args: [{ selector: 'lib-list-table-header', standalone: false, template: "<div class=\"lth\">\n <div class=\"lth-main\">\n <div class=\"lth-icon\" aria-hidden=\"true\">\n <ng-content select=\"[header-icon]\"></ng-content>\n </div>\n <div class=\"lth-titles\">\n <div class=\"lth-title-row\">\n <h1 class=\"lth-title\">{{ title }}</h1>\n @if (infoText) {\n <span class=\"lth-info\" [title]=\"infoText\" tabindex=\"0\" role=\"img\" [attr.aria-label]=\"infoText\">\n <span class=\"lth-info-badge\" aria-hidden=\"true\">i</span>\n </span>\n }\n </div>\n @if (subtitle) {\n <p class=\"lth-subtitle\">{{ subtitle }}</p>\n }\n </div>\n <div class=\"lth-actions\">\n @if (showAdd && !blockCreate) {\n <button type=\"button\" class=\"lth-create\" (click)=\"clickAction('add')\" data-action=\"add\" id=\"CreateButton\">\n <span class=\"lth-create-plus\" aria-hidden=\"true\">+</span>\n <span>{{ createLabel }}</span>\n </button>\n }\n @if (!showAdd && !blockDelete) {\n <button type=\"button\" class=\"lth-delete\" (click)=\"clickAction('delete')\" data-action=\"delete\" id=\"DeleteButton\">\n <span class=\"lth-delete-icon icon-minus\" aria-hidden=\"true\"></span>\n <span>Delete</span>\n </button>\n }\n </div>\n </div>\n @if (showTabs) {\n <div class=\"lth-tabs\">\n @for (tab of tabs; track tab) {\n <a\n class=\"lth-tab\"\n [ngClass]=\"{ selected: tabSelected(tab) }\"\n [routerLink]=\"tabsUseRouter ? tab.url : null\"\n [hidden]=\"tab.hidden\"\n [attr.role]=\"tabsUseRouter ? null : 'button'\"\n [attr.tabindex]=\"tabsUseRouter ? null : 0\"\n (click)=\"onTabClick(tab)\"\n (keydown.enter)=\"tabsUseRouter ? null : onTabClick(tab)\"\n >{{ tab.label }}</a>\n }\n </div>\n }\n</div>\n", styles: [":host{display:block;width:100%}.lth{display:flex;flex-direction:column;gap:.875rem;padding-bottom:.625rem}.lth-main{display:flex;align-items:center;gap:.875rem}.lth-icon{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:2.75rem;height:2.75rem;border-radius:.75rem;color:var(--lt-header-icon, var(--primary));background:color-mix(in srgb,var(--lt-header-icon, var(--primary)) 12%,var(--background));border:1px solid color-mix(in srgb,var(--lt-header-icon, var(--primary)) 22%,var(--background))}.lth-icon svg,.lth-icon img{display:block;width:1.5rem;height:1.5rem}:host ::ng-deep .lth-icon [class^=icon-],:host ::ng-deep .lth-icon [class*=\" icon-\"]{font-size:1.5rem;line-height:1}:host ::ng-deep .lth-icon [class^=icon-]:before,:host ::ng-deep .lth-icon [class*=\" icon-\"]:before{color:var(--lt-header-icon, var(--primary))}.lth-titles{flex:1 1 auto;min-width:0}.lth-title-row{display:flex;align-items:center;gap:.5rem}.lth-title{margin:0;font-family:var(--lt-font, \"Open Sans\", sans-serif);font-size:1.5rem;font-weight:700;line-height:1.15;color:var(--tableText, var(--text))}.lth-info{display:inline-flex;align-items:center;justify-content:center;padding:.25rem;background:var(--background);border:1px solid var(--stroke);border-radius:.375rem;box-shadow:0 1px 2px #0000000f;cursor:help}.lth-info:hover{border-color:var(--groupText)}.lth-info-badge{display:inline-flex;align-items:center;justify-content:center;width:.9375rem;height:.9375rem;font-size:.625rem;font-weight:700;font-style:italic;font-family:Georgia,Times New Roman,serif;line-height:1;color:#fff;background:var(--dark);border-radius:50%}.lth-subtitle{margin:.125rem 0 0;font-family:var(--lt-font, \"Open Sans\", sans-serif);font-size:.8125rem;color:var(--groupText)}.lth-actions{flex:0 0 auto;display:flex;align-items:center;gap:.5rem}.lth-create{display:inline-flex;align-items:center;gap:.4375rem;height:2.5rem;padding:0 1rem;font-family:var(--lt-font, \"Open Sans\", sans-serif);font-size:.8125rem;font-weight:600;color:#fff;background:var(--primary);border:none;border-radius:var(--inputBorderRadius, .5rem);cursor:pointer;transition:filter .15s}.lth-create:hover{filter:brightness(1.06)}.lth-create-plus{font-size:1.125rem;line-height:1}.lth-delete{display:inline-flex;align-items:center;gap:.4375rem;height:2.5rem;padding:0 1rem;font-family:var(--lt-font, \"Open Sans\", sans-serif);font-size:.8125rem;font-weight:600;color:var(--redText, #9c0027);background:transparent;border:1px solid var(--redText, #9c0027);border-radius:var(--inputBorderRadius, .5rem);cursor:pointer;transition:background .15s}.lth-delete:hover{background:color-mix(in srgb,var(--redText, #9c0027) 8%,transparent)}.lth-tabs{display:flex;align-items:center;gap:1.25rem;border-bottom:1px solid var(--stroke)}.lth-tab{padding:.4375rem .125rem;font-family:var(--lt-font, \"Open Sans\", sans-serif);font-size:.8125rem;font-weight:600;color:var(--groupText);text-decoration:none;border-bottom:2px solid transparent;margin-bottom:-1px;cursor:pointer;transition:color .15s,border-color .15s}.lth-tab:hover{color:var(--text)}.lth-tab.selected{color:var(--primary);border-bottom-color:var(--primary)}\n"] }]
|
|
10218
10374
|
}], propDecorators: { title: [{
|
|
10219
10375
|
type: Input
|
|
10220
10376
|
}], subtitle: [{
|
|
@@ -11802,6 +11958,12 @@ class ListTableAutoRefreshComponent {
|
|
|
11802
11958
|
this.refresh = new EventEmitter();
|
|
11803
11959
|
this.secondsChange = new EventEmitter();
|
|
11804
11960
|
this.open = false;
|
|
11961
|
+
/** Menu geometry, all measured when the menu opens: left offset so labels line up
|
|
11962
|
+
* under the button's value, width so the right edge lands on the button's right
|
|
11963
|
+
* edge, and right padding so the check centers under the chevron. */
|
|
11964
|
+
this.menuLeft = 0;
|
|
11965
|
+
this.menuWidth = 0;
|
|
11966
|
+
this.menuPadRight = 0;
|
|
11805
11967
|
}
|
|
11806
11968
|
/** Current interval in seconds; 0 means off. */
|
|
11807
11969
|
set seconds(value) {
|
|
@@ -11823,7 +11985,37 @@ class ListTableAutoRefreshComponent {
|
|
|
11823
11985
|
}
|
|
11824
11986
|
toggleMenu(event) {
|
|
11825
11987
|
event.stopPropagation();
|
|
11826
|
-
this.open
|
|
11988
|
+
if (this.open) {
|
|
11989
|
+
this.open = false;
|
|
11990
|
+
return;
|
|
11991
|
+
}
|
|
11992
|
+
this.alignMenuToValue();
|
|
11993
|
+
this.open = true;
|
|
11994
|
+
}
|
|
11995
|
+
/** Position + size the menu so its labels sit directly under the button's value,
|
|
11996
|
+
* its right edge lands on the button's right edge (one shared border), and the
|
|
11997
|
+
* right-aligned check centers under the chevron. */
|
|
11998
|
+
alignMenuToValue() {
|
|
11999
|
+
const el = this.arEl?.nativeElement;
|
|
12000
|
+
const btn = el?.querySelector('.lt-ar-btn');
|
|
12001
|
+
const value = this.valueEl?.nativeElement?.getBoundingClientRect();
|
|
12002
|
+
const chevron = this.chevronEl?.nativeElement?.getBoundingClientRect();
|
|
12003
|
+
const container = el?.getBoundingClientRect();
|
|
12004
|
+
if (!btn || !value || !chevron || !container) {
|
|
12005
|
+
return;
|
|
12006
|
+
}
|
|
12007
|
+
const rem = parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;
|
|
12008
|
+
// left padding we back out of the value position so labels sit under it
|
|
12009
|
+
const itemPadLeft = 0.875 * rem;
|
|
12010
|
+
// half the check's box, so we can land its center rather than its edge
|
|
12011
|
+
const tickHalf = 0.375 * rem;
|
|
12012
|
+
const borderWidth = parseFloat(getComputedStyle(btn).borderRightWidth) || 1;
|
|
12013
|
+
this.menuLeft = Math.max(0, value.left - container.left - itemPadLeft);
|
|
12014
|
+
this.menuWidth = container.width - this.menuLeft;
|
|
12015
|
+
// the check is right-aligned, so its right padding is the gap from the menu's
|
|
12016
|
+
// right edge to the chevron center, less the border and half the check box
|
|
12017
|
+
const chevronCenter = (chevron.left + chevron.right) / 2;
|
|
12018
|
+
this.menuPadRight = Math.max(0, container.right - chevronCenter - borderWidth - tickHalf);
|
|
11827
12019
|
}
|
|
11828
12020
|
closeMenu() {
|
|
11829
12021
|
this.open = false;
|
|
@@ -11859,11 +12051,11 @@ class ListTableAutoRefreshComponent {
|
|
|
11859
12051
|
}
|
|
11860
12052
|
}
|
|
11861
12053
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListTableAutoRefreshComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
11862
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: ListTableAutoRefreshComponent, isStandalone: false, selector: "lib-list-table-auto-refresh", inputs: { seconds: "seconds", loading: "loading", intervals: "intervals" }, outputs: { refresh: "refresh", secondsChange: "secondsChange" }, ngImport: i0, template: "<div class=\"lt-ar\" [class.is-open]=\"open\">\n <button\n type=\"button\"\n class=\"lt-ar-btn\"\n [class.is-on]=\"enabled\"\n [class.is-open]=\"open\"\n (click)=\"toggleMenu($event)\"\n aria-haspopup=\"menu\"\n [attr.aria-expanded]=\"open\"\n [attr.aria-label]=\"'Auto-refresh: ' + valueLabel\"\n id=\"AutoRefreshButton\"\n >\n <svg class=\"lt-ar-icon\" viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M3 6.4A5.6 5.6 0 1 1 2.4 9\"/>\n <path fill=\"currentColor\" d=\"M1.4 3.1l.7 3.3 3.2-.9z\"/>\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M8 5.3V8.2l2 1.3\"/>\n </svg>\n <span class=\"lt-ar-prefix\">Auto-refresh:</span>\n <span class=\"lt-ar-value\">{{ valueLabel }}</span>\n <svg class=\"lt-ar-chevron\" viewBox=\"0 0 10 6\" width=\"9\" height=\"6\" aria-hidden=\"true\"><path fill=\"currentColor\" d=\"
|
|
12054
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: ListTableAutoRefreshComponent, isStandalone: false, selector: "lib-list-table-auto-refresh", inputs: { seconds: "seconds", loading: "loading", intervals: "intervals" }, outputs: { refresh: "refresh", secondsChange: "secondsChange" }, viewQueries: [{ propertyName: "arEl", first: true, predicate: ["arEl"], descendants: true }, { propertyName: "valueEl", first: true, predicate: ["valueEl"], descendants: true }, { propertyName: "chevronEl", first: true, predicate: ["chevronEl"], descendants: true }], ngImport: i0, template: "<div class=\"lt-ar\" #arEl [class.is-open]=\"open\">\n <button\n type=\"button\"\n class=\"lt-ar-btn\"\n [class.is-on]=\"enabled\"\n [class.is-open]=\"open\"\n (click)=\"toggleMenu($event)\"\n aria-haspopup=\"menu\"\n [attr.aria-expanded]=\"open\"\n [attr.aria-label]=\"'Auto-refresh: ' + valueLabel\"\n id=\"AutoRefreshButton\"\n >\n <svg class=\"lt-ar-icon\" viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M3 6.4A5.6 5.6 0 1 1 2.4 9\"/>\n <path fill=\"currentColor\" d=\"M1.4 3.1l.7 3.3 3.2-.9z\"/>\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M8 5.3V8.2l2 1.3\"/>\n </svg>\n <span class=\"lt-ar-prefix\">Auto-refresh:</span>\n <span class=\"lt-ar-value\" #valueEl>{{ valueLabel }}</span>\n <svg class=\"lt-ar-chevron\" #chevronEl viewBox=\"0 0 10 6\" width=\"9\" height=\"6\" aria-hidden=\"true\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M1 1.5 5 5 9 1.5\"/></svg>\n </button>\n\n @if (open) {\n <div class=\"lt-ar-menu\" [style.left.px]=\"menuLeft\" [style.width.px]=\"menuWidth\" [style.--lt-ar-pad-right]=\"menuPadRight + 'px'\" (clickOutside)=\"closeMenu()\" role=\"menu\">\n <button type=\"button\" class=\"lt-ar-item\" [class.is-selected]=\"!enabled\" (click)=\"select(0)\" role=\"menuitemradio\" [attr.aria-checked]=\"!enabled\">\n <span class=\"lt-ar-label\">Off</span>\n <span class=\"lt-ar-tick\" aria-hidden=\"true\">\n @if (!enabled) {\n <svg viewBox=\"0 0 12 12\" width=\"11\" height=\"11\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M2 6.3 4.6 9 10 3\"/></svg>\n }\n </span>\n </button>\n @for (interval of intervals; track interval.seconds) {\n <button type=\"button\" class=\"lt-ar-item\" [class.is-selected]=\"isSelected(interval.seconds)\" (click)=\"select(interval.seconds)\" role=\"menuitemradio\" [attr.aria-checked]=\"isSelected(interval.seconds)\">\n <span class=\"lt-ar-label\">{{ interval.label }}</span>\n <span class=\"lt-ar-tick\" aria-hidden=\"true\">\n @if (isSelected(interval.seconds)) {\n <svg viewBox=\"0 0 12 12\" width=\"11\" height=\"11\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M2 6.3 4.6 9 10 3\"/></svg>\n }\n </span>\n </button>\n }\n </div>\n }\n</div>\n", styles: [":host{display:inline-flex}.lt-ar{position:relative;display:inline-flex}.lt-ar-btn{display:inline-flex;align-items:center;gap:var(--lt-control-gap);height:var(--lt-toolbar-height);padding:0 var(--lt-control-padding-x);font-family:var(--lt-font);font-size:var(--lt-control-font-size);font-weight:var(--lt-control-font-weight);color:var(--lt-cell-text);background:var(--lt-control-bg);border:var(--lt-control-border-full);border-radius:var(--lt-radius);cursor:pointer;white-space:nowrap;transition:border-color .15s,background .15s,color .15s}.lt-ar-btn svg{display:block}.lt-ar-btn:hover,.lt-ar-btn.is-on{border-color:var(--lt-link);color:var(--lt-link)}.lt-ar-btn.is-on{background:color-mix(in srgb,var(--lt-link) 8%,var(--lt-control-bg))}.lt-ar-btn.is-open{border-color:var(--lt-link);color:var(--lt-link);border-bottom-right-radius:0}.lt-ar-value{font-weight:700}.lt-ar-chevron{opacity:.7}.lt-ar-menu{position:absolute;top:100%;left:0;z-index:1000;min-width:0;margin-top:calc(var(--lt-control-border-width) * -1);display:flex;flex-direction:column;padding:.25rem 0;background:var(--lt-control-bg);border:var(--lt-control-border-width) solid var(--lt-link);border-radius:0 0 var(--lt-radius) var(--lt-radius);box-shadow:var(--shadowLarge);animation:lt-ar-in .12s ease-out}@keyframes lt-ar-in{0%{opacity:0;transform:translateY(-.125rem)}to{opacity:1;transform:translateY(0)}}.lt-ar-item{display:flex;align-items:center;justify-content:space-between;gap:0;min-height:2rem;padding:0 var(--lt-ar-pad-right, .875rem) 0 .875rem;font-family:var(--lt-font);font-size:var(--lt-control-font-size);color:var(--lt-cell-text);background:transparent;border:none;cursor:pointer;text-align:left;transition:background .1s,color .1s}.lt-ar-item:hover{background:var(--lt-row-hover)}.lt-ar-item.is-selected{color:var(--lt-link);font-weight:700}.lt-ar-tick{display:inline-flex;flex:0 0 auto;justify-content:center;width:.75rem;color:var(--lt-link)}.lt-ar-tick svg{display:block}\n"], dependencies: [{ kind: "directive", type: i1$4.ClickOutsideDirective, selector: "[clickOutside]", inputs: ["clickOutsideEnabled", "attachOutsideOnClick", "delayClickOutsideInit", "emitOnBlur", "exclude", "excludeBeforeClick", "clickOutsideEvents"], outputs: ["clickOutside"] }] }); }
|
|
11863
12055
|
}
|
|
11864
12056
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListTableAutoRefreshComponent, decorators: [{
|
|
11865
12057
|
type: Component,
|
|
11866
|
-
args: [{ selector: 'lib-list-table-auto-refresh', standalone: false, template: "<div class=\"lt-ar\" [class.is-open]=\"open\">\n <button\n type=\"button\"\n class=\"lt-ar-btn\"\n [class.is-on]=\"enabled\"\n [class.is-open]=\"open\"\n (click)=\"toggleMenu($event)\"\n aria-haspopup=\"menu\"\n [attr.aria-expanded]=\"open\"\n [attr.aria-label]=\"'Auto-refresh: ' + valueLabel\"\n id=\"AutoRefreshButton\"\n >\n <svg class=\"lt-ar-icon\" viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M3 6.4A5.6 5.6 0 1 1 2.4 9\"/>\n <path fill=\"currentColor\" d=\"M1.4 3.1l.7 3.3 3.2-.9z\"/>\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M8 5.3V8.2l2 1.3\"/>\n </svg>\n <span class=\"lt-ar-prefix\">Auto-refresh:</span>\n <span class=\"lt-ar-value\">{{ valueLabel }}</span>\n <svg class=\"lt-ar-chevron\" viewBox=\"0 0 10 6\" width=\"9\" height=\"6\" aria-hidden=\"true\"><path fill=\"currentColor\" d=\"
|
|
12058
|
+
args: [{ selector: 'lib-list-table-auto-refresh', standalone: false, template: "<div class=\"lt-ar\" #arEl [class.is-open]=\"open\">\n <button\n type=\"button\"\n class=\"lt-ar-btn\"\n [class.is-on]=\"enabled\"\n [class.is-open]=\"open\"\n (click)=\"toggleMenu($event)\"\n aria-haspopup=\"menu\"\n [attr.aria-expanded]=\"open\"\n [attr.aria-label]=\"'Auto-refresh: ' + valueLabel\"\n id=\"AutoRefreshButton\"\n >\n <svg class=\"lt-ar-icon\" viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M3 6.4A5.6 5.6 0 1 1 2.4 9\"/>\n <path fill=\"currentColor\" d=\"M1.4 3.1l.7 3.3 3.2-.9z\"/>\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M8 5.3V8.2l2 1.3\"/>\n </svg>\n <span class=\"lt-ar-prefix\">Auto-refresh:</span>\n <span class=\"lt-ar-value\" #valueEl>{{ valueLabel }}</span>\n <svg class=\"lt-ar-chevron\" #chevronEl viewBox=\"0 0 10 6\" width=\"9\" height=\"6\" aria-hidden=\"true\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M1 1.5 5 5 9 1.5\"/></svg>\n </button>\n\n @if (open) {\n <div class=\"lt-ar-menu\" [style.left.px]=\"menuLeft\" [style.width.px]=\"menuWidth\" [style.--lt-ar-pad-right]=\"menuPadRight + 'px'\" (clickOutside)=\"closeMenu()\" role=\"menu\">\n <button type=\"button\" class=\"lt-ar-item\" [class.is-selected]=\"!enabled\" (click)=\"select(0)\" role=\"menuitemradio\" [attr.aria-checked]=\"!enabled\">\n <span class=\"lt-ar-label\">Off</span>\n <span class=\"lt-ar-tick\" aria-hidden=\"true\">\n @if (!enabled) {\n <svg viewBox=\"0 0 12 12\" width=\"11\" height=\"11\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M2 6.3 4.6 9 10 3\"/></svg>\n }\n </span>\n </button>\n @for (interval of intervals; track interval.seconds) {\n <button type=\"button\" class=\"lt-ar-item\" [class.is-selected]=\"isSelected(interval.seconds)\" (click)=\"select(interval.seconds)\" role=\"menuitemradio\" [attr.aria-checked]=\"isSelected(interval.seconds)\">\n <span class=\"lt-ar-label\">{{ interval.label }}</span>\n <span class=\"lt-ar-tick\" aria-hidden=\"true\">\n @if (isSelected(interval.seconds)) {\n <svg viewBox=\"0 0 12 12\" width=\"11\" height=\"11\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M2 6.3 4.6 9 10 3\"/></svg>\n }\n </span>\n </button>\n }\n </div>\n }\n</div>\n", styles: [":host{display:inline-flex}.lt-ar{position:relative;display:inline-flex}.lt-ar-btn{display:inline-flex;align-items:center;gap:var(--lt-control-gap);height:var(--lt-toolbar-height);padding:0 var(--lt-control-padding-x);font-family:var(--lt-font);font-size:var(--lt-control-font-size);font-weight:var(--lt-control-font-weight);color:var(--lt-cell-text);background:var(--lt-control-bg);border:var(--lt-control-border-full);border-radius:var(--lt-radius);cursor:pointer;white-space:nowrap;transition:border-color .15s,background .15s,color .15s}.lt-ar-btn svg{display:block}.lt-ar-btn:hover,.lt-ar-btn.is-on{border-color:var(--lt-link);color:var(--lt-link)}.lt-ar-btn.is-on{background:color-mix(in srgb,var(--lt-link) 8%,var(--lt-control-bg))}.lt-ar-btn.is-open{border-color:var(--lt-link);color:var(--lt-link);border-bottom-right-radius:0}.lt-ar-value{font-weight:700}.lt-ar-chevron{opacity:.7}.lt-ar-menu{position:absolute;top:100%;left:0;z-index:1000;min-width:0;margin-top:calc(var(--lt-control-border-width) * -1);display:flex;flex-direction:column;padding:.25rem 0;background:var(--lt-control-bg);border:var(--lt-control-border-width) solid var(--lt-link);border-radius:0 0 var(--lt-radius) var(--lt-radius);box-shadow:var(--shadowLarge);animation:lt-ar-in .12s ease-out}@keyframes lt-ar-in{0%{opacity:0;transform:translateY(-.125rem)}to{opacity:1;transform:translateY(0)}}.lt-ar-item{display:flex;align-items:center;justify-content:space-between;gap:0;min-height:2rem;padding:0 var(--lt-ar-pad-right, .875rem) 0 .875rem;font-family:var(--lt-font);font-size:var(--lt-control-font-size);color:var(--lt-cell-text);background:transparent;border:none;cursor:pointer;text-align:left;transition:background .1s,color .1s}.lt-ar-item:hover{background:var(--lt-row-hover)}.lt-ar-item.is-selected{color:var(--lt-link);font-weight:700}.lt-ar-tick{display:inline-flex;flex:0 0 auto;justify-content:center;width:.75rem;color:var(--lt-link)}.lt-ar-tick svg{display:block}\n"] }]
|
|
11867
12059
|
}], propDecorators: { seconds: [{
|
|
11868
12060
|
type: Input
|
|
11869
12061
|
}], loading: [{
|
|
@@ -11874,6 +12066,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
11874
12066
|
type: Output
|
|
11875
12067
|
}], secondsChange: [{
|
|
11876
12068
|
type: Output
|
|
12069
|
+
}], arEl: [{
|
|
12070
|
+
type: ViewChild,
|
|
12071
|
+
args: ['arEl']
|
|
12072
|
+
}], valueEl: [{
|
|
12073
|
+
type: ViewChild,
|
|
12074
|
+
args: ['valueEl']
|
|
12075
|
+
}], chevronEl: [{
|
|
12076
|
+
type: ViewChild,
|
|
12077
|
+
args: ['chevronEl']
|
|
11877
12078
|
}] } });
|
|
11878
12079
|
|
|
11879
12080
|
/**
|
|
@@ -11941,11 +12142,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
11941
12142
|
See the License for the specific language governing permissions and
|
|
11942
12143
|
limitations under the License.
|
|
11943
12144
|
*/
|
|
11944
|
-
/** Header cell for {@link ListTableComponent}: label
|
|
12145
|
+
/** Header cell for {@link ListTableComponent}: label and 3-state sort (asc/desc). */
|
|
11945
12146
|
class ListHeaderCellComponent {
|
|
11946
12147
|
constructor() {
|
|
11947
12148
|
this.sortChanged = new EventEmitter();
|
|
11948
|
-
this.hideColumn = new EventEmitter();
|
|
11949
12149
|
}
|
|
11950
12150
|
get enableSorting() {
|
|
11951
12151
|
return !!(this.column?.sortable || this.column?.enableSorting);
|
|
@@ -11959,24 +12159,18 @@ class ListHeaderCellComponent {
|
|
|
11959
12159
|
this.column.onSort?.(this.column.key, dir);
|
|
11960
12160
|
this.sortChanged.emit({ colId: this.column.key, dir });
|
|
11961
12161
|
}
|
|
11962
|
-
hide(event) {
|
|
11963
|
-
event.stopPropagation();
|
|
11964
|
-
this.hideColumn.emit(this.column);
|
|
11965
|
-
}
|
|
11966
12162
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListHeaderCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
11967
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: ListHeaderCellComponent, isStandalone: false, selector: "lib-list-header-cell", inputs: { column: "column", sortDir: "sortDir" }, outputs: { sortChanged: "sortChanged"
|
|
12163
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: ListHeaderCellComponent, isStandalone: false, selector: "lib-list-header-cell", inputs: { column: "column", sortDir: "sortDir" }, outputs: { sortChanged: "sortChanged" }, ngImport: i0, template: "<div\n (click)=\"sort()\"\n [ngClass]=\"{ 'nf-can-sort': enableSorting }\"\n class=\"lt-header-container\"\n id=\"TableHeaderContainer_{{ column.key }}\"\n>\n <div class=\"lt-header-label\">\n <span\n [title]=\"column.label || null\"\n class=\"lt-header-text\"\n [class.is-sorted]=\"sortDir === 'asc' || sortDir === 'desc'\"\n id=\"HeaderName_{{ column.key }}\"\n unselectable=\"on\"\n >{{ column.label }}</span>\n @if (enableSorting) {\n <span class=\"lt-sort\" [class.asc]=\"sortDir === 'asc'\" [class.desc]=\"sortDir === 'desc'\">\n <svg viewBox=\"0 0 8 14\" width=\"8\" height=\"13\" aria-hidden=\"true\">\n <path class=\"lt-sort-up\" d=\"M4 0 7.5 4.5H0.5z\"/>\n <path class=\"lt-sort-down\" d=\"M4 14 0.5 9.5H7.5z\"/>\n </svg>\n </span>\n }\n </div>\n</div>\n", styles: [":host{display:flex;width:100%;align-items:center}.lt-header-container{display:flex;align-items:center;width:100%;height:100%;cursor:default;gap:.25rem;position:relative}.lt-header-container.nf-can-sort{cursor:pointer}.lt-header-label{display:flex;align-items:center;flex:1 1 auto;min-width:0;gap:.25rem}.lt-header-text{color:var(--lt-header-text);font-family:var(--lt-font);font-size:.6875rem;font-weight:600;letter-spacing:.045em;text-transform:uppercase;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;transition:color .15s}.lt-header-text.is-sorted{color:var(--lt-header-sorted-text, var(--lt-icon-active));font-weight:var(--lt-header-sorted-weight, 700)}.lt-header-text-container{display:flex;align-items:center;min-width:0;flex:1 1 auto}.lt-header-text-container.show-input-filter{width:100%}.lt-sort{display:inline-flex;align-items:center;flex:0 0 auto;margin-left:auto;margin-right:.375rem}.lt-sort svg{display:block}.lt-sort .lt-sort-up,.lt-sort .lt-sort-down{fill:var(--lt-icon);opacity:.35;transition:opacity .15s,fill .15s}.lt-sort.asc .lt-sort-up,.lt-sort.desc .lt-sort-down{fill:var(--lt-icon-active);opacity:1}.nf-hidden{display:none}\n"], dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
|
|
11968
12164
|
}
|
|
11969
12165
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListHeaderCellComponent, decorators: [{
|
|
11970
12166
|
type: Component,
|
|
11971
|
-
args: [{ selector: 'lib-list-header-cell', standalone: false, template: "<div\n (click)=\"sort()\"\n [ngClass]=\"{ 'nf-can-sort': enableSorting }\"\n class=\"lt-header-container\"\n id=\"TableHeaderContainer_{{ column.key }}\"\n>\n
|
|
12167
|
+
args: [{ selector: 'lib-list-header-cell', standalone: false, template: "<div\n (click)=\"sort()\"\n [ngClass]=\"{ 'nf-can-sort': enableSorting }\"\n class=\"lt-header-container\"\n id=\"TableHeaderContainer_{{ column.key }}\"\n>\n <div class=\"lt-header-label\">\n <span\n [title]=\"column.label || null\"\n class=\"lt-header-text\"\n [class.is-sorted]=\"sortDir === 'asc' || sortDir === 'desc'\"\n id=\"HeaderName_{{ column.key }}\"\n unselectable=\"on\"\n >{{ column.label }}</span>\n @if (enableSorting) {\n <span class=\"lt-sort\" [class.asc]=\"sortDir === 'asc'\" [class.desc]=\"sortDir === 'desc'\">\n <svg viewBox=\"0 0 8 14\" width=\"8\" height=\"13\" aria-hidden=\"true\">\n <path class=\"lt-sort-up\" d=\"M4 0 7.5 4.5H0.5z\"/>\n <path class=\"lt-sort-down\" d=\"M4 14 0.5 9.5H7.5z\"/>\n </svg>\n </span>\n }\n </div>\n</div>\n", styles: [":host{display:flex;width:100%;align-items:center}.lt-header-container{display:flex;align-items:center;width:100%;height:100%;cursor:default;gap:.25rem;position:relative}.lt-header-container.nf-can-sort{cursor:pointer}.lt-header-label{display:flex;align-items:center;flex:1 1 auto;min-width:0;gap:.25rem}.lt-header-text{color:var(--lt-header-text);font-family:var(--lt-font);font-size:.6875rem;font-weight:600;letter-spacing:.045em;text-transform:uppercase;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;transition:color .15s}.lt-header-text.is-sorted{color:var(--lt-header-sorted-text, var(--lt-icon-active));font-weight:var(--lt-header-sorted-weight, 700)}.lt-header-text-container{display:flex;align-items:center;min-width:0;flex:1 1 auto}.lt-header-text-container.show-input-filter{width:100%}.lt-sort{display:inline-flex;align-items:center;flex:0 0 auto;margin-left:auto;margin-right:.375rem}.lt-sort svg{display:block}.lt-sort .lt-sort-up,.lt-sort .lt-sort-down{fill:var(--lt-icon);opacity:.35;transition:opacity .15s,fill .15s}.lt-sort.asc .lt-sort-up,.lt-sort.desc .lt-sort-down{fill:var(--lt-icon-active);opacity:1}.nf-hidden{display:none}\n"] }]
|
|
11972
12168
|
}], propDecorators: { column: [{
|
|
11973
12169
|
type: Input
|
|
11974
12170
|
}], sortDir: [{
|
|
11975
12171
|
type: Input
|
|
11976
12172
|
}], sortChanged: [{
|
|
11977
12173
|
type: Output
|
|
11978
|
-
}], hideColumn: [{
|
|
11979
|
-
type: Output
|
|
11980
12174
|
}] } });
|
|
11981
12175
|
|
|
11982
12176
|
/*
|
|
@@ -12018,6 +12212,8 @@ class ListFilterCellComponent {
|
|
|
12018
12212
|
this.selectedValues = [];
|
|
12019
12213
|
/** In-dropdown search text for the multi-select attribute combo. */
|
|
12020
12214
|
this.attrSearch = '';
|
|
12215
|
+
/** Match any selected attribute (or) vs every one (and); attribute filters only. */
|
|
12216
|
+
this.attrSemantic = 'AnyOf';
|
|
12021
12217
|
this.open = false;
|
|
12022
12218
|
this.menuLeft = 0;
|
|
12023
12219
|
this.menuTop = 0;
|
|
@@ -12217,10 +12413,19 @@ class ListFilterCellComponent {
|
|
|
12217
12413
|
value: [...this.selectedValues],
|
|
12218
12414
|
label: this.selectedValues.map((v) => this.labelForValue(v)).join(', '),
|
|
12219
12415
|
type: this.isAttributeMode ? 'ATTRIBUTE' : 'MULTISELECT',
|
|
12220
|
-
semantic: 'AnyOf',
|
|
12416
|
+
semantic: this.isAttributeMode ? this.attrSemantic : 'AnyOf',
|
|
12221
12417
|
};
|
|
12222
12418
|
this.filterService.updateFilter(filter);
|
|
12223
12419
|
}
|
|
12420
|
+
setSemantic(semantic) {
|
|
12421
|
+
if (this.attrSemantic === semantic) {
|
|
12422
|
+
return;
|
|
12423
|
+
}
|
|
12424
|
+
this.attrSemantic = semantic;
|
|
12425
|
+
if (this.selectedValues.length) {
|
|
12426
|
+
this.emitMulti();
|
|
12427
|
+
}
|
|
12428
|
+
}
|
|
12224
12429
|
// ------------------------------------------------------------------ date range
|
|
12225
12430
|
selectDatePreset(opt) {
|
|
12226
12431
|
this.selectedValue = opt.value;
|
|
@@ -12293,6 +12498,7 @@ class ListFilterCellComponent {
|
|
|
12293
12498
|
this.textValue = '';
|
|
12294
12499
|
this.dateRangeStart = null;
|
|
12295
12500
|
this.dateRangeEnd = null;
|
|
12501
|
+
this.attrSemantic = 'AnyOf';
|
|
12296
12502
|
this.removeThis();
|
|
12297
12503
|
}
|
|
12298
12504
|
removeThis() {
|
|
@@ -12319,6 +12525,9 @@ class ListFilterCellComponent {
|
|
|
12319
12525
|
}
|
|
12320
12526
|
else if (this.mode === 'multi') {
|
|
12321
12527
|
this.selectedValues = _.isArray(match.value) ? [...match.value] : [match.value];
|
|
12528
|
+
if (this.isAttributeMode) {
|
|
12529
|
+
this.attrSemantic = match.semantic === 'AllOf' ? 'AllOf' : 'AnyOf';
|
|
12530
|
+
}
|
|
12322
12531
|
}
|
|
12323
12532
|
else if (this.mode === 'daterange') {
|
|
12324
12533
|
// keep the locally chosen preset label; match.value is the raw [start,end] range
|
|
@@ -12328,11 +12537,11 @@ class ListFilterCellComponent {
|
|
|
12328
12537
|
}
|
|
12329
12538
|
}
|
|
12330
12539
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListFilterCellComponent, deps: [{ token: DataTableFilterService }, { token: ListTableService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
12331
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: ListFilterCellComponent, isStandalone: false, selector: "lib-list-filter-cell", inputs: { column: "column" }, viewQueries: [{ propertyName: "trigger", first: true, predicate: ["trigger"], descendants: true }, { propertyName: "rangePicker", first: true, predicate: ["rangePicker"], descendants: true }], ngImport: i0, template: "@switch (mode) {\n @case ('text') {\n <div class=\"fc-text\">\n <input\n class=\"fc-input\"\n type=\"text\"\n [placeholder]=\"column.filterPlaceholder || 'Filter'\"\n [(ngModel)]=\"textValue\"\n (keyup)=\"onTextInput()\"\n />\n @if (textValue) {\n <span class=\"fc-clear\" (click)=\"clear($event)\" title=\"Clear\" aria-label=\"Clear filter\">×</span>\n }\n </div>\n }\n @default {\n <button\n #trigger\n type=\"button\"\n class=\"fc-pill\"\n [class.has-value]=\"hasValue\"\n [class.is-open]=\"open\"\n (click)=\"toggleMenu($event)\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"open\"\n >\n <span class=\"fc-pill-field\">{{ column.label }}</span>\n @if (hasValue) {\n <span class=\"fc-pill-value\" [title]=\"valueLabel\">{{ valueLabel }}</span>\n <span class=\"fc-clear\" (click)=\"clear($event)\" title=\"Clear\" aria-label=\"Clear filter\">×</span>\n } @else {\n <span class=\"fc-caret\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 10 6\" width=\"9\" height=\"6\"><path fill=\"currentColor\" d=\"M0 0h10L5 6z\"/></svg>\n </span>\n }\n </button>\n\n @if (open) {\n <div\n class=\"fc-menu\"\n (clickOutside)=\"closeMenu()\"\n [ngStyle]=\"{ left: menuLeft + 'px', top: menuTop + 'px', 'min-width.px': menuWidth }\"\n >\n @if (mode === 'multi') {\n <div class=\"fc-search\">\n <svg class=\"fc-search-icon\" viewBox=\"0 0 16 16\" width=\"13\" height=\"13\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"4.3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"/>\n <line x1=\"10.4\" y1=\"10.4\" x2=\"14.6\" y2=\"14.6\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n <input\n class=\"fc-search-input\"\n type=\"text\"\n [(ngModel)]=\"attrSearch\"\n [placeholder]=\"isAttributeMode ? 'Search attributes' : 'Search'\"\n (click)=\"$event.stopPropagation()\"\n autocomplete=\"off\"\n />\n </div>\n @if (!filteredOptions.length) {\n <div class=\"fc-empty\">{{ options.length ? 'No matches' : (isAttributeMode ? 'No attributes available' : 'No options available') }}</div>\n }\n <div class=\"fc-opt-list\">\n @for (opt of filteredOptions; track opt.value) {\n <button type=\"button\" class=\"fc-opt\" [class.selected]=\"isOptionSelected(opt)\" (click)=\"toggleOption(opt)\">\n <span class=\"fc-check\" aria-hidden=\"true\">\n @if (isOptionSelected(opt)) {\n <svg viewBox=\"0 0 12 12\" width=\"10\" height=\"10\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M2 6.3 4.6 9 10 3\"/></svg>\n }\n </span>\n @if (isAttributeMode) {\n <span class=\"fc-attr\" [class.at]=\"isNamedOption(opt)\">{{ optionLabel(opt) }}</span>\n } @else if (opt.chipClass) {\n <span [ngClass]=\"opt.chipClass\">{{ opt.label }}</span>\n } @else {\n <span class=\"fc-opt-label\">{{ optionLabel(opt) }}</span>\n }\n </button>\n }\n </div>\n } @else if (mode === 'daterange') {\n @for (opt of options; track opt.value) {\n <button type=\"button\" class=\"fc-opt\" [class.selected]=\"isOptionSelected(opt)\" (click)=\"selectDatePreset(opt)\">\n <span class=\"fc-opt-label\">{{ opt.label }}</span>\n </button>\n }\n <div class=\"fc-divider\"></div>\n <button type=\"button\" class=\"fc-opt\" [class.selected]=\"selectedValue === 'custom'\" (click)=\"openCustomRange($event)\">\n <span class=\"fc-opt-label\">Custom range\u2026</span>\n </button>\n } @else {\n @for (opt of options; track opt.value) {\n <button type=\"button\" class=\"fc-opt\" [class.selected]=\"isOptionSelected(opt)\" (click)=\"selectOption(opt)\">\n @if (opt.chipClass) {\n <span [ngClass]=\"opt.chipClass\">{{ opt.label }}</span>\n } @else {\n <span class=\"fc-opt-label\">{{ opt.label }}</span>\n }\n </button>\n }\n }\n </div>\n }\n }\n}\n\n@if (mode === 'daterange') {\n <!-- hidden Material range input; the calendar is opened from the \"Custom range\u2026\" option -->\n <mat-date-range-input class=\"fc-hidden-range\" [rangePicker]=\"rangePicker\">\n <input matStartDate [(ngModel)]=\"dateRangeStart\" (dateChange)=\"onRangeStartChanged($event.value)\" tabindex=\"-1\" aria-hidden=\"true\" />\n <input matEndDate [(ngModel)]=\"dateRangeEnd\" (dateChange)=\"onRangeEndChanged($event.value)\" tabindex=\"-1\" aria-hidden=\"true\" />\n </mat-date-range-input>\n <mat-date-range-picker #rangePicker xPosition=\"start\" yPosition=\"below\"></mat-date-range-picker>\n}\n", styles: [":host{display:inline-flex;position:relative}.fc-hidden-range{position:absolute;left:0;top:100%;width:1px;height:1px;opacity:0;pointer-events:none;overflow:hidden}.fc-divider{height:1px;margin:.25rem;background:var(--lt-border)}.fc-text{position:relative;display:flex;align-items:center}.fc-input{width:100%;height:1.875rem;padding:0 1.5rem 0 .5rem;font-family:var(--lt-font);font-size:.75rem;color:var(--lt-cell-text);background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);outline:none}.fc-input::placeholder{color:var(--placeholder)}.fc-input:focus{border-color:var(--lt-link)}.fc-pill{display:inline-flex;align-items:center;gap:.375rem;height:var(--lt-toolbar-height);max-width:14rem;padding:0 .75rem;font-family:var(--lt-font);font-size:.8125rem;font-weight:600;color:var(--lt-cell-text);background:var(--lt-control-bg);border:1px solid var(--lt-control-border, var(--lt-border));border-radius:var(--lt-radius);cursor:pointer;white-space:nowrap;transition:border-color .15s,background .15s,color .15s}.fc-pill:hover,.fc-pill.is-open{border-color:var(--lt-link)}.fc-pill.has-value{border-color:var(--lt-link);background:color-mix(in srgb,var(--lt-link) 8%,var(--lt-control-bg))}.fc-pill-field{color:var(--lt-cell-text)}.fc-pill.has-value .fc-pill-field{color:var(--groupText)}.fc-pill.has-value .fc-pill-field:after{content:\":\"}.fc-pill-value{color:var(--lt-link);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fc-caret{flex:0 0 auto;display:inline-flex;color:var(--lt-icon)}.fc-clear{flex:0 0 auto;font-size:1rem;line-height:1;color:var(--lt-icon);cursor:pointer}.fc-clear:hover{color:var(--lt-icon-active)}.fc-text .fc-clear{position:absolute;right:.5rem}.fc-menu{position:fixed;z-index:1000;max-height:18rem;overflow-y:auto;padding:.25rem;background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);box-shadow:var(--shadowLarge);animation:fc-in .1s ease-out}@keyframes fc-in{0%{opacity:0;transform:translateY(-.25rem)}to{opacity:1;transform:translateY(0)}}.fc-opt{display:flex;align-items:center;gap:.5rem;width:100%;padding:.4375rem .5rem;font-family:var(--lt-font);font-size:.8125rem;color:var(--lt-cell-text);background:transparent;border:none;border-radius:var(--lt-radius);cursor:pointer;text-align:left}.fc-opt:hover{background:var(--lt-row-hover)}.fc-opt.selected{color:var(--lt-link);font-weight:600}.fc-opt-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fc-check{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:1rem;height:1rem;box-sizing:border-box;border:.09375rem solid var(--lt-border);border-radius:.25rem;color:var(--lt-control-bg);background:var(--lt-control-bg)}.fc-opt.selected .fc-check{background:var(--lt-link);border-color:var(--lt-link)}.fc-empty{padding:.5rem;font-size:.75rem;color:var(--groupText)}.fc-search{position:sticky;top:0;z-index:1;display:flex;align-items:center;gap:.375rem;padding:.125rem .25rem .375rem;background:var(--lt-control-bg)}.fc-search-icon{flex:0 0 auto;margin-left:.25rem;color:var(--lt-icon)}.fc-search-input{flex:1 1 auto;min-width:0;height:1.75rem;padding:0 .5rem;font-family:var(--lt-font);font-size:.75rem;color:var(--lt-cell-text);background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);outline:none}.fc-search-input::placeholder{color:var(--placeholder)}.fc-search-input:focus{border-color:var(--lt-link)}.fc-opt-list{display:flex;flex-direction:column}.fc-attr{display:inline-flex;align-items:center;padding:.0625rem .375rem;font-size:.75rem;font-weight:600;line-height:1.4;border-radius:.25rem;color:var(--lt-link);background:color-mix(in srgb,var(--lt-link) 12%,transparent);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fc-attr.at{color:var(--secondary);background:color-mix(in srgb,var(--secondary) 14%,transparent)}.fc-opt.selected .fc-attr{color:var(--lt-link)}.fc-opt.selected .fc-attr.at{color:var(--secondary)}\n"], dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i6.MatDateRangeInput, selector: "mat-date-range-input", inputs: ["rangePicker", "required", "dateFilter", "min", "max", "disabled", "separator", "comparisonStart", "comparisonEnd"], exportAs: ["matDateRangeInput"] }, { kind: "directive", type: i6.MatStartDate, selector: "input[matStartDate]", outputs: ["dateChange", "dateInput"] }, { kind: "directive", type: i6.MatEndDate, selector: "input[matEndDate]", outputs: ["dateChange", "dateInput"] }, { kind: "component", type: i6.MatDateRangePicker, selector: "mat-date-range-picker", exportAs: ["matDateRangePicker"] }, { kind: "directive", type: i1$4.ClickOutsideDirective, selector: "[clickOutside]", inputs: ["clickOutsideEnabled", "attachOutsideOnClick", "delayClickOutsideInit", "emitOnBlur", "exclude", "excludeBeforeClick", "clickOutsideEvents"], outputs: ["clickOutside"] }] }); }
|
|
12540
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: ListFilterCellComponent, isStandalone: false, selector: "lib-list-filter-cell", inputs: { column: "column" }, viewQueries: [{ propertyName: "trigger", first: true, predicate: ["trigger"], descendants: true }, { propertyName: "rangePicker", first: true, predicate: ["rangePicker"], descendants: true }], ngImport: i0, template: "@switch (mode) {\n @case ('text') {\n <div class=\"fc-text\">\n <input\n class=\"fc-input\"\n type=\"text\"\n [placeholder]=\"column.filterPlaceholder || 'Filter'\"\n [(ngModel)]=\"textValue\"\n (keyup)=\"onTextInput()\"\n />\n @if (textValue) {\n <span class=\"fc-clear\" (click)=\"clear($event)\" title=\"Clear\" aria-label=\"Clear filter\">×</span>\n }\n </div>\n }\n @default {\n <button\n #trigger\n type=\"button\"\n class=\"fc-pill\"\n [class.has-value]=\"hasValue\"\n [class.is-open]=\"open\"\n (click)=\"toggleMenu($event)\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"open\"\n >\n <span class=\"fc-pill-field\">{{ column.label }}</span>\n @if (hasValue) {\n <span class=\"fc-pill-value\" [title]=\"valueLabel\">{{ valueLabel }}</span>\n <span class=\"fc-clear\" (click)=\"clear($event)\" title=\"Clear\" aria-label=\"Clear filter\">×</span>\n } @else {\n <span class=\"fc-caret\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 10 6\" width=\"9\" height=\"6\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M1 1.5 5 5 9 1.5\"/></svg>\n </span>\n }\n </button>\n\n @if (open) {\n <div\n class=\"fc-menu\"\n (clickOutside)=\"closeMenu()\"\n [ngStyle]=\"{ left: menuLeft + 'px', top: menuTop + 'px', 'min-width.px': menuWidth }\"\n >\n @if (mode === 'multi') {\n <div class=\"fc-search\">\n <svg class=\"fc-search-icon\" viewBox=\"0 0 16 16\" width=\"13\" height=\"13\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"4.3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"/>\n <line x1=\"10.4\" y1=\"10.4\" x2=\"14.6\" y2=\"14.6\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n <input\n class=\"fc-search-input\"\n type=\"text\"\n [(ngModel)]=\"attrSearch\"\n [placeholder]=\"isAttributeMode ? 'Search attributes' : 'Search'\"\n (click)=\"$event.stopPropagation()\"\n autocomplete=\"off\"\n />\n </div>\n @if (isAttributeMode) {\n <div class=\"fc-semantic\" role=\"group\" aria-label=\"Match\" (click)=\"$event.stopPropagation()\">\n <button type=\"button\" class=\"fc-semantic-opt\" [class.active]=\"attrSemantic === 'AnyOf'\" (click)=\"setSemantic('AnyOf')\">Any of</button>\n <button type=\"button\" class=\"fc-semantic-opt\" [class.active]=\"attrSemantic === 'AllOf'\" (click)=\"setSemantic('AllOf')\">All of</button>\n </div>\n }\n @if (!filteredOptions.length) {\n <div class=\"fc-empty\">{{ options.length ? 'No matches' : (isAttributeMode ? 'No attributes available' : 'No options available') }}</div>\n }\n <div class=\"fc-opt-list\">\n @for (opt of filteredOptions; track opt.value) {\n <button type=\"button\" class=\"fc-opt\" [class.selected]=\"isOptionSelected(opt)\" (click)=\"toggleOption(opt)\">\n <span class=\"fc-check\" aria-hidden=\"true\">\n @if (isOptionSelected(opt)) {\n <svg viewBox=\"0 0 12 12\" width=\"10\" height=\"10\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M2 6.3 4.6 9 10 3\"/></svg>\n }\n </span>\n @if (isAttributeMode) {\n <span class=\"fc-attr\" [class.at]=\"isNamedOption(opt)\">{{ optionLabel(opt) }}</span>\n } @else if (opt.chipClass) {\n <span [ngClass]=\"opt.chipClass\">{{ opt.label }}</span>\n } @else {\n <span class=\"fc-opt-label\">{{ optionLabel(opt) }}</span>\n }\n </button>\n }\n </div>\n } @else if (mode === 'daterange') {\n @for (opt of options; track opt.value) {\n <button type=\"button\" class=\"fc-opt\" [class.selected]=\"isOptionSelected(opt)\" (click)=\"selectDatePreset(opt)\">\n <span class=\"fc-opt-label\">{{ opt.label }}</span>\n </button>\n }\n <div class=\"fc-divider\"></div>\n <button type=\"button\" class=\"fc-opt\" [class.selected]=\"selectedValue === 'custom'\" (click)=\"openCustomRange($event)\">\n <span class=\"fc-opt-label\">Custom range\u2026</span>\n </button>\n } @else {\n @for (opt of options; track opt.value) {\n <button type=\"button\" class=\"fc-opt\" [class.selected]=\"isOptionSelected(opt)\" (click)=\"selectOption(opt)\">\n @if (opt.chipClass) {\n <span [ngClass]=\"opt.chipClass\">{{ opt.label }}</span>\n } @else {\n <span class=\"fc-opt-label\">{{ opt.label }}</span>\n }\n </button>\n }\n }\n </div>\n }\n }\n}\n\n@if (mode === 'daterange') {\n <!-- hidden Material range input; the calendar is opened from the \"Custom range\u2026\" option -->\n <mat-date-range-input class=\"fc-hidden-range\" [rangePicker]=\"rangePicker\">\n <input matStartDate [(ngModel)]=\"dateRangeStart\" (dateChange)=\"onRangeStartChanged($event.value)\" tabindex=\"-1\" aria-hidden=\"true\" />\n <input matEndDate [(ngModel)]=\"dateRangeEnd\" (dateChange)=\"onRangeEndChanged($event.value)\" tabindex=\"-1\" aria-hidden=\"true\" />\n </mat-date-range-input>\n <mat-date-range-picker #rangePicker xPosition=\"start\" yPosition=\"below\"></mat-date-range-picker>\n}\n", styles: [":host{display:inline-flex;position:relative}.fc-hidden-range{position:absolute;left:0;top:100%;width:1px;height:1px;opacity:0;pointer-events:none;overflow:hidden}.fc-divider{height:1px;margin:.25rem;background:var(--lt-border)}.fc-text{position:relative;display:flex;align-items:center}.fc-input{width:100%;height:1.875rem;padding:0 1.5rem 0 .5rem;font-family:var(--lt-font);font-size:.75rem;color:var(--lt-cell-text);background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);outline:none}.fc-input::placeholder{color:var(--placeholder)}.fc-input:focus{border-color:var(--lt-link)}.fc-pill{display:inline-flex;align-items:center;gap:.375rem;height:var(--lt-toolbar-height);max-width:14rem;padding:0 var(--lt-control-padding-x);font-family:var(--lt-font);font-size:.8125rem;font-weight:var(--lt-control-font-weight);color:var(--lt-cell-text);background:var(--lt-control-bg);border:var(--lt-control-border-full);border-radius:var(--lt-radius);cursor:pointer;white-space:nowrap;transition:border-color .15s,background .15s,color .15s}.fc-pill:hover,.fc-pill.is-open{border-color:var(--lt-link)}.fc-pill.has-value{border-color:var(--lt-link);background:color-mix(in srgb,var(--lt-link) 8%,var(--lt-control-bg))}.fc-pill-field{color:var(--lt-cell-text)}.fc-pill.has-value .fc-pill-field{color:var(--groupText)}.fc-pill.has-value .fc-pill-field:after{content:\":\"}.fc-pill-value{color:var(--lt-link);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fc-caret{flex:0 0 auto;display:inline-flex;color:var(--lt-icon)}.fc-clear{flex:0 0 auto;font-size:1rem;line-height:1;color:var(--lt-icon);cursor:pointer}.fc-clear:hover{color:var(--lt-icon-active)}.fc-text .fc-clear{position:absolute;right:.5rem}.fc-menu{position:fixed;z-index:1000;max-height:20rem;overflow-y:auto;padding:.375rem;background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);box-shadow:var(--shadowLarge);animation:fc-in .1s ease-out}@keyframes fc-in{0%{opacity:0;transform:translateY(-.25rem)}to{opacity:1;transform:translateY(0)}}.fc-semantic{display:flex;gap:.1875rem;margin:.125rem 0 .4375rem;padding:.1875rem;background:color-mix(in srgb,var(--lt-border) 30%,var(--lt-control-bg));border:1px solid var(--lt-border);border-radius:var(--lt-radius)}.fc-semantic-opt{flex:1 1 0;padding:.4375rem .5rem;font-family:var(--lt-font);font-size:.8125rem;font-weight:500;color:var(--lt-cell-text);background:transparent;border:none;border-radius:calc(var(--lt-radius) - .0625rem);cursor:pointer}.fc-semantic-opt:hover:not(.active){color:var(--lt-link)}.fc-semantic-opt.active{color:var(--lt-link);background:var(--lt-control-bg);box-shadow:0 1px 2px color-mix(in srgb,var(--lt-cell-text) 14%,transparent)}.fc-opt{display:flex;align-items:center;gap:.5625rem;width:100%;padding:.5rem;font-family:var(--lt-font);font-size:.875rem;color:var(--lt-cell-text);background:transparent;border:none;border-radius:var(--lt-radius);cursor:pointer;text-align:left}.fc-opt:hover{background:var(--lt-row-hover)}.fc-opt.selected{color:var(--lt-link);font-weight:600}.fc-opt-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fc-check{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:1.125rem;height:1.125rem;box-sizing:border-box;border:.09375rem solid var(--lt-border);border-radius:.25rem;color:var(--lt-control-bg);background:var(--lt-control-bg)}.fc-opt.selected .fc-check{background:var(--lt-link);border-color:var(--lt-link)}.fc-empty{padding:.5rem;font-size:.75rem;color:var(--groupText)}.fc-search{position:sticky;top:0;z-index:1;padding:.125rem 0 .4375rem;background:var(--lt-control-bg)}.fc-search-icon{position:absolute;left:.625rem;top:.125rem;display:flex;align-items:center;height:2.125rem;color:var(--lt-icon);pointer-events:none}.fc-search-input{width:100%;box-sizing:border-box;height:2.125rem;padding:0 .625rem 0 2rem;font-family:var(--lt-font);font-size:.8125rem;color:var(--lt-cell-text);background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);outline:none}.fc-search-input::placeholder{color:var(--placeholder)}.fc-search-input:focus{border-color:var(--lt-link)}.fc-opt-list{display:flex;flex-direction:column}.fc-attr{display:inline-flex;align-items:center;padding:.1875rem .5rem;font-size:.8125rem;font-weight:600;line-height:1.4;border-radius:.25rem;color:var(--lt-link);background:color-mix(in srgb,var(--lt-link) 12%,transparent);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fc-attr.at{color:var(--secondary);background:color-mix(in srgb,var(--secondary) 14%,transparent)}.fc-opt.selected .fc-attr{color:var(--lt-link)}.fc-opt.selected .fc-attr.at{color:var(--secondary)}\n"], dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i6.MatDateRangeInput, selector: "mat-date-range-input", inputs: ["rangePicker", "required", "dateFilter", "min", "max", "disabled", "separator", "comparisonStart", "comparisonEnd"], exportAs: ["matDateRangeInput"] }, { kind: "directive", type: i6.MatStartDate, selector: "input[matStartDate]", outputs: ["dateChange", "dateInput"] }, { kind: "directive", type: i6.MatEndDate, selector: "input[matEndDate]", outputs: ["dateChange", "dateInput"] }, { kind: "component", type: i6.MatDateRangePicker, selector: "mat-date-range-picker", exportAs: ["matDateRangePicker"] }, { kind: "directive", type: i1$4.ClickOutsideDirective, selector: "[clickOutside]", inputs: ["clickOutsideEnabled", "attachOutsideOnClick", "delayClickOutsideInit", "emitOnBlur", "exclude", "excludeBeforeClick", "clickOutsideEvents"], outputs: ["clickOutside"] }] }); }
|
|
12332
12541
|
}
|
|
12333
12542
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListFilterCellComponent, decorators: [{
|
|
12334
12543
|
type: Component,
|
|
12335
|
-
args: [{ selector: 'lib-list-filter-cell', standalone: false, template: "@switch (mode) {\n @case ('text') {\n <div class=\"fc-text\">\n <input\n class=\"fc-input\"\n type=\"text\"\n [placeholder]=\"column.filterPlaceholder || 'Filter'\"\n [(ngModel)]=\"textValue\"\n (keyup)=\"onTextInput()\"\n />\n @if (textValue) {\n <span class=\"fc-clear\" (click)=\"clear($event)\" title=\"Clear\" aria-label=\"Clear filter\">×</span>\n }\n </div>\n }\n @default {\n <button\n #trigger\n type=\"button\"\n class=\"fc-pill\"\n [class.has-value]=\"hasValue\"\n [class.is-open]=\"open\"\n (click)=\"toggleMenu($event)\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"open\"\n >\n <span class=\"fc-pill-field\">{{ column.label }}</span>\n @if (hasValue) {\n <span class=\"fc-pill-value\" [title]=\"valueLabel\">{{ valueLabel }}</span>\n <span class=\"fc-clear\" (click)=\"clear($event)\" title=\"Clear\" aria-label=\"Clear filter\">×</span>\n } @else {\n <span class=\"fc-caret\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 10 6\" width=\"9\" height=\"6\"><path fill=\"currentColor\" d=\"M0 0h10L5 6z\"/></svg>\n </span>\n }\n </button>\n\n @if (open) {\n <div\n class=\"fc-menu\"\n (clickOutside)=\"closeMenu()\"\n [ngStyle]=\"{ left: menuLeft + 'px', top: menuTop + 'px', 'min-width.px': menuWidth }\"\n >\n @if (mode === 'multi') {\n <div class=\"fc-search\">\n <svg class=\"fc-search-icon\" viewBox=\"0 0 16 16\" width=\"13\" height=\"13\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"4.3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"/>\n <line x1=\"10.4\" y1=\"10.4\" x2=\"14.6\" y2=\"14.6\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n <input\n class=\"fc-search-input\"\n type=\"text\"\n [(ngModel)]=\"attrSearch\"\n [placeholder]=\"isAttributeMode ? 'Search attributes' : 'Search'\"\n (click)=\"$event.stopPropagation()\"\n autocomplete=\"off\"\n />\n </div>\n @if (!filteredOptions.length) {\n <div class=\"fc-empty\">{{ options.length ? 'No matches' : (isAttributeMode ? 'No attributes available' : 'No options available') }}</div>\n }\n <div class=\"fc-opt-list\">\n @for (opt of filteredOptions; track opt.value) {\n <button type=\"button\" class=\"fc-opt\" [class.selected]=\"isOptionSelected(opt)\" (click)=\"toggleOption(opt)\">\n <span class=\"fc-check\" aria-hidden=\"true\">\n @if (isOptionSelected(opt)) {\n <svg viewBox=\"0 0 12 12\" width=\"10\" height=\"10\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M2 6.3 4.6 9 10 3\"/></svg>\n }\n </span>\n @if (isAttributeMode) {\n <span class=\"fc-attr\" [class.at]=\"isNamedOption(opt)\">{{ optionLabel(opt) }}</span>\n } @else if (opt.chipClass) {\n <span [ngClass]=\"opt.chipClass\">{{ opt.label }}</span>\n } @else {\n <span class=\"fc-opt-label\">{{ optionLabel(opt) }}</span>\n }\n </button>\n }\n </div>\n } @else if (mode === 'daterange') {\n @for (opt of options; track opt.value) {\n <button type=\"button\" class=\"fc-opt\" [class.selected]=\"isOptionSelected(opt)\" (click)=\"selectDatePreset(opt)\">\n <span class=\"fc-opt-label\">{{ opt.label }}</span>\n </button>\n }\n <div class=\"fc-divider\"></div>\n <button type=\"button\" class=\"fc-opt\" [class.selected]=\"selectedValue === 'custom'\" (click)=\"openCustomRange($event)\">\n <span class=\"fc-opt-label\">Custom range\u2026</span>\n </button>\n } @else {\n @for (opt of options; track opt.value) {\n <button type=\"button\" class=\"fc-opt\" [class.selected]=\"isOptionSelected(opt)\" (click)=\"selectOption(opt)\">\n @if (opt.chipClass) {\n <span [ngClass]=\"opt.chipClass\">{{ opt.label }}</span>\n } @else {\n <span class=\"fc-opt-label\">{{ opt.label }}</span>\n }\n </button>\n }\n }\n </div>\n }\n }\n}\n\n@if (mode === 'daterange') {\n <!-- hidden Material range input; the calendar is opened from the \"Custom range\u2026\" option -->\n <mat-date-range-input class=\"fc-hidden-range\" [rangePicker]=\"rangePicker\">\n <input matStartDate [(ngModel)]=\"dateRangeStart\" (dateChange)=\"onRangeStartChanged($event.value)\" tabindex=\"-1\" aria-hidden=\"true\" />\n <input matEndDate [(ngModel)]=\"dateRangeEnd\" (dateChange)=\"onRangeEndChanged($event.value)\" tabindex=\"-1\" aria-hidden=\"true\" />\n </mat-date-range-input>\n <mat-date-range-picker #rangePicker xPosition=\"start\" yPosition=\"below\"></mat-date-range-picker>\n}\n", styles: [":host{display:inline-flex;position:relative}.fc-hidden-range{position:absolute;left:0;top:100%;width:1px;height:1px;opacity:0;pointer-events:none;overflow:hidden}.fc-divider{height:1px;margin:.25rem;background:var(--lt-border)}.fc-text{position:relative;display:flex;align-items:center}.fc-input{width:100%;height:1.875rem;padding:0 1.5rem 0 .5rem;font-family:var(--lt-font);font-size:.75rem;color:var(--lt-cell-text);background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);outline:none}.fc-input::placeholder{color:var(--placeholder)}.fc-input:focus{border-color:var(--lt-link)}.fc-pill{display:inline-flex;align-items:center;gap:.375rem;height:var(--lt-toolbar-height);max-width:14rem;padding:0 .75rem;font-family:var(--lt-font);font-size:.8125rem;font-weight:600;color:var(--lt-cell-text);background:var(--lt-control-bg);border:1px solid var(--lt-control-border, var(--lt-border));border-radius:var(--lt-radius);cursor:pointer;white-space:nowrap;transition:border-color .15s,background .15s,color .15s}.fc-pill:hover,.fc-pill.is-open{border-color:var(--lt-link)}.fc-pill.has-value{border-color:var(--lt-link);background:color-mix(in srgb,var(--lt-link) 8%,var(--lt-control-bg))}.fc-pill-field{color:var(--lt-cell-text)}.fc-pill.has-value .fc-pill-field{color:var(--groupText)}.fc-pill.has-value .fc-pill-field:after{content:\":\"}.fc-pill-value{color:var(--lt-link);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fc-caret{flex:0 0 auto;display:inline-flex;color:var(--lt-icon)}.fc-clear{flex:0 0 auto;font-size:1rem;line-height:1;color:var(--lt-icon);cursor:pointer}.fc-clear:hover{color:var(--lt-icon-active)}.fc-text .fc-clear{position:absolute;right:.5rem}.fc-menu{position:fixed;z-index:1000;max-height:18rem;overflow-y:auto;padding:.25rem;background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);box-shadow:var(--shadowLarge);animation:fc-in .1s ease-out}@keyframes fc-in{0%{opacity:0;transform:translateY(-.25rem)}to{opacity:1;transform:translateY(0)}}.fc-opt{display:flex;align-items:center;gap:.5rem;width:100%;padding:.4375rem .5rem;font-family:var(--lt-font);font-size:.8125rem;color:var(--lt-cell-text);background:transparent;border:none;border-radius:var(--lt-radius);cursor:pointer;text-align:left}.fc-opt:hover{background:var(--lt-row-hover)}.fc-opt.selected{color:var(--lt-link);font-weight:600}.fc-opt-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fc-check{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:1rem;height:1rem;box-sizing:border-box;border:.09375rem solid var(--lt-border);border-radius:.25rem;color:var(--lt-control-bg);background:var(--lt-control-bg)}.fc-opt.selected .fc-check{background:var(--lt-link);border-color:var(--lt-link)}.fc-empty{padding:.5rem;font-size:.75rem;color:var(--groupText)}.fc-search{position:sticky;top:0;z-index:1;display:flex;align-items:center;gap:.375rem;padding:.125rem .25rem .375rem;background:var(--lt-control-bg)}.fc-search-icon{flex:0 0 auto;margin-left:.25rem;color:var(--lt-icon)}.fc-search-input{flex:1 1 auto;min-width:0;height:1.75rem;padding:0 .5rem;font-family:var(--lt-font);font-size:.75rem;color:var(--lt-cell-text);background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);outline:none}.fc-search-input::placeholder{color:var(--placeholder)}.fc-search-input:focus{border-color:var(--lt-link)}.fc-opt-list{display:flex;flex-direction:column}.fc-attr{display:inline-flex;align-items:center;padding:.0625rem .375rem;font-size:.75rem;font-weight:600;line-height:1.4;border-radius:.25rem;color:var(--lt-link);background:color-mix(in srgb,var(--lt-link) 12%,transparent);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fc-attr.at{color:var(--secondary);background:color-mix(in srgb,var(--secondary) 14%,transparent)}.fc-opt.selected .fc-attr{color:var(--lt-link)}.fc-opt.selected .fc-attr.at{color:var(--secondary)}\n"] }]
|
|
12544
|
+
args: [{ selector: 'lib-list-filter-cell', standalone: false, template: "@switch (mode) {\n @case ('text') {\n <div class=\"fc-text\">\n <input\n class=\"fc-input\"\n type=\"text\"\n [placeholder]=\"column.filterPlaceholder || 'Filter'\"\n [(ngModel)]=\"textValue\"\n (keyup)=\"onTextInput()\"\n />\n @if (textValue) {\n <span class=\"fc-clear\" (click)=\"clear($event)\" title=\"Clear\" aria-label=\"Clear filter\">×</span>\n }\n </div>\n }\n @default {\n <button\n #trigger\n type=\"button\"\n class=\"fc-pill\"\n [class.has-value]=\"hasValue\"\n [class.is-open]=\"open\"\n (click)=\"toggleMenu($event)\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"open\"\n >\n <span class=\"fc-pill-field\">{{ column.label }}</span>\n @if (hasValue) {\n <span class=\"fc-pill-value\" [title]=\"valueLabel\">{{ valueLabel }}</span>\n <span class=\"fc-clear\" (click)=\"clear($event)\" title=\"Clear\" aria-label=\"Clear filter\">×</span>\n } @else {\n <span class=\"fc-caret\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 10 6\" width=\"9\" height=\"6\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M1 1.5 5 5 9 1.5\"/></svg>\n </span>\n }\n </button>\n\n @if (open) {\n <div\n class=\"fc-menu\"\n (clickOutside)=\"closeMenu()\"\n [ngStyle]=\"{ left: menuLeft + 'px', top: menuTop + 'px', 'min-width.px': menuWidth }\"\n >\n @if (mode === 'multi') {\n <div class=\"fc-search\">\n <svg class=\"fc-search-icon\" viewBox=\"0 0 16 16\" width=\"13\" height=\"13\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"4.3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"/>\n <line x1=\"10.4\" y1=\"10.4\" x2=\"14.6\" y2=\"14.6\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n <input\n class=\"fc-search-input\"\n type=\"text\"\n [(ngModel)]=\"attrSearch\"\n [placeholder]=\"isAttributeMode ? 'Search attributes' : 'Search'\"\n (click)=\"$event.stopPropagation()\"\n autocomplete=\"off\"\n />\n </div>\n @if (isAttributeMode) {\n <div class=\"fc-semantic\" role=\"group\" aria-label=\"Match\" (click)=\"$event.stopPropagation()\">\n <button type=\"button\" class=\"fc-semantic-opt\" [class.active]=\"attrSemantic === 'AnyOf'\" (click)=\"setSemantic('AnyOf')\">Any of</button>\n <button type=\"button\" class=\"fc-semantic-opt\" [class.active]=\"attrSemantic === 'AllOf'\" (click)=\"setSemantic('AllOf')\">All of</button>\n </div>\n }\n @if (!filteredOptions.length) {\n <div class=\"fc-empty\">{{ options.length ? 'No matches' : (isAttributeMode ? 'No attributes available' : 'No options available') }}</div>\n }\n <div class=\"fc-opt-list\">\n @for (opt of filteredOptions; track opt.value) {\n <button type=\"button\" class=\"fc-opt\" [class.selected]=\"isOptionSelected(opt)\" (click)=\"toggleOption(opt)\">\n <span class=\"fc-check\" aria-hidden=\"true\">\n @if (isOptionSelected(opt)) {\n <svg viewBox=\"0 0 12 12\" width=\"10\" height=\"10\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M2 6.3 4.6 9 10 3\"/></svg>\n }\n </span>\n @if (isAttributeMode) {\n <span class=\"fc-attr\" [class.at]=\"isNamedOption(opt)\">{{ optionLabel(opt) }}</span>\n } @else if (opt.chipClass) {\n <span [ngClass]=\"opt.chipClass\">{{ opt.label }}</span>\n } @else {\n <span class=\"fc-opt-label\">{{ optionLabel(opt) }}</span>\n }\n </button>\n }\n </div>\n } @else if (mode === 'daterange') {\n @for (opt of options; track opt.value) {\n <button type=\"button\" class=\"fc-opt\" [class.selected]=\"isOptionSelected(opt)\" (click)=\"selectDatePreset(opt)\">\n <span class=\"fc-opt-label\">{{ opt.label }}</span>\n </button>\n }\n <div class=\"fc-divider\"></div>\n <button type=\"button\" class=\"fc-opt\" [class.selected]=\"selectedValue === 'custom'\" (click)=\"openCustomRange($event)\">\n <span class=\"fc-opt-label\">Custom range\u2026</span>\n </button>\n } @else {\n @for (opt of options; track opt.value) {\n <button type=\"button\" class=\"fc-opt\" [class.selected]=\"isOptionSelected(opt)\" (click)=\"selectOption(opt)\">\n @if (opt.chipClass) {\n <span [ngClass]=\"opt.chipClass\">{{ opt.label }}</span>\n } @else {\n <span class=\"fc-opt-label\">{{ opt.label }}</span>\n }\n </button>\n }\n }\n </div>\n }\n }\n}\n\n@if (mode === 'daterange') {\n <!-- hidden Material range input; the calendar is opened from the \"Custom range\u2026\" option -->\n <mat-date-range-input class=\"fc-hidden-range\" [rangePicker]=\"rangePicker\">\n <input matStartDate [(ngModel)]=\"dateRangeStart\" (dateChange)=\"onRangeStartChanged($event.value)\" tabindex=\"-1\" aria-hidden=\"true\" />\n <input matEndDate [(ngModel)]=\"dateRangeEnd\" (dateChange)=\"onRangeEndChanged($event.value)\" tabindex=\"-1\" aria-hidden=\"true\" />\n </mat-date-range-input>\n <mat-date-range-picker #rangePicker xPosition=\"start\" yPosition=\"below\"></mat-date-range-picker>\n}\n", styles: [":host{display:inline-flex;position:relative}.fc-hidden-range{position:absolute;left:0;top:100%;width:1px;height:1px;opacity:0;pointer-events:none;overflow:hidden}.fc-divider{height:1px;margin:.25rem;background:var(--lt-border)}.fc-text{position:relative;display:flex;align-items:center}.fc-input{width:100%;height:1.875rem;padding:0 1.5rem 0 .5rem;font-family:var(--lt-font);font-size:.75rem;color:var(--lt-cell-text);background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);outline:none}.fc-input::placeholder{color:var(--placeholder)}.fc-input:focus{border-color:var(--lt-link)}.fc-pill{display:inline-flex;align-items:center;gap:.375rem;height:var(--lt-toolbar-height);max-width:14rem;padding:0 var(--lt-control-padding-x);font-family:var(--lt-font);font-size:.8125rem;font-weight:var(--lt-control-font-weight);color:var(--lt-cell-text);background:var(--lt-control-bg);border:var(--lt-control-border-full);border-radius:var(--lt-radius);cursor:pointer;white-space:nowrap;transition:border-color .15s,background .15s,color .15s}.fc-pill:hover,.fc-pill.is-open{border-color:var(--lt-link)}.fc-pill.has-value{border-color:var(--lt-link);background:color-mix(in srgb,var(--lt-link) 8%,var(--lt-control-bg))}.fc-pill-field{color:var(--lt-cell-text)}.fc-pill.has-value .fc-pill-field{color:var(--groupText)}.fc-pill.has-value .fc-pill-field:after{content:\":\"}.fc-pill-value{color:var(--lt-link);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fc-caret{flex:0 0 auto;display:inline-flex;color:var(--lt-icon)}.fc-clear{flex:0 0 auto;font-size:1rem;line-height:1;color:var(--lt-icon);cursor:pointer}.fc-clear:hover{color:var(--lt-icon-active)}.fc-text .fc-clear{position:absolute;right:.5rem}.fc-menu{position:fixed;z-index:1000;max-height:20rem;overflow-y:auto;padding:.375rem;background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);box-shadow:var(--shadowLarge);animation:fc-in .1s ease-out}@keyframes fc-in{0%{opacity:0;transform:translateY(-.25rem)}to{opacity:1;transform:translateY(0)}}.fc-semantic{display:flex;gap:.1875rem;margin:.125rem 0 .4375rem;padding:.1875rem;background:color-mix(in srgb,var(--lt-border) 30%,var(--lt-control-bg));border:1px solid var(--lt-border);border-radius:var(--lt-radius)}.fc-semantic-opt{flex:1 1 0;padding:.4375rem .5rem;font-family:var(--lt-font);font-size:.8125rem;font-weight:500;color:var(--lt-cell-text);background:transparent;border:none;border-radius:calc(var(--lt-radius) - .0625rem);cursor:pointer}.fc-semantic-opt:hover:not(.active){color:var(--lt-link)}.fc-semantic-opt.active{color:var(--lt-link);background:var(--lt-control-bg);box-shadow:0 1px 2px color-mix(in srgb,var(--lt-cell-text) 14%,transparent)}.fc-opt{display:flex;align-items:center;gap:.5625rem;width:100%;padding:.5rem;font-family:var(--lt-font);font-size:.875rem;color:var(--lt-cell-text);background:transparent;border:none;border-radius:var(--lt-radius);cursor:pointer;text-align:left}.fc-opt:hover{background:var(--lt-row-hover)}.fc-opt.selected{color:var(--lt-link);font-weight:600}.fc-opt-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fc-check{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:1.125rem;height:1.125rem;box-sizing:border-box;border:.09375rem solid var(--lt-border);border-radius:.25rem;color:var(--lt-control-bg);background:var(--lt-control-bg)}.fc-opt.selected .fc-check{background:var(--lt-link);border-color:var(--lt-link)}.fc-empty{padding:.5rem;font-size:.75rem;color:var(--groupText)}.fc-search{position:sticky;top:0;z-index:1;padding:.125rem 0 .4375rem;background:var(--lt-control-bg)}.fc-search-icon{position:absolute;left:.625rem;top:.125rem;display:flex;align-items:center;height:2.125rem;color:var(--lt-icon);pointer-events:none}.fc-search-input{width:100%;box-sizing:border-box;height:2.125rem;padding:0 .625rem 0 2rem;font-family:var(--lt-font);font-size:.8125rem;color:var(--lt-cell-text);background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);outline:none}.fc-search-input::placeholder{color:var(--placeholder)}.fc-search-input:focus{border-color:var(--lt-link)}.fc-opt-list{display:flex;flex-direction:column}.fc-attr{display:inline-flex;align-items:center;padding:.1875rem .5rem;font-size:.8125rem;font-weight:600;line-height:1.4;border-radius:.25rem;color:var(--lt-link);background:color-mix(in srgb,var(--lt-link) 12%,transparent);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fc-attr.at{color:var(--secondary);background:color-mix(in srgb,var(--secondary) 14%,transparent)}.fc-opt.selected .fc-attr{color:var(--lt-link)}.fc-opt.selected .fc-attr.at{color:var(--secondary)}\n"] }]
|
|
12336
12545
|
}], ctorParameters: () => [{ type: DataTableFilterService }, { type: ListTableService }], propDecorators: { column: [{
|
|
12337
12546
|
type: Input
|
|
12338
12547
|
}], trigger: [{
|
|
@@ -12376,6 +12585,87 @@ class ListTableComponent {
|
|
|
12376
12585
|
this.buildColumns();
|
|
12377
12586
|
}
|
|
12378
12587
|
}
|
|
12588
|
+
set rowData(value) {
|
|
12589
|
+
this._rowData = value || [];
|
|
12590
|
+
this.rebuildFlatRows();
|
|
12591
|
+
}
|
|
12592
|
+
get rowData() {
|
|
12593
|
+
return this._rowData;
|
|
12594
|
+
}
|
|
12595
|
+
// fitColumns: keep the table within its visible width when resizing - a column can only grow until
|
|
12596
|
+
// the other columns reach their set or minimum width, then the drag stops, so nothing is pushed
|
|
12597
|
+
// off screen into the horizontal scroll. Off by default (columns can grow past the view and scroll).
|
|
12598
|
+
set options(value) {
|
|
12599
|
+
const wasTree = !!this._options?.tree;
|
|
12600
|
+
this._options = value || {};
|
|
12601
|
+
// rebuild the render list if tree mode was flipped after init, otherwise flatRows
|
|
12602
|
+
// keeps the pre-toggle shape
|
|
12603
|
+
if (this._initialized && !!this._options.tree !== wasTree) {
|
|
12604
|
+
this.rebuildFlatRows();
|
|
12605
|
+
}
|
|
12606
|
+
}
|
|
12607
|
+
get options() {
|
|
12608
|
+
return this._options;
|
|
12609
|
+
}
|
|
12610
|
+
/** Tree mode: columns per depth level (index = level; level 0 uses `columns`).
|
|
12611
|
+
* Nested rows render in their own grid with a per-level sub-header, so children
|
|
12612
|
+
* need not match the parent. Unset renders children with the parent's columns.
|
|
12613
|
+
* The bound value is the default; users can show/hide/reorder/resize child columns
|
|
12614
|
+
* per depth from the Columns menu, persisted per table. */
|
|
12615
|
+
set childColumnsByLevel(v) {
|
|
12616
|
+
this._declaredChildColumnsByLevel = v;
|
|
12617
|
+
this.buildChildColumns();
|
|
12618
|
+
}
|
|
12619
|
+
get childColumnsByLevel() {
|
|
12620
|
+
return this._childColumnsByLevel;
|
|
12621
|
+
}
|
|
12622
|
+
invalidateColumnCache() {
|
|
12623
|
+
this._childColsVersion++;
|
|
12624
|
+
}
|
|
12625
|
+
syncTreeMemo() {
|
|
12626
|
+
if (this._treeMemoVersion !== this._childColsVersion) {
|
|
12627
|
+
this._treeKeyCache.clear();
|
|
12628
|
+
this._leadOffsetCache.clear();
|
|
12629
|
+
this._treeMemoVersion = this._childColsVersion;
|
|
12630
|
+
}
|
|
12631
|
+
}
|
|
12632
|
+
/** Rebuilds the effective per-level child columns from the declared defaults with
|
|
12633
|
+
* any persisted order/visibility/width applied. */
|
|
12634
|
+
buildChildColumns() {
|
|
12635
|
+
const declared = this._declaredChildColumnsByLevel;
|
|
12636
|
+
if (!declared) {
|
|
12637
|
+
this._childColumnsByLevel = undefined;
|
|
12638
|
+
this.invalidateColumnCache();
|
|
12639
|
+
return;
|
|
12640
|
+
}
|
|
12641
|
+
this._childColumnsByLevel = declared.map((set, level) => set && set.length ? this.svc.applyPersistedChildState(level, set) : (set ? [...set] : set));
|
|
12642
|
+
this.invalidateColumnCache();
|
|
12643
|
+
}
|
|
12644
|
+
/** Tree look: 'card' floats each nested level as a bordered card; 'flat' renders
|
|
12645
|
+
* nested rows inline with the table, sub-headers as plain strips, no card chrome.
|
|
12646
|
+
* The bound value is the default; the user can switch it from the Columns menu and
|
|
12647
|
+
* the choice is remembered per table. */
|
|
12648
|
+
set treeVariant(v) {
|
|
12649
|
+
this._declaredTreeVariant = v;
|
|
12650
|
+
this._treeVariant = v;
|
|
12651
|
+
}
|
|
12652
|
+
get treeVariant() {
|
|
12653
|
+
return this._treeVariant;
|
|
12654
|
+
}
|
|
12655
|
+
get isFlatTree() {
|
|
12656
|
+
return this.isTreeMode && this.treeVariant === 'flat';
|
|
12657
|
+
}
|
|
12658
|
+
/** Show the flat/nested switch only when the table actually renders nested rows. */
|
|
12659
|
+
get canSwitchTreeVariant() {
|
|
12660
|
+
return this.isTreeMode && this.hasChildColumns;
|
|
12661
|
+
}
|
|
12662
|
+
setTreeVariant(variant) {
|
|
12663
|
+
if (this._treeVariant === variant) {
|
|
12664
|
+
return;
|
|
12665
|
+
}
|
|
12666
|
+
this._treeVariant = variant;
|
|
12667
|
+
this.svc.saveTreeVariant(variant);
|
|
12668
|
+
}
|
|
12379
12669
|
constructor(svc, tableFilterService, el, ngZone, sanitizer) {
|
|
12380
12670
|
this.svc = svc;
|
|
12381
12671
|
this.tableFilterService = tableFilterService;
|
|
@@ -12383,9 +12673,19 @@ class ListTableComponent {
|
|
|
12383
12673
|
this.ngZone = ngZone;
|
|
12384
12674
|
this.sanitizer = sanitizer;
|
|
12385
12675
|
this._tableId = '';
|
|
12386
|
-
this.
|
|
12676
|
+
this._rowData = [];
|
|
12387
12677
|
this.isLoading = false;
|
|
12388
|
-
this.
|
|
12678
|
+
this._options = { noSelect: false, noMenu: false };
|
|
12679
|
+
// Cached per level; a width change mutates the same column objects, so no rebuild is needed.
|
|
12680
|
+
this._childLevelCache = new Map();
|
|
12681
|
+
this._childColsVersion = 0;
|
|
12682
|
+
this._childLevelCacheVersion = -1;
|
|
12683
|
+
// per-level derived values, recomputed only when the column set changes, so the
|
|
12684
|
+
// template's per-cell/per-row calls stay cheap on every change-detection pass
|
|
12685
|
+
this._treeKeyCache = new Map();
|
|
12686
|
+
this._leadOffsetCache = new Map();
|
|
12687
|
+
this._treeMemoVersion = -1;
|
|
12688
|
+
this.nodeToggled = new EventEmitter();
|
|
12389
12689
|
this.hasNext = false;
|
|
12390
12690
|
this.hasPrev = false;
|
|
12391
12691
|
this.startCount = '-';
|
|
@@ -12403,6 +12703,8 @@ class ListTableComponent {
|
|
|
12403
12703
|
this.filterColumn = 'name';
|
|
12404
12704
|
this.actionRequested = new EventEmitter();
|
|
12405
12705
|
this.tableReady = new EventEmitter();
|
|
12706
|
+
/** Full set of selected rows (all depths) whenever the selection changes. */
|
|
12707
|
+
this.selectionChanged = new EventEmitter();
|
|
12406
12708
|
/** Full column list (includes hidden), after persisted state. */
|
|
12407
12709
|
this.allColumns = [];
|
|
12408
12710
|
/** Currently rendered columns (visible + ordered). */
|
|
@@ -12418,6 +12720,28 @@ class ListTableComponent {
|
|
|
12418
12720
|
this.selectedItem = { actionList: [] };
|
|
12419
12721
|
// ---- selection ----
|
|
12420
12722
|
this.allToggled = false;
|
|
12723
|
+
/** Rows actually rendered: in tree mode this is the roots plus the expanded
|
|
12724
|
+
* descendants in order; otherwise it is `rowData` unchanged. */
|
|
12725
|
+
this.flatRows = [];
|
|
12726
|
+
this._treeVariant = 'card';
|
|
12727
|
+
this._declaredTreeVariant = 'card';
|
|
12728
|
+
/** Show the flat/nested row-layout switch in the Columns menu. Hidden for now;
|
|
12729
|
+
* the variant still comes from the `treeVariant` input. */
|
|
12730
|
+
this.showTreeVariantToggle = false;
|
|
12731
|
+
/** Flat variant only: draw a running guide rail down the left of each nested level. */
|
|
12732
|
+
this.treeRail = false;
|
|
12733
|
+
this.treeIndentRem = 1.25;
|
|
12734
|
+
// nudges cards past the first nested level right so their edge lands on the
|
|
12735
|
+
// parent chevron (a nested chevron sits one grid-padding deeper than the root's)
|
|
12736
|
+
this.treeDeepAlignRem = 0.625;
|
|
12737
|
+
// flat first-column indent: base clears the select gutter, then one chevron-width
|
|
12738
|
+
// per level so each sub-header lines up under its parent row's name
|
|
12739
|
+
this.treeFlatBaseRem = 3.75;
|
|
12740
|
+
this.treeFlatStepRem = 2.125;
|
|
12741
|
+
// nested card's left inset before per-depth indent; must match the --lt-card-inset token
|
|
12742
|
+
this.treeCardBaseRem = 4;
|
|
12743
|
+
// width of the leading checkbox column injected into nested grids when selectChildren is on
|
|
12744
|
+
this.treeSelectColRem = 2.25;
|
|
12421
12745
|
// ---- column chooser (skinned show/hide + reorder panel) ----
|
|
12422
12746
|
this.showColumnChooser = false;
|
|
12423
12747
|
// ---- integrated toolbar: search + filter chips + pagination ----
|
|
@@ -12440,16 +12764,28 @@ class ListTableComponent {
|
|
|
12440
12764
|
this._initialColumns = [];
|
|
12441
12765
|
this._initialized = false;
|
|
12442
12766
|
this.subscription = new Subscription();
|
|
12443
|
-
|
|
12767
|
+
// expansion + lazily-loaded children keyed by __treeRowKey, so a rowData refresh
|
|
12768
|
+
// (auto-refresh, paging, filter) keeps the tree open instead of collapsing it
|
|
12769
|
+
this._expandedKeys = new Set();
|
|
12770
|
+
this._childrenCache = new Map();
|
|
12771
|
+
this._destroyed = false;
|
|
12772
|
+
this.trackRow = (index, row) => row?.__treeRowKey ?? row?.id ?? row?.name ?? index;
|
|
12444
12773
|
this.trackCol = (index, col) => col.key;
|
|
12445
12774
|
// ---------------------------------------------------------------- hover tooltip
|
|
12446
12775
|
this.hoverTooltip = null;
|
|
12447
|
-
// ---------------------------------------------------------------- selection
|
|
12448
12776
|
this.toggleItem = (item) => {
|
|
12449
12777
|
item.selected = !item.selected;
|
|
12450
|
-
this.
|
|
12778
|
+
this.syncSelectAll();
|
|
12451
12779
|
this.actionRequested.emit({ action: 'toggleItem', item });
|
|
12452
|
-
|
|
12780
|
+
this.emitSelection();
|
|
12781
|
+
};
|
|
12782
|
+
this._railCache = new Map();
|
|
12783
|
+
// The whole chooser row is draggable, and the label sits inside the visibility
|
|
12784
|
+
// toggle button, so a reorder drag ends with a click on that button. This guard
|
|
12785
|
+
// swallows that one click so dragging a row never also hides its column.
|
|
12786
|
+
this._chooserDragged = false;
|
|
12787
|
+
// ---- nested-column chooser: one expandable group per depth level ----
|
|
12788
|
+
this.nestedChooserOpen = new Set();
|
|
12453
12789
|
// ---------------------------------------------------------------- action menus
|
|
12454
12790
|
this.openActionMenu = (event, item) => {
|
|
12455
12791
|
this.selectedItem = item;
|
|
@@ -12485,7 +12821,12 @@ class ListTableComponent {
|
|
|
12485
12821
|
this._initialized = true;
|
|
12486
12822
|
// set directly (no emit) to avoid forcing a second fetch when a host pre-seeded it
|
|
12487
12823
|
this.tableFilterService.pageSize = this.svc.restorePageSize(this.initialPageSize);
|
|
12824
|
+
this._treeVariant = this.svc.restoreTreeVariant(this._declaredTreeVariant);
|
|
12825
|
+
this.buildChildColumns();
|
|
12488
12826
|
this.buildColumns();
|
|
12827
|
+
// all inputs are bound by now, so settle the render list against the final
|
|
12828
|
+
// tree flag (the rowData setter may have run before `options` arrived)
|
|
12829
|
+
this.rebuildFlatRows();
|
|
12489
12830
|
this.updateEntityTypeLabel();
|
|
12490
12831
|
this.subscription.add(this.tableFilterService.filtersChanged.subscribe((filters) => {
|
|
12491
12832
|
// chips: every non-hidden filter except the free-text search (shown in the box)
|
|
@@ -12514,6 +12855,7 @@ class ListTableComponent {
|
|
|
12514
12855
|
this.ensureFilterResizeObserver();
|
|
12515
12856
|
}
|
|
12516
12857
|
ngOnDestroy() {
|
|
12858
|
+
this._destroyed = true;
|
|
12517
12859
|
this.subscription.unsubscribe();
|
|
12518
12860
|
this.detachResizeListeners();
|
|
12519
12861
|
this.filterRO?.disconnect();
|
|
@@ -12683,6 +13025,7 @@ class ListTableComponent {
|
|
|
12683
13025
|
this.hiddenColumns = this.allColumns
|
|
12684
13026
|
.filter((c) => c.hidden)
|
|
12685
13027
|
.map((c) => ({ ...c, headerName: c.label }));
|
|
13028
|
+
this.invalidateColumnCache();
|
|
12686
13029
|
}
|
|
12687
13030
|
colWidth(col) {
|
|
12688
13031
|
return col.width != null ? `${col.width}px` : null;
|
|
@@ -12751,17 +13094,325 @@ class ListTableComponent {
|
|
|
12751
13094
|
onCellLeave() {
|
|
12752
13095
|
this.hoverTooltip = null;
|
|
12753
13096
|
}
|
|
13097
|
+
// ---------------------------------------------------------------- selection
|
|
13098
|
+
/** True when nested rows get checkboxes and join the selection (opt-in). */
|
|
13099
|
+
get childSelectEnabled() {
|
|
13100
|
+
return !!this.options?.selectChildren && !this.options?.noSelect;
|
|
13101
|
+
}
|
|
13102
|
+
/** Rows the checkboxes and select-all act on: top-level only, unless selectChildren
|
|
13103
|
+
* is set. Keeps select-all from marking nested rows a host that reads rowData never sees. */
|
|
13104
|
+
get selectableRows() {
|
|
13105
|
+
if (!this.isTreeMode || this.childSelectEnabled) {
|
|
13106
|
+
return this.flatRows;
|
|
13107
|
+
}
|
|
13108
|
+
return this.flatRows.filter((r) => (r.__treeLevel ?? 0) === 0);
|
|
13109
|
+
}
|
|
12754
13110
|
/** Some rows selected but the header select-all isn't fully on (indeterminate). */
|
|
12755
13111
|
get someSelected() {
|
|
12756
|
-
return !this.allToggled &&
|
|
13112
|
+
return !this.allToggled && this.selectableRows.some((r) => r.selected);
|
|
12757
13113
|
}
|
|
12758
13114
|
toggleAll() {
|
|
12759
13115
|
const newState = !this.allToggled;
|
|
12760
13116
|
this.allToggled = newState;
|
|
12761
|
-
|
|
12762
|
-
row.selected = newState;
|
|
12763
|
-
});
|
|
13117
|
+
this.selectableRows.forEach((row) => (row.selected = newState));
|
|
12764
13118
|
this.actionRequested.emit({ action: 'toggleAll' });
|
|
13119
|
+
this.emitSelection();
|
|
13120
|
+
}
|
|
13121
|
+
syncSelectAll() {
|
|
13122
|
+
const rows = this.selectableRows;
|
|
13123
|
+
this.allToggled = rows.length > 0 && rows.every((r) => r.selected);
|
|
13124
|
+
}
|
|
13125
|
+
/** Emit every selected row across all depths. Walks the full data, not just the rendered
|
|
13126
|
+
* rows, so a collapsed parent's selected children are still reported. */
|
|
13127
|
+
emitSelection() {
|
|
13128
|
+
const out = [];
|
|
13129
|
+
const walk = (rows) => {
|
|
13130
|
+
(rows || []).forEach((r) => {
|
|
13131
|
+
if (r.selected) {
|
|
13132
|
+
out.push(r);
|
|
13133
|
+
}
|
|
13134
|
+
if (Array.isArray(r.children)) {
|
|
13135
|
+
walk(r.children);
|
|
13136
|
+
}
|
|
13137
|
+
});
|
|
13138
|
+
};
|
|
13139
|
+
walk(this._rowData);
|
|
13140
|
+
this.selectionChanged.emit(out);
|
|
13141
|
+
}
|
|
13142
|
+
// ---------------------------------------------------------------- tree rows
|
|
13143
|
+
get isTreeMode() {
|
|
13144
|
+
return !!this.options?.tree;
|
|
13145
|
+
}
|
|
13146
|
+
/** True when per-level child columns are configured (children render in their own
|
|
13147
|
+
* grid with a sub-header rather than the parent's columns). */
|
|
13148
|
+
get hasChildColumns() {
|
|
13149
|
+
return !!(this.childColumnsByLevel && this.childColumnsByLevel.length);
|
|
13150
|
+
}
|
|
13151
|
+
/** Columns used at a given depth: level 0 is the main (visible) columns; deeper
|
|
13152
|
+
* levels use `childColumnsByLevel`, falling back to the deepest set defined. */
|
|
13153
|
+
columnsForLevel(level) {
|
|
13154
|
+
if (level <= 0 || !this.hasChildColumns) {
|
|
13155
|
+
return this.visibleColumns;
|
|
13156
|
+
}
|
|
13157
|
+
if (this._childLevelCacheVersion !== this._childColsVersion) {
|
|
13158
|
+
this._childLevelCache.clear();
|
|
13159
|
+
this._childLevelCacheVersion = this._childColsVersion;
|
|
13160
|
+
}
|
|
13161
|
+
const cached = this._childLevelCache.get(level);
|
|
13162
|
+
if (cached) {
|
|
13163
|
+
return cached;
|
|
13164
|
+
}
|
|
13165
|
+
const sets = this.childColumnsByLevel;
|
|
13166
|
+
const set = sets[level] ?? sets[sets.length - 1];
|
|
13167
|
+
const cols = (set ?? this.visibleColumns).filter((c) => !c.hidden);
|
|
13168
|
+
this._childLevelCache.set(level, cols);
|
|
13169
|
+
return cols;
|
|
13170
|
+
}
|
|
13171
|
+
/** Child columns the chooser lists at a depth: all declared ones (including hidden),
|
|
13172
|
+
* minus structural columns like the select checkbox or row-actions gutter. */
|
|
13173
|
+
allColumnsForLevel(level) {
|
|
13174
|
+
return (this._childColumnsByLevel?.[level] ?? []).filter((c) => !c.excludeFromChooser);
|
|
13175
|
+
}
|
|
13176
|
+
/** Depths that offer configurable columns (skips the level-0 placeholder and any
|
|
13177
|
+
* level that only holds structural columns), one chooser group per level. */
|
|
13178
|
+
get childLevels() {
|
|
13179
|
+
const sets = this._childColumnsByLevel;
|
|
13180
|
+
if (!sets) {
|
|
13181
|
+
return [];
|
|
13182
|
+
}
|
|
13183
|
+
const levels = [];
|
|
13184
|
+
sets.forEach((_set, level) => {
|
|
13185
|
+
if (level > 0 && this.allColumnsForLevel(level).length) {
|
|
13186
|
+
levels.push(level);
|
|
13187
|
+
}
|
|
13188
|
+
});
|
|
13189
|
+
return levels;
|
|
13190
|
+
}
|
|
13191
|
+
/** Chooser hint for a nested level: its first few column labels, then "+N". */
|
|
13192
|
+
childLevelLabel(level) {
|
|
13193
|
+
const labels = this.allColumnsForLevel(level)
|
|
13194
|
+
.map((c) => c.label)
|
|
13195
|
+
.filter(Boolean);
|
|
13196
|
+
const max = 3;
|
|
13197
|
+
if (labels.length <= max) {
|
|
13198
|
+
return labels.join(' / ');
|
|
13199
|
+
}
|
|
13200
|
+
return labels.slice(0, max).join(' / ') + ' +' + (labels.length - max);
|
|
13201
|
+
}
|
|
13202
|
+
/** Key of the column that carries the expand control + indentation for a column set:
|
|
13203
|
+
* the flagged one, else the first real data column (skipping a leading structural
|
|
13204
|
+
* column such as a select checkbox the host put at the start). */
|
|
13205
|
+
treeColumnKeyFor(cols) {
|
|
13206
|
+
return (cols.find((c) => c.treeColumn) || cols.find((c) => !c.excludeFromChooser) || cols[0])?.key;
|
|
13207
|
+
}
|
|
13208
|
+
treeColumnKeyForLevel(level) {
|
|
13209
|
+
this.syncTreeMemo();
|
|
13210
|
+
if (!this._treeKeyCache.has(level)) {
|
|
13211
|
+
this._treeKeyCache.set(level, this.treeColumnKeyFor(this.columnsForLevel(level)));
|
|
13212
|
+
}
|
|
13213
|
+
return this._treeKeyCache.get(level);
|
|
13214
|
+
}
|
|
13215
|
+
/** Width of the columns before the tree column, used to pull the flat first-column
|
|
13216
|
+
* indent back by whatever structural columns (like a select checkbox) sit ahead of
|
|
13217
|
+
* it, so its content still lands under the parent row's name. */
|
|
13218
|
+
treeLeadOffset(level) {
|
|
13219
|
+
this.syncTreeMemo();
|
|
13220
|
+
const cacheKey = `${level}|${this.childSelectEnabled}`;
|
|
13221
|
+
const hit = this._leadOffsetCache.get(cacheKey);
|
|
13222
|
+
if (hit !== undefined) {
|
|
13223
|
+
return hit;
|
|
13224
|
+
}
|
|
13225
|
+
const cols = this.columnsForLevel(level);
|
|
13226
|
+
const treeKey = this.treeColumnKeyForLevel(level);
|
|
13227
|
+
let px = 0;
|
|
13228
|
+
let count = 0;
|
|
13229
|
+
for (const c of cols) {
|
|
13230
|
+
if (c.key === treeKey) {
|
|
13231
|
+
break;
|
|
13232
|
+
}
|
|
13233
|
+
px += c.width ?? 0;
|
|
13234
|
+
count++;
|
|
13235
|
+
}
|
|
13236
|
+
const gap = 'var(--lt-tree-col-gap, 0.5rem)';
|
|
13237
|
+
// the injected select column (when on) sits before every data column
|
|
13238
|
+
const selRem = this.childSelectEnabled ? this.treeSelectColRem : 0;
|
|
13239
|
+
const gaps = count + (this.childSelectEnabled ? 1 : 0);
|
|
13240
|
+
const result = (!gaps && !selRem && !px) ? '0px' : `calc(${selRem}rem + ${px}px + ${gaps} * ${gap})`;
|
|
13241
|
+
this._leadOffsetCache.set(cacheKey, result);
|
|
13242
|
+
return result;
|
|
13243
|
+
}
|
|
13244
|
+
isTreeColumn(col, level) {
|
|
13245
|
+
return this.isTreeMode && col.key === this.treeColumnKeyForLevel(level);
|
|
13246
|
+
}
|
|
13247
|
+
isTreeCell(col) {
|
|
13248
|
+
return this.isTreeColumn(col, 0);
|
|
13249
|
+
}
|
|
13250
|
+
/** Columns a full-width nested row spans: the data columns plus the select and
|
|
13251
|
+
* menu gutters, matching the header's cell count. */
|
|
13252
|
+
get treeSpanCount() {
|
|
13253
|
+
return this.visibleColumns.length + (this.options?.noSelect ? 0 : 1) + (this.options?.noMenu ? 0 : 1);
|
|
13254
|
+
}
|
|
13255
|
+
/** Per-level indent (rem); the card variant nudges levels past the first so the edge meets the parent chevron. */
|
|
13256
|
+
treeIndentFor(level) {
|
|
13257
|
+
const align = this.treeVariant === 'card' && level >= 2 ? this.treeDeepAlignRem : 0;
|
|
13258
|
+
return level * this.treeIndentRem + align;
|
|
13259
|
+
}
|
|
13260
|
+
/** Flat variant: left pad (rem) of a nested row's first column (sub-header + data),
|
|
13261
|
+
* one chevron-width per level so it lines up under the parent row's name. */
|
|
13262
|
+
treeFlatFirstIndentRem(level) {
|
|
13263
|
+
return this.treeFlatBaseRem + level * this.treeFlatStepRem;
|
|
13264
|
+
}
|
|
13265
|
+
/** Flat variant: drop the chevron slot for a leaf-only level so values sit under their header. */
|
|
13266
|
+
showTreeLead(row) {
|
|
13267
|
+
return !(this.isFlatTree && row?.__treeSiblingsCanExpand === false);
|
|
13268
|
+
}
|
|
13269
|
+
/** Left inset (rem) of a nested card at a given depth, matching the td padding. */
|
|
13270
|
+
treeCardLeftRem(level) {
|
|
13271
|
+
return this.treeCardBaseRem + this.treeIndentFor(level);
|
|
13272
|
+
}
|
|
13273
|
+
/** Vertical guide lines redrawing each ancestor card's left edge at this row's
|
|
13274
|
+
* position, so a card's left border stays continuous where a nested card is
|
|
13275
|
+
* inserted between its rows. Returns a stack of 1px background gradients, or null
|
|
13276
|
+
* when there is no ancestor to redraw (roots and the first nested level). */
|
|
13277
|
+
treeAncestorRails(level) {
|
|
13278
|
+
const key = `${level}|${this._treeVariant}|${this.treeRail}|${this.isTreeMode}`;
|
|
13279
|
+
const cached = this._railCache.get(key);
|
|
13280
|
+
if (cached !== undefined) {
|
|
13281
|
+
return cached;
|
|
13282
|
+
}
|
|
13283
|
+
const rails = this.computeAncestorRails(level);
|
|
13284
|
+
this._railCache.set(key, rails);
|
|
13285
|
+
return rails;
|
|
13286
|
+
}
|
|
13287
|
+
computeAncestorRails(level) {
|
|
13288
|
+
if (!this.isTreeMode || level < 2) {
|
|
13289
|
+
return null;
|
|
13290
|
+
}
|
|
13291
|
+
const flat = this.treeVariant === 'flat';
|
|
13292
|
+
// card mode always redraws ancestor card borders; flat mode draws the rail
|
|
13293
|
+
// only when the optional running rail is turned on
|
|
13294
|
+
if (flat && !this.treeRail) {
|
|
13295
|
+
return null;
|
|
13296
|
+
}
|
|
13297
|
+
const color = flat
|
|
13298
|
+
? 'var(--lt-tree-rail, color-mix(in srgb, var(--lt-border) 55%, var(--lt-icon)))'
|
|
13299
|
+
: 'var(--lt-tree-card-border, color-mix(in srgb, var(--lt-border) 70%, var(--lt-icon)))';
|
|
13300
|
+
const rails = [];
|
|
13301
|
+
for (let k = 1; k < level; k++) {
|
|
13302
|
+
const x = this.treeCardLeftRem(k);
|
|
13303
|
+
rails.push(`linear-gradient(90deg, transparent ${x}rem, ${color} ${x}rem, ${color} calc(${x}rem + 1px), transparent calc(${x}rem + 1px))`);
|
|
13304
|
+
}
|
|
13305
|
+
return rails.join(', ');
|
|
13306
|
+
}
|
|
13307
|
+
gridTemplate(level) {
|
|
13308
|
+
const tracks = this.columnsForLevel(level)
|
|
13309
|
+
.map((c) => (c.width != null ? `${c.width}px` : 'minmax(0, 1fr)'));
|
|
13310
|
+
if (this.childSelectEnabled) {
|
|
13311
|
+
tracks.unshift(`${this.treeSelectColRem}rem`);
|
|
13312
|
+
}
|
|
13313
|
+
return tracks.join(' ');
|
|
13314
|
+
}
|
|
13315
|
+
hasChildren(row) {
|
|
13316
|
+
return Array.isArray(row?.children) && row.children.length > 0;
|
|
13317
|
+
}
|
|
13318
|
+
/** A row can be expanded unless it is a leaf, has no loaded children, and has no
|
|
13319
|
+
* loader left to try. */
|
|
13320
|
+
canExpand(row) {
|
|
13321
|
+
if (!this.isTreeMode || row?.leaf === true) {
|
|
13322
|
+
return false;
|
|
13323
|
+
}
|
|
13324
|
+
if (this.hasChildren(row)) {
|
|
13325
|
+
return true;
|
|
13326
|
+
}
|
|
13327
|
+
const key = row?.__treeRowKey;
|
|
13328
|
+
if (key && this._childrenCache.has(key)) {
|
|
13329
|
+
return true;
|
|
13330
|
+
}
|
|
13331
|
+
return !!this.loadChildren && row?.__treeLoaded !== true;
|
|
13332
|
+
}
|
|
13333
|
+
toggleNode(row) {
|
|
13334
|
+
if (!this.isTreeMode || row?.__treeLoading) {
|
|
13335
|
+
return;
|
|
13336
|
+
}
|
|
13337
|
+
const key = row.__treeRowKey;
|
|
13338
|
+
if (this._expandedKeys.has(key)) {
|
|
13339
|
+
this._expandedKeys.delete(key);
|
|
13340
|
+
this.rebuildFlatRows();
|
|
13341
|
+
this.nodeToggled.emit({ row, expanded: false });
|
|
13342
|
+
return;
|
|
13343
|
+
}
|
|
13344
|
+
if (this.loadChildren && !this.hasChildren(row) && !this._childrenCache.has(key)) {
|
|
13345
|
+
row.__treeLoading = true;
|
|
13346
|
+
row.__treeLoadError = false; // clear any previous failure on retry
|
|
13347
|
+
this.rebuildFlatRows(); // surface the spinner while children load
|
|
13348
|
+
// run the loader inside the executor so a synchronous throw rejects the
|
|
13349
|
+
// promise instead of escaping and leaving __treeLoading stuck on forever
|
|
13350
|
+
new Promise((resolve) => resolve(this.loadChildren(row))).then((children) => this.onChildrenLoaded(row, children), () => this.onChildrenLoaded(row, [], true));
|
|
13351
|
+
return;
|
|
13352
|
+
}
|
|
13353
|
+
this._expandedKeys.add(key);
|
|
13354
|
+
this.rebuildFlatRows();
|
|
13355
|
+
this.nodeToggled.emit({ row, expanded: true });
|
|
13356
|
+
}
|
|
13357
|
+
onChildrenLoaded(row, children, failed = false) {
|
|
13358
|
+
if (this._destroyed) {
|
|
13359
|
+
return;
|
|
13360
|
+
}
|
|
13361
|
+
row.__treeLoading = false;
|
|
13362
|
+
if (failed) {
|
|
13363
|
+
// flag the failure so the toggle shows a retry affordance, and leave it collapsed
|
|
13364
|
+
row.__treeLoadError = true;
|
|
13365
|
+
this.rebuildFlatRows();
|
|
13366
|
+
return;
|
|
13367
|
+
}
|
|
13368
|
+
const list = Array.isArray(children) ? children : [];
|
|
13369
|
+
this._childrenCache.set(row.__treeRowKey, list);
|
|
13370
|
+
row.children = list;
|
|
13371
|
+
row.__treeLoaded = true;
|
|
13372
|
+
if (!list.length) {
|
|
13373
|
+
row.leaf = true; // nothing under it, so stop offering the control
|
|
13374
|
+
}
|
|
13375
|
+
this._expandedKeys.add(row.__treeRowKey);
|
|
13376
|
+
this.rebuildFlatRows();
|
|
13377
|
+
this.nodeToggled.emit({ row, expanded: true });
|
|
13378
|
+
}
|
|
13379
|
+
/** Flatten the tree into the ordered render list, tagging each row with its depth.
|
|
13380
|
+
* Outside tree mode the render list is `rowData` as-is. */
|
|
13381
|
+
rebuildFlatRows() {
|
|
13382
|
+
if (!this.isTreeMode) {
|
|
13383
|
+
this.flatRows = this._rowData;
|
|
13384
|
+
return;
|
|
13385
|
+
}
|
|
13386
|
+
const out = [];
|
|
13387
|
+
const walk = (rows, level, parentKey) => {
|
|
13388
|
+
const list = rows || [];
|
|
13389
|
+
// when no sibling can expand, the level needs no chevron slot
|
|
13390
|
+
const siblingsCanExpand = list.some((r) => this.canExpand(r));
|
|
13391
|
+
list.forEach((row, idx) => {
|
|
13392
|
+
row.__treeLevel = level;
|
|
13393
|
+
row.__treeSiblingsCanExpand = siblingsCanExpand;
|
|
13394
|
+
// first child of a group drives the per-expansion sub-header;
|
|
13395
|
+
// first and last mark the top and bottom of the nested card
|
|
13396
|
+
row.__treeFirstChild = level > 0 && idx === 0;
|
|
13397
|
+
row.__treeLastChild = level > 0 && idx === list.length - 1;
|
|
13398
|
+
// branch-unique track key: the same entity can appear under two parents
|
|
13399
|
+
// in a flat tree, so fold the parent path in to keep @for keys distinct
|
|
13400
|
+
row.__treeRowKey = parentKey + '/' + (row?.id ?? row?.name ?? idx);
|
|
13401
|
+
// a rowData refresh replaces the row object; re-attach children we loaded
|
|
13402
|
+
// earlier so an expanded lazy node stays populated instead of emptying out
|
|
13403
|
+
if (!this.hasChildren(row) && this._childrenCache.has(row.__treeRowKey)) {
|
|
13404
|
+
row.children = this._childrenCache.get(row.__treeRowKey);
|
|
13405
|
+
row.__treeLoaded = true;
|
|
13406
|
+
}
|
|
13407
|
+
row.__treeExpanded = this._expandedKeys.has(row.__treeRowKey);
|
|
13408
|
+
out.push(row);
|
|
13409
|
+
if (row.__treeExpanded && this.hasChildren(row)) {
|
|
13410
|
+
walk(row.children, level + 1, row.__treeRowKey);
|
|
13411
|
+
}
|
|
13412
|
+
});
|
|
13413
|
+
};
|
|
13414
|
+
walk(this._rowData, 0, '');
|
|
13415
|
+
this.flatRows = out;
|
|
12765
13416
|
}
|
|
12766
13417
|
// ---------------------------------------------------------------- sort
|
|
12767
13418
|
onHeaderSort(event) {
|
|
@@ -12769,16 +13420,7 @@ class ListTableComponent {
|
|
|
12769
13420
|
c.sortDir = c.key === event.colId ? event.dir : undefined;
|
|
12770
13421
|
});
|
|
12771
13422
|
}
|
|
12772
|
-
// ----------------------------------------------------------------
|
|
12773
|
-
hideColumn(col) {
|
|
12774
|
-
const target = this.allColumns.find((c) => c.key === col.key);
|
|
12775
|
-
if (!target) {
|
|
12776
|
-
return;
|
|
12777
|
-
}
|
|
12778
|
-
target.hidden = true;
|
|
12779
|
-
this.updateVisible();
|
|
12780
|
-
this.svc.saveState(this.allColumns);
|
|
12781
|
-
}
|
|
13423
|
+
// ---------------------------------------------------------------- show / reorder
|
|
12782
13424
|
showColumn(event) {
|
|
12783
13425
|
const target = this.allColumns.find((c) => c.key === event.column?.key);
|
|
12784
13426
|
if (!target) {
|
|
@@ -12801,7 +13443,9 @@ class ListTableComponent {
|
|
|
12801
13443
|
}
|
|
12802
13444
|
resetTableColumns() {
|
|
12803
13445
|
this.svc.reset();
|
|
13446
|
+
this._treeVariant = this._declaredTreeVariant;
|
|
12804
13447
|
this.allColumns = this._initialColumns.map((c) => ({ ...c }));
|
|
13448
|
+
this._childColumnsByLevel = this._declaredChildColumnsByLevel?.map((set) => set ? set.map((c) => ({ ...c })) : set);
|
|
12805
13449
|
this.updateVisible();
|
|
12806
13450
|
this.closeActionMenu();
|
|
12807
13451
|
}
|
|
@@ -12811,14 +13455,45 @@ class ListTableComponent {
|
|
|
12811
13455
|
get hiddenColumnCount() {
|
|
12812
13456
|
return this.allColumns.filter((c) => c.hidden && !c.excludeFromChooser && !this.isDefaultHidden(c)).length;
|
|
12813
13457
|
}
|
|
12814
|
-
/** True when visibility
|
|
13458
|
+
/** True when visibility, order, and width all match the originally declared
|
|
13459
|
+
* columns. Width is included so resizing a column alone still enables the
|
|
13460
|
+
* reset button; a column with no declared width uses null on both sides so
|
|
13461
|
+
* it only counts as changed once the user drags it to a concrete width. */
|
|
12815
13462
|
get columnsAtDefault() {
|
|
13463
|
+
if (this.canSwitchTreeVariant && this._treeVariant !== this._declaredTreeVariant) {
|
|
13464
|
+
return false;
|
|
13465
|
+
}
|
|
12816
13466
|
if (this.allColumns.length !== this._initialColumns.length) {
|
|
12817
13467
|
return false;
|
|
12818
13468
|
}
|
|
12819
|
-
|
|
13469
|
+
const parentAtDefault = this.allColumns.every((c, i) => {
|
|
12820
13470
|
const init = this._initialColumns[i];
|
|
12821
|
-
return init
|
|
13471
|
+
return init
|
|
13472
|
+
&& init.key === c.key
|
|
13473
|
+
&& !!init.hidden === !!c.hidden
|
|
13474
|
+
&& (init.width ?? null) === (c.width ?? null);
|
|
13475
|
+
});
|
|
13476
|
+
return parentAtDefault && this.childColumnsAtDefault;
|
|
13477
|
+
}
|
|
13478
|
+
/** True when every nested level's columns match their declared order/visibility/width. */
|
|
13479
|
+
get childColumnsAtDefault() {
|
|
13480
|
+
const declared = this._declaredChildColumnsByLevel;
|
|
13481
|
+
const current = this._childColumnsByLevel;
|
|
13482
|
+
if (!declared || !current) {
|
|
13483
|
+
return true;
|
|
13484
|
+
}
|
|
13485
|
+
return declared.every((set, level) => {
|
|
13486
|
+
const cur = current[level] ?? [];
|
|
13487
|
+
if (!set || set.length !== cur.length) {
|
|
13488
|
+
return set ? set.length === cur.length : true;
|
|
13489
|
+
}
|
|
13490
|
+
return set.every((d, i) => {
|
|
13491
|
+
const c = cur[i];
|
|
13492
|
+
return c
|
|
13493
|
+
&& d.key === c.key
|
|
13494
|
+
&& !!d.hidden === !!c.hidden
|
|
13495
|
+
&& (d.width ?? null) === (c.width ?? null);
|
|
13496
|
+
});
|
|
12822
13497
|
});
|
|
12823
13498
|
}
|
|
12824
13499
|
/** True when the column is hidden in the originally declared defaults. */
|
|
@@ -12836,36 +13511,82 @@ class ListTableComponent {
|
|
|
12836
13511
|
closeColumnChooser() {
|
|
12837
13512
|
this.showColumnChooser = false;
|
|
12838
13513
|
}
|
|
12839
|
-
|
|
12840
|
-
|
|
13514
|
+
onChooserDragStarted() {
|
|
13515
|
+
this._chooserDragged = true;
|
|
13516
|
+
}
|
|
13517
|
+
onChooserDragEnded() {
|
|
13518
|
+
// clear after the post-drag click has been handled (and skipped) below
|
|
13519
|
+
setTimeout(() => (this._chooserDragged = false));
|
|
13520
|
+
}
|
|
13521
|
+
/** Toggle a column's visibility. `level` undefined targets the top-level columns;
|
|
13522
|
+
* a number targets that nested depth's columns. */
|
|
13523
|
+
toggleColumnVisible(col, level) {
|
|
13524
|
+
if (this._chooserDragged || col.hideable === false) {
|
|
12841
13525
|
return;
|
|
12842
13526
|
}
|
|
12843
|
-
const
|
|
13527
|
+
const set = level == null ? this.allColumns : this._childColumnsByLevel?.[level];
|
|
13528
|
+
const target = set?.find((c) => c.key === col.key);
|
|
12844
13529
|
if (!target) {
|
|
12845
13530
|
return;
|
|
12846
13531
|
}
|
|
13532
|
+
if (!target.hidden && this.isLastVisibleColumn(target, level)) {
|
|
13533
|
+
return;
|
|
13534
|
+
}
|
|
12847
13535
|
target.hidden = !target.hidden;
|
|
12848
|
-
this.
|
|
12849
|
-
this.svc.saveState(this.allColumns);
|
|
13536
|
+
this.afterColumnChange(level, set);
|
|
12850
13537
|
}
|
|
12851
|
-
/**
|
|
13538
|
+
/** True when this is the only visible column at its level, so its toggle is disabled
|
|
13539
|
+
* to keep at least one column on screen. */
|
|
13540
|
+
isLastVisibleColumn(col, level) {
|
|
13541
|
+
const list = level == null ? this.chooserColumns : this.allColumnsForLevel(level);
|
|
13542
|
+
return !col.hidden && list.filter((c) => !c.hidden).length <= 1;
|
|
13543
|
+
}
|
|
13544
|
+
/** Columns shown in the top-level Columns menu. */
|
|
12852
13545
|
get chooserColumns() {
|
|
12853
13546
|
return this.allColumns.filter((c) => !c.excludeFromChooser);
|
|
12854
13547
|
}
|
|
12855
|
-
|
|
13548
|
+
/** Reorder columns from a chooser drag. `level` undefined targets the top-level
|
|
13549
|
+
* columns; a number targets that nested depth's columns. */
|
|
13550
|
+
chooserReorder(event, level) {
|
|
12856
13551
|
if (event.previousIndex === event.currentIndex) {
|
|
12857
13552
|
return;
|
|
12858
13553
|
}
|
|
12859
|
-
// menu lists a subset, so map the drag indices back onto
|
|
12860
|
-
const
|
|
12861
|
-
const
|
|
12862
|
-
|
|
13554
|
+
// the menu lists a chooser subset, so map the drag indices back onto the full set
|
|
13555
|
+
const full = level == null ? this.allColumns : this._childColumnsByLevel?.[level];
|
|
13556
|
+
const list = level == null ? this.chooserColumns : this.allColumnsForLevel(level);
|
|
13557
|
+
if (!full) {
|
|
13558
|
+
return;
|
|
13559
|
+
}
|
|
13560
|
+
const from = full.indexOf(list[event.previousIndex]);
|
|
13561
|
+
const to = full.indexOf(list[event.currentIndex]);
|
|
12863
13562
|
if (from < 0 || to < 0) {
|
|
12864
13563
|
return;
|
|
12865
13564
|
}
|
|
12866
|
-
moveItemInArray(
|
|
12867
|
-
this.
|
|
12868
|
-
|
|
13565
|
+
moveItemInArray(full, from, to);
|
|
13566
|
+
this.afterColumnChange(level, full);
|
|
13567
|
+
}
|
|
13568
|
+
/** Refresh and persist after a column visibility/order change, routing to the
|
|
13569
|
+
* top-level or nested-level persistence as appropriate. */
|
|
13570
|
+
afterColumnChange(level, set) {
|
|
13571
|
+
if (level == null) {
|
|
13572
|
+
this.updateVisible();
|
|
13573
|
+
this.svc.saveState(this.allColumns);
|
|
13574
|
+
}
|
|
13575
|
+
else {
|
|
13576
|
+
this.invalidateColumnCache();
|
|
13577
|
+
this.svc.saveChildState(level, set);
|
|
13578
|
+
}
|
|
13579
|
+
}
|
|
13580
|
+
isNestedGroupOpen(id) {
|
|
13581
|
+
return this.nestedChooserOpen.has(id);
|
|
13582
|
+
}
|
|
13583
|
+
toggleNestedGroup(id) {
|
|
13584
|
+
if (this.nestedChooserOpen.has(id)) {
|
|
13585
|
+
this.nestedChooserOpen.delete(id);
|
|
13586
|
+
}
|
|
13587
|
+
else {
|
|
13588
|
+
this.nestedChooserOpen.add(id);
|
|
13589
|
+
}
|
|
12869
13590
|
}
|
|
12870
13591
|
// ---------------------------------------------------------------- resize
|
|
12871
13592
|
startResize(col, event) {
|
|
@@ -12876,7 +13597,25 @@ class ListTableComponent {
|
|
|
12876
13597
|
event.stopPropagation();
|
|
12877
13598
|
const th = event.target?.closest('th');
|
|
12878
13599
|
const startWidth = col.width ?? th?.offsetWidth ?? 150;
|
|
12879
|
-
this.resizing = { col, startX: event.clientX, startWidth };
|
|
13600
|
+
this.resizing = { col, startX: event.clientX, startWidth, persist: true };
|
|
13601
|
+
this.setupFitCompensation(col, startWidth, this.visibleColumns, (key) => this.measuredHeaderWidth(key));
|
|
13602
|
+
document.addEventListener('pointermove', this.onPointerMove);
|
|
13603
|
+
document.addEventListener('pointerup', this.onPointerUp);
|
|
13604
|
+
}
|
|
13605
|
+
/** Resize a nested row's column. Measures the sub-header cell's current rendered
|
|
13606
|
+
* width so a flexible (1fr) column converts to a concrete width before dragging;
|
|
13607
|
+
* the grid reflows live because its template reads each column's width. */
|
|
13608
|
+
startChildResize(col, level, event) {
|
|
13609
|
+
if (col.resizable === false) {
|
|
13610
|
+
return;
|
|
13611
|
+
}
|
|
13612
|
+
event.preventDefault();
|
|
13613
|
+
event.stopPropagation();
|
|
13614
|
+
const cell = event.target?.closest('.lt-tree-subhead-cell');
|
|
13615
|
+
const startWidth = col.width ?? Math.round(cell?.getBoundingClientRect().width ?? 150);
|
|
13616
|
+
const grid = cell?.closest('.lt-tree-grid');
|
|
13617
|
+
this.resizing = { col, startX: event.clientX, startWidth, persist: true, level };
|
|
13618
|
+
this.setupFitCompensation(col, startWidth, this.columnsForLevel(level), (key) => this.measuredCellWidth(grid, level, key));
|
|
12880
13619
|
document.addEventListener('pointermove', this.onPointerMove);
|
|
12881
13620
|
document.addEventListener('pointerup', this.onPointerUp);
|
|
12882
13621
|
}
|
|
@@ -12884,13 +13623,94 @@ class ListTableComponent {
|
|
|
12884
13623
|
if (!this.resizing) {
|
|
12885
13624
|
return;
|
|
12886
13625
|
}
|
|
12887
|
-
const
|
|
12888
|
-
const
|
|
12889
|
-
|
|
13626
|
+
const r = this.resizing;
|
|
13627
|
+
const delta = event.clientX - r.startX;
|
|
13628
|
+
if (r.sink && r.sinkStart != null) {
|
|
13629
|
+
// fitColumns: the column grows and the sink shrinks by the same amount, so the table stays
|
|
13630
|
+
// the same width and no other column (notably the tree column) shifts. The drag stops once
|
|
13631
|
+
// the column or the sink reaches its minimum.
|
|
13632
|
+
const d = Math.min(r.maxDelta ?? delta, Math.max(r.minDelta ?? delta, delta));
|
|
13633
|
+
r.col.width = Math.round(r.startWidth + d);
|
|
13634
|
+
r.sink.width = Math.round(r.sinkStart - d);
|
|
13635
|
+
}
|
|
13636
|
+
else {
|
|
13637
|
+
const min = r.col.minWidth ?? 40;
|
|
13638
|
+
r.col.width = Math.max(min, Math.round(r.startWidth + delta));
|
|
13639
|
+
}
|
|
13640
|
+
}
|
|
13641
|
+
/** fitColumns: pick the sink column and the range the drag may travel, so the column and the sink
|
|
13642
|
+
* trade width while every other column stays fixed. No-op (plain resize) when fitColumns is off. */
|
|
13643
|
+
setupFitCompensation(col, startWidth, columns, measure) {
|
|
13644
|
+
if (!this.options?.fitColumns || !this.resizing) {
|
|
13645
|
+
return;
|
|
13646
|
+
}
|
|
13647
|
+
const sink = this.pickSink(col, columns);
|
|
13648
|
+
if (!sink) {
|
|
13649
|
+
return;
|
|
13650
|
+
}
|
|
13651
|
+
const FLOOR = 60;
|
|
13652
|
+
// measure() returns 0 when the element isn't found; fall back so a width of 0
|
|
13653
|
+
// never gets frozen in (and later persisted) for the sink or a flex column
|
|
13654
|
+
const sinkStart = sink.width ?? (measure(sink.key) || startWidth);
|
|
13655
|
+
// Freeze any other flexible column to its rendered width so only the column and the sink move
|
|
13656
|
+
// (otherwise the browser would still redistribute slack among the flexible columns). These are
|
|
13657
|
+
// restored to flexible when the drag ends, so one resize doesn't pin the whole table to px.
|
|
13658
|
+
const frozen = [];
|
|
13659
|
+
columns.forEach((c) => {
|
|
13660
|
+
if (c.key !== col.key && c.key !== sink.key && c.width == null) {
|
|
13661
|
+
const w = measure(c.key);
|
|
13662
|
+
if (w > 0) {
|
|
13663
|
+
c.width = w;
|
|
13664
|
+
frozen.push(c);
|
|
13665
|
+
}
|
|
13666
|
+
}
|
|
13667
|
+
});
|
|
13668
|
+
this.resizing.sink = sink;
|
|
13669
|
+
this.resizing.sinkStart = sinkStart;
|
|
13670
|
+
this.resizing.frozen = frozen;
|
|
13671
|
+
this.resizing.maxDelta = Math.max(0, sinkStart - (sink.minWidth ?? FLOOR)); // grow until the sink hits its min
|
|
13672
|
+
this.resizing.minDelta = Math.min(0, (col.minWidth ?? 40) - startWidth); // shrink until the column hits its min
|
|
13673
|
+
}
|
|
13674
|
+
/** The column that absorbs a resize: a flexible column first (it is meant to take up slack), else
|
|
13675
|
+
* the nearest resizable column that is not the tree column, so indentation never shifts. */
|
|
13676
|
+
pickSink(col, columns) {
|
|
13677
|
+
// never pick the tree column (explicit or implicit) as the sink, or resizing
|
|
13678
|
+
// would move the expand chevrons
|
|
13679
|
+
const treeKey = this.treeColumnKeyFor(columns);
|
|
13680
|
+
const usable = columns.filter((c) => c.key !== col.key && c.resizable !== false && c.key !== treeKey);
|
|
13681
|
+
const flex = usable.find((c) => c.width == null);
|
|
13682
|
+
if (flex) {
|
|
13683
|
+
return flex;
|
|
13684
|
+
}
|
|
13685
|
+
const idx = columns.findIndex((c) => c.key === col.key);
|
|
13686
|
+
return usable.find((c) => columns.indexOf(c) > idx) ?? usable[usable.length - 1];
|
|
13687
|
+
}
|
|
13688
|
+
measuredHeaderWidth(key) {
|
|
13689
|
+
const host = this.el?.nativeElement;
|
|
13690
|
+
const th = host?.querySelector(`[id="Header_${key}"]`);
|
|
13691
|
+
return th ? Math.round(th.getBoundingClientRect().width) : 0;
|
|
13692
|
+
}
|
|
13693
|
+
measuredCellWidth(grid, level, key) {
|
|
13694
|
+
const idx = this.columnsForLevel(level).findIndex((c) => c.key === key);
|
|
13695
|
+
const cells = grid?.querySelectorAll('.lt-tree-subhead-cell');
|
|
13696
|
+
const cell = cells ? cells[idx] : undefined;
|
|
13697
|
+
return cell ? Math.round(cell.getBoundingClientRect().width) : 0;
|
|
12890
13698
|
}
|
|
12891
13699
|
handleResizeEnd() {
|
|
12892
|
-
|
|
12893
|
-
|
|
13700
|
+
const r = this.resizing;
|
|
13701
|
+
// columns frozen only to steady the drag go back to flexible, so the table keeps
|
|
13702
|
+
// filling the viewport and their temporary px widths are not persisted by saveState
|
|
13703
|
+
r?.frozen?.forEach((c) => (c.width = undefined));
|
|
13704
|
+
if (r?.persist) {
|
|
13705
|
+
if (r.level != null) {
|
|
13706
|
+
const set = this._childColumnsByLevel?.[r.level];
|
|
13707
|
+
if (set) {
|
|
13708
|
+
this.svc.saveChildWidth(r.level, r.col.key, r.col.width, set);
|
|
13709
|
+
}
|
|
13710
|
+
}
|
|
13711
|
+
else {
|
|
13712
|
+
this.svc.saveWidth(r.col.key, r.col.width, this.allColumns);
|
|
13713
|
+
}
|
|
12894
13714
|
}
|
|
12895
13715
|
this.resizing = undefined;
|
|
12896
13716
|
this.detachResizeListeners();
|
|
@@ -13095,11 +13915,11 @@ class ListTableComponent {
|
|
|
13095
13915
|
this.entityTypeLabel = map[this._tableId] || this.entityTypeName || '';
|
|
13096
13916
|
}
|
|
13097
13917
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListTableComponent, deps: [{ token: ListTableService }, { token: DataTableFilterService }, { token: i0.ElementRef }, { token: i0.NgZone }, { token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
13098
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: ListTableComponent, isStandalone: false, selector: "lib-list-table", inputs: { tableId: "tableId", columns: "columns", rowData: "rowData", isLoading: "isLoading", options: "options", hasNext: "hasNext", hasPrev: "hasPrev", startCount: "startCount", endCount: "endCount", totalCount: "totalCount", filterApplied: "filterApplied", menuItems: "menuItems", headerActions: "headerActions", noItemsImage: "noItemsImage", showNoItemsAdd: "showNoItemsAdd", noItemsReadonly: "noItemsReadonly", accessDenied: "accessDenied", entityTypeName: "entityTypeName", filterName: "filterName", filterColumn: "filterColumn", initialPageSize: "initialPageSize" }, outputs: { actionRequested: "actionRequested", tableReady: "tableReady" }, providers: [ListTableService], viewQueries: [{ propertyName: "contextMenu", first: true, predicate: ["contextMenu"], descendants: true }, { propertyName: "filterZone", first: true, predicate: ["filterZone"], descendants: true }, { propertyName: "filtersRow", first: true, predicate: ["filtersRow"], descendants: true }], ngImport: i0, template: "@if (showTable && !accessDenied) {\n <div class=\"lt-container\">\n <div class=\"lt-toolbar\">\n <div class=\"lt-toolbar-left\">\n <div class=\"lt-search\">\n <svg class=\"lt-search-icon\" viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"4.3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"/>\n <line x1=\"10.4\" y1=\"10.4\" x2=\"14.6\" y2=\"14.6\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n <input\n class=\"lt-search-input\"\n id=\"SearchFilter\"\n type=\"text\"\n [placeholder]=\"'Search ' + (entityTypeLabel || 'items')\"\n [(ngModel)]=\"searchString\"\n (keyup)=\"onSearchInput()\"\n />\n </div>\n @if (filterableColumns.length) {\n <div class=\"lt-filter-zone\" #filterZone>\n <div class=\"lt-filters\" #filtersRow>\n @for (col of visibleFilterColumns; track col.key) {\n <span class=\"lt-filter-item\" [attr.data-filter-key]=\"col.key\">\n <lib-list-filter-cell [column]=\"col\"></lib-list-filter-cell>\n </span>\n }\n </div>\n @if (overflowFilterColumns.length) {\n <div class=\"lt-filter-more\">\n <button\n type=\"button\"\n class=\"lt-filter-more-btn\"\n [class.is-on]=\"hiddenActiveCount > 0\"\n [class.is-open]=\"showFilterOverflow\"\n (click)=\"toggleFilterOverflow($event)\"\n aria-haspopup=\"true\"\n [attr.aria-expanded]=\"showFilterOverflow\"\n [attr.aria-label]=\"overflowFilterColumns.length + ' more filters'\"\n id=\"FilterOverflowButton\"\n >\n <span class=\"lt-filter-more-icon\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\" width=\"14\" height=\"14\"><path fill=\"currentColor\" d=\"M2 3h12l-4.6 5.6v4l-2.8 1.4v-5.4z\"/></svg>\n </span>\n <span class=\"lt-filter-more-label\">More</span>\n <span class=\"lt-filter-more-count\">{{ overflowFilterColumns.length }}</span>\n </button>\n @if (showFilterOverflow) {\n <div class=\"lt-filter-overflow\" (clickOutside)=\"closeFilterOverflow($event)\">\n <div class=\"lt-filter-overflow-title\">Filters</div>\n @for (col of overflowFilterColumns; track col.key) {\n <div class=\"lt-filter-overflow-row\" [class.is-active]=\"isFilterActive(col)\">\n <lib-list-filter-cell [column]=\"col\"></lib-list-filter-cell>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n <div class=\"lt-toolbar-right\">\n <ng-template #refreshIcon>\n <svg viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" d=\"M13.4 8a5.4 5.4 0 1 1-1.5-3.8\"/>\n <path fill=\"currentColor\" d=\"M13.9 2.1l.5 3.2-3.2-.5z\"/>\n </svg>\n </ng-template>\n <button\n type=\"button\"\n class=\"lt-refresh-btn\"\n (click)=\"refresh()\"\n [disabled]=\"filtering\"\n aria-label=\"Refresh\"\n title=\"Refresh\"\n id=\"RefreshTableButton\"\n >\n <ng-container [ngTemplateOutlet]=\"refreshIcon\"></ng-container>\n </button>\n <lib-list-table-auto-refresh [loading]=\"filtering\" (refresh)=\"refresh()\"></lib-list-table-auto-refresh>\n <div class=\"lt-columns\">\n <button\n type=\"button\"\n class=\"lt-columns-btn\"\n [class.is-on]=\"hiddenColumnCount > 0\"\n [class.is-open]=\"showColumnChooser\"\n (click)=\"toggleColumnChooser($event)\"\n aria-haspopup=\"true\"\n [attr.aria-expanded]=\"showColumnChooser\"\n id=\"ColumnChooserButton\"\n >\n <svg viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\">\n <path fill=\"currentColor\" d=\"M2 3.5h9v1.4H2zM2 7.3h6v1.4H2zM2 11.1h11v1.4H2z\"/>\n <circle cx=\"13\" cy=\"4.2\" r=\"1.7\" fill=\"currentColor\"/>\n <circle cx=\"10\" cy=\"8\" r=\"1.7\" fill=\"currentColor\"/>\n <circle cx=\"14.4\" cy=\"11.8\" r=\"1.7\" fill=\"currentColor\"/>\n </svg>\n <span>Columns</span>\n @if (hiddenColumnCount > 0) {\n <span class=\"lt-columns-count\">{{ hiddenColumnCount }}</span>\n }\n </button>\n @if (showColumnChooser) {\n <div class=\"lt-column-chooser\" (clickOutside)=\"closeColumnChooser()\">\n <div class=\"lt-chooser-header\">\n <span class=\"lt-chooser-title\">Columns</span>\n <span class=\"lt-chooser-subtitle\">Customize order and visibility</span>\n </div>\n <ul class=\"lt-chooser-list\" cdkDropList cdkDropListLockAxis=\"y\" (cdkDropListDropped)=\"chooserReorder($event)\">\n @for (col of chooserColumns; track col.key) {\n <li class=\"lt-chooser-row\" cdkDrag cdkDragLockAxis=\"y\" [cdkDragDisabled]=\"col.reorderable === false\">\n <button\n type=\"button\"\n class=\"lt-chooser-toggle\"\n [class.checked]=\"!col.hidden\"\n [disabled]=\"col.hideable === false\"\n (click)=\"toggleColumnVisible(col)\"\n [attr.aria-pressed]=\"!col.hidden\"\n >\n <span class=\"lt-chooser-box\" aria-hidden=\"true\">\n @if (!col.hidden) {\n <svg viewBox=\"0 0 12 12\" width=\"10\" height=\"10\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M2 6.3 4.6 9 10 3\"/>\n </svg>\n }\n </span>\n <span class=\"lt-chooser-text\">{{ col.label }}</span>\n @if (isDefaultHidden(col)) {\n <span class=\"lt-chooser-default-tag\">hidden by default</span>\n }\n </button>\n @if (col.reorderable !== false) {\n <span class=\"lt-chooser-handle\" cdkDragHandle aria-label=\"Drag to reorder\" title=\"Drag to reorder\">\n <svg viewBox=\"0 0 10 16\" width=\"10\" height=\"15\" fill=\"currentColor\" aria-hidden=\"true\">\n <circle cx=\"3\" cy=\"3\" r=\"1.25\"/><circle cx=\"7\" cy=\"3\" r=\"1.25\"/>\n <circle cx=\"3\" cy=\"8\" r=\"1.25\"/><circle cx=\"7\" cy=\"8\" r=\"1.25\"/>\n <circle cx=\"3\" cy=\"13\" r=\"1.25\"/><circle cx=\"7\" cy=\"13\" r=\"1.25\"/>\n </svg>\n </span>\n }\n </li>\n }\n </ul>\n <div class=\"lt-chooser-footer\">\n <button\n type=\"button\"\n class=\"lt-chooser-reset\"\n [disabled]=\"columnsAtDefault\"\n (click)=\"resetTableColumns()\"\n id=\"ResetColumnsButton\"\n >\n Reset to default\n </button>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n\n <div class=\"lt-scroll\" id=\"ItemTable\">\n <table class=\"lt-table\">\n <colgroup>\n @if (!options.noSelect) { <col class=\"lt-col-select\" /> }\n @for (col of visibleColumns; track trackCol($index, col)) {\n <col [style.width]=\"colWidth(col)\" />\n }\n @if (!options.noMenu) { <col class=\"lt-col-menu\" /> }\n </colgroup>\n <thead class=\"lt-head\">\n <tr cdkDropList cdkDropListOrientation=\"horizontal\" (cdkDropListDropped)=\"onReorder($event)\">\n @if (!options.noSelect) {\n <th class=\"lt-select-cell\">\n <div\n class=\"lt-select-all\"\n [class.checked]=\"allToggled\"\n [class.indeterminate]=\"someSelected\"\n (click)=\"toggleAll()\"\n id=\"SelectAllRows\"\n ></div>\n </th>\n }\n @for (col of visibleColumns; track trackCol($index, col)) {\n <th\n cdkDrag\n [cdkDragDisabled]=\"col.reorderable === false\"\n class=\"lt-th\"\n [ngClass]=\"col.cellClass\"\n id=\"Header_{{ col.key }}\"\n >\n <lib-list-header-cell\n [column]=\"col\"\n [sortDir]=\"col.sortDir\"\n (sortChanged)=\"onHeaderSort($event)\"\n (hideColumn)=\"hideColumn($event)\"\n ></lib-list-header-cell>\n @if (col.resizable !== false) {\n <span class=\"lt-resize\" (pointerdown)=\"startResize(col, $event)\"></span>\n }\n </th>\n }\n @if (!options.noMenu) {\n <th class=\"lt-menu-cell\">\n <div class=\"lt-header-menu-trigger\" (click)=\"openHeaderActionMenu($event)\" id=\"ColumnMenuHeader\">\n ⋮\n </div>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of rowData; track trackRow($index, row); let i = $index) {\n <tr\n class=\"lt-row\"\n [class.lt-row-odd]=\"i % 2 === 1\"\n [class.lt-row-selected]=\"row.selected\"\n [class.row-invalid]=\"row.invalid\"\n [class.row-copied]=\"row.copied\"\n >\n @if (!options.noSelect) {\n <td class=\"lt-select-cell\">\n <lib-select-cell [row]=\"row\" [toggleItem]=\"toggleItem\"></lib-select-cell>\n </td>\n }\n @for (col of visibleColumns; track trackCol($index, col)) {\n <td\n class=\"lt-cell\"\n [ngClass]=\"cellClass(col)\"\n (click)=\"onCellClick(col, row, i)\"\n (mouseenter)=\"onCellHover(col, row, i, $event)\"\n (mouseleave)=\"onCellLeave()\"\n >\n @switch (renderMode(col)) {\n @case ('component') {\n <ng-container *ngComponentOutlet=\"col.cell; inputs: cellInputs(col, row, i)\"></ng-container>\n }\n @case ('html') {\n <span class=\"lt-cell-html\" [innerHTML]=\"cellHtml(col, row, i)\"></span>\n }\n @default {\n <span class=\"lt-cell-text\">{{ cellText(col, row, i) }}</span>\n }\n }\n </td>\n }\n @if (!options.noMenu) {\n <td class=\"lt-menu-cell\">\n @if (row.actionList?.length) {\n <button\n type=\"button\"\n class=\"lt-row-menu-trigger\"\n (click)=\"$event.stopPropagation(); openActionMenu($event, row)\"\n attr.id=\"RowMenu_{{ row.id }}\"\n aria-label=\"Row actions\"\n >⋮</button>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n @if (!isLoading && filterApplied && (!rowData || rowData.length === 0)) {\n <div class=\"no-rows-message\">No Rows To Show</div>\n }\n </div>\n\n <div class=\"lt-footer\">\n <div class=\"lt-footer-count\">\n Showing <span id=\"Start\">{{ startCount }}</span>–<span id=\"End\">{{ endCount }}</span>\n of <span id=\"Total\">{{ totalCount }}</span>\n </div>\n <div class=\"lt-footer-controls\">\n <div class=\"lt-rpp\">\n <span class=\"lt-rpp-label\">Rows per page</span>\n <select\n class=\"lt-rpp-select\"\n [disabled]=\"filtering\"\n [value]=\"pageSize\"\n (change)=\"onPageSizeChange(+$any($event.target).value)\"\n aria-label=\"Rows per page\"\n >\n @for (opt of pageSizeOptions; track opt) {\n <option [value]=\"opt\">{{ opt }}</option>\n }\n </select>\n </div>\n <div class=\"lt-pager\">\n <button type=\"button\" class=\"lt-page-btn icon-prev\" [disabled]=\"prevDisabled\" (click)=\"prevPage()\" aria-label=\"Previous page\"></button>\n @if (!cursorPager) {\n @for (p of pageWindow; track $index) {\n @if (p === 0) {\n <span class=\"lt-page-gap\">…</span>\n } @else {\n <button\n type=\"button\"\n class=\"lt-page-num\"\n [class.is-current]=\"p === currentPageNum\"\n (click)=\"goToPage(p)\"\n >{{ p }}</button>\n }\n }\n }\n <button type=\"button\" class=\"lt-page-btn icon-next\" [disabled]=\"nextDisabled\" (click)=\"nextPage()\" aria-label=\"Next page\"></button>\n </div>\n </div>\n </div>\n\n <!-- header action menu -->\n <lib-list-menu\n menuId=\"HeaderActionMenu\"\n [open]=\"openHeaderMenu\"\n [items]=\"headerMenuItems\"\n [left]=\"menuLeft\"\n [top]=\"menuTop\"\n (itemClick)=\"onHeaderMenuClick($event)\"\n (closed)=\"closeHeaderActionMenu()\"\n ></lib-list-menu>\n\n <!-- row action menu -->\n <lib-list-menu\n menuId=\"RowActionMenu\"\n [open]=\"openMenu\"\n [items]=\"rowMenuItems\"\n [left]=\"menuLeft\"\n [top]=\"menuTop\"\n (itemClick)=\"onRowMenuClick($event)\"\n (closed)=\"closeActionMenu()\"\n ></lib-list-menu>\n </div>\n} @else {\n <lib-no-items\n (clickEmit)=\"openCreate()\"\n [image]=\"noItemsImage\"\n [isEmpty]=\"!rowData || rowData.length === 0\"\n [isLoading]=\"isLoading\"\n [typeName]=\"entityTypeLabel\"\n [hasAdd]=\"showNoItemsAdd\"\n [readonly]=\"noItemsReadonly\"\n [accessDenied]=\"accessDenied\"\n ></lib-no-items>\n}\n\n@if (hoverTooltip) {\n <div class=\"lt-tooltip\" [ngStyle]=\"{ left: hoverTooltip.left + 'px', top: hoverTooltip.top + 'px' }\">\n <ng-container *ngComponentOutlet=\"hoverTooltip.component; inputs: hoverTooltip.inputs\"></ng-container>\n </div>\n}\n", styles: [":host{display:flex;flex-direction:column;width:100%;height:100%}.lt-columns-btn,.lt-refresh-btn,.lt-filter-more-btn{display:inline-flex;align-items:center;gap:var(--lt-control-gap);height:var(--lt-toolbar-height);padding:0 var(--lt-control-padding-x);font-family:var(--lt-font);font-size:var(--lt-control-font-size);font-weight:var(--lt-control-font-weight);color:var(--lt-cell-text);background:var(--lt-control-bg);border:var(--inputBorderWidth) solid var(--lt-control-border, var(--lt-border));border-radius:var(--lt-radius);cursor:pointer;white-space:nowrap;transition:border-color .15s,background .15s,color .15s}.lt-columns-btn svg,.lt-refresh-btn svg,.lt-filter-more-btn svg{display:block}.lt-columns-btn:hover,.lt-refresh-btn:hover,.lt-filter-more-btn:hover,.is-open.lt-columns-btn,.is-open.lt-refresh-btn,.is-open.lt-filter-more-btn,.is-on.lt-columns-btn,.is-on.lt-refresh-btn,.is-on.lt-filter-more-btn{border-color:var(--lt-link);color:var(--lt-link)}.lt-columns-count,.lt-filter-more-count{display:inline-flex;align-items:center;justify-content:center;min-width:1.125rem;height:1.125rem;padding:0 .3125rem;font-size:.6875rem;font-weight:700;color:var(--lt-control-bg);background:var(--lt-link);border-radius:.5625rem}.lt-container{display:flex;position:relative;height:calc(100% - var(--lt-container-reserve, 5.625rem));width:100%;flex-direction:column}.lt-scroll{position:relative;z-index:1;width:100%;flex:0 1 auto;min-height:0;overflow:auto;background-color:var(--lt-bg)}.lt-scroll .no-rows-message{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:var(--lt-cell-text);font-size:.875rem;pointer-events:none}.lt-table{width:100%;border-collapse:collapse;table-layout:fixed;font-family:var(--lt-font);font-size:.8125rem;color:var(--lt-cell-text)}.lt-head{position:sticky;top:0;z-index:10}.lt-head th{position:relative;box-sizing:border-box;height:2.75rem;padding:0 .3125rem 0 .625rem;text-align:left;vertical-align:middle;background-color:var(--lt-header-bg);border-bottom:1px solid var(--lt-header-underline);white-space:nowrap;-webkit-user-select:none;user-select:none}.lt-head th.lt-th{border-right:1px solid var(--lt-border)}.lt-head .lt-select-cell,.lt-head .lt-menu-cell{width:3.75rem;padding:0}.lt-resize{position:absolute;right:0;top:50%;transform:translateY(-50%);width:.625rem;height:.875rem;cursor:col-resize}.lt-resize:before,.lt-resize:after{content:\"\";position:absolute;top:0;height:100%;width:1px;background:transparent;transition:background .15s}.lt-resize:before{right:.25rem}.lt-resize:after{right:.125rem}.lt-resize:hover:before,.lt-resize:hover:after{background:var(--lt-icon)}.lt-head th:hover .lt-resize:before,.lt-head th:hover .lt-resize:after{background:var(--lt-border)}.lt-select-all{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);box-sizing:border-box;width:1rem;height:1rem;border:1px solid var(--lt-control-border, var(--lt-border));border-radius:.25rem;background:var(--lt-control-bg);background-repeat:no-repeat;background-position:center center;cursor:pointer;transition:border-color .12s,background-color .12s}.lt-select-all:hover{border-color:var(--lt-link)}.lt-select-all.checked{background-color:var(--lt-link);border-color:var(--lt-link);background-size:.75rem;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' d='M2.5 7.6 5.7 10.8 11.5 3.6'/%3E%3C/svg%3E\")}.lt-select-all.indeterminate{background-color:var(--lt-link);border-color:var(--lt-link);background-image:linear-gradient(#fff,#fff);background-size:.5rem .125rem}.lt-header-menu-trigger{display:flex;align-items:center;justify-content:center;height:100%;font-size:1.25rem;color:var(--lt-icon);cursor:pointer}.lt-header-menu-trigger:hover{color:var(--lt-icon-active)}.lt-row-menu-trigger{display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;padding:0;font-size:1.25rem;line-height:1;color:var(--lt-icon);background:transparent;border:none;border-radius:var(--lt-radius);cursor:pointer;transition:color .15s,background .15s}.lt-row-menu-trigger:hover{color:var(--lt-icon-active);background:var(--lt-row-hover)}.cdk-drag-preview{box-sizing:border-box;background-color:var(--lt-header-bg);color:var(--lt-header-text);box-shadow:var(--shadowLarge);padding:0 .625rem;display:flex;align-items:center;border-radius:var(--lt-radius)}.cdk-drag-placeholder{opacity:.3}.cdk-drag-animating{transition:transform .2s cubic-bezier(0,0,.2,1)}.lt-row{height:var(--lt-row-height);background-color:var(--lt-row-bg);color:var(--lt-cell-text)}.lt-row td{border-bottom:1px solid var(--lt-border)}.lt-row.lt-row-odd{background-color:var(--lt-row-alt-bg)}.lt-row:hover{background-color:var(--lt-row-hover)}.lt-row.lt-row-selected{background-color:var(--lt-row-selected)}.lt-row.lt-row-selected:hover{background-color:var(--lt-row-hover)}.lt-row.row-invalid{background-color:var(--invalid)!important}.lt-row.row-copied{background-color:var(--copiedRow)!important}.lt-cell{height:var(--lt-row-height);padding:0 .625rem 0 1.25rem;text-align:left;vertical-align:middle;border:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;-webkit-user-select:text;user-select:text}.lt-cell-text{display:inline-block;overflow:hidden;text-overflow:ellipsis;max-width:100%;vertical-align:middle}.lt-cell.lt-cell-center{text-align:center}.lt-badge-cell .lt-cell-text{padding:.1875rem .5rem;font-size:.75rem;font-weight:600;line-height:1.2;color:var(--lt-cell-text);background:color-mix(in srgb,var(--lt-border) 45%,transparent);border:1px solid var(--lt-border);border-radius:999px}.lt-badge-cell .lt-cell-text:empty{display:none}.lt-select-cell,.lt-menu-cell{width:3.75rem;padding:0;text-align:center;vertical-align:middle;overflow:visible;position:relative}.lt-toolbar{display:flex;align-items:center;justify-content:space-between;gap:.75rem;margin:var(--lt-toolbar-margin-y, 0) 0;padding:0 0 var(--lt-toolbar-pad-bottom, .625rem);min-height:var(--lt-toolbar-height);position:relative;z-index:30}.lt-toolbar-left{display:flex;align-items:center;gap:.5rem;flex:1 1 auto;min-width:0;flex-wrap:nowrap}.lt-filter-zone{display:flex;align-items:center;flex-wrap:nowrap;gap:.5rem;flex:0 1 auto;min-width:0}.lt-filters{display:flex;align-items:center;flex-wrap:nowrap;gap:.5rem;min-width:0;flex:0 1 auto;overflow:hidden}.lt-filter-item{display:inline-flex;flex:0 0 auto}.lt-filter-more{position:relative;flex:0 0 auto}.lt-filter-more-btn{gap:.375rem;padding:0 .625rem}.lt-filter-more-btn .lt-filter-more-icon{display:inline-flex}.lt-filter-overflow{position:absolute;top:calc(100% + .25rem);right:0;z-index:1000;min-width:15rem;max-width:min(22rem,90vw);display:flex;flex-direction:column;gap:.5rem;padding:.625rem;background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);box-shadow:var(--shadowLarge);animation:lt-chooser-in .12s ease-out}.lt-filter-overflow-title{font-family:var(--lt-font);font-size:.6875rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--groupText)}.lt-filter-overflow-row{display:flex}.lt-filter-overflow-row lib-list-filter-cell,.lt-filter-overflow-row .lt-filter-item{flex:1 1 auto;min-width:0}.lt-toolbar-right{display:flex;align-items:center;gap:.75rem;flex:0 0 auto}.lt-divider{flex:0 0 auto;width:1px;height:1.5rem;background:var(--lt-border)}.lt-search{position:relative;display:flex;align-items:center;width:18rem;max-width:40vw;flex:0 1 18rem}.lt-search-icon{position:absolute;left:.625rem;display:block;color:var(--lt-icon);pointer-events:none}.lt-search-input{width:100%;height:var(--lt-toolbar-height);padding:0 .75rem 0 1.75rem;font-family:var(--lt-font);font-size:.8125rem;color:var(--lt-cell-text);background:var(--lt-control-bg);border:var(--inputBorderWidth) solid var(--lt-control-border, var(--lt-border));border-radius:var(--lt-radius);outline:none;transition:border-color .15s,box-shadow .15s}.lt-search-input::placeholder{color:var(--placeholder)}.lt-search-input:focus{border-color:var(--lt-link);box-shadow:0 0 0 .1875rem color-mix(in srgb,var(--lt-link) 18%,transparent)}.lt-count{font-size:.8125rem;color:var(--groupText);white-space:nowrap}.lt-count .lt-count-of{color:var(--groupText)}.lt-pager{display:flex;align-items:center;gap:.25rem}.lt-page-btn{display:inline-flex;align-items:center;justify-content:center;width:var(--lt-toolbar-height);height:var(--lt-toolbar-height);color:var(--lt-icon);background:var(--lt-control-bg);border:var(--inputBorderWidth) solid var(--lt-control-border, var(--lt-border));border-radius:var(--lt-radius);cursor:pointer;font-size:.9375rem;transition:border-color .15s,color .15s}.lt-page-btn:not(:disabled):hover{border-color:var(--lt-link);color:var(--lt-link)}.lt-page-btn:disabled{opacity:.4;cursor:default}.lt-refresh-btn{padding:0;width:var(--lt-toolbar-height);justify-content:center}.lt-refresh-btn:disabled{opacity:.5;cursor:default;border-color:var(--lt-border);color:var(--lt-cell-text)}.lt-columns{position:relative;flex:0 0 auto}.lt-column-chooser{position:absolute;top:calc(100% + .25rem);right:0;z-index:1000;width:15rem;max-height:calc(100vh - 9rem);display:flex;flex-direction:column;background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);box-shadow:var(--shadowLarge);overflow:hidden;animation:lt-chooser-in .12s ease-out}@keyframes lt-chooser-in{0%{opacity:0;transform:translateY(-.25rem)}to{opacity:1;transform:translateY(0)}}.lt-chooser-header{flex:0 0 auto;display:flex;flex-direction:column;padding:.625rem .75rem .5rem;border-bottom:1px solid var(--lt-border)}.lt-chooser-title{font-size:.8125rem;font-weight:700;color:var(--lt-cell-text)}.lt-chooser-subtitle{font-size:.6875rem;color:var(--groupText)}.lt-chooser-list{flex:1 1 auto;list-style:none;margin:0;padding:.375rem .5rem;min-height:0;overflow-y:auto}.lt-chooser-row{display:flex;align-items:center;justify-content:space-between;min-height:2.5rem;padding:.5rem;border-radius:var(--lt-radius);background:var(--lt-control-bg)}.lt-chooser-row:hover{background:var(--lt-row-hover)}.lt-chooser-row:hover .lt-chooser-handle{opacity:1}.lt-chooser-toggle{display:flex;align-items:center;gap:.625rem;flex:1 1 auto;min-width:0;padding:0;background:transparent;border:none;font:inherit;font-size:.875rem;color:var(--lt-cell-text);text-align:left;cursor:pointer}.lt-chooser-toggle:disabled{cursor:default;opacity:.5}.lt-chooser-box{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;width:1rem;height:1rem;border:.09375rem solid var(--lt-control-border, var(--lt-border));border-radius:.25rem;color:var(--lt-control-bg);background:var(--lt-control-bg);transition:background .12s,border-color .12s}.lt-chooser-toggle.checked .lt-chooser-box{background:var(--lt-link);border-color:var(--lt-link)}.lt-chooser-toggle:not(:disabled):hover .lt-chooser-box{border-color:var(--lt-link)}.lt-chooser-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.lt-chooser-default-tag{flex:0 0 auto;margin-left:.375rem;font-size:.6875rem;font-weight:400;font-style:italic;color:var(--groupText);white-space:nowrap}.lt-chooser-handle{flex:0 0 auto;display:inline-flex;align-items:center;color:var(--lt-icon);cursor:grab;padding-left:.5rem;-webkit-user-select:none;user-select:none}.lt-chooser-handle:active{cursor:grabbing}.lt-chooser-footer{flex:0 0 auto;padding:.5rem .75rem;border-top:1px solid var(--lt-border)}.lt-chooser-reset{width:100%;height:1.875rem;font-size:.75rem;font-weight:600;color:var(--lt-link);background:transparent;border:1px solid var(--lt-border);border-radius:var(--lt-radius);cursor:pointer}.lt-chooser-reset:disabled{color:var(--groupText);cursor:default;opacity:.6}.lt-chooser-reset:not(:disabled):hover{border-color:var(--lt-link)}.lt-footer{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;padding:.625rem .125rem 0;font-family:var(--lt-font);font-size:.8125rem;color:var(--groupText)}.lt-footer-count{white-space:nowrap}.lt-footer-count span{color:var(--lt-cell-text);font-weight:600}.lt-footer-controls{display:flex;align-items:center;gap:1.25rem;flex-wrap:nowrap}.lt-rpp{display:inline-flex;align-items:center;gap:.5rem;white-space:nowrap}.lt-rpp-label{text-transform:none;font-weight:400;color:var(--groupText)}.lt-rpp-select{width:auto;min-width:4rem;height:var(--lt-toolbar-height);padding:0 1.75rem 0 .625rem;font-family:var(--lt-font);font-size:.8125rem;color:var(--lt-cell-text);background-color:var(--lt-control-bg);background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%236b7280' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='M3 4.5 6 7.5 9 4.5'/%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right .5rem center;border:var(--inputBorderWidth) solid var(--lt-control-border, var(--lt-border));border-radius:var(--lt-radius);appearance:none;-webkit-appearance:none;cursor:pointer}.lt-rpp-select:focus{outline:none;border-color:var(--lt-link)}.lt-page-num{display:inline-flex;align-items:center;justify-content:center;min-width:var(--lt-toolbar-height);height:var(--lt-toolbar-height);padding:0 .5rem;font-family:var(--lt-font);font-size:.8125rem;font-weight:600;color:var(--lt-cell-text);background:var(--lt-control-bg);border:var(--inputBorderWidth) solid var(--lt-control-border, var(--lt-border));border-radius:var(--lt-radius);cursor:pointer;transition:border-color .15s,color .15s,background .15s}.lt-page-num:hover{border-color:var(--lt-link);color:var(--lt-link)}.lt-page-num.is-current{color:#fff;background:var(--lt-link);border-color:var(--lt-link);cursor:default}.lt-page-gap{display:inline-flex;align-items:center;justify-content:center;min-width:1.25rem;color:var(--groupText)}.lt-tooltip{position:fixed;z-index:1100;pointer-events:none;animation:lt-tooltip-in .12s ease-out}@keyframes lt-tooltip-in{0%{opacity:0;transform:translateY(-.1875rem)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i6$1.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i6$1.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i6$1.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: i1$4.ClickOutsideDirective, selector: "[clickOutside]", inputs: ["clickOutsideEnabled", "attachOutsideOnClick", "delayClickOutsideInit", "emitOnBlur", "exclude", "excludeBeforeClick", "clickOutsideEvents"], outputs: ["clickOutside"] }, { kind: "component", type: ListMenuComponent, selector: "lib-list-menu", inputs: ["open", "items", "left", "top", "menuId"], outputs: ["itemClick", "closed"] }, { kind: "component", type: ListTableAutoRefreshComponent, selector: "lib-list-table-auto-refresh", inputs: ["seconds", "loading", "intervals"], outputs: ["refresh", "secondsChange"] }, { kind: "component", type: SelectCellComponent, selector: "lib-select-cell", inputs: ["row", "toggleItem"] }, { kind: "component", type: ListHeaderCellComponent, selector: "lib-list-header-cell", inputs: ["column", "sortDir"], outputs: ["sortChanged", "hideColumn"] }, { kind: "component", type: ListFilterCellComponent, selector: "lib-list-filter-cell", inputs: ["column"] }, { kind: "component", type: NoItemsComponent, selector: "lib-no-items", inputs: ["image", "typeName", "isEmpty", "hasAdd", "hiddenResults", "isLoading", "readonly", "accessDenied"], outputs: ["clickEmit", "refresh"] }] }); }
|
|
13918
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: ListTableComponent, isStandalone: false, selector: "lib-list-table", inputs: { tableId: "tableId", columns: "columns", rowData: "rowData", isLoading: "isLoading", options: "options", loadChildren: "loadChildren", childColumnsByLevel: "childColumnsByLevel", hasNext: "hasNext", hasPrev: "hasPrev", startCount: "startCount", endCount: "endCount", totalCount: "totalCount", filterApplied: "filterApplied", menuItems: "menuItems", headerActions: "headerActions", noItemsImage: "noItemsImage", showNoItemsAdd: "showNoItemsAdd", noItemsReadonly: "noItemsReadonly", accessDenied: "accessDenied", entityTypeName: "entityTypeName", filterName: "filterName", filterColumn: "filterColumn", treeVariant: "treeVariant", showTreeVariantToggle: "showTreeVariantToggle", treeRail: "treeRail", initialPageSize: "initialPageSize" }, outputs: { nodeToggled: "nodeToggled", actionRequested: "actionRequested", tableReady: "tableReady", selectionChanged: "selectionChanged" }, host: { properties: { "class.lt-tree-flat": "this.isFlatTree" } }, providers: [ListTableService], viewQueries: [{ propertyName: "contextMenu", first: true, predicate: ["contextMenu"], descendants: true }, { propertyName: "filterZone", first: true, predicate: ["filterZone"], descendants: true }, { propertyName: "filtersRow", first: true, predicate: ["filtersRow"], descendants: true }], ngImport: i0, template: "@if (showTable && !accessDenied) {\n <div class=\"lt-container\">\n <div class=\"lt-toolbar\">\n <div class=\"lt-toolbar-left\">\n <div class=\"lt-search\">\n <svg class=\"lt-search-icon\" viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"4.3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"/>\n <line x1=\"10.4\" y1=\"10.4\" x2=\"14.6\" y2=\"14.6\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n <input\n class=\"lt-search-input\"\n id=\"SearchFilter\"\n type=\"text\"\n [placeholder]=\"'Search ' + (entityTypeLabel || 'items')\"\n [(ngModel)]=\"searchString\"\n (keyup)=\"onSearchInput()\"\n />\n </div>\n @if (filterableColumns.length) {\n <div class=\"lt-filter-zone\" #filterZone>\n <div class=\"lt-filters\" #filtersRow>\n @for (col of visibleFilterColumns; track col.key) {\n <span class=\"lt-filter-item\" [attr.data-filter-key]=\"col.key\">\n <lib-list-filter-cell [column]=\"col\"></lib-list-filter-cell>\n </span>\n }\n </div>\n @if (overflowFilterColumns.length) {\n <div class=\"lt-filter-more\">\n <button\n type=\"button\"\n class=\"lt-filter-more-btn\"\n [class.is-on]=\"hiddenActiveCount > 0\"\n [class.is-open]=\"showFilterOverflow\"\n (click)=\"toggleFilterOverflow($event)\"\n aria-haspopup=\"true\"\n [attr.aria-expanded]=\"showFilterOverflow\"\n [attr.aria-label]=\"overflowFilterColumns.length + ' more filters'\"\n id=\"FilterOverflowButton\"\n >\n <span class=\"lt-filter-more-icon\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\" width=\"14\" height=\"14\"><path fill=\"currentColor\" d=\"M2 3h12l-4.6 5.6v4l-2.8 1.4v-5.4z\"/></svg>\n </span>\n <span class=\"lt-filter-more-label\">More</span>\n <span class=\"lt-filter-more-count\">{{ overflowFilterColumns.length }}</span>\n </button>\n @if (showFilterOverflow) {\n <div class=\"lt-filter-overflow\" (clickOutside)=\"closeFilterOverflow($event)\">\n <div class=\"lt-filter-overflow-title\">Filters</div>\n @for (col of overflowFilterColumns; track col.key) {\n <div class=\"lt-filter-overflow-row\" [class.is-active]=\"isFilterActive(col)\">\n <lib-list-filter-cell [column]=\"col\"></lib-list-filter-cell>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n <!-- Consumer-supplied toolbar controls (e.g. page-specific filters), rendered inline beside search. -->\n <ng-content select=\"[toolbar-filters]\"></ng-content>\n </div>\n <div class=\"lt-toolbar-right\">\n <ng-template #refreshIcon>\n <svg viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" d=\"M13.4 8a5.4 5.4 0 1 1-1.5-3.8\"/>\n <path fill=\"currentColor\" d=\"M13.9 2.1l.5 3.2-3.2-.5z\"/>\n </svg>\n </ng-template>\n <button\n type=\"button\"\n class=\"lt-refresh-btn\"\n (click)=\"refresh()\"\n [disabled]=\"filtering\"\n aria-label=\"Refresh\"\n title=\"Refresh\"\n id=\"RefreshTableButton\"\n >\n <ng-container [ngTemplateOutlet]=\"refreshIcon\"></ng-container>\n </button>\n <lib-list-table-auto-refresh [loading]=\"filtering\" (refresh)=\"refresh()\"></lib-list-table-auto-refresh>\n <div class=\"lt-columns\">\n <button\n type=\"button\"\n class=\"lt-columns-btn\"\n [class.is-on]=\"hiddenColumnCount > 0\"\n [class.is-open]=\"showColumnChooser\"\n (click)=\"toggleColumnChooser($event)\"\n aria-haspopup=\"true\"\n [attr.aria-expanded]=\"showColumnChooser\"\n id=\"ColumnChooserButton\"\n >\n <svg viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\">\n <path fill=\"currentColor\" d=\"M2 3.5h9v1.4H2zM2 7.3h6v1.4H2zM2 11.1h11v1.4H2z\"/>\n <circle cx=\"13\" cy=\"4.2\" r=\"1.7\" fill=\"currentColor\"/>\n <circle cx=\"10\" cy=\"8\" r=\"1.7\" fill=\"currentColor\"/>\n <circle cx=\"14.4\" cy=\"11.8\" r=\"1.7\" fill=\"currentColor\"/>\n </svg>\n <span>Columns</span>\n @if (hiddenColumnCount > 0) {\n <span class=\"lt-columns-count\">{{ hiddenColumnCount }}</span>\n }\n </button>\n @if (showColumnChooser) {\n <div class=\"lt-column-chooser\" (clickOutside)=\"closeColumnChooser()\">\n <div class=\"lt-chooser-header\">\n <span class=\"lt-chooser-title\">Columns</span>\n <span class=\"lt-chooser-subtitle\">Customize order and visibility</span>\n </div>\n @if (canSwitchTreeVariant && showTreeVariantToggle) {\n <div class=\"lt-chooser-view\" role=\"group\" aria-label=\"Expanded row layout\">\n <span class=\"lt-chooser-view-label\">Expanded rows</span>\n <div class=\"lt-chooser-view-toggle\">\n <button type=\"button\" class=\"lt-chooser-view-opt\" [class.active]=\"treeVariant === 'flat'\" (click)=\"setTreeVariant('flat')\">Flat</button>\n <button type=\"button\" class=\"lt-chooser-view-opt\" [class.active]=\"treeVariant === 'card'\" (click)=\"setTreeVariant('card')\">Nested</button>\n </div>\n </div>\n }\n <div class=\"lt-chooser-scroll\">\n <ul class=\"lt-chooser-list\" cdkDropList cdkDropListLockAxis=\"y\" (cdkDropListDropped)=\"chooserReorder($event)\">\n @for (col of chooserColumns; track col.key) {\n <li class=\"lt-chooser-row\" cdkDrag cdkDragLockAxis=\"y\" [cdkDragDisabled]=\"col.reorderable === false\"\n (cdkDragStarted)=\"onChooserDragStarted()\" (cdkDragEnded)=\"onChooserDragEnded()\">\n <ng-container *ngTemplateOutlet=\"chooserRowBody; context: { col: col }\"></ng-container>\n </li>\n }\n </ul>\n @if (canSwitchTreeVariant && childLevels.length) {\n <div class=\"lt-chooser-nested\">\n <button\n type=\"button\"\n class=\"lt-chooser-group\"\n (click)=\"toggleNestedGroup('__root')\"\n [attr.aria-expanded]=\"isNestedGroupOpen('__root')\"\n >\n <span class=\"lt-chooser-chevron\" [class.open]=\"isNestedGroupOpen('__root')\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\" width=\"11\" height=\"11\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 4l4 4-4 4\"/></svg>\n </span>\n <span class=\"lt-chooser-group-label\">Nested rows</span>\n </button>\n @if (isNestedGroupOpen('__root')) {\n @for (level of childLevels; track level) {\n <button\n type=\"button\"\n class=\"lt-chooser-group lt-chooser-group-sub\"\n (click)=\"toggleNestedGroup('lvl' + level)\"\n [attr.aria-expanded]=\"isNestedGroupOpen('lvl' + level)\"\n >\n <span class=\"lt-chooser-chevron\" [class.open]=\"isNestedGroupOpen('lvl' + level)\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\" width=\"11\" height=\"11\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 4l4 4-4 4\"/></svg>\n </span>\n <span class=\"lt-chooser-group-label\">Level {{ level }}</span>\n <span class=\"lt-chooser-group-hint\">{{ childLevelLabel(level) }}</span>\n </button>\n @if (isNestedGroupOpen('lvl' + level)) {\n <ul class=\"lt-chooser-list lt-chooser-sublist\" cdkDropList cdkDropListLockAxis=\"y\" (cdkDropListDropped)=\"chooserReorder($event, level)\">\n @for (col of allColumnsForLevel(level); track col.key) {\n <li class=\"lt-chooser-row\" cdkDrag cdkDragLockAxis=\"y\" [cdkDragDisabled]=\"col.reorderable === false\"\n (cdkDragStarted)=\"onChooserDragStarted()\" (cdkDragEnded)=\"onChooserDragEnded()\">\n <ng-container *ngTemplateOutlet=\"chooserRowBody; context: { col: col, level: level }\"></ng-container>\n </li>\n }\n </ul>\n }\n }\n }\n </div>\n }\n </div>\n <div class=\"lt-chooser-footer\">\n <button\n type=\"button\"\n class=\"lt-chooser-reset\"\n [disabled]=\"columnsAtDefault\"\n (click)=\"resetTableColumns()\"\n id=\"ResetColumnsButton\"\n >\n Reset to default\n </button>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- inner content of a Columns-chooser row, shared by the top-level and nested lists.\n The <li cdkDrag> wrapper stays inline in each list (above) so cdkDropList's content\n query still registers it as a draggable; only the body is shared here.\n `level` undefined targets the top-level columns, a number targets that nested depth. -->\n <ng-template #chooserRowBody let-col=\"col\" let-level=\"level\">\n <button\n type=\"button\"\n class=\"lt-chooser-toggle\"\n [class.checked]=\"!col.hidden\"\n [disabled]=\"col.hideable === false || isLastVisibleColumn(col, level)\"\n [attr.title]=\"isLastVisibleColumn(col, level) ? 'At least one column must stay visible' : null\"\n (click)=\"toggleColumnVisible(col, level)\"\n [attr.aria-pressed]=\"!col.hidden\"\n >\n <span class=\"lt-chooser-box\" aria-hidden=\"true\">\n <!-- always rendered: the check is white, so it stays invisible until the box\n turns blue when checked. Keeping it in the DOM means clicking to hide a\n column never detaches the click target, which would otherwise make the\n click-outside handler think the click was outside and close the menu. -->\n <svg viewBox=\"0 0 12 12\" width=\"10\" height=\"10\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M2 6.3 4.6 9 10 3\"/>\n </svg>\n </span>\n <span class=\"lt-chooser-text\">{{ col.label }}</span>\n @if (level == null && isDefaultHidden(col)) {\n <span class=\"lt-chooser-default-tag\">hidden by default</span>\n }\n </button>\n @if (col.reorderable !== false) {\n <!-- the whole row is the drag target (cdkDrag on the <li>); this is just the grip affordance -->\n <span class=\"lt-chooser-handle\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 10 16\" width=\"10\" height=\"15\" fill=\"currentColor\">\n <circle cx=\"3\" cy=\"3\" r=\"1.25\"/><circle cx=\"7\" cy=\"3\" r=\"1.25\"/>\n <circle cx=\"3\" cy=\"8\" r=\"1.25\"/><circle cx=\"7\" cy=\"8\" r=\"1.25\"/>\n <circle cx=\"3\" cy=\"13\" r=\"1.25\"/><circle cx=\"7\" cy=\"13\" r=\"1.25\"/>\n </svg>\n </span>\n }\n </ng-template>\n\n <div class=\"lt-scroll\" id=\"ItemTable\">\n <!-- expand/collapse control, reused by root rows and nested child rows -->\n <ng-template #treeToggle let-row=\"row\">\n @if (canExpand(row)) {\n <button\n type=\"button\"\n class=\"lt-tree-toggle\"\n [class.is-expanded]=\"row.__treeExpanded\"\n [class.is-loading]=\"row.__treeLoading\"\n [class.is-error]=\"row.__treeLoadError\"\n (click)=\"$event.stopPropagation(); toggleNode(row)\"\n [attr.aria-expanded]=\"!!row.__treeExpanded\"\n [attr.aria-busy]=\"!!row.__treeLoading\"\n [attr.title]=\"row.__treeLoadError ? 'Could not load children - click to retry' : null\"\n [attr.aria-label]=\"row.__treeExpanded ? 'Collapse row' : 'Expand row'\"\n >\n <svg class=\"lt-tree-chevron\" viewBox=\"0 0 16 16\" width=\"12\" height=\"12\" aria-hidden=\"true\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 4l4 4-4 4\"/>\n </svg>\n @if (row.__treeLoading) {\n <span class=\"lt-tree-spinner\" aria-hidden=\"true\"></span>\n }\n </button>\n } @else {\n <span class=\"lt-tree-spacer\" aria-hidden=\"true\"></span>\n }\n </ng-template>\n\n <!-- a single cell's content, reused across the fixed grid and the nested grid -->\n <ng-template #cellBody let-col=\"col\" let-row=\"row\" let-i=\"i\">\n @switch (renderMode(col)) {\n @case ('component') {\n <ng-container *ngComponentOutlet=\"col.cell; inputs: cellInputs(col, row, i)\"></ng-container>\n }\n @case ('html') {\n <span class=\"lt-cell-html\" [innerHTML]=\"cellHtml(col, row, i)\"></span>\n }\n @default {\n <span class=\"lt-cell-text\">{{ cellText(col, row, i) }}</span>\n }\n }\n </ng-template>\n\n <table class=\"lt-table\">\n <colgroup>\n @if (!options.noSelect) { <col class=\"lt-col-select\" /> }\n @for (col of visibleColumns; track trackCol($index, col)) {\n <col [style.width]=\"colWidth(col)\" />\n }\n @if (!options.noMenu) { <col class=\"lt-col-menu\" /> }\n </colgroup>\n <thead class=\"lt-head\">\n <tr cdkDropList cdkDropListOrientation=\"horizontal\" (cdkDropListDropped)=\"onReorder($event)\">\n @if (!options.noSelect) {\n <th class=\"lt-select-cell\">\n <div\n class=\"lt-select-all\"\n [class.checked]=\"allToggled\"\n [class.indeterminate]=\"someSelected\"\n (click)=\"toggleAll()\"\n id=\"SelectAllRows\"\n ></div>\n </th>\n }\n @for (col of visibleColumns; track trackCol($index, col)) {\n <th\n cdkDrag\n [cdkDragDisabled]=\"col.reorderable === false\"\n class=\"lt-th\"\n [class.lt-th-tree]=\"isTreeCell(col)\"\n [ngClass]=\"col.cellClass\"\n id=\"Header_{{ col.key }}\"\n >\n <lib-list-header-cell\n [column]=\"col\"\n [sortDir]=\"col.sortDir\"\n (sortChanged)=\"onHeaderSort($event)\"\n ></lib-list-header-cell>\n @if (col.resizable !== false) {\n <span class=\"lt-resize\" (pointerdown)=\"startResize(col, $event)\"></span>\n }\n </th>\n }\n @if (!options.noMenu) {\n <th class=\"lt-menu-cell\">\n <div class=\"lt-header-menu-trigger\" (click)=\"openHeaderActionMenu($event)\" id=\"ColumnMenuHeader\">\n ⋮\n </div>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of flatRows; track trackRow($index, row); let i = $index) {\n @if (isTreeMode && row.__treeLevel > 0 && hasChildColumns) {\n <!-- nested rows with their own per-level columns, laid out in a grid\n that spans the full table width (so they need not match the parent) -->\n @if (row.__treeFirstChild) {\n <tr class=\"lt-tree-subhead-row\">\n <td\n [attr.colspan]=\"treeSpanCount\"\n [style.--lt-tree-indent.rem]=\"treeIndentFor(row.__treeLevel)\"\n [style.--lt-tree-first-indent.rem]=\"treeFlatFirstIndentRem(row.__treeLevel)\"\n [style.--lt-tree-lead-offset]=\"treeLeadOffset(row.__treeLevel)\"\n [style.background-image]=\"treeAncestorRails(row.__treeLevel)\"\n >\n <div\n class=\"lt-tree-grid\"\n [style.grid-template-columns]=\"gridTemplate(row.__treeLevel)\"\n >\n @if (childSelectEnabled) {\n <span class=\"lt-tree-subhead-cell lt-tree-select-cell\"></span>\n }\n @for (col of columnsForLevel(row.__treeLevel); track col.key; let last = $last) {\n <span class=\"lt-tree-subhead-cell\" [class.lt-tree-indent-col]=\"isTreeColumn(col, row.__treeLevel)\" [ngClass]=\"cellClass(col)\">\n {{ col.label }}\n @if (!last && col.resizable !== false) {\n <span class=\"lt-resize lt-tree-resize\" (pointerdown)=\"startChildResize(col, row.__treeLevel, $event)\"></span>\n }\n </span>\n }\n </div>\n </td>\n </tr>\n }\n <tr\n class=\"lt-row lt-tree-child-row\"\n [class.lt-tree-last-child]=\"row.__treeLastChild\"\n [class.lt-row-selected]=\"row.selected\"\n [class.lt-row-expanded]=\"row.__treeExpanded\"\n >\n <td\n [attr.colspan]=\"treeSpanCount\"\n [style.--lt-tree-indent.rem]=\"treeIndentFor(row.__treeLevel)\"\n [style.--lt-tree-first-indent.rem]=\"treeFlatFirstIndentRem(row.__treeLevel)\"\n [style.--lt-tree-lead-offset]=\"treeLeadOffset(row.__treeLevel)\"\n [style.background-image]=\"treeAncestorRails(row.__treeLevel)\"\n >\n <div\n class=\"lt-tree-grid\"\n [style.grid-template-columns]=\"gridTemplate(row.__treeLevel)\"\n >\n @if (childSelectEnabled) {\n <div class=\"lt-tree-cellbox lt-tree-select-cell\">\n <lib-select-cell [row]=\"row\" [toggleItem]=\"toggleItem\"></lib-select-cell>\n </div>\n }\n @for (col of columnsForLevel(row.__treeLevel); track col.key) {\n <div\n class=\"lt-tree-cellbox\"\n [class.lt-tree-indent-col]=\"isTreeColumn(col, row.__treeLevel)\"\n [ngClass]=\"cellClass(col)\"\n (click)=\"onCellClick(col, row, i)\"\n (mouseenter)=\"onCellHover(col, row, i, $event)\"\n (mouseleave)=\"onCellLeave()\"\n >\n @if (isTreeColumn(col, row.__treeLevel) && showTreeLead(row)) {\n <span class=\"lt-tree-lead\">\n <ng-container *ngTemplateOutlet=\"treeToggle; context: {row: row}\"></ng-container>\n </span>\n }\n <ng-container *ngTemplateOutlet=\"cellBody; context: {col: col, row: row, i: i}\"></ng-container>\n </div>\n }\n </div>\n </td>\n </tr>\n } @else {\n <tr\n class=\"lt-row\"\n [class.lt-row-odd]=\"i % 2 === 1\"\n [class.lt-row-selected]=\"row.selected\"\n [class.lt-row-expanded]=\"row.__treeExpanded\"\n [class.row-invalid]=\"row.invalid\"\n [class.row-copied]=\"row.copied\"\n >\n @if (!options.noSelect) {\n <td class=\"lt-select-cell\">\n <lib-select-cell [row]=\"row\" [toggleItem]=\"toggleItem\"></lib-select-cell>\n </td>\n }\n @for (col of visibleColumns; track trackCol($index, col)) {\n <td\n class=\"lt-cell\"\n [class.lt-tree-cell]=\"isTreeCell(col)\"\n [ngClass]=\"cellClass(col)\"\n (click)=\"onCellClick(col, row, i)\"\n (mouseenter)=\"onCellHover(col, row, i, $event)\"\n (mouseleave)=\"onCellLeave()\"\n >\n @if (isTreeCell(col)) {\n <span class=\"lt-tree-cell-inner\">\n <span class=\"lt-tree-lead\" [style.margin-left.rem]=\"(row.__treeLevel || 0) * treeIndentRem\">\n <ng-container *ngTemplateOutlet=\"treeToggle; context: {row: row}\"></ng-container>\n </span>\n <ng-container *ngTemplateOutlet=\"cellBody; context: {col: col, row: row, i: i}\"></ng-container>\n </span>\n } @else {\n <ng-container *ngTemplateOutlet=\"cellBody; context: {col: col, row: row, i: i}\"></ng-container>\n }\n </td>\n }\n @if (!options.noMenu) {\n <td class=\"lt-menu-cell\">\n @if (row.actionList?.length) {\n <button\n type=\"button\"\n class=\"lt-row-menu-trigger\"\n (click)=\"$event.stopPropagation(); openActionMenu($event, row)\"\n attr.id=\"RowMenu_{{ row.id }}\"\n aria-label=\"Row actions\"\n >⋮</button>\n }\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n @if (!isLoading && filterApplied && (!rowData || rowData.length === 0)) {\n <div class=\"no-rows-message\">No Rows To Show</div>\n }\n </div>\n\n <div class=\"lt-footer\">\n <div class=\"lt-footer-count\">\n Showing <span id=\"Start\">{{ startCount }}</span>–<span id=\"End\">{{ endCount }}</span>\n of <span id=\"Total\">{{ totalCount }}</span>\n </div>\n <div class=\"lt-footer-controls\">\n <div class=\"lt-rpp\">\n <span class=\"lt-rpp-label\">Rows per page</span>\n <select\n class=\"lt-rpp-select\"\n [disabled]=\"filtering\"\n [value]=\"pageSize\"\n (change)=\"onPageSizeChange(+$any($event.target).value)\"\n aria-label=\"Rows per page\"\n >\n @for (opt of pageSizeOptions; track opt) {\n <option [value]=\"opt\">{{ opt }}</option>\n }\n </select>\n </div>\n <div class=\"lt-pager\">\n <button type=\"button\" class=\"lt-page-btn icon-prev\" [disabled]=\"prevDisabled\" (click)=\"prevPage()\" aria-label=\"Previous page\"></button>\n @if (!cursorPager) {\n @for (p of pageWindow; track $index) {\n @if (p === 0) {\n <span class=\"lt-page-gap\">…</span>\n } @else {\n <button\n type=\"button\"\n class=\"lt-page-num\"\n [class.is-current]=\"p === currentPageNum\"\n (click)=\"goToPage(p)\"\n >{{ p }}</button>\n }\n }\n }\n <button type=\"button\" class=\"lt-page-btn icon-next\" [disabled]=\"nextDisabled\" (click)=\"nextPage()\" aria-label=\"Next page\"></button>\n </div>\n </div>\n </div>\n\n <!-- header action menu -->\n <lib-list-menu\n menuId=\"HeaderActionMenu\"\n [open]=\"openHeaderMenu\"\n [items]=\"headerMenuItems\"\n [left]=\"menuLeft\"\n [top]=\"menuTop\"\n (itemClick)=\"onHeaderMenuClick($event)\"\n (closed)=\"closeHeaderActionMenu()\"\n ></lib-list-menu>\n\n <!-- row action menu -->\n <lib-list-menu\n menuId=\"RowActionMenu\"\n [open]=\"openMenu\"\n [items]=\"rowMenuItems\"\n [left]=\"menuLeft\"\n [top]=\"menuTop\"\n (itemClick)=\"onRowMenuClick($event)\"\n (closed)=\"closeActionMenu()\"\n ></lib-list-menu>\n </div>\n} @else {\n <lib-no-items\n (clickEmit)=\"openCreate()\"\n [image]=\"noItemsImage\"\n [isEmpty]=\"!rowData || rowData.length === 0\"\n [isLoading]=\"isLoading\"\n [typeName]=\"entityTypeLabel\"\n [hasAdd]=\"showNoItemsAdd\"\n [readonly]=\"noItemsReadonly\"\n [accessDenied]=\"accessDenied\"\n ></lib-no-items>\n}\n\n@if (hoverTooltip) {\n <div class=\"lt-tooltip\" [ngStyle]=\"{ left: hoverTooltip.left + 'px', top: hoverTooltip.top + 'px' }\">\n <ng-container *ngComponentOutlet=\"hoverTooltip.component; inputs: hoverTooltip.inputs\"></ng-container>\n </div>\n}\n", styles: [":host{display:flex;flex-direction:column;width:100%;height:100%}.lt-columns-btn,.lt-refresh-btn,.lt-filter-more-btn{display:inline-flex;align-items:center;gap:var(--lt-control-gap);height:var(--lt-toolbar-height);padding:0 var(--lt-control-padding-x);font-family:var(--lt-font);font-size:var(--lt-control-font-size);font-weight:var(--lt-control-font-weight);color:var(--lt-cell-text);background:var(--lt-control-bg);border:var(--lt-control-border-full);border-radius:var(--lt-radius);cursor:pointer;white-space:nowrap;transition:border-color .15s,background .15s,color .15s}.lt-columns-btn svg,.lt-refresh-btn svg,.lt-filter-more-btn svg{display:block}.lt-columns-btn:hover,.lt-refresh-btn:hover,.lt-filter-more-btn:hover,.is-open.lt-columns-btn,.is-open.lt-refresh-btn,.is-open.lt-filter-more-btn,.is-on.lt-columns-btn,.is-on.lt-refresh-btn,.is-on.lt-filter-more-btn{border-color:var(--lt-link);color:var(--lt-link)}.is-on.lt-columns-btn,.is-on.lt-refresh-btn,.is-on.lt-filter-more-btn{background:color-mix(in srgb,var(--lt-link) 8%,var(--lt-control-bg))}.lt-columns-count,.lt-filter-more-count{display:inline-flex;align-items:center;justify-content:center;min-width:1.125rem;height:1.125rem;padding:0 .3125rem;font-size:.6875rem;font-weight:700;color:var(--lt-control-bg);background:var(--lt-link);border-radius:.5625rem}.lt-container{display:flex;position:relative;height:calc(100% - var(--lt-container-reserve, 5.625rem));width:100%;flex-direction:column}.lt-scroll{position:relative;z-index:1;width:100%;flex:0 1 auto;min-height:0;overflow:auto;background-color:var(--lt-bg)}.lt-scroll .no-rows-message{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:var(--lt-cell-text);font-size:.875rem;pointer-events:none}.lt-table{width:100%;border-collapse:collapse;table-layout:fixed;font-family:var(--lt-font);font-size:.8125rem;color:var(--lt-cell-text)}.lt-head{position:sticky;top:0;z-index:10}.lt-head th{position:relative;box-sizing:border-box;height:2.6rem;padding:0 .3125rem 0 1.25rem;text-align:left;vertical-align:middle;background-color:var(--lt-header-bg);border-bottom:1px solid var(--lt-header-underline);white-space:nowrap;-webkit-user-select:none;user-select:none}.lt-head th.lt-th-tree{padding-left:2.75rem}.lt-head .lt-select-cell,.lt-head .lt-menu-cell{width:3.75rem;padding:0}.lt-resize{position:absolute;right:0;top:50%;transform:translateY(-50%);width:.75rem;height:2.25rem;cursor:col-resize}.lt-resize:before,.lt-resize:after{content:\"\";position:absolute;top:50%;height:1.25rem;transform:translateY(-50%);width:1px;background:color-mix(in srgb,var(--lt-border) 50%,var(--lt-icon));transition:background .15s}.lt-resize:before{right:.3125rem}.lt-resize:after{right:.125rem}.lt-resize:hover:before,.lt-resize:hover:after{background:color-mix(in srgb,var(--lt-icon) 72%,var(--lt-cell-text))}.lt-select-all{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);box-sizing:border-box;width:1rem;height:1rem;border:1px solid var(--lt-control-border, var(--lt-border));border-radius:.25rem;background:var(--lt-control-bg);background-repeat:no-repeat;background-position:center center;cursor:pointer;transition:border-color .12s,background-color .12s}.lt-select-all:hover{border-color:var(--lt-link)}.lt-select-all.checked{background-color:var(--lt-link);border-color:var(--lt-link);background-size:.75rem;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' d='M2.5 7.6 5.7 10.8 11.5 3.6'/%3E%3C/svg%3E\")}.lt-select-all.indeterminate{background-color:var(--lt-link);border-color:var(--lt-link);background-image:linear-gradient(#fff,#fff);background-size:.5rem .125rem}.lt-header-menu-trigger{display:flex;align-items:center;justify-content:center;height:100%;font-size:1.25rem;color:var(--lt-icon);cursor:pointer}.lt-header-menu-trigger:hover{color:var(--lt-icon-active)}.lt-row-menu-trigger{display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;padding:0;font-size:1.25rem;line-height:1;color:var(--lt-icon);background:transparent;border:none;border-radius:var(--lt-radius);cursor:pointer;transition:color .15s,background .15s}.lt-row-menu-trigger:hover{color:var(--lt-icon-active);background:var(--lt-row-hover)}.cdk-drag-preview{box-sizing:border-box;background-color:var(--lt-header-bg);color:var(--lt-header-text);box-shadow:var(--shadowLarge);padding:0 .625rem;display:flex;align-items:center;border-radius:var(--lt-radius)}.cdk-drag-placeholder{opacity:.3}.cdk-drag-animating{transition:transform .2s cubic-bezier(0,0,.2,1)}.lt-row{height:var(--lt-row-height);background-color:var(--lt-row-bg);color:var(--lt-cell-text)}.lt-row td{border-bottom:1px solid var(--lt-border)}.lt-row.lt-row-odd{background-color:var(--lt-row-alt-bg)}.lt-row:hover{background-color:var(--lt-row-hover)}.lt-row.lt-row-selected{background-color:var(--lt-row-selected)}.lt-row.lt-row-selected:hover{background-color:var(--lt-row-hover)}.lt-row.row-invalid{background-color:var(--invalid)!important}.lt-row.row-copied{background-color:var(--copiedRow)!important}.lt-cell{height:var(--lt-row-height);padding:0 .625rem 0 1.25rem;text-align:left;vertical-align:middle;border:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;-webkit-user-select:text;user-select:text}.lt-cell-text{display:inline-block;overflow:hidden;text-overflow:ellipsis;max-width:100%;vertical-align:middle}.lt-cell.lt-cell-center{text-align:center}.lt-badge-cell .lt-cell-text{padding:.1875rem .5rem;font-size:.75rem;font-weight:600;line-height:1.2;color:var(--lt-cell-text);background:color-mix(in srgb,var(--lt-border) 45%,transparent);border:1px solid var(--lt-border);border-radius:999px}.lt-badge-cell .lt-cell-text:empty{display:none}.lt-select-cell,.lt-menu-cell{width:3.75rem;padding:0;text-align:center;vertical-align:middle;overflow:visible;position:relative}.lt-tree-cell{padding-left:.625rem}.lt-tree-cell-inner{display:flex;align-items:center}.lt-tree-lead{display:inline-flex;align-items:center;flex:0 0 auto;margin-right:.375rem}.lt-tree-toggle{position:relative;display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;padding:0;color:var(--lt-icon);background:transparent;border:none;border-radius:50%;cursor:pointer;transition:color .15s,background .15s}.lt-tree-toggle:hover{color:var(--lt-link);background:color-mix(in srgb,var(--lt-link) 18%,transparent)}.lt-tree-chevron{display:block;width:13.8px;height:13.8px;transition:transform .15s ease}.lt-tree-toggle.is-expanded .lt-tree-chevron{transform:rotate(90deg)}.lt-tree-toggle.is-error .lt-tree-chevron{color:var(--lt-negative, #dc2626)}.lt-tree-spacer{display:inline-block;width:1.75rem;height:1.75rem}.lt-tree-spinner{position:absolute;top:50%;left:50%;box-sizing:border-box;width:1.875rem;height:1.875rem;margin:-.9375rem 0 0 -.9375rem;border:2px solid color-mix(in srgb,var(--lt-link) 25%,transparent);border-top-color:var(--lt-link);border-radius:50%;animation:loading .6s linear infinite;pointer-events:none}.lt-row-expanded>.lt-tree-cell .lt-cell-text{font-weight:600}.lt-tree-subhead-row>td,.lt-tree-child-row>td{padding:0 1rem 0 calc(var(--lt-card-inset, 4rem) + var(--lt-tree-indent, 0rem));background:transparent;border-bottom:none}.lt-tree-subhead-row,.lt-tree-child-row,.lt-tree-child-row:hover{background-color:var(--lt-tree-well, color-mix(in srgb, var(--lt-border) 22%, var(--lt-row-bg)))}.lt-tree-subhead-row>td{padding-top:1rem}.lt-tree-child-row.lt-tree-last-child>td{padding-bottom:1rem}.lt-tree-grid{display:grid;align-items:center;--lt-tree-col-gap: .5rem;column-gap:var(--lt-tree-col-gap);min-height:var(--lt-row-height);padding-left:.625rem;padding-right:.625rem;background:var(--lt-row-bg);border-left:1px solid var(--lt-tree-card-border, color-mix(in srgb, var(--lt-border) 70%, var(--lt-icon)));border-right:1px solid var(--lt-tree-card-border, color-mix(in srgb, var(--lt-border) 70%, var(--lt-icon)))}.lt-tree-child-row:hover .lt-tree-grid{background:var(--lt-row-hover)}.lt-tree-subhead-row .lt-tree-grid{min-height:2rem;background:var(--lt-header-bg);border-top:1px solid var(--lt-tree-card-border, color-mix(in srgb, var(--lt-border) 70%, var(--lt-icon)));border-top-left-radius:var(--lt-radius, 8px);border-top-right-radius:var(--lt-radius, 8px)}.lt-tree-child-row.lt-tree-last-child .lt-tree-grid{border-bottom:1px solid var(--lt-tree-card-border, color-mix(in srgb, var(--lt-border) 70%, var(--lt-icon)));border-bottom-left-radius:var(--lt-radius, 8px);border-bottom-right-radius:var(--lt-radius, 8px);box-shadow:var(--lt-tree-card-shadow, 0 2px 4px color-mix(in srgb, #000 10%, transparent))}.lt-tree-child-row:not(.lt-tree-last-child) .lt-tree-grid{border-bottom:1px solid color-mix(in srgb,var(--lt-border) 55%,transparent)}.lt-tree-subhead-cell{position:relative;padding:0 .3125rem;font-size:.6875rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--lt-header-text);overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.lt-tree-cellbox{display:flex;align-items:center;min-width:0;padding:0 .3125rem;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.lt-tree-cellbox .lt-cell-text{overflow:hidden;text-overflow:ellipsis}.lt-tree-grid>.lt-tree-select-cell{display:flex;align-items:center;justify-content:center;padding:0;overflow:visible}:host(.lt-tree-flat) .lt-tree-subhead-row,:host(.lt-tree-flat) .lt-tree-child-row,:host(.lt-tree-flat) .lt-tree-child-row:hover{background-color:transparent}:host(.lt-tree-flat) .lt-tree-subhead-row>td,:host(.lt-tree-flat) .lt-tree-child-row>td{padding:0}:host(.lt-tree-flat) .lt-tree-grid>.lt-tree-indent-col{padding-left:calc(var(--lt-tree-first-indent, 5.875rem) - var(--lt-tree-lead-offset, 0px))}:host(.lt-tree-flat) .lt-tree-grid{background:transparent;border-left:none;border-right:none;border-radius:0}:host(.lt-tree-flat) .lt-tree-subhead-row .lt-tree-grid{background:var(--lt-header-bg);border:none;border-bottom:1px solid var(--lt-border);border-radius:0}:host(.lt-tree-flat) .lt-tree-child-row .lt-tree-grid,:host(.lt-tree-flat) .lt-tree-child-row.lt-tree-last-child .lt-tree-grid{border-left:none;border-right:none;border-radius:0;box-shadow:none;border-bottom:1px solid color-mix(in srgb,var(--lt-border) 55%,transparent)}.lt-toolbar{display:flex;align-items:center;justify-content:space-between;gap:.75rem;margin:var(--lt-toolbar-margin-top, .75rem) 0 var(--lt-toolbar-margin-bottom, 0);padding:0 0 var(--lt-toolbar-pad-bottom, .625rem);min-height:var(--lt-toolbar-height);position:relative;z-index:30}.lt-toolbar-left{display:flex;align-items:center;gap:var(--lt-control-row-gap);flex:1 1 auto;min-width:0;flex-wrap:nowrap}.lt-filter-zone{display:flex;align-items:center;flex-wrap:nowrap;gap:var(--lt-control-row-gap);flex:0 1 auto;min-width:0}.lt-filters{display:flex;align-items:center;flex-wrap:nowrap;gap:var(--lt-control-row-gap);min-width:0;flex:0 1 auto;overflow:hidden}.lt-filter-item{display:inline-flex;flex:0 0 auto}.lt-filter-more{position:relative;flex:0 0 auto}.lt-filter-more-btn{gap:.375rem;padding:0 .625rem}.lt-filter-more-btn .lt-filter-more-icon{display:inline-flex}.lt-filter-overflow{position:absolute;top:calc(100% + .25rem);right:0;z-index:1000;min-width:15rem;max-width:min(22rem,90vw);display:flex;flex-direction:column;gap:.5rem;padding:.625rem;background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);box-shadow:var(--shadowLarge);animation:lt-chooser-in .12s ease-out}.lt-filter-overflow-title{font-family:var(--lt-font);font-size:.6875rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--groupText)}.lt-filter-overflow-row{display:flex}.lt-filter-overflow-row lib-list-filter-cell,.lt-filter-overflow-row .lt-filter-item{flex:1 1 auto;min-width:0}.lt-toolbar-right{display:flex;align-items:center;gap:var(--lt-control-row-gap);flex:0 0 auto}.lt-divider{flex:0 0 auto;width:1px;height:1.5rem;background:var(--lt-border)}.lt-search{position:relative;display:flex;align-items:center;width:18rem;max-width:40vw;flex:0 1 18rem}.lt-search-icon{position:absolute;left:.625rem;display:block;color:var(--lt-icon);pointer-events:none}.lt-search-input{width:100%;height:var(--lt-toolbar-height);padding:0 .75rem 0 1.75rem;font-family:var(--lt-font);font-size:.8125rem;color:var(--lt-cell-text);background:var(--lt-control-bg);border:var(--lt-control-border-full);border-radius:var(--lt-radius);outline:none;transition:border-color .15s,box-shadow .15s}.lt-search-input::placeholder{color:var(--placeholder)}.lt-search-input:focus{border-color:var(--lt-link);box-shadow:0 0 0 .1875rem color-mix(in srgb,var(--lt-link) 18%,transparent)}.lt-count{font-size:.8125rem;color:var(--groupText);white-space:nowrap}.lt-count .lt-count-of{color:var(--groupText)}.lt-pager{display:flex;align-items:center;gap:.25rem}.lt-page-btn{display:inline-flex;align-items:center;justify-content:center;width:var(--lt-toolbar-height);height:var(--lt-toolbar-height);color:var(--lt-icon);background:var(--lt-control-bg);border:var(--lt-control-border-full);border-radius:var(--lt-radius);cursor:pointer;font-size:.9375rem;transition:border-color .15s,color .15s}.lt-page-btn:not(:disabled):hover{border-color:var(--lt-link);color:var(--lt-link)}.lt-page-btn:disabled{opacity:.4;cursor:default}.lt-refresh-btn{padding:0;width:var(--lt-toolbar-height);justify-content:center}.lt-refresh-btn:disabled{opacity:.5;cursor:default;border-color:var(--lt-border);color:var(--lt-cell-text)}.lt-columns{position:relative;flex:0 0 auto}.lt-column-chooser{position:absolute;top:calc(100% + .25rem);right:0;z-index:1000;width:15rem;max-height:calc(100vh - 9rem);display:flex;flex-direction:column;background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);box-shadow:var(--shadowLarge);overflow:hidden;animation:lt-chooser-in .12s ease-out}@keyframes lt-chooser-in{0%{opacity:0;transform:translateY(-.25rem)}to{opacity:1;transform:translateY(0)}}.lt-chooser-header{flex:0 0 auto;display:flex;flex-direction:column;padding:.625rem .75rem .5rem;border-bottom:1px solid var(--lt-border)}.lt-chooser-title{font-size:.8125rem;font-weight:700;color:var(--lt-cell-text)}.lt-chooser-subtitle{font-size:.6875rem;color:var(--groupText)}.lt-chooser-view{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:.75rem;padding:.5rem .75rem;border-bottom:1px solid var(--lt-border)}.lt-chooser-view-label{font-size:.75rem;font-weight:600;color:var(--lt-cell-text)}.lt-chooser-view-toggle{display:flex;gap:.1875rem;padding:.1875rem;background:color-mix(in srgb,var(--lt-border) 30%,var(--lt-control-bg));border:1px solid var(--lt-border);border-radius:var(--lt-radius)}.lt-chooser-view-opt{padding:.25rem .625rem;font-family:var(--lt-font);font-size:.75rem;font-weight:500;color:var(--lt-cell-text);background:transparent;border:none;border-radius:calc(var(--lt-radius) - .0625rem);cursor:pointer}.lt-chooser-view-opt:hover:not(.active){color:var(--lt-link)}.lt-chooser-view-opt.active{color:var(--lt-link);background:var(--lt-control-bg);box-shadow:0 1px 2px color-mix(in srgb,var(--lt-cell-text) 14%,transparent)}.lt-chooser-scroll{flex:1 1 auto;min-height:0;overflow-y:auto}.lt-chooser-list{list-style:none;margin:0;padding:.375rem .5rem}.lt-chooser-nested{padding:0 .5rem .375rem;border-top:1px solid var(--lt-border)}.lt-chooser-group{display:flex;align-items:center;gap:.375rem;width:100%;min-height:2.25rem;padding:.375rem .25rem;font-family:var(--lt-font);font-size:.75rem;font-weight:600;color:var(--lt-cell-text);background:transparent;border:none;border-radius:var(--lt-radius);cursor:pointer;text-align:left}.lt-chooser-group:hover{background:var(--lt-row-hover)}.lt-chooser-group-sub{padding-left:1.25rem;font-weight:500}.lt-chooser-group-label{flex:0 0 auto}.lt-chooser-chevron{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:.875rem;color:var(--lt-icon);transition:transform .15s ease}.lt-chooser-chevron svg{display:block}.lt-chooser-chevron.open{transform:rotate(90deg)}.lt-chooser-group-hint{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.6875rem;font-weight:400;color:var(--groupText)}.lt-chooser-sublist{padding-left:1.75rem}.lt-chooser-row{display:flex;align-items:center;justify-content:space-between;min-height:2.5rem;padding:.5rem;border-radius:var(--lt-radius);background:var(--lt-control-bg);cursor:grab}.lt-chooser-row:active{cursor:grabbing}.lt-chooser-row.cdk-drag-disabled{cursor:default}.lt-chooser-row:hover{background:var(--lt-row-hover)}.lt-chooser-row:hover .lt-chooser-handle{opacity:1}.lt-chooser-toggle{display:flex;align-items:center;gap:.625rem;flex:1 1 auto;min-width:0;padding:0;background:transparent;border:none;font:inherit;font-size:.875rem;color:var(--lt-cell-text);text-align:left;cursor:pointer}.lt-chooser-toggle:disabled{cursor:default;opacity:.5}.lt-chooser-box{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;width:1rem;height:1rem;border:.09375rem solid var(--lt-control-border, var(--lt-border));border-radius:.25rem;color:var(--lt-control-bg);background:var(--lt-control-bg);transition:background .12s,border-color .12s}.lt-chooser-toggle.checked .lt-chooser-box{background:var(--lt-link);border-color:var(--lt-link)}.lt-chooser-toggle:not(:disabled):hover .lt-chooser-box{border-color:var(--lt-link)}.lt-chooser-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.lt-chooser-default-tag{flex:0 0 auto;margin-left:.375rem;font-size:.6875rem;font-weight:400;font-style:italic;color:var(--groupText);white-space:nowrap}.lt-chooser-handle{flex:0 0 auto;display:inline-flex;align-items:center;color:var(--lt-icon);cursor:grab;padding-left:.5rem;-webkit-user-select:none;user-select:none}.lt-chooser-handle:active{cursor:grabbing}.lt-chooser-footer{flex:0 0 auto;padding:.5rem .75rem;border-top:1px solid var(--lt-border)}.lt-chooser-reset{width:100%;height:1.875rem;font-size:.75rem;font-weight:600;color:var(--lt-link);background:transparent;border:1px solid var(--lt-border);border-radius:var(--lt-radius);cursor:pointer}.lt-chooser-reset:disabled{color:var(--groupText);cursor:default;opacity:.6}.lt-chooser-reset:not(:disabled):hover{border-color:var(--lt-link)}.lt-footer{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;padding:.625rem .125rem 0;font-family:var(--lt-font);font-size:.8125rem;color:var(--groupText)}.lt-footer-count{white-space:nowrap}.lt-footer-count span{color:var(--lt-cell-text);font-weight:600}.lt-footer-controls{display:flex;align-items:center;gap:1.25rem;flex-wrap:nowrap}.lt-rpp{display:inline-flex;align-items:center;gap:.5rem;white-space:nowrap}.lt-rpp-label{text-transform:none;font-weight:400;color:var(--groupText)}.lt-rpp-select{width:auto;min-width:4rem;height:var(--lt-toolbar-height);padding:0 1.75rem 0 .625rem;font-family:var(--lt-font);font-size:.8125rem;color:var(--lt-cell-text);background-color:var(--lt-control-bg);background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%236b7280' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='M3 4.5 6 7.5 9 4.5'/%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right .5rem center;border:var(--lt-control-border-full);border-radius:var(--lt-radius);appearance:none;-webkit-appearance:none;cursor:pointer}.lt-rpp-select:focus{outline:none;border-color:var(--lt-link)}.lt-page-num{display:inline-flex;align-items:center;justify-content:center;min-width:var(--lt-toolbar-height);height:var(--lt-toolbar-height);padding:0 .5rem;font-family:var(--lt-font);font-size:.8125rem;font-weight:600;color:var(--lt-cell-text);background:var(--lt-control-bg);border:var(--lt-control-border-full);border-radius:var(--lt-radius);cursor:pointer;transition:border-color .15s,color .15s,background .15s}.lt-page-num:hover{border-color:var(--lt-link);color:var(--lt-link)}.lt-page-num.is-current{color:#fff;background:var(--lt-link);border-color:var(--lt-link);cursor:default}.lt-page-gap{display:inline-flex;align-items:center;justify-content:center;min-width:1.25rem;color:var(--groupText)}.lt-tooltip{position:fixed;z-index:1100;pointer-events:none;animation:lt-tooltip-in .12s ease-out}@keyframes lt-tooltip-in{0%{opacity:0;transform:translateY(-.1875rem)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i6$1.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i6$1.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i1$4.ClickOutsideDirective, selector: "[clickOutside]", inputs: ["clickOutsideEnabled", "attachOutsideOnClick", "delayClickOutsideInit", "emitOnBlur", "exclude", "excludeBeforeClick", "clickOutsideEvents"], outputs: ["clickOutside"] }, { kind: "component", type: ListMenuComponent, selector: "lib-list-menu", inputs: ["open", "items", "left", "top", "menuId"], outputs: ["itemClick", "closed"] }, { kind: "component", type: ListTableAutoRefreshComponent, selector: "lib-list-table-auto-refresh", inputs: ["seconds", "loading", "intervals"], outputs: ["refresh", "secondsChange"] }, { kind: "component", type: SelectCellComponent, selector: "lib-select-cell", inputs: ["row", "toggleItem"] }, { kind: "component", type: ListHeaderCellComponent, selector: "lib-list-header-cell", inputs: ["column", "sortDir"], outputs: ["sortChanged"] }, { kind: "component", type: ListFilterCellComponent, selector: "lib-list-filter-cell", inputs: ["column"] }, { kind: "component", type: NoItemsComponent, selector: "lib-no-items", inputs: ["image", "typeName", "isEmpty", "hasAdd", "hiddenResults", "isLoading", "readonly", "accessDenied"], outputs: ["clickEmit", "refresh"] }] }); }
|
|
13099
13919
|
}
|
|
13100
13920
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListTableComponent, decorators: [{
|
|
13101
13921
|
type: Component,
|
|
13102
|
-
args: [{ selector: 'lib-list-table', standalone: false, providers: [ListTableService], template: "@if (showTable && !accessDenied) {\n <div class=\"lt-container\">\n <div class=\"lt-toolbar\">\n <div class=\"lt-toolbar-left\">\n <div class=\"lt-search\">\n <svg class=\"lt-search-icon\" viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"4.3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"/>\n <line x1=\"10.4\" y1=\"10.4\" x2=\"14.6\" y2=\"14.6\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n <input\n class=\"lt-search-input\"\n id=\"SearchFilter\"\n type=\"text\"\n [placeholder]=\"'Search ' + (entityTypeLabel || 'items')\"\n [(ngModel)]=\"searchString\"\n (keyup)=\"onSearchInput()\"\n />\n </div>\n @if (filterableColumns.length) {\n <div class=\"lt-filter-zone\" #filterZone>\n <div class=\"lt-filters\" #filtersRow>\n @for (col of visibleFilterColumns; track col.key) {\n <span class=\"lt-filter-item\" [attr.data-filter-key]=\"col.key\">\n <lib-list-filter-cell [column]=\"col\"></lib-list-filter-cell>\n </span>\n }\n </div>\n @if (overflowFilterColumns.length) {\n <div class=\"lt-filter-more\">\n <button\n type=\"button\"\n class=\"lt-filter-more-btn\"\n [class.is-on]=\"hiddenActiveCount > 0\"\n [class.is-open]=\"showFilterOverflow\"\n (click)=\"toggleFilterOverflow($event)\"\n aria-haspopup=\"true\"\n [attr.aria-expanded]=\"showFilterOverflow\"\n [attr.aria-label]=\"overflowFilterColumns.length + ' more filters'\"\n id=\"FilterOverflowButton\"\n >\n <span class=\"lt-filter-more-icon\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\" width=\"14\" height=\"14\"><path fill=\"currentColor\" d=\"M2 3h12l-4.6 5.6v4l-2.8 1.4v-5.4z\"/></svg>\n </span>\n <span class=\"lt-filter-more-label\">More</span>\n <span class=\"lt-filter-more-count\">{{ overflowFilterColumns.length }}</span>\n </button>\n @if (showFilterOverflow) {\n <div class=\"lt-filter-overflow\" (clickOutside)=\"closeFilterOverflow($event)\">\n <div class=\"lt-filter-overflow-title\">Filters</div>\n @for (col of overflowFilterColumns; track col.key) {\n <div class=\"lt-filter-overflow-row\" [class.is-active]=\"isFilterActive(col)\">\n <lib-list-filter-cell [column]=\"col\"></lib-list-filter-cell>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n <div class=\"lt-toolbar-right\">\n <ng-template #refreshIcon>\n <svg viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" d=\"M13.4 8a5.4 5.4 0 1 1-1.5-3.8\"/>\n <path fill=\"currentColor\" d=\"M13.9 2.1l.5 3.2-3.2-.5z\"/>\n </svg>\n </ng-template>\n <button\n type=\"button\"\n class=\"lt-refresh-btn\"\n (click)=\"refresh()\"\n [disabled]=\"filtering\"\n aria-label=\"Refresh\"\n title=\"Refresh\"\n id=\"RefreshTableButton\"\n >\n <ng-container [ngTemplateOutlet]=\"refreshIcon\"></ng-container>\n </button>\n <lib-list-table-auto-refresh [loading]=\"filtering\" (refresh)=\"refresh()\"></lib-list-table-auto-refresh>\n <div class=\"lt-columns\">\n <button\n type=\"button\"\n class=\"lt-columns-btn\"\n [class.is-on]=\"hiddenColumnCount > 0\"\n [class.is-open]=\"showColumnChooser\"\n (click)=\"toggleColumnChooser($event)\"\n aria-haspopup=\"true\"\n [attr.aria-expanded]=\"showColumnChooser\"\n id=\"ColumnChooserButton\"\n >\n <svg viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\">\n <path fill=\"currentColor\" d=\"M2 3.5h9v1.4H2zM2 7.3h6v1.4H2zM2 11.1h11v1.4H2z\"/>\n <circle cx=\"13\" cy=\"4.2\" r=\"1.7\" fill=\"currentColor\"/>\n <circle cx=\"10\" cy=\"8\" r=\"1.7\" fill=\"currentColor\"/>\n <circle cx=\"14.4\" cy=\"11.8\" r=\"1.7\" fill=\"currentColor\"/>\n </svg>\n <span>Columns</span>\n @if (hiddenColumnCount > 0) {\n <span class=\"lt-columns-count\">{{ hiddenColumnCount }}</span>\n }\n </button>\n @if (showColumnChooser) {\n <div class=\"lt-column-chooser\" (clickOutside)=\"closeColumnChooser()\">\n <div class=\"lt-chooser-header\">\n <span class=\"lt-chooser-title\">Columns</span>\n <span class=\"lt-chooser-subtitle\">Customize order and visibility</span>\n </div>\n <ul class=\"lt-chooser-list\" cdkDropList cdkDropListLockAxis=\"y\" (cdkDropListDropped)=\"chooserReorder($event)\">\n @for (col of chooserColumns; track col.key) {\n <li class=\"lt-chooser-row\" cdkDrag cdkDragLockAxis=\"y\" [cdkDragDisabled]=\"col.reorderable === false\">\n <button\n type=\"button\"\n class=\"lt-chooser-toggle\"\n [class.checked]=\"!col.hidden\"\n [disabled]=\"col.hideable === false\"\n (click)=\"toggleColumnVisible(col)\"\n [attr.aria-pressed]=\"!col.hidden\"\n >\n <span class=\"lt-chooser-box\" aria-hidden=\"true\">\n @if (!col.hidden) {\n <svg viewBox=\"0 0 12 12\" width=\"10\" height=\"10\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M2 6.3 4.6 9 10 3\"/>\n </svg>\n }\n </span>\n <span class=\"lt-chooser-text\">{{ col.label }}</span>\n @if (isDefaultHidden(col)) {\n <span class=\"lt-chooser-default-tag\">hidden by default</span>\n }\n </button>\n @if (col.reorderable !== false) {\n <span class=\"lt-chooser-handle\" cdkDragHandle aria-label=\"Drag to reorder\" title=\"Drag to reorder\">\n <svg viewBox=\"0 0 10 16\" width=\"10\" height=\"15\" fill=\"currentColor\" aria-hidden=\"true\">\n <circle cx=\"3\" cy=\"3\" r=\"1.25\"/><circle cx=\"7\" cy=\"3\" r=\"1.25\"/>\n <circle cx=\"3\" cy=\"8\" r=\"1.25\"/><circle cx=\"7\" cy=\"8\" r=\"1.25\"/>\n <circle cx=\"3\" cy=\"13\" r=\"1.25\"/><circle cx=\"7\" cy=\"13\" r=\"1.25\"/>\n </svg>\n </span>\n }\n </li>\n }\n </ul>\n <div class=\"lt-chooser-footer\">\n <button\n type=\"button\"\n class=\"lt-chooser-reset\"\n [disabled]=\"columnsAtDefault\"\n (click)=\"resetTableColumns()\"\n id=\"ResetColumnsButton\"\n >\n Reset to default\n </button>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n\n <div class=\"lt-scroll\" id=\"ItemTable\">\n <table class=\"lt-table\">\n <colgroup>\n @if (!options.noSelect) { <col class=\"lt-col-select\" /> }\n @for (col of visibleColumns; track trackCol($index, col)) {\n <col [style.width]=\"colWidth(col)\" />\n }\n @if (!options.noMenu) { <col class=\"lt-col-menu\" /> }\n </colgroup>\n <thead class=\"lt-head\">\n <tr cdkDropList cdkDropListOrientation=\"horizontal\" (cdkDropListDropped)=\"onReorder($event)\">\n @if (!options.noSelect) {\n <th class=\"lt-select-cell\">\n <div\n class=\"lt-select-all\"\n [class.checked]=\"allToggled\"\n [class.indeterminate]=\"someSelected\"\n (click)=\"toggleAll()\"\n id=\"SelectAllRows\"\n ></div>\n </th>\n }\n @for (col of visibleColumns; track trackCol($index, col)) {\n <th\n cdkDrag\n [cdkDragDisabled]=\"col.reorderable === false\"\n class=\"lt-th\"\n [ngClass]=\"col.cellClass\"\n id=\"Header_{{ col.key }}\"\n >\n <lib-list-header-cell\n [column]=\"col\"\n [sortDir]=\"col.sortDir\"\n (sortChanged)=\"onHeaderSort($event)\"\n (hideColumn)=\"hideColumn($event)\"\n ></lib-list-header-cell>\n @if (col.resizable !== false) {\n <span class=\"lt-resize\" (pointerdown)=\"startResize(col, $event)\"></span>\n }\n </th>\n }\n @if (!options.noMenu) {\n <th class=\"lt-menu-cell\">\n <div class=\"lt-header-menu-trigger\" (click)=\"openHeaderActionMenu($event)\" id=\"ColumnMenuHeader\">\n ⋮\n </div>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of rowData; track trackRow($index, row); let i = $index) {\n <tr\n class=\"lt-row\"\n [class.lt-row-odd]=\"i % 2 === 1\"\n [class.lt-row-selected]=\"row.selected\"\n [class.row-invalid]=\"row.invalid\"\n [class.row-copied]=\"row.copied\"\n >\n @if (!options.noSelect) {\n <td class=\"lt-select-cell\">\n <lib-select-cell [row]=\"row\" [toggleItem]=\"toggleItem\"></lib-select-cell>\n </td>\n }\n @for (col of visibleColumns; track trackCol($index, col)) {\n <td\n class=\"lt-cell\"\n [ngClass]=\"cellClass(col)\"\n (click)=\"onCellClick(col, row, i)\"\n (mouseenter)=\"onCellHover(col, row, i, $event)\"\n (mouseleave)=\"onCellLeave()\"\n >\n @switch (renderMode(col)) {\n @case ('component') {\n <ng-container *ngComponentOutlet=\"col.cell; inputs: cellInputs(col, row, i)\"></ng-container>\n }\n @case ('html') {\n <span class=\"lt-cell-html\" [innerHTML]=\"cellHtml(col, row, i)\"></span>\n }\n @default {\n <span class=\"lt-cell-text\">{{ cellText(col, row, i) }}</span>\n }\n }\n </td>\n }\n @if (!options.noMenu) {\n <td class=\"lt-menu-cell\">\n @if (row.actionList?.length) {\n <button\n type=\"button\"\n class=\"lt-row-menu-trigger\"\n (click)=\"$event.stopPropagation(); openActionMenu($event, row)\"\n attr.id=\"RowMenu_{{ row.id }}\"\n aria-label=\"Row actions\"\n >⋮</button>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n @if (!isLoading && filterApplied && (!rowData || rowData.length === 0)) {\n <div class=\"no-rows-message\">No Rows To Show</div>\n }\n </div>\n\n <div class=\"lt-footer\">\n <div class=\"lt-footer-count\">\n Showing <span id=\"Start\">{{ startCount }}</span>–<span id=\"End\">{{ endCount }}</span>\n of <span id=\"Total\">{{ totalCount }}</span>\n </div>\n <div class=\"lt-footer-controls\">\n <div class=\"lt-rpp\">\n <span class=\"lt-rpp-label\">Rows per page</span>\n <select\n class=\"lt-rpp-select\"\n [disabled]=\"filtering\"\n [value]=\"pageSize\"\n (change)=\"onPageSizeChange(+$any($event.target).value)\"\n aria-label=\"Rows per page\"\n >\n @for (opt of pageSizeOptions; track opt) {\n <option [value]=\"opt\">{{ opt }}</option>\n }\n </select>\n </div>\n <div class=\"lt-pager\">\n <button type=\"button\" class=\"lt-page-btn icon-prev\" [disabled]=\"prevDisabled\" (click)=\"prevPage()\" aria-label=\"Previous page\"></button>\n @if (!cursorPager) {\n @for (p of pageWindow; track $index) {\n @if (p === 0) {\n <span class=\"lt-page-gap\">…</span>\n } @else {\n <button\n type=\"button\"\n class=\"lt-page-num\"\n [class.is-current]=\"p === currentPageNum\"\n (click)=\"goToPage(p)\"\n >{{ p }}</button>\n }\n }\n }\n <button type=\"button\" class=\"lt-page-btn icon-next\" [disabled]=\"nextDisabled\" (click)=\"nextPage()\" aria-label=\"Next page\"></button>\n </div>\n </div>\n </div>\n\n <!-- header action menu -->\n <lib-list-menu\n menuId=\"HeaderActionMenu\"\n [open]=\"openHeaderMenu\"\n [items]=\"headerMenuItems\"\n [left]=\"menuLeft\"\n [top]=\"menuTop\"\n (itemClick)=\"onHeaderMenuClick($event)\"\n (closed)=\"closeHeaderActionMenu()\"\n ></lib-list-menu>\n\n <!-- row action menu -->\n <lib-list-menu\n menuId=\"RowActionMenu\"\n [open]=\"openMenu\"\n [items]=\"rowMenuItems\"\n [left]=\"menuLeft\"\n [top]=\"menuTop\"\n (itemClick)=\"onRowMenuClick($event)\"\n (closed)=\"closeActionMenu()\"\n ></lib-list-menu>\n </div>\n} @else {\n <lib-no-items\n (clickEmit)=\"openCreate()\"\n [image]=\"noItemsImage\"\n [isEmpty]=\"!rowData || rowData.length === 0\"\n [isLoading]=\"isLoading\"\n [typeName]=\"entityTypeLabel\"\n [hasAdd]=\"showNoItemsAdd\"\n [readonly]=\"noItemsReadonly\"\n [accessDenied]=\"accessDenied\"\n ></lib-no-items>\n}\n\n@if (hoverTooltip) {\n <div class=\"lt-tooltip\" [ngStyle]=\"{ left: hoverTooltip.left + 'px', top: hoverTooltip.top + 'px' }\">\n <ng-container *ngComponentOutlet=\"hoverTooltip.component; inputs: hoverTooltip.inputs\"></ng-container>\n </div>\n}\n", styles: [":host{display:flex;flex-direction:column;width:100%;height:100%}.lt-columns-btn,.lt-refresh-btn,.lt-filter-more-btn{display:inline-flex;align-items:center;gap:var(--lt-control-gap);height:var(--lt-toolbar-height);padding:0 var(--lt-control-padding-x);font-family:var(--lt-font);font-size:var(--lt-control-font-size);font-weight:var(--lt-control-font-weight);color:var(--lt-cell-text);background:var(--lt-control-bg);border:var(--inputBorderWidth) solid var(--lt-control-border, var(--lt-border));border-radius:var(--lt-radius);cursor:pointer;white-space:nowrap;transition:border-color .15s,background .15s,color .15s}.lt-columns-btn svg,.lt-refresh-btn svg,.lt-filter-more-btn svg{display:block}.lt-columns-btn:hover,.lt-refresh-btn:hover,.lt-filter-more-btn:hover,.is-open.lt-columns-btn,.is-open.lt-refresh-btn,.is-open.lt-filter-more-btn,.is-on.lt-columns-btn,.is-on.lt-refresh-btn,.is-on.lt-filter-more-btn{border-color:var(--lt-link);color:var(--lt-link)}.lt-columns-count,.lt-filter-more-count{display:inline-flex;align-items:center;justify-content:center;min-width:1.125rem;height:1.125rem;padding:0 .3125rem;font-size:.6875rem;font-weight:700;color:var(--lt-control-bg);background:var(--lt-link);border-radius:.5625rem}.lt-container{display:flex;position:relative;height:calc(100% - var(--lt-container-reserve, 5.625rem));width:100%;flex-direction:column}.lt-scroll{position:relative;z-index:1;width:100%;flex:0 1 auto;min-height:0;overflow:auto;background-color:var(--lt-bg)}.lt-scroll .no-rows-message{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:var(--lt-cell-text);font-size:.875rem;pointer-events:none}.lt-table{width:100%;border-collapse:collapse;table-layout:fixed;font-family:var(--lt-font);font-size:.8125rem;color:var(--lt-cell-text)}.lt-head{position:sticky;top:0;z-index:10}.lt-head th{position:relative;box-sizing:border-box;height:2.75rem;padding:0 .3125rem 0 .625rem;text-align:left;vertical-align:middle;background-color:var(--lt-header-bg);border-bottom:1px solid var(--lt-header-underline);white-space:nowrap;-webkit-user-select:none;user-select:none}.lt-head th.lt-th{border-right:1px solid var(--lt-border)}.lt-head .lt-select-cell,.lt-head .lt-menu-cell{width:3.75rem;padding:0}.lt-resize{position:absolute;right:0;top:50%;transform:translateY(-50%);width:.625rem;height:.875rem;cursor:col-resize}.lt-resize:before,.lt-resize:after{content:\"\";position:absolute;top:0;height:100%;width:1px;background:transparent;transition:background .15s}.lt-resize:before{right:.25rem}.lt-resize:after{right:.125rem}.lt-resize:hover:before,.lt-resize:hover:after{background:var(--lt-icon)}.lt-head th:hover .lt-resize:before,.lt-head th:hover .lt-resize:after{background:var(--lt-border)}.lt-select-all{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);box-sizing:border-box;width:1rem;height:1rem;border:1px solid var(--lt-control-border, var(--lt-border));border-radius:.25rem;background:var(--lt-control-bg);background-repeat:no-repeat;background-position:center center;cursor:pointer;transition:border-color .12s,background-color .12s}.lt-select-all:hover{border-color:var(--lt-link)}.lt-select-all.checked{background-color:var(--lt-link);border-color:var(--lt-link);background-size:.75rem;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' d='M2.5 7.6 5.7 10.8 11.5 3.6'/%3E%3C/svg%3E\")}.lt-select-all.indeterminate{background-color:var(--lt-link);border-color:var(--lt-link);background-image:linear-gradient(#fff,#fff);background-size:.5rem .125rem}.lt-header-menu-trigger{display:flex;align-items:center;justify-content:center;height:100%;font-size:1.25rem;color:var(--lt-icon);cursor:pointer}.lt-header-menu-trigger:hover{color:var(--lt-icon-active)}.lt-row-menu-trigger{display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;padding:0;font-size:1.25rem;line-height:1;color:var(--lt-icon);background:transparent;border:none;border-radius:var(--lt-radius);cursor:pointer;transition:color .15s,background .15s}.lt-row-menu-trigger:hover{color:var(--lt-icon-active);background:var(--lt-row-hover)}.cdk-drag-preview{box-sizing:border-box;background-color:var(--lt-header-bg);color:var(--lt-header-text);box-shadow:var(--shadowLarge);padding:0 .625rem;display:flex;align-items:center;border-radius:var(--lt-radius)}.cdk-drag-placeholder{opacity:.3}.cdk-drag-animating{transition:transform .2s cubic-bezier(0,0,.2,1)}.lt-row{height:var(--lt-row-height);background-color:var(--lt-row-bg);color:var(--lt-cell-text)}.lt-row td{border-bottom:1px solid var(--lt-border)}.lt-row.lt-row-odd{background-color:var(--lt-row-alt-bg)}.lt-row:hover{background-color:var(--lt-row-hover)}.lt-row.lt-row-selected{background-color:var(--lt-row-selected)}.lt-row.lt-row-selected:hover{background-color:var(--lt-row-hover)}.lt-row.row-invalid{background-color:var(--invalid)!important}.lt-row.row-copied{background-color:var(--copiedRow)!important}.lt-cell{height:var(--lt-row-height);padding:0 .625rem 0 1.25rem;text-align:left;vertical-align:middle;border:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;-webkit-user-select:text;user-select:text}.lt-cell-text{display:inline-block;overflow:hidden;text-overflow:ellipsis;max-width:100%;vertical-align:middle}.lt-cell.lt-cell-center{text-align:center}.lt-badge-cell .lt-cell-text{padding:.1875rem .5rem;font-size:.75rem;font-weight:600;line-height:1.2;color:var(--lt-cell-text);background:color-mix(in srgb,var(--lt-border) 45%,transparent);border:1px solid var(--lt-border);border-radius:999px}.lt-badge-cell .lt-cell-text:empty{display:none}.lt-select-cell,.lt-menu-cell{width:3.75rem;padding:0;text-align:center;vertical-align:middle;overflow:visible;position:relative}.lt-toolbar{display:flex;align-items:center;justify-content:space-between;gap:.75rem;margin:var(--lt-toolbar-margin-y, 0) 0;padding:0 0 var(--lt-toolbar-pad-bottom, .625rem);min-height:var(--lt-toolbar-height);position:relative;z-index:30}.lt-toolbar-left{display:flex;align-items:center;gap:.5rem;flex:1 1 auto;min-width:0;flex-wrap:nowrap}.lt-filter-zone{display:flex;align-items:center;flex-wrap:nowrap;gap:.5rem;flex:0 1 auto;min-width:0}.lt-filters{display:flex;align-items:center;flex-wrap:nowrap;gap:.5rem;min-width:0;flex:0 1 auto;overflow:hidden}.lt-filter-item{display:inline-flex;flex:0 0 auto}.lt-filter-more{position:relative;flex:0 0 auto}.lt-filter-more-btn{gap:.375rem;padding:0 .625rem}.lt-filter-more-btn .lt-filter-more-icon{display:inline-flex}.lt-filter-overflow{position:absolute;top:calc(100% + .25rem);right:0;z-index:1000;min-width:15rem;max-width:min(22rem,90vw);display:flex;flex-direction:column;gap:.5rem;padding:.625rem;background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);box-shadow:var(--shadowLarge);animation:lt-chooser-in .12s ease-out}.lt-filter-overflow-title{font-family:var(--lt-font);font-size:.6875rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--groupText)}.lt-filter-overflow-row{display:flex}.lt-filter-overflow-row lib-list-filter-cell,.lt-filter-overflow-row .lt-filter-item{flex:1 1 auto;min-width:0}.lt-toolbar-right{display:flex;align-items:center;gap:.75rem;flex:0 0 auto}.lt-divider{flex:0 0 auto;width:1px;height:1.5rem;background:var(--lt-border)}.lt-search{position:relative;display:flex;align-items:center;width:18rem;max-width:40vw;flex:0 1 18rem}.lt-search-icon{position:absolute;left:.625rem;display:block;color:var(--lt-icon);pointer-events:none}.lt-search-input{width:100%;height:var(--lt-toolbar-height);padding:0 .75rem 0 1.75rem;font-family:var(--lt-font);font-size:.8125rem;color:var(--lt-cell-text);background:var(--lt-control-bg);border:var(--inputBorderWidth) solid var(--lt-control-border, var(--lt-border));border-radius:var(--lt-radius);outline:none;transition:border-color .15s,box-shadow .15s}.lt-search-input::placeholder{color:var(--placeholder)}.lt-search-input:focus{border-color:var(--lt-link);box-shadow:0 0 0 .1875rem color-mix(in srgb,var(--lt-link) 18%,transparent)}.lt-count{font-size:.8125rem;color:var(--groupText);white-space:nowrap}.lt-count .lt-count-of{color:var(--groupText)}.lt-pager{display:flex;align-items:center;gap:.25rem}.lt-page-btn{display:inline-flex;align-items:center;justify-content:center;width:var(--lt-toolbar-height);height:var(--lt-toolbar-height);color:var(--lt-icon);background:var(--lt-control-bg);border:var(--inputBorderWidth) solid var(--lt-control-border, var(--lt-border));border-radius:var(--lt-radius);cursor:pointer;font-size:.9375rem;transition:border-color .15s,color .15s}.lt-page-btn:not(:disabled):hover{border-color:var(--lt-link);color:var(--lt-link)}.lt-page-btn:disabled{opacity:.4;cursor:default}.lt-refresh-btn{padding:0;width:var(--lt-toolbar-height);justify-content:center}.lt-refresh-btn:disabled{opacity:.5;cursor:default;border-color:var(--lt-border);color:var(--lt-cell-text)}.lt-columns{position:relative;flex:0 0 auto}.lt-column-chooser{position:absolute;top:calc(100% + .25rem);right:0;z-index:1000;width:15rem;max-height:calc(100vh - 9rem);display:flex;flex-direction:column;background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);box-shadow:var(--shadowLarge);overflow:hidden;animation:lt-chooser-in .12s ease-out}@keyframes lt-chooser-in{0%{opacity:0;transform:translateY(-.25rem)}to{opacity:1;transform:translateY(0)}}.lt-chooser-header{flex:0 0 auto;display:flex;flex-direction:column;padding:.625rem .75rem .5rem;border-bottom:1px solid var(--lt-border)}.lt-chooser-title{font-size:.8125rem;font-weight:700;color:var(--lt-cell-text)}.lt-chooser-subtitle{font-size:.6875rem;color:var(--groupText)}.lt-chooser-list{flex:1 1 auto;list-style:none;margin:0;padding:.375rem .5rem;min-height:0;overflow-y:auto}.lt-chooser-row{display:flex;align-items:center;justify-content:space-between;min-height:2.5rem;padding:.5rem;border-radius:var(--lt-radius);background:var(--lt-control-bg)}.lt-chooser-row:hover{background:var(--lt-row-hover)}.lt-chooser-row:hover .lt-chooser-handle{opacity:1}.lt-chooser-toggle{display:flex;align-items:center;gap:.625rem;flex:1 1 auto;min-width:0;padding:0;background:transparent;border:none;font:inherit;font-size:.875rem;color:var(--lt-cell-text);text-align:left;cursor:pointer}.lt-chooser-toggle:disabled{cursor:default;opacity:.5}.lt-chooser-box{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;width:1rem;height:1rem;border:.09375rem solid var(--lt-control-border, var(--lt-border));border-radius:.25rem;color:var(--lt-control-bg);background:var(--lt-control-bg);transition:background .12s,border-color .12s}.lt-chooser-toggle.checked .lt-chooser-box{background:var(--lt-link);border-color:var(--lt-link)}.lt-chooser-toggle:not(:disabled):hover .lt-chooser-box{border-color:var(--lt-link)}.lt-chooser-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.lt-chooser-default-tag{flex:0 0 auto;margin-left:.375rem;font-size:.6875rem;font-weight:400;font-style:italic;color:var(--groupText);white-space:nowrap}.lt-chooser-handle{flex:0 0 auto;display:inline-flex;align-items:center;color:var(--lt-icon);cursor:grab;padding-left:.5rem;-webkit-user-select:none;user-select:none}.lt-chooser-handle:active{cursor:grabbing}.lt-chooser-footer{flex:0 0 auto;padding:.5rem .75rem;border-top:1px solid var(--lt-border)}.lt-chooser-reset{width:100%;height:1.875rem;font-size:.75rem;font-weight:600;color:var(--lt-link);background:transparent;border:1px solid var(--lt-border);border-radius:var(--lt-radius);cursor:pointer}.lt-chooser-reset:disabled{color:var(--groupText);cursor:default;opacity:.6}.lt-chooser-reset:not(:disabled):hover{border-color:var(--lt-link)}.lt-footer{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;padding:.625rem .125rem 0;font-family:var(--lt-font);font-size:.8125rem;color:var(--groupText)}.lt-footer-count{white-space:nowrap}.lt-footer-count span{color:var(--lt-cell-text);font-weight:600}.lt-footer-controls{display:flex;align-items:center;gap:1.25rem;flex-wrap:nowrap}.lt-rpp{display:inline-flex;align-items:center;gap:.5rem;white-space:nowrap}.lt-rpp-label{text-transform:none;font-weight:400;color:var(--groupText)}.lt-rpp-select{width:auto;min-width:4rem;height:var(--lt-toolbar-height);padding:0 1.75rem 0 .625rem;font-family:var(--lt-font);font-size:.8125rem;color:var(--lt-cell-text);background-color:var(--lt-control-bg);background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%236b7280' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='M3 4.5 6 7.5 9 4.5'/%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right .5rem center;border:var(--inputBorderWidth) solid var(--lt-control-border, var(--lt-border));border-radius:var(--lt-radius);appearance:none;-webkit-appearance:none;cursor:pointer}.lt-rpp-select:focus{outline:none;border-color:var(--lt-link)}.lt-page-num{display:inline-flex;align-items:center;justify-content:center;min-width:var(--lt-toolbar-height);height:var(--lt-toolbar-height);padding:0 .5rem;font-family:var(--lt-font);font-size:.8125rem;font-weight:600;color:var(--lt-cell-text);background:var(--lt-control-bg);border:var(--inputBorderWidth) solid var(--lt-control-border, var(--lt-border));border-radius:var(--lt-radius);cursor:pointer;transition:border-color .15s,color .15s,background .15s}.lt-page-num:hover{border-color:var(--lt-link);color:var(--lt-link)}.lt-page-num.is-current{color:#fff;background:var(--lt-link);border-color:var(--lt-link);cursor:default}.lt-page-gap{display:inline-flex;align-items:center;justify-content:center;min-width:1.25rem;color:var(--groupText)}.lt-tooltip{position:fixed;z-index:1100;pointer-events:none;animation:lt-tooltip-in .12s ease-out}@keyframes lt-tooltip-in{0%{opacity:0;transform:translateY(-.1875rem)}to{opacity:1;transform:translateY(0)}}\n"] }]
|
|
13922
|
+
args: [{ selector: 'lib-list-table', standalone: false, providers: [ListTableService], template: "@if (showTable && !accessDenied) {\n <div class=\"lt-container\">\n <div class=\"lt-toolbar\">\n <div class=\"lt-toolbar-left\">\n <div class=\"lt-search\">\n <svg class=\"lt-search-icon\" viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"4.3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"/>\n <line x1=\"10.4\" y1=\"10.4\" x2=\"14.6\" y2=\"14.6\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n <input\n class=\"lt-search-input\"\n id=\"SearchFilter\"\n type=\"text\"\n [placeholder]=\"'Search ' + (entityTypeLabel || 'items')\"\n [(ngModel)]=\"searchString\"\n (keyup)=\"onSearchInput()\"\n />\n </div>\n @if (filterableColumns.length) {\n <div class=\"lt-filter-zone\" #filterZone>\n <div class=\"lt-filters\" #filtersRow>\n @for (col of visibleFilterColumns; track col.key) {\n <span class=\"lt-filter-item\" [attr.data-filter-key]=\"col.key\">\n <lib-list-filter-cell [column]=\"col\"></lib-list-filter-cell>\n </span>\n }\n </div>\n @if (overflowFilterColumns.length) {\n <div class=\"lt-filter-more\">\n <button\n type=\"button\"\n class=\"lt-filter-more-btn\"\n [class.is-on]=\"hiddenActiveCount > 0\"\n [class.is-open]=\"showFilterOverflow\"\n (click)=\"toggleFilterOverflow($event)\"\n aria-haspopup=\"true\"\n [attr.aria-expanded]=\"showFilterOverflow\"\n [attr.aria-label]=\"overflowFilterColumns.length + ' more filters'\"\n id=\"FilterOverflowButton\"\n >\n <span class=\"lt-filter-more-icon\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\" width=\"14\" height=\"14\"><path fill=\"currentColor\" d=\"M2 3h12l-4.6 5.6v4l-2.8 1.4v-5.4z\"/></svg>\n </span>\n <span class=\"lt-filter-more-label\">More</span>\n <span class=\"lt-filter-more-count\">{{ overflowFilterColumns.length }}</span>\n </button>\n @if (showFilterOverflow) {\n <div class=\"lt-filter-overflow\" (clickOutside)=\"closeFilterOverflow($event)\">\n <div class=\"lt-filter-overflow-title\">Filters</div>\n @for (col of overflowFilterColumns; track col.key) {\n <div class=\"lt-filter-overflow-row\" [class.is-active]=\"isFilterActive(col)\">\n <lib-list-filter-cell [column]=\"col\"></lib-list-filter-cell>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n <!-- Consumer-supplied toolbar controls (e.g. page-specific filters), rendered inline beside search. -->\n <ng-content select=\"[toolbar-filters]\"></ng-content>\n </div>\n <div class=\"lt-toolbar-right\">\n <ng-template #refreshIcon>\n <svg viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" d=\"M13.4 8a5.4 5.4 0 1 1-1.5-3.8\"/>\n <path fill=\"currentColor\" d=\"M13.9 2.1l.5 3.2-3.2-.5z\"/>\n </svg>\n </ng-template>\n <button\n type=\"button\"\n class=\"lt-refresh-btn\"\n (click)=\"refresh()\"\n [disabled]=\"filtering\"\n aria-label=\"Refresh\"\n title=\"Refresh\"\n id=\"RefreshTableButton\"\n >\n <ng-container [ngTemplateOutlet]=\"refreshIcon\"></ng-container>\n </button>\n <lib-list-table-auto-refresh [loading]=\"filtering\" (refresh)=\"refresh()\"></lib-list-table-auto-refresh>\n <div class=\"lt-columns\">\n <button\n type=\"button\"\n class=\"lt-columns-btn\"\n [class.is-on]=\"hiddenColumnCount > 0\"\n [class.is-open]=\"showColumnChooser\"\n (click)=\"toggleColumnChooser($event)\"\n aria-haspopup=\"true\"\n [attr.aria-expanded]=\"showColumnChooser\"\n id=\"ColumnChooserButton\"\n >\n <svg viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\">\n <path fill=\"currentColor\" d=\"M2 3.5h9v1.4H2zM2 7.3h6v1.4H2zM2 11.1h11v1.4H2z\"/>\n <circle cx=\"13\" cy=\"4.2\" r=\"1.7\" fill=\"currentColor\"/>\n <circle cx=\"10\" cy=\"8\" r=\"1.7\" fill=\"currentColor\"/>\n <circle cx=\"14.4\" cy=\"11.8\" r=\"1.7\" fill=\"currentColor\"/>\n </svg>\n <span>Columns</span>\n @if (hiddenColumnCount > 0) {\n <span class=\"lt-columns-count\">{{ hiddenColumnCount }}</span>\n }\n </button>\n @if (showColumnChooser) {\n <div class=\"lt-column-chooser\" (clickOutside)=\"closeColumnChooser()\">\n <div class=\"lt-chooser-header\">\n <span class=\"lt-chooser-title\">Columns</span>\n <span class=\"lt-chooser-subtitle\">Customize order and visibility</span>\n </div>\n @if (canSwitchTreeVariant && showTreeVariantToggle) {\n <div class=\"lt-chooser-view\" role=\"group\" aria-label=\"Expanded row layout\">\n <span class=\"lt-chooser-view-label\">Expanded rows</span>\n <div class=\"lt-chooser-view-toggle\">\n <button type=\"button\" class=\"lt-chooser-view-opt\" [class.active]=\"treeVariant === 'flat'\" (click)=\"setTreeVariant('flat')\">Flat</button>\n <button type=\"button\" class=\"lt-chooser-view-opt\" [class.active]=\"treeVariant === 'card'\" (click)=\"setTreeVariant('card')\">Nested</button>\n </div>\n </div>\n }\n <div class=\"lt-chooser-scroll\">\n <ul class=\"lt-chooser-list\" cdkDropList cdkDropListLockAxis=\"y\" (cdkDropListDropped)=\"chooserReorder($event)\">\n @for (col of chooserColumns; track col.key) {\n <li class=\"lt-chooser-row\" cdkDrag cdkDragLockAxis=\"y\" [cdkDragDisabled]=\"col.reorderable === false\"\n (cdkDragStarted)=\"onChooserDragStarted()\" (cdkDragEnded)=\"onChooserDragEnded()\">\n <ng-container *ngTemplateOutlet=\"chooserRowBody; context: { col: col }\"></ng-container>\n </li>\n }\n </ul>\n @if (canSwitchTreeVariant && childLevels.length) {\n <div class=\"lt-chooser-nested\">\n <button\n type=\"button\"\n class=\"lt-chooser-group\"\n (click)=\"toggleNestedGroup('__root')\"\n [attr.aria-expanded]=\"isNestedGroupOpen('__root')\"\n >\n <span class=\"lt-chooser-chevron\" [class.open]=\"isNestedGroupOpen('__root')\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\" width=\"11\" height=\"11\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 4l4 4-4 4\"/></svg>\n </span>\n <span class=\"lt-chooser-group-label\">Nested rows</span>\n </button>\n @if (isNestedGroupOpen('__root')) {\n @for (level of childLevels; track level) {\n <button\n type=\"button\"\n class=\"lt-chooser-group lt-chooser-group-sub\"\n (click)=\"toggleNestedGroup('lvl' + level)\"\n [attr.aria-expanded]=\"isNestedGroupOpen('lvl' + level)\"\n >\n <span class=\"lt-chooser-chevron\" [class.open]=\"isNestedGroupOpen('lvl' + level)\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\" width=\"11\" height=\"11\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 4l4 4-4 4\"/></svg>\n </span>\n <span class=\"lt-chooser-group-label\">Level {{ level }}</span>\n <span class=\"lt-chooser-group-hint\">{{ childLevelLabel(level) }}</span>\n </button>\n @if (isNestedGroupOpen('lvl' + level)) {\n <ul class=\"lt-chooser-list lt-chooser-sublist\" cdkDropList cdkDropListLockAxis=\"y\" (cdkDropListDropped)=\"chooserReorder($event, level)\">\n @for (col of allColumnsForLevel(level); track col.key) {\n <li class=\"lt-chooser-row\" cdkDrag cdkDragLockAxis=\"y\" [cdkDragDisabled]=\"col.reorderable === false\"\n (cdkDragStarted)=\"onChooserDragStarted()\" (cdkDragEnded)=\"onChooserDragEnded()\">\n <ng-container *ngTemplateOutlet=\"chooserRowBody; context: { col: col, level: level }\"></ng-container>\n </li>\n }\n </ul>\n }\n }\n }\n </div>\n }\n </div>\n <div class=\"lt-chooser-footer\">\n <button\n type=\"button\"\n class=\"lt-chooser-reset\"\n [disabled]=\"columnsAtDefault\"\n (click)=\"resetTableColumns()\"\n id=\"ResetColumnsButton\"\n >\n Reset to default\n </button>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- inner content of a Columns-chooser row, shared by the top-level and nested lists.\n The <li cdkDrag> wrapper stays inline in each list (above) so cdkDropList's content\n query still registers it as a draggable; only the body is shared here.\n `level` undefined targets the top-level columns, a number targets that nested depth. -->\n <ng-template #chooserRowBody let-col=\"col\" let-level=\"level\">\n <button\n type=\"button\"\n class=\"lt-chooser-toggle\"\n [class.checked]=\"!col.hidden\"\n [disabled]=\"col.hideable === false || isLastVisibleColumn(col, level)\"\n [attr.title]=\"isLastVisibleColumn(col, level) ? 'At least one column must stay visible' : null\"\n (click)=\"toggleColumnVisible(col, level)\"\n [attr.aria-pressed]=\"!col.hidden\"\n >\n <span class=\"lt-chooser-box\" aria-hidden=\"true\">\n <!-- always rendered: the check is white, so it stays invisible until the box\n turns blue when checked. Keeping it in the DOM means clicking to hide a\n column never detaches the click target, which would otherwise make the\n click-outside handler think the click was outside and close the menu. -->\n <svg viewBox=\"0 0 12 12\" width=\"10\" height=\"10\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M2 6.3 4.6 9 10 3\"/>\n </svg>\n </span>\n <span class=\"lt-chooser-text\">{{ col.label }}</span>\n @if (level == null && isDefaultHidden(col)) {\n <span class=\"lt-chooser-default-tag\">hidden by default</span>\n }\n </button>\n @if (col.reorderable !== false) {\n <!-- the whole row is the drag target (cdkDrag on the <li>); this is just the grip affordance -->\n <span class=\"lt-chooser-handle\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 10 16\" width=\"10\" height=\"15\" fill=\"currentColor\">\n <circle cx=\"3\" cy=\"3\" r=\"1.25\"/><circle cx=\"7\" cy=\"3\" r=\"1.25\"/>\n <circle cx=\"3\" cy=\"8\" r=\"1.25\"/><circle cx=\"7\" cy=\"8\" r=\"1.25\"/>\n <circle cx=\"3\" cy=\"13\" r=\"1.25\"/><circle cx=\"7\" cy=\"13\" r=\"1.25\"/>\n </svg>\n </span>\n }\n </ng-template>\n\n <div class=\"lt-scroll\" id=\"ItemTable\">\n <!-- expand/collapse control, reused by root rows and nested child rows -->\n <ng-template #treeToggle let-row=\"row\">\n @if (canExpand(row)) {\n <button\n type=\"button\"\n class=\"lt-tree-toggle\"\n [class.is-expanded]=\"row.__treeExpanded\"\n [class.is-loading]=\"row.__treeLoading\"\n [class.is-error]=\"row.__treeLoadError\"\n (click)=\"$event.stopPropagation(); toggleNode(row)\"\n [attr.aria-expanded]=\"!!row.__treeExpanded\"\n [attr.aria-busy]=\"!!row.__treeLoading\"\n [attr.title]=\"row.__treeLoadError ? 'Could not load children - click to retry' : null\"\n [attr.aria-label]=\"row.__treeExpanded ? 'Collapse row' : 'Expand row'\"\n >\n <svg class=\"lt-tree-chevron\" viewBox=\"0 0 16 16\" width=\"12\" height=\"12\" aria-hidden=\"true\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 4l4 4-4 4\"/>\n </svg>\n @if (row.__treeLoading) {\n <span class=\"lt-tree-spinner\" aria-hidden=\"true\"></span>\n }\n </button>\n } @else {\n <span class=\"lt-tree-spacer\" aria-hidden=\"true\"></span>\n }\n </ng-template>\n\n <!-- a single cell's content, reused across the fixed grid and the nested grid -->\n <ng-template #cellBody let-col=\"col\" let-row=\"row\" let-i=\"i\">\n @switch (renderMode(col)) {\n @case ('component') {\n <ng-container *ngComponentOutlet=\"col.cell; inputs: cellInputs(col, row, i)\"></ng-container>\n }\n @case ('html') {\n <span class=\"lt-cell-html\" [innerHTML]=\"cellHtml(col, row, i)\"></span>\n }\n @default {\n <span class=\"lt-cell-text\">{{ cellText(col, row, i) }}</span>\n }\n }\n </ng-template>\n\n <table class=\"lt-table\">\n <colgroup>\n @if (!options.noSelect) { <col class=\"lt-col-select\" /> }\n @for (col of visibleColumns; track trackCol($index, col)) {\n <col [style.width]=\"colWidth(col)\" />\n }\n @if (!options.noMenu) { <col class=\"lt-col-menu\" /> }\n </colgroup>\n <thead class=\"lt-head\">\n <tr cdkDropList cdkDropListOrientation=\"horizontal\" (cdkDropListDropped)=\"onReorder($event)\">\n @if (!options.noSelect) {\n <th class=\"lt-select-cell\">\n <div\n class=\"lt-select-all\"\n [class.checked]=\"allToggled\"\n [class.indeterminate]=\"someSelected\"\n (click)=\"toggleAll()\"\n id=\"SelectAllRows\"\n ></div>\n </th>\n }\n @for (col of visibleColumns; track trackCol($index, col)) {\n <th\n cdkDrag\n [cdkDragDisabled]=\"col.reorderable === false\"\n class=\"lt-th\"\n [class.lt-th-tree]=\"isTreeCell(col)\"\n [ngClass]=\"col.cellClass\"\n id=\"Header_{{ col.key }}\"\n >\n <lib-list-header-cell\n [column]=\"col\"\n [sortDir]=\"col.sortDir\"\n (sortChanged)=\"onHeaderSort($event)\"\n ></lib-list-header-cell>\n @if (col.resizable !== false) {\n <span class=\"lt-resize\" (pointerdown)=\"startResize(col, $event)\"></span>\n }\n </th>\n }\n @if (!options.noMenu) {\n <th class=\"lt-menu-cell\">\n <div class=\"lt-header-menu-trigger\" (click)=\"openHeaderActionMenu($event)\" id=\"ColumnMenuHeader\">\n ⋮\n </div>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of flatRows; track trackRow($index, row); let i = $index) {\n @if (isTreeMode && row.__treeLevel > 0 && hasChildColumns) {\n <!-- nested rows with their own per-level columns, laid out in a grid\n that spans the full table width (so they need not match the parent) -->\n @if (row.__treeFirstChild) {\n <tr class=\"lt-tree-subhead-row\">\n <td\n [attr.colspan]=\"treeSpanCount\"\n [style.--lt-tree-indent.rem]=\"treeIndentFor(row.__treeLevel)\"\n [style.--lt-tree-first-indent.rem]=\"treeFlatFirstIndentRem(row.__treeLevel)\"\n [style.--lt-tree-lead-offset]=\"treeLeadOffset(row.__treeLevel)\"\n [style.background-image]=\"treeAncestorRails(row.__treeLevel)\"\n >\n <div\n class=\"lt-tree-grid\"\n [style.grid-template-columns]=\"gridTemplate(row.__treeLevel)\"\n >\n @if (childSelectEnabled) {\n <span class=\"lt-tree-subhead-cell lt-tree-select-cell\"></span>\n }\n @for (col of columnsForLevel(row.__treeLevel); track col.key; let last = $last) {\n <span class=\"lt-tree-subhead-cell\" [class.lt-tree-indent-col]=\"isTreeColumn(col, row.__treeLevel)\" [ngClass]=\"cellClass(col)\">\n {{ col.label }}\n @if (!last && col.resizable !== false) {\n <span class=\"lt-resize lt-tree-resize\" (pointerdown)=\"startChildResize(col, row.__treeLevel, $event)\"></span>\n }\n </span>\n }\n </div>\n </td>\n </tr>\n }\n <tr\n class=\"lt-row lt-tree-child-row\"\n [class.lt-tree-last-child]=\"row.__treeLastChild\"\n [class.lt-row-selected]=\"row.selected\"\n [class.lt-row-expanded]=\"row.__treeExpanded\"\n >\n <td\n [attr.colspan]=\"treeSpanCount\"\n [style.--lt-tree-indent.rem]=\"treeIndentFor(row.__treeLevel)\"\n [style.--lt-tree-first-indent.rem]=\"treeFlatFirstIndentRem(row.__treeLevel)\"\n [style.--lt-tree-lead-offset]=\"treeLeadOffset(row.__treeLevel)\"\n [style.background-image]=\"treeAncestorRails(row.__treeLevel)\"\n >\n <div\n class=\"lt-tree-grid\"\n [style.grid-template-columns]=\"gridTemplate(row.__treeLevel)\"\n >\n @if (childSelectEnabled) {\n <div class=\"lt-tree-cellbox lt-tree-select-cell\">\n <lib-select-cell [row]=\"row\" [toggleItem]=\"toggleItem\"></lib-select-cell>\n </div>\n }\n @for (col of columnsForLevel(row.__treeLevel); track col.key) {\n <div\n class=\"lt-tree-cellbox\"\n [class.lt-tree-indent-col]=\"isTreeColumn(col, row.__treeLevel)\"\n [ngClass]=\"cellClass(col)\"\n (click)=\"onCellClick(col, row, i)\"\n (mouseenter)=\"onCellHover(col, row, i, $event)\"\n (mouseleave)=\"onCellLeave()\"\n >\n @if (isTreeColumn(col, row.__treeLevel) && showTreeLead(row)) {\n <span class=\"lt-tree-lead\">\n <ng-container *ngTemplateOutlet=\"treeToggle; context: {row: row}\"></ng-container>\n </span>\n }\n <ng-container *ngTemplateOutlet=\"cellBody; context: {col: col, row: row, i: i}\"></ng-container>\n </div>\n }\n </div>\n </td>\n </tr>\n } @else {\n <tr\n class=\"lt-row\"\n [class.lt-row-odd]=\"i % 2 === 1\"\n [class.lt-row-selected]=\"row.selected\"\n [class.lt-row-expanded]=\"row.__treeExpanded\"\n [class.row-invalid]=\"row.invalid\"\n [class.row-copied]=\"row.copied\"\n >\n @if (!options.noSelect) {\n <td class=\"lt-select-cell\">\n <lib-select-cell [row]=\"row\" [toggleItem]=\"toggleItem\"></lib-select-cell>\n </td>\n }\n @for (col of visibleColumns; track trackCol($index, col)) {\n <td\n class=\"lt-cell\"\n [class.lt-tree-cell]=\"isTreeCell(col)\"\n [ngClass]=\"cellClass(col)\"\n (click)=\"onCellClick(col, row, i)\"\n (mouseenter)=\"onCellHover(col, row, i, $event)\"\n (mouseleave)=\"onCellLeave()\"\n >\n @if (isTreeCell(col)) {\n <span class=\"lt-tree-cell-inner\">\n <span class=\"lt-tree-lead\" [style.margin-left.rem]=\"(row.__treeLevel || 0) * treeIndentRem\">\n <ng-container *ngTemplateOutlet=\"treeToggle; context: {row: row}\"></ng-container>\n </span>\n <ng-container *ngTemplateOutlet=\"cellBody; context: {col: col, row: row, i: i}\"></ng-container>\n </span>\n } @else {\n <ng-container *ngTemplateOutlet=\"cellBody; context: {col: col, row: row, i: i}\"></ng-container>\n }\n </td>\n }\n @if (!options.noMenu) {\n <td class=\"lt-menu-cell\">\n @if (row.actionList?.length) {\n <button\n type=\"button\"\n class=\"lt-row-menu-trigger\"\n (click)=\"$event.stopPropagation(); openActionMenu($event, row)\"\n attr.id=\"RowMenu_{{ row.id }}\"\n aria-label=\"Row actions\"\n >⋮</button>\n }\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n @if (!isLoading && filterApplied && (!rowData || rowData.length === 0)) {\n <div class=\"no-rows-message\">No Rows To Show</div>\n }\n </div>\n\n <div class=\"lt-footer\">\n <div class=\"lt-footer-count\">\n Showing <span id=\"Start\">{{ startCount }}</span>–<span id=\"End\">{{ endCount }}</span>\n of <span id=\"Total\">{{ totalCount }}</span>\n </div>\n <div class=\"lt-footer-controls\">\n <div class=\"lt-rpp\">\n <span class=\"lt-rpp-label\">Rows per page</span>\n <select\n class=\"lt-rpp-select\"\n [disabled]=\"filtering\"\n [value]=\"pageSize\"\n (change)=\"onPageSizeChange(+$any($event.target).value)\"\n aria-label=\"Rows per page\"\n >\n @for (opt of pageSizeOptions; track opt) {\n <option [value]=\"opt\">{{ opt }}</option>\n }\n </select>\n </div>\n <div class=\"lt-pager\">\n <button type=\"button\" class=\"lt-page-btn icon-prev\" [disabled]=\"prevDisabled\" (click)=\"prevPage()\" aria-label=\"Previous page\"></button>\n @if (!cursorPager) {\n @for (p of pageWindow; track $index) {\n @if (p === 0) {\n <span class=\"lt-page-gap\">…</span>\n } @else {\n <button\n type=\"button\"\n class=\"lt-page-num\"\n [class.is-current]=\"p === currentPageNum\"\n (click)=\"goToPage(p)\"\n >{{ p }}</button>\n }\n }\n }\n <button type=\"button\" class=\"lt-page-btn icon-next\" [disabled]=\"nextDisabled\" (click)=\"nextPage()\" aria-label=\"Next page\"></button>\n </div>\n </div>\n </div>\n\n <!-- header action menu -->\n <lib-list-menu\n menuId=\"HeaderActionMenu\"\n [open]=\"openHeaderMenu\"\n [items]=\"headerMenuItems\"\n [left]=\"menuLeft\"\n [top]=\"menuTop\"\n (itemClick)=\"onHeaderMenuClick($event)\"\n (closed)=\"closeHeaderActionMenu()\"\n ></lib-list-menu>\n\n <!-- row action menu -->\n <lib-list-menu\n menuId=\"RowActionMenu\"\n [open]=\"openMenu\"\n [items]=\"rowMenuItems\"\n [left]=\"menuLeft\"\n [top]=\"menuTop\"\n (itemClick)=\"onRowMenuClick($event)\"\n (closed)=\"closeActionMenu()\"\n ></lib-list-menu>\n </div>\n} @else {\n <lib-no-items\n (clickEmit)=\"openCreate()\"\n [image]=\"noItemsImage\"\n [isEmpty]=\"!rowData || rowData.length === 0\"\n [isLoading]=\"isLoading\"\n [typeName]=\"entityTypeLabel\"\n [hasAdd]=\"showNoItemsAdd\"\n [readonly]=\"noItemsReadonly\"\n [accessDenied]=\"accessDenied\"\n ></lib-no-items>\n}\n\n@if (hoverTooltip) {\n <div class=\"lt-tooltip\" [ngStyle]=\"{ left: hoverTooltip.left + 'px', top: hoverTooltip.top + 'px' }\">\n <ng-container *ngComponentOutlet=\"hoverTooltip.component; inputs: hoverTooltip.inputs\"></ng-container>\n </div>\n}\n", styles: [":host{display:flex;flex-direction:column;width:100%;height:100%}.lt-columns-btn,.lt-refresh-btn,.lt-filter-more-btn{display:inline-flex;align-items:center;gap:var(--lt-control-gap);height:var(--lt-toolbar-height);padding:0 var(--lt-control-padding-x);font-family:var(--lt-font);font-size:var(--lt-control-font-size);font-weight:var(--lt-control-font-weight);color:var(--lt-cell-text);background:var(--lt-control-bg);border:var(--lt-control-border-full);border-radius:var(--lt-radius);cursor:pointer;white-space:nowrap;transition:border-color .15s,background .15s,color .15s}.lt-columns-btn svg,.lt-refresh-btn svg,.lt-filter-more-btn svg{display:block}.lt-columns-btn:hover,.lt-refresh-btn:hover,.lt-filter-more-btn:hover,.is-open.lt-columns-btn,.is-open.lt-refresh-btn,.is-open.lt-filter-more-btn,.is-on.lt-columns-btn,.is-on.lt-refresh-btn,.is-on.lt-filter-more-btn{border-color:var(--lt-link);color:var(--lt-link)}.is-on.lt-columns-btn,.is-on.lt-refresh-btn,.is-on.lt-filter-more-btn{background:color-mix(in srgb,var(--lt-link) 8%,var(--lt-control-bg))}.lt-columns-count,.lt-filter-more-count{display:inline-flex;align-items:center;justify-content:center;min-width:1.125rem;height:1.125rem;padding:0 .3125rem;font-size:.6875rem;font-weight:700;color:var(--lt-control-bg);background:var(--lt-link);border-radius:.5625rem}.lt-container{display:flex;position:relative;height:calc(100% - var(--lt-container-reserve, 5.625rem));width:100%;flex-direction:column}.lt-scroll{position:relative;z-index:1;width:100%;flex:0 1 auto;min-height:0;overflow:auto;background-color:var(--lt-bg)}.lt-scroll .no-rows-message{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:var(--lt-cell-text);font-size:.875rem;pointer-events:none}.lt-table{width:100%;border-collapse:collapse;table-layout:fixed;font-family:var(--lt-font);font-size:.8125rem;color:var(--lt-cell-text)}.lt-head{position:sticky;top:0;z-index:10}.lt-head th{position:relative;box-sizing:border-box;height:2.6rem;padding:0 .3125rem 0 1.25rem;text-align:left;vertical-align:middle;background-color:var(--lt-header-bg);border-bottom:1px solid var(--lt-header-underline);white-space:nowrap;-webkit-user-select:none;user-select:none}.lt-head th.lt-th-tree{padding-left:2.75rem}.lt-head .lt-select-cell,.lt-head .lt-menu-cell{width:3.75rem;padding:0}.lt-resize{position:absolute;right:0;top:50%;transform:translateY(-50%);width:.75rem;height:2.25rem;cursor:col-resize}.lt-resize:before,.lt-resize:after{content:\"\";position:absolute;top:50%;height:1.25rem;transform:translateY(-50%);width:1px;background:color-mix(in srgb,var(--lt-border) 50%,var(--lt-icon));transition:background .15s}.lt-resize:before{right:.3125rem}.lt-resize:after{right:.125rem}.lt-resize:hover:before,.lt-resize:hover:after{background:color-mix(in srgb,var(--lt-icon) 72%,var(--lt-cell-text))}.lt-select-all{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);box-sizing:border-box;width:1rem;height:1rem;border:1px solid var(--lt-control-border, var(--lt-border));border-radius:.25rem;background:var(--lt-control-bg);background-repeat:no-repeat;background-position:center center;cursor:pointer;transition:border-color .12s,background-color .12s}.lt-select-all:hover{border-color:var(--lt-link)}.lt-select-all.checked{background-color:var(--lt-link);border-color:var(--lt-link);background-size:.75rem;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' d='M2.5 7.6 5.7 10.8 11.5 3.6'/%3E%3C/svg%3E\")}.lt-select-all.indeterminate{background-color:var(--lt-link);border-color:var(--lt-link);background-image:linear-gradient(#fff,#fff);background-size:.5rem .125rem}.lt-header-menu-trigger{display:flex;align-items:center;justify-content:center;height:100%;font-size:1.25rem;color:var(--lt-icon);cursor:pointer}.lt-header-menu-trigger:hover{color:var(--lt-icon-active)}.lt-row-menu-trigger{display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;padding:0;font-size:1.25rem;line-height:1;color:var(--lt-icon);background:transparent;border:none;border-radius:var(--lt-radius);cursor:pointer;transition:color .15s,background .15s}.lt-row-menu-trigger:hover{color:var(--lt-icon-active);background:var(--lt-row-hover)}.cdk-drag-preview{box-sizing:border-box;background-color:var(--lt-header-bg);color:var(--lt-header-text);box-shadow:var(--shadowLarge);padding:0 .625rem;display:flex;align-items:center;border-radius:var(--lt-radius)}.cdk-drag-placeholder{opacity:.3}.cdk-drag-animating{transition:transform .2s cubic-bezier(0,0,.2,1)}.lt-row{height:var(--lt-row-height);background-color:var(--lt-row-bg);color:var(--lt-cell-text)}.lt-row td{border-bottom:1px solid var(--lt-border)}.lt-row.lt-row-odd{background-color:var(--lt-row-alt-bg)}.lt-row:hover{background-color:var(--lt-row-hover)}.lt-row.lt-row-selected{background-color:var(--lt-row-selected)}.lt-row.lt-row-selected:hover{background-color:var(--lt-row-hover)}.lt-row.row-invalid{background-color:var(--invalid)!important}.lt-row.row-copied{background-color:var(--copiedRow)!important}.lt-cell{height:var(--lt-row-height);padding:0 .625rem 0 1.25rem;text-align:left;vertical-align:middle;border:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;-webkit-user-select:text;user-select:text}.lt-cell-text{display:inline-block;overflow:hidden;text-overflow:ellipsis;max-width:100%;vertical-align:middle}.lt-cell.lt-cell-center{text-align:center}.lt-badge-cell .lt-cell-text{padding:.1875rem .5rem;font-size:.75rem;font-weight:600;line-height:1.2;color:var(--lt-cell-text);background:color-mix(in srgb,var(--lt-border) 45%,transparent);border:1px solid var(--lt-border);border-radius:999px}.lt-badge-cell .lt-cell-text:empty{display:none}.lt-select-cell,.lt-menu-cell{width:3.75rem;padding:0;text-align:center;vertical-align:middle;overflow:visible;position:relative}.lt-tree-cell{padding-left:.625rem}.lt-tree-cell-inner{display:flex;align-items:center}.lt-tree-lead{display:inline-flex;align-items:center;flex:0 0 auto;margin-right:.375rem}.lt-tree-toggle{position:relative;display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;padding:0;color:var(--lt-icon);background:transparent;border:none;border-radius:50%;cursor:pointer;transition:color .15s,background .15s}.lt-tree-toggle:hover{color:var(--lt-link);background:color-mix(in srgb,var(--lt-link) 18%,transparent)}.lt-tree-chevron{display:block;width:13.8px;height:13.8px;transition:transform .15s ease}.lt-tree-toggle.is-expanded .lt-tree-chevron{transform:rotate(90deg)}.lt-tree-toggle.is-error .lt-tree-chevron{color:var(--lt-negative, #dc2626)}.lt-tree-spacer{display:inline-block;width:1.75rem;height:1.75rem}.lt-tree-spinner{position:absolute;top:50%;left:50%;box-sizing:border-box;width:1.875rem;height:1.875rem;margin:-.9375rem 0 0 -.9375rem;border:2px solid color-mix(in srgb,var(--lt-link) 25%,transparent);border-top-color:var(--lt-link);border-radius:50%;animation:loading .6s linear infinite;pointer-events:none}.lt-row-expanded>.lt-tree-cell .lt-cell-text{font-weight:600}.lt-tree-subhead-row>td,.lt-tree-child-row>td{padding:0 1rem 0 calc(var(--lt-card-inset, 4rem) + var(--lt-tree-indent, 0rem));background:transparent;border-bottom:none}.lt-tree-subhead-row,.lt-tree-child-row,.lt-tree-child-row:hover{background-color:var(--lt-tree-well, color-mix(in srgb, var(--lt-border) 22%, var(--lt-row-bg)))}.lt-tree-subhead-row>td{padding-top:1rem}.lt-tree-child-row.lt-tree-last-child>td{padding-bottom:1rem}.lt-tree-grid{display:grid;align-items:center;--lt-tree-col-gap: .5rem;column-gap:var(--lt-tree-col-gap);min-height:var(--lt-row-height);padding-left:.625rem;padding-right:.625rem;background:var(--lt-row-bg);border-left:1px solid var(--lt-tree-card-border, color-mix(in srgb, var(--lt-border) 70%, var(--lt-icon)));border-right:1px solid var(--lt-tree-card-border, color-mix(in srgb, var(--lt-border) 70%, var(--lt-icon)))}.lt-tree-child-row:hover .lt-tree-grid{background:var(--lt-row-hover)}.lt-tree-subhead-row .lt-tree-grid{min-height:2rem;background:var(--lt-header-bg);border-top:1px solid var(--lt-tree-card-border, color-mix(in srgb, var(--lt-border) 70%, var(--lt-icon)));border-top-left-radius:var(--lt-radius, 8px);border-top-right-radius:var(--lt-radius, 8px)}.lt-tree-child-row.lt-tree-last-child .lt-tree-grid{border-bottom:1px solid var(--lt-tree-card-border, color-mix(in srgb, var(--lt-border) 70%, var(--lt-icon)));border-bottom-left-radius:var(--lt-radius, 8px);border-bottom-right-radius:var(--lt-radius, 8px);box-shadow:var(--lt-tree-card-shadow, 0 2px 4px color-mix(in srgb, #000 10%, transparent))}.lt-tree-child-row:not(.lt-tree-last-child) .lt-tree-grid{border-bottom:1px solid color-mix(in srgb,var(--lt-border) 55%,transparent)}.lt-tree-subhead-cell{position:relative;padding:0 .3125rem;font-size:.6875rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--lt-header-text);overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.lt-tree-cellbox{display:flex;align-items:center;min-width:0;padding:0 .3125rem;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.lt-tree-cellbox .lt-cell-text{overflow:hidden;text-overflow:ellipsis}.lt-tree-grid>.lt-tree-select-cell{display:flex;align-items:center;justify-content:center;padding:0;overflow:visible}:host(.lt-tree-flat) .lt-tree-subhead-row,:host(.lt-tree-flat) .lt-tree-child-row,:host(.lt-tree-flat) .lt-tree-child-row:hover{background-color:transparent}:host(.lt-tree-flat) .lt-tree-subhead-row>td,:host(.lt-tree-flat) .lt-tree-child-row>td{padding:0}:host(.lt-tree-flat) .lt-tree-grid>.lt-tree-indent-col{padding-left:calc(var(--lt-tree-first-indent, 5.875rem) - var(--lt-tree-lead-offset, 0px))}:host(.lt-tree-flat) .lt-tree-grid{background:transparent;border-left:none;border-right:none;border-radius:0}:host(.lt-tree-flat) .lt-tree-subhead-row .lt-tree-grid{background:var(--lt-header-bg);border:none;border-bottom:1px solid var(--lt-border);border-radius:0}:host(.lt-tree-flat) .lt-tree-child-row .lt-tree-grid,:host(.lt-tree-flat) .lt-tree-child-row.lt-tree-last-child .lt-tree-grid{border-left:none;border-right:none;border-radius:0;box-shadow:none;border-bottom:1px solid color-mix(in srgb,var(--lt-border) 55%,transparent)}.lt-toolbar{display:flex;align-items:center;justify-content:space-between;gap:.75rem;margin:var(--lt-toolbar-margin-top, .75rem) 0 var(--lt-toolbar-margin-bottom, 0);padding:0 0 var(--lt-toolbar-pad-bottom, .625rem);min-height:var(--lt-toolbar-height);position:relative;z-index:30}.lt-toolbar-left{display:flex;align-items:center;gap:var(--lt-control-row-gap);flex:1 1 auto;min-width:0;flex-wrap:nowrap}.lt-filter-zone{display:flex;align-items:center;flex-wrap:nowrap;gap:var(--lt-control-row-gap);flex:0 1 auto;min-width:0}.lt-filters{display:flex;align-items:center;flex-wrap:nowrap;gap:var(--lt-control-row-gap);min-width:0;flex:0 1 auto;overflow:hidden}.lt-filter-item{display:inline-flex;flex:0 0 auto}.lt-filter-more{position:relative;flex:0 0 auto}.lt-filter-more-btn{gap:.375rem;padding:0 .625rem}.lt-filter-more-btn .lt-filter-more-icon{display:inline-flex}.lt-filter-overflow{position:absolute;top:calc(100% + .25rem);right:0;z-index:1000;min-width:15rem;max-width:min(22rem,90vw);display:flex;flex-direction:column;gap:.5rem;padding:.625rem;background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);box-shadow:var(--shadowLarge);animation:lt-chooser-in .12s ease-out}.lt-filter-overflow-title{font-family:var(--lt-font);font-size:.6875rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--groupText)}.lt-filter-overflow-row{display:flex}.lt-filter-overflow-row lib-list-filter-cell,.lt-filter-overflow-row .lt-filter-item{flex:1 1 auto;min-width:0}.lt-toolbar-right{display:flex;align-items:center;gap:var(--lt-control-row-gap);flex:0 0 auto}.lt-divider{flex:0 0 auto;width:1px;height:1.5rem;background:var(--lt-border)}.lt-search{position:relative;display:flex;align-items:center;width:18rem;max-width:40vw;flex:0 1 18rem}.lt-search-icon{position:absolute;left:.625rem;display:block;color:var(--lt-icon);pointer-events:none}.lt-search-input{width:100%;height:var(--lt-toolbar-height);padding:0 .75rem 0 1.75rem;font-family:var(--lt-font);font-size:.8125rem;color:var(--lt-cell-text);background:var(--lt-control-bg);border:var(--lt-control-border-full);border-radius:var(--lt-radius);outline:none;transition:border-color .15s,box-shadow .15s}.lt-search-input::placeholder{color:var(--placeholder)}.lt-search-input:focus{border-color:var(--lt-link);box-shadow:0 0 0 .1875rem color-mix(in srgb,var(--lt-link) 18%,transparent)}.lt-count{font-size:.8125rem;color:var(--groupText);white-space:nowrap}.lt-count .lt-count-of{color:var(--groupText)}.lt-pager{display:flex;align-items:center;gap:.25rem}.lt-page-btn{display:inline-flex;align-items:center;justify-content:center;width:var(--lt-toolbar-height);height:var(--lt-toolbar-height);color:var(--lt-icon);background:var(--lt-control-bg);border:var(--lt-control-border-full);border-radius:var(--lt-radius);cursor:pointer;font-size:.9375rem;transition:border-color .15s,color .15s}.lt-page-btn:not(:disabled):hover{border-color:var(--lt-link);color:var(--lt-link)}.lt-page-btn:disabled{opacity:.4;cursor:default}.lt-refresh-btn{padding:0;width:var(--lt-toolbar-height);justify-content:center}.lt-refresh-btn:disabled{opacity:.5;cursor:default;border-color:var(--lt-border);color:var(--lt-cell-text)}.lt-columns{position:relative;flex:0 0 auto}.lt-column-chooser{position:absolute;top:calc(100% + .25rem);right:0;z-index:1000;width:15rem;max-height:calc(100vh - 9rem);display:flex;flex-direction:column;background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);box-shadow:var(--shadowLarge);overflow:hidden;animation:lt-chooser-in .12s ease-out}@keyframes lt-chooser-in{0%{opacity:0;transform:translateY(-.25rem)}to{opacity:1;transform:translateY(0)}}.lt-chooser-header{flex:0 0 auto;display:flex;flex-direction:column;padding:.625rem .75rem .5rem;border-bottom:1px solid var(--lt-border)}.lt-chooser-title{font-size:.8125rem;font-weight:700;color:var(--lt-cell-text)}.lt-chooser-subtitle{font-size:.6875rem;color:var(--groupText)}.lt-chooser-view{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:.75rem;padding:.5rem .75rem;border-bottom:1px solid var(--lt-border)}.lt-chooser-view-label{font-size:.75rem;font-weight:600;color:var(--lt-cell-text)}.lt-chooser-view-toggle{display:flex;gap:.1875rem;padding:.1875rem;background:color-mix(in srgb,var(--lt-border) 30%,var(--lt-control-bg));border:1px solid var(--lt-border);border-radius:var(--lt-radius)}.lt-chooser-view-opt{padding:.25rem .625rem;font-family:var(--lt-font);font-size:.75rem;font-weight:500;color:var(--lt-cell-text);background:transparent;border:none;border-radius:calc(var(--lt-radius) - .0625rem);cursor:pointer}.lt-chooser-view-opt:hover:not(.active){color:var(--lt-link)}.lt-chooser-view-opt.active{color:var(--lt-link);background:var(--lt-control-bg);box-shadow:0 1px 2px color-mix(in srgb,var(--lt-cell-text) 14%,transparent)}.lt-chooser-scroll{flex:1 1 auto;min-height:0;overflow-y:auto}.lt-chooser-list{list-style:none;margin:0;padding:.375rem .5rem}.lt-chooser-nested{padding:0 .5rem .375rem;border-top:1px solid var(--lt-border)}.lt-chooser-group{display:flex;align-items:center;gap:.375rem;width:100%;min-height:2.25rem;padding:.375rem .25rem;font-family:var(--lt-font);font-size:.75rem;font-weight:600;color:var(--lt-cell-text);background:transparent;border:none;border-radius:var(--lt-radius);cursor:pointer;text-align:left}.lt-chooser-group:hover{background:var(--lt-row-hover)}.lt-chooser-group-sub{padding-left:1.25rem;font-weight:500}.lt-chooser-group-label{flex:0 0 auto}.lt-chooser-chevron{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:.875rem;color:var(--lt-icon);transition:transform .15s ease}.lt-chooser-chevron svg{display:block}.lt-chooser-chevron.open{transform:rotate(90deg)}.lt-chooser-group-hint{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.6875rem;font-weight:400;color:var(--groupText)}.lt-chooser-sublist{padding-left:1.75rem}.lt-chooser-row{display:flex;align-items:center;justify-content:space-between;min-height:2.5rem;padding:.5rem;border-radius:var(--lt-radius);background:var(--lt-control-bg);cursor:grab}.lt-chooser-row:active{cursor:grabbing}.lt-chooser-row.cdk-drag-disabled{cursor:default}.lt-chooser-row:hover{background:var(--lt-row-hover)}.lt-chooser-row:hover .lt-chooser-handle{opacity:1}.lt-chooser-toggle{display:flex;align-items:center;gap:.625rem;flex:1 1 auto;min-width:0;padding:0;background:transparent;border:none;font:inherit;font-size:.875rem;color:var(--lt-cell-text);text-align:left;cursor:pointer}.lt-chooser-toggle:disabled{cursor:default;opacity:.5}.lt-chooser-box{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;width:1rem;height:1rem;border:.09375rem solid var(--lt-control-border, var(--lt-border));border-radius:.25rem;color:var(--lt-control-bg);background:var(--lt-control-bg);transition:background .12s,border-color .12s}.lt-chooser-toggle.checked .lt-chooser-box{background:var(--lt-link);border-color:var(--lt-link)}.lt-chooser-toggle:not(:disabled):hover .lt-chooser-box{border-color:var(--lt-link)}.lt-chooser-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.lt-chooser-default-tag{flex:0 0 auto;margin-left:.375rem;font-size:.6875rem;font-weight:400;font-style:italic;color:var(--groupText);white-space:nowrap}.lt-chooser-handle{flex:0 0 auto;display:inline-flex;align-items:center;color:var(--lt-icon);cursor:grab;padding-left:.5rem;-webkit-user-select:none;user-select:none}.lt-chooser-handle:active{cursor:grabbing}.lt-chooser-footer{flex:0 0 auto;padding:.5rem .75rem;border-top:1px solid var(--lt-border)}.lt-chooser-reset{width:100%;height:1.875rem;font-size:.75rem;font-weight:600;color:var(--lt-link);background:transparent;border:1px solid var(--lt-border);border-radius:var(--lt-radius);cursor:pointer}.lt-chooser-reset:disabled{color:var(--groupText);cursor:default;opacity:.6}.lt-chooser-reset:not(:disabled):hover{border-color:var(--lt-link)}.lt-footer{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;padding:.625rem .125rem 0;font-family:var(--lt-font);font-size:.8125rem;color:var(--groupText)}.lt-footer-count{white-space:nowrap}.lt-footer-count span{color:var(--lt-cell-text);font-weight:600}.lt-footer-controls{display:flex;align-items:center;gap:1.25rem;flex-wrap:nowrap}.lt-rpp{display:inline-flex;align-items:center;gap:.5rem;white-space:nowrap}.lt-rpp-label{text-transform:none;font-weight:400;color:var(--groupText)}.lt-rpp-select{width:auto;min-width:4rem;height:var(--lt-toolbar-height);padding:0 1.75rem 0 .625rem;font-family:var(--lt-font);font-size:.8125rem;color:var(--lt-cell-text);background-color:var(--lt-control-bg);background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%236b7280' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='M3 4.5 6 7.5 9 4.5'/%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right .5rem center;border:var(--lt-control-border-full);border-radius:var(--lt-radius);appearance:none;-webkit-appearance:none;cursor:pointer}.lt-rpp-select:focus{outline:none;border-color:var(--lt-link)}.lt-page-num{display:inline-flex;align-items:center;justify-content:center;min-width:var(--lt-toolbar-height);height:var(--lt-toolbar-height);padding:0 .5rem;font-family:var(--lt-font);font-size:.8125rem;font-weight:600;color:var(--lt-cell-text);background:var(--lt-control-bg);border:var(--lt-control-border-full);border-radius:var(--lt-radius);cursor:pointer;transition:border-color .15s,color .15s,background .15s}.lt-page-num:hover{border-color:var(--lt-link);color:var(--lt-link)}.lt-page-num.is-current{color:#fff;background:var(--lt-link);border-color:var(--lt-link);cursor:default}.lt-page-gap{display:inline-flex;align-items:center;justify-content:center;min-width:1.25rem;color:var(--groupText)}.lt-tooltip{position:fixed;z-index:1100;pointer-events:none;animation:lt-tooltip-in .12s ease-out}@keyframes lt-tooltip-in{0%{opacity:0;transform:translateY(-.1875rem)}to{opacity:1;transform:translateY(0)}}\n"] }]
|
|
13103
13923
|
}], ctorParameters: () => [{ type: ListTableService }, { type: DataTableFilterService }, { type: i0.ElementRef }, { type: i0.NgZone }, { type: i1.DomSanitizer }], propDecorators: { tableId: [{
|
|
13104
13924
|
type: Input
|
|
13105
13925
|
}], columns: [{
|
|
@@ -13110,6 +13930,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
13110
13930
|
type: Input
|
|
13111
13931
|
}], options: [{
|
|
13112
13932
|
type: Input
|
|
13933
|
+
}], loadChildren: [{
|
|
13934
|
+
type: Input
|
|
13935
|
+
}], childColumnsByLevel: [{
|
|
13936
|
+
type: Input
|
|
13937
|
+
}], nodeToggled: [{
|
|
13938
|
+
type: Output
|
|
13113
13939
|
}], hasNext: [{
|
|
13114
13940
|
type: Input
|
|
13115
13941
|
}], hasPrev: [{
|
|
@@ -13144,6 +13970,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
13144
13970
|
type: Output
|
|
13145
13971
|
}], tableReady: [{
|
|
13146
13972
|
type: Output
|
|
13973
|
+
}], selectionChanged: [{
|
|
13974
|
+
type: Output
|
|
13147
13975
|
}], contextMenu: [{
|
|
13148
13976
|
type: ViewChild,
|
|
13149
13977
|
args: ['contextMenu']
|
|
@@ -13153,6 +13981,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
13153
13981
|
}], filtersRow: [{
|
|
13154
13982
|
type: ViewChild,
|
|
13155
13983
|
args: ['filtersRow']
|
|
13984
|
+
}], treeVariant: [{
|
|
13985
|
+
type: Input
|
|
13986
|
+
}], showTreeVariantToggle: [{
|
|
13987
|
+
type: Input
|
|
13988
|
+
}], treeRail: [{
|
|
13989
|
+
type: Input
|
|
13990
|
+
}], isFlatTree: [{
|
|
13991
|
+
type: HostBinding,
|
|
13992
|
+
args: ['class.lt-tree-flat']
|
|
13156
13993
|
}], initialPageSize: [{
|
|
13157
13994
|
type: Input
|
|
13158
13995
|
}] } });
|
|
@@ -16122,7 +16959,7 @@ class IdentitiesListPageComponent extends ListPageComponent {
|
|
|
16122
16959
|
return true;
|
|
16123
16960
|
}
|
|
16124
16961
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: IdentitiesListPageComponent, deps: [{ token: IdentitiesPageService }, { token: DataTableFilterService }, { token: i5.MatDialog }, { token: TabNameService }, { token: i4.Router }, { token: ConsoleEventsService }, { token: IDENTITY_EXTENSION_SERVICE }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
16125
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: IdentitiesListPageComponent, isStandalone: false, selector: "lib-identities-list", usesInheritance: true, ngImport: i0, template: "<div class=\"ziti-page-container ziti-identities-container lt-skin-page\">\n <lib-list-table-header\n [title]=\"title\"\n subtitle=\"Manage identities across the network\"\n createLabel=\"Create Identity\"\n infoText=\"Identities are the clients, services, and routers enrolled in this network.\"\n [tabs]=\"tabs\"\n [showAdd]=\"!itemsSelected\"\n [blockCreate]=\"headerBlockCreate\"\n [blockDelete]=\"headerBlockDelete\"\n (actionClicked)=\"headerActionClicked($event)\"\n >\n <span header-icon class=\"icon-identity\" aria-hidden=\"true\"></span>\n </lib-list-table-header>\n <ng-content select=\"[slot=list-page-subheader]\"></ng-content>\n <lib-list-table class=\"lt-skin\" [tableId]=\"tableId\" [initialPageSize]=\"initialPageSize\"\n [noItemsReadonly]=\"headerBlockCreate\"\n [accessDenied]=\"headerBlockRead\"\n [rowData]=\"rowData\"\n [isLoading]=\"isLoading\"\n [columns]=\"columnDefs\"\n (actionRequested)=\"tableAction($event)\"\n [startCount]=\"startCount\"\n [endCount]=\"endCount\"\n [totalCount]=\"totalCount\"\n [filterApplied]=\"filterApplied\"\n [menuItems]=\"svc.menuItems\"\n [headerActions]=\"svc.tableHeaderActions\"\n [noItemsImage]=\"'No_Clients'\"\n (tableReady)=\"tableReady($event)\"\n >\n </lib-list-table>\n</div>\n<lib-side-modal [(open)]=\"svc.sideModalOpen\" [showClose]=\"false\">\n @if (svc.modalType === 'overrides' && svc.sideModalOpen) {\n <lib-overrides\n [identity]=\"svc.selectedIdentity\"\n (close)=\"closeModal($event)\"\n ></lib-overrides>\n }\n</lib-side-modal>\n@if (isLoading) {\n <lib-loading-indicator [isLoading]=\"isLoading\"></lib-loading-indicator>\n}\n", styles: [".ziti-page-container .action{line-height:3.75rem;top:1.5625rem;right:1.5625rem;z-index:999}.ziti-identities-container ::ng-deep .zac-wrapper-container{height:0rem;left:-62499.9375rem;position:fixed}.ziti-identities-container ::ng-deep .zac-wrapper-container .action{display:none}.ziti-ag-grid{height:100%;position:relative;width:100%}.ziti-ag-grid .ziti-ag-grid-table{height:100%;width:100%}.ziti-ag-grid .ziti-ag-grid-table .ag-root-wrapper{border-bottom-style:none}.ziti-ag-grid .ziti-ag-grid-table .ag-cell{align-items:center;display:flex}.system-policies-toggle,.hidden-results-container{position:relative;right:0;display:flex;flex-direction:row;justify-content:center;align-items:flex-start;margin-top:.625rem;padding-left:1.25rem;border-radius:var(--inputBorderRadius);padding-bottom:0;padding-right:0;padding-top:0;flex-wrap:nowrap;flex:1 0 auto}.system-policies-toggle .toggle-text,.hidden-results-container .toggle-text{font-weight:600;font-size:.75rem}.system-policies-toggle .toggle-text a,.hidden-results-container .toggle-text a{cursor:pointer}.system-policies-toggle .toggle,.hidden-results-container .toggle{width:4.6875rem;margin-left:.625rem}.system-policies-toggle .toggle.on .switch,.hidden-results-container .toggle.on .switch{left:3.25rem}.system-policies-toggle .spinner,.hidden-results-container .spinner{display:inline-block;width:.625rem;height:.625rem;border-radius:50%;background:transparent;border-top:.125rem solid var(--tableText);border-right:.125rem solid var(--tableText);border-bottom:.125rem solid transparent;border-left:.125rem solid transparent;animation:loading .5s infinite linear;margin-left:.3125rem}.hidden-results-container.loading-results{opacity:.7}.nf-cell-vert-align,.ag-row .ag-cell{align-items:center;display:flex}.hidden-columns-list{align-items:center;display:flex;flex-direction:row;margin-left:.4375rem;min-height:1.875rem;flex-wrap:wrap;flex:0 1 auto}.hidden-columns-list.hidden-results{flex-wrap:nowrap;overflow:auto}.hidden-columns-list.hidden-results .hidden-column-item{flex:1 0 auto}.hidden-columns-list::-webkit-scrollbar{height:.875rem}.hidden-columns-list .hidden-column-item{align-items:center;background-color:var(--background);border:.125rem solid var(--background);border-radius:.75rem;cursor:pointer;color:var(----stroke);font-weight:600;font-family:Open Sans,sans-serif;display:flex;flex:0 1 auto;height:1.5625rem!important;margin-left:.625rem;margin-top:.3125rem;padding:.125rem .625rem .125rem .3125rem;position:relative;text-align:center;box-shadow:unset;transform:translateY(0)}.hidden-columns-list .ag-dnd-ghost:hover{border:.125rem solid var(--primaryColor)!important}.hidden-columns-list .ag-dnd-ghost:hover .ag-dnd-ghost-label,.hidden-columns-list .ag-dnd-ghost:hover .ag-dnd-ghost-icon .ag-icon-eye-slash{color:var(--ag-alpine-active-color, var(--primaryColor))}.hidden-columns-list .ag-dnd-ghost:hover .ag-dnd-ghost-icon .ag-icon-eye-slash:before{content:\"\\f113\"}.hidden-columns-list .ag-dnd-ghost-label{line-height:initial}::ng-deep .darkmode .ag-dnd-ghost-icon .ag-icon-eye-slash{color:#fff!important}.tMenu{transition-property:opacity;z-index:99999999999;height:fit-content}.tMenu.action-menu{position:fixed;width:10.9375rem}.tMenu .tActionRow{transition-property:opacity}.tMenu .tActionRow.has-icon{display:flex;flex-direction:row;align-items:center}.tMenu .tActionRow .v7Offline{background-color:var(--placeholder)}.tMenu .tActionRow .v7OnlineOffline{width:.875rem;height:.875rem;border-color:var(--placeholder)}.tMenu .tActionRow .v7OnlineOffline:hover{border-color:var(--placeholder)}.hidden-items-container{display:flex;flex-direction:row;width:100%;flex-wrap:nowrap;justify-content:space-between}.os-icon{width:1.4375rem;height:1.4375rem;background-size:1.4375rem 1.4375rem;display:inline-flex;margin-right:.5rem;margin-top:.3125rem;margin-bottom:.3125rem}::ng-deep .date-time-container{position:fixed}::ng-deep .date-time-container .p-calendar .p-inputtext{height:.0625rem;width:.0625rem;padding:0}::ng-deep .date-time-container .filter-button-container{height:3.125rem;display:flex;flex-direction:row;justify-content:center;align-items:center}::ng-deep .date-time-container .filter-button-container .toggleButton{padding-left:.3125rem;padding-right:.3125rem;width:unset}::ng-deep .date-time-container .p-calendar{height:1.875rem}::ng-deep .date-time-container .p-calendar .p-inputtext{height:1.875rem;border-top-left-radius:1.25rem;border-bottom-left-radius:1.25rem;text-indent:.3125rem}::ng-deep .date-time-container .p-calendar .p-button-icon-only{border-top-right-radius:1.25rem;border-bottom-right-radius:1.25rem}#TimeSearch{position:relative;float:left;display:inline-block;margin-left:.625rem;width:3.125rem;height:2.5rem;background-color:var(--primary)}#TimeSearch #TimeSearchList{width:2.75rem;height:0;position:absolute;top:0;left:-.125rem;overflow:hidden;transition:var(--transition);background-color:var(--menu);border-radius:.5rem;z-index:30}#TimeSearch #TimeSearchList .time{width:2.5rem;background-color:var(--background);padding-left:.5rem;padding-right:.5rem;border-radius:.5rem;line-height:1.625rem;font-size:.75rem;font-weight:700;text-align:center;margin-top:.125rem;margin-left:.125rem;left:-.125rem;top:-3.1875rem;cursor:pointer;transition:var(--transition)}#TimeSearch #TimeSearchList.open{top:-3.1875rem;width:2.75rem;height:14.125rem}#TimeSearch #TimeSelectButton{width:2.5rem;background-color:var(--background);padding-left:.5rem;padding-right:.5rem;border-radius:.5rem;line-height:1.625rem;text-align:center;font-size:.75rem;font-weight:700;margin-top:.4375rem;cursor:pointer;transition:var(--transition)}#TimeSearch #TimeSelectButton:hover,#TimeSearch #TimeSearchList .time:hover{background-color:var(--primaryColor);color:var(--white)}::ng-deep p-togglebutton .p-togglebutton.p-button{border-radius:var(--inputBorderRadius)!important;box-shadow:0 .3125rem 1.25rem #0000000d!important;margin-top:-.125rem!important}::ng-deep p-togglebutton .p-togglebutton.p-button:hover{filter:brightness(99%)!important;box-shadow:0 .3125rem 1.25rem #0000000d!important;transition:all .3s ease}::ng-deep p-togglebutton .p-togglebutton.p-button:active{filter:brightness(95%)!important;box-shadow:none!important;transform:translateY(.0625rem)!important;transition:all .3s ease}#TimeSearch #TimeSelectButton{margin-top:.25rem!important}::ng-deep .p-calendar .p-inputtext{height:2.3125rem}::ng-deep .p-inputtext{border-radius:var(--inputBorderRadius)}.calendar{display:inline-block;padding-left:.3125rem;float:left;padding-right:.625rem;margin-top:-.125rem}::ng-deep .p-datepicker:not(.p-datepicker-inline){background:var(--table);border:0 none;box-shadow:#091e4226 0 1.25rem 2rem -.5rem;border-radius:.75rem}::ng-deep .p-button.p-button-text{background-color:transparent;color:var(--primaryColor);border-color:transparent}::ng-deep .p-button.p-button-text:enabled:hover{background:var(--primaryColorShadowLight);color:var(--primaryColor);border-color:transparent}::ng-deep .p-datepicker table td>span.p-highlight{color:var(--tableText);background:var(--primaryColorShadowLight)}::ng-deep .p-inputtext:enabled:hover{border-color:var(--primaryColor)}::ng-deep .p-datepicker{padding:.5rem;padding-bottom:0;background:var(--table);color:var(--tableText);border:.0625rem solid var(--inputBorder);border-radius:.1875rem}::ng-deep .p-inputtext:enabled:focus{outline:0 none;outline-offset:0;box-shadow:0 0 0 1 var(--primaryColorShadowLight);border-color:var(--primaryColor)}::ng-deep .p-inputtext{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol;font-size:1rem;color:var(--tableText);background:var(--table);padding:.5rem;border:.0625rem solid var(--inputBorder);transition:background-color .2s,color .2s,border-color .2s,box-shadow .2s;-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:var(--inputBorderRadius)}::ng-deep .p-datepicker:not(.p-datepicker-inline) .p-datepicker-header{background:var(--table)}::ng-deep .p-datepicker .p-datepicker-header{padding:.5rem;color:var(--tableText);background:var(--table);font-weight:600;margin:0;border-bottom:.0625rem solid var(--inputBorder);border-top-right-radius:.75rem;border-top-left-radius:.75rem}::ng-deep .p-datepicker:not(.p-disabled) table td span:not(.p-highlight):not(.p-disabled):hover{background:#e9ecef;color:var(--table)}::ng-deep .p-datepicker .p-timepicker{border-top:.0625rem solid var(--background);padding:.5rem}::ng-deep .p-togglebutton.p-button{background:var(--background);border:.0625rem solid var(--inputBorder);color:var(--tableText);transition:background-color .2s,color .2s,border-color .2s,box-shadow .2s}::ng-deep .p-datepicker .p-datepicker-buttonbar{padding:1rem 0;border-top:.0625rem solid var(--inputBorder)}::ng-deep .p-button{color:#fff;background:var(--primaryColor);border:.0625rem solid var(--primaryColor);padding:.495rem 1rem;font-size:1rem;transition:background-color .2s,color .2s,border-color .2s,box-shadow .2s;border-radius:var(--inputBorderRadius)}::ng-deep .p-togglebutton.p-button.p-highlight{background:var(--primaryColor);border:.0625rem solid var(--primaryColor);color:var(--background)}::ng-deep .p-togglebutton.p-button.p-highlight:hover{background:var(--primaryColor);border:.0625rem solid var(--primaryColor);color:var(--background)}app-zac-wrapper{z-index:999999}\n"], dependencies: [{ kind: "component", type: ListTableHeaderComponent, selector: "lib-list-table-header", inputs: ["title", "subtitle", "createLabel", "infoText", "tabs", "showAdd", "blockCreate", "blockDelete", "tabsUseRouter", "activeTab"], outputs: ["actionClicked", "tabClicked"] }, { kind: "component", type: ListTableComponent, selector: "lib-list-table", inputs: ["tableId", "columns", "rowData", "isLoading", "options", "hasNext", "hasPrev", "startCount", "endCount", "totalCount", "filterApplied", "menuItems", "headerActions", "noItemsImage", "showNoItemsAdd", "noItemsReadonly", "accessDenied", "entityTypeName", "filterName", "filterColumn", "initialPageSize"], outputs: ["actionRequested", "tableReady"] }, { kind: "component", type: SideModalComponent, selector: "lib-side-modal", inputs: ["showClose", "open"], outputs: ["openChange"] }, { kind: "component", type: LoadingIndicatorComponent, selector: "lib-loading-indicator", inputs: ["isLoading"] }, { kind: "component", type: OverridesComponent, selector: "lib-overrides", inputs: ["identity"], outputs: ["close"] }] }); }
|
|
16962
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: IdentitiesListPageComponent, isStandalone: false, selector: "lib-identities-list", usesInheritance: true, ngImport: i0, template: "<div class=\"ziti-page-container ziti-identities-container lt-skin-page\">\n <lib-list-table-header\n [title]=\"title\"\n subtitle=\"Manage identities across the network\"\n createLabel=\"Create Identity\"\n infoText=\"Identities are the clients, services, and routers enrolled in this network.\"\n [tabs]=\"tabs\"\n [showAdd]=\"!itemsSelected\"\n [blockCreate]=\"headerBlockCreate\"\n [blockDelete]=\"headerBlockDelete\"\n (actionClicked)=\"headerActionClicked($event)\"\n >\n <span header-icon class=\"icon-identity\" aria-hidden=\"true\"></span>\n </lib-list-table-header>\n <ng-content select=\"[slot=list-page-subheader]\"></ng-content>\n <lib-list-table class=\"lt-skin\" [tableId]=\"tableId\" [initialPageSize]=\"initialPageSize\"\n [noItemsReadonly]=\"headerBlockCreate\"\n [accessDenied]=\"headerBlockRead\"\n [rowData]=\"rowData\"\n [isLoading]=\"isLoading\"\n [columns]=\"columnDefs\"\n (actionRequested)=\"tableAction($event)\"\n [startCount]=\"startCount\"\n [endCount]=\"endCount\"\n [totalCount]=\"totalCount\"\n [filterApplied]=\"filterApplied\"\n [menuItems]=\"svc.menuItems\"\n [headerActions]=\"svc.tableHeaderActions\"\n [noItemsImage]=\"'No_Clients'\"\n (tableReady)=\"tableReady($event)\"\n >\n </lib-list-table>\n</div>\n<lib-side-modal [(open)]=\"svc.sideModalOpen\" [showClose]=\"false\">\n @if (svc.modalType === 'overrides' && svc.sideModalOpen) {\n <lib-overrides\n [identity]=\"svc.selectedIdentity\"\n (close)=\"closeModal($event)\"\n ></lib-overrides>\n }\n</lib-side-modal>\n@if (isLoading) {\n <lib-loading-indicator [isLoading]=\"isLoading\"></lib-loading-indicator>\n}\n", styles: [".ziti-page-container .action{line-height:3.75rem;top:1.5625rem;right:1.5625rem;z-index:999}.ziti-identities-container ::ng-deep .zac-wrapper-container{height:0rem;left:-62499.9375rem;position:fixed}.ziti-identities-container ::ng-deep .zac-wrapper-container .action{display:none}.ziti-ag-grid{height:100%;position:relative;width:100%}.ziti-ag-grid .ziti-ag-grid-table{height:100%;width:100%}.ziti-ag-grid .ziti-ag-grid-table .ag-root-wrapper{border-bottom-style:none}.ziti-ag-grid .ziti-ag-grid-table .ag-cell{align-items:center;display:flex}.system-policies-toggle,.hidden-results-container{position:relative;right:0;display:flex;flex-direction:row;justify-content:center;align-items:flex-start;margin-top:.625rem;padding-left:1.25rem;border-radius:var(--inputBorderRadius);padding-bottom:0;padding-right:0;padding-top:0;flex-wrap:nowrap;flex:1 0 auto}.system-policies-toggle .toggle-text,.hidden-results-container .toggle-text{font-weight:600;font-size:.75rem}.system-policies-toggle .toggle-text a,.hidden-results-container .toggle-text a{cursor:pointer}.system-policies-toggle .toggle,.hidden-results-container .toggle{width:4.6875rem;margin-left:.625rem}.system-policies-toggle .toggle.on .switch,.hidden-results-container .toggle.on .switch{left:3.25rem}.system-policies-toggle .spinner,.hidden-results-container .spinner{display:inline-block;width:.625rem;height:.625rem;border-radius:50%;background:transparent;border-top:.125rem solid var(--tableText);border-right:.125rem solid var(--tableText);border-bottom:.125rem solid transparent;border-left:.125rem solid transparent;animation:loading .5s infinite linear;margin-left:.3125rem}.hidden-results-container.loading-results{opacity:.7}.nf-cell-vert-align,.ag-row .ag-cell{align-items:center;display:flex}.hidden-columns-list{align-items:center;display:flex;flex-direction:row;margin-left:.4375rem;min-height:1.875rem;flex-wrap:wrap;flex:0 1 auto}.hidden-columns-list.hidden-results{flex-wrap:nowrap;overflow:auto}.hidden-columns-list.hidden-results .hidden-column-item{flex:1 0 auto}.hidden-columns-list::-webkit-scrollbar{height:.875rem}.hidden-columns-list .hidden-column-item{align-items:center;background-color:var(--background);border:.125rem solid var(--background);border-radius:.75rem;cursor:pointer;color:var(----stroke);font-weight:600;font-family:Open Sans,sans-serif;display:flex;flex:0 1 auto;height:1.5625rem!important;margin-left:.625rem;margin-top:.3125rem;padding:.125rem .625rem .125rem .3125rem;position:relative;text-align:center;box-shadow:unset;transform:translateY(0)}.hidden-columns-list .ag-dnd-ghost:hover{border:.125rem solid var(--primaryColor)!important}.hidden-columns-list .ag-dnd-ghost:hover .ag-dnd-ghost-label,.hidden-columns-list .ag-dnd-ghost:hover .ag-dnd-ghost-icon .ag-icon-eye-slash{color:var(--ag-alpine-active-color, var(--primaryColor))}.hidden-columns-list .ag-dnd-ghost:hover .ag-dnd-ghost-icon .ag-icon-eye-slash:before{content:\"\\f113\"}.hidden-columns-list .ag-dnd-ghost-label{line-height:initial}::ng-deep .darkmode .ag-dnd-ghost-icon .ag-icon-eye-slash{color:#fff!important}.tMenu{transition-property:opacity;z-index:99999999999;height:fit-content}.tMenu.action-menu{position:fixed;width:10.9375rem}.tMenu .tActionRow{transition-property:opacity}.tMenu .tActionRow.has-icon{display:flex;flex-direction:row;align-items:center}.tMenu .tActionRow .v7Offline{background-color:var(--placeholder)}.tMenu .tActionRow .v7OnlineOffline{width:.875rem;height:.875rem;border-color:var(--placeholder)}.tMenu .tActionRow .v7OnlineOffline:hover{border-color:var(--placeholder)}.hidden-items-container{display:flex;flex-direction:row;width:100%;flex-wrap:nowrap;justify-content:space-between}.os-icon{width:1.4375rem;height:1.4375rem;background-size:1.4375rem 1.4375rem;display:inline-flex;margin-right:.5rem;margin-top:.3125rem;margin-bottom:.3125rem}::ng-deep .date-time-container{position:fixed}::ng-deep .date-time-container .p-calendar .p-inputtext{height:.0625rem;width:.0625rem;padding:0}::ng-deep .date-time-container .filter-button-container{height:3.125rem;display:flex;flex-direction:row;justify-content:center;align-items:center}::ng-deep .date-time-container .filter-button-container .toggleButton{padding-left:.3125rem;padding-right:.3125rem;width:unset}::ng-deep .date-time-container .p-calendar{height:1.875rem}::ng-deep .date-time-container .p-calendar .p-inputtext{height:1.875rem;border-top-left-radius:1.25rem;border-bottom-left-radius:1.25rem;text-indent:.3125rem}::ng-deep .date-time-container .p-calendar .p-button-icon-only{border-top-right-radius:1.25rem;border-bottom-right-radius:1.25rem}#TimeSearch{position:relative;float:left;display:inline-block;margin-left:.625rem;width:3.125rem;height:2.5rem;background-color:var(--primary)}#TimeSearch #TimeSearchList{width:2.75rem;height:0;position:absolute;top:0;left:-.125rem;overflow:hidden;transition:var(--transition);background-color:var(--menu);border-radius:.5rem;z-index:30}#TimeSearch #TimeSearchList .time{width:2.5rem;background-color:var(--background);padding-left:.5rem;padding-right:.5rem;border-radius:.5rem;line-height:1.625rem;font-size:.75rem;font-weight:700;text-align:center;margin-top:.125rem;margin-left:.125rem;left:-.125rem;top:-3.1875rem;cursor:pointer;transition:var(--transition)}#TimeSearch #TimeSearchList.open{top:-3.1875rem;width:2.75rem;height:14.125rem}#TimeSearch #TimeSelectButton{width:2.5rem;background-color:var(--background);padding-left:.5rem;padding-right:.5rem;border-radius:.5rem;line-height:1.625rem;text-align:center;font-size:.75rem;font-weight:700;margin-top:.4375rem;cursor:pointer;transition:var(--transition)}#TimeSearch #TimeSelectButton:hover,#TimeSearch #TimeSearchList .time:hover{background-color:var(--primaryColor);color:var(--white)}::ng-deep p-togglebutton .p-togglebutton.p-button{border-radius:var(--inputBorderRadius)!important;box-shadow:0 .3125rem 1.25rem #0000000d!important;margin-top:-.125rem!important}::ng-deep p-togglebutton .p-togglebutton.p-button:hover{filter:brightness(99%)!important;box-shadow:0 .3125rem 1.25rem #0000000d!important;transition:all .3s ease}::ng-deep p-togglebutton .p-togglebutton.p-button:active{filter:brightness(95%)!important;box-shadow:none!important;transform:translateY(.0625rem)!important;transition:all .3s ease}#TimeSearch #TimeSelectButton{margin-top:.25rem!important}::ng-deep .p-calendar .p-inputtext{height:2.3125rem}::ng-deep .p-inputtext{border-radius:var(--inputBorderRadius)}.calendar{display:inline-block;padding-left:.3125rem;float:left;padding-right:.625rem;margin-top:-.125rem}::ng-deep .p-datepicker:not(.p-datepicker-inline){background:var(--table);border:0 none;box-shadow:#091e4226 0 1.25rem 2rem -.5rem;border-radius:.75rem}::ng-deep .p-button.p-button-text{background-color:transparent;color:var(--primaryColor);border-color:transparent}::ng-deep .p-button.p-button-text:enabled:hover{background:var(--primaryColorShadowLight);color:var(--primaryColor);border-color:transparent}::ng-deep .p-datepicker table td>span.p-highlight{color:var(--tableText);background:var(--primaryColorShadowLight)}::ng-deep .p-inputtext:enabled:hover{border-color:var(--primaryColor)}::ng-deep .p-datepicker{padding:.5rem;padding-bottom:0;background:var(--table);color:var(--tableText);border:.0625rem solid var(--inputBorder);border-radius:.1875rem}::ng-deep .p-inputtext:enabled:focus{outline:0 none;outline-offset:0;box-shadow:0 0 0 1 var(--primaryColorShadowLight);border-color:var(--primaryColor)}::ng-deep .p-inputtext{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol;font-size:1rem;color:var(--tableText);background:var(--table);padding:.5rem;border:.0625rem solid var(--inputBorder);transition:background-color .2s,color .2s,border-color .2s,box-shadow .2s;-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:var(--inputBorderRadius)}::ng-deep .p-datepicker:not(.p-datepicker-inline) .p-datepicker-header{background:var(--table)}::ng-deep .p-datepicker .p-datepicker-header{padding:.5rem;color:var(--tableText);background:var(--table);font-weight:600;margin:0;border-bottom:.0625rem solid var(--inputBorder);border-top-right-radius:.75rem;border-top-left-radius:.75rem}::ng-deep .p-datepicker:not(.p-disabled) table td span:not(.p-highlight):not(.p-disabled):hover{background:#e9ecef;color:var(--table)}::ng-deep .p-datepicker .p-timepicker{border-top:.0625rem solid var(--background);padding:.5rem}::ng-deep .p-togglebutton.p-button{background:var(--background);border:.0625rem solid var(--inputBorder);color:var(--tableText);transition:background-color .2s,color .2s,border-color .2s,box-shadow .2s}::ng-deep .p-datepicker .p-datepicker-buttonbar{padding:1rem 0;border-top:.0625rem solid var(--inputBorder)}::ng-deep .p-button{color:#fff;background:var(--primaryColor);border:.0625rem solid var(--primaryColor);padding:.495rem 1rem;font-size:1rem;transition:background-color .2s,color .2s,border-color .2s,box-shadow .2s;border-radius:var(--inputBorderRadius)}::ng-deep .p-togglebutton.p-button.p-highlight{background:var(--primaryColor);border:.0625rem solid var(--primaryColor);color:var(--background)}::ng-deep .p-togglebutton.p-button.p-highlight:hover{background:var(--primaryColor);border:.0625rem solid var(--primaryColor);color:var(--background)}app-zac-wrapper{z-index:999999}\n"], dependencies: [{ kind: "component", type: ListTableHeaderComponent, selector: "lib-list-table-header", inputs: ["title", "subtitle", "createLabel", "infoText", "tabs", "showAdd", "blockCreate", "blockDelete", "tabsUseRouter", "activeTab"], outputs: ["actionClicked", "tabClicked"] }, { kind: "component", type: ListTableComponent, selector: "lib-list-table", inputs: ["tableId", "columns", "rowData", "isLoading", "options", "loadChildren", "childColumnsByLevel", "hasNext", "hasPrev", "startCount", "endCount", "totalCount", "filterApplied", "menuItems", "headerActions", "noItemsImage", "showNoItemsAdd", "noItemsReadonly", "accessDenied", "entityTypeName", "filterName", "filterColumn", "treeVariant", "showTreeVariantToggle", "treeRail", "initialPageSize"], outputs: ["nodeToggled", "actionRequested", "tableReady", "selectionChanged"] }, { kind: "component", type: SideModalComponent, selector: "lib-side-modal", inputs: ["showClose", "open"], outputs: ["openChange"] }, { kind: "component", type: LoadingIndicatorComponent, selector: "lib-loading-indicator", inputs: ["isLoading"] }, { kind: "component", type: OverridesComponent, selector: "lib-overrides", inputs: ["identity"], outputs: ["close"] }] }); }
|
|
16126
16963
|
}
|
|
16127
16964
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: IdentitiesListPageComponent, decorators: [{
|
|
16128
16965
|
type: Component,
|
|
@@ -25067,12 +25904,12 @@ class EdgeRouterPoliciesPageService extends ListPageServiceClass {
|
|
|
25067
25904
|
createdAt: '',
|
|
25068
25905
|
};
|
|
25069
25906
|
this.menuItems = [
|
|
25070
|
-
{ name: 'Edit', action: 'update' },
|
|
25071
|
-
{ name: 'Delete', action: 'delete' },
|
|
25907
|
+
{ name: 'Edit', action: 'update', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" d="M11.2 2.6 13.4 4.8 6 12.2l-2.8.6.6-2.8z"/></svg>' },
|
|
25908
|
+
{ name: 'Delete', action: 'delete', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" d="M3.4 4.6h9.2M6.4 4.6V3.2h3.2v1.4M4.6 4.6 5 13h6l.4-8.4"/></svg>' },
|
|
25072
25909
|
];
|
|
25073
25910
|
this.tableHeaderActions = [
|
|
25074
|
-
{ name: 'Download All', action: 'download-all' },
|
|
25075
|
-
{ name: 'Download Selected', action: 'download-selected' },
|
|
25911
|
+
{ name: 'Download All', action: 'download-all', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" d="M8 2.5v7M5 6.6 8 9.6l3-3M3.2 12.6h9.6"/></svg>' },
|
|
25912
|
+
{ name: 'Download Selected', action: 'download-selected', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" d="M8 2.5v7M5 6.6 8 9.6l3-3M3.2 12.6h9.6"/></svg>' },
|
|
25076
25913
|
];
|
|
25077
25914
|
this.resourceType = 'edge-router-policies';
|
|
25078
25915
|
this.validate = (formData) => {
|
|
@@ -25310,9 +26147,163 @@ class EdgeRouterPoliciesPageService extends ListPageServiceClass {
|
|
|
25310
26147
|
this.ID_COLUMN_DEF
|
|
25311
26148
|
];
|
|
25312
26149
|
}
|
|
25313
|
-
|
|
26150
|
+
// Declarative ListColumn set for the new `lib-list-table` (Beta Features on).
|
|
26151
|
+
initListTableColumns() {
|
|
26152
|
+
this.initMenuActions();
|
|
26153
|
+
const routerRolesHeaderComponentParams = {
|
|
26154
|
+
filterType: 'ATTRIBUTE',
|
|
26155
|
+
enableSorting: true,
|
|
26156
|
+
getRoleAttributes: () => this.routerRoleAttributes,
|
|
26157
|
+
getNamedAttributes: () => this.routerNamedAttributes,
|
|
26158
|
+
getSelectedRoleAttributes: () => this.selectedRouterRoleAttributes,
|
|
26159
|
+
getSelectedNamedAttributes: () => this.selectedRouterNamedAttributes,
|
|
26160
|
+
setSelectedRoleAttributes: (attributes) => {
|
|
26161
|
+
this.selectedRouterRoleAttributes = attributes;
|
|
26162
|
+
},
|
|
26163
|
+
setSelectedNamedAttributes: (attributes) => {
|
|
26164
|
+
this.selectedRouterNamedAttributes = attributes;
|
|
26165
|
+
},
|
|
26166
|
+
getNamedAttributesMap: () => this.routerNamedAttributesMap,
|
|
26167
|
+
};
|
|
26168
|
+
const identityRolesHeaderComponentParams = {
|
|
26169
|
+
filterType: 'ATTRIBUTE',
|
|
26170
|
+
enableSorting: true,
|
|
26171
|
+
getRoleAttributes: () => this.identityRoleAttributes,
|
|
26172
|
+
getNamedAttributes: () => this.identityNamedAttributes,
|
|
26173
|
+
getSelectedRoleAttributes: () => this.selectedIdentityRoleAttributes,
|
|
26174
|
+
getSelectedNamedAttributes: () => this.selectedIdentityNamedAttributes,
|
|
26175
|
+
setSelectedRoleAttributes: (attributes) => {
|
|
26176
|
+
this.selectedIdentityRoleAttributes = attributes;
|
|
26177
|
+
},
|
|
26178
|
+
setSelectedNamedAttributes: (attributes) => {
|
|
26179
|
+
this.selectedIdentityNamedAttributes = attributes;
|
|
26180
|
+
},
|
|
26181
|
+
getNamedAttributesMap: () => this.identityNamedAttributesMap,
|
|
26182
|
+
};
|
|
26183
|
+
// @ marks a named attribute, # a role attribute (matches the tag selector)
|
|
26184
|
+
const rolesChipRenderer = (row) => {
|
|
26185
|
+
const colId = row?.column?.colId;
|
|
26186
|
+
const attrs = row?.data?.[colId + 'Display'] || row?.data?.[colId] || [];
|
|
26187
|
+
return attrs.map((attr) => {
|
|
26188
|
+
const raw = String(attr?.name ?? attr ?? '').trim();
|
|
26189
|
+
if (!raw) {
|
|
26190
|
+
return '';
|
|
26191
|
+
}
|
|
26192
|
+
const isNamed = raw.charAt(0) === '@';
|
|
26193
|
+
const label = isNamed || raw.charAt(0) === '#' ? raw : '#' + raw;
|
|
26194
|
+
return `<span class="${isNamed ? 'lt-chip lt-chip-at' : 'lt-chip'}">${label}</span>`;
|
|
26195
|
+
}).join('');
|
|
26196
|
+
};
|
|
26197
|
+
const semanticFilterOptions = [
|
|
26198
|
+
{ label: 'Show All', value: '' },
|
|
26199
|
+
{ label: 'Any Of', value: 'AnyOf' },
|
|
26200
|
+
{ label: 'All Of', value: 'AllOf' },
|
|
26201
|
+
];
|
|
26202
|
+
const semanticRenderer = (row) => row?.data?.semantic === 'AnyOf' ? 'Any Of' : 'All Of';
|
|
26203
|
+
const openForm = (ctx) => {
|
|
26204
|
+
if (this.hasSelectedText()) {
|
|
26205
|
+
return;
|
|
26206
|
+
}
|
|
26207
|
+
this.serviceType = 'advanced';
|
|
26208
|
+
this.openEditForm(ctx.row?.id);
|
|
26209
|
+
};
|
|
26210
|
+
let tableColumns = [
|
|
26211
|
+
{
|
|
26212
|
+
key: 'name',
|
|
26213
|
+
field: 'name',
|
|
26214
|
+
label: 'Name',
|
|
26215
|
+
filterType: 'TEXTINPUT',
|
|
26216
|
+
cell: NameCellComponent,
|
|
26217
|
+
cellInputs: (ctx) => ({
|
|
26218
|
+
row: ctx.row,
|
|
26219
|
+
cellValue: ctx.value,
|
|
26220
|
+
cellConfig: { pathRoot: this.basePath, showIdentityIcons: false },
|
|
26221
|
+
}),
|
|
26222
|
+
onCellClick: openForm,
|
|
26223
|
+
resizable: true,
|
|
26224
|
+
cellClass: 'nf-cell-vert-align',
|
|
26225
|
+
sortable: true,
|
|
26226
|
+
onSort: this.sort.bind(this),
|
|
26227
|
+
sortDir: 'asc',
|
|
26228
|
+
width: 300,
|
|
26229
|
+
},
|
|
26230
|
+
{
|
|
26231
|
+
key: 'edgeRouterRoles',
|
|
26232
|
+
field: 'edgeRouterRoles',
|
|
26233
|
+
label: 'Router Attributes',
|
|
26234
|
+
filterType: 'ATTRIBUTE',
|
|
26235
|
+
headerParams: routerRolesHeaderComponentParams,
|
|
26236
|
+
cellHtml: rolesChipRenderer,
|
|
26237
|
+
onCellClick: openForm,
|
|
26238
|
+
resizable: true,
|
|
26239
|
+
cellClass: 'nf-cell-vert-align',
|
|
26240
|
+
sortable: false,
|
|
26241
|
+
},
|
|
26242
|
+
{
|
|
26243
|
+
key: 'identityRoles',
|
|
26244
|
+
field: 'identityRoles',
|
|
26245
|
+
label: 'Identity Attributes',
|
|
26246
|
+
filterType: 'ATTRIBUTE',
|
|
26247
|
+
headerParams: identityRolesHeaderComponentParams,
|
|
26248
|
+
cellHtml: rolesChipRenderer,
|
|
26249
|
+
onCellClick: openForm,
|
|
26250
|
+
resizable: true,
|
|
26251
|
+
cellClass: 'nf-cell-vert-align',
|
|
26252
|
+
sortable: false,
|
|
26253
|
+
},
|
|
26254
|
+
{
|
|
26255
|
+
key: 'semantic',
|
|
26256
|
+
field: 'semantic',
|
|
26257
|
+
label: 'Semantic',
|
|
26258
|
+
filterType: 'SELECT',
|
|
26259
|
+
filterPlaceholder: 'Any semantic',
|
|
26260
|
+
filterOptions: semanticFilterOptions,
|
|
26261
|
+
cellHtml: semanticRenderer,
|
|
26262
|
+
onCellClick: openForm,
|
|
26263
|
+
resizable: true,
|
|
26264
|
+
sortable: true,
|
|
26265
|
+
onSort: this.sort.bind(this),
|
|
26266
|
+
cellClass: 'nf-cell-vert-align',
|
|
26267
|
+
width: 120,
|
|
26268
|
+
},
|
|
26269
|
+
{
|
|
26270
|
+
key: 'createdAt',
|
|
26271
|
+
field: 'createdAt',
|
|
26272
|
+
label: 'Created At',
|
|
26273
|
+
valueFormatter: this.createdAtFormatter,
|
|
26274
|
+
filterType: 'DATETIME',
|
|
26275
|
+
filterPlaceholder: 'Any time',
|
|
26276
|
+
onCellClick: openForm,
|
|
26277
|
+
resizable: true,
|
|
26278
|
+
sortable: true,
|
|
26279
|
+
onSort: this.sort.bind(this),
|
|
26280
|
+
cellClass: 'nf-cell-vert-align',
|
|
26281
|
+
hidden: true,
|
|
26282
|
+
},
|
|
26283
|
+
{
|
|
26284
|
+
key: 'id',
|
|
26285
|
+
field: 'id',
|
|
26286
|
+
label: 'ID',
|
|
26287
|
+
filterType: 'TEXTINPUT',
|
|
26288
|
+
onCellClick: openForm,
|
|
26289
|
+
resizable: true,
|
|
26290
|
+
sortable: true,
|
|
26291
|
+
onSort: this.sort.bind(this),
|
|
26292
|
+
cellClass: 'nf-cell-vert-align',
|
|
26293
|
+
hidden: true,
|
|
26294
|
+
},
|
|
26295
|
+
];
|
|
26296
|
+
if (this.extService?.processListTableColumns) {
|
|
26297
|
+
tableColumns = this.extService.processListTableColumns(tableColumns);
|
|
26298
|
+
}
|
|
26299
|
+
return tableColumns;
|
|
26300
|
+
}
|
|
26301
|
+
getData(filters, sort, page, pageSize) {
|
|
25314
26302
|
// we can customize filters or sorting here before moving on...
|
|
25315
26303
|
this.paging.page = page || this.paging.page;
|
|
26304
|
+
if (pageSize) {
|
|
26305
|
+
this.paging.total = pageSize;
|
|
26306
|
+
}
|
|
25316
26307
|
return super.getTableData('edge-router-policies', this.paging, filters, sort)
|
|
25317
26308
|
.then((results) => {
|
|
25318
26309
|
return this.processData(results);
|
|
@@ -25536,6 +26527,135 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
25536
26527
|
args: [SHAREDZ_EXTENSION]
|
|
25537
26528
|
}] }] });
|
|
25538
26529
|
|
|
26530
|
+
/*
|
|
26531
|
+
Copyright NetFoundry Inc.
|
|
26532
|
+
|
|
26533
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
26534
|
+
you may not use this file except in compliance with the License.
|
|
26535
|
+
You may obtain a copy of the License at
|
|
26536
|
+
|
|
26537
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
26538
|
+
|
|
26539
|
+
Unless required by applicable law or agreed to in writing, software
|
|
26540
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
26541
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
26542
|
+
See the License for the specific language governing permissions and
|
|
26543
|
+
limitations under the License.
|
|
26544
|
+
*/
|
|
26545
|
+
// Edge Router Policies page on `lib-list-table`, selected by the route when Beta Features is on.
|
|
26546
|
+
class EdgeRouterPoliciesListPageComponent extends ListPageComponent {
|
|
26547
|
+
constructor(svc, filterService, dialogForm, tabNames, consoleEvents, extService) {
|
|
26548
|
+
super(filterService, svc, consoleEvents, dialogForm, extService);
|
|
26549
|
+
this.svc = svc;
|
|
26550
|
+
this.tabNames = tabNames;
|
|
26551
|
+
this.extService = extService;
|
|
26552
|
+
this.title = 'Edge Router Policies';
|
|
26553
|
+
this.isLoading = false;
|
|
26554
|
+
this.formDataChanged = false;
|
|
26555
|
+
this.tableId = 'edge-router-policies';
|
|
26556
|
+
this.initialPageSize = 50;
|
|
26557
|
+
}
|
|
26558
|
+
loadTableColumns() {
|
|
26559
|
+
return this.svc.initListTableColumns();
|
|
26560
|
+
}
|
|
26561
|
+
ngOnInit() {
|
|
26562
|
+
this.tabs = this.tabNames.getTabs('policies');
|
|
26563
|
+
this.svc.refreshData = this.refreshData;
|
|
26564
|
+
this.getRoleAttributes();
|
|
26565
|
+
super.ngOnInit();
|
|
26566
|
+
}
|
|
26567
|
+
headerActionClicked(action) {
|
|
26568
|
+
switch (action) {
|
|
26569
|
+
case 'add':
|
|
26570
|
+
this.svc.serviceType = '';
|
|
26571
|
+
this.svc.openEditForm();
|
|
26572
|
+
break;
|
|
26573
|
+
case 'edit':
|
|
26574
|
+
this.svc.openEditForm();
|
|
26575
|
+
break;
|
|
26576
|
+
case 'delete':
|
|
26577
|
+
const selectedItems = this.rowData.filter((row) => {
|
|
26578
|
+
return row.selected;
|
|
26579
|
+
});
|
|
26580
|
+
const label = selectedItems.length > 1 ? 'edge router policies' : 'edge router policy';
|
|
26581
|
+
this.openBulkDelete(selectedItems, label);
|
|
26582
|
+
break;
|
|
26583
|
+
default:
|
|
26584
|
+
}
|
|
26585
|
+
}
|
|
26586
|
+
tableAction(event) {
|
|
26587
|
+
this.trackMenuAction(event?.action, event?.item);
|
|
26588
|
+
switch (event?.action) {
|
|
26589
|
+
case 'toggleAll':
|
|
26590
|
+
case 'toggleItem':
|
|
26591
|
+
this.itemToggled(event.item);
|
|
26592
|
+
this.rowData.forEach((item) => {
|
|
26593
|
+
if (item.isSystem) {
|
|
26594
|
+
item.selected = false;
|
|
26595
|
+
}
|
|
26596
|
+
});
|
|
26597
|
+
break;
|
|
26598
|
+
case 'update':
|
|
26599
|
+
this.svc.serviceType = 'advanced';
|
|
26600
|
+
this.svc.openEditForm(event.item?.id);
|
|
26601
|
+
break;
|
|
26602
|
+
case 'create':
|
|
26603
|
+
this.svc.openEditForm();
|
|
26604
|
+
break;
|
|
26605
|
+
case 'delete':
|
|
26606
|
+
this.deleteItem(event.item);
|
|
26607
|
+
break;
|
|
26608
|
+
case 'download-all':
|
|
26609
|
+
this.downloadAllItems();
|
|
26610
|
+
break;
|
|
26611
|
+
case 'download-selected':
|
|
26612
|
+
this.svc.downloadItems(this.selectedItems);
|
|
26613
|
+
break;
|
|
26614
|
+
default:
|
|
26615
|
+
break;
|
|
26616
|
+
}
|
|
26617
|
+
}
|
|
26618
|
+
trackMenuAction(action, item) {
|
|
26619
|
+
this.extService?.consoleActionTriggered?.emit({
|
|
26620
|
+
action,
|
|
26621
|
+
page: 'edge-router-policy',
|
|
26622
|
+
item,
|
|
26623
|
+
type: 'menu-action'
|
|
26624
|
+
});
|
|
26625
|
+
}
|
|
26626
|
+
getRoleAttributes() {
|
|
26627
|
+
this.svc.getEdgeRouterRoleAttributes();
|
|
26628
|
+
this.svc.getIdentityRoleAttributes();
|
|
26629
|
+
this.svc.getServiceNamedAttributes();
|
|
26630
|
+
this.svc.getIdentityNamedAttributes();
|
|
26631
|
+
this.svc.getPostureNamedAttributes();
|
|
26632
|
+
}
|
|
26633
|
+
deleteItem(item) {
|
|
26634
|
+
this.openBulkDelete([item], 'edge-router-policies');
|
|
26635
|
+
}
|
|
26636
|
+
closeModal(event) {
|
|
26637
|
+
this.svc.sideModalOpen = false;
|
|
26638
|
+
if (event?.refresh) {
|
|
26639
|
+
this.refreshData();
|
|
26640
|
+
}
|
|
26641
|
+
}
|
|
26642
|
+
dataChanged(event) {
|
|
26643
|
+
this.formDataChanged = event;
|
|
26644
|
+
}
|
|
26645
|
+
ngOnDestroy() {
|
|
26646
|
+
super.ngOnDestroy();
|
|
26647
|
+
}
|
|
26648
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: EdgeRouterPoliciesListPageComponent, deps: [{ token: EdgeRouterPoliciesPageService }, { token: DataTableFilterService }, { token: i5.MatDialog }, { token: TabNameService }, { token: ConsoleEventsService }, { token: SHAREDZ_EXTENSION }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
26649
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: EdgeRouterPoliciesListPageComponent, isStandalone: false, selector: "lib-edge-router-policies-list", usesInheritance: true, ngImport: i0, template: "<div class=\"ziti-page-container ziti-edge-router-policies-container lt-skin-page\">\n <lib-list-table-header\n [title]=\"title\"\n subtitle=\"Control which identities can use which edge routers\"\n createLabel=\"Create Edge Router Policy\"\n infoText=\"Edge router policies grant identities access to edge routers.\"\n [tabs]=\"tabs\"\n [showAdd]=\"!itemsSelected\"\n [blockCreate]=\"headerBlockCreate\"\n [blockDelete]=\"headerBlockDelete\"\n (actionClicked)=\"headerActionClicked($event)\"\n >\n <span header-icon class=\"icon-routerpolicy\" aria-hidden=\"true\"></span>\n </lib-list-table-header>\n <ng-content select=\"[slot=list-page-subheader]\"></ng-content>\n <lib-list-table class=\"lt-skin\" [tableId]=\"tableId\" [initialPageSize]=\"initialPageSize\"\n [noItemsReadonly]=\"headerBlockCreate\"\n [accessDenied]=\"headerBlockRead\"\n [rowData]=\"rowData\"\n [isLoading]=\"isLoading\"\n [columns]=\"columnDefs\"\n (actionRequested)=\"tableAction($event)\"\n [startCount]=\"startCount\"\n [endCount]=\"endCount\"\n [totalCount]=\"totalCount\"\n [filterApplied]=\"filterApplied\"\n [menuItems]=\"svc.menuItems\"\n [headerActions]=\"svc.tableHeaderActions\"\n [noItemsImage]=\"'No_Clients'\"\n (tableReady)=\"tableReady($event)\"\n >\n </lib-list-table>\n</div>\n@if (isLoading) {\n <lib-loading-indicator [isLoading]=\"isLoading\"></lib-loading-indicator>\n}\n", styles: [""], dependencies: [{ kind: "component", type: ListTableHeaderComponent, selector: "lib-list-table-header", inputs: ["title", "subtitle", "createLabel", "infoText", "tabs", "showAdd", "blockCreate", "blockDelete", "tabsUseRouter", "activeTab"], outputs: ["actionClicked", "tabClicked"] }, { kind: "component", type: ListTableComponent, selector: "lib-list-table", inputs: ["tableId", "columns", "rowData", "isLoading", "options", "loadChildren", "childColumnsByLevel", "hasNext", "hasPrev", "startCount", "endCount", "totalCount", "filterApplied", "menuItems", "headerActions", "noItemsImage", "showNoItemsAdd", "noItemsReadonly", "accessDenied", "entityTypeName", "filterName", "filterColumn", "treeVariant", "showTreeVariantToggle", "treeRail", "initialPageSize"], outputs: ["nodeToggled", "actionRequested", "tableReady", "selectionChanged"] }, { kind: "component", type: LoadingIndicatorComponent, selector: "lib-loading-indicator", inputs: ["isLoading"] }] }); }
|
|
26650
|
+
}
|
|
26651
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: EdgeRouterPoliciesListPageComponent, decorators: [{
|
|
26652
|
+
type: Component,
|
|
26653
|
+
args: [{ selector: 'lib-edge-router-policies-list', standalone: false, template: "<div class=\"ziti-page-container ziti-edge-router-policies-container lt-skin-page\">\n <lib-list-table-header\n [title]=\"title\"\n subtitle=\"Control which identities can use which edge routers\"\n createLabel=\"Create Edge Router Policy\"\n infoText=\"Edge router policies grant identities access to edge routers.\"\n [tabs]=\"tabs\"\n [showAdd]=\"!itemsSelected\"\n [blockCreate]=\"headerBlockCreate\"\n [blockDelete]=\"headerBlockDelete\"\n (actionClicked)=\"headerActionClicked($event)\"\n >\n <span header-icon class=\"icon-routerpolicy\" aria-hidden=\"true\"></span>\n </lib-list-table-header>\n <ng-content select=\"[slot=list-page-subheader]\"></ng-content>\n <lib-list-table class=\"lt-skin\" [tableId]=\"tableId\" [initialPageSize]=\"initialPageSize\"\n [noItemsReadonly]=\"headerBlockCreate\"\n [accessDenied]=\"headerBlockRead\"\n [rowData]=\"rowData\"\n [isLoading]=\"isLoading\"\n [columns]=\"columnDefs\"\n (actionRequested)=\"tableAction($event)\"\n [startCount]=\"startCount\"\n [endCount]=\"endCount\"\n [totalCount]=\"totalCount\"\n [filterApplied]=\"filterApplied\"\n [menuItems]=\"svc.menuItems\"\n [headerActions]=\"svc.tableHeaderActions\"\n [noItemsImage]=\"'No_Clients'\"\n (tableReady)=\"tableReady($event)\"\n >\n </lib-list-table>\n</div>\n@if (isLoading) {\n <lib-loading-indicator [isLoading]=\"isLoading\"></lib-loading-indicator>\n}\n" }]
|
|
26654
|
+
}], ctorParameters: () => [{ type: EdgeRouterPoliciesPageService }, { type: DataTableFilterService }, { type: i5.MatDialog }, { type: TabNameService }, { type: ConsoleEventsService }, { type: undefined, decorators: [{
|
|
26655
|
+
type: Inject,
|
|
26656
|
+
args: [SHAREDZ_EXTENSION]
|
|
26657
|
+
}] }] });
|
|
26658
|
+
|
|
25539
26659
|
/*
|
|
25540
26660
|
Copyright NetFoundry Inc.
|
|
25541
26661
|
|
|
@@ -25584,13 +26704,14 @@ class ServicePoliciesPageService extends ListPageServiceClass {
|
|
|
25584
26704
|
os: '',
|
|
25585
26705
|
createdAt: '',
|
|
25586
26706
|
};
|
|
26707
|
+
// `icon` is rendered by the new list-table's menus; the legacy ag-grid menu ignores it.
|
|
25587
26708
|
this.menuItems = [
|
|
25588
|
-
{ name: 'Edit', action: 'update' },
|
|
25589
|
-
{ name: 'Delete', action: 'delete' },
|
|
26709
|
+
{ name: 'Edit', action: 'update', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" d="M11.2 2.6 13.4 4.8 6 12.2l-2.8.6.6-2.8z"/></svg>' },
|
|
26710
|
+
{ name: 'Delete', action: 'delete', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" d="M3.4 4.6h9.2M6.4 4.6V3.2h3.2v1.4M4.6 4.6 5 13h6l.4-8.4"/></svg>' },
|
|
25590
26711
|
];
|
|
25591
26712
|
this.tableHeaderActions = [
|
|
25592
|
-
{ name: 'Download All', action: 'download-all' },
|
|
25593
|
-
{ name: 'Download Selected', action: 'download-selected' },
|
|
26713
|
+
{ name: 'Download All', action: 'download-all', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" d="M8 2.5v7M5 6.6 8 9.6l3-3M3.2 12.6h9.6"/></svg>' },
|
|
26714
|
+
{ name: 'Download Selected', action: 'download-selected', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" d="M8 2.5v7M5 6.6 8 9.6l3-3M3.2 12.6h9.6"/></svg>' },
|
|
25594
26715
|
];
|
|
25595
26716
|
this.resourceType = 'service-policies';
|
|
25596
26717
|
this.validate = (formData) => {
|
|
@@ -25607,6 +26728,7 @@ class ServicePoliciesPageService extends ListPageServiceClass {
|
|
|
25607
26728
|
identityFilter = true;
|
|
25608
26729
|
break;
|
|
25609
26730
|
case 'postureRoles':
|
|
26731
|
+
case 'postureCheckRoles':
|
|
25610
26732
|
postureFilter = true;
|
|
25611
26733
|
break;
|
|
25612
26734
|
}
|
|
@@ -25619,6 +26741,10 @@ class ServicePoliciesPageService extends ListPageServiceClass {
|
|
|
25619
26741
|
this.selectedIdentityRoleAttributes = [];
|
|
25620
26742
|
this.selectedIdentityNamedAttributes = [];
|
|
25621
26743
|
}
|
|
26744
|
+
if (!postureFilter) {
|
|
26745
|
+
this.selectedPostureRoleAttributes = [];
|
|
26746
|
+
this.selectedPostureNamedAttributes = [];
|
|
26747
|
+
}
|
|
25622
26748
|
});
|
|
25623
26749
|
}
|
|
25624
26750
|
initTableColumns() {
|
|
@@ -25872,9 +26998,209 @@ class ServicePoliciesPageService extends ListPageServiceClass {
|
|
|
25872
26998
|
}
|
|
25873
26999
|
return tableColumns;
|
|
25874
27000
|
}
|
|
25875
|
-
|
|
27001
|
+
// Declarative ListColumn set for the new `lib-list-table` (Beta Features on).
|
|
27002
|
+
initListTableColumns() {
|
|
27003
|
+
this.initMenuActions();
|
|
27004
|
+
const serviceRolesHeaderComponentParams = {
|
|
27005
|
+
filterType: 'ATTRIBUTE',
|
|
27006
|
+
enableSorting: true,
|
|
27007
|
+
getRoleAttributes: () => this.serviceRoleAttributes,
|
|
27008
|
+
getNamedAttributes: () => this.serviceNamedAttributes,
|
|
27009
|
+
getSelectedRoleAttributes: () => this.selectedServiceRoleAttributes,
|
|
27010
|
+
getSelectedNamedAttributes: () => this.selectedServiceNamedAttributes,
|
|
27011
|
+
setSelectedRoleAttributes: (attributes) => {
|
|
27012
|
+
this.selectedServiceRoleAttributes = attributes;
|
|
27013
|
+
},
|
|
27014
|
+
setSelectedNamedAttributes: (attributes) => {
|
|
27015
|
+
this.selectedServiceNamedAttributes = attributes;
|
|
27016
|
+
},
|
|
27017
|
+
getNamedAttributesMap: () => this.serviceNamedAttributesMap,
|
|
27018
|
+
};
|
|
27019
|
+
const identityRolesHeaderComponentParams = {
|
|
27020
|
+
filterType: 'ATTRIBUTE',
|
|
27021
|
+
enableSorting: true,
|
|
27022
|
+
getRoleAttributes: () => this.identityRoleAttributes,
|
|
27023
|
+
getNamedAttributes: () => this.identityNamedAttributes,
|
|
27024
|
+
getSelectedRoleAttributes: () => this.selectedIdentityRoleAttributes,
|
|
27025
|
+
getSelectedNamedAttributes: () => this.selectedIdentityNamedAttributes,
|
|
27026
|
+
setSelectedRoleAttributes: (attributes) => {
|
|
27027
|
+
this.selectedIdentityRoleAttributes = attributes;
|
|
27028
|
+
},
|
|
27029
|
+
setSelectedNamedAttributes: (attributes) => {
|
|
27030
|
+
this.selectedIdentityNamedAttributes = attributes;
|
|
27031
|
+
},
|
|
27032
|
+
getNamedAttributesMap: () => this.identityNamedAttributesMap,
|
|
27033
|
+
};
|
|
27034
|
+
const postureRolesHeaderComponentParams = {
|
|
27035
|
+
filterType: 'ATTRIBUTE',
|
|
27036
|
+
enableSorting: true,
|
|
27037
|
+
getRoleAttributes: () => this.postureRoleAttributes,
|
|
27038
|
+
getNamedAttributes: () => this.postureNamedAttributes,
|
|
27039
|
+
getSelectedRoleAttributes: () => this.selectedPostureRoleAttributes,
|
|
27040
|
+
getSelectedNamedAttributes: () => this.selectedPostureNamedAttributes,
|
|
27041
|
+
setSelectedRoleAttributes: (attributes) => {
|
|
27042
|
+
this.selectedPostureRoleAttributes = attributes;
|
|
27043
|
+
},
|
|
27044
|
+
setSelectedNamedAttributes: (attributes) => {
|
|
27045
|
+
this.selectedPostureNamedAttributes = attributes;
|
|
27046
|
+
},
|
|
27047
|
+
getNamedAttributesMap: () => this.postureNamedAttributesMap,
|
|
27048
|
+
};
|
|
27049
|
+
// @ marks a named attribute, # a role attribute (matches the tag selector)
|
|
27050
|
+
const rolesChipRenderer = (row) => {
|
|
27051
|
+
const colId = row?.column?.colId;
|
|
27052
|
+
const attrs = row?.data?.[colId + 'Display'] || row?.data?.[colId] || [];
|
|
27053
|
+
return attrs.map((attr) => {
|
|
27054
|
+
const raw = String(attr?.name ?? attr ?? '').trim();
|
|
27055
|
+
if (!raw) {
|
|
27056
|
+
return '';
|
|
27057
|
+
}
|
|
27058
|
+
const isNamed = raw.charAt(0) === '@';
|
|
27059
|
+
const label = isNamed || raw.charAt(0) === '#' ? raw : '#' + raw;
|
|
27060
|
+
return `<span class="${isNamed ? 'lt-chip lt-chip-at' : 'lt-chip'}">${label}</span>`;
|
|
27061
|
+
}).join('');
|
|
27062
|
+
};
|
|
27063
|
+
const semanticFilterOptions = [
|
|
27064
|
+
{ label: 'Show All', value: '' },
|
|
27065
|
+
{ label: 'Any Of', value: 'AnyOf' },
|
|
27066
|
+
{ label: 'All Of', value: 'AllOf' },
|
|
27067
|
+
];
|
|
27068
|
+
const semanticRenderer = (row) => row?.data?.semantic === 'AnyOf' ? 'Any Of' : 'All Of';
|
|
27069
|
+
const openForm = (ctx) => {
|
|
27070
|
+
if (this.hasSelectedText()) {
|
|
27071
|
+
return;
|
|
27072
|
+
}
|
|
27073
|
+
this.serviceType = 'advanced';
|
|
27074
|
+
this.openEditForm(ctx.row?.id);
|
|
27075
|
+
};
|
|
27076
|
+
let tableColumns = [
|
|
27077
|
+
{
|
|
27078
|
+
key: 'name',
|
|
27079
|
+
field: 'name',
|
|
27080
|
+
label: 'Name',
|
|
27081
|
+
filterType: 'TEXTINPUT',
|
|
27082
|
+
cell: NameCellComponent,
|
|
27083
|
+
cellInputs: (ctx) => ({
|
|
27084
|
+
row: ctx.row,
|
|
27085
|
+
cellValue: ctx.value,
|
|
27086
|
+
cellConfig: { pathRoot: this.basePath, showIdentityIcons: false },
|
|
27087
|
+
}),
|
|
27088
|
+
onCellClick: openForm,
|
|
27089
|
+
resizable: true,
|
|
27090
|
+
cellClass: 'nf-cell-vert-align',
|
|
27091
|
+
sortable: true,
|
|
27092
|
+
onSort: this.sort.bind(this),
|
|
27093
|
+
sortDir: 'asc',
|
|
27094
|
+
width: 300,
|
|
27095
|
+
},
|
|
27096
|
+
{
|
|
27097
|
+
key: 'serviceRoles',
|
|
27098
|
+
field: 'serviceRoles',
|
|
27099
|
+
label: 'Service Attributes',
|
|
27100
|
+
filterType: 'ATTRIBUTE',
|
|
27101
|
+
headerParams: serviceRolesHeaderComponentParams,
|
|
27102
|
+
cellHtml: rolesChipRenderer,
|
|
27103
|
+
onCellClick: openForm,
|
|
27104
|
+
resizable: true,
|
|
27105
|
+
cellClass: 'nf-cell-vert-align',
|
|
27106
|
+
sortable: false,
|
|
27107
|
+
},
|
|
27108
|
+
{
|
|
27109
|
+
key: 'identityRoles',
|
|
27110
|
+
field: 'identityRoles',
|
|
27111
|
+
label: 'Identity Attributes',
|
|
27112
|
+
filterType: 'ATTRIBUTE',
|
|
27113
|
+
headerParams: identityRolesHeaderComponentParams,
|
|
27114
|
+
cellHtml: rolesChipRenderer,
|
|
27115
|
+
onCellClick: openForm,
|
|
27116
|
+
resizable: true,
|
|
27117
|
+
cellClass: 'nf-cell-vert-align',
|
|
27118
|
+
sortable: false,
|
|
27119
|
+
},
|
|
27120
|
+
{
|
|
27121
|
+
key: 'postureCheckRoles',
|
|
27122
|
+
field: 'postureCheckRoles',
|
|
27123
|
+
label: 'Posture Check Attributes',
|
|
27124
|
+
filterType: 'ATTRIBUTE',
|
|
27125
|
+
headerParams: postureRolesHeaderComponentParams,
|
|
27126
|
+
cellHtml: rolesChipRenderer,
|
|
27127
|
+
onCellClick: openForm,
|
|
27128
|
+
resizable: true,
|
|
27129
|
+
cellClass: 'nf-cell-vert-align',
|
|
27130
|
+
sortable: false,
|
|
27131
|
+
},
|
|
27132
|
+
{
|
|
27133
|
+
key: 'semantic',
|
|
27134
|
+
field: 'semantic',
|
|
27135
|
+
label: 'Semantic',
|
|
27136
|
+
filterType: 'SELECT',
|
|
27137
|
+
filterPlaceholder: 'Any semantic',
|
|
27138
|
+
filterOptions: semanticFilterOptions,
|
|
27139
|
+
cellHtml: semanticRenderer,
|
|
27140
|
+
onCellClick: openForm,
|
|
27141
|
+
resizable: true,
|
|
27142
|
+
sortable: true,
|
|
27143
|
+
onSort: this.sort.bind(this),
|
|
27144
|
+
cellClass: 'nf-cell-vert-align',
|
|
27145
|
+
width: 120,
|
|
27146
|
+
},
|
|
27147
|
+
{
|
|
27148
|
+
key: 'type',
|
|
27149
|
+
field: 'type',
|
|
27150
|
+
label: 'Type',
|
|
27151
|
+
filterType: 'SELECT',
|
|
27152
|
+
filterPlaceholder: 'Any type',
|
|
27153
|
+
filterOptions: [
|
|
27154
|
+
{ label: 'Show All', value: '' },
|
|
27155
|
+
{ label: 'Dial', value: 'Dial' },
|
|
27156
|
+
{ label: 'Bind', value: 'Bind' },
|
|
27157
|
+
],
|
|
27158
|
+
cellHtml: (row) => row?.data?.type ?? '',
|
|
27159
|
+
onCellClick: openForm,
|
|
27160
|
+
resizable: true,
|
|
27161
|
+
sortable: true,
|
|
27162
|
+
onSort: this.sort.bind(this),
|
|
27163
|
+
cellClass: 'nf-cell-vert-align',
|
|
27164
|
+
width: 100,
|
|
27165
|
+
},
|
|
27166
|
+
{
|
|
27167
|
+
key: 'createdAt',
|
|
27168
|
+
field: 'createdAt',
|
|
27169
|
+
label: 'Created At',
|
|
27170
|
+
valueFormatter: this.createdAtFormatter,
|
|
27171
|
+
filterType: 'DATETIME',
|
|
27172
|
+
filterPlaceholder: 'Any time',
|
|
27173
|
+
onCellClick: openForm,
|
|
27174
|
+
resizable: true,
|
|
27175
|
+
sortable: true,
|
|
27176
|
+
onSort: this.sort.bind(this),
|
|
27177
|
+
cellClass: 'nf-cell-vert-align',
|
|
27178
|
+
hidden: true,
|
|
27179
|
+
},
|
|
27180
|
+
{
|
|
27181
|
+
key: 'id',
|
|
27182
|
+
field: 'id',
|
|
27183
|
+
label: 'ID',
|
|
27184
|
+
filterType: 'TEXTINPUT',
|
|
27185
|
+
onCellClick: openForm,
|
|
27186
|
+
resizable: true,
|
|
27187
|
+
sortable: true,
|
|
27188
|
+
onSort: this.sort.bind(this),
|
|
27189
|
+
cellClass: 'nf-cell-vert-align',
|
|
27190
|
+
hidden: true,
|
|
27191
|
+
},
|
|
27192
|
+
];
|
|
27193
|
+
if (this.extService?.processListTableColumns) {
|
|
27194
|
+
tableColumns = this.extService.processListTableColumns(tableColumns);
|
|
27195
|
+
}
|
|
27196
|
+
return tableColumns;
|
|
27197
|
+
}
|
|
27198
|
+
getData(filters, sort, page, pageSize) {
|
|
25876
27199
|
// we can customize filters or sorting here before moving on...
|
|
25877
27200
|
this.paging.page = page || this.paging.page;
|
|
27201
|
+
if (pageSize) {
|
|
27202
|
+
this.paging.total = pageSize;
|
|
27203
|
+
}
|
|
25878
27204
|
return super.getTableData('service-policies', this.paging, filters, sort)
|
|
25879
27205
|
.then((results) => {
|
|
25880
27206
|
return this.processData(results);
|
|
@@ -26113,6 +27439,134 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
26113
27439
|
args: [SERVICE_POLICY_EXTENSION_SERVICE]
|
|
26114
27440
|
}] }] });
|
|
26115
27441
|
|
|
27442
|
+
/*
|
|
27443
|
+
Copyright NetFoundry Inc.
|
|
27444
|
+
|
|
27445
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
27446
|
+
you may not use this file except in compliance with the License.
|
|
27447
|
+
You may obtain a copy of the License at
|
|
27448
|
+
|
|
27449
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
27450
|
+
|
|
27451
|
+
Unless required by applicable law or agreed to in writing, software
|
|
27452
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
27453
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
27454
|
+
See the License for the specific language governing permissions and
|
|
27455
|
+
limitations under the License.
|
|
27456
|
+
*/
|
|
27457
|
+
// Service Policies page on `lib-list-table`, selected by the route when Beta Features is on.
|
|
27458
|
+
class ServicePoliciesListPageComponent extends ListPageComponent {
|
|
27459
|
+
constructor(svc, filterService, dialogForm, tabNames, consoleEvents, extService) {
|
|
27460
|
+
super(filterService, svc, consoleEvents, dialogForm, extService);
|
|
27461
|
+
this.svc = svc;
|
|
27462
|
+
this.tabNames = tabNames;
|
|
27463
|
+
this.extService = extService;
|
|
27464
|
+
this.title = 'Service Policies';
|
|
27465
|
+
this.isLoading = false;
|
|
27466
|
+
this.formDataChanged = false;
|
|
27467
|
+
this.tableId = 'service-policies';
|
|
27468
|
+
this.initialPageSize = 50;
|
|
27469
|
+
}
|
|
27470
|
+
loadTableColumns() {
|
|
27471
|
+
return this.svc.initListTableColumns();
|
|
27472
|
+
}
|
|
27473
|
+
ngOnInit() {
|
|
27474
|
+
this.tabs = this.tabNames.getTabs('policies');
|
|
27475
|
+
this.svc.refreshData = this.refreshData;
|
|
27476
|
+
this.getRoleAttributes();
|
|
27477
|
+
super.ngOnInit();
|
|
27478
|
+
}
|
|
27479
|
+
headerActionClicked(action) {
|
|
27480
|
+
switch (action) {
|
|
27481
|
+
case 'add':
|
|
27482
|
+
this.svc.serviceType = '';
|
|
27483
|
+
this.svc.openEditForm();
|
|
27484
|
+
break;
|
|
27485
|
+
case 'edit':
|
|
27486
|
+
this.svc.openEditForm();
|
|
27487
|
+
break;
|
|
27488
|
+
case 'delete':
|
|
27489
|
+
const selectedItems = this.rowData.filter((row) => {
|
|
27490
|
+
return row.selected;
|
|
27491
|
+
});
|
|
27492
|
+
const label = selectedItems.length > 1 ? 'service policies' : 'service policy';
|
|
27493
|
+
this.openBulkDelete(selectedItems, label);
|
|
27494
|
+
break;
|
|
27495
|
+
default:
|
|
27496
|
+
}
|
|
27497
|
+
}
|
|
27498
|
+
tableAction(event) {
|
|
27499
|
+
const extensionActionFound = this.handleExtensionActions(event);
|
|
27500
|
+
this.trackMenuAction(event?.action, event?.item);
|
|
27501
|
+
if (extensionActionFound) {
|
|
27502
|
+
return;
|
|
27503
|
+
}
|
|
27504
|
+
switch (event?.action) {
|
|
27505
|
+
case 'toggleAll':
|
|
27506
|
+
case 'toggleItem':
|
|
27507
|
+
this.itemToggled(event.item);
|
|
27508
|
+
break;
|
|
27509
|
+
case 'update':
|
|
27510
|
+
this.svc.serviceType = 'advanced';
|
|
27511
|
+
this.svc.openEditForm(event.item.id);
|
|
27512
|
+
break;
|
|
27513
|
+
case 'create':
|
|
27514
|
+
this.svc.openEditForm();
|
|
27515
|
+
break;
|
|
27516
|
+
case 'delete':
|
|
27517
|
+
this.deleteItem(event.item);
|
|
27518
|
+
break;
|
|
27519
|
+
case 'download-all':
|
|
27520
|
+
this.downloadAllItems();
|
|
27521
|
+
break;
|
|
27522
|
+
case 'download-selected':
|
|
27523
|
+
this.svc.downloadItems(this.selectedItems);
|
|
27524
|
+
break;
|
|
27525
|
+
default:
|
|
27526
|
+
break;
|
|
27527
|
+
}
|
|
27528
|
+
}
|
|
27529
|
+
trackMenuAction(action, item) {
|
|
27530
|
+
this.extService?.consoleActionTriggered?.emit({
|
|
27531
|
+
action,
|
|
27532
|
+
page: 'service-policy',
|
|
27533
|
+
item,
|
|
27534
|
+
type: 'menu-action'
|
|
27535
|
+
});
|
|
27536
|
+
}
|
|
27537
|
+
getRoleAttributes() {
|
|
27538
|
+
this.svc.getServiceRoleAttributes();
|
|
27539
|
+
this.svc.getIdentityRoleAttributes();
|
|
27540
|
+
this.svc.getServiceNamedAttributes();
|
|
27541
|
+
this.svc.getIdentityNamedAttributes();
|
|
27542
|
+
this.svc.getPostureNamedAttributes();
|
|
27543
|
+
}
|
|
27544
|
+
deleteItem(item) {
|
|
27545
|
+
this.openBulkDelete([item], 'service-policies');
|
|
27546
|
+
}
|
|
27547
|
+
closeModal(event) {
|
|
27548
|
+
this.svc.sideModalOpen = false;
|
|
27549
|
+
if (event?.refresh) {
|
|
27550
|
+
this.refreshData();
|
|
27551
|
+
}
|
|
27552
|
+
}
|
|
27553
|
+
dataChanged(event) {
|
|
27554
|
+
this.formDataChanged = event;
|
|
27555
|
+
}
|
|
27556
|
+
ngOnDestroy() {
|
|
27557
|
+
super.ngOnDestroy();
|
|
27558
|
+
}
|
|
27559
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ServicePoliciesListPageComponent, deps: [{ token: ServicePoliciesPageService }, { token: DataTableFilterService }, { token: i5.MatDialog }, { token: TabNameService }, { token: ConsoleEventsService }, { token: SERVICE_POLICY_EXTENSION_SERVICE }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
27560
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: ServicePoliciesListPageComponent, isStandalone: false, selector: "lib-service-policies-list", usesInheritance: true, ngImport: i0, template: "<div class=\"ziti-page-container ziti-service-policies-container lt-skin-page\">\n <lib-list-table-header\n [title]=\"title\"\n subtitle=\"Control which identities can dial or bind which services\"\n createLabel=\"Create Service Policy\"\n infoText=\"Service policies grant identities access to dial or bind services.\"\n [tabs]=\"tabs\"\n [showAdd]=\"!itemsSelected\"\n [blockCreate]=\"headerBlockCreate\"\n [blockDelete]=\"headerBlockDelete\"\n (actionClicked)=\"headerActionClicked($event)\"\n >\n <span header-icon class=\"icon-policies\" aria-hidden=\"true\"></span>\n </lib-list-table-header>\n <ng-content select=\"[slot=list-page-subheader]\"></ng-content>\n <lib-list-table class=\"lt-skin\" [tableId]=\"tableId\" [initialPageSize]=\"initialPageSize\"\n [noItemsReadonly]=\"headerBlockCreate\"\n [accessDenied]=\"headerBlockRead\"\n [rowData]=\"rowData\"\n [isLoading]=\"isLoading\"\n [columns]=\"columnDefs\"\n (actionRequested)=\"tableAction($event)\"\n [startCount]=\"startCount\"\n [endCount]=\"endCount\"\n [totalCount]=\"totalCount\"\n [filterApplied]=\"filterApplied\"\n [menuItems]=\"svc.menuItems\"\n [headerActions]=\"svc.tableHeaderActions\"\n [noItemsImage]=\"'No_Clients'\"\n (tableReady)=\"tableReady($event)\"\n >\n </lib-list-table>\n</div>\n@if (isLoading) {\n <lib-loading-indicator [isLoading]=\"isLoading\"></lib-loading-indicator>\n}\n", styles: [""], dependencies: [{ kind: "component", type: ListTableHeaderComponent, selector: "lib-list-table-header", inputs: ["title", "subtitle", "createLabel", "infoText", "tabs", "showAdd", "blockCreate", "blockDelete", "tabsUseRouter", "activeTab"], outputs: ["actionClicked", "tabClicked"] }, { kind: "component", type: ListTableComponent, selector: "lib-list-table", inputs: ["tableId", "columns", "rowData", "isLoading", "options", "loadChildren", "childColumnsByLevel", "hasNext", "hasPrev", "startCount", "endCount", "totalCount", "filterApplied", "menuItems", "headerActions", "noItemsImage", "showNoItemsAdd", "noItemsReadonly", "accessDenied", "entityTypeName", "filterName", "filterColumn", "treeVariant", "showTreeVariantToggle", "treeRail", "initialPageSize"], outputs: ["nodeToggled", "actionRequested", "tableReady", "selectionChanged"] }, { kind: "component", type: LoadingIndicatorComponent, selector: "lib-loading-indicator", inputs: ["isLoading"] }] }); }
|
|
27561
|
+
}
|
|
27562
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ServicePoliciesListPageComponent, decorators: [{
|
|
27563
|
+
type: Component,
|
|
27564
|
+
args: [{ selector: 'lib-service-policies-list', standalone: false, template: "<div class=\"ziti-page-container ziti-service-policies-container lt-skin-page\">\n <lib-list-table-header\n [title]=\"title\"\n subtitle=\"Control which identities can dial or bind which services\"\n createLabel=\"Create Service Policy\"\n infoText=\"Service policies grant identities access to dial or bind services.\"\n [tabs]=\"tabs\"\n [showAdd]=\"!itemsSelected\"\n [blockCreate]=\"headerBlockCreate\"\n [blockDelete]=\"headerBlockDelete\"\n (actionClicked)=\"headerActionClicked($event)\"\n >\n <span header-icon class=\"icon-policies\" aria-hidden=\"true\"></span>\n </lib-list-table-header>\n <ng-content select=\"[slot=list-page-subheader]\"></ng-content>\n <lib-list-table class=\"lt-skin\" [tableId]=\"tableId\" [initialPageSize]=\"initialPageSize\"\n [noItemsReadonly]=\"headerBlockCreate\"\n [accessDenied]=\"headerBlockRead\"\n [rowData]=\"rowData\"\n [isLoading]=\"isLoading\"\n [columns]=\"columnDefs\"\n (actionRequested)=\"tableAction($event)\"\n [startCount]=\"startCount\"\n [endCount]=\"endCount\"\n [totalCount]=\"totalCount\"\n [filterApplied]=\"filterApplied\"\n [menuItems]=\"svc.menuItems\"\n [headerActions]=\"svc.tableHeaderActions\"\n [noItemsImage]=\"'No_Clients'\"\n (tableReady)=\"tableReady($event)\"\n >\n </lib-list-table>\n</div>\n@if (isLoading) {\n <lib-loading-indicator [isLoading]=\"isLoading\"></lib-loading-indicator>\n}\n" }]
|
|
27565
|
+
}], ctorParameters: () => [{ type: ServicePoliciesPageService }, { type: DataTableFilterService }, { type: i5.MatDialog }, { type: TabNameService }, { type: ConsoleEventsService }, { type: undefined, decorators: [{
|
|
27566
|
+
type: Inject,
|
|
27567
|
+
args: [SERVICE_POLICY_EXTENSION_SERVICE]
|
|
27568
|
+
}] }] });
|
|
27569
|
+
|
|
26116
27570
|
class ServicePolicyFormComponent extends ProjectableForm {
|
|
26117
27571
|
constructor(settingsService, svc, zitiService, growlerService, extService, router, route, location, dialogForm) {
|
|
26118
27572
|
super(growlerService, extService, zitiService, router, route, location, settingsService, dialogForm);
|
|
@@ -26985,12 +28439,12 @@ class ServiceEdgeRouterPoliciesPageService extends ListPageServiceClass {
|
|
|
26985
28439
|
createdAt: '',
|
|
26986
28440
|
};
|
|
26987
28441
|
this.menuItems = [
|
|
26988
|
-
{ name: 'Edit', action: 'update' },
|
|
26989
|
-
{ name: 'Delete', action: 'delete' },
|
|
28442
|
+
{ name: 'Edit', action: 'update', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" d="M11.2 2.6 13.4 4.8 6 12.2l-2.8.6.6-2.8z"/></svg>' },
|
|
28443
|
+
{ name: 'Delete', action: 'delete', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" d="M3.4 4.6h9.2M6.4 4.6V3.2h3.2v1.4M4.6 4.6 5 13h6l.4-8.4"/></svg>' },
|
|
26990
28444
|
];
|
|
26991
28445
|
this.tableHeaderActions = [
|
|
26992
|
-
{ name: 'Download All', action: 'download-all' },
|
|
26993
|
-
{ name: 'Download Selected', action: 'download-selected' },
|
|
28446
|
+
{ name: 'Download All', action: 'download-all', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" d="M8 2.5v7M5 6.6 8 9.6l3-3M3.2 12.6h9.6"/></svg>' },
|
|
28447
|
+
{ name: 'Download Selected', action: 'download-selected', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" d="M8 2.5v7M5 6.6 8 9.6l3-3M3.2 12.6h9.6"/></svg>' },
|
|
26994
28448
|
];
|
|
26995
28449
|
this.resourceType = 'service-edge-router-policies';
|
|
26996
28450
|
this.validate = (formData) => {
|
|
@@ -27203,9 +28657,163 @@ class ServiceEdgeRouterPoliciesPageService extends ListPageServiceClass {
|
|
|
27203
28657
|
this.ID_COLUMN_DEF
|
|
27204
28658
|
];
|
|
27205
28659
|
}
|
|
27206
|
-
|
|
28660
|
+
// Declarative ListColumn set for the new `lib-list-table` (Beta Features on).
|
|
28661
|
+
initListTableColumns() {
|
|
28662
|
+
this.initMenuActions();
|
|
28663
|
+
const serviceRolesHeaderComponentParams = {
|
|
28664
|
+
filterType: 'ATTRIBUTE',
|
|
28665
|
+
enableSorting: true,
|
|
28666
|
+
getRoleAttributes: () => this.serviceRoleAttributes,
|
|
28667
|
+
getNamedAttributes: () => this.serviceNamedAttributes,
|
|
28668
|
+
getSelectedRoleAttributes: () => this.selectedServiceRoleAttributes,
|
|
28669
|
+
getSelectedNamedAttributes: () => this.selectedServiceNamedAttributes,
|
|
28670
|
+
setSelectedRoleAttributes: (attributes) => {
|
|
28671
|
+
this.selectedServiceRoleAttributes = attributes;
|
|
28672
|
+
},
|
|
28673
|
+
setSelectedNamedAttributes: (attributes) => {
|
|
28674
|
+
this.selectedServiceNamedAttributes = attributes;
|
|
28675
|
+
},
|
|
28676
|
+
getNamedAttributesMap: () => this.serviceNamedAttributesMap,
|
|
28677
|
+
};
|
|
28678
|
+
const routerRolesHeaderComponentParams = {
|
|
28679
|
+
filterType: 'ATTRIBUTE',
|
|
28680
|
+
enableSorting: true,
|
|
28681
|
+
getRoleAttributes: () => this.routerRoleAttributes,
|
|
28682
|
+
getNamedAttributes: () => this.routerNamedAttributes,
|
|
28683
|
+
getSelectedRoleAttributes: () => this.selectedRouterRoleAttributes,
|
|
28684
|
+
getSelectedNamedAttributes: () => this.selectedRouterNamedAttributes,
|
|
28685
|
+
setSelectedRoleAttributes: (attributes) => {
|
|
28686
|
+
this.selectedRouterRoleAttributes = attributes;
|
|
28687
|
+
},
|
|
28688
|
+
setSelectedNamedAttributes: (attributes) => {
|
|
28689
|
+
this.selectedRouterNamedAttributes = attributes;
|
|
28690
|
+
},
|
|
28691
|
+
getNamedAttributesMap: () => this.routerNamedAttributesMap,
|
|
28692
|
+
};
|
|
28693
|
+
// @ marks a named attribute, # a role attribute (matches the tag selector)
|
|
28694
|
+
const rolesChipRenderer = (row) => {
|
|
28695
|
+
const colId = row?.column?.colId;
|
|
28696
|
+
const attrs = row?.data?.[colId + 'Display'] || row?.data?.[colId] || [];
|
|
28697
|
+
return attrs.map((attr) => {
|
|
28698
|
+
const raw = String(attr?.name ?? attr ?? '').trim();
|
|
28699
|
+
if (!raw) {
|
|
28700
|
+
return '';
|
|
28701
|
+
}
|
|
28702
|
+
const isNamed = raw.charAt(0) === '@';
|
|
28703
|
+
const label = isNamed || raw.charAt(0) === '#' ? raw : '#' + raw;
|
|
28704
|
+
return `<span class="${isNamed ? 'lt-chip lt-chip-at' : 'lt-chip'}">${label}</span>`;
|
|
28705
|
+
}).join('');
|
|
28706
|
+
};
|
|
28707
|
+
const semanticFilterOptions = [
|
|
28708
|
+
{ label: 'Show All', value: '' },
|
|
28709
|
+
{ label: 'Any Of', value: 'AnyOf' },
|
|
28710
|
+
{ label: 'All Of', value: 'AllOf' },
|
|
28711
|
+
];
|
|
28712
|
+
const semanticRenderer = (row) => row?.data?.semantic === 'AnyOf' ? 'Any Of' : 'All Of';
|
|
28713
|
+
const openForm = (ctx) => {
|
|
28714
|
+
if (this.hasSelectedText()) {
|
|
28715
|
+
return;
|
|
28716
|
+
}
|
|
28717
|
+
this.serviceType = 'advanced';
|
|
28718
|
+
this.openEditForm(ctx.row?.id);
|
|
28719
|
+
};
|
|
28720
|
+
let tableColumns = [
|
|
28721
|
+
{
|
|
28722
|
+
key: 'name',
|
|
28723
|
+
field: 'name',
|
|
28724
|
+
label: 'Name',
|
|
28725
|
+
filterType: 'TEXTINPUT',
|
|
28726
|
+
cell: NameCellComponent,
|
|
28727
|
+
cellInputs: (ctx) => ({
|
|
28728
|
+
row: ctx.row,
|
|
28729
|
+
cellValue: ctx.value,
|
|
28730
|
+
cellConfig: { pathRoot: this.basePath, showIdentityIcons: false },
|
|
28731
|
+
}),
|
|
28732
|
+
onCellClick: openForm,
|
|
28733
|
+
resizable: true,
|
|
28734
|
+
cellClass: 'nf-cell-vert-align',
|
|
28735
|
+
sortable: true,
|
|
28736
|
+
onSort: this.sort.bind(this),
|
|
28737
|
+
sortDir: 'asc',
|
|
28738
|
+
width: 300,
|
|
28739
|
+
},
|
|
28740
|
+
{
|
|
28741
|
+
key: 'serviceRoles',
|
|
28742
|
+
field: 'serviceRoles',
|
|
28743
|
+
label: 'Service Attributes',
|
|
28744
|
+
filterType: 'ATTRIBUTE',
|
|
28745
|
+
headerParams: serviceRolesHeaderComponentParams,
|
|
28746
|
+
cellHtml: rolesChipRenderer,
|
|
28747
|
+
onCellClick: openForm,
|
|
28748
|
+
resizable: true,
|
|
28749
|
+
cellClass: 'nf-cell-vert-align',
|
|
28750
|
+
sortable: false,
|
|
28751
|
+
},
|
|
28752
|
+
{
|
|
28753
|
+
key: 'edgeRouterRoles',
|
|
28754
|
+
field: 'edgeRouterRoles',
|
|
28755
|
+
label: 'Router Attributes',
|
|
28756
|
+
filterType: 'ATTRIBUTE',
|
|
28757
|
+
headerParams: routerRolesHeaderComponentParams,
|
|
28758
|
+
cellHtml: rolesChipRenderer,
|
|
28759
|
+
onCellClick: openForm,
|
|
28760
|
+
resizable: true,
|
|
28761
|
+
cellClass: 'nf-cell-vert-align',
|
|
28762
|
+
sortable: false,
|
|
28763
|
+
},
|
|
28764
|
+
{
|
|
28765
|
+
key: 'semantic',
|
|
28766
|
+
field: 'semantic',
|
|
28767
|
+
label: 'Semantic',
|
|
28768
|
+
filterType: 'SELECT',
|
|
28769
|
+
filterPlaceholder: 'Any semantic',
|
|
28770
|
+
filterOptions: semanticFilterOptions,
|
|
28771
|
+
cellHtml: semanticRenderer,
|
|
28772
|
+
onCellClick: openForm,
|
|
28773
|
+
resizable: true,
|
|
28774
|
+
sortable: true,
|
|
28775
|
+
onSort: this.sort.bind(this),
|
|
28776
|
+
cellClass: 'nf-cell-vert-align',
|
|
28777
|
+
width: 120,
|
|
28778
|
+
},
|
|
28779
|
+
{
|
|
28780
|
+
key: 'createdAt',
|
|
28781
|
+
field: 'createdAt',
|
|
28782
|
+
label: 'Created At',
|
|
28783
|
+
valueFormatter: this.createdAtFormatter,
|
|
28784
|
+
filterType: 'DATETIME',
|
|
28785
|
+
filterPlaceholder: 'Any time',
|
|
28786
|
+
onCellClick: openForm,
|
|
28787
|
+
resizable: true,
|
|
28788
|
+
sortable: true,
|
|
28789
|
+
onSort: this.sort.bind(this),
|
|
28790
|
+
cellClass: 'nf-cell-vert-align',
|
|
28791
|
+
hidden: true,
|
|
28792
|
+
},
|
|
28793
|
+
{
|
|
28794
|
+
key: 'id',
|
|
28795
|
+
field: 'id',
|
|
28796
|
+
label: 'ID',
|
|
28797
|
+
filterType: 'TEXTINPUT',
|
|
28798
|
+
onCellClick: openForm,
|
|
28799
|
+
resizable: true,
|
|
28800
|
+
sortable: true,
|
|
28801
|
+
onSort: this.sort.bind(this),
|
|
28802
|
+
cellClass: 'nf-cell-vert-align',
|
|
28803
|
+
hidden: true,
|
|
28804
|
+
},
|
|
28805
|
+
];
|
|
28806
|
+
if (this.extService?.processListTableColumns) {
|
|
28807
|
+
tableColumns = this.extService.processListTableColumns(tableColumns);
|
|
28808
|
+
}
|
|
28809
|
+
return tableColumns;
|
|
28810
|
+
}
|
|
28811
|
+
getData(filters, sort, page, pageSize) {
|
|
27207
28812
|
// we can customize filters or sorting here before moving on...
|
|
27208
28813
|
this.paging.page = page || this.paging.page;
|
|
28814
|
+
if (pageSize) {
|
|
28815
|
+
this.paging.total = pageSize;
|
|
28816
|
+
}
|
|
27209
28817
|
return super.getTableData('service-edge-router-policies', this.paging, filters, sort)
|
|
27210
28818
|
.then((results) => {
|
|
27211
28819
|
return this.processData(results);
|
|
@@ -27413,6 +29021,129 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
27413
29021
|
args: [SHAREDZ_EXTENSION]
|
|
27414
29022
|
}] }] });
|
|
27415
29023
|
|
|
29024
|
+
/*
|
|
29025
|
+
Copyright NetFoundry Inc.
|
|
29026
|
+
|
|
29027
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
29028
|
+
you may not use this file except in compliance with the License.
|
|
29029
|
+
You may obtain a copy of the License at
|
|
29030
|
+
|
|
29031
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
29032
|
+
|
|
29033
|
+
Unless required by applicable law or agreed to in writing, software
|
|
29034
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
29035
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
29036
|
+
See the License for the specific language governing permissions and
|
|
29037
|
+
limitations under the License.
|
|
29038
|
+
*/
|
|
29039
|
+
// Service Edge Router Policies page on `lib-list-table`, selected by the route when Beta Features is on.
|
|
29040
|
+
class ServiceEdgeRouterPoliciesListPageComponent extends ListPageComponent {
|
|
29041
|
+
constructor(svc, filterService, dialogForm, tabNames, consoleEvents, extService) {
|
|
29042
|
+
super(filterService, svc, consoleEvents, dialogForm, extService);
|
|
29043
|
+
this.svc = svc;
|
|
29044
|
+
this.tabNames = tabNames;
|
|
29045
|
+
this.extService = extService;
|
|
29046
|
+
this.title = 'Service Edge Router Policies';
|
|
29047
|
+
this.isLoading = false;
|
|
29048
|
+
this.formDataChanged = false;
|
|
29049
|
+
this.tableId = 'service-edge-router-policies';
|
|
29050
|
+
this.initialPageSize = 50;
|
|
29051
|
+
}
|
|
29052
|
+
loadTableColumns() {
|
|
29053
|
+
return this.svc.initListTableColumns();
|
|
29054
|
+
}
|
|
29055
|
+
ngOnInit() {
|
|
29056
|
+
this.tabs = this.tabNames.getTabs('policies');
|
|
29057
|
+
this.svc.refreshData = this.refreshData;
|
|
29058
|
+
this.getRoleAttributes();
|
|
29059
|
+
super.ngOnInit();
|
|
29060
|
+
}
|
|
29061
|
+
headerActionClicked(action) {
|
|
29062
|
+
switch (action) {
|
|
29063
|
+
case 'add':
|
|
29064
|
+
this.svc.serviceType = '';
|
|
29065
|
+
this.svc.openEditForm();
|
|
29066
|
+
break;
|
|
29067
|
+
case 'edit':
|
|
29068
|
+
this.svc.openEditForm();
|
|
29069
|
+
break;
|
|
29070
|
+
case 'delete':
|
|
29071
|
+
const selectedItems = this.rowData.filter((row) => {
|
|
29072
|
+
return row.selected;
|
|
29073
|
+
});
|
|
29074
|
+
const label = selectedItems.length > 1 ? 'service edge router policies' : 'service edge router policy';
|
|
29075
|
+
this.openBulkDelete(selectedItems, label);
|
|
29076
|
+
break;
|
|
29077
|
+
default:
|
|
29078
|
+
}
|
|
29079
|
+
}
|
|
29080
|
+
tableAction(event) {
|
|
29081
|
+
this.trackMenuAction(event?.action, event?.item);
|
|
29082
|
+
switch (event?.action) {
|
|
29083
|
+
case 'toggleAll':
|
|
29084
|
+
case 'toggleItem':
|
|
29085
|
+
this.itemToggled(event.item);
|
|
29086
|
+
break;
|
|
29087
|
+
case 'update':
|
|
29088
|
+
this.svc.serviceType = 'advanced';
|
|
29089
|
+
this.svc.openEditForm(event.item?.id);
|
|
29090
|
+
break;
|
|
29091
|
+
case 'create':
|
|
29092
|
+
this.svc.openEditForm();
|
|
29093
|
+
break;
|
|
29094
|
+
case 'delete':
|
|
29095
|
+
this.deleteItem(event.item);
|
|
29096
|
+
break;
|
|
29097
|
+
case 'download-all':
|
|
29098
|
+
this.downloadAllItems();
|
|
29099
|
+
break;
|
|
29100
|
+
case 'download-selected':
|
|
29101
|
+
this.svc.downloadItems(this.selectedItems);
|
|
29102
|
+
break;
|
|
29103
|
+
default:
|
|
29104
|
+
break;
|
|
29105
|
+
}
|
|
29106
|
+
}
|
|
29107
|
+
trackMenuAction(action, item) {
|
|
29108
|
+
this.extService?.consoleActionTriggered?.emit({
|
|
29109
|
+
action,
|
|
29110
|
+
page: 'service-edge-router-policy',
|
|
29111
|
+
item,
|
|
29112
|
+
type: 'menu-action'
|
|
29113
|
+
});
|
|
29114
|
+
}
|
|
29115
|
+
getRoleAttributes() {
|
|
29116
|
+
this.svc.getEdgeRouterRoleAttributes();
|
|
29117
|
+
this.svc.getServiceRoleAttributes();
|
|
29118
|
+
this.svc.getServiceNamedAttributes();
|
|
29119
|
+
this.svc.getRouterNamedAttributes();
|
|
29120
|
+
}
|
|
29121
|
+
deleteItem(item) {
|
|
29122
|
+
this.openBulkDelete([item], 'service-edge-router-policies');
|
|
29123
|
+
}
|
|
29124
|
+
closeModal(event) {
|
|
29125
|
+
this.svc.sideModalOpen = false;
|
|
29126
|
+
if (event?.refresh) {
|
|
29127
|
+
this.refreshData();
|
|
29128
|
+
}
|
|
29129
|
+
}
|
|
29130
|
+
dataChanged(event) {
|
|
29131
|
+
this.formDataChanged = event;
|
|
29132
|
+
}
|
|
29133
|
+
ngOnDestroy() {
|
|
29134
|
+
super.ngOnDestroy();
|
|
29135
|
+
}
|
|
29136
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ServiceEdgeRouterPoliciesListPageComponent, deps: [{ token: ServiceEdgeRouterPoliciesPageService }, { token: DataTableFilterService }, { token: i5.MatDialog }, { token: TabNameService }, { token: ConsoleEventsService }, { token: SHAREDZ_EXTENSION }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
29137
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: ServiceEdgeRouterPoliciesListPageComponent, isStandalone: false, selector: "lib-service-edge-router-policies-list", usesInheritance: true, ngImport: i0, template: "<div class=\"ziti-page-container ziti-service-edge-router-policies-container lt-skin-page\">\n <lib-list-table-header\n [title]=\"title\"\n subtitle=\"Control which edge routers can carry which services\"\n createLabel=\"Create Service Edge Router Policy\"\n infoText=\"Service edge router policies define which edge routers can carry traffic for which services.\"\n [tabs]=\"tabs\"\n [showAdd]=\"!itemsSelected\"\n [blockCreate]=\"headerBlockCreate\"\n [blockDelete]=\"headerBlockDelete\"\n (actionClicked)=\"headerActionClicked($event)\"\n >\n <span header-icon class=\"icon-routerpolicy\" aria-hidden=\"true\"></span>\n </lib-list-table-header>\n <ng-content select=\"[slot=list-page-subheader]\"></ng-content>\n <lib-list-table class=\"lt-skin\" [tableId]=\"tableId\" [initialPageSize]=\"initialPageSize\"\n [noItemsReadonly]=\"headerBlockCreate\"\n [accessDenied]=\"headerBlockRead\"\n [rowData]=\"rowData\"\n [isLoading]=\"isLoading\"\n [columns]=\"columnDefs\"\n (actionRequested)=\"tableAction($event)\"\n [startCount]=\"startCount\"\n [endCount]=\"endCount\"\n [totalCount]=\"totalCount\"\n [filterApplied]=\"filterApplied\"\n [menuItems]=\"svc.menuItems\"\n [headerActions]=\"svc.tableHeaderActions\"\n [noItemsImage]=\"'No_Clients'\"\n (tableReady)=\"tableReady($event)\"\n >\n </lib-list-table>\n</div>\n@if (isLoading) {\n <lib-loading-indicator [isLoading]=\"isLoading\"></lib-loading-indicator>\n}\n", styles: [""], dependencies: [{ kind: "component", type: ListTableHeaderComponent, selector: "lib-list-table-header", inputs: ["title", "subtitle", "createLabel", "infoText", "tabs", "showAdd", "blockCreate", "blockDelete", "tabsUseRouter", "activeTab"], outputs: ["actionClicked", "tabClicked"] }, { kind: "component", type: ListTableComponent, selector: "lib-list-table", inputs: ["tableId", "columns", "rowData", "isLoading", "options", "loadChildren", "childColumnsByLevel", "hasNext", "hasPrev", "startCount", "endCount", "totalCount", "filterApplied", "menuItems", "headerActions", "noItemsImage", "showNoItemsAdd", "noItemsReadonly", "accessDenied", "entityTypeName", "filterName", "filterColumn", "treeVariant", "showTreeVariantToggle", "treeRail", "initialPageSize"], outputs: ["nodeToggled", "actionRequested", "tableReady", "selectionChanged"] }, { kind: "component", type: LoadingIndicatorComponent, selector: "lib-loading-indicator", inputs: ["isLoading"] }] }); }
|
|
29138
|
+
}
|
|
29139
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ServiceEdgeRouterPoliciesListPageComponent, decorators: [{
|
|
29140
|
+
type: Component,
|
|
29141
|
+
args: [{ selector: 'lib-service-edge-router-policies-list', standalone: false, template: "<div class=\"ziti-page-container ziti-service-edge-router-policies-container lt-skin-page\">\n <lib-list-table-header\n [title]=\"title\"\n subtitle=\"Control which edge routers can carry which services\"\n createLabel=\"Create Service Edge Router Policy\"\n infoText=\"Service edge router policies define which edge routers can carry traffic for which services.\"\n [tabs]=\"tabs\"\n [showAdd]=\"!itemsSelected\"\n [blockCreate]=\"headerBlockCreate\"\n [blockDelete]=\"headerBlockDelete\"\n (actionClicked)=\"headerActionClicked($event)\"\n >\n <span header-icon class=\"icon-routerpolicy\" aria-hidden=\"true\"></span>\n </lib-list-table-header>\n <ng-content select=\"[slot=list-page-subheader]\"></ng-content>\n <lib-list-table class=\"lt-skin\" [tableId]=\"tableId\" [initialPageSize]=\"initialPageSize\"\n [noItemsReadonly]=\"headerBlockCreate\"\n [accessDenied]=\"headerBlockRead\"\n [rowData]=\"rowData\"\n [isLoading]=\"isLoading\"\n [columns]=\"columnDefs\"\n (actionRequested)=\"tableAction($event)\"\n [startCount]=\"startCount\"\n [endCount]=\"endCount\"\n [totalCount]=\"totalCount\"\n [filterApplied]=\"filterApplied\"\n [menuItems]=\"svc.menuItems\"\n [headerActions]=\"svc.tableHeaderActions\"\n [noItemsImage]=\"'No_Clients'\"\n (tableReady)=\"tableReady($event)\"\n >\n </lib-list-table>\n</div>\n@if (isLoading) {\n <lib-loading-indicator [isLoading]=\"isLoading\"></lib-loading-indicator>\n}\n" }]
|
|
29142
|
+
}], ctorParameters: () => [{ type: ServiceEdgeRouterPoliciesPageService }, { type: DataTableFilterService }, { type: i5.MatDialog }, { type: TabNameService }, { type: ConsoleEventsService }, { type: undefined, decorators: [{
|
|
29143
|
+
type: Inject,
|
|
29144
|
+
args: [SHAREDZ_EXTENSION]
|
|
29145
|
+
}] }] });
|
|
29146
|
+
|
|
27416
29147
|
class ServiceEdgeRouterPolicy {
|
|
27417
29148
|
constructor() {
|
|
27418
29149
|
this.name = '';
|
|
@@ -32331,32 +34062,20 @@ class PostureChecksPageService extends ListPageServiceClass {
|
|
|
32331
34062
|
constructor(schemaSvc, settings, filterService, csvDownloadService, extService, router) {
|
|
32332
34063
|
super(settings, filterService, csvDownloadService, extService, router);
|
|
32333
34064
|
this.schemaSvc = schemaSvc;
|
|
34065
|
+
this.extService = extService;
|
|
32334
34066
|
this.router = router;
|
|
32335
34067
|
this.paging = this.DEFAULT_PAGING;
|
|
32336
34068
|
this.resourceType = 'posture-checks';
|
|
32337
34069
|
this.modalType = '';
|
|
32338
34070
|
this.menuItems = [
|
|
32339
|
-
{ name: 'Edit', action: 'update' },
|
|
32340
|
-
{ name: 'Delete', action: 'delete' },
|
|
34071
|
+
{ name: 'Edit', action: 'update', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" d="M11.2 2.6 13.4 4.8 6 12.2l-2.8.6.6-2.8z"/></svg>' },
|
|
34072
|
+
{ name: 'Delete', action: 'delete', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" d="M3.4 4.6h9.2M6.4 4.6V3.2h3.2v1.4M4.6 4.6 5 13h6l.4-8.4"/></svg>' },
|
|
32341
34073
|
];
|
|
32342
|
-
|
|
32343
|
-
|
|
32344
|
-
|
|
32345
|
-
|
|
32346
|
-
|
|
32347
|
-
filterOptions: [
|
|
32348
|
-
{ label: 'Domain', value: 'DOMAIN' },
|
|
32349
|
-
{ label: 'MAC', value: 'MAC' },
|
|
32350
|
-
{ label: 'MFA', value: 'MFA' },
|
|
32351
|
-
{ label: 'OS', value: 'OS' },
|
|
32352
|
-
{ label: 'Process', value: 'PROCESS' },
|
|
32353
|
-
{ label: 'Process Multi', value: 'MULTI_PROCESS' },
|
|
32354
|
-
]
|
|
32355
|
-
};
|
|
32356
|
-
const createdAtHeaderComponentParams = {
|
|
32357
|
-
filterType: 'DATETIME',
|
|
32358
|
-
};
|
|
32359
|
-
const detailsRenderer = (row) => {
|
|
34074
|
+
this.tableHeaderActions = [
|
|
34075
|
+
{ name: 'Download All', action: 'download-all', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" d="M8 2.5v7M5 6.6 8 9.6l3-3M3.2 12.6h9.6"/></svg>' },
|
|
34076
|
+
{ name: 'Download Selected', action: 'download-selected', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" d="M8 2.5v7M5 6.6 8 9.6l3-3M3.2 12.6h9.6"/></svg>' },
|
|
34077
|
+
];
|
|
34078
|
+
this.detailsRenderer = (row) => {
|
|
32360
34079
|
const data = row?.data || '';
|
|
32361
34080
|
let details = '';
|
|
32362
34081
|
if (data.typeId == "DOMAIN") {
|
|
@@ -32387,6 +34106,23 @@ class PostureChecksPageService extends ListPageServiceClass {
|
|
|
32387
34106
|
}
|
|
32388
34107
|
return details;
|
|
32389
34108
|
};
|
|
34109
|
+
}
|
|
34110
|
+
initTableColumns() {
|
|
34111
|
+
const osTypeFilterOptions = {
|
|
34112
|
+
filterType: 'SELECT',
|
|
34113
|
+
enableSorting: true,
|
|
34114
|
+
filterOptions: [
|
|
34115
|
+
{ label: 'Domain', value: 'DOMAIN' },
|
|
34116
|
+
{ label: 'MAC', value: 'MAC' },
|
|
34117
|
+
{ label: 'MFA', value: 'MFA' },
|
|
34118
|
+
{ label: 'OS', value: 'OS' },
|
|
34119
|
+
{ label: 'Process', value: 'PROCESS' },
|
|
34120
|
+
{ label: 'Process Multi', value: 'MULTI_PROCESS' },
|
|
34121
|
+
]
|
|
34122
|
+
};
|
|
34123
|
+
const createdAtHeaderComponentParams = {
|
|
34124
|
+
filterType: 'DATETIME',
|
|
34125
|
+
};
|
|
32390
34126
|
return [
|
|
32391
34127
|
{
|
|
32392
34128
|
colId: 'name',
|
|
@@ -32432,7 +34168,7 @@ class PostureChecksPageService extends ListPageServiceClass {
|
|
|
32432
34168
|
field: 'details',
|
|
32433
34169
|
headerName: 'Details',
|
|
32434
34170
|
headerComponent: TableColumnDefaultComponent,
|
|
32435
|
-
cellRenderer: detailsRenderer,
|
|
34171
|
+
cellRenderer: this.detailsRenderer,
|
|
32436
34172
|
cellRendererParams: { pathRoot: this.basePath },
|
|
32437
34173
|
onCellClicked: (data) => {
|
|
32438
34174
|
if (this.hasSelectedText()) {
|
|
@@ -32460,8 +34196,102 @@ class PostureChecksPageService extends ListPageServiceClass {
|
|
|
32460
34196
|
this.ID_COLUMN_DEF
|
|
32461
34197
|
];
|
|
32462
34198
|
}
|
|
32463
|
-
|
|
34199
|
+
// Declarative ListColumn set for the new `lib-list-table` (Beta Features on).
|
|
34200
|
+
initListTableColumns() {
|
|
34201
|
+
this.initMenuActions();
|
|
34202
|
+
const escapeHtml = (v) => String(v ?? '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
34203
|
+
const openForm = (ctx) => {
|
|
34204
|
+
if (this.hasSelectedText()) {
|
|
34205
|
+
return;
|
|
34206
|
+
}
|
|
34207
|
+
this.openEditForm(ctx.row?.id);
|
|
34208
|
+
};
|
|
34209
|
+
let tableColumns = [
|
|
34210
|
+
{
|
|
34211
|
+
key: 'name',
|
|
34212
|
+
field: 'name',
|
|
34213
|
+
label: 'Name',
|
|
34214
|
+
filterType: 'TEXTINPUT',
|
|
34215
|
+
cell: NameCellComponent,
|
|
34216
|
+
cellInputs: (ctx) => ({
|
|
34217
|
+
row: ctx.row,
|
|
34218
|
+
cellValue: ctx.value,
|
|
34219
|
+
cellConfig: { pathRoot: this.basePath, showIdentityIcons: false },
|
|
34220
|
+
}),
|
|
34221
|
+
onCellClick: openForm,
|
|
34222
|
+
resizable: true,
|
|
34223
|
+
cellClass: 'nf-cell-vert-align',
|
|
34224
|
+
sortable: true,
|
|
34225
|
+
onSort: this.sort.bind(this),
|
|
34226
|
+
width: 300,
|
|
34227
|
+
},
|
|
34228
|
+
{
|
|
34229
|
+
key: 'typeId',
|
|
34230
|
+
field: 'typeId',
|
|
34231
|
+
label: 'Type',
|
|
34232
|
+
filterType: 'SELECT',
|
|
34233
|
+
filterPlaceholder: 'Any type',
|
|
34234
|
+
filterOptions: [
|
|
34235
|
+
{ label: 'Show All', value: '' },
|
|
34236
|
+
{ label: 'Domain', value: 'DOMAIN' },
|
|
34237
|
+
{ label: 'MAC', value: 'MAC' },
|
|
34238
|
+
{ label: 'MFA', value: 'MFA' },
|
|
34239
|
+
{ label: 'OS', value: 'OS' },
|
|
34240
|
+
{ label: 'Process', value: 'PROCESS' },
|
|
34241
|
+
{ label: 'Process Multi', value: 'MULTI_PROCESS' },
|
|
34242
|
+
],
|
|
34243
|
+
onCellClick: openForm,
|
|
34244
|
+
resizable: true,
|
|
34245
|
+
cellClass: 'nf-cell-vert-align',
|
|
34246
|
+
width: 140,
|
|
34247
|
+
},
|
|
34248
|
+
{
|
|
34249
|
+
key: 'details',
|
|
34250
|
+
field: 'details',
|
|
34251
|
+
label: 'Details',
|
|
34252
|
+
cellHtml: (row) => escapeHtml(this.detailsRenderer(row)),
|
|
34253
|
+
onCellClick: openForm,
|
|
34254
|
+
resizable: true,
|
|
34255
|
+
cellClass: 'nf-cell-vert-align',
|
|
34256
|
+
},
|
|
34257
|
+
{
|
|
34258
|
+
key: 'createdAt',
|
|
34259
|
+
field: 'createdAt',
|
|
34260
|
+
label: 'Created At',
|
|
34261
|
+
valueFormatter: this.createdAtFormatter,
|
|
34262
|
+
filterType: 'DATETIME',
|
|
34263
|
+
filterPlaceholder: 'Any time',
|
|
34264
|
+
onCellClick: openForm,
|
|
34265
|
+
resizable: true,
|
|
34266
|
+
sortable: true,
|
|
34267
|
+
onSort: this.sort.bind(this),
|
|
34268
|
+
cellClass: 'nf-cell-vert-align',
|
|
34269
|
+
width: this.remToPx(10),
|
|
34270
|
+
},
|
|
34271
|
+
{
|
|
34272
|
+
key: 'id',
|
|
34273
|
+
field: 'id',
|
|
34274
|
+
label: 'ID',
|
|
34275
|
+
filterType: 'TEXTINPUT',
|
|
34276
|
+
onCellClick: openForm,
|
|
34277
|
+
resizable: true,
|
|
34278
|
+
sortable: true,
|
|
34279
|
+
onSort: this.sort.bind(this),
|
|
34280
|
+
cellClass: 'nf-cell-vert-align',
|
|
34281
|
+
hidden: true,
|
|
34282
|
+
},
|
|
34283
|
+
];
|
|
34284
|
+
if (this.extService?.processListTableColumns) {
|
|
34285
|
+
tableColumns = this.extService.processListTableColumns(tableColumns);
|
|
34286
|
+
}
|
|
34287
|
+
return tableColumns;
|
|
34288
|
+
}
|
|
34289
|
+
getData(filters, sort, page, pageSize) {
|
|
32464
34290
|
// we can customize filters or sorting here before moving on...
|
|
34291
|
+
this.paging.page = page || this.paging.page;
|
|
34292
|
+
if (pageSize) {
|
|
34293
|
+
this.paging.total = pageSize;
|
|
34294
|
+
}
|
|
32465
34295
|
return super.getTableData('posture-checks', this.paging, filters, sort)
|
|
32466
34296
|
.then((results) => {
|
|
32467
34297
|
return this.processData(results);
|
|
@@ -32603,6 +34433,120 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
32603
34433
|
args: [SHAREDZ_EXTENSION]
|
|
32604
34434
|
}] }] });
|
|
32605
34435
|
|
|
34436
|
+
/*
|
|
34437
|
+
Copyright NetFoundry Inc.
|
|
34438
|
+
|
|
34439
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
34440
|
+
you may not use this file except in compliance with the License.
|
|
34441
|
+
You may obtain a copy of the License at
|
|
34442
|
+
|
|
34443
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
34444
|
+
|
|
34445
|
+
Unless required by applicable law or agreed to in writing, software
|
|
34446
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
34447
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
34448
|
+
See the License for the specific language governing permissions and
|
|
34449
|
+
limitations under the License.
|
|
34450
|
+
*/
|
|
34451
|
+
// Posture Checks page on `lib-list-table`, selected by the route when Beta Features is on.
|
|
34452
|
+
class PostureChecksListPageComponent extends ListPageComponent {
|
|
34453
|
+
constructor(svc, filterService, dialogForm, tabNames, consoleEvents, extService) {
|
|
34454
|
+
super(filterService, svc, consoleEvents, dialogForm, extService);
|
|
34455
|
+
this.svc = svc;
|
|
34456
|
+
this.tabNames = tabNames;
|
|
34457
|
+
this.extService = extService;
|
|
34458
|
+
this.title = 'Posture Checks';
|
|
34459
|
+
this.isLoading = false;
|
|
34460
|
+
this.formDataChanged = false;
|
|
34461
|
+
this.tableId = 'posture-checks';
|
|
34462
|
+
this.initialPageSize = 50;
|
|
34463
|
+
}
|
|
34464
|
+
loadTableColumns() {
|
|
34465
|
+
return this.svc.initListTableColumns();
|
|
34466
|
+
}
|
|
34467
|
+
ngOnInit() {
|
|
34468
|
+
this.tabs = this.tabNames.getTabs('policies');
|
|
34469
|
+
this.svc.refreshData = this.refreshData;
|
|
34470
|
+
super.ngOnInit();
|
|
34471
|
+
}
|
|
34472
|
+
headerActionClicked(action) {
|
|
34473
|
+
switch (action) {
|
|
34474
|
+
case 'add':
|
|
34475
|
+
this.svc.openEditForm();
|
|
34476
|
+
break;
|
|
34477
|
+
case 'edit':
|
|
34478
|
+
this.svc.openEditForm();
|
|
34479
|
+
break;
|
|
34480
|
+
case 'delete':
|
|
34481
|
+
const selectedItems = this.rowData.filter((row) => {
|
|
34482
|
+
return row.selected;
|
|
34483
|
+
});
|
|
34484
|
+
const label = selectedItems.length > 1 ? 'posture checks' : 'posture check';
|
|
34485
|
+
this.openBulkDelete(selectedItems, label);
|
|
34486
|
+
break;
|
|
34487
|
+
default:
|
|
34488
|
+
}
|
|
34489
|
+
}
|
|
34490
|
+
tableAction(event) {
|
|
34491
|
+
this.trackMenuAction(event?.action, event?.item);
|
|
34492
|
+
switch (event?.action) {
|
|
34493
|
+
case 'toggleAll':
|
|
34494
|
+
case 'toggleItem':
|
|
34495
|
+
this.itemToggled(event.item);
|
|
34496
|
+
break;
|
|
34497
|
+
case 'update':
|
|
34498
|
+
this.svc.openEditForm(event.item?.id);
|
|
34499
|
+
break;
|
|
34500
|
+
case 'create':
|
|
34501
|
+
this.svc.openEditForm();
|
|
34502
|
+
break;
|
|
34503
|
+
case 'delete':
|
|
34504
|
+
this.deleteItem(event.item);
|
|
34505
|
+
break;
|
|
34506
|
+
case 'download-all':
|
|
34507
|
+
this.downloadAllItems();
|
|
34508
|
+
break;
|
|
34509
|
+
case 'download-selected':
|
|
34510
|
+
this.svc.downloadItems(this.selectedItems);
|
|
34511
|
+
break;
|
|
34512
|
+
default:
|
|
34513
|
+
break;
|
|
34514
|
+
}
|
|
34515
|
+
}
|
|
34516
|
+
trackMenuAction(action, item) {
|
|
34517
|
+
this.extService?.consoleActionTriggered?.emit({
|
|
34518
|
+
action,
|
|
34519
|
+
page: 'posture-check',
|
|
34520
|
+
item,
|
|
34521
|
+
type: 'menu-action'
|
|
34522
|
+
});
|
|
34523
|
+
}
|
|
34524
|
+
deleteItem(item) {
|
|
34525
|
+
this.openBulkDelete([item], 'posture-checks');
|
|
34526
|
+
}
|
|
34527
|
+
closeModal(event) {
|
|
34528
|
+
this.svc.sideModalOpen = false;
|
|
34529
|
+
if (event?.refresh) {
|
|
34530
|
+
this.refreshData();
|
|
34531
|
+
}
|
|
34532
|
+
}
|
|
34533
|
+
dataChanged(event) {
|
|
34534
|
+
this.formDataChanged = event;
|
|
34535
|
+
}
|
|
34536
|
+
ngOnDestroy() {
|
|
34537
|
+
super.ngOnDestroy();
|
|
34538
|
+
}
|
|
34539
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PostureChecksListPageComponent, deps: [{ token: PostureChecksPageService }, { token: DataTableFilterService }, { token: i5.MatDialog }, { token: TabNameService }, { token: ConsoleEventsService }, { token: SHAREDZ_EXTENSION }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
34540
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: PostureChecksListPageComponent, isStandalone: false, selector: "lib-posture-checks-list", usesInheritance: true, ngImport: i0, template: "<div class=\"ziti-page-container ziti-posture-checks-container lt-skin-page\">\n <lib-list-table-header\n [title]=\"title\"\n subtitle=\"Verify the state of identities before granting access\"\n createLabel=\"Create Posture Check\"\n infoText=\"Posture checks verify attributes of an identity, such as its OS or MFA status, before access is granted.\"\n [tabs]=\"tabs\"\n [showAdd]=\"!itemsSelected\"\n [blockCreate]=\"headerBlockCreate\"\n [blockDelete]=\"headerBlockDelete\"\n (actionClicked)=\"headerActionClicked($event)\"\n >\n <span header-icon class=\"icon-posturechecks\" aria-hidden=\"true\"></span>\n </lib-list-table-header>\n <ng-content select=\"[slot=list-page-subheader]\"></ng-content>\n <lib-list-table class=\"lt-skin\" [tableId]=\"tableId\" [initialPageSize]=\"initialPageSize\"\n [noItemsReadonly]=\"headerBlockCreate\"\n [accessDenied]=\"headerBlockRead\"\n [rowData]=\"rowData\"\n [isLoading]=\"isLoading\"\n [columns]=\"columnDefs\"\n (actionRequested)=\"tableAction($event)\"\n [startCount]=\"startCount\"\n [endCount]=\"endCount\"\n [totalCount]=\"totalCount\"\n [filterApplied]=\"filterApplied\"\n [menuItems]=\"svc.menuItems\"\n [headerActions]=\"svc.tableHeaderActions\"\n [noItemsImage]=\"'No_Clients'\"\n (tableReady)=\"tableReady($event)\"\n >\n </lib-list-table>\n</div>\n@if (isLoading) {\n <lib-loading-indicator [isLoading]=\"isLoading\"></lib-loading-indicator>\n}\n", styles: [""], dependencies: [{ kind: "component", type: ListTableHeaderComponent, selector: "lib-list-table-header", inputs: ["title", "subtitle", "createLabel", "infoText", "tabs", "showAdd", "blockCreate", "blockDelete", "tabsUseRouter", "activeTab"], outputs: ["actionClicked", "tabClicked"] }, { kind: "component", type: ListTableComponent, selector: "lib-list-table", inputs: ["tableId", "columns", "rowData", "isLoading", "options", "loadChildren", "childColumnsByLevel", "hasNext", "hasPrev", "startCount", "endCount", "totalCount", "filterApplied", "menuItems", "headerActions", "noItemsImage", "showNoItemsAdd", "noItemsReadonly", "accessDenied", "entityTypeName", "filterName", "filterColumn", "treeVariant", "showTreeVariantToggle", "treeRail", "initialPageSize"], outputs: ["nodeToggled", "actionRequested", "tableReady", "selectionChanged"] }, { kind: "component", type: LoadingIndicatorComponent, selector: "lib-loading-indicator", inputs: ["isLoading"] }] }); }
|
|
34541
|
+
}
|
|
34542
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PostureChecksListPageComponent, decorators: [{
|
|
34543
|
+
type: Component,
|
|
34544
|
+
args: [{ selector: 'lib-posture-checks-list', standalone: false, template: "<div class=\"ziti-page-container ziti-posture-checks-container lt-skin-page\">\n <lib-list-table-header\n [title]=\"title\"\n subtitle=\"Verify the state of identities before granting access\"\n createLabel=\"Create Posture Check\"\n infoText=\"Posture checks verify attributes of an identity, such as its OS or MFA status, before access is granted.\"\n [tabs]=\"tabs\"\n [showAdd]=\"!itemsSelected\"\n [blockCreate]=\"headerBlockCreate\"\n [blockDelete]=\"headerBlockDelete\"\n (actionClicked)=\"headerActionClicked($event)\"\n >\n <span header-icon class=\"icon-posturechecks\" aria-hidden=\"true\"></span>\n </lib-list-table-header>\n <ng-content select=\"[slot=list-page-subheader]\"></ng-content>\n <lib-list-table class=\"lt-skin\" [tableId]=\"tableId\" [initialPageSize]=\"initialPageSize\"\n [noItemsReadonly]=\"headerBlockCreate\"\n [accessDenied]=\"headerBlockRead\"\n [rowData]=\"rowData\"\n [isLoading]=\"isLoading\"\n [columns]=\"columnDefs\"\n (actionRequested)=\"tableAction($event)\"\n [startCount]=\"startCount\"\n [endCount]=\"endCount\"\n [totalCount]=\"totalCount\"\n [filterApplied]=\"filterApplied\"\n [menuItems]=\"svc.menuItems\"\n [headerActions]=\"svc.tableHeaderActions\"\n [noItemsImage]=\"'No_Clients'\"\n (tableReady)=\"tableReady($event)\"\n >\n </lib-list-table>\n</div>\n@if (isLoading) {\n <lib-loading-indicator [isLoading]=\"isLoading\"></lib-loading-indicator>\n}\n" }]
|
|
34545
|
+
}], ctorParameters: () => [{ type: PostureChecksPageService }, { type: DataTableFilterService }, { type: i5.MatDialog }, { type: TabNameService }, { type: ConsoleEventsService }, { type: undefined, decorators: [{
|
|
34546
|
+
type: Inject,
|
|
34547
|
+
args: [SHAREDZ_EXTENSION]
|
|
34548
|
+
}] }] });
|
|
34549
|
+
|
|
32606
34550
|
class PostureCheck {
|
|
32607
34551
|
constructor() {
|
|
32608
34552
|
this.name = '';
|
|
@@ -44280,6 +46224,7 @@ class OpenZitiConsoleLibModule {
|
|
|
44280
46224
|
SdkInfoTooltipComponent,
|
|
44281
46225
|
BooleanCellComponent,
|
|
44282
46226
|
TokenCellComponent,
|
|
46227
|
+
AttributeCellComponent,
|
|
44283
46228
|
TableCellSelectComponent,
|
|
44284
46229
|
TableColumnSelectComponent,
|
|
44285
46230
|
TableCellMenuComponent,
|
|
@@ -44319,12 +46264,15 @@ class OpenZitiConsoleLibModule {
|
|
|
44319
46264
|
CreationSummaryDialogComponent,
|
|
44320
46265
|
ConfigEditorComponent,
|
|
44321
46266
|
ServicePoliciesPageComponent,
|
|
46267
|
+
ServicePoliciesListPageComponent,
|
|
44322
46268
|
ServicePolicyFormComponent,
|
|
44323
46269
|
EdgeRouterPoliciesPageComponent,
|
|
46270
|
+
EdgeRouterPoliciesListPageComponent,
|
|
44324
46271
|
EdgeRouterPolicyFormComponent,
|
|
44325
46272
|
MultiActionButtonComponent,
|
|
44326
46273
|
TableCellNameComponent,
|
|
44327
46274
|
ServiceEdgeRouterPoliciesPageComponent,
|
|
46275
|
+
ServiceEdgeRouterPoliciesListPageComponent,
|
|
44328
46276
|
ServiceEdgeRouterPolicyFormComponent,
|
|
44329
46277
|
TerminatorsPageComponent,
|
|
44330
46278
|
ConfigurationFormComponent,
|
|
@@ -44338,6 +46286,7 @@ class OpenZitiConsoleLibModule {
|
|
|
44338
46286
|
VerifyCertificateComponent,
|
|
44339
46287
|
LoginDialogComponent,
|
|
44340
46288
|
PostureChecksPageComponent,
|
|
46289
|
+
PostureChecksListPageComponent,
|
|
44341
46290
|
PostureCheckFormComponent,
|
|
44342
46291
|
SessionsPageComponent,
|
|
44343
46292
|
SessionFormComponent,
|
|
@@ -44425,8 +46374,10 @@ class OpenZitiConsoleLibModule {
|
|
|
44425
46374
|
FormFieldToggleComponent,
|
|
44426
46375
|
ServiceFormComponent,
|
|
44427
46376
|
ServicePoliciesPageComponent,
|
|
46377
|
+
ServicePoliciesListPageComponent,
|
|
44428
46378
|
ServicePolicyFormComponent,
|
|
44429
46379
|
EdgeRouterPoliciesPageComponent,
|
|
46380
|
+
EdgeRouterPoliciesListPageComponent,
|
|
44430
46381
|
TerminatorsPageComponent,
|
|
44431
46382
|
TerminatorFormComponent,
|
|
44432
46383
|
JwtSignersPageComponent,
|
|
@@ -44435,6 +46386,7 @@ class OpenZitiConsoleLibModule {
|
|
|
44435
46386
|
AuthPolicyFormComponent,
|
|
44436
46387
|
LoginDialogComponent,
|
|
44437
46388
|
PostureChecksPageComponent,
|
|
46389
|
+
PostureChecksListPageComponent,
|
|
44438
46390
|
PostureCheckFormComponent,
|
|
44439
46391
|
SessionsPageComponent,
|
|
44440
46392
|
SessionFormComponent,
|
|
@@ -44536,6 +46488,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
44536
46488
|
SdkInfoTooltipComponent,
|
|
44537
46489
|
BooleanCellComponent,
|
|
44538
46490
|
TokenCellComponent,
|
|
46491
|
+
AttributeCellComponent,
|
|
44539
46492
|
TableCellSelectComponent,
|
|
44540
46493
|
TableColumnSelectComponent,
|
|
44541
46494
|
TableCellMenuComponent,
|
|
@@ -44575,12 +46528,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
44575
46528
|
CreationSummaryDialogComponent,
|
|
44576
46529
|
ConfigEditorComponent,
|
|
44577
46530
|
ServicePoliciesPageComponent,
|
|
46531
|
+
ServicePoliciesListPageComponent,
|
|
44578
46532
|
ServicePolicyFormComponent,
|
|
44579
46533
|
EdgeRouterPoliciesPageComponent,
|
|
46534
|
+
EdgeRouterPoliciesListPageComponent,
|
|
44580
46535
|
EdgeRouterPolicyFormComponent,
|
|
44581
46536
|
MultiActionButtonComponent,
|
|
44582
46537
|
TableCellNameComponent,
|
|
44583
46538
|
ServiceEdgeRouterPoliciesPageComponent,
|
|
46539
|
+
ServiceEdgeRouterPoliciesListPageComponent,
|
|
44584
46540
|
ServiceEdgeRouterPolicyFormComponent,
|
|
44585
46541
|
TerminatorsPageComponent,
|
|
44586
46542
|
ConfigurationFormComponent,
|
|
@@ -44594,6 +46550,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
44594
46550
|
VerifyCertificateComponent,
|
|
44595
46551
|
LoginDialogComponent,
|
|
44596
46552
|
PostureChecksPageComponent,
|
|
46553
|
+
PostureChecksListPageComponent,
|
|
44597
46554
|
PostureCheckFormComponent,
|
|
44598
46555
|
SessionsPageComponent,
|
|
44599
46556
|
SessionFormComponent,
|
|
@@ -44662,8 +46619,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
44662
46619
|
FormFieldToggleComponent,
|
|
44663
46620
|
ServiceFormComponent,
|
|
44664
46621
|
ServicePoliciesPageComponent,
|
|
46622
|
+
ServicePoliciesListPageComponent,
|
|
44665
46623
|
ServicePolicyFormComponent,
|
|
44666
46624
|
EdgeRouterPoliciesPageComponent,
|
|
46625
|
+
EdgeRouterPoliciesListPageComponent,
|
|
44667
46626
|
TerminatorsPageComponent,
|
|
44668
46627
|
TerminatorFormComponent,
|
|
44669
46628
|
JwtSignersPageComponent,
|
|
@@ -44672,6 +46631,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
44672
46631
|
AuthPolicyFormComponent,
|
|
44673
46632
|
LoginDialogComponent,
|
|
44674
46633
|
PostureChecksPageComponent,
|
|
46634
|
+
PostureChecksListPageComponent,
|
|
44675
46635
|
PostureCheckFormComponent,
|
|
44676
46636
|
SessionsPageComponent,
|
|
44677
46637
|
SessionFormComponent,
|
|
@@ -46197,7 +48157,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
46197
48157
|
*/
|
|
46198
48158
|
|
|
46199
48159
|
const ZAC_VERSION = {
|
|
46200
|
-
"version": "4.
|
|
48160
|
+
"version": "4.7.0"
|
|
46201
48161
|
};
|
|
46202
48162
|
|
|
46203
48163
|
/*
|
|
@@ -46208,5 +48168,5 @@ const ZAC_VERSION = {
|
|
|
46208
48168
|
* Generated bundle index. Do not edit.
|
|
46209
48169
|
*/
|
|
46210
48170
|
|
|
46211
|
-
export { APISessionFormComponent, APISessionsPageComponent, API_RESOURCE_TO_ENTITY_PERMISSION, ApiSessionsPageService, AttributesComponent, AuthPoliciesPageComponent, AuthPoliciesPageService, AuthPolicyFormComponent, AuthPolicyFormService, AuthService, BooleanCellComponent, BooleanToggleInputComponent, CallbackComponent, CardListComponent, CertificateAuthoritiesPageComponent, CertificateAuthoritiesPageService, CertificateAuthorityFormComponent, CertificateAuthorityFormService, CheckboxListInputComponent, ChipsInputComponent, ConfigBuilderComponent, ConfigBuilderModule, ConfigEditorComponent, ConfigTypeFormComponent, ConfigTypesPageComponent, ConfigurationFormComponent, ConfigurationService, ConfigurationsPageComponent, CsvDownloadService, DEACTIVATE_GUARD, DEFAULT_APP_CONFIG, DataTableFilterService, DeactivateGuardService, EDGE_ROUTER_EXTENSION_SERVICE, EDGE_ROUTER_POLICY_EXTENSION_SERVICE, EdgeRouter, EdgeRouterFormComponent, EdgeRouterFormService, EdgeRouterPoliciesPageComponent, EdgeRouterPoliciesPageService, EdgeRouterPolicyFormComponent, EdgeRouterPolicyFormService, EdgeRoutersPageComponent, EdgeRoutersPageService, Entity, ExtendableComponent, ExtensionsNoopService, FilterSelectComponent, FilterSelectOptionTemplateDirective, FilterSelectTriggerTemplateDirective, FormFieldContainerComponent, FormFieldToggleComponent, FormHeaderComponent, GeolocateComponent, GrowlerComponent, GrowlerModel, GrowlerModule, GrowlerService, HAControllerService, HaStatusIndicatorComponent, HeaderBarComponent, IDENTITY_EXTENSION_SERVICE, IdentitiesListPageComponent, IdentitiesPageComponent, IdentitiesPageService, Identity$1 as Identity, IdentityFormComponent, IdentityFormService, IdentityServicePathComponent, InsecureContextError, JsonViewComponent, JwtSignerFormComponent, JwtSignerFormService, JwtSignersPageComponent, JwtSignersPageService, KEY_CODES, ListFilterCellComponent, ListHeaderCellComponent, ListMenuComponent, ListPageComponent, ListPageServiceClass, ListTableAutoRefreshComponent, ListTableComponent, ListTableHeaderComponent, ListTableService, LoadingIndicatorComponent, LoggerService, LoginDialogComponent, LoginServiceClass, ManagementPermissionsService, NameCellComponent, NetworkVisualizerComponent, NodeDataService, NoopLoginService, NoopTabInterceptorService, NumberInputComponent, OIDC_CLIENT_ID, OIDC_CLIENT_ID_LEGACY, ObjectComponent, OidcEnvironmentalError, OidcSessionUnrecoverableError, OpenZitiConsoleLibModule, OsInfoTooltipComponent, PasswordInputComponent, PostureCheckFormComponent, PostureChecksPageComponent, PostureChecksPageService, PreviewListComponent, ProfileComponent, ProgressMeterComponent, ProgressMeterStep, ProgressWizardComponent, ProgressWizardStep, ProjectableForm, ProtocolAddressPortInputComponent, QuickAddComponent, ResetEnrollmentService, SAVE_DENIED_BY_PERMISSION_TOOLTIP, SERVICE_EDGE_ROUTER_POLICY_EXTENSION_SERVICE, SERVICE_EXTENSION_SERVICE, SERVICE_POLICY_EXTENSION_SERVICE, SETTINGS_SERVICE, SHAREDZ_EXTENSION, SdkInfoTooltipComponent, SelectCellComponent, SelectorInputComponent, ServiceEdgeRouterPoliciesPageComponent, ServiceEdgeRouterPoliciesPageService, ServiceEdgeRouterPolicyFormComponent, ServiceEdgeRouterPolicyFormService, ServiceFormComponent, ServiceFormService, ServicePoliciesPageComponent, ServicePoliciesPageService, ServicePolicyFormComponent, ServicePolicyFormService, ServicesPageComponent, ServicesPageService, Session, SessionFormComponent, SessionRefreshService, SessionsPageComponent, SessionsPageService, SettingsComponent, SettingsService, SettingsServiceClass, SideModalComponent, SideNavbarComponent, SideNavigatorComponent, SimpleServiceComponent, StringInputComponent, TabNameService, TagSelectorComponent, TerminatorFormComponent, TerminatorFormService, TerminatorsPageComponent, TerminatorsPageService, TextListInputComponent, TokenCellComponent, TransitRouterFormComponent, TransitRouterFormService, TransitRoutersPageComponent, TransitRoutersPageService, ValidationService, VerifyCertificateComponent, VisualizerServiceClass, ZAC_LOGIN_SERVICE, ZAC_VERSION, ZITI_DATA_SERVICE, ZITI_DOMAIN_CONTROLLER, ZITI_NAVIGATOR, ZITI_TAB_OVERRIDES, ZITI_URLS, ZacRoutingModule, ZitiControllerDataService, ZitiDataService, ZitiOidcService, decodeJwtPayload, jwtExpMs, jwtIatMs, pkceChallengeS256, playerFactory, randomUrlSafeString };
|
|
48171
|
+
export { APISessionFormComponent, APISessionsPageComponent, API_RESOURCE_TO_ENTITY_PERMISSION, ApiSessionsPageService, AttributesComponent, AuthPoliciesPageComponent, AuthPoliciesPageService, AuthPolicyFormComponent, AuthPolicyFormService, AuthService, BooleanCellComponent, BooleanToggleInputComponent, CallbackComponent, CardListComponent, CertificateAuthoritiesPageComponent, CertificateAuthoritiesPageService, CertificateAuthorityFormComponent, CertificateAuthorityFormService, CheckboxListInputComponent, ChipsInputComponent, ConfigBuilderComponent, ConfigBuilderModule, ConfigEditorComponent, ConfigTypeFormComponent, ConfigTypesPageComponent, ConfigurationFormComponent, ConfigurationService, ConfigurationsPageComponent, CsvDownloadService, DEACTIVATE_GUARD, DEFAULT_APP_CONFIG, DataTableFilterService, DeactivateGuardService, EDGE_ROUTER_EXTENSION_SERVICE, EDGE_ROUTER_POLICY_EXTENSION_SERVICE, EdgeRouter, EdgeRouterFormComponent, EdgeRouterFormService, EdgeRouterPoliciesListPageComponent, EdgeRouterPoliciesPageComponent, EdgeRouterPoliciesPageService, EdgeRouterPolicyFormComponent, EdgeRouterPolicyFormService, EdgeRoutersPageComponent, EdgeRoutersPageService, Entity, ExtendableComponent, ExtensionsNoopService, FilterSelectComponent, FilterSelectOptionTemplateDirective, FilterSelectTriggerTemplateDirective, FormFieldContainerComponent, FormFieldToggleComponent, FormHeaderComponent, GeolocateComponent, GrowlerComponent, GrowlerModel, GrowlerModule, GrowlerService, HAControllerService, HaStatusIndicatorComponent, HeaderBarComponent, IDENTITY_EXTENSION_SERVICE, IdentitiesListPageComponent, IdentitiesPageComponent, IdentitiesPageService, Identity$1 as Identity, IdentityFormComponent, IdentityFormService, IdentityServicePathComponent, InsecureContextError, JsonViewComponent, JwtSignerFormComponent, JwtSignerFormService, JwtSignersPageComponent, JwtSignersPageService, KEY_CODES, ListFilterCellComponent, ListHeaderCellComponent, ListMenuComponent, ListPageComponent, ListPageServiceClass, ListTableAutoRefreshComponent, ListTableComponent, ListTableHeaderComponent, ListTableService, LoadingIndicatorComponent, LoggerService, LoginDialogComponent, LoginServiceClass, ManagementPermissionsService, NameCellComponent, NetworkVisualizerComponent, NodeDataService, NoopLoginService, NoopTabInterceptorService, NumberInputComponent, OIDC_CLIENT_ID, OIDC_CLIENT_ID_LEGACY, ObjectComponent, OidcEnvironmentalError, OidcSessionUnrecoverableError, OpenZitiConsoleLibModule, OsInfoTooltipComponent, PasswordInputComponent, PostureCheckFormComponent, PostureChecksListPageComponent, PostureChecksPageComponent, PostureChecksPageService, PreviewListComponent, ProfileComponent, ProgressMeterComponent, ProgressMeterStep, ProgressWizardComponent, ProgressWizardStep, ProjectableForm, ProtocolAddressPortInputComponent, QuickAddComponent, ResetEnrollmentService, SAVE_DENIED_BY_PERMISSION_TOOLTIP, SERVICE_EDGE_ROUTER_POLICY_EXTENSION_SERVICE, SERVICE_EXTENSION_SERVICE, SERVICE_POLICY_EXTENSION_SERVICE, SETTINGS_SERVICE, SHAREDZ_EXTENSION, SdkInfoTooltipComponent, SelectCellComponent, SelectorInputComponent, ServiceEdgeRouterPoliciesListPageComponent, ServiceEdgeRouterPoliciesPageComponent, ServiceEdgeRouterPoliciesPageService, ServiceEdgeRouterPolicyFormComponent, ServiceEdgeRouterPolicyFormService, ServiceFormComponent, ServiceFormService, ServicePoliciesListPageComponent, ServicePoliciesPageComponent, ServicePoliciesPageService, ServicePolicyFormComponent, ServicePolicyFormService, ServicesPageComponent, ServicesPageService, Session, SessionFormComponent, SessionRefreshService, SessionsPageComponent, SessionsPageService, SettingsComponent, SettingsService, SettingsServiceClass, SideModalComponent, SideNavbarComponent, SideNavigatorComponent, SimpleServiceComponent, StringInputComponent, TabNameService, TagSelectorComponent, TerminatorFormComponent, TerminatorFormService, TerminatorsPageComponent, TerminatorsPageService, TextListInputComponent, TokenCellComponent, TransitRouterFormComponent, TransitRouterFormService, TransitRoutersPageComponent, TransitRoutersPageService, ValidationService, VerifyCertificateComponent, VisualizerServiceClass, ZAC_LOGIN_SERVICE, ZAC_VERSION, ZITI_DATA_SERVICE, ZITI_DOMAIN_CONTROLLER, ZITI_NAVIGATOR, ZITI_TAB_OVERRIDES, ZITI_URLS, ZacRoutingModule, ZitiControllerDataService, ZitiDataService, ZitiOidcService, decodeJwtPayload, jwtExpMs, jwtIatMs, pkceChallengeS256, playerFactory, randomUrlSafeString };
|
|
46212
48172
|
//# sourceMappingURL=openziti-ziti-console-lib.mjs.map
|