@openziti/ziti-console-lib 1.6.0 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/styles/dark.css +16 -0
- package/assets/styles/global.scss +142 -65
- package/fesm2022/openziti-ziti-console-lib.mjs +2200 -181
- package/fesm2022/openziti-ziti-console-lib.mjs.map +1 -1
- package/index.d.ts +471 -40
- 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)));
|
|
1909
|
+
}
|
|
1910
|
+
catch {
|
|
1911
|
+
// ignore
|
|
1912
|
+
}
|
|
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));
|
|
1888
1932
|
}
|
|
1889
1933
|
catch {
|
|
1890
1934
|
// ignore
|
|
1891
1935
|
}
|
|
1892
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,
|
|
@@ -7419,6 +7570,23 @@ class IdentitiesPageService extends ListPageServiceClass {
|
|
|
7419
7570
|
cellClass: 'nf-cell-vert-align',
|
|
7420
7571
|
width: 100,
|
|
7421
7572
|
},
|
|
7573
|
+
{
|
|
7574
|
+
key: 'externalId',
|
|
7575
|
+
field: 'externalId',
|
|
7576
|
+
label: 'External Id',
|
|
7577
|
+
filterType: 'TEXTINPUT',
|
|
7578
|
+
cellClass: 'nf-cell-vert-align',
|
|
7579
|
+
resizable: true,
|
|
7580
|
+
sortable: true,
|
|
7581
|
+
onSort: this.sort.bind(this),
|
|
7582
|
+
onCellClick: (ctx) => {
|
|
7583
|
+
if (this.hasSelectedText()) {
|
|
7584
|
+
return;
|
|
7585
|
+
}
|
|
7586
|
+
this.openEditForm(ctx.row?.id);
|
|
7587
|
+
},
|
|
7588
|
+
hidden: true,
|
|
7589
|
+
},
|
|
7422
7590
|
{
|
|
7423
7591
|
key: 'id',
|
|
7424
7592
|
field: 'id',
|
|
@@ -10169,6 +10337,11 @@ class ListTableHeaderComponent {
|
|
|
10169
10337
|
this.actionClicked = new EventEmitter();
|
|
10170
10338
|
this.tabClicked = new EventEmitter();
|
|
10171
10339
|
}
|
|
10340
|
+
/** Only show the tab strip when there is more than one visible tab; a lone tab
|
|
10341
|
+
* is just a redundant label, so the strip is hidden. */
|
|
10342
|
+
get showTabs() {
|
|
10343
|
+
return (this.tabs || []).filter((t) => !t?.hidden).length > 1;
|
|
10344
|
+
}
|
|
10172
10345
|
clickAction(value) {
|
|
10173
10346
|
this.actionClicked.emit(value);
|
|
10174
10347
|
}
|
|
@@ -10210,11 +10383,11 @@ class ListTableHeaderComponent {
|
|
|
10210
10383
|
return active === tab?.id || active === tab?.value || active === tab?.url || active === tab?.label;
|
|
10211
10384
|
}
|
|
10212
10385
|
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 (
|
|
10386
|
+
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
10387
|
}
|
|
10215
10388
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListTableHeaderComponent, decorators: [{
|
|
10216
10389
|
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 (
|
|
10390
|
+
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
10391
|
}], propDecorators: { title: [{
|
|
10219
10392
|
type: Input
|
|
10220
10393
|
}], subtitle: [{
|
|
@@ -11802,6 +11975,12 @@ class ListTableAutoRefreshComponent {
|
|
|
11802
11975
|
this.refresh = new EventEmitter();
|
|
11803
11976
|
this.secondsChange = new EventEmitter();
|
|
11804
11977
|
this.open = false;
|
|
11978
|
+
/** Menu geometry, all measured when the menu opens: left offset so labels line up
|
|
11979
|
+
* under the button's value, width so the right edge lands on the button's right
|
|
11980
|
+
* edge, and right padding so the check centers under the chevron. */
|
|
11981
|
+
this.menuLeft = 0;
|
|
11982
|
+
this.menuWidth = 0;
|
|
11983
|
+
this.menuPadRight = 0;
|
|
11805
11984
|
}
|
|
11806
11985
|
/** Current interval in seconds; 0 means off. */
|
|
11807
11986
|
set seconds(value) {
|
|
@@ -11823,7 +12002,37 @@ class ListTableAutoRefreshComponent {
|
|
|
11823
12002
|
}
|
|
11824
12003
|
toggleMenu(event) {
|
|
11825
12004
|
event.stopPropagation();
|
|
11826
|
-
this.open
|
|
12005
|
+
if (this.open) {
|
|
12006
|
+
this.open = false;
|
|
12007
|
+
return;
|
|
12008
|
+
}
|
|
12009
|
+
this.alignMenuToValue();
|
|
12010
|
+
this.open = true;
|
|
12011
|
+
}
|
|
12012
|
+
/** Position + size the menu so its labels sit directly under the button's value,
|
|
12013
|
+
* its right edge lands on the button's right edge (one shared border), and the
|
|
12014
|
+
* right-aligned check centers under the chevron. */
|
|
12015
|
+
alignMenuToValue() {
|
|
12016
|
+
const el = this.arEl?.nativeElement;
|
|
12017
|
+
const btn = el?.querySelector('.lt-ar-btn');
|
|
12018
|
+
const value = this.valueEl?.nativeElement?.getBoundingClientRect();
|
|
12019
|
+
const chevron = this.chevronEl?.nativeElement?.getBoundingClientRect();
|
|
12020
|
+
const container = el?.getBoundingClientRect();
|
|
12021
|
+
if (!btn || !value || !chevron || !container) {
|
|
12022
|
+
return;
|
|
12023
|
+
}
|
|
12024
|
+
const rem = parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;
|
|
12025
|
+
// left padding we back out of the value position so labels sit under it
|
|
12026
|
+
const itemPadLeft = 0.875 * rem;
|
|
12027
|
+
// half the check's box, so we can land its center rather than its edge
|
|
12028
|
+
const tickHalf = 0.375 * rem;
|
|
12029
|
+
const borderWidth = parseFloat(getComputedStyle(btn).borderRightWidth) || 1;
|
|
12030
|
+
this.menuLeft = Math.max(0, value.left - container.left - itemPadLeft);
|
|
12031
|
+
this.menuWidth = container.width - this.menuLeft;
|
|
12032
|
+
// the check is right-aligned, so its right padding is the gap from the menu's
|
|
12033
|
+
// right edge to the chevron center, less the border and half the check box
|
|
12034
|
+
const chevronCenter = (chevron.left + chevron.right) / 2;
|
|
12035
|
+
this.menuPadRight = Math.max(0, container.right - chevronCenter - borderWidth - tickHalf);
|
|
11827
12036
|
}
|
|
11828
12037
|
closeMenu() {
|
|
11829
12038
|
this.open = false;
|
|
@@ -11859,11 +12068,11 @@ class ListTableAutoRefreshComponent {
|
|
|
11859
12068
|
}
|
|
11860
12069
|
}
|
|
11861
12070
|
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=\"
|
|
12071
|
+
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
12072
|
}
|
|
11864
12073
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListTableAutoRefreshComponent, decorators: [{
|
|
11865
12074
|
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=\"
|
|
12075
|
+
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
12076
|
}], propDecorators: { seconds: [{
|
|
11868
12077
|
type: Input
|
|
11869
12078
|
}], loading: [{
|
|
@@ -11874,6 +12083,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
11874
12083
|
type: Output
|
|
11875
12084
|
}], secondsChange: [{
|
|
11876
12085
|
type: Output
|
|
12086
|
+
}], arEl: [{
|
|
12087
|
+
type: ViewChild,
|
|
12088
|
+
args: ['arEl']
|
|
12089
|
+
}], valueEl: [{
|
|
12090
|
+
type: ViewChild,
|
|
12091
|
+
args: ['valueEl']
|
|
12092
|
+
}], chevronEl: [{
|
|
12093
|
+
type: ViewChild,
|
|
12094
|
+
args: ['chevronEl']
|
|
11877
12095
|
}] } });
|
|
11878
12096
|
|
|
11879
12097
|
/**
|
|
@@ -11915,11 +12133,11 @@ class SelectCellComponent {
|
|
|
11915
12133
|
return tooltip;
|
|
11916
12134
|
}
|
|
11917
12135
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: SelectCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
11918
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: SelectCellComponent, isStandalone: false, selector: "lib-select-cell", inputs: { row: "row", toggleItem: "toggleItem" }, ngImport: i0, template: "@if (!item.hideSelect) {\n <div\n #toggleButton\n (click)=\"toggle(item)\"\n [ngClass]=\"{ selected: item.selected, disabled: disableToggle }\"\n attr.name=\"RowSelect0_{{ item.name }}\"\n class=\"row-toggle tSelect\"\n id=\"RowSelect0_{{ item.id }}\"\n attr.data-id=\"{{item.id}}\"\n [matTooltip]=\"tooltip\"\n ></div>\n}\n", styles: [".row-toggle.tSelect{box-sizing:border-box;width:1rem;height:1rem;border:1px solid var(--lt-border);border-radius:.25rem;cursor:pointer;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background-color:var(--lt-control-bg);background-repeat:no-repeat;background-position:center center;transition:border-color .12s,background-color .12s}.row-toggle.tSelect:hover{border-color:var(--lt-link)}.row-toggle.tSelect.selected{border-color:var(--lt-link);background-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\")}.row-toggle.tSelect.disabled{opacity:.3;cursor:not-allowed;transform:translate(-50%,-50%)!important}.row-toggle.tSelect.disabled:hover{border-color:var(--lt-border);background-color:var(--lt-control-bg)}\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"] }] }); }
|
|
12136
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: SelectCellComponent, isStandalone: false, selector: "lib-select-cell", inputs: { row: "row", toggleItem: "toggleItem" }, ngImport: i0, template: "@if (!item.hideSelect) {\n <div\n #toggleButton\n (click)=\"toggle(item)\"\n [ngClass]=\"{ selected: item.selected, indeterminate: item.indeterminate && !item.selected, disabled: disableToggle }\"\n attr.name=\"RowSelect0_{{ item.name }}\"\n class=\"row-toggle tSelect\"\n id=\"RowSelect0_{{ item.id }}\"\n attr.data-id=\"{{item.id}}\"\n [matTooltip]=\"tooltip\"\n ></div>\n}\n", styles: [".row-toggle.tSelect{box-sizing:border-box;width:1rem;height:1rem;border:1px solid var(--lt-border);border-radius:.25rem;cursor:pointer;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background-color:var(--lt-control-bg);background-repeat:no-repeat;background-position:center center;transition:border-color .12s,background-color .12s}.row-toggle.tSelect:hover{border-color:var(--lt-link)}.row-toggle.tSelect.selected{border-color:var(--lt-link);background-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\")}.row-toggle.tSelect.indeterminate{border-color:var(--lt-link);background-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' d='M3 7 L11 7'/%3E%3C/svg%3E\")}.row-toggle.tSelect.disabled{opacity:.3;cursor:not-allowed;transform:translate(-50%,-50%)!important}.row-toggle.tSelect.disabled:hover{border-color:var(--lt-border);background-color:var(--lt-control-bg)}\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"] }] }); }
|
|
11919
12137
|
}
|
|
11920
12138
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: SelectCellComponent, decorators: [{
|
|
11921
12139
|
type: Component,
|
|
11922
|
-
args: [{ selector: 'lib-select-cell', standalone: false, template: "@if (!item.hideSelect) {\n <div\n #toggleButton\n (click)=\"toggle(item)\"\n [ngClass]=\"{ selected: item.selected, disabled: disableToggle }\"\n attr.name=\"RowSelect0_{{ item.name }}\"\n class=\"row-toggle tSelect\"\n id=\"RowSelect0_{{ item.id }}\"\n attr.data-id=\"{{item.id}}\"\n [matTooltip]=\"tooltip\"\n ></div>\n}\n", styles: [".row-toggle.tSelect{box-sizing:border-box;width:1rem;height:1rem;border:1px solid var(--lt-border);border-radius:.25rem;cursor:pointer;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background-color:var(--lt-control-bg);background-repeat:no-repeat;background-position:center center;transition:border-color .12s,background-color .12s}.row-toggle.tSelect:hover{border-color:var(--lt-link)}.row-toggle.tSelect.selected{border-color:var(--lt-link);background-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\")}.row-toggle.tSelect.disabled{opacity:.3;cursor:not-allowed;transform:translate(-50%,-50%)!important}.row-toggle.tSelect.disabled:hover{border-color:var(--lt-border);background-color:var(--lt-control-bg)}\n"] }]
|
|
12140
|
+
args: [{ selector: 'lib-select-cell', standalone: false, template: "@if (!item.hideSelect) {\n <div\n #toggleButton\n (click)=\"toggle(item)\"\n [ngClass]=\"{ selected: item.selected, indeterminate: item.indeterminate && !item.selected, disabled: disableToggle }\"\n attr.name=\"RowSelect0_{{ item.name }}\"\n class=\"row-toggle tSelect\"\n id=\"RowSelect0_{{ item.id }}\"\n attr.data-id=\"{{item.id}}\"\n [matTooltip]=\"tooltip\"\n ></div>\n}\n", styles: [".row-toggle.tSelect{box-sizing:border-box;width:1rem;height:1rem;border:1px solid var(--lt-border);border-radius:.25rem;cursor:pointer;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background-color:var(--lt-control-bg);background-repeat:no-repeat;background-position:center center;transition:border-color .12s,background-color .12s}.row-toggle.tSelect:hover{border-color:var(--lt-link)}.row-toggle.tSelect.selected{border-color:var(--lt-link);background-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\")}.row-toggle.tSelect.indeterminate{border-color:var(--lt-link);background-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' d='M3 7 L11 7'/%3E%3C/svg%3E\")}.row-toggle.tSelect.disabled{opacity:.3;cursor:not-allowed;transform:translate(-50%,-50%)!important}.row-toggle.tSelect.disabled:hover{border-color:var(--lt-border);background-color:var(--lt-control-bg)}\n"] }]
|
|
11923
12141
|
}], propDecorators: { row: [{
|
|
11924
12142
|
type: Input
|
|
11925
12143
|
}], toggleItem: [{
|
|
@@ -11941,11 +12159,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
11941
12159
|
See the License for the specific language governing permissions and
|
|
11942
12160
|
limitations under the License.
|
|
11943
12161
|
*/
|
|
11944
|
-
/** Header cell for {@link ListTableComponent}: label
|
|
12162
|
+
/** Header cell for {@link ListTableComponent}: label and 3-state sort (asc/desc). */
|
|
11945
12163
|
class ListHeaderCellComponent {
|
|
11946
12164
|
constructor() {
|
|
11947
12165
|
this.sortChanged = new EventEmitter();
|
|
11948
|
-
this.hideColumn = new EventEmitter();
|
|
11949
12166
|
}
|
|
11950
12167
|
get enableSorting() {
|
|
11951
12168
|
return !!(this.column?.sortable || this.column?.enableSorting);
|
|
@@ -11959,24 +12176,18 @@ class ListHeaderCellComponent {
|
|
|
11959
12176
|
this.column.onSort?.(this.column.key, dir);
|
|
11960
12177
|
this.sortChanged.emit({ colId: this.column.key, dir });
|
|
11961
12178
|
}
|
|
11962
|
-
hide(event) {
|
|
11963
|
-
event.stopPropagation();
|
|
11964
|
-
this.hideColumn.emit(this.column);
|
|
11965
|
-
}
|
|
11966
12179
|
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"
|
|
12180
|
+
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
12181
|
}
|
|
11969
12182
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListHeaderCellComponent, decorators: [{
|
|
11970
12183
|
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
|
|
12184
|
+
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
12185
|
}], propDecorators: { column: [{
|
|
11973
12186
|
type: Input
|
|
11974
12187
|
}], sortDir: [{
|
|
11975
12188
|
type: Input
|
|
11976
12189
|
}], sortChanged: [{
|
|
11977
12190
|
type: Output
|
|
11978
|
-
}], hideColumn: [{
|
|
11979
|
-
type: Output
|
|
11980
12191
|
}] } });
|
|
11981
12192
|
|
|
11982
12193
|
/*
|
|
@@ -12018,6 +12229,8 @@ class ListFilterCellComponent {
|
|
|
12018
12229
|
this.selectedValues = [];
|
|
12019
12230
|
/** In-dropdown search text for the multi-select attribute combo. */
|
|
12020
12231
|
this.attrSearch = '';
|
|
12232
|
+
/** Match any selected attribute (or) vs every one (and); attribute filters only. */
|
|
12233
|
+
this.attrSemantic = 'AnyOf';
|
|
12021
12234
|
this.open = false;
|
|
12022
12235
|
this.menuLeft = 0;
|
|
12023
12236
|
this.menuTop = 0;
|
|
@@ -12217,10 +12430,19 @@ class ListFilterCellComponent {
|
|
|
12217
12430
|
value: [...this.selectedValues],
|
|
12218
12431
|
label: this.selectedValues.map((v) => this.labelForValue(v)).join(', '),
|
|
12219
12432
|
type: this.isAttributeMode ? 'ATTRIBUTE' : 'MULTISELECT',
|
|
12220
|
-
semantic: 'AnyOf',
|
|
12433
|
+
semantic: this.isAttributeMode ? this.attrSemantic : 'AnyOf',
|
|
12221
12434
|
};
|
|
12222
12435
|
this.filterService.updateFilter(filter);
|
|
12223
12436
|
}
|
|
12437
|
+
setSemantic(semantic) {
|
|
12438
|
+
if (this.attrSemantic === semantic) {
|
|
12439
|
+
return;
|
|
12440
|
+
}
|
|
12441
|
+
this.attrSemantic = semantic;
|
|
12442
|
+
if (this.selectedValues.length) {
|
|
12443
|
+
this.emitMulti();
|
|
12444
|
+
}
|
|
12445
|
+
}
|
|
12224
12446
|
// ------------------------------------------------------------------ date range
|
|
12225
12447
|
selectDatePreset(opt) {
|
|
12226
12448
|
this.selectedValue = opt.value;
|
|
@@ -12293,6 +12515,7 @@ class ListFilterCellComponent {
|
|
|
12293
12515
|
this.textValue = '';
|
|
12294
12516
|
this.dateRangeStart = null;
|
|
12295
12517
|
this.dateRangeEnd = null;
|
|
12518
|
+
this.attrSemantic = 'AnyOf';
|
|
12296
12519
|
this.removeThis();
|
|
12297
12520
|
}
|
|
12298
12521
|
removeThis() {
|
|
@@ -12319,6 +12542,9 @@ class ListFilterCellComponent {
|
|
|
12319
12542
|
}
|
|
12320
12543
|
else if (this.mode === 'multi') {
|
|
12321
12544
|
this.selectedValues = _.isArray(match.value) ? [...match.value] : [match.value];
|
|
12545
|
+
if (this.isAttributeMode) {
|
|
12546
|
+
this.attrSemantic = match.semantic === 'AllOf' ? 'AllOf' : 'AnyOf';
|
|
12547
|
+
}
|
|
12322
12548
|
}
|
|
12323
12549
|
else if (this.mode === 'daterange') {
|
|
12324
12550
|
// keep the locally chosen preset label; match.value is the raw [start,end] range
|
|
@@ -12328,11 +12554,11 @@ class ListFilterCellComponent {
|
|
|
12328
12554
|
}
|
|
12329
12555
|
}
|
|
12330
12556
|
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"] }] }); }
|
|
12557
|
+
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
12558
|
}
|
|
12333
12559
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListFilterCellComponent, decorators: [{
|
|
12334
12560
|
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"] }]
|
|
12561
|
+
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
12562
|
}], ctorParameters: () => [{ type: DataTableFilterService }, { type: ListTableService }], propDecorators: { column: [{
|
|
12337
12563
|
type: Input
|
|
12338
12564
|
}], trigger: [{
|
|
@@ -12376,6 +12602,103 @@ class ListTableComponent {
|
|
|
12376
12602
|
this.buildColumns();
|
|
12377
12603
|
}
|
|
12378
12604
|
}
|
|
12605
|
+
set rowData(value) {
|
|
12606
|
+
this._rowData = value || [];
|
|
12607
|
+
this.rebuildFlatRows();
|
|
12608
|
+
}
|
|
12609
|
+
get rowData() {
|
|
12610
|
+
return this._rowData;
|
|
12611
|
+
}
|
|
12612
|
+
// fitColumns: keep the table within its visible width when resizing - a column can only grow until
|
|
12613
|
+
// the other columns reach their set or minimum width, then the drag stops, so nothing is pushed
|
|
12614
|
+
// off screen into the horizontal scroll. Off by default (columns can grow past the view and scroll).
|
|
12615
|
+
set options(value) {
|
|
12616
|
+
const wasTree = !!this._options?.tree;
|
|
12617
|
+
this._options = value || {};
|
|
12618
|
+
this.toolbarControls = this.normalizeToolbar(this._options.toolbar);
|
|
12619
|
+
// rebuild the render list if tree mode was flipped after init, otherwise flatRows
|
|
12620
|
+
// keeps the pre-toggle shape
|
|
12621
|
+
if (this._initialized && !!this._options.tree !== wasTree) {
|
|
12622
|
+
this.rebuildFlatRows();
|
|
12623
|
+
}
|
|
12624
|
+
}
|
|
12625
|
+
get options() {
|
|
12626
|
+
return this._options;
|
|
12627
|
+
}
|
|
12628
|
+
normalizeToolbar(toolbar) {
|
|
12629
|
+
const resolve = (c) => ({
|
|
12630
|
+
show: c?.show !== false,
|
|
12631
|
+
disabled: !!c?.disabled,
|
|
12632
|
+
});
|
|
12633
|
+
return {
|
|
12634
|
+
search: resolve(toolbar?.search),
|
|
12635
|
+
filters: resolve(toolbar?.filters),
|
|
12636
|
+
refresh: resolve(toolbar?.refresh),
|
|
12637
|
+
autoRefresh: resolve(toolbar?.autoRefresh),
|
|
12638
|
+
columns: resolve(toolbar?.columns),
|
|
12639
|
+
pageSize: resolve(toolbar?.pageSize),
|
|
12640
|
+
pagination: resolve(toolbar?.pagination),
|
|
12641
|
+
};
|
|
12642
|
+
}
|
|
12643
|
+
/** Tree mode: columns per depth level (index = level; level 0 uses `columns`).
|
|
12644
|
+
* Nested rows render in their own grid with a per-level sub-header, so children
|
|
12645
|
+
* need not match the parent. Unset renders children with the parent's columns.
|
|
12646
|
+
* The bound value is the default; users can show/hide/reorder/resize child columns
|
|
12647
|
+
* per depth from the Columns menu, persisted per table. */
|
|
12648
|
+
set childColumnsByLevel(v) {
|
|
12649
|
+
this._declaredChildColumnsByLevel = v;
|
|
12650
|
+
this.buildChildColumns();
|
|
12651
|
+
}
|
|
12652
|
+
get childColumnsByLevel() {
|
|
12653
|
+
return this._childColumnsByLevel;
|
|
12654
|
+
}
|
|
12655
|
+
invalidateColumnCache() {
|
|
12656
|
+
this._childColsVersion++;
|
|
12657
|
+
}
|
|
12658
|
+
syncTreeMemo() {
|
|
12659
|
+
if (this._treeMemoVersion !== this._childColsVersion) {
|
|
12660
|
+
this._treeKeyCache.clear();
|
|
12661
|
+
this._leadOffsetCache.clear();
|
|
12662
|
+
this._treeMemoVersion = this._childColsVersion;
|
|
12663
|
+
}
|
|
12664
|
+
}
|
|
12665
|
+
/** Rebuilds the effective per-level child columns from the declared defaults with
|
|
12666
|
+
* any persisted order/visibility/width applied. */
|
|
12667
|
+
buildChildColumns() {
|
|
12668
|
+
const declared = this._declaredChildColumnsByLevel;
|
|
12669
|
+
if (!declared) {
|
|
12670
|
+
this._childColumnsByLevel = undefined;
|
|
12671
|
+
this.invalidateColumnCache();
|
|
12672
|
+
return;
|
|
12673
|
+
}
|
|
12674
|
+
this._childColumnsByLevel = declared.map((set, level) => set && set.length ? this.svc.applyPersistedChildState(level, set) : (set ? [...set] : set));
|
|
12675
|
+
this.invalidateColumnCache();
|
|
12676
|
+
}
|
|
12677
|
+
/** Tree look: 'card' floats each nested level as a bordered card; 'flat' renders
|
|
12678
|
+
* nested rows inline with the table, sub-headers as plain strips, no card chrome.
|
|
12679
|
+
* The bound value is the default; the user can switch it from the Columns menu and
|
|
12680
|
+
* the choice is remembered per table. */
|
|
12681
|
+
set treeVariant(v) {
|
|
12682
|
+
this._declaredTreeVariant = v;
|
|
12683
|
+
this._treeVariant = v;
|
|
12684
|
+
}
|
|
12685
|
+
get treeVariant() {
|
|
12686
|
+
return this._treeVariant;
|
|
12687
|
+
}
|
|
12688
|
+
get isFlatTree() {
|
|
12689
|
+
return this.isTreeMode && this.treeVariant === 'flat';
|
|
12690
|
+
}
|
|
12691
|
+
/** Show the flat/nested switch only when the table actually renders nested rows. */
|
|
12692
|
+
get canSwitchTreeVariant() {
|
|
12693
|
+
return this.isTreeMode && this.hasChildColumns;
|
|
12694
|
+
}
|
|
12695
|
+
setTreeVariant(variant) {
|
|
12696
|
+
if (this._treeVariant === variant) {
|
|
12697
|
+
return;
|
|
12698
|
+
}
|
|
12699
|
+
this._treeVariant = variant;
|
|
12700
|
+
this.svc.saveTreeVariant(variant);
|
|
12701
|
+
}
|
|
12379
12702
|
constructor(svc, tableFilterService, el, ngZone, sanitizer) {
|
|
12380
12703
|
this.svc = svc;
|
|
12381
12704
|
this.tableFilterService = tableFilterService;
|
|
@@ -12383,9 +12706,22 @@ class ListTableComponent {
|
|
|
12383
12706
|
this.ngZone = ngZone;
|
|
12384
12707
|
this.sanitizer = sanitizer;
|
|
12385
12708
|
this._tableId = '';
|
|
12386
|
-
this.
|
|
12709
|
+
this._rowData = [];
|
|
12387
12710
|
this.isLoading = false;
|
|
12388
|
-
this.
|
|
12711
|
+
this._options = { noSelect: false, noMenu: false };
|
|
12712
|
+
/** Resolved show/disabled state for each toolbar control, read by the template.
|
|
12713
|
+
* Every control shows and is enabled unless the host's `options.toolbar` says otherwise. */
|
|
12714
|
+
this.toolbarControls = this.normalizeToolbar(undefined);
|
|
12715
|
+
// Cached per level; a width change mutates the same column objects, so no rebuild is needed.
|
|
12716
|
+
this._childLevelCache = new Map();
|
|
12717
|
+
this._childColsVersion = 0;
|
|
12718
|
+
this._childLevelCacheVersion = -1;
|
|
12719
|
+
// per-level derived values, recomputed only when the column set changes, so the
|
|
12720
|
+
// template's per-cell/per-row calls stay cheap on every change-detection pass
|
|
12721
|
+
this._treeKeyCache = new Map();
|
|
12722
|
+
this._leadOffsetCache = new Map();
|
|
12723
|
+
this._treeMemoVersion = -1;
|
|
12724
|
+
this.nodeToggled = new EventEmitter();
|
|
12389
12725
|
this.hasNext = false;
|
|
12390
12726
|
this.hasPrev = false;
|
|
12391
12727
|
this.startCount = '-';
|
|
@@ -12403,6 +12739,12 @@ class ListTableComponent {
|
|
|
12403
12739
|
this.filterColumn = 'name';
|
|
12404
12740
|
this.actionRequested = new EventEmitter();
|
|
12405
12741
|
this.tableReady = new EventEmitter();
|
|
12742
|
+
/** Full set of selected rows (all depths) whenever the selection changes. */
|
|
12743
|
+
this.selectionChanged = new EventEmitter();
|
|
12744
|
+
/** The row the pointer is over, or null when it leaves. Emitted once per row (at the
|
|
12745
|
+
* row level, not per cell) so consumers can react to the whole hovered row, for
|
|
12746
|
+
* example to highlight that row's path in a connected diagram. */
|
|
12747
|
+
this.rowHover = new EventEmitter();
|
|
12406
12748
|
/** Full column list (includes hidden), after persisted state. */
|
|
12407
12749
|
this.allColumns = [];
|
|
12408
12750
|
/** Currently rendered columns (visible + ordered). */
|
|
@@ -12418,6 +12760,28 @@ class ListTableComponent {
|
|
|
12418
12760
|
this.selectedItem = { actionList: [] };
|
|
12419
12761
|
// ---- selection ----
|
|
12420
12762
|
this.allToggled = false;
|
|
12763
|
+
/** Rows actually rendered: in tree mode this is the roots plus the expanded
|
|
12764
|
+
* descendants in order; otherwise it is `rowData` unchanged. */
|
|
12765
|
+
this.flatRows = [];
|
|
12766
|
+
this._treeVariant = 'card';
|
|
12767
|
+
this._declaredTreeVariant = 'card';
|
|
12768
|
+
/** Show the flat/nested row-layout switch in the Columns menu. Hidden for now;
|
|
12769
|
+
* the variant still comes from the `treeVariant` input. */
|
|
12770
|
+
this.showTreeVariantToggle = false;
|
|
12771
|
+
/** Flat variant only: draw a running guide rail down the left of each nested level. */
|
|
12772
|
+
this.treeRail = false;
|
|
12773
|
+
this.treeIndentRem = 1.25;
|
|
12774
|
+
// nudges cards past the first nested level right so their edge lands on the
|
|
12775
|
+
// parent chevron (a nested chevron sits one grid-padding deeper than the root's)
|
|
12776
|
+
this.treeDeepAlignRem = 0.625;
|
|
12777
|
+
// flat first-column indent: base clears the select gutter, then one chevron-width
|
|
12778
|
+
// per level so each sub-header lines up under its parent row's name
|
|
12779
|
+
this.treeFlatBaseRem = 3.75;
|
|
12780
|
+
this.treeFlatStepRem = 2.125;
|
|
12781
|
+
// nested card's left inset before per-depth indent; must match the --lt-card-inset token
|
|
12782
|
+
this.treeCardBaseRem = 4;
|
|
12783
|
+
// width of the leading checkbox column injected into nested grids when selectChildren is on
|
|
12784
|
+
this.treeSelectColRem = 2.25;
|
|
12421
12785
|
// ---- column chooser (skinned show/hide + reorder panel) ----
|
|
12422
12786
|
this.showColumnChooser = false;
|
|
12423
12787
|
// ---- integrated toolbar: search + filter chips + pagination ----
|
|
@@ -12440,16 +12804,31 @@ class ListTableComponent {
|
|
|
12440
12804
|
this._initialColumns = [];
|
|
12441
12805
|
this._initialized = false;
|
|
12442
12806
|
this.subscription = new Subscription();
|
|
12443
|
-
|
|
12807
|
+
// expansion + lazily-loaded children keyed by __treeRowKey, so a rowData refresh
|
|
12808
|
+
// (auto-refresh, paging, filter) keeps the tree open instead of collapsing it
|
|
12809
|
+
this._expandedKeys = new Set();
|
|
12810
|
+
this._childrenCache = new Map();
|
|
12811
|
+
this._destroyed = false;
|
|
12812
|
+
this.trackRow = (index, row) => row?.__treeRowKey ?? row?.id ?? row?.name ?? index;
|
|
12444
12813
|
this.trackCol = (index, col) => col.key;
|
|
12445
12814
|
// ---------------------------------------------------------------- hover tooltip
|
|
12446
12815
|
this.hoverTooltip = null;
|
|
12447
|
-
// ----------------------------------------------------------------
|
|
12816
|
+
// ---------------------------------------------------------------- row hover
|
|
12817
|
+
/** The row currently under the pointer, so we only emit when it actually changes. */
|
|
12818
|
+
this.hoveredRow = null;
|
|
12448
12819
|
this.toggleItem = (item) => {
|
|
12449
12820
|
item.selected = !item.selected;
|
|
12450
|
-
this.
|
|
12821
|
+
this.syncSelectAll();
|
|
12451
12822
|
this.actionRequested.emit({ action: 'toggleItem', item });
|
|
12452
|
-
|
|
12823
|
+
this.emitSelection();
|
|
12824
|
+
};
|
|
12825
|
+
this._railCache = new Map();
|
|
12826
|
+
// The whole chooser row is draggable, and the label sits inside the visibility
|
|
12827
|
+
// toggle button, so a reorder drag ends with a click on that button. This guard
|
|
12828
|
+
// swallows that one click so dragging a row never also hides its column.
|
|
12829
|
+
this._chooserDragged = false;
|
|
12830
|
+
// ---- nested-column chooser: one expandable group per depth level ----
|
|
12831
|
+
this.nestedChooserOpen = new Set();
|
|
12453
12832
|
// ---------------------------------------------------------------- action menus
|
|
12454
12833
|
this.openActionMenu = (event, item) => {
|
|
12455
12834
|
this.selectedItem = item;
|
|
@@ -12485,7 +12864,12 @@ class ListTableComponent {
|
|
|
12485
12864
|
this._initialized = true;
|
|
12486
12865
|
// set directly (no emit) to avoid forcing a second fetch when a host pre-seeded it
|
|
12487
12866
|
this.tableFilterService.pageSize = this.svc.restorePageSize(this.initialPageSize);
|
|
12867
|
+
this._treeVariant = this.svc.restoreTreeVariant(this._declaredTreeVariant);
|
|
12868
|
+
this.buildChildColumns();
|
|
12488
12869
|
this.buildColumns();
|
|
12870
|
+
// all inputs are bound by now, so settle the render list against the final
|
|
12871
|
+
// tree flag (the rowData setter may have run before `options` arrived)
|
|
12872
|
+
this.rebuildFlatRows();
|
|
12489
12873
|
this.updateEntityTypeLabel();
|
|
12490
12874
|
this.subscription.add(this.tableFilterService.filtersChanged.subscribe((filters) => {
|
|
12491
12875
|
// chips: every non-hidden filter except the free-text search (shown in the box)
|
|
@@ -12514,6 +12898,7 @@ class ListTableComponent {
|
|
|
12514
12898
|
this.ensureFilterResizeObserver();
|
|
12515
12899
|
}
|
|
12516
12900
|
ngOnDestroy() {
|
|
12901
|
+
this._destroyed = true;
|
|
12517
12902
|
this.subscription.unsubscribe();
|
|
12518
12903
|
this.detachResizeListeners();
|
|
12519
12904
|
this.filterRO?.disconnect();
|
|
@@ -12683,6 +13068,7 @@ class ListTableComponent {
|
|
|
12683
13068
|
this.hiddenColumns = this.allColumns
|
|
12684
13069
|
.filter((c) => c.hidden)
|
|
12685
13070
|
.map((c) => ({ ...c, headerName: c.label }));
|
|
13071
|
+
this.invalidateColumnCache();
|
|
12686
13072
|
}
|
|
12687
13073
|
colWidth(col) {
|
|
12688
13074
|
return col.width != null ? `${col.width}px` : null;
|
|
@@ -12751,17 +13137,339 @@ class ListTableComponent {
|
|
|
12751
13137
|
onCellLeave() {
|
|
12752
13138
|
this.hoverTooltip = null;
|
|
12753
13139
|
}
|
|
13140
|
+
onRowHover(row) {
|
|
13141
|
+
if (this.hoveredRow === row) {
|
|
13142
|
+
return;
|
|
13143
|
+
}
|
|
13144
|
+
this.hoveredRow = row;
|
|
13145
|
+
this.rowHover.emit(row);
|
|
13146
|
+
}
|
|
13147
|
+
onRowLeave(row) {
|
|
13148
|
+
if (this.hoveredRow !== row) {
|
|
13149
|
+
return;
|
|
13150
|
+
}
|
|
13151
|
+
this.hoveredRow = null;
|
|
13152
|
+
this.rowHover.emit(null);
|
|
13153
|
+
}
|
|
13154
|
+
// ---------------------------------------------------------------- selection
|
|
13155
|
+
/** True when nested rows get checkboxes and join the selection (opt-in). */
|
|
13156
|
+
get childSelectEnabled() {
|
|
13157
|
+
return !!this.options?.selectChildren && !this.options?.noSelect;
|
|
13158
|
+
}
|
|
13159
|
+
/** Rows the checkboxes and select-all act on: top-level only, unless selectChildren
|
|
13160
|
+
* is set. Keeps select-all from marking nested rows a host that reads rowData never sees. */
|
|
13161
|
+
get selectableRows() {
|
|
13162
|
+
if (!this.isTreeMode || this.childSelectEnabled) {
|
|
13163
|
+
return this.flatRows;
|
|
13164
|
+
}
|
|
13165
|
+
return this.flatRows.filter((r) => (r.__treeLevel ?? 0) === 0);
|
|
13166
|
+
}
|
|
12754
13167
|
/** Some rows selected but the header select-all isn't fully on (indeterminate). */
|
|
12755
13168
|
get someSelected() {
|
|
12756
|
-
return !this.allToggled &&
|
|
13169
|
+
return !this.allToggled && this.selectableRows.some((r) => r.selected);
|
|
12757
13170
|
}
|
|
12758
13171
|
toggleAll() {
|
|
12759
13172
|
const newState = !this.allToggled;
|
|
12760
13173
|
this.allToggled = newState;
|
|
12761
|
-
|
|
12762
|
-
row.selected = newState;
|
|
12763
|
-
});
|
|
13174
|
+
this.selectableRows.forEach((row) => (row.selected = newState));
|
|
12764
13175
|
this.actionRequested.emit({ action: 'toggleAll' });
|
|
13176
|
+
this.emitSelection();
|
|
13177
|
+
}
|
|
13178
|
+
syncSelectAll() {
|
|
13179
|
+
const rows = this.selectableRows;
|
|
13180
|
+
this.allToggled = rows.length > 0 && rows.every((r) => r.selected);
|
|
13181
|
+
}
|
|
13182
|
+
/** Emit every selected row across all depths. Walks the full data, not just the rendered
|
|
13183
|
+
* rows, so a collapsed parent's selected children are still reported. */
|
|
13184
|
+
emitSelection() {
|
|
13185
|
+
const out = [];
|
|
13186
|
+
const walk = (rows) => {
|
|
13187
|
+
(rows || []).forEach((r) => {
|
|
13188
|
+
if (r.selected) {
|
|
13189
|
+
out.push(r);
|
|
13190
|
+
}
|
|
13191
|
+
if (Array.isArray(r.children)) {
|
|
13192
|
+
walk(r.children);
|
|
13193
|
+
}
|
|
13194
|
+
});
|
|
13195
|
+
};
|
|
13196
|
+
walk(this._rowData);
|
|
13197
|
+
this.selectionChanged.emit(out);
|
|
13198
|
+
}
|
|
13199
|
+
// ---------------------------------------------------------------- tree rows
|
|
13200
|
+
get isTreeMode() {
|
|
13201
|
+
return !!this.options?.tree;
|
|
13202
|
+
}
|
|
13203
|
+
/** True when per-level child columns are configured (children render in their own
|
|
13204
|
+
* grid with a sub-header rather than the parent's columns). */
|
|
13205
|
+
get hasChildColumns() {
|
|
13206
|
+
return !!(this.childColumnsByLevel && this.childColumnsByLevel.length);
|
|
13207
|
+
}
|
|
13208
|
+
/** Columns used at a given depth: level 0 is the main (visible) columns; deeper
|
|
13209
|
+
* levels use `childColumnsByLevel`, falling back to the deepest set defined. */
|
|
13210
|
+
columnsForLevel(level) {
|
|
13211
|
+
if (level <= 0 || !this.hasChildColumns) {
|
|
13212
|
+
return this.visibleColumns;
|
|
13213
|
+
}
|
|
13214
|
+
if (this._childLevelCacheVersion !== this._childColsVersion) {
|
|
13215
|
+
this._childLevelCache.clear();
|
|
13216
|
+
this._childLevelCacheVersion = this._childColsVersion;
|
|
13217
|
+
}
|
|
13218
|
+
const cached = this._childLevelCache.get(level);
|
|
13219
|
+
if (cached) {
|
|
13220
|
+
return cached;
|
|
13221
|
+
}
|
|
13222
|
+
const sets = this.childColumnsByLevel;
|
|
13223
|
+
const set = sets[level] ?? sets[sets.length - 1];
|
|
13224
|
+
const cols = (set ?? this.visibleColumns).filter((c) => !c.hidden);
|
|
13225
|
+
this._childLevelCache.set(level, cols);
|
|
13226
|
+
return cols;
|
|
13227
|
+
}
|
|
13228
|
+
/** Child columns the chooser lists at a depth: all declared ones (including hidden),
|
|
13229
|
+
* minus structural columns like the select checkbox or row-actions gutter. */
|
|
13230
|
+
allColumnsForLevel(level) {
|
|
13231
|
+
return (this._childColumnsByLevel?.[level] ?? []).filter((c) => !c.excludeFromChooser);
|
|
13232
|
+
}
|
|
13233
|
+
/** Depths that offer configurable columns (skips the level-0 placeholder and any
|
|
13234
|
+
* level that only holds structural columns), one chooser group per level. */
|
|
13235
|
+
get childLevels() {
|
|
13236
|
+
const sets = this._childColumnsByLevel;
|
|
13237
|
+
if (!sets) {
|
|
13238
|
+
return [];
|
|
13239
|
+
}
|
|
13240
|
+
const levels = [];
|
|
13241
|
+
sets.forEach((_set, level) => {
|
|
13242
|
+
if (level > 0 && this.allColumnsForLevel(level).length) {
|
|
13243
|
+
levels.push(level);
|
|
13244
|
+
}
|
|
13245
|
+
});
|
|
13246
|
+
return levels;
|
|
13247
|
+
}
|
|
13248
|
+
/** Chooser hint for a nested level: its first few column labels, then "+N". */
|
|
13249
|
+
childLevelLabel(level) {
|
|
13250
|
+
const labels = this.allColumnsForLevel(level)
|
|
13251
|
+
.map((c) => c.label)
|
|
13252
|
+
.filter(Boolean);
|
|
13253
|
+
const max = 3;
|
|
13254
|
+
if (labels.length <= max) {
|
|
13255
|
+
return labels.join(' / ');
|
|
13256
|
+
}
|
|
13257
|
+
return labels.slice(0, max).join(' / ') + ' +' + (labels.length - max);
|
|
13258
|
+
}
|
|
13259
|
+
/** Key of the column that carries the expand control + indentation for a column set:
|
|
13260
|
+
* the flagged one, else the first real data column (skipping a leading structural
|
|
13261
|
+
* column such as a select checkbox the host put at the start). */
|
|
13262
|
+
treeColumnKeyFor(cols) {
|
|
13263
|
+
return (cols.find((c) => c.treeColumn) || cols.find((c) => !c.excludeFromChooser) || cols[0])?.key;
|
|
13264
|
+
}
|
|
13265
|
+
treeColumnKeyForLevel(level) {
|
|
13266
|
+
this.syncTreeMemo();
|
|
13267
|
+
if (!this._treeKeyCache.has(level)) {
|
|
13268
|
+
this._treeKeyCache.set(level, this.treeColumnKeyFor(this.columnsForLevel(level)));
|
|
13269
|
+
}
|
|
13270
|
+
return this._treeKeyCache.get(level);
|
|
13271
|
+
}
|
|
13272
|
+
/** Width of the columns before the tree column, used to pull the flat first-column
|
|
13273
|
+
* indent back by whatever structural columns (like a select checkbox) sit ahead of
|
|
13274
|
+
* it, so its content still lands under the parent row's name. */
|
|
13275
|
+
treeLeadOffset(level) {
|
|
13276
|
+
this.syncTreeMemo();
|
|
13277
|
+
const cacheKey = `${level}|${this.childSelectEnabled}`;
|
|
13278
|
+
const hit = this._leadOffsetCache.get(cacheKey);
|
|
13279
|
+
if (hit !== undefined) {
|
|
13280
|
+
return hit;
|
|
13281
|
+
}
|
|
13282
|
+
const cols = this.columnsForLevel(level);
|
|
13283
|
+
const treeKey = this.treeColumnKeyForLevel(level);
|
|
13284
|
+
let px = 0;
|
|
13285
|
+
let count = 0;
|
|
13286
|
+
for (const c of cols) {
|
|
13287
|
+
if (c.key === treeKey) {
|
|
13288
|
+
break;
|
|
13289
|
+
}
|
|
13290
|
+
px += c.width ?? 0;
|
|
13291
|
+
count++;
|
|
13292
|
+
}
|
|
13293
|
+
const gap = 'var(--lt-tree-col-gap, 0.5rem)';
|
|
13294
|
+
// the injected select column (when on) sits before every data column
|
|
13295
|
+
const selRem = this.childSelectEnabled ? this.treeSelectColRem : 0;
|
|
13296
|
+
const gaps = count + (this.childSelectEnabled ? 1 : 0);
|
|
13297
|
+
const result = (!gaps && !selRem && !px) ? '0px' : `calc(${selRem}rem + ${px}px + ${gaps} * ${gap})`;
|
|
13298
|
+
this._leadOffsetCache.set(cacheKey, result);
|
|
13299
|
+
return result;
|
|
13300
|
+
}
|
|
13301
|
+
isTreeColumn(col, level) {
|
|
13302
|
+
return this.isTreeMode && col.key === this.treeColumnKeyForLevel(level);
|
|
13303
|
+
}
|
|
13304
|
+
isTreeCell(col) {
|
|
13305
|
+
return this.isTreeColumn(col, 0);
|
|
13306
|
+
}
|
|
13307
|
+
/** Columns a full-width nested row spans: the data columns plus the select and
|
|
13308
|
+
* menu gutters, matching the header's cell count. */
|
|
13309
|
+
get treeSpanCount() {
|
|
13310
|
+
return this.visibleColumns.length + (this.options?.noSelect ? 0 : 1) + (this.options?.noMenu ? 0 : 1);
|
|
13311
|
+
}
|
|
13312
|
+
/** Per-level indent (rem); the card variant nudges levels past the first so the edge meets the parent chevron. */
|
|
13313
|
+
treeIndentFor(level) {
|
|
13314
|
+
const align = this.treeVariant === 'card' && level >= 2 ? this.treeDeepAlignRem : 0;
|
|
13315
|
+
return level * this.treeIndentRem + align;
|
|
13316
|
+
}
|
|
13317
|
+
/** Flat variant: left pad (rem) of a nested row's first column (sub-header + data),
|
|
13318
|
+
* one chevron-width per level so it lines up under the parent row's name. */
|
|
13319
|
+
treeFlatFirstIndentRem(level) {
|
|
13320
|
+
return this.treeFlatBaseRem + level * this.treeFlatStepRem;
|
|
13321
|
+
}
|
|
13322
|
+
/** Flat variant: drop the chevron slot for a leaf-only level so values sit under their header. */
|
|
13323
|
+
showTreeLead(row) {
|
|
13324
|
+
return !(this.isFlatTree && row?.__treeSiblingsCanExpand === false);
|
|
13325
|
+
}
|
|
13326
|
+
/** Left inset (rem) of a nested card at a given depth, matching the td padding. */
|
|
13327
|
+
treeCardLeftRem(level) {
|
|
13328
|
+
return this.treeCardBaseRem + this.treeIndentFor(level);
|
|
13329
|
+
}
|
|
13330
|
+
/** Vertical guide lines redrawing each ancestor card's left edge at this row's
|
|
13331
|
+
* position, so a card's left border stays continuous where a nested card is
|
|
13332
|
+
* inserted between its rows. Returns a stack of 1px background gradients, or null
|
|
13333
|
+
* when there is no ancestor to redraw (roots and the first nested level). */
|
|
13334
|
+
treeAncestorRails(level) {
|
|
13335
|
+
const key = `${level}|${this._treeVariant}|${this.treeRail}|${this.isTreeMode}`;
|
|
13336
|
+
const cached = this._railCache.get(key);
|
|
13337
|
+
if (cached !== undefined) {
|
|
13338
|
+
return cached;
|
|
13339
|
+
}
|
|
13340
|
+
const rails = this.computeAncestorRails(level);
|
|
13341
|
+
this._railCache.set(key, rails);
|
|
13342
|
+
return rails;
|
|
13343
|
+
}
|
|
13344
|
+
computeAncestorRails(level) {
|
|
13345
|
+
if (!this.isTreeMode || level < 2) {
|
|
13346
|
+
return null;
|
|
13347
|
+
}
|
|
13348
|
+
const flat = this.treeVariant === 'flat';
|
|
13349
|
+
// card mode always redraws ancestor card borders; flat mode draws the rail
|
|
13350
|
+
// only when the optional running rail is turned on
|
|
13351
|
+
if (flat && !this.treeRail) {
|
|
13352
|
+
return null;
|
|
13353
|
+
}
|
|
13354
|
+
const color = flat
|
|
13355
|
+
? 'var(--lt-tree-rail, color-mix(in srgb, var(--lt-border) 55%, var(--lt-icon)))'
|
|
13356
|
+
: 'var(--lt-tree-card-border, color-mix(in srgb, var(--lt-border) 70%, var(--lt-icon)))';
|
|
13357
|
+
const rails = [];
|
|
13358
|
+
for (let k = 1; k < level; k++) {
|
|
13359
|
+
const x = this.treeCardLeftRem(k);
|
|
13360
|
+
rails.push(`linear-gradient(90deg, transparent ${x}rem, ${color} ${x}rem, ${color} calc(${x}rem + 1px), transparent calc(${x}rem + 1px))`);
|
|
13361
|
+
}
|
|
13362
|
+
return rails.join(', ');
|
|
13363
|
+
}
|
|
13364
|
+
gridTemplate(level) {
|
|
13365
|
+
const tracks = this.columnsForLevel(level)
|
|
13366
|
+
.map((c) => (c.width != null ? `${c.width}px` : 'minmax(0, 1fr)'));
|
|
13367
|
+
if (this.childSelectEnabled) {
|
|
13368
|
+
tracks.unshift(`${this.treeSelectColRem}rem`);
|
|
13369
|
+
}
|
|
13370
|
+
return tracks.join(' ');
|
|
13371
|
+
}
|
|
13372
|
+
hasChildren(row) {
|
|
13373
|
+
return Array.isArray(row?.children) && row.children.length > 0;
|
|
13374
|
+
}
|
|
13375
|
+
/** A row can be expanded unless it is a leaf, has no loaded children, and has no
|
|
13376
|
+
* loader left to try. */
|
|
13377
|
+
canExpand(row) {
|
|
13378
|
+
if (!this.isTreeMode || row?.leaf === true) {
|
|
13379
|
+
return false;
|
|
13380
|
+
}
|
|
13381
|
+
if (this.hasChildren(row)) {
|
|
13382
|
+
return true;
|
|
13383
|
+
}
|
|
13384
|
+
const key = row?.__treeRowKey;
|
|
13385
|
+
if (key && this._childrenCache.has(key)) {
|
|
13386
|
+
return true;
|
|
13387
|
+
}
|
|
13388
|
+
return !!this.loadChildren && row?.__treeLoaded !== true;
|
|
13389
|
+
}
|
|
13390
|
+
toggleNode(row) {
|
|
13391
|
+
if (!this.isTreeMode || row?.__treeLoading) {
|
|
13392
|
+
return;
|
|
13393
|
+
}
|
|
13394
|
+
const key = row.__treeRowKey;
|
|
13395
|
+
if (this._expandedKeys.has(key)) {
|
|
13396
|
+
this._expandedKeys.delete(key);
|
|
13397
|
+
this.rebuildFlatRows();
|
|
13398
|
+
this.nodeToggled.emit({ row, expanded: false });
|
|
13399
|
+
return;
|
|
13400
|
+
}
|
|
13401
|
+
if (this.loadChildren && !this.hasChildren(row) && !this._childrenCache.has(key)) {
|
|
13402
|
+
row.__treeLoading = true;
|
|
13403
|
+
row.__treeLoadError = false; // clear any previous failure on retry
|
|
13404
|
+
this.rebuildFlatRows(); // surface the spinner while children load
|
|
13405
|
+
// run the loader inside the executor so a synchronous throw rejects the
|
|
13406
|
+
// promise instead of escaping and leaving __treeLoading stuck on forever
|
|
13407
|
+
new Promise((resolve) => resolve(this.loadChildren(row))).then((children) => this.onChildrenLoaded(row, children), () => this.onChildrenLoaded(row, [], true));
|
|
13408
|
+
return;
|
|
13409
|
+
}
|
|
13410
|
+
this._expandedKeys.add(key);
|
|
13411
|
+
this.rebuildFlatRows();
|
|
13412
|
+
this.nodeToggled.emit({ row, expanded: true });
|
|
13413
|
+
}
|
|
13414
|
+
onChildrenLoaded(row, children, failed = false) {
|
|
13415
|
+
if (this._destroyed) {
|
|
13416
|
+
return;
|
|
13417
|
+
}
|
|
13418
|
+
row.__treeLoading = false;
|
|
13419
|
+
if (failed) {
|
|
13420
|
+
// flag the failure so the toggle shows a retry affordance, and leave it collapsed
|
|
13421
|
+
row.__treeLoadError = true;
|
|
13422
|
+
this.rebuildFlatRows();
|
|
13423
|
+
return;
|
|
13424
|
+
}
|
|
13425
|
+
const list = Array.isArray(children) ? children : [];
|
|
13426
|
+
this._childrenCache.set(row.__treeRowKey, list);
|
|
13427
|
+
row.children = list;
|
|
13428
|
+
row.__treeLoaded = true;
|
|
13429
|
+
if (!list.length) {
|
|
13430
|
+
row.leaf = true; // nothing under it, so stop offering the control
|
|
13431
|
+
}
|
|
13432
|
+
this._expandedKeys.add(row.__treeRowKey);
|
|
13433
|
+
this.rebuildFlatRows();
|
|
13434
|
+
this.nodeToggled.emit({ row, expanded: true });
|
|
13435
|
+
}
|
|
13436
|
+
/** Flatten the tree into the ordered render list, tagging each row with its depth.
|
|
13437
|
+
* Outside tree mode the render list is `rowData` as-is. */
|
|
13438
|
+
rebuildFlatRows() {
|
|
13439
|
+
if (!this.isTreeMode) {
|
|
13440
|
+
this.flatRows = this._rowData;
|
|
13441
|
+
return;
|
|
13442
|
+
}
|
|
13443
|
+
const out = [];
|
|
13444
|
+
const walk = (rows, level, parentKey) => {
|
|
13445
|
+
const list = rows || [];
|
|
13446
|
+
// when no sibling can expand, the level needs no chevron slot
|
|
13447
|
+
const siblingsCanExpand = list.some((r) => this.canExpand(r));
|
|
13448
|
+
list.forEach((row, idx) => {
|
|
13449
|
+
row.__treeLevel = level;
|
|
13450
|
+
row.__treeSiblingsCanExpand = siblingsCanExpand;
|
|
13451
|
+
// first child of a group drives the per-expansion sub-header;
|
|
13452
|
+
// first and last mark the top and bottom of the nested card
|
|
13453
|
+
row.__treeFirstChild = level > 0 && idx === 0;
|
|
13454
|
+
row.__treeLastChild = level > 0 && idx === list.length - 1;
|
|
13455
|
+
// branch-unique track key: the same entity can appear under two parents
|
|
13456
|
+
// in a flat tree, so fold the parent path in to keep @for keys distinct
|
|
13457
|
+
row.__treeRowKey = parentKey + '/' + (row?.id ?? row?.name ?? idx);
|
|
13458
|
+
// a rowData refresh replaces the row object; re-attach children we loaded
|
|
13459
|
+
// earlier so an expanded lazy node stays populated instead of emptying out
|
|
13460
|
+
if (!this.hasChildren(row) && this._childrenCache.has(row.__treeRowKey)) {
|
|
13461
|
+
row.children = this._childrenCache.get(row.__treeRowKey);
|
|
13462
|
+
row.__treeLoaded = true;
|
|
13463
|
+
}
|
|
13464
|
+
row.__treeExpanded = this._expandedKeys.has(row.__treeRowKey);
|
|
13465
|
+
out.push(row);
|
|
13466
|
+
if (row.__treeExpanded && this.hasChildren(row)) {
|
|
13467
|
+
walk(row.children, level + 1, row.__treeRowKey);
|
|
13468
|
+
}
|
|
13469
|
+
});
|
|
13470
|
+
};
|
|
13471
|
+
walk(this._rowData, 0, '');
|
|
13472
|
+
this.flatRows = out;
|
|
12765
13473
|
}
|
|
12766
13474
|
// ---------------------------------------------------------------- sort
|
|
12767
13475
|
onHeaderSort(event) {
|
|
@@ -12769,16 +13477,7 @@ class ListTableComponent {
|
|
|
12769
13477
|
c.sortDir = c.key === event.colId ? event.dir : undefined;
|
|
12770
13478
|
});
|
|
12771
13479
|
}
|
|
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
|
-
}
|
|
13480
|
+
// ---------------------------------------------------------------- show / reorder
|
|
12782
13481
|
showColumn(event) {
|
|
12783
13482
|
const target = this.allColumns.find((c) => c.key === event.column?.key);
|
|
12784
13483
|
if (!target) {
|
|
@@ -12801,7 +13500,9 @@ class ListTableComponent {
|
|
|
12801
13500
|
}
|
|
12802
13501
|
resetTableColumns() {
|
|
12803
13502
|
this.svc.reset();
|
|
13503
|
+
this._treeVariant = this._declaredTreeVariant;
|
|
12804
13504
|
this.allColumns = this._initialColumns.map((c) => ({ ...c }));
|
|
13505
|
+
this._childColumnsByLevel = this._declaredChildColumnsByLevel?.map((set) => set ? set.map((c) => ({ ...c })) : set);
|
|
12805
13506
|
this.updateVisible();
|
|
12806
13507
|
this.closeActionMenu();
|
|
12807
13508
|
}
|
|
@@ -12811,14 +13512,45 @@ class ListTableComponent {
|
|
|
12811
13512
|
get hiddenColumnCount() {
|
|
12812
13513
|
return this.allColumns.filter((c) => c.hidden && !c.excludeFromChooser && !this.isDefaultHidden(c)).length;
|
|
12813
13514
|
}
|
|
12814
|
-
/** True when visibility
|
|
13515
|
+
/** True when visibility, order, and width all match the originally declared
|
|
13516
|
+
* columns. Width is included so resizing a column alone still enables the
|
|
13517
|
+
* reset button; a column with no declared width uses null on both sides so
|
|
13518
|
+
* it only counts as changed once the user drags it to a concrete width. */
|
|
12815
13519
|
get columnsAtDefault() {
|
|
13520
|
+
if (this.canSwitchTreeVariant && this._treeVariant !== this._declaredTreeVariant) {
|
|
13521
|
+
return false;
|
|
13522
|
+
}
|
|
12816
13523
|
if (this.allColumns.length !== this._initialColumns.length) {
|
|
12817
13524
|
return false;
|
|
12818
13525
|
}
|
|
12819
|
-
|
|
13526
|
+
const parentAtDefault = this.allColumns.every((c, i) => {
|
|
12820
13527
|
const init = this._initialColumns[i];
|
|
12821
|
-
return init
|
|
13528
|
+
return init
|
|
13529
|
+
&& init.key === c.key
|
|
13530
|
+
&& !!init.hidden === !!c.hidden
|
|
13531
|
+
&& (init.width ?? null) === (c.width ?? null);
|
|
13532
|
+
});
|
|
13533
|
+
return parentAtDefault && this.childColumnsAtDefault;
|
|
13534
|
+
}
|
|
13535
|
+
/** True when every nested level's columns match their declared order/visibility/width. */
|
|
13536
|
+
get childColumnsAtDefault() {
|
|
13537
|
+
const declared = this._declaredChildColumnsByLevel;
|
|
13538
|
+
const current = this._childColumnsByLevel;
|
|
13539
|
+
if (!declared || !current) {
|
|
13540
|
+
return true;
|
|
13541
|
+
}
|
|
13542
|
+
return declared.every((set, level) => {
|
|
13543
|
+
const cur = current[level] ?? [];
|
|
13544
|
+
if (!set || set.length !== cur.length) {
|
|
13545
|
+
return set ? set.length === cur.length : true;
|
|
13546
|
+
}
|
|
13547
|
+
return set.every((d, i) => {
|
|
13548
|
+
const c = cur[i];
|
|
13549
|
+
return c
|
|
13550
|
+
&& d.key === c.key
|
|
13551
|
+
&& !!d.hidden === !!c.hidden
|
|
13552
|
+
&& (d.width ?? null) === (c.width ?? null);
|
|
13553
|
+
});
|
|
12822
13554
|
});
|
|
12823
13555
|
}
|
|
12824
13556
|
/** True when the column is hidden in the originally declared defaults. */
|
|
@@ -12836,36 +13568,82 @@ class ListTableComponent {
|
|
|
12836
13568
|
closeColumnChooser() {
|
|
12837
13569
|
this.showColumnChooser = false;
|
|
12838
13570
|
}
|
|
12839
|
-
|
|
12840
|
-
|
|
13571
|
+
onChooserDragStarted() {
|
|
13572
|
+
this._chooserDragged = true;
|
|
13573
|
+
}
|
|
13574
|
+
onChooserDragEnded() {
|
|
13575
|
+
// clear after the post-drag click has been handled (and skipped) below
|
|
13576
|
+
setTimeout(() => (this._chooserDragged = false));
|
|
13577
|
+
}
|
|
13578
|
+
/** Toggle a column's visibility. `level` undefined targets the top-level columns;
|
|
13579
|
+
* a number targets that nested depth's columns. */
|
|
13580
|
+
toggleColumnVisible(col, level) {
|
|
13581
|
+
if (this._chooserDragged || col.hideable === false) {
|
|
12841
13582
|
return;
|
|
12842
13583
|
}
|
|
12843
|
-
const
|
|
13584
|
+
const set = level == null ? this.allColumns : this._childColumnsByLevel?.[level];
|
|
13585
|
+
const target = set?.find((c) => c.key === col.key);
|
|
12844
13586
|
if (!target) {
|
|
12845
13587
|
return;
|
|
12846
13588
|
}
|
|
13589
|
+
if (!target.hidden && this.isLastVisibleColumn(target, level)) {
|
|
13590
|
+
return;
|
|
13591
|
+
}
|
|
12847
13592
|
target.hidden = !target.hidden;
|
|
12848
|
-
this.
|
|
12849
|
-
|
|
13593
|
+
this.afterColumnChange(level, set);
|
|
13594
|
+
}
|
|
13595
|
+
/** True when this is the only visible column at its level, so its toggle is disabled
|
|
13596
|
+
* to keep at least one column on screen. */
|
|
13597
|
+
isLastVisibleColumn(col, level) {
|
|
13598
|
+
const list = level == null ? this.chooserColumns : this.allColumnsForLevel(level);
|
|
13599
|
+
return !col.hidden && list.filter((c) => !c.hidden).length <= 1;
|
|
12850
13600
|
}
|
|
12851
|
-
/** Columns shown in the Columns menu. */
|
|
13601
|
+
/** Columns shown in the top-level Columns menu. */
|
|
12852
13602
|
get chooserColumns() {
|
|
12853
13603
|
return this.allColumns.filter((c) => !c.excludeFromChooser);
|
|
12854
13604
|
}
|
|
12855
|
-
|
|
13605
|
+
/** Reorder columns from a chooser drag. `level` undefined targets the top-level
|
|
13606
|
+
* columns; a number targets that nested depth's columns. */
|
|
13607
|
+
chooserReorder(event, level) {
|
|
12856
13608
|
if (event.previousIndex === event.currentIndex) {
|
|
12857
13609
|
return;
|
|
12858
13610
|
}
|
|
12859
|
-
// menu lists a subset, so map the drag indices back onto
|
|
12860
|
-
const
|
|
12861
|
-
const
|
|
12862
|
-
|
|
13611
|
+
// the menu lists a chooser subset, so map the drag indices back onto the full set
|
|
13612
|
+
const full = level == null ? this.allColumns : this._childColumnsByLevel?.[level];
|
|
13613
|
+
const list = level == null ? this.chooserColumns : this.allColumnsForLevel(level);
|
|
13614
|
+
if (!full) {
|
|
13615
|
+
return;
|
|
13616
|
+
}
|
|
13617
|
+
const from = full.indexOf(list[event.previousIndex]);
|
|
13618
|
+
const to = full.indexOf(list[event.currentIndex]);
|
|
12863
13619
|
if (from < 0 || to < 0) {
|
|
12864
13620
|
return;
|
|
12865
13621
|
}
|
|
12866
|
-
moveItemInArray(
|
|
12867
|
-
this.
|
|
12868
|
-
|
|
13622
|
+
moveItemInArray(full, from, to);
|
|
13623
|
+
this.afterColumnChange(level, full);
|
|
13624
|
+
}
|
|
13625
|
+
/** Refresh and persist after a column visibility/order change, routing to the
|
|
13626
|
+
* top-level or nested-level persistence as appropriate. */
|
|
13627
|
+
afterColumnChange(level, set) {
|
|
13628
|
+
if (level == null) {
|
|
13629
|
+
this.updateVisible();
|
|
13630
|
+
this.svc.saveState(this.allColumns);
|
|
13631
|
+
}
|
|
13632
|
+
else {
|
|
13633
|
+
this.invalidateColumnCache();
|
|
13634
|
+
this.svc.saveChildState(level, set);
|
|
13635
|
+
}
|
|
13636
|
+
}
|
|
13637
|
+
isNestedGroupOpen(id) {
|
|
13638
|
+
return this.nestedChooserOpen.has(id);
|
|
13639
|
+
}
|
|
13640
|
+
toggleNestedGroup(id) {
|
|
13641
|
+
if (this.nestedChooserOpen.has(id)) {
|
|
13642
|
+
this.nestedChooserOpen.delete(id);
|
|
13643
|
+
}
|
|
13644
|
+
else {
|
|
13645
|
+
this.nestedChooserOpen.add(id);
|
|
13646
|
+
}
|
|
12869
13647
|
}
|
|
12870
13648
|
// ---------------------------------------------------------------- resize
|
|
12871
13649
|
startResize(col, event) {
|
|
@@ -12876,7 +13654,25 @@ class ListTableComponent {
|
|
|
12876
13654
|
event.stopPropagation();
|
|
12877
13655
|
const th = event.target?.closest('th');
|
|
12878
13656
|
const startWidth = col.width ?? th?.offsetWidth ?? 150;
|
|
12879
|
-
this.resizing = { col, startX: event.clientX, startWidth };
|
|
13657
|
+
this.resizing = { col, startX: event.clientX, startWidth, persist: true };
|
|
13658
|
+
this.setupFitCompensation(col, startWidth, this.visibleColumns, (key) => this.measuredHeaderWidth(key));
|
|
13659
|
+
document.addEventListener('pointermove', this.onPointerMove);
|
|
13660
|
+
document.addEventListener('pointerup', this.onPointerUp);
|
|
13661
|
+
}
|
|
13662
|
+
/** Resize a nested row's column. Measures the sub-header cell's current rendered
|
|
13663
|
+
* width so a flexible (1fr) column converts to a concrete width before dragging;
|
|
13664
|
+
* the grid reflows live because its template reads each column's width. */
|
|
13665
|
+
startChildResize(col, level, event) {
|
|
13666
|
+
if (col.resizable === false) {
|
|
13667
|
+
return;
|
|
13668
|
+
}
|
|
13669
|
+
event.preventDefault();
|
|
13670
|
+
event.stopPropagation();
|
|
13671
|
+
const cell = event.target?.closest('.lt-tree-subhead-cell');
|
|
13672
|
+
const startWidth = col.width ?? Math.round(cell?.getBoundingClientRect().width ?? 150);
|
|
13673
|
+
const grid = cell?.closest('.lt-tree-grid');
|
|
13674
|
+
this.resizing = { col, startX: event.clientX, startWidth, persist: true, level };
|
|
13675
|
+
this.setupFitCompensation(col, startWidth, this.columnsForLevel(level), (key) => this.measuredCellWidth(grid, level, key));
|
|
12880
13676
|
document.addEventListener('pointermove', this.onPointerMove);
|
|
12881
13677
|
document.addEventListener('pointerup', this.onPointerUp);
|
|
12882
13678
|
}
|
|
@@ -12884,13 +13680,94 @@ class ListTableComponent {
|
|
|
12884
13680
|
if (!this.resizing) {
|
|
12885
13681
|
return;
|
|
12886
13682
|
}
|
|
12887
|
-
const
|
|
12888
|
-
const
|
|
12889
|
-
|
|
13683
|
+
const r = this.resizing;
|
|
13684
|
+
const delta = event.clientX - r.startX;
|
|
13685
|
+
if (r.sink && r.sinkStart != null) {
|
|
13686
|
+
// fitColumns: the column grows and the sink shrinks by the same amount, so the table stays
|
|
13687
|
+
// the same width and no other column (notably the tree column) shifts. The drag stops once
|
|
13688
|
+
// the column or the sink reaches its minimum.
|
|
13689
|
+
const d = Math.min(r.maxDelta ?? delta, Math.max(r.minDelta ?? delta, delta));
|
|
13690
|
+
r.col.width = Math.round(r.startWidth + d);
|
|
13691
|
+
r.sink.width = Math.round(r.sinkStart - d);
|
|
13692
|
+
}
|
|
13693
|
+
else {
|
|
13694
|
+
const min = r.col.minWidth ?? 40;
|
|
13695
|
+
r.col.width = Math.max(min, Math.round(r.startWidth + delta));
|
|
13696
|
+
}
|
|
13697
|
+
}
|
|
13698
|
+
/** fitColumns: pick the sink column and the range the drag may travel, so the column and the sink
|
|
13699
|
+
* trade width while every other column stays fixed. No-op (plain resize) when fitColumns is off. */
|
|
13700
|
+
setupFitCompensation(col, startWidth, columns, measure) {
|
|
13701
|
+
if (!this.options?.fitColumns || !this.resizing) {
|
|
13702
|
+
return;
|
|
13703
|
+
}
|
|
13704
|
+
const sink = this.pickSink(col, columns);
|
|
13705
|
+
if (!sink) {
|
|
13706
|
+
return;
|
|
13707
|
+
}
|
|
13708
|
+
const FLOOR = 60;
|
|
13709
|
+
// measure() returns 0 when the element isn't found; fall back so a width of 0
|
|
13710
|
+
// never gets frozen in (and later persisted) for the sink or a flex column
|
|
13711
|
+
const sinkStart = sink.width ?? (measure(sink.key) || startWidth);
|
|
13712
|
+
// Freeze any other flexible column to its rendered width so only the column and the sink move
|
|
13713
|
+
// (otherwise the browser would still redistribute slack among the flexible columns). These are
|
|
13714
|
+
// restored to flexible when the drag ends, so one resize doesn't pin the whole table to px.
|
|
13715
|
+
const frozen = [];
|
|
13716
|
+
columns.forEach((c) => {
|
|
13717
|
+
if (c.key !== col.key && c.key !== sink.key && c.width == null) {
|
|
13718
|
+
const w = measure(c.key);
|
|
13719
|
+
if (w > 0) {
|
|
13720
|
+
c.width = w;
|
|
13721
|
+
frozen.push(c);
|
|
13722
|
+
}
|
|
13723
|
+
}
|
|
13724
|
+
});
|
|
13725
|
+
this.resizing.sink = sink;
|
|
13726
|
+
this.resizing.sinkStart = sinkStart;
|
|
13727
|
+
this.resizing.frozen = frozen;
|
|
13728
|
+
this.resizing.maxDelta = Math.max(0, sinkStart - (sink.minWidth ?? FLOOR)); // grow until the sink hits its min
|
|
13729
|
+
this.resizing.minDelta = Math.min(0, (col.minWidth ?? 40) - startWidth); // shrink until the column hits its min
|
|
13730
|
+
}
|
|
13731
|
+
/** The column that absorbs a resize: a flexible column first (it is meant to take up slack), else
|
|
13732
|
+
* the nearest resizable column that is not the tree column, so indentation never shifts. */
|
|
13733
|
+
pickSink(col, columns) {
|
|
13734
|
+
// never pick the tree column (explicit or implicit) as the sink, or resizing
|
|
13735
|
+
// would move the expand chevrons
|
|
13736
|
+
const treeKey = this.treeColumnKeyFor(columns);
|
|
13737
|
+
const usable = columns.filter((c) => c.key !== col.key && c.resizable !== false && c.key !== treeKey);
|
|
13738
|
+
const flex = usable.find((c) => c.width == null);
|
|
13739
|
+
if (flex) {
|
|
13740
|
+
return flex;
|
|
13741
|
+
}
|
|
13742
|
+
const idx = columns.findIndex((c) => c.key === col.key);
|
|
13743
|
+
return usable.find((c) => columns.indexOf(c) > idx) ?? usable[usable.length - 1];
|
|
13744
|
+
}
|
|
13745
|
+
measuredHeaderWidth(key) {
|
|
13746
|
+
const host = this.el?.nativeElement;
|
|
13747
|
+
const th = host?.querySelector(`[id="Header_${key}"]`);
|
|
13748
|
+
return th ? Math.round(th.getBoundingClientRect().width) : 0;
|
|
13749
|
+
}
|
|
13750
|
+
measuredCellWidth(grid, level, key) {
|
|
13751
|
+
const idx = this.columnsForLevel(level).findIndex((c) => c.key === key);
|
|
13752
|
+
const cells = grid?.querySelectorAll('.lt-tree-subhead-cell');
|
|
13753
|
+
const cell = cells ? cells[idx] : undefined;
|
|
13754
|
+
return cell ? Math.round(cell.getBoundingClientRect().width) : 0;
|
|
12890
13755
|
}
|
|
12891
13756
|
handleResizeEnd() {
|
|
12892
|
-
|
|
12893
|
-
|
|
13757
|
+
const r = this.resizing;
|
|
13758
|
+
// columns frozen only to steady the drag go back to flexible, so the table keeps
|
|
13759
|
+
// filling the viewport and their temporary px widths are not persisted by saveState
|
|
13760
|
+
r?.frozen?.forEach((c) => (c.width = undefined));
|
|
13761
|
+
if (r?.persist) {
|
|
13762
|
+
if (r.level != null) {
|
|
13763
|
+
const set = this._childColumnsByLevel?.[r.level];
|
|
13764
|
+
if (set) {
|
|
13765
|
+
this.svc.saveChildWidth(r.level, r.col.key, r.col.width, set);
|
|
13766
|
+
}
|
|
13767
|
+
}
|
|
13768
|
+
else {
|
|
13769
|
+
this.svc.saveWidth(r.col.key, r.col.width, this.allColumns);
|
|
13770
|
+
}
|
|
12894
13771
|
}
|
|
12895
13772
|
this.resizing = undefined;
|
|
12896
13773
|
this.detachResizeListeners();
|
|
@@ -13095,11 +13972,11 @@ class ListTableComponent {
|
|
|
13095
13972
|
this.entityTypeLabel = map[this._tableId] || this.entityTypeName || '';
|
|
13096
13973
|
}
|
|
13097
13974
|
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"] }] }); }
|
|
13975
|
+
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", rowHover: "rowHover" }, 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 @if (toolbarControls.search.show) {\n <div class=\"lt-search\" [class.lt-ctl-disabled]=\"toolbarControls.search.disabled\">\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 [disabled]=\"toolbarControls.search.disabled\"\n (keyup)=\"onSearchInput()\"\n />\n </div>\n }\n @if (toolbarControls.filters.show && filterableColumns.length) {\n <div class=\"lt-filter-zone\" [class.lt-ctl-disabled]=\"toolbarControls.filters.disabled\" #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 @if (toolbarControls.refresh.show) {\n <button\n type=\"button\"\n class=\"lt-refresh-btn\"\n (click)=\"refresh()\"\n [disabled]=\"filtering || toolbarControls.refresh.disabled\"\n aria-label=\"Refresh\"\n title=\"Refresh\"\n id=\"RefreshTableButton\"\n >\n <ng-container [ngTemplateOutlet]=\"refreshIcon\"></ng-container>\n </button>\n }\n @if (toolbarControls.autoRefresh.show) {\n <span class=\"lt-autorefresh-wrap\" [class.lt-ctl-disabled]=\"toolbarControls.autoRefresh.disabled\">\n <lib-list-table-auto-refresh [loading]=\"filtering\" (refresh)=\"refresh()\"></lib-list-table-auto-refresh>\n </span>\n }\n @if (toolbarControls.columns.show) {\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 [disabled]=\"toolbarControls.columns.disabled\"\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 }\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 (mouseenter)=\"onRowHover(row)\"\n (mouseleave)=\"onRowLeave(row)\"\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 (mouseenter)=\"onRowHover(row)\"\n (mouseleave)=\"onRowLeave(row)\"\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 @if (toolbarControls.pageSize.show) {\n <div class=\"lt-rpp\" [class.lt-ctl-disabled]=\"toolbarControls.pageSize.disabled\">\n <span class=\"lt-rpp-label\">Rows per page</span>\n <select\n class=\"lt-rpp-select\"\n [disabled]=\"filtering || toolbarControls.pageSize.disabled\"\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 }\n @if (toolbarControls.pagination.show) {\n <div class=\"lt-pager\" [class.lt-ctl-disabled]=\"toolbarControls.pagination.disabled\">\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 }\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-ctl-disabled{opacity:.5;pointer-events:none}.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:18rem;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
13976
|
}
|
|
13100
13977
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListTableComponent, decorators: [{
|
|
13101
13978
|
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"] }]
|
|
13979
|
+
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 @if (toolbarControls.search.show) {\n <div class=\"lt-search\" [class.lt-ctl-disabled]=\"toolbarControls.search.disabled\">\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 [disabled]=\"toolbarControls.search.disabled\"\n (keyup)=\"onSearchInput()\"\n />\n </div>\n }\n @if (toolbarControls.filters.show && filterableColumns.length) {\n <div class=\"lt-filter-zone\" [class.lt-ctl-disabled]=\"toolbarControls.filters.disabled\" #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 @if (toolbarControls.refresh.show) {\n <button\n type=\"button\"\n class=\"lt-refresh-btn\"\n (click)=\"refresh()\"\n [disabled]=\"filtering || toolbarControls.refresh.disabled\"\n aria-label=\"Refresh\"\n title=\"Refresh\"\n id=\"RefreshTableButton\"\n >\n <ng-container [ngTemplateOutlet]=\"refreshIcon\"></ng-container>\n </button>\n }\n @if (toolbarControls.autoRefresh.show) {\n <span class=\"lt-autorefresh-wrap\" [class.lt-ctl-disabled]=\"toolbarControls.autoRefresh.disabled\">\n <lib-list-table-auto-refresh [loading]=\"filtering\" (refresh)=\"refresh()\"></lib-list-table-auto-refresh>\n </span>\n }\n @if (toolbarControls.columns.show) {\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 [disabled]=\"toolbarControls.columns.disabled\"\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 }\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 (mouseenter)=\"onRowHover(row)\"\n (mouseleave)=\"onRowLeave(row)\"\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 (mouseenter)=\"onRowHover(row)\"\n (mouseleave)=\"onRowLeave(row)\"\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 @if (toolbarControls.pageSize.show) {\n <div class=\"lt-rpp\" [class.lt-ctl-disabled]=\"toolbarControls.pageSize.disabled\">\n <span class=\"lt-rpp-label\">Rows per page</span>\n <select\n class=\"lt-rpp-select\"\n [disabled]=\"filtering || toolbarControls.pageSize.disabled\"\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 }\n @if (toolbarControls.pagination.show) {\n <div class=\"lt-pager\" [class.lt-ctl-disabled]=\"toolbarControls.pagination.disabled\">\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 }\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-ctl-disabled{opacity:.5;pointer-events:none}.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:18rem;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
13980
|
}], ctorParameters: () => [{ type: ListTableService }, { type: DataTableFilterService }, { type: i0.ElementRef }, { type: i0.NgZone }, { type: i1.DomSanitizer }], propDecorators: { tableId: [{
|
|
13104
13981
|
type: Input
|
|
13105
13982
|
}], columns: [{
|
|
@@ -13110,6 +13987,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
13110
13987
|
type: Input
|
|
13111
13988
|
}], options: [{
|
|
13112
13989
|
type: Input
|
|
13990
|
+
}], loadChildren: [{
|
|
13991
|
+
type: Input
|
|
13992
|
+
}], childColumnsByLevel: [{
|
|
13993
|
+
type: Input
|
|
13994
|
+
}], nodeToggled: [{
|
|
13995
|
+
type: Output
|
|
13113
13996
|
}], hasNext: [{
|
|
13114
13997
|
type: Input
|
|
13115
13998
|
}], hasPrev: [{
|
|
@@ -13144,6 +14027,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
13144
14027
|
type: Output
|
|
13145
14028
|
}], tableReady: [{
|
|
13146
14029
|
type: Output
|
|
14030
|
+
}], selectionChanged: [{
|
|
14031
|
+
type: Output
|
|
14032
|
+
}], rowHover: [{
|
|
14033
|
+
type: Output
|
|
13147
14034
|
}], contextMenu: [{
|
|
13148
14035
|
type: ViewChild,
|
|
13149
14036
|
args: ['contextMenu']
|
|
@@ -13153,6 +14040,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
13153
14040
|
}], filtersRow: [{
|
|
13154
14041
|
type: ViewChild,
|
|
13155
14042
|
args: ['filtersRow']
|
|
14043
|
+
}], treeVariant: [{
|
|
14044
|
+
type: Input
|
|
14045
|
+
}], showTreeVariantToggle: [{
|
|
14046
|
+
type: Input
|
|
14047
|
+
}], treeRail: [{
|
|
14048
|
+
type: Input
|
|
14049
|
+
}], isFlatTree: [{
|
|
14050
|
+
type: HostBinding,
|
|
14051
|
+
args: ['class.lt-tree-flat']
|
|
13156
14052
|
}], initialPageSize: [{
|
|
13157
14053
|
type: Input
|
|
13158
14054
|
}] } });
|
|
@@ -16122,7 +17018,7 @@ class IdentitiesListPageComponent extends ListPageComponent {
|
|
|
16122
17018
|
return true;
|
|
16123
17019
|
}
|
|
16124
17020
|
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"] }] }); }
|
|
17021
|
+
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", "rowHover"] }, { 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
17022
|
}
|
|
16127
17023
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: IdentitiesListPageComponent, decorators: [{
|
|
16128
17024
|
type: Component,
|
|
@@ -25067,12 +25963,12 @@ class EdgeRouterPoliciesPageService extends ListPageServiceClass {
|
|
|
25067
25963
|
createdAt: '',
|
|
25068
25964
|
};
|
|
25069
25965
|
this.menuItems = [
|
|
25070
|
-
{ name: 'Edit', action: 'update' },
|
|
25071
|
-
{ name: 'Delete', action: 'delete' },
|
|
25966
|
+
{ 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>' },
|
|
25967
|
+
{ 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
25968
|
];
|
|
25073
25969
|
this.tableHeaderActions = [
|
|
25074
|
-
{ name: 'Download All', action: 'download-all' },
|
|
25075
|
-
{ name: 'Download Selected', action: 'download-selected' },
|
|
25970
|
+
{ 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>' },
|
|
25971
|
+
{ 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
25972
|
];
|
|
25077
25973
|
this.resourceType = 'edge-router-policies';
|
|
25078
25974
|
this.validate = (formData) => {
|
|
@@ -25310,9 +26206,163 @@ class EdgeRouterPoliciesPageService extends ListPageServiceClass {
|
|
|
25310
26206
|
this.ID_COLUMN_DEF
|
|
25311
26207
|
];
|
|
25312
26208
|
}
|
|
25313
|
-
|
|
26209
|
+
// Declarative ListColumn set for the new `lib-list-table` (Beta Features on).
|
|
26210
|
+
initListTableColumns() {
|
|
26211
|
+
this.initMenuActions();
|
|
26212
|
+
const routerRolesHeaderComponentParams = {
|
|
26213
|
+
filterType: 'ATTRIBUTE',
|
|
26214
|
+
enableSorting: true,
|
|
26215
|
+
getRoleAttributes: () => this.routerRoleAttributes,
|
|
26216
|
+
getNamedAttributes: () => this.routerNamedAttributes,
|
|
26217
|
+
getSelectedRoleAttributes: () => this.selectedRouterRoleAttributes,
|
|
26218
|
+
getSelectedNamedAttributes: () => this.selectedRouterNamedAttributes,
|
|
26219
|
+
setSelectedRoleAttributes: (attributes) => {
|
|
26220
|
+
this.selectedRouterRoleAttributes = attributes;
|
|
26221
|
+
},
|
|
26222
|
+
setSelectedNamedAttributes: (attributes) => {
|
|
26223
|
+
this.selectedRouterNamedAttributes = attributes;
|
|
26224
|
+
},
|
|
26225
|
+
getNamedAttributesMap: () => this.routerNamedAttributesMap,
|
|
26226
|
+
};
|
|
26227
|
+
const identityRolesHeaderComponentParams = {
|
|
26228
|
+
filterType: 'ATTRIBUTE',
|
|
26229
|
+
enableSorting: true,
|
|
26230
|
+
getRoleAttributes: () => this.identityRoleAttributes,
|
|
26231
|
+
getNamedAttributes: () => this.identityNamedAttributes,
|
|
26232
|
+
getSelectedRoleAttributes: () => this.selectedIdentityRoleAttributes,
|
|
26233
|
+
getSelectedNamedAttributes: () => this.selectedIdentityNamedAttributes,
|
|
26234
|
+
setSelectedRoleAttributes: (attributes) => {
|
|
26235
|
+
this.selectedIdentityRoleAttributes = attributes;
|
|
26236
|
+
},
|
|
26237
|
+
setSelectedNamedAttributes: (attributes) => {
|
|
26238
|
+
this.selectedIdentityNamedAttributes = attributes;
|
|
26239
|
+
},
|
|
26240
|
+
getNamedAttributesMap: () => this.identityNamedAttributesMap,
|
|
26241
|
+
};
|
|
26242
|
+
// @ marks a named attribute, # a role attribute (matches the tag selector)
|
|
26243
|
+
const rolesChipRenderer = (row) => {
|
|
26244
|
+
const colId = row?.column?.colId;
|
|
26245
|
+
const attrs = row?.data?.[colId + 'Display'] || row?.data?.[colId] || [];
|
|
26246
|
+
return attrs.map((attr) => {
|
|
26247
|
+
const raw = String(attr?.name ?? attr ?? '').trim();
|
|
26248
|
+
if (!raw) {
|
|
26249
|
+
return '';
|
|
26250
|
+
}
|
|
26251
|
+
const isNamed = raw.charAt(0) === '@';
|
|
26252
|
+
const label = isNamed || raw.charAt(0) === '#' ? raw : '#' + raw;
|
|
26253
|
+
return `<span class="${isNamed ? 'lt-chip lt-chip-at' : 'lt-chip'}">${label}</span>`;
|
|
26254
|
+
}).join('');
|
|
26255
|
+
};
|
|
26256
|
+
const semanticFilterOptions = [
|
|
26257
|
+
{ label: 'Show All', value: '' },
|
|
26258
|
+
{ label: 'Any Of', value: 'AnyOf' },
|
|
26259
|
+
{ label: 'All Of', value: 'AllOf' },
|
|
26260
|
+
];
|
|
26261
|
+
const semanticRenderer = (row) => row?.data?.semantic === 'AnyOf' ? 'Any Of' : 'All Of';
|
|
26262
|
+
const openForm = (ctx) => {
|
|
26263
|
+
if (this.hasSelectedText()) {
|
|
26264
|
+
return;
|
|
26265
|
+
}
|
|
26266
|
+
this.serviceType = 'advanced';
|
|
26267
|
+
this.openEditForm(ctx.row?.id);
|
|
26268
|
+
};
|
|
26269
|
+
let tableColumns = [
|
|
26270
|
+
{
|
|
26271
|
+
key: 'name',
|
|
26272
|
+
field: 'name',
|
|
26273
|
+
label: 'Name',
|
|
26274
|
+
filterType: 'TEXTINPUT',
|
|
26275
|
+
cell: NameCellComponent,
|
|
26276
|
+
cellInputs: (ctx) => ({
|
|
26277
|
+
row: ctx.row,
|
|
26278
|
+
cellValue: ctx.value,
|
|
26279
|
+
cellConfig: { pathRoot: this.basePath, showIdentityIcons: false },
|
|
26280
|
+
}),
|
|
26281
|
+
onCellClick: openForm,
|
|
26282
|
+
resizable: true,
|
|
26283
|
+
cellClass: 'nf-cell-vert-align',
|
|
26284
|
+
sortable: true,
|
|
26285
|
+
onSort: this.sort.bind(this),
|
|
26286
|
+
sortDir: 'asc',
|
|
26287
|
+
width: 300,
|
|
26288
|
+
},
|
|
26289
|
+
{
|
|
26290
|
+
key: 'edgeRouterRoles',
|
|
26291
|
+
field: 'edgeRouterRoles',
|
|
26292
|
+
label: 'Router Attributes',
|
|
26293
|
+
filterType: 'ATTRIBUTE',
|
|
26294
|
+
headerParams: routerRolesHeaderComponentParams,
|
|
26295
|
+
cellHtml: rolesChipRenderer,
|
|
26296
|
+
onCellClick: openForm,
|
|
26297
|
+
resizable: true,
|
|
26298
|
+
cellClass: 'nf-cell-vert-align',
|
|
26299
|
+
sortable: false,
|
|
26300
|
+
},
|
|
26301
|
+
{
|
|
26302
|
+
key: 'identityRoles',
|
|
26303
|
+
field: 'identityRoles',
|
|
26304
|
+
label: 'Identity Attributes',
|
|
26305
|
+
filterType: 'ATTRIBUTE',
|
|
26306
|
+
headerParams: identityRolesHeaderComponentParams,
|
|
26307
|
+
cellHtml: rolesChipRenderer,
|
|
26308
|
+
onCellClick: openForm,
|
|
26309
|
+
resizable: true,
|
|
26310
|
+
cellClass: 'nf-cell-vert-align',
|
|
26311
|
+
sortable: false,
|
|
26312
|
+
},
|
|
26313
|
+
{
|
|
26314
|
+
key: 'semantic',
|
|
26315
|
+
field: 'semantic',
|
|
26316
|
+
label: 'Semantic',
|
|
26317
|
+
filterType: 'SELECT',
|
|
26318
|
+
filterPlaceholder: 'Any semantic',
|
|
26319
|
+
filterOptions: semanticFilterOptions,
|
|
26320
|
+
cellHtml: semanticRenderer,
|
|
26321
|
+
onCellClick: openForm,
|
|
26322
|
+
resizable: true,
|
|
26323
|
+
sortable: true,
|
|
26324
|
+
onSort: this.sort.bind(this),
|
|
26325
|
+
cellClass: 'nf-cell-vert-align',
|
|
26326
|
+
width: 120,
|
|
26327
|
+
},
|
|
26328
|
+
{
|
|
26329
|
+
key: 'createdAt',
|
|
26330
|
+
field: 'createdAt',
|
|
26331
|
+
label: 'Created At',
|
|
26332
|
+
valueFormatter: this.createdAtFormatter,
|
|
26333
|
+
filterType: 'DATETIME',
|
|
26334
|
+
filterPlaceholder: 'Any time',
|
|
26335
|
+
onCellClick: openForm,
|
|
26336
|
+
resizable: true,
|
|
26337
|
+
sortable: true,
|
|
26338
|
+
onSort: this.sort.bind(this),
|
|
26339
|
+
cellClass: 'nf-cell-vert-align',
|
|
26340
|
+
hidden: true,
|
|
26341
|
+
},
|
|
26342
|
+
{
|
|
26343
|
+
key: 'id',
|
|
26344
|
+
field: 'id',
|
|
26345
|
+
label: 'ID',
|
|
26346
|
+
filterType: 'TEXTINPUT',
|
|
26347
|
+
onCellClick: openForm,
|
|
26348
|
+
resizable: true,
|
|
26349
|
+
sortable: true,
|
|
26350
|
+
onSort: this.sort.bind(this),
|
|
26351
|
+
cellClass: 'nf-cell-vert-align',
|
|
26352
|
+
hidden: true,
|
|
26353
|
+
},
|
|
26354
|
+
];
|
|
26355
|
+
if (this.extService?.processListTableColumns) {
|
|
26356
|
+
tableColumns = this.extService.processListTableColumns(tableColumns);
|
|
26357
|
+
}
|
|
26358
|
+
return tableColumns;
|
|
26359
|
+
}
|
|
26360
|
+
getData(filters, sort, page, pageSize) {
|
|
25314
26361
|
// we can customize filters or sorting here before moving on...
|
|
25315
26362
|
this.paging.page = page || this.paging.page;
|
|
26363
|
+
if (pageSize) {
|
|
26364
|
+
this.paging.total = pageSize;
|
|
26365
|
+
}
|
|
25316
26366
|
return super.getTableData('edge-router-policies', this.paging, filters, sort)
|
|
25317
26367
|
.then((results) => {
|
|
25318
26368
|
return this.processData(results);
|
|
@@ -25536,6 +26586,135 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
25536
26586
|
args: [SHAREDZ_EXTENSION]
|
|
25537
26587
|
}] }] });
|
|
25538
26588
|
|
|
26589
|
+
/*
|
|
26590
|
+
Copyright NetFoundry Inc.
|
|
26591
|
+
|
|
26592
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
26593
|
+
you may not use this file except in compliance with the License.
|
|
26594
|
+
You may obtain a copy of the License at
|
|
26595
|
+
|
|
26596
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
26597
|
+
|
|
26598
|
+
Unless required by applicable law or agreed to in writing, software
|
|
26599
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
26600
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
26601
|
+
See the License for the specific language governing permissions and
|
|
26602
|
+
limitations under the License.
|
|
26603
|
+
*/
|
|
26604
|
+
// Edge Router Policies page on `lib-list-table`, selected by the route when Beta Features is on.
|
|
26605
|
+
class EdgeRouterPoliciesListPageComponent extends ListPageComponent {
|
|
26606
|
+
constructor(svc, filterService, dialogForm, tabNames, consoleEvents, extService) {
|
|
26607
|
+
super(filterService, svc, consoleEvents, dialogForm, extService);
|
|
26608
|
+
this.svc = svc;
|
|
26609
|
+
this.tabNames = tabNames;
|
|
26610
|
+
this.extService = extService;
|
|
26611
|
+
this.title = 'Edge Router Policies';
|
|
26612
|
+
this.isLoading = false;
|
|
26613
|
+
this.formDataChanged = false;
|
|
26614
|
+
this.tableId = 'edge-router-policies';
|
|
26615
|
+
this.initialPageSize = 50;
|
|
26616
|
+
}
|
|
26617
|
+
loadTableColumns() {
|
|
26618
|
+
return this.svc.initListTableColumns();
|
|
26619
|
+
}
|
|
26620
|
+
ngOnInit() {
|
|
26621
|
+
this.tabs = this.tabNames.getTabs('policies');
|
|
26622
|
+
this.svc.refreshData = this.refreshData;
|
|
26623
|
+
this.getRoleAttributes();
|
|
26624
|
+
super.ngOnInit();
|
|
26625
|
+
}
|
|
26626
|
+
headerActionClicked(action) {
|
|
26627
|
+
switch (action) {
|
|
26628
|
+
case 'add':
|
|
26629
|
+
this.svc.serviceType = '';
|
|
26630
|
+
this.svc.openEditForm();
|
|
26631
|
+
break;
|
|
26632
|
+
case 'edit':
|
|
26633
|
+
this.svc.openEditForm();
|
|
26634
|
+
break;
|
|
26635
|
+
case 'delete':
|
|
26636
|
+
const selectedItems = this.rowData.filter((row) => {
|
|
26637
|
+
return row.selected;
|
|
26638
|
+
});
|
|
26639
|
+
const label = selectedItems.length > 1 ? 'edge router policies' : 'edge router policy';
|
|
26640
|
+
this.openBulkDelete(selectedItems, label);
|
|
26641
|
+
break;
|
|
26642
|
+
default:
|
|
26643
|
+
}
|
|
26644
|
+
}
|
|
26645
|
+
tableAction(event) {
|
|
26646
|
+
this.trackMenuAction(event?.action, event?.item);
|
|
26647
|
+
switch (event?.action) {
|
|
26648
|
+
case 'toggleAll':
|
|
26649
|
+
case 'toggleItem':
|
|
26650
|
+
this.itemToggled(event.item);
|
|
26651
|
+
this.rowData.forEach((item) => {
|
|
26652
|
+
if (item.isSystem) {
|
|
26653
|
+
item.selected = false;
|
|
26654
|
+
}
|
|
26655
|
+
});
|
|
26656
|
+
break;
|
|
26657
|
+
case 'update':
|
|
26658
|
+
this.svc.serviceType = 'advanced';
|
|
26659
|
+
this.svc.openEditForm(event.item?.id);
|
|
26660
|
+
break;
|
|
26661
|
+
case 'create':
|
|
26662
|
+
this.svc.openEditForm();
|
|
26663
|
+
break;
|
|
26664
|
+
case 'delete':
|
|
26665
|
+
this.deleteItem(event.item);
|
|
26666
|
+
break;
|
|
26667
|
+
case 'download-all':
|
|
26668
|
+
this.downloadAllItems();
|
|
26669
|
+
break;
|
|
26670
|
+
case 'download-selected':
|
|
26671
|
+
this.svc.downloadItems(this.selectedItems);
|
|
26672
|
+
break;
|
|
26673
|
+
default:
|
|
26674
|
+
break;
|
|
26675
|
+
}
|
|
26676
|
+
}
|
|
26677
|
+
trackMenuAction(action, item) {
|
|
26678
|
+
this.extService?.consoleActionTriggered?.emit({
|
|
26679
|
+
action,
|
|
26680
|
+
page: 'edge-router-policy',
|
|
26681
|
+
item,
|
|
26682
|
+
type: 'menu-action'
|
|
26683
|
+
});
|
|
26684
|
+
}
|
|
26685
|
+
getRoleAttributes() {
|
|
26686
|
+
this.svc.getEdgeRouterRoleAttributes();
|
|
26687
|
+
this.svc.getIdentityRoleAttributes();
|
|
26688
|
+
this.svc.getServiceNamedAttributes();
|
|
26689
|
+
this.svc.getIdentityNamedAttributes();
|
|
26690
|
+
this.svc.getPostureNamedAttributes();
|
|
26691
|
+
}
|
|
26692
|
+
deleteItem(item) {
|
|
26693
|
+
this.openBulkDelete([item], 'edge-router-policies');
|
|
26694
|
+
}
|
|
26695
|
+
closeModal(event) {
|
|
26696
|
+
this.svc.sideModalOpen = false;
|
|
26697
|
+
if (event?.refresh) {
|
|
26698
|
+
this.refreshData();
|
|
26699
|
+
}
|
|
26700
|
+
}
|
|
26701
|
+
dataChanged(event) {
|
|
26702
|
+
this.formDataChanged = event;
|
|
26703
|
+
}
|
|
26704
|
+
ngOnDestroy() {
|
|
26705
|
+
super.ngOnDestroy();
|
|
26706
|
+
}
|
|
26707
|
+
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 }); }
|
|
26708
|
+
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", "rowHover"] }, { kind: "component", type: LoadingIndicatorComponent, selector: "lib-loading-indicator", inputs: ["isLoading"] }] }); }
|
|
26709
|
+
}
|
|
26710
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: EdgeRouterPoliciesListPageComponent, decorators: [{
|
|
26711
|
+
type: Component,
|
|
26712
|
+
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" }]
|
|
26713
|
+
}], ctorParameters: () => [{ type: EdgeRouterPoliciesPageService }, { type: DataTableFilterService }, { type: i5.MatDialog }, { type: TabNameService }, { type: ConsoleEventsService }, { type: undefined, decorators: [{
|
|
26714
|
+
type: Inject,
|
|
26715
|
+
args: [SHAREDZ_EXTENSION]
|
|
26716
|
+
}] }] });
|
|
26717
|
+
|
|
25539
26718
|
/*
|
|
25540
26719
|
Copyright NetFoundry Inc.
|
|
25541
26720
|
|
|
@@ -25584,13 +26763,14 @@ class ServicePoliciesPageService extends ListPageServiceClass {
|
|
|
25584
26763
|
os: '',
|
|
25585
26764
|
createdAt: '',
|
|
25586
26765
|
};
|
|
26766
|
+
// `icon` is rendered by the new list-table's menus; the legacy ag-grid menu ignores it.
|
|
25587
26767
|
this.menuItems = [
|
|
25588
|
-
{ name: 'Edit', action: 'update' },
|
|
25589
|
-
{ name: 'Delete', action: 'delete' },
|
|
26768
|
+
{ 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>' },
|
|
26769
|
+
{ 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
26770
|
];
|
|
25591
26771
|
this.tableHeaderActions = [
|
|
25592
|
-
{ name: 'Download All', action: 'download-all' },
|
|
25593
|
-
{ name: 'Download Selected', action: 'download-selected' },
|
|
26772
|
+
{ 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>' },
|
|
26773
|
+
{ 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
26774
|
];
|
|
25595
26775
|
this.resourceType = 'service-policies';
|
|
25596
26776
|
this.validate = (formData) => {
|
|
@@ -25607,6 +26787,7 @@ class ServicePoliciesPageService extends ListPageServiceClass {
|
|
|
25607
26787
|
identityFilter = true;
|
|
25608
26788
|
break;
|
|
25609
26789
|
case 'postureRoles':
|
|
26790
|
+
case 'postureCheckRoles':
|
|
25610
26791
|
postureFilter = true;
|
|
25611
26792
|
break;
|
|
25612
26793
|
}
|
|
@@ -25619,6 +26800,10 @@ class ServicePoliciesPageService extends ListPageServiceClass {
|
|
|
25619
26800
|
this.selectedIdentityRoleAttributes = [];
|
|
25620
26801
|
this.selectedIdentityNamedAttributes = [];
|
|
25621
26802
|
}
|
|
26803
|
+
if (!postureFilter) {
|
|
26804
|
+
this.selectedPostureRoleAttributes = [];
|
|
26805
|
+
this.selectedPostureNamedAttributes = [];
|
|
26806
|
+
}
|
|
25622
26807
|
});
|
|
25623
26808
|
}
|
|
25624
26809
|
initTableColumns() {
|
|
@@ -25872,9 +27057,209 @@ class ServicePoliciesPageService extends ListPageServiceClass {
|
|
|
25872
27057
|
}
|
|
25873
27058
|
return tableColumns;
|
|
25874
27059
|
}
|
|
25875
|
-
|
|
27060
|
+
// Declarative ListColumn set for the new `lib-list-table` (Beta Features on).
|
|
27061
|
+
initListTableColumns() {
|
|
27062
|
+
this.initMenuActions();
|
|
27063
|
+
const serviceRolesHeaderComponentParams = {
|
|
27064
|
+
filterType: 'ATTRIBUTE',
|
|
27065
|
+
enableSorting: true,
|
|
27066
|
+
getRoleAttributes: () => this.serviceRoleAttributes,
|
|
27067
|
+
getNamedAttributes: () => this.serviceNamedAttributes,
|
|
27068
|
+
getSelectedRoleAttributes: () => this.selectedServiceRoleAttributes,
|
|
27069
|
+
getSelectedNamedAttributes: () => this.selectedServiceNamedAttributes,
|
|
27070
|
+
setSelectedRoleAttributes: (attributes) => {
|
|
27071
|
+
this.selectedServiceRoleAttributes = attributes;
|
|
27072
|
+
},
|
|
27073
|
+
setSelectedNamedAttributes: (attributes) => {
|
|
27074
|
+
this.selectedServiceNamedAttributes = attributes;
|
|
27075
|
+
},
|
|
27076
|
+
getNamedAttributesMap: () => this.serviceNamedAttributesMap,
|
|
27077
|
+
};
|
|
27078
|
+
const identityRolesHeaderComponentParams = {
|
|
27079
|
+
filterType: 'ATTRIBUTE',
|
|
27080
|
+
enableSorting: true,
|
|
27081
|
+
getRoleAttributes: () => this.identityRoleAttributes,
|
|
27082
|
+
getNamedAttributes: () => this.identityNamedAttributes,
|
|
27083
|
+
getSelectedRoleAttributes: () => this.selectedIdentityRoleAttributes,
|
|
27084
|
+
getSelectedNamedAttributes: () => this.selectedIdentityNamedAttributes,
|
|
27085
|
+
setSelectedRoleAttributes: (attributes) => {
|
|
27086
|
+
this.selectedIdentityRoleAttributes = attributes;
|
|
27087
|
+
},
|
|
27088
|
+
setSelectedNamedAttributes: (attributes) => {
|
|
27089
|
+
this.selectedIdentityNamedAttributes = attributes;
|
|
27090
|
+
},
|
|
27091
|
+
getNamedAttributesMap: () => this.identityNamedAttributesMap,
|
|
27092
|
+
};
|
|
27093
|
+
const postureRolesHeaderComponentParams = {
|
|
27094
|
+
filterType: 'ATTRIBUTE',
|
|
27095
|
+
enableSorting: true,
|
|
27096
|
+
getRoleAttributes: () => this.postureRoleAttributes,
|
|
27097
|
+
getNamedAttributes: () => this.postureNamedAttributes,
|
|
27098
|
+
getSelectedRoleAttributes: () => this.selectedPostureRoleAttributes,
|
|
27099
|
+
getSelectedNamedAttributes: () => this.selectedPostureNamedAttributes,
|
|
27100
|
+
setSelectedRoleAttributes: (attributes) => {
|
|
27101
|
+
this.selectedPostureRoleAttributes = attributes;
|
|
27102
|
+
},
|
|
27103
|
+
setSelectedNamedAttributes: (attributes) => {
|
|
27104
|
+
this.selectedPostureNamedAttributes = attributes;
|
|
27105
|
+
},
|
|
27106
|
+
getNamedAttributesMap: () => this.postureNamedAttributesMap,
|
|
27107
|
+
};
|
|
27108
|
+
// @ marks a named attribute, # a role attribute (matches the tag selector)
|
|
27109
|
+
const rolesChipRenderer = (row) => {
|
|
27110
|
+
const colId = row?.column?.colId;
|
|
27111
|
+
const attrs = row?.data?.[colId + 'Display'] || row?.data?.[colId] || [];
|
|
27112
|
+
return attrs.map((attr) => {
|
|
27113
|
+
const raw = String(attr?.name ?? attr ?? '').trim();
|
|
27114
|
+
if (!raw) {
|
|
27115
|
+
return '';
|
|
27116
|
+
}
|
|
27117
|
+
const isNamed = raw.charAt(0) === '@';
|
|
27118
|
+
const label = isNamed || raw.charAt(0) === '#' ? raw : '#' + raw;
|
|
27119
|
+
return `<span class="${isNamed ? 'lt-chip lt-chip-at' : 'lt-chip'}">${label}</span>`;
|
|
27120
|
+
}).join('');
|
|
27121
|
+
};
|
|
27122
|
+
const semanticFilterOptions = [
|
|
27123
|
+
{ label: 'Show All', value: '' },
|
|
27124
|
+
{ label: 'Any Of', value: 'AnyOf' },
|
|
27125
|
+
{ label: 'All Of', value: 'AllOf' },
|
|
27126
|
+
];
|
|
27127
|
+
const semanticRenderer = (row) => row?.data?.semantic === 'AnyOf' ? 'Any Of' : 'All Of';
|
|
27128
|
+
const openForm = (ctx) => {
|
|
27129
|
+
if (this.hasSelectedText()) {
|
|
27130
|
+
return;
|
|
27131
|
+
}
|
|
27132
|
+
this.serviceType = 'advanced';
|
|
27133
|
+
this.openEditForm(ctx.row?.id);
|
|
27134
|
+
};
|
|
27135
|
+
let tableColumns = [
|
|
27136
|
+
{
|
|
27137
|
+
key: 'name',
|
|
27138
|
+
field: 'name',
|
|
27139
|
+
label: 'Name',
|
|
27140
|
+
filterType: 'TEXTINPUT',
|
|
27141
|
+
cell: NameCellComponent,
|
|
27142
|
+
cellInputs: (ctx) => ({
|
|
27143
|
+
row: ctx.row,
|
|
27144
|
+
cellValue: ctx.value,
|
|
27145
|
+
cellConfig: { pathRoot: this.basePath, showIdentityIcons: false },
|
|
27146
|
+
}),
|
|
27147
|
+
onCellClick: openForm,
|
|
27148
|
+
resizable: true,
|
|
27149
|
+
cellClass: 'nf-cell-vert-align',
|
|
27150
|
+
sortable: true,
|
|
27151
|
+
onSort: this.sort.bind(this),
|
|
27152
|
+
sortDir: 'asc',
|
|
27153
|
+
width: 300,
|
|
27154
|
+
},
|
|
27155
|
+
{
|
|
27156
|
+
key: 'serviceRoles',
|
|
27157
|
+
field: 'serviceRoles',
|
|
27158
|
+
label: 'Service Attributes',
|
|
27159
|
+
filterType: 'ATTRIBUTE',
|
|
27160
|
+
headerParams: serviceRolesHeaderComponentParams,
|
|
27161
|
+
cellHtml: rolesChipRenderer,
|
|
27162
|
+
onCellClick: openForm,
|
|
27163
|
+
resizable: true,
|
|
27164
|
+
cellClass: 'nf-cell-vert-align',
|
|
27165
|
+
sortable: false,
|
|
27166
|
+
},
|
|
27167
|
+
{
|
|
27168
|
+
key: 'identityRoles',
|
|
27169
|
+
field: 'identityRoles',
|
|
27170
|
+
label: 'Identity Attributes',
|
|
27171
|
+
filterType: 'ATTRIBUTE',
|
|
27172
|
+
headerParams: identityRolesHeaderComponentParams,
|
|
27173
|
+
cellHtml: rolesChipRenderer,
|
|
27174
|
+
onCellClick: openForm,
|
|
27175
|
+
resizable: true,
|
|
27176
|
+
cellClass: 'nf-cell-vert-align',
|
|
27177
|
+
sortable: false,
|
|
27178
|
+
},
|
|
27179
|
+
{
|
|
27180
|
+
key: 'postureCheckRoles',
|
|
27181
|
+
field: 'postureCheckRoles',
|
|
27182
|
+
label: 'Posture Check Attributes',
|
|
27183
|
+
filterType: 'ATTRIBUTE',
|
|
27184
|
+
headerParams: postureRolesHeaderComponentParams,
|
|
27185
|
+
cellHtml: rolesChipRenderer,
|
|
27186
|
+
onCellClick: openForm,
|
|
27187
|
+
resizable: true,
|
|
27188
|
+
cellClass: 'nf-cell-vert-align',
|
|
27189
|
+
sortable: false,
|
|
27190
|
+
},
|
|
27191
|
+
{
|
|
27192
|
+
key: 'semantic',
|
|
27193
|
+
field: 'semantic',
|
|
27194
|
+
label: 'Semantic',
|
|
27195
|
+
filterType: 'SELECT',
|
|
27196
|
+
filterPlaceholder: 'Any semantic',
|
|
27197
|
+
filterOptions: semanticFilterOptions,
|
|
27198
|
+
cellHtml: semanticRenderer,
|
|
27199
|
+
onCellClick: openForm,
|
|
27200
|
+
resizable: true,
|
|
27201
|
+
sortable: true,
|
|
27202
|
+
onSort: this.sort.bind(this),
|
|
27203
|
+
cellClass: 'nf-cell-vert-align',
|
|
27204
|
+
width: 120,
|
|
27205
|
+
},
|
|
27206
|
+
{
|
|
27207
|
+
key: 'type',
|
|
27208
|
+
field: 'type',
|
|
27209
|
+
label: 'Type',
|
|
27210
|
+
filterType: 'SELECT',
|
|
27211
|
+
filterPlaceholder: 'Any type',
|
|
27212
|
+
filterOptions: [
|
|
27213
|
+
{ label: 'Show All', value: '' },
|
|
27214
|
+
{ label: 'Dial', value: 'Dial' },
|
|
27215
|
+
{ label: 'Bind', value: 'Bind' },
|
|
27216
|
+
],
|
|
27217
|
+
cellHtml: (row) => row?.data?.type ?? '',
|
|
27218
|
+
onCellClick: openForm,
|
|
27219
|
+
resizable: true,
|
|
27220
|
+
sortable: true,
|
|
27221
|
+
onSort: this.sort.bind(this),
|
|
27222
|
+
cellClass: 'nf-cell-vert-align',
|
|
27223
|
+
width: 100,
|
|
27224
|
+
},
|
|
27225
|
+
{
|
|
27226
|
+
key: 'createdAt',
|
|
27227
|
+
field: 'createdAt',
|
|
27228
|
+
label: 'Created At',
|
|
27229
|
+
valueFormatter: this.createdAtFormatter,
|
|
27230
|
+
filterType: 'DATETIME',
|
|
27231
|
+
filterPlaceholder: 'Any time',
|
|
27232
|
+
onCellClick: openForm,
|
|
27233
|
+
resizable: true,
|
|
27234
|
+
sortable: true,
|
|
27235
|
+
onSort: this.sort.bind(this),
|
|
27236
|
+
cellClass: 'nf-cell-vert-align',
|
|
27237
|
+
hidden: true,
|
|
27238
|
+
},
|
|
27239
|
+
{
|
|
27240
|
+
key: 'id',
|
|
27241
|
+
field: 'id',
|
|
27242
|
+
label: 'ID',
|
|
27243
|
+
filterType: 'TEXTINPUT',
|
|
27244
|
+
onCellClick: openForm,
|
|
27245
|
+
resizable: true,
|
|
27246
|
+
sortable: true,
|
|
27247
|
+
onSort: this.sort.bind(this),
|
|
27248
|
+
cellClass: 'nf-cell-vert-align',
|
|
27249
|
+
hidden: true,
|
|
27250
|
+
},
|
|
27251
|
+
];
|
|
27252
|
+
if (this.extService?.processListTableColumns) {
|
|
27253
|
+
tableColumns = this.extService.processListTableColumns(tableColumns);
|
|
27254
|
+
}
|
|
27255
|
+
return tableColumns;
|
|
27256
|
+
}
|
|
27257
|
+
getData(filters, sort, page, pageSize) {
|
|
25876
27258
|
// we can customize filters or sorting here before moving on...
|
|
25877
27259
|
this.paging.page = page || this.paging.page;
|
|
27260
|
+
if (pageSize) {
|
|
27261
|
+
this.paging.total = pageSize;
|
|
27262
|
+
}
|
|
25878
27263
|
return super.getTableData('service-policies', this.paging, filters, sort)
|
|
25879
27264
|
.then((results) => {
|
|
25880
27265
|
return this.processData(results);
|
|
@@ -26113,6 +27498,134 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
26113
27498
|
args: [SERVICE_POLICY_EXTENSION_SERVICE]
|
|
26114
27499
|
}] }] });
|
|
26115
27500
|
|
|
27501
|
+
/*
|
|
27502
|
+
Copyright NetFoundry Inc.
|
|
27503
|
+
|
|
27504
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
27505
|
+
you may not use this file except in compliance with the License.
|
|
27506
|
+
You may obtain a copy of the License at
|
|
27507
|
+
|
|
27508
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
27509
|
+
|
|
27510
|
+
Unless required by applicable law or agreed to in writing, software
|
|
27511
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
27512
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
27513
|
+
See the License for the specific language governing permissions and
|
|
27514
|
+
limitations under the License.
|
|
27515
|
+
*/
|
|
27516
|
+
// Service Policies page on `lib-list-table`, selected by the route when Beta Features is on.
|
|
27517
|
+
class ServicePoliciesListPageComponent extends ListPageComponent {
|
|
27518
|
+
constructor(svc, filterService, dialogForm, tabNames, consoleEvents, extService) {
|
|
27519
|
+
super(filterService, svc, consoleEvents, dialogForm, extService);
|
|
27520
|
+
this.svc = svc;
|
|
27521
|
+
this.tabNames = tabNames;
|
|
27522
|
+
this.extService = extService;
|
|
27523
|
+
this.title = 'Service Policies';
|
|
27524
|
+
this.isLoading = false;
|
|
27525
|
+
this.formDataChanged = false;
|
|
27526
|
+
this.tableId = 'service-policies';
|
|
27527
|
+
this.initialPageSize = 50;
|
|
27528
|
+
}
|
|
27529
|
+
loadTableColumns() {
|
|
27530
|
+
return this.svc.initListTableColumns();
|
|
27531
|
+
}
|
|
27532
|
+
ngOnInit() {
|
|
27533
|
+
this.tabs = this.tabNames.getTabs('policies');
|
|
27534
|
+
this.svc.refreshData = this.refreshData;
|
|
27535
|
+
this.getRoleAttributes();
|
|
27536
|
+
super.ngOnInit();
|
|
27537
|
+
}
|
|
27538
|
+
headerActionClicked(action) {
|
|
27539
|
+
switch (action) {
|
|
27540
|
+
case 'add':
|
|
27541
|
+
this.svc.serviceType = '';
|
|
27542
|
+
this.svc.openEditForm();
|
|
27543
|
+
break;
|
|
27544
|
+
case 'edit':
|
|
27545
|
+
this.svc.openEditForm();
|
|
27546
|
+
break;
|
|
27547
|
+
case 'delete':
|
|
27548
|
+
const selectedItems = this.rowData.filter((row) => {
|
|
27549
|
+
return row.selected;
|
|
27550
|
+
});
|
|
27551
|
+
const label = selectedItems.length > 1 ? 'service policies' : 'service policy';
|
|
27552
|
+
this.openBulkDelete(selectedItems, label);
|
|
27553
|
+
break;
|
|
27554
|
+
default:
|
|
27555
|
+
}
|
|
27556
|
+
}
|
|
27557
|
+
tableAction(event) {
|
|
27558
|
+
const extensionActionFound = this.handleExtensionActions(event);
|
|
27559
|
+
this.trackMenuAction(event?.action, event?.item);
|
|
27560
|
+
if (extensionActionFound) {
|
|
27561
|
+
return;
|
|
27562
|
+
}
|
|
27563
|
+
switch (event?.action) {
|
|
27564
|
+
case 'toggleAll':
|
|
27565
|
+
case 'toggleItem':
|
|
27566
|
+
this.itemToggled(event.item);
|
|
27567
|
+
break;
|
|
27568
|
+
case 'update':
|
|
27569
|
+
this.svc.serviceType = 'advanced';
|
|
27570
|
+
this.svc.openEditForm(event.item.id);
|
|
27571
|
+
break;
|
|
27572
|
+
case 'create':
|
|
27573
|
+
this.svc.openEditForm();
|
|
27574
|
+
break;
|
|
27575
|
+
case 'delete':
|
|
27576
|
+
this.deleteItem(event.item);
|
|
27577
|
+
break;
|
|
27578
|
+
case 'download-all':
|
|
27579
|
+
this.downloadAllItems();
|
|
27580
|
+
break;
|
|
27581
|
+
case 'download-selected':
|
|
27582
|
+
this.svc.downloadItems(this.selectedItems);
|
|
27583
|
+
break;
|
|
27584
|
+
default:
|
|
27585
|
+
break;
|
|
27586
|
+
}
|
|
27587
|
+
}
|
|
27588
|
+
trackMenuAction(action, item) {
|
|
27589
|
+
this.extService?.consoleActionTriggered?.emit({
|
|
27590
|
+
action,
|
|
27591
|
+
page: 'service-policy',
|
|
27592
|
+
item,
|
|
27593
|
+
type: 'menu-action'
|
|
27594
|
+
});
|
|
27595
|
+
}
|
|
27596
|
+
getRoleAttributes() {
|
|
27597
|
+
this.svc.getServiceRoleAttributes();
|
|
27598
|
+
this.svc.getIdentityRoleAttributes();
|
|
27599
|
+
this.svc.getServiceNamedAttributes();
|
|
27600
|
+
this.svc.getIdentityNamedAttributes();
|
|
27601
|
+
this.svc.getPostureNamedAttributes();
|
|
27602
|
+
}
|
|
27603
|
+
deleteItem(item) {
|
|
27604
|
+
this.openBulkDelete([item], 'service-policies');
|
|
27605
|
+
}
|
|
27606
|
+
closeModal(event) {
|
|
27607
|
+
this.svc.sideModalOpen = false;
|
|
27608
|
+
if (event?.refresh) {
|
|
27609
|
+
this.refreshData();
|
|
27610
|
+
}
|
|
27611
|
+
}
|
|
27612
|
+
dataChanged(event) {
|
|
27613
|
+
this.formDataChanged = event;
|
|
27614
|
+
}
|
|
27615
|
+
ngOnDestroy() {
|
|
27616
|
+
super.ngOnDestroy();
|
|
27617
|
+
}
|
|
27618
|
+
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 }); }
|
|
27619
|
+
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", "rowHover"] }, { kind: "component", type: LoadingIndicatorComponent, selector: "lib-loading-indicator", inputs: ["isLoading"] }] }); }
|
|
27620
|
+
}
|
|
27621
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ServicePoliciesListPageComponent, decorators: [{
|
|
27622
|
+
type: Component,
|
|
27623
|
+
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" }]
|
|
27624
|
+
}], ctorParameters: () => [{ type: ServicePoliciesPageService }, { type: DataTableFilterService }, { type: i5.MatDialog }, { type: TabNameService }, { type: ConsoleEventsService }, { type: undefined, decorators: [{
|
|
27625
|
+
type: Inject,
|
|
27626
|
+
args: [SERVICE_POLICY_EXTENSION_SERVICE]
|
|
27627
|
+
}] }] });
|
|
27628
|
+
|
|
26116
27629
|
class ServicePolicyFormComponent extends ProjectableForm {
|
|
26117
27630
|
constructor(settingsService, svc, zitiService, growlerService, extService, router, route, location, dialogForm) {
|
|
26118
27631
|
super(growlerService, extService, zitiService, router, route, location, settingsService, dialogForm);
|
|
@@ -26985,12 +28498,12 @@ class ServiceEdgeRouterPoliciesPageService extends ListPageServiceClass {
|
|
|
26985
28498
|
createdAt: '',
|
|
26986
28499
|
};
|
|
26987
28500
|
this.menuItems = [
|
|
26988
|
-
{ name: 'Edit', action: 'update' },
|
|
26989
|
-
{ name: 'Delete', action: 'delete' },
|
|
28501
|
+
{ 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>' },
|
|
28502
|
+
{ 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
28503
|
];
|
|
26991
28504
|
this.tableHeaderActions = [
|
|
26992
|
-
{ name: 'Download All', action: 'download-all' },
|
|
26993
|
-
{ name: 'Download Selected', action: 'download-selected' },
|
|
28505
|
+
{ 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>' },
|
|
28506
|
+
{ 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
28507
|
];
|
|
26995
28508
|
this.resourceType = 'service-edge-router-policies';
|
|
26996
28509
|
this.validate = (formData) => {
|
|
@@ -27203,9 +28716,163 @@ class ServiceEdgeRouterPoliciesPageService extends ListPageServiceClass {
|
|
|
27203
28716
|
this.ID_COLUMN_DEF
|
|
27204
28717
|
];
|
|
27205
28718
|
}
|
|
27206
|
-
|
|
28719
|
+
// Declarative ListColumn set for the new `lib-list-table` (Beta Features on).
|
|
28720
|
+
initListTableColumns() {
|
|
28721
|
+
this.initMenuActions();
|
|
28722
|
+
const serviceRolesHeaderComponentParams = {
|
|
28723
|
+
filterType: 'ATTRIBUTE',
|
|
28724
|
+
enableSorting: true,
|
|
28725
|
+
getRoleAttributes: () => this.serviceRoleAttributes,
|
|
28726
|
+
getNamedAttributes: () => this.serviceNamedAttributes,
|
|
28727
|
+
getSelectedRoleAttributes: () => this.selectedServiceRoleAttributes,
|
|
28728
|
+
getSelectedNamedAttributes: () => this.selectedServiceNamedAttributes,
|
|
28729
|
+
setSelectedRoleAttributes: (attributes) => {
|
|
28730
|
+
this.selectedServiceRoleAttributes = attributes;
|
|
28731
|
+
},
|
|
28732
|
+
setSelectedNamedAttributes: (attributes) => {
|
|
28733
|
+
this.selectedServiceNamedAttributes = attributes;
|
|
28734
|
+
},
|
|
28735
|
+
getNamedAttributesMap: () => this.serviceNamedAttributesMap,
|
|
28736
|
+
};
|
|
28737
|
+
const routerRolesHeaderComponentParams = {
|
|
28738
|
+
filterType: 'ATTRIBUTE',
|
|
28739
|
+
enableSorting: true,
|
|
28740
|
+
getRoleAttributes: () => this.routerRoleAttributes,
|
|
28741
|
+
getNamedAttributes: () => this.routerNamedAttributes,
|
|
28742
|
+
getSelectedRoleAttributes: () => this.selectedRouterRoleAttributes,
|
|
28743
|
+
getSelectedNamedAttributes: () => this.selectedRouterNamedAttributes,
|
|
28744
|
+
setSelectedRoleAttributes: (attributes) => {
|
|
28745
|
+
this.selectedRouterRoleAttributes = attributes;
|
|
28746
|
+
},
|
|
28747
|
+
setSelectedNamedAttributes: (attributes) => {
|
|
28748
|
+
this.selectedRouterNamedAttributes = attributes;
|
|
28749
|
+
},
|
|
28750
|
+
getNamedAttributesMap: () => this.routerNamedAttributesMap,
|
|
28751
|
+
};
|
|
28752
|
+
// @ marks a named attribute, # a role attribute (matches the tag selector)
|
|
28753
|
+
const rolesChipRenderer = (row) => {
|
|
28754
|
+
const colId = row?.column?.colId;
|
|
28755
|
+
const attrs = row?.data?.[colId + 'Display'] || row?.data?.[colId] || [];
|
|
28756
|
+
return attrs.map((attr) => {
|
|
28757
|
+
const raw = String(attr?.name ?? attr ?? '').trim();
|
|
28758
|
+
if (!raw) {
|
|
28759
|
+
return '';
|
|
28760
|
+
}
|
|
28761
|
+
const isNamed = raw.charAt(0) === '@';
|
|
28762
|
+
const label = isNamed || raw.charAt(0) === '#' ? raw : '#' + raw;
|
|
28763
|
+
return `<span class="${isNamed ? 'lt-chip lt-chip-at' : 'lt-chip'}">${label}</span>`;
|
|
28764
|
+
}).join('');
|
|
28765
|
+
};
|
|
28766
|
+
const semanticFilterOptions = [
|
|
28767
|
+
{ label: 'Show All', value: '' },
|
|
28768
|
+
{ label: 'Any Of', value: 'AnyOf' },
|
|
28769
|
+
{ label: 'All Of', value: 'AllOf' },
|
|
28770
|
+
];
|
|
28771
|
+
const semanticRenderer = (row) => row?.data?.semantic === 'AnyOf' ? 'Any Of' : 'All Of';
|
|
28772
|
+
const openForm = (ctx) => {
|
|
28773
|
+
if (this.hasSelectedText()) {
|
|
28774
|
+
return;
|
|
28775
|
+
}
|
|
28776
|
+
this.serviceType = 'advanced';
|
|
28777
|
+
this.openEditForm(ctx.row?.id);
|
|
28778
|
+
};
|
|
28779
|
+
let tableColumns = [
|
|
28780
|
+
{
|
|
28781
|
+
key: 'name',
|
|
28782
|
+
field: 'name',
|
|
28783
|
+
label: 'Name',
|
|
28784
|
+
filterType: 'TEXTINPUT',
|
|
28785
|
+
cell: NameCellComponent,
|
|
28786
|
+
cellInputs: (ctx) => ({
|
|
28787
|
+
row: ctx.row,
|
|
28788
|
+
cellValue: ctx.value,
|
|
28789
|
+
cellConfig: { pathRoot: this.basePath, showIdentityIcons: false },
|
|
28790
|
+
}),
|
|
28791
|
+
onCellClick: openForm,
|
|
28792
|
+
resizable: true,
|
|
28793
|
+
cellClass: 'nf-cell-vert-align',
|
|
28794
|
+
sortable: true,
|
|
28795
|
+
onSort: this.sort.bind(this),
|
|
28796
|
+
sortDir: 'asc',
|
|
28797
|
+
width: 300,
|
|
28798
|
+
},
|
|
28799
|
+
{
|
|
28800
|
+
key: 'serviceRoles',
|
|
28801
|
+
field: 'serviceRoles',
|
|
28802
|
+
label: 'Service Attributes',
|
|
28803
|
+
filterType: 'ATTRIBUTE',
|
|
28804
|
+
headerParams: serviceRolesHeaderComponentParams,
|
|
28805
|
+
cellHtml: rolesChipRenderer,
|
|
28806
|
+
onCellClick: openForm,
|
|
28807
|
+
resizable: true,
|
|
28808
|
+
cellClass: 'nf-cell-vert-align',
|
|
28809
|
+
sortable: false,
|
|
28810
|
+
},
|
|
28811
|
+
{
|
|
28812
|
+
key: 'edgeRouterRoles',
|
|
28813
|
+
field: 'edgeRouterRoles',
|
|
28814
|
+
label: 'Router Attributes',
|
|
28815
|
+
filterType: 'ATTRIBUTE',
|
|
28816
|
+
headerParams: routerRolesHeaderComponentParams,
|
|
28817
|
+
cellHtml: rolesChipRenderer,
|
|
28818
|
+
onCellClick: openForm,
|
|
28819
|
+
resizable: true,
|
|
28820
|
+
cellClass: 'nf-cell-vert-align',
|
|
28821
|
+
sortable: false,
|
|
28822
|
+
},
|
|
28823
|
+
{
|
|
28824
|
+
key: 'semantic',
|
|
28825
|
+
field: 'semantic',
|
|
28826
|
+
label: 'Semantic',
|
|
28827
|
+
filterType: 'SELECT',
|
|
28828
|
+
filterPlaceholder: 'Any semantic',
|
|
28829
|
+
filterOptions: semanticFilterOptions,
|
|
28830
|
+
cellHtml: semanticRenderer,
|
|
28831
|
+
onCellClick: openForm,
|
|
28832
|
+
resizable: true,
|
|
28833
|
+
sortable: true,
|
|
28834
|
+
onSort: this.sort.bind(this),
|
|
28835
|
+
cellClass: 'nf-cell-vert-align',
|
|
28836
|
+
width: 120,
|
|
28837
|
+
},
|
|
28838
|
+
{
|
|
28839
|
+
key: 'createdAt',
|
|
28840
|
+
field: 'createdAt',
|
|
28841
|
+
label: 'Created At',
|
|
28842
|
+
valueFormatter: this.createdAtFormatter,
|
|
28843
|
+
filterType: 'DATETIME',
|
|
28844
|
+
filterPlaceholder: 'Any time',
|
|
28845
|
+
onCellClick: openForm,
|
|
28846
|
+
resizable: true,
|
|
28847
|
+
sortable: true,
|
|
28848
|
+
onSort: this.sort.bind(this),
|
|
28849
|
+
cellClass: 'nf-cell-vert-align',
|
|
28850
|
+
hidden: true,
|
|
28851
|
+
},
|
|
28852
|
+
{
|
|
28853
|
+
key: 'id',
|
|
28854
|
+
field: 'id',
|
|
28855
|
+
label: 'ID',
|
|
28856
|
+
filterType: 'TEXTINPUT',
|
|
28857
|
+
onCellClick: openForm,
|
|
28858
|
+
resizable: true,
|
|
28859
|
+
sortable: true,
|
|
28860
|
+
onSort: this.sort.bind(this),
|
|
28861
|
+
cellClass: 'nf-cell-vert-align',
|
|
28862
|
+
hidden: true,
|
|
28863
|
+
},
|
|
28864
|
+
];
|
|
28865
|
+
if (this.extService?.processListTableColumns) {
|
|
28866
|
+
tableColumns = this.extService.processListTableColumns(tableColumns);
|
|
28867
|
+
}
|
|
28868
|
+
return tableColumns;
|
|
28869
|
+
}
|
|
28870
|
+
getData(filters, sort, page, pageSize) {
|
|
27207
28871
|
// we can customize filters or sorting here before moving on...
|
|
27208
28872
|
this.paging.page = page || this.paging.page;
|
|
28873
|
+
if (pageSize) {
|
|
28874
|
+
this.paging.total = pageSize;
|
|
28875
|
+
}
|
|
27209
28876
|
return super.getTableData('service-edge-router-policies', this.paging, filters, sort)
|
|
27210
28877
|
.then((results) => {
|
|
27211
28878
|
return this.processData(results);
|
|
@@ -27413,6 +29080,129 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
27413
29080
|
args: [SHAREDZ_EXTENSION]
|
|
27414
29081
|
}] }] });
|
|
27415
29082
|
|
|
29083
|
+
/*
|
|
29084
|
+
Copyright NetFoundry Inc.
|
|
29085
|
+
|
|
29086
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
29087
|
+
you may not use this file except in compliance with the License.
|
|
29088
|
+
You may obtain a copy of the License at
|
|
29089
|
+
|
|
29090
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
29091
|
+
|
|
29092
|
+
Unless required by applicable law or agreed to in writing, software
|
|
29093
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
29094
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
29095
|
+
See the License for the specific language governing permissions and
|
|
29096
|
+
limitations under the License.
|
|
29097
|
+
*/
|
|
29098
|
+
// Service Edge Router Policies page on `lib-list-table`, selected by the route when Beta Features is on.
|
|
29099
|
+
class ServiceEdgeRouterPoliciesListPageComponent extends ListPageComponent {
|
|
29100
|
+
constructor(svc, filterService, dialogForm, tabNames, consoleEvents, extService) {
|
|
29101
|
+
super(filterService, svc, consoleEvents, dialogForm, extService);
|
|
29102
|
+
this.svc = svc;
|
|
29103
|
+
this.tabNames = tabNames;
|
|
29104
|
+
this.extService = extService;
|
|
29105
|
+
this.title = 'Service Edge Router Policies';
|
|
29106
|
+
this.isLoading = false;
|
|
29107
|
+
this.formDataChanged = false;
|
|
29108
|
+
this.tableId = 'service-edge-router-policies';
|
|
29109
|
+
this.initialPageSize = 50;
|
|
29110
|
+
}
|
|
29111
|
+
loadTableColumns() {
|
|
29112
|
+
return this.svc.initListTableColumns();
|
|
29113
|
+
}
|
|
29114
|
+
ngOnInit() {
|
|
29115
|
+
this.tabs = this.tabNames.getTabs('policies');
|
|
29116
|
+
this.svc.refreshData = this.refreshData;
|
|
29117
|
+
this.getRoleAttributes();
|
|
29118
|
+
super.ngOnInit();
|
|
29119
|
+
}
|
|
29120
|
+
headerActionClicked(action) {
|
|
29121
|
+
switch (action) {
|
|
29122
|
+
case 'add':
|
|
29123
|
+
this.svc.serviceType = '';
|
|
29124
|
+
this.svc.openEditForm();
|
|
29125
|
+
break;
|
|
29126
|
+
case 'edit':
|
|
29127
|
+
this.svc.openEditForm();
|
|
29128
|
+
break;
|
|
29129
|
+
case 'delete':
|
|
29130
|
+
const selectedItems = this.rowData.filter((row) => {
|
|
29131
|
+
return row.selected;
|
|
29132
|
+
});
|
|
29133
|
+
const label = selectedItems.length > 1 ? 'service edge router policies' : 'service edge router policy';
|
|
29134
|
+
this.openBulkDelete(selectedItems, label);
|
|
29135
|
+
break;
|
|
29136
|
+
default:
|
|
29137
|
+
}
|
|
29138
|
+
}
|
|
29139
|
+
tableAction(event) {
|
|
29140
|
+
this.trackMenuAction(event?.action, event?.item);
|
|
29141
|
+
switch (event?.action) {
|
|
29142
|
+
case 'toggleAll':
|
|
29143
|
+
case 'toggleItem':
|
|
29144
|
+
this.itemToggled(event.item);
|
|
29145
|
+
break;
|
|
29146
|
+
case 'update':
|
|
29147
|
+
this.svc.serviceType = 'advanced';
|
|
29148
|
+
this.svc.openEditForm(event.item?.id);
|
|
29149
|
+
break;
|
|
29150
|
+
case 'create':
|
|
29151
|
+
this.svc.openEditForm();
|
|
29152
|
+
break;
|
|
29153
|
+
case 'delete':
|
|
29154
|
+
this.deleteItem(event.item);
|
|
29155
|
+
break;
|
|
29156
|
+
case 'download-all':
|
|
29157
|
+
this.downloadAllItems();
|
|
29158
|
+
break;
|
|
29159
|
+
case 'download-selected':
|
|
29160
|
+
this.svc.downloadItems(this.selectedItems);
|
|
29161
|
+
break;
|
|
29162
|
+
default:
|
|
29163
|
+
break;
|
|
29164
|
+
}
|
|
29165
|
+
}
|
|
29166
|
+
trackMenuAction(action, item) {
|
|
29167
|
+
this.extService?.consoleActionTriggered?.emit({
|
|
29168
|
+
action,
|
|
29169
|
+
page: 'service-edge-router-policy',
|
|
29170
|
+
item,
|
|
29171
|
+
type: 'menu-action'
|
|
29172
|
+
});
|
|
29173
|
+
}
|
|
29174
|
+
getRoleAttributes() {
|
|
29175
|
+
this.svc.getEdgeRouterRoleAttributes();
|
|
29176
|
+
this.svc.getServiceRoleAttributes();
|
|
29177
|
+
this.svc.getServiceNamedAttributes();
|
|
29178
|
+
this.svc.getRouterNamedAttributes();
|
|
29179
|
+
}
|
|
29180
|
+
deleteItem(item) {
|
|
29181
|
+
this.openBulkDelete([item], 'service-edge-router-policies');
|
|
29182
|
+
}
|
|
29183
|
+
closeModal(event) {
|
|
29184
|
+
this.svc.sideModalOpen = false;
|
|
29185
|
+
if (event?.refresh) {
|
|
29186
|
+
this.refreshData();
|
|
29187
|
+
}
|
|
29188
|
+
}
|
|
29189
|
+
dataChanged(event) {
|
|
29190
|
+
this.formDataChanged = event;
|
|
29191
|
+
}
|
|
29192
|
+
ngOnDestroy() {
|
|
29193
|
+
super.ngOnDestroy();
|
|
29194
|
+
}
|
|
29195
|
+
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 }); }
|
|
29196
|
+
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", "rowHover"] }, { kind: "component", type: LoadingIndicatorComponent, selector: "lib-loading-indicator", inputs: ["isLoading"] }] }); }
|
|
29197
|
+
}
|
|
29198
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ServiceEdgeRouterPoliciesListPageComponent, decorators: [{
|
|
29199
|
+
type: Component,
|
|
29200
|
+
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" }]
|
|
29201
|
+
}], ctorParameters: () => [{ type: ServiceEdgeRouterPoliciesPageService }, { type: DataTableFilterService }, { type: i5.MatDialog }, { type: TabNameService }, { type: ConsoleEventsService }, { type: undefined, decorators: [{
|
|
29202
|
+
type: Inject,
|
|
29203
|
+
args: [SHAREDZ_EXTENSION]
|
|
29204
|
+
}] }] });
|
|
29205
|
+
|
|
27416
29206
|
class ServiceEdgeRouterPolicy {
|
|
27417
29207
|
constructor() {
|
|
27418
29208
|
this.name = '';
|
|
@@ -29911,7 +31701,7 @@ class AuthPoliciesPageService extends ListPageServiceClass {
|
|
|
29911
31701
|
];
|
|
29912
31702
|
}
|
|
29913
31703
|
checkDefaultAuthPolicy(authPolicy) {
|
|
29914
|
-
if (authPolicy
|
|
31704
|
+
if (authPolicy?.id !== 'default') {
|
|
29915
31705
|
return Promise.resolve({ confirmed: true });
|
|
29916
31706
|
}
|
|
29917
31707
|
const confirmationMessage = `<p>WARNING: Do not change the default policy unless you're sure you know what you are doing.</p>
|
|
@@ -30045,7 +31835,7 @@ class AuthPoliciesPageComponent extends ListPageComponent {
|
|
|
30045
31835
|
break;
|
|
30046
31836
|
case 'update':
|
|
30047
31837
|
this.svc.checkDefaultAuthPolicy(event.item).then((result) => {
|
|
30048
|
-
if (!result) {
|
|
31838
|
+
if (!result?.confirmed) {
|
|
30049
31839
|
return;
|
|
30050
31840
|
}
|
|
30051
31841
|
this.svc.openEditForm(event.item?.id);
|
|
@@ -30056,7 +31846,7 @@ class AuthPoliciesPageComponent extends ListPageComponent {
|
|
|
30056
31846
|
break;
|
|
30057
31847
|
case 'delete':
|
|
30058
31848
|
this.svc.checkDefaultAuthPolicy(event.item).then((result) => {
|
|
30059
|
-
if (!result) {
|
|
31849
|
+
if (!result?.confirmed) {
|
|
30060
31850
|
return;
|
|
30061
31851
|
}
|
|
30062
31852
|
this.deleteItem(event.item);
|
|
@@ -32331,32 +34121,20 @@ class PostureChecksPageService extends ListPageServiceClass {
|
|
|
32331
34121
|
constructor(schemaSvc, settings, filterService, csvDownloadService, extService, router) {
|
|
32332
34122
|
super(settings, filterService, csvDownloadService, extService, router);
|
|
32333
34123
|
this.schemaSvc = schemaSvc;
|
|
34124
|
+
this.extService = extService;
|
|
32334
34125
|
this.router = router;
|
|
32335
34126
|
this.paging = this.DEFAULT_PAGING;
|
|
32336
34127
|
this.resourceType = 'posture-checks';
|
|
32337
34128
|
this.modalType = '';
|
|
32338
34129
|
this.menuItems = [
|
|
32339
|
-
{ name: 'Edit', action: 'update' },
|
|
32340
|
-
{ name: 'Delete', action: 'delete' },
|
|
34130
|
+
{ 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>' },
|
|
34131
|
+
{ 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
34132
|
];
|
|
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) => {
|
|
34133
|
+
this.tableHeaderActions = [
|
|
34134
|
+
{ 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>' },
|
|
34135
|
+
{ 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>' },
|
|
34136
|
+
];
|
|
34137
|
+
this.detailsRenderer = (row) => {
|
|
32360
34138
|
const data = row?.data || '';
|
|
32361
34139
|
let details = '';
|
|
32362
34140
|
if (data.typeId == "DOMAIN") {
|
|
@@ -32387,6 +34165,23 @@ class PostureChecksPageService extends ListPageServiceClass {
|
|
|
32387
34165
|
}
|
|
32388
34166
|
return details;
|
|
32389
34167
|
};
|
|
34168
|
+
}
|
|
34169
|
+
initTableColumns() {
|
|
34170
|
+
const osTypeFilterOptions = {
|
|
34171
|
+
filterType: 'SELECT',
|
|
34172
|
+
enableSorting: true,
|
|
34173
|
+
filterOptions: [
|
|
34174
|
+
{ label: 'Domain', value: 'DOMAIN' },
|
|
34175
|
+
{ label: 'MAC', value: 'MAC' },
|
|
34176
|
+
{ label: 'MFA', value: 'MFA' },
|
|
34177
|
+
{ label: 'OS', value: 'OS' },
|
|
34178
|
+
{ label: 'Process', value: 'PROCESS' },
|
|
34179
|
+
{ label: 'Process Multi', value: 'MULTI_PROCESS' },
|
|
34180
|
+
]
|
|
34181
|
+
};
|
|
34182
|
+
const createdAtHeaderComponentParams = {
|
|
34183
|
+
filterType: 'DATETIME',
|
|
34184
|
+
};
|
|
32390
34185
|
return [
|
|
32391
34186
|
{
|
|
32392
34187
|
colId: 'name',
|
|
@@ -32432,7 +34227,7 @@ class PostureChecksPageService extends ListPageServiceClass {
|
|
|
32432
34227
|
field: 'details',
|
|
32433
34228
|
headerName: 'Details',
|
|
32434
34229
|
headerComponent: TableColumnDefaultComponent,
|
|
32435
|
-
cellRenderer: detailsRenderer,
|
|
34230
|
+
cellRenderer: this.detailsRenderer,
|
|
32436
34231
|
cellRendererParams: { pathRoot: this.basePath },
|
|
32437
34232
|
onCellClicked: (data) => {
|
|
32438
34233
|
if (this.hasSelectedText()) {
|
|
@@ -32460,8 +34255,102 @@ class PostureChecksPageService extends ListPageServiceClass {
|
|
|
32460
34255
|
this.ID_COLUMN_DEF
|
|
32461
34256
|
];
|
|
32462
34257
|
}
|
|
32463
|
-
|
|
34258
|
+
// Declarative ListColumn set for the new `lib-list-table` (Beta Features on).
|
|
34259
|
+
initListTableColumns() {
|
|
34260
|
+
this.initMenuActions();
|
|
34261
|
+
const escapeHtml = (v) => String(v ?? '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
34262
|
+
const openForm = (ctx) => {
|
|
34263
|
+
if (this.hasSelectedText()) {
|
|
34264
|
+
return;
|
|
34265
|
+
}
|
|
34266
|
+
this.openEditForm(ctx.row?.id);
|
|
34267
|
+
};
|
|
34268
|
+
let tableColumns = [
|
|
34269
|
+
{
|
|
34270
|
+
key: 'name',
|
|
34271
|
+
field: 'name',
|
|
34272
|
+
label: 'Name',
|
|
34273
|
+
filterType: 'TEXTINPUT',
|
|
34274
|
+
cell: NameCellComponent,
|
|
34275
|
+
cellInputs: (ctx) => ({
|
|
34276
|
+
row: ctx.row,
|
|
34277
|
+
cellValue: ctx.value,
|
|
34278
|
+
cellConfig: { pathRoot: this.basePath, showIdentityIcons: false },
|
|
34279
|
+
}),
|
|
34280
|
+
onCellClick: openForm,
|
|
34281
|
+
resizable: true,
|
|
34282
|
+
cellClass: 'nf-cell-vert-align',
|
|
34283
|
+
sortable: true,
|
|
34284
|
+
onSort: this.sort.bind(this),
|
|
34285
|
+
width: 300,
|
|
34286
|
+
},
|
|
34287
|
+
{
|
|
34288
|
+
key: 'typeId',
|
|
34289
|
+
field: 'typeId',
|
|
34290
|
+
label: 'Type',
|
|
34291
|
+
filterType: 'SELECT',
|
|
34292
|
+
filterPlaceholder: 'Any type',
|
|
34293
|
+
filterOptions: [
|
|
34294
|
+
{ label: 'Show All', value: '' },
|
|
34295
|
+
{ label: 'Domain', value: 'DOMAIN' },
|
|
34296
|
+
{ label: 'MAC', value: 'MAC' },
|
|
34297
|
+
{ label: 'MFA', value: 'MFA' },
|
|
34298
|
+
{ label: 'OS', value: 'OS' },
|
|
34299
|
+
{ label: 'Process', value: 'PROCESS' },
|
|
34300
|
+
{ label: 'Process Multi', value: 'MULTI_PROCESS' },
|
|
34301
|
+
],
|
|
34302
|
+
onCellClick: openForm,
|
|
34303
|
+
resizable: true,
|
|
34304
|
+
cellClass: 'nf-cell-vert-align',
|
|
34305
|
+
width: 140,
|
|
34306
|
+
},
|
|
34307
|
+
{
|
|
34308
|
+
key: 'details',
|
|
34309
|
+
field: 'details',
|
|
34310
|
+
label: 'Details',
|
|
34311
|
+
cellHtml: (row) => escapeHtml(this.detailsRenderer(row)),
|
|
34312
|
+
onCellClick: openForm,
|
|
34313
|
+
resizable: true,
|
|
34314
|
+
cellClass: 'nf-cell-vert-align',
|
|
34315
|
+
},
|
|
34316
|
+
{
|
|
34317
|
+
key: 'createdAt',
|
|
34318
|
+
field: 'createdAt',
|
|
34319
|
+
label: 'Created At',
|
|
34320
|
+
valueFormatter: this.createdAtFormatter,
|
|
34321
|
+
filterType: 'DATETIME',
|
|
34322
|
+
filterPlaceholder: 'Any time',
|
|
34323
|
+
onCellClick: openForm,
|
|
34324
|
+
resizable: true,
|
|
34325
|
+
sortable: true,
|
|
34326
|
+
onSort: this.sort.bind(this),
|
|
34327
|
+
cellClass: 'nf-cell-vert-align',
|
|
34328
|
+
width: this.remToPx(10),
|
|
34329
|
+
},
|
|
34330
|
+
{
|
|
34331
|
+
key: 'id',
|
|
34332
|
+
field: 'id',
|
|
34333
|
+
label: 'ID',
|
|
34334
|
+
filterType: 'TEXTINPUT',
|
|
34335
|
+
onCellClick: openForm,
|
|
34336
|
+
resizable: true,
|
|
34337
|
+
sortable: true,
|
|
34338
|
+
onSort: this.sort.bind(this),
|
|
34339
|
+
cellClass: 'nf-cell-vert-align',
|
|
34340
|
+
hidden: true,
|
|
34341
|
+
},
|
|
34342
|
+
];
|
|
34343
|
+
if (this.extService?.processListTableColumns) {
|
|
34344
|
+
tableColumns = this.extService.processListTableColumns(tableColumns);
|
|
34345
|
+
}
|
|
34346
|
+
return tableColumns;
|
|
34347
|
+
}
|
|
34348
|
+
getData(filters, sort, page, pageSize) {
|
|
32464
34349
|
// we can customize filters or sorting here before moving on...
|
|
34350
|
+
this.paging.page = page || this.paging.page;
|
|
34351
|
+
if (pageSize) {
|
|
34352
|
+
this.paging.total = pageSize;
|
|
34353
|
+
}
|
|
32465
34354
|
return super.getTableData('posture-checks', this.paging, filters, sort)
|
|
32466
34355
|
.then((results) => {
|
|
32467
34356
|
return this.processData(results);
|
|
@@ -32603,6 +34492,120 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
32603
34492
|
args: [SHAREDZ_EXTENSION]
|
|
32604
34493
|
}] }] });
|
|
32605
34494
|
|
|
34495
|
+
/*
|
|
34496
|
+
Copyright NetFoundry Inc.
|
|
34497
|
+
|
|
34498
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
34499
|
+
you may not use this file except in compliance with the License.
|
|
34500
|
+
You may obtain a copy of the License at
|
|
34501
|
+
|
|
34502
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
34503
|
+
|
|
34504
|
+
Unless required by applicable law or agreed to in writing, software
|
|
34505
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
34506
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
34507
|
+
See the License for the specific language governing permissions and
|
|
34508
|
+
limitations under the License.
|
|
34509
|
+
*/
|
|
34510
|
+
// Posture Checks page on `lib-list-table`, selected by the route when Beta Features is on.
|
|
34511
|
+
class PostureChecksListPageComponent extends ListPageComponent {
|
|
34512
|
+
constructor(svc, filterService, dialogForm, tabNames, consoleEvents, extService) {
|
|
34513
|
+
super(filterService, svc, consoleEvents, dialogForm, extService);
|
|
34514
|
+
this.svc = svc;
|
|
34515
|
+
this.tabNames = tabNames;
|
|
34516
|
+
this.extService = extService;
|
|
34517
|
+
this.title = 'Posture Checks';
|
|
34518
|
+
this.isLoading = false;
|
|
34519
|
+
this.formDataChanged = false;
|
|
34520
|
+
this.tableId = 'posture-checks';
|
|
34521
|
+
this.initialPageSize = 50;
|
|
34522
|
+
}
|
|
34523
|
+
loadTableColumns() {
|
|
34524
|
+
return this.svc.initListTableColumns();
|
|
34525
|
+
}
|
|
34526
|
+
ngOnInit() {
|
|
34527
|
+
this.tabs = this.tabNames.getTabs('policies');
|
|
34528
|
+
this.svc.refreshData = this.refreshData;
|
|
34529
|
+
super.ngOnInit();
|
|
34530
|
+
}
|
|
34531
|
+
headerActionClicked(action) {
|
|
34532
|
+
switch (action) {
|
|
34533
|
+
case 'add':
|
|
34534
|
+
this.svc.openEditForm();
|
|
34535
|
+
break;
|
|
34536
|
+
case 'edit':
|
|
34537
|
+
this.svc.openEditForm();
|
|
34538
|
+
break;
|
|
34539
|
+
case 'delete':
|
|
34540
|
+
const selectedItems = this.rowData.filter((row) => {
|
|
34541
|
+
return row.selected;
|
|
34542
|
+
});
|
|
34543
|
+
const label = selectedItems.length > 1 ? 'posture checks' : 'posture check';
|
|
34544
|
+
this.openBulkDelete(selectedItems, label);
|
|
34545
|
+
break;
|
|
34546
|
+
default:
|
|
34547
|
+
}
|
|
34548
|
+
}
|
|
34549
|
+
tableAction(event) {
|
|
34550
|
+
this.trackMenuAction(event?.action, event?.item);
|
|
34551
|
+
switch (event?.action) {
|
|
34552
|
+
case 'toggleAll':
|
|
34553
|
+
case 'toggleItem':
|
|
34554
|
+
this.itemToggled(event.item);
|
|
34555
|
+
break;
|
|
34556
|
+
case 'update':
|
|
34557
|
+
this.svc.openEditForm(event.item?.id);
|
|
34558
|
+
break;
|
|
34559
|
+
case 'create':
|
|
34560
|
+
this.svc.openEditForm();
|
|
34561
|
+
break;
|
|
34562
|
+
case 'delete':
|
|
34563
|
+
this.deleteItem(event.item);
|
|
34564
|
+
break;
|
|
34565
|
+
case 'download-all':
|
|
34566
|
+
this.downloadAllItems();
|
|
34567
|
+
break;
|
|
34568
|
+
case 'download-selected':
|
|
34569
|
+
this.svc.downloadItems(this.selectedItems);
|
|
34570
|
+
break;
|
|
34571
|
+
default:
|
|
34572
|
+
break;
|
|
34573
|
+
}
|
|
34574
|
+
}
|
|
34575
|
+
trackMenuAction(action, item) {
|
|
34576
|
+
this.extService?.consoleActionTriggered?.emit({
|
|
34577
|
+
action,
|
|
34578
|
+
page: 'posture-check',
|
|
34579
|
+
item,
|
|
34580
|
+
type: 'menu-action'
|
|
34581
|
+
});
|
|
34582
|
+
}
|
|
34583
|
+
deleteItem(item) {
|
|
34584
|
+
this.openBulkDelete([item], 'posture-checks');
|
|
34585
|
+
}
|
|
34586
|
+
closeModal(event) {
|
|
34587
|
+
this.svc.sideModalOpen = false;
|
|
34588
|
+
if (event?.refresh) {
|
|
34589
|
+
this.refreshData();
|
|
34590
|
+
}
|
|
34591
|
+
}
|
|
34592
|
+
dataChanged(event) {
|
|
34593
|
+
this.formDataChanged = event;
|
|
34594
|
+
}
|
|
34595
|
+
ngOnDestroy() {
|
|
34596
|
+
super.ngOnDestroy();
|
|
34597
|
+
}
|
|
34598
|
+
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 }); }
|
|
34599
|
+
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", "rowHover"] }, { kind: "component", type: LoadingIndicatorComponent, selector: "lib-loading-indicator", inputs: ["isLoading"] }] }); }
|
|
34600
|
+
}
|
|
34601
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PostureChecksListPageComponent, decorators: [{
|
|
34602
|
+
type: Component,
|
|
34603
|
+
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" }]
|
|
34604
|
+
}], ctorParameters: () => [{ type: PostureChecksPageService }, { type: DataTableFilterService }, { type: i5.MatDialog }, { type: TabNameService }, { type: ConsoleEventsService }, { type: undefined, decorators: [{
|
|
34605
|
+
type: Inject,
|
|
34606
|
+
args: [SHAREDZ_EXTENSION]
|
|
34607
|
+
}] }] });
|
|
34608
|
+
|
|
32606
34609
|
class PostureCheck {
|
|
32607
34610
|
constructor() {
|
|
32608
34611
|
this.name = '';
|
|
@@ -44280,6 +46283,7 @@ class OpenZitiConsoleLibModule {
|
|
|
44280
46283
|
SdkInfoTooltipComponent,
|
|
44281
46284
|
BooleanCellComponent,
|
|
44282
46285
|
TokenCellComponent,
|
|
46286
|
+
AttributeCellComponent,
|
|
44283
46287
|
TableCellSelectComponent,
|
|
44284
46288
|
TableColumnSelectComponent,
|
|
44285
46289
|
TableCellMenuComponent,
|
|
@@ -44319,12 +46323,15 @@ class OpenZitiConsoleLibModule {
|
|
|
44319
46323
|
CreationSummaryDialogComponent,
|
|
44320
46324
|
ConfigEditorComponent,
|
|
44321
46325
|
ServicePoliciesPageComponent,
|
|
46326
|
+
ServicePoliciesListPageComponent,
|
|
44322
46327
|
ServicePolicyFormComponent,
|
|
44323
46328
|
EdgeRouterPoliciesPageComponent,
|
|
46329
|
+
EdgeRouterPoliciesListPageComponent,
|
|
44324
46330
|
EdgeRouterPolicyFormComponent,
|
|
44325
46331
|
MultiActionButtonComponent,
|
|
44326
46332
|
TableCellNameComponent,
|
|
44327
46333
|
ServiceEdgeRouterPoliciesPageComponent,
|
|
46334
|
+
ServiceEdgeRouterPoliciesListPageComponent,
|
|
44328
46335
|
ServiceEdgeRouterPolicyFormComponent,
|
|
44329
46336
|
TerminatorsPageComponent,
|
|
44330
46337
|
ConfigurationFormComponent,
|
|
@@ -44338,6 +46345,7 @@ class OpenZitiConsoleLibModule {
|
|
|
44338
46345
|
VerifyCertificateComponent,
|
|
44339
46346
|
LoginDialogComponent,
|
|
44340
46347
|
PostureChecksPageComponent,
|
|
46348
|
+
PostureChecksListPageComponent,
|
|
44341
46349
|
PostureCheckFormComponent,
|
|
44342
46350
|
SessionsPageComponent,
|
|
44343
46351
|
SessionFormComponent,
|
|
@@ -44425,8 +46433,10 @@ class OpenZitiConsoleLibModule {
|
|
|
44425
46433
|
FormFieldToggleComponent,
|
|
44426
46434
|
ServiceFormComponent,
|
|
44427
46435
|
ServicePoliciesPageComponent,
|
|
46436
|
+
ServicePoliciesListPageComponent,
|
|
44428
46437
|
ServicePolicyFormComponent,
|
|
44429
46438
|
EdgeRouterPoliciesPageComponent,
|
|
46439
|
+
EdgeRouterPoliciesListPageComponent,
|
|
44430
46440
|
TerminatorsPageComponent,
|
|
44431
46441
|
TerminatorFormComponent,
|
|
44432
46442
|
JwtSignersPageComponent,
|
|
@@ -44435,6 +46445,7 @@ class OpenZitiConsoleLibModule {
|
|
|
44435
46445
|
AuthPolicyFormComponent,
|
|
44436
46446
|
LoginDialogComponent,
|
|
44437
46447
|
PostureChecksPageComponent,
|
|
46448
|
+
PostureChecksListPageComponent,
|
|
44438
46449
|
PostureCheckFormComponent,
|
|
44439
46450
|
SessionsPageComponent,
|
|
44440
46451
|
SessionFormComponent,
|
|
@@ -44536,6 +46547,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
44536
46547
|
SdkInfoTooltipComponent,
|
|
44537
46548
|
BooleanCellComponent,
|
|
44538
46549
|
TokenCellComponent,
|
|
46550
|
+
AttributeCellComponent,
|
|
44539
46551
|
TableCellSelectComponent,
|
|
44540
46552
|
TableColumnSelectComponent,
|
|
44541
46553
|
TableCellMenuComponent,
|
|
@@ -44575,12 +46587,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
44575
46587
|
CreationSummaryDialogComponent,
|
|
44576
46588
|
ConfigEditorComponent,
|
|
44577
46589
|
ServicePoliciesPageComponent,
|
|
46590
|
+
ServicePoliciesListPageComponent,
|
|
44578
46591
|
ServicePolicyFormComponent,
|
|
44579
46592
|
EdgeRouterPoliciesPageComponent,
|
|
46593
|
+
EdgeRouterPoliciesListPageComponent,
|
|
44580
46594
|
EdgeRouterPolicyFormComponent,
|
|
44581
46595
|
MultiActionButtonComponent,
|
|
44582
46596
|
TableCellNameComponent,
|
|
44583
46597
|
ServiceEdgeRouterPoliciesPageComponent,
|
|
46598
|
+
ServiceEdgeRouterPoliciesListPageComponent,
|
|
44584
46599
|
ServiceEdgeRouterPolicyFormComponent,
|
|
44585
46600
|
TerminatorsPageComponent,
|
|
44586
46601
|
ConfigurationFormComponent,
|
|
@@ -44594,6 +46609,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
44594
46609
|
VerifyCertificateComponent,
|
|
44595
46610
|
LoginDialogComponent,
|
|
44596
46611
|
PostureChecksPageComponent,
|
|
46612
|
+
PostureChecksListPageComponent,
|
|
44597
46613
|
PostureCheckFormComponent,
|
|
44598
46614
|
SessionsPageComponent,
|
|
44599
46615
|
SessionFormComponent,
|
|
@@ -44662,8 +46678,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
44662
46678
|
FormFieldToggleComponent,
|
|
44663
46679
|
ServiceFormComponent,
|
|
44664
46680
|
ServicePoliciesPageComponent,
|
|
46681
|
+
ServicePoliciesListPageComponent,
|
|
44665
46682
|
ServicePolicyFormComponent,
|
|
44666
46683
|
EdgeRouterPoliciesPageComponent,
|
|
46684
|
+
EdgeRouterPoliciesListPageComponent,
|
|
44667
46685
|
TerminatorsPageComponent,
|
|
44668
46686
|
TerminatorFormComponent,
|
|
44669
46687
|
JwtSignersPageComponent,
|
|
@@ -44672,6 +46690,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
44672
46690
|
AuthPolicyFormComponent,
|
|
44673
46691
|
LoginDialogComponent,
|
|
44674
46692
|
PostureChecksPageComponent,
|
|
46693
|
+
PostureChecksListPageComponent,
|
|
44675
46694
|
PostureCheckFormComponent,
|
|
44676
46695
|
SessionsPageComponent,
|
|
44677
46696
|
SessionFormComponent,
|
|
@@ -46197,7 +48216,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
46197
48216
|
*/
|
|
46198
48217
|
|
|
46199
48218
|
const ZAC_VERSION = {
|
|
46200
|
-
"version": "4.
|
|
48219
|
+
"version": "4.7.1"
|
|
46201
48220
|
};
|
|
46202
48221
|
|
|
46203
48222
|
/*
|
|
@@ -46208,5 +48227,5 @@ const ZAC_VERSION = {
|
|
|
46208
48227
|
* Generated bundle index. Do not edit.
|
|
46209
48228
|
*/
|
|
46210
48229
|
|
|
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 };
|
|
48230
|
+
export { APISessionFormComponent, APISessionsPageComponent, API_RESOURCE_TO_ENTITY_PERMISSION, ApiSessionsPageService, AttributeCellComponent, 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
48231
|
//# sourceMappingURL=openziti-ziti-console-lib.mjs.map
|