@openziti/ziti-console-lib 1.5.2 → 1.5.4
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.
|
@@ -10,7 +10,7 @@ import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
|
|
|
10
10
|
import * as i4 from '@angular/router';
|
|
11
11
|
import { RouterModule, NavigationEnd } from '@angular/router';
|
|
12
12
|
import { BehaviorSubject, Subject, firstValueFrom, tap, map, Subscription, fromEvent, of, interval } from 'rxjs';
|
|
13
|
-
import _, { debounce, defer, isEmpty, isNumber, includes, isNil, isNaN as isNaN$1, cloneDeep, isString, forEach, isFunction, get, unset,
|
|
13
|
+
import _, { debounce, defer, isEmpty, isNumber, includes, isNil, isNaN as isNaN$1, cloneDeep, isBoolean, isArray, isString, forEach, isFunction, get, unset, keys, isEqual, isObject, forOwn, invert, map as map$2, some, filter, sortBy, sortedUniq, set, has, trim, delay, invoke } from 'lodash';
|
|
14
14
|
import * as i3 from '@angular/material/tooltip';
|
|
15
15
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
16
16
|
import * as i5$2 from 'angularx-qrcode';
|
|
@@ -30,6 +30,8 @@ import * as i5$3 from '@angular/material/select';
|
|
|
30
30
|
import { MatSelect, MatSelectModule } from '@angular/material/select';
|
|
31
31
|
import * as i1$4 from '@angular/cdk/overlay';
|
|
32
32
|
import { OverlayModule } from '@angular/cdk/overlay';
|
|
33
|
+
import * as i6$1 from '@angular/cdk/drag-drop';
|
|
34
|
+
import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
|
|
33
35
|
import { catchError, map as map$1, distinctUntilChanged, debounceTime, skip, takeUntil, throttleTime, filter as filter$1 } from 'rxjs/operators';
|
|
34
36
|
import * as i1$2 from 'ngx-logger';
|
|
35
37
|
import { NgxLoggerLevel } from 'ngx-logger';
|
|
@@ -154,6 +156,9 @@ class ExtensionsNoopService {
|
|
|
154
156
|
processTableColumns(tableColumns) {
|
|
155
157
|
return tableColumns;
|
|
156
158
|
}
|
|
159
|
+
processListTableColumns(tableColumns) {
|
|
160
|
+
return tableColumns;
|
|
161
|
+
}
|
|
157
162
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ExtensionsNoopService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
158
163
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ExtensionsNoopService, providedIn: 'root' }); }
|
|
159
164
|
}
|
|
@@ -1753,6 +1758,168 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
1753
1758
|
type: Output
|
|
1754
1759
|
}] } });
|
|
1755
1760
|
|
|
1761
|
+
/*
|
|
1762
|
+
Copyright NetFoundry Inc.
|
|
1763
|
+
|
|
1764
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
1765
|
+
you may not use this file except in compliance with the License.
|
|
1766
|
+
You may obtain a copy of the License at
|
|
1767
|
+
|
|
1768
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
1769
|
+
|
|
1770
|
+
Unless required by applicable law or agreed to in writing, software
|
|
1771
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
1772
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1773
|
+
See the License for the specific language governing permissions and
|
|
1774
|
+
limitations under the License.
|
|
1775
|
+
*/
|
|
1776
|
+
/**
|
|
1777
|
+
* Per-instance state + localStorage persistence for {@link ListTableComponent}.
|
|
1778
|
+
* Uses its own `lt_<tableId>_*` keys (separate from the legacy ag-grid table) so a
|
|
1779
|
+
* first visit starts from the column defs' default widths, not a carried-over ag layout.
|
|
1780
|
+
*/
|
|
1781
|
+
class ListTableService {
|
|
1782
|
+
constructor() {
|
|
1783
|
+
this.tableId = '';
|
|
1784
|
+
/** Coordinates the toolbar dropdowns so only one (filter pill or column chooser)
|
|
1785
|
+
* is open at a time. Openers emit themselves; others close when they see an
|
|
1786
|
+
* owner that isn't them. */
|
|
1787
|
+
this.menuOpenedSubject = new Subject();
|
|
1788
|
+
this.menuOpened$ = this.menuOpenedSubject.asObservable();
|
|
1789
|
+
}
|
|
1790
|
+
notifyMenuOpened(owner) {
|
|
1791
|
+
this.menuOpenedSubject.next(owner);
|
|
1792
|
+
}
|
|
1793
|
+
stateKey() {
|
|
1794
|
+
return `lt_${this.tableId}_table_state`;
|
|
1795
|
+
}
|
|
1796
|
+
widthsKey() {
|
|
1797
|
+
return `lt_${this.tableId}_column_widths`;
|
|
1798
|
+
}
|
|
1799
|
+
pageSizeKey() {
|
|
1800
|
+
return `lt_${this.tableId}_page_size`;
|
|
1801
|
+
}
|
|
1802
|
+
static pageSizeKeyFor(tableId) {
|
|
1803
|
+
return `lt_${tableId}_page_size`;
|
|
1804
|
+
}
|
|
1805
|
+
restorePageSize(fallback) {
|
|
1806
|
+
return ListTableService.readPersistedPageSize(this.tableId, fallback);
|
|
1807
|
+
}
|
|
1808
|
+
savePageSize(size) {
|
|
1809
|
+
try {
|
|
1810
|
+
localStorage.setItem(this.pageSizeKey(), String(size));
|
|
1811
|
+
}
|
|
1812
|
+
catch {
|
|
1813
|
+
// ignore
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
/** Reads a table's remembered rows-per-page without an instance (for host pre-seeding). */
|
|
1817
|
+
static readPersistedPageSize(tableId, fallback) {
|
|
1818
|
+
try {
|
|
1819
|
+
const raw = localStorage.getItem(ListTableService.pageSizeKeyFor(tableId));
|
|
1820
|
+
const n = raw ? parseInt(raw, 10) : NaN;
|
|
1821
|
+
return Number.isFinite(n) && n > 0 ? n : fallback;
|
|
1822
|
+
}
|
|
1823
|
+
catch {
|
|
1824
|
+
return fallback;
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
/**
|
|
1828
|
+
* Returns a shallow-cloned copy of `columns` with any persisted width, visibility,
|
|
1829
|
+
* and order applied. Columns not present in the saved state keep their declared
|
|
1830
|
+
* position (appended after the saved ones).
|
|
1831
|
+
*/
|
|
1832
|
+
applyPersistedState(columns) {
|
|
1833
|
+
let cols = columns.map((c) => ({ ...c }));
|
|
1834
|
+
// widths
|
|
1835
|
+
try {
|
|
1836
|
+
const raw = localStorage.getItem(this.widthsKey());
|
|
1837
|
+
if (raw) {
|
|
1838
|
+
const widths = JSON.parse(raw) || {};
|
|
1839
|
+
cols.forEach((c) => {
|
|
1840
|
+
if (widths[c.key] != null) {
|
|
1841
|
+
c.width = widths[c.key];
|
|
1842
|
+
}
|
|
1843
|
+
});
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
catch {
|
|
1847
|
+
// ignore malformed / unavailable storage
|
|
1848
|
+
}
|
|
1849
|
+
// order + visibility
|
|
1850
|
+
try {
|
|
1851
|
+
const raw = localStorage.getItem(this.stateKey());
|
|
1852
|
+
if (raw) {
|
|
1853
|
+
const state = JSON.parse(raw) || [];
|
|
1854
|
+
const ordered = [];
|
|
1855
|
+
state.forEach((s) => {
|
|
1856
|
+
const found = cols.find((c) => c.key === s.colId);
|
|
1857
|
+
if (found && !ordered.includes(found)) {
|
|
1858
|
+
if (s.hide != null) {
|
|
1859
|
+
found.hidden = s.hide;
|
|
1860
|
+
}
|
|
1861
|
+
if (s.width != null) {
|
|
1862
|
+
found.width = s.width;
|
|
1863
|
+
}
|
|
1864
|
+
ordered.push(found);
|
|
1865
|
+
}
|
|
1866
|
+
});
|
|
1867
|
+
cols.forEach((c) => {
|
|
1868
|
+
if (!ordered.includes(c)) {
|
|
1869
|
+
ordered.push(c);
|
|
1870
|
+
}
|
|
1871
|
+
});
|
|
1872
|
+
if (ordered.length) {
|
|
1873
|
+
cols = ordered;
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
catch {
|
|
1878
|
+
// ignore malformed / unavailable storage
|
|
1879
|
+
}
|
|
1880
|
+
return cols;
|
|
1881
|
+
}
|
|
1882
|
+
/** Persists the current order + visibility (and widths embedded in each entry). */
|
|
1883
|
+
saveState(columns) {
|
|
1884
|
+
const state = columns.map((c) => ({ colId: c.key, hide: !!c.hidden, width: c.width }));
|
|
1885
|
+
try {
|
|
1886
|
+
localStorage.setItem(this.stateKey(), JSON.stringify(state));
|
|
1887
|
+
}
|
|
1888
|
+
catch {
|
|
1889
|
+
// ignore
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
/** Persists a single column's width, then rewrites the ordered state. */
|
|
1893
|
+
saveWidth(colId, width, columns) {
|
|
1894
|
+
try {
|
|
1895
|
+
const raw = localStorage.getItem(this.widthsKey());
|
|
1896
|
+
const widths = raw ? JSON.parse(raw) : {};
|
|
1897
|
+
widths[colId] = width;
|
|
1898
|
+
localStorage.setItem(this.widthsKey(), JSON.stringify(widths));
|
|
1899
|
+
}
|
|
1900
|
+
catch {
|
|
1901
|
+
// ignore
|
|
1902
|
+
}
|
|
1903
|
+
this.saveState(columns);
|
|
1904
|
+
}
|
|
1905
|
+
/** Clears all persisted layout for this table ("Restore Default Table"). */
|
|
1906
|
+
reset() {
|
|
1907
|
+
try {
|
|
1908
|
+
localStorage.removeItem(this.stateKey());
|
|
1909
|
+
localStorage.removeItem(this.widthsKey());
|
|
1910
|
+
localStorage.removeItem(this.pageSizeKey());
|
|
1911
|
+
}
|
|
1912
|
+
catch {
|
|
1913
|
+
// ignore
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListTableService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1917
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListTableService }); }
|
|
1918
|
+
}
|
|
1919
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListTableService, decorators: [{
|
|
1920
|
+
type: Injectable
|
|
1921
|
+
}] });
|
|
1922
|
+
|
|
1756
1923
|
/*
|
|
1757
1924
|
Copyright NetFoundry Inc.
|
|
1758
1925
|
|
|
@@ -2561,6 +2728,20 @@ class ZitiDataService {
|
|
|
2561
2728
|
}
|
|
2562
2729
|
return filters;
|
|
2563
2730
|
}
|
|
2731
|
+
// escape ziti-ql string contents so a value with a quote/backslash can't alter the query
|
|
2732
|
+
escapeQlString(v) {
|
|
2733
|
+
return String(v).replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
2734
|
+
}
|
|
2735
|
+
// generic multi-select over a scalar field: `col = "a" or col = "b"` (vs anyOf() for collections)
|
|
2736
|
+
getMultiSelectFilter(val, columnId, semantic = 'AnyOf') {
|
|
2737
|
+
const join = semantic === 'AllOf' ? 'and' : 'or';
|
|
2738
|
+
const clause = (v) => `${columnId} = ${(isNumber(v) || isBoolean(v)) ? `${v}` : `"${this.escapeQlString(v)}"`}`;
|
|
2739
|
+
if (isArray(val)) {
|
|
2740
|
+
const parts = val.map(clause);
|
|
2741
|
+
return parts.length > 1 ? `(${parts.join(` ${join} `)})` : (parts[0] || '');
|
|
2742
|
+
}
|
|
2743
|
+
return clause(val);
|
|
2744
|
+
}
|
|
2564
2745
|
getErrorMessage(resp) {
|
|
2565
2746
|
let errorMessage;
|
|
2566
2747
|
if (resp?.error?.error?.cause?.message) {
|
|
@@ -2908,15 +3089,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
2908
3089
|
}] }] });
|
|
2909
3090
|
|
|
2910
3091
|
class DataTableFilterService {
|
|
3092
|
+
// filter params live under this prefix so unrelated params (e.g. ?tab=) aren't treated as filters
|
|
3093
|
+
static { this.URL_FILTER_PREFIX = 'f.'; }
|
|
2911
3094
|
constructor(location, router, activatedRoute) {
|
|
2912
3095
|
this.location = location;
|
|
2913
3096
|
this.router = router;
|
|
2914
3097
|
this.activatedRoute = activatedRoute;
|
|
2915
3098
|
this.filters = [];
|
|
2916
3099
|
this.currentPage = 1;
|
|
3100
|
+
/** Rows requested per page. Defaults to the legacy page size; the list-table's
|
|
3101
|
+
* rows-per-page control changes it via {@link changePageSize}. */
|
|
3102
|
+
this.pageSize = 50;
|
|
2917
3103
|
this.filtersChanged = new BehaviorSubject(this.filters);
|
|
2918
3104
|
this.filtering = new BehaviorSubject(false);
|
|
2919
3105
|
this.pageChanged = new BehaviorSubject(this.currentPage);
|
|
3106
|
+
this.pageSizeChanged = new BehaviorSubject(this.pageSize);
|
|
2920
3107
|
this.currentQueryParams = [];
|
|
2921
3108
|
}
|
|
2922
3109
|
updateFilter(filterObj) {
|
|
@@ -2962,6 +3149,11 @@ class DataTableFilterService {
|
|
|
2962
3149
|
this.currentPage = page;
|
|
2963
3150
|
this.pageChanged.next(page);
|
|
2964
3151
|
}
|
|
3152
|
+
changePageSize(size) {
|
|
3153
|
+
this.pageSize = size;
|
|
3154
|
+
this.currentPage = 1;
|
|
3155
|
+
this.pageSizeChanged.next(size);
|
|
3156
|
+
}
|
|
2965
3157
|
clearFilters() {
|
|
2966
3158
|
this.filters = [];
|
|
2967
3159
|
this.updateUrlParameters();
|
|
@@ -2976,18 +3168,25 @@ class DataTableFilterService {
|
|
|
2976
3168
|
return filters;
|
|
2977
3169
|
}
|
|
2978
3170
|
updateUrlParameters(filtersToRemove = []) {
|
|
3171
|
+
const prefix = DataTableFilterService.URL_FILTER_PREFIX;
|
|
2979
3172
|
const urlFiltersMap = this.getUrlFiltersMap();
|
|
2980
|
-
let params = new HttpParams();
|
|
2981
3173
|
this.filters.forEach(filter => {
|
|
2982
3174
|
urlFiltersMap[filter.columnId] = filter;
|
|
2983
3175
|
});
|
|
3176
|
+
const currentParamString = window.location.href.split("?")[1] || '';
|
|
3177
|
+
let params = new HttpParams({ fromString: currentParamString });
|
|
3178
|
+
params.keys()
|
|
3179
|
+
.filter((key) => key.startsWith(prefix))
|
|
3180
|
+
.forEach((key) => {
|
|
3181
|
+
params = params.delete(key);
|
|
3182
|
+
});
|
|
2984
3183
|
const newFilters = [];
|
|
2985
3184
|
forEach(urlFiltersMap, (value, key) => {
|
|
2986
3185
|
const filterRemoved = filtersToRemove.some((removed) => {
|
|
2987
3186
|
return removed.columnId === key;
|
|
2988
3187
|
});
|
|
2989
3188
|
if (!filterRemoved) {
|
|
2990
|
-
params = params.append(key, value.value);
|
|
3189
|
+
params = params.append(prefix + key, value.value);
|
|
2991
3190
|
newFilters.push(value);
|
|
2992
3191
|
}
|
|
2993
3192
|
});
|
|
@@ -2997,11 +3196,16 @@ class DataTableFilterService {
|
|
|
2997
3196
|
this.storeFilters();
|
|
2998
3197
|
}
|
|
2999
3198
|
getUrlFiltersMap() {
|
|
3199
|
+
const prefix = DataTableFilterService.URL_FILTER_PREFIX;
|
|
3000
3200
|
const paramString = window.location.href.split("?")[1];
|
|
3001
3201
|
const params = new HttpParams({ fromString: paramString });
|
|
3002
3202
|
const storedFilters = this.getStoredFilters();
|
|
3003
3203
|
const appliedFiltersMap = {};
|
|
3004
|
-
params.keys().forEach((
|
|
3204
|
+
params.keys().forEach((rawKey) => {
|
|
3205
|
+
if (!rawKey.startsWith(prefix)) {
|
|
3206
|
+
return;
|
|
3207
|
+
}
|
|
3208
|
+
const key = rawKey.slice(prefix.length);
|
|
3005
3209
|
const storedFilter = storedFilters.find((filter) => {
|
|
3006
3210
|
return filter.columnId === key;
|
|
3007
3211
|
});
|
|
@@ -3009,7 +3213,7 @@ class DataTableFilterService {
|
|
|
3009
3213
|
appliedFiltersMap[key] = storedFilter;
|
|
3010
3214
|
}
|
|
3011
3215
|
else {
|
|
3012
|
-
let val = params.get(
|
|
3216
|
+
let val = params.get(rawKey);
|
|
3013
3217
|
let type = 'TEXTINPUT';
|
|
3014
3218
|
let label = val;
|
|
3015
3219
|
if (val?.split(',')?.length > 1) {
|
|
@@ -3510,6 +3714,14 @@ let ListPageServiceClass = class ListPageServiceClass {
|
|
|
3510
3714
|
this.basePath = pathSegments[0];
|
|
3511
3715
|
}
|
|
3512
3716
|
});
|
|
3717
|
+
// The subscription above misses the NavigationEnd that already fired before
|
|
3718
|
+
// this root-provided service was lazily constructed (first page load), which
|
|
3719
|
+
// would leave basePath empty and send name links / openEditForm to "/<id>".
|
|
3720
|
+
// Seed it from the current route immediately.
|
|
3721
|
+
const currentConfig = this.router?.routerState?.snapshot?.root?.firstChild?.routeConfig;
|
|
3722
|
+
if (currentConfig?.path) {
|
|
3723
|
+
this.basePath = currentConfig.path.split('/')[0];
|
|
3724
|
+
}
|
|
3513
3725
|
}
|
|
3514
3726
|
/**
|
|
3515
3727
|
* Root-provided page services survive route changes; restore baseline menus before each table init
|
|
@@ -3702,17 +3914,23 @@ class ListPageComponent {
|
|
|
3702
3914
|
this.filterApplied = false;
|
|
3703
3915
|
this.modalOpen = false;
|
|
3704
3916
|
this.gridObj = {};
|
|
3917
|
+
this.tableObj = null;
|
|
3705
3918
|
this.subscription = new Subscription();
|
|
3706
3919
|
this.growlerSvc = inject(GrowlerService);
|
|
3707
3920
|
this.managementPermissions = inject(ManagementPermissionsService);
|
|
3708
3921
|
}
|
|
3709
3922
|
ngOnInit() {
|
|
3710
3923
|
this.filterService.currentPage = 1;
|
|
3924
|
+
// new list-table pages: adopt this table's remembered rows-per-page before the
|
|
3925
|
+
// first fetch so the initial load honors it (consumers get this without copying)
|
|
3926
|
+
if (this.tableId) {
|
|
3927
|
+
this.filterService.pageSize = ListTableService.readPersistedPageSize(this.tableId, this.initialPageSize ?? this.filterService.pageSize);
|
|
3928
|
+
}
|
|
3711
3929
|
this.svc.sideModalOpen = false;
|
|
3712
3930
|
this.svc.refreshData = this.refreshData.bind(this);
|
|
3713
3931
|
this.svc.resetMenusForInit();
|
|
3714
3932
|
this.svc.initMenuActions();
|
|
3715
|
-
this.columnDefs = this.
|
|
3933
|
+
this.columnDefs = this.loadTableColumns();
|
|
3716
3934
|
this.svc.capturePermissionSnapshots();
|
|
3717
3935
|
this.subscription.add(this.managementPermissions.stateVersion$.subscribe(() => {
|
|
3718
3936
|
this.svc.rebuildMenusAndHeaders(this.managementPermissions);
|
|
@@ -3731,6 +3949,9 @@ class ListPageComponent {
|
|
|
3731
3949
|
this.subscription.add(this.filterService.pageChanged.pipe(skip(1)).subscribe(page => {
|
|
3732
3950
|
this.refreshData();
|
|
3733
3951
|
}));
|
|
3952
|
+
this.subscription.add(this.filterService.pageSizeChanged.pipe(skip(1)).subscribe(() => {
|
|
3953
|
+
this.refreshData();
|
|
3954
|
+
}));
|
|
3734
3955
|
this.subscription.add(this.consoleEvents.closeSideModal.subscribe((event) => {
|
|
3735
3956
|
this.closeModal();
|
|
3736
3957
|
}));
|
|
@@ -3751,7 +3972,8 @@ class ListPageComponent {
|
|
|
3751
3972
|
const index = this.svc.tableHeaderActions.findIndex((a) => a.action === 'download-selected');
|
|
3752
3973
|
const allow = this.managementPermissions.canRead(this.svc.resourceType);
|
|
3753
3974
|
if (hasSelection && allow && index === -1) {
|
|
3754
|
-
|
|
3975
|
+
// icon (SVG) is rendered by the new list-table's header menu; legacy ignores it
|
|
3976
|
+
this.svc.tableHeaderActions.push({ 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>' });
|
|
3755
3977
|
}
|
|
3756
3978
|
if ((!hasSelection || !allow) && index !== -1) {
|
|
3757
3979
|
this.svc.tableHeaderActions.splice(index, 1);
|
|
@@ -3782,7 +4004,7 @@ class ListPageComponent {
|
|
|
3782
4004
|
}
|
|
3783
4005
|
this.isLoading = true;
|
|
3784
4006
|
sort = sort ? sort : this.svc.currentSort;
|
|
3785
|
-
this.svc.getData(this.filterService.filters, sort, this.filterService.currentPage)
|
|
4007
|
+
this.svc.getData(this.filterService.filters, sort, this.filterService.currentPage, this.filterService.pageSize)
|
|
3786
4008
|
.then((data) => {
|
|
3787
4009
|
this.rowData = [];
|
|
3788
4010
|
if (hardRefresh) {
|
|
@@ -3868,9 +4090,22 @@ class ListPageComponent {
|
|
|
3868
4090
|
}
|
|
3869
4091
|
return extensionFound;
|
|
3870
4092
|
}
|
|
4093
|
+
/**
|
|
4094
|
+
* Column set loaded into the table on init. Defaults to the service's ag-grid
|
|
4095
|
+
* column defs (the legacy {@link DataTableComponent}). A page that renders the
|
|
4096
|
+
* new {@link ListTableComponent} overrides this to return the `ListColumn` set
|
|
4097
|
+
* instead, leaving every other page untouched.
|
|
4098
|
+
*/
|
|
4099
|
+
loadTableColumns() {
|
|
4100
|
+
return this.svc.initTableColumns();
|
|
4101
|
+
}
|
|
3871
4102
|
gridReady(event) {
|
|
3872
4103
|
this.gridObj = event;
|
|
3873
4104
|
}
|
|
4105
|
+
/** Ready hook for {@link ListTableComponent}; keeps the instance for extension use. */
|
|
4106
|
+
tableReady(event) {
|
|
4107
|
+
this.tableObj = event?.component;
|
|
4108
|
+
}
|
|
3874
4109
|
refreshCells() {
|
|
3875
4110
|
defer(() => {
|
|
3876
4111
|
var params = {
|
|
@@ -6292,6 +6527,320 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
6292
6527
|
args: [ZITI_DATA_SERVICE]
|
|
6293
6528
|
}] }, { type: GrowlerService }] });
|
|
6294
6529
|
|
|
6530
|
+
/**
|
|
6531
|
+
* Name cell for {@link ListTableComponent}: a link to the entity's detail route,
|
|
6532
|
+
* with optional identity/router status circles and a prefix icon. Inputs come from
|
|
6533
|
+
* the column's `cellInputs(ctx)`: `{ row, cellValue, cellConfig }`, where
|
|
6534
|
+
* `cellConfig` carries `pathRoot`, `itemProp?`, `showIdentityIcons?`,
|
|
6535
|
+
* `showRouterIcons?`, `getNamePrefix?`, `cellNamePreCheck?`.
|
|
6536
|
+
*/
|
|
6537
|
+
class NameCellComponent {
|
|
6538
|
+
set row(v) {
|
|
6539
|
+
this.item = v;
|
|
6540
|
+
}
|
|
6541
|
+
set cellValue(v) {
|
|
6542
|
+
this.value = v;
|
|
6543
|
+
}
|
|
6544
|
+
set cellConfig(cfg) {
|
|
6545
|
+
this.cellParams = cfg || {};
|
|
6546
|
+
}
|
|
6547
|
+
constructor(router) {
|
|
6548
|
+
this.router = router;
|
|
6549
|
+
this.cellParams = {};
|
|
6550
|
+
}
|
|
6551
|
+
get namePrefix() {
|
|
6552
|
+
const fn = this.cellParams?.getNamePrefix;
|
|
6553
|
+
if (typeof fn !== 'function') {
|
|
6554
|
+
return null;
|
|
6555
|
+
}
|
|
6556
|
+
const result = fn(this.item);
|
|
6557
|
+
if (!result?.show) {
|
|
6558
|
+
return null;
|
|
6559
|
+
}
|
|
6560
|
+
return result;
|
|
6561
|
+
}
|
|
6562
|
+
linkClicked(event) {
|
|
6563
|
+
event.stopPropagation();
|
|
6564
|
+
event.preventDefault();
|
|
6565
|
+
if (isFunction(this.cellParams?.cellNamePreCheck)) {
|
|
6566
|
+
this.cellParams?.cellNamePreCheck(this.item).then((result) => {
|
|
6567
|
+
if (!result?.confirmed) {
|
|
6568
|
+
return;
|
|
6569
|
+
}
|
|
6570
|
+
this.navigate();
|
|
6571
|
+
});
|
|
6572
|
+
return;
|
|
6573
|
+
}
|
|
6574
|
+
this.navigate();
|
|
6575
|
+
}
|
|
6576
|
+
navigate() {
|
|
6577
|
+
this.router.navigateByUrl(`${this.cellParams.pathRoot}/${get(this.item, this.cellParams.itemProp, this.item.id)}`);
|
|
6578
|
+
}
|
|
6579
|
+
get cellText() {
|
|
6580
|
+
let val = this.value;
|
|
6581
|
+
if (isEmpty(val)) {
|
|
6582
|
+
val = this.item?.name;
|
|
6583
|
+
}
|
|
6584
|
+
return val;
|
|
6585
|
+
}
|
|
6586
|
+
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 }); }
|
|
6587
|
+
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(--highlighted);font-size:1rem}.circle.online{background-color:var(--green)}.circle.unknown{background-color:var(--highlighted)}\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"] }] }); }
|
|
6588
|
+
}
|
|
6589
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: NameCellComponent, decorators: [{
|
|
6590
|
+
type: Component,
|
|
6591
|
+
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(--highlighted);font-size:1rem}.circle.online{background-color:var(--green)}.circle.unknown{background-color:var(--highlighted)}\n"] }]
|
|
6592
|
+
}], ctorParameters: () => [{ type: i4.Router }], propDecorators: { row: [{
|
|
6593
|
+
type: Input
|
|
6594
|
+
}], cellValue: [{
|
|
6595
|
+
type: Input
|
|
6596
|
+
}], cellConfig: [{
|
|
6597
|
+
type: Input
|
|
6598
|
+
}] } });
|
|
6599
|
+
|
|
6600
|
+
/*
|
|
6601
|
+
Copyright NetFoundry Inc.
|
|
6602
|
+
|
|
6603
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6604
|
+
you may not use this file except in compliance with the License.
|
|
6605
|
+
You may obtain a copy of the License at
|
|
6606
|
+
|
|
6607
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
6608
|
+
|
|
6609
|
+
Unless required by applicable law or agreed to in writing, software
|
|
6610
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
6611
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
6612
|
+
See the License for the specific language governing permissions and
|
|
6613
|
+
limitations under the License.
|
|
6614
|
+
*/
|
|
6615
|
+
/**
|
|
6616
|
+
* Modern hover card for the identities O/S cell — shows the environment info
|
|
6617
|
+
* (OS, version, release, arch) in a clean key/value layout. Rendered by
|
|
6618
|
+
* ListTableComponent's hover-tooltip mechanism (column `tooltip`).
|
|
6619
|
+
*/
|
|
6620
|
+
class OsInfoTooltipComponent {
|
|
6621
|
+
get envInfo() {
|
|
6622
|
+
return this.row?.envInfo || this.row?.versionInfo || {};
|
|
6623
|
+
}
|
|
6624
|
+
get osClass() {
|
|
6625
|
+
const os = `${this.envInfo?.os || ''}`.toLowerCase();
|
|
6626
|
+
const ver = `${this.envInfo?.osVersion || ''}`.toLowerCase();
|
|
6627
|
+
if (ver.includes('windows') || os.includes('mingw') || os.includes('windows')) {
|
|
6628
|
+
return 'windows';
|
|
6629
|
+
}
|
|
6630
|
+
if (os.includes('darwin')) {
|
|
6631
|
+
return 'apple';
|
|
6632
|
+
}
|
|
6633
|
+
if (os.includes('linux')) {
|
|
6634
|
+
return 'linux';
|
|
6635
|
+
}
|
|
6636
|
+
if (os.includes('android')) {
|
|
6637
|
+
return 'android';
|
|
6638
|
+
}
|
|
6639
|
+
return 'other';
|
|
6640
|
+
}
|
|
6641
|
+
get osTitle() {
|
|
6642
|
+
switch (this.osClass) {
|
|
6643
|
+
case 'apple': return 'macOS';
|
|
6644
|
+
case 'windows': return 'Windows';
|
|
6645
|
+
case 'linux': return 'Linux';
|
|
6646
|
+
case 'android': return 'Android';
|
|
6647
|
+
default: return this.envInfo?.os || 'Unknown OS';
|
|
6648
|
+
}
|
|
6649
|
+
}
|
|
6650
|
+
/** Whether there is any environment info worth showing. */
|
|
6651
|
+
get hasInfo() {
|
|
6652
|
+
const e = this.envInfo;
|
|
6653
|
+
return !!(e && (e.os || e.osVersion || e.osRelease || e.arch));
|
|
6654
|
+
}
|
|
6655
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: OsInfoTooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6656
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: OsInfoTooltipComponent, isStandalone: false, selector: "lib-os-info-tooltip", inputs: { row: "row" }, ngImport: i0, template: "<div class=\"os-tip\">\n <div class=\"os-tip-head\">\n <span class=\"os-tip-icon {{ osClass }}\"></span>\n <span class=\"os-tip-title\">{{ osTitle }}</span>\n </div>\n @if (hasInfo) {\n <div class=\"os-tip-body\">\n @if (envInfo?.osVersion) {\n <div class=\"os-tip-row\"><span class=\"os-tip-key\">Version</span><span class=\"os-tip-val\">{{ envInfo.osVersion }}</span></div>\n }\n @if (envInfo?.osRelease) {\n <div class=\"os-tip-row\"><span class=\"os-tip-key\">Release</span><span class=\"os-tip-val\">{{ envInfo.osRelease }}</span></div>\n }\n @if (envInfo?.arch) {\n <div class=\"os-tip-row\"><span class=\"os-tip-key\">Arch</span><span class=\"os-tip-val\">{{ envInfo.arch }}</span></div>\n }\n </div>\n } @else {\n <div class=\"os-tip-empty\">No environment info reported</div>\n }\n</div>\n", styles: [":host{display:block}.os-tip{min-width:11rem;max-width:16rem;padding:.625rem .75rem;background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);box-shadow:var(--shadowLarge);font-family:var(--lt-font)}.os-tip-head{display:flex;align-items:center;gap:.5rem;padding-bottom:.5rem;margin-bottom:.5rem;border-bottom:1px solid var(--lt-border)}.os-tip-icon{flex:0 0 auto;width:1.25rem;height:1.25rem;background-size:contain;background-repeat:no-repeat;background-position:center}.os-tip-icon.apple{background-image:url(/assets/images/apple.png)}.os-tip-icon.windows{background-image:url(/assets/images/windows.png)}.os-tip-icon.linux{background-image:url(/assets/images/linux.png)}.os-tip-icon.android{background-image:url(/assets/images/android.png)}.os-tip-icon.other{background-image:url(/assets/images/other.png)}.os-tip-title{font-size:.875rem;font-weight:700;color:var(--lt-cell-text)}.os-tip-body{display:flex;flex-direction:column;gap:.3125rem}.os-tip-row{display:flex;align-items:baseline;justify-content:space-between;gap:.75rem;font-size:.75rem}.os-tip-key{flex:0 0 auto;color:var(--groupText);font-size:.75rem}.os-tip-val{flex:1 1 auto;min-width:0;text-align:right;font-weight:600;color:var(--lt-cell-text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.os-tip-empty{font-size:.75rem;font-style:italic;color:var(--groupText)}\n"] }); }
|
|
6657
|
+
}
|
|
6658
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: OsInfoTooltipComponent, decorators: [{
|
|
6659
|
+
type: Component,
|
|
6660
|
+
args: [{ selector: 'lib-os-info-tooltip', standalone: false, template: "<div class=\"os-tip\">\n <div class=\"os-tip-head\">\n <span class=\"os-tip-icon {{ osClass }}\"></span>\n <span class=\"os-tip-title\">{{ osTitle }}</span>\n </div>\n @if (hasInfo) {\n <div class=\"os-tip-body\">\n @if (envInfo?.osVersion) {\n <div class=\"os-tip-row\"><span class=\"os-tip-key\">Version</span><span class=\"os-tip-val\">{{ envInfo.osVersion }}</span></div>\n }\n @if (envInfo?.osRelease) {\n <div class=\"os-tip-row\"><span class=\"os-tip-key\">Release</span><span class=\"os-tip-val\">{{ envInfo.osRelease }}</span></div>\n }\n @if (envInfo?.arch) {\n <div class=\"os-tip-row\"><span class=\"os-tip-key\">Arch</span><span class=\"os-tip-val\">{{ envInfo.arch }}</span></div>\n }\n </div>\n } @else {\n <div class=\"os-tip-empty\">No environment info reported</div>\n }\n</div>\n", styles: [":host{display:block}.os-tip{min-width:11rem;max-width:16rem;padding:.625rem .75rem;background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);box-shadow:var(--shadowLarge);font-family:var(--lt-font)}.os-tip-head{display:flex;align-items:center;gap:.5rem;padding-bottom:.5rem;margin-bottom:.5rem;border-bottom:1px solid var(--lt-border)}.os-tip-icon{flex:0 0 auto;width:1.25rem;height:1.25rem;background-size:contain;background-repeat:no-repeat;background-position:center}.os-tip-icon.apple{background-image:url(/assets/images/apple.png)}.os-tip-icon.windows{background-image:url(/assets/images/windows.png)}.os-tip-icon.linux{background-image:url(/assets/images/linux.png)}.os-tip-icon.android{background-image:url(/assets/images/android.png)}.os-tip-icon.other{background-image:url(/assets/images/other.png)}.os-tip-title{font-size:.875rem;font-weight:700;color:var(--lt-cell-text)}.os-tip-body{display:flex;flex-direction:column;gap:.3125rem}.os-tip-row{display:flex;align-items:baseline;justify-content:space-between;gap:.75rem;font-size:.75rem}.os-tip-key{flex:0 0 auto;color:var(--groupText);font-size:.75rem}.os-tip-val{flex:1 1 auto;min-width:0;text-align:right;font-weight:600;color:var(--lt-cell-text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.os-tip-empty{font-size:.75rem;font-style:italic;color:var(--groupText)}\n"] }]
|
|
6661
|
+
}], propDecorators: { row: [{
|
|
6662
|
+
type: Input
|
|
6663
|
+
}] } });
|
|
6664
|
+
|
|
6665
|
+
/*
|
|
6666
|
+
Copyright NetFoundry Inc.
|
|
6667
|
+
|
|
6668
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6669
|
+
you may not use this file except in compliance with the License.
|
|
6670
|
+
You may obtain a copy of the License at
|
|
6671
|
+
|
|
6672
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
6673
|
+
|
|
6674
|
+
Unless required by applicable law or agreed to in writing, software
|
|
6675
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
6676
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
6677
|
+
See the License for the specific language governing permissions and
|
|
6678
|
+
limitations under the License.
|
|
6679
|
+
*/
|
|
6680
|
+
/**
|
|
6681
|
+
* Hover card for the identities SDK cell — shows the reported SDK details
|
|
6682
|
+
* (app id/version, version, type, branch, revision), the same fields the legacy
|
|
6683
|
+
* ag-grid SDK tooltip surfaced. Rendered by ListTableComponent's hover-tooltip
|
|
6684
|
+
* mechanism (column `tooltip`).
|
|
6685
|
+
*/
|
|
6686
|
+
class SdkInfoTooltipComponent {
|
|
6687
|
+
get sdkInfo() {
|
|
6688
|
+
return this.row?.sdkInfo || {};
|
|
6689
|
+
}
|
|
6690
|
+
get title() {
|
|
6691
|
+
const s = this.sdkInfo;
|
|
6692
|
+
return s?.appId || s?.type || 'SDK';
|
|
6693
|
+
}
|
|
6694
|
+
get hasInfo() {
|
|
6695
|
+
const s = this.sdkInfo;
|
|
6696
|
+
return !!(s && (s.appId || s.appVersion || s.version || s.type || s.branch || s.revision));
|
|
6697
|
+
}
|
|
6698
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: SdkInfoTooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6699
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: SdkInfoTooltipComponent, isStandalone: false, selector: "lib-sdk-info-tooltip", inputs: { row: "row" }, ngImport: i0, template: "<div class=\"sdk-tip\">\n <div class=\"sdk-tip-head\">\n <span class=\"sdk-tip-title\">{{ title }}</span>\n </div>\n @if (hasInfo) {\n <div class=\"sdk-tip-body\">\n @if (sdkInfo?.appId) {\n <div class=\"sdk-tip-row\"><span class=\"sdk-tip-key\">App ID</span><span class=\"sdk-tip-val\">{{ sdkInfo.appId }}</span></div>\n }\n @if (sdkInfo?.appVersion) {\n <div class=\"sdk-tip-row\"><span class=\"sdk-tip-key\">App Version</span><span class=\"sdk-tip-val\">{{ sdkInfo.appVersion }}</span></div>\n }\n @if (sdkInfo?.version) {\n <div class=\"sdk-tip-row\"><span class=\"sdk-tip-key\">Version</span><span class=\"sdk-tip-val\">{{ sdkInfo.version }}</span></div>\n }\n @if (sdkInfo?.type) {\n <div class=\"sdk-tip-row\"><span class=\"sdk-tip-key\">Type</span><span class=\"sdk-tip-val\">{{ sdkInfo.type }}</span></div>\n }\n @if (sdkInfo?.branch) {\n <div class=\"sdk-tip-row\"><span class=\"sdk-tip-key\">Branch</span><span class=\"sdk-tip-val\">{{ sdkInfo.branch }}</span></div>\n }\n @if (sdkInfo?.revision) {\n <div class=\"sdk-tip-row\"><span class=\"sdk-tip-key\">Revision</span><span class=\"sdk-tip-val\">{{ sdkInfo.revision }}</span></div>\n }\n </div>\n } @else {\n <div class=\"sdk-tip-empty\">No SDK info reported</div>\n }\n</div>\n", styles: [":host{display:block}.sdk-tip{min-width:11rem;max-width:18rem;padding:.625rem .75rem;background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);box-shadow:var(--shadowLarge);font-family:var(--lt-font)}.sdk-tip-head{display:flex;align-items:center;gap:.5rem;padding-bottom:.5rem;margin-bottom:.5rem;border-bottom:1px solid var(--lt-border)}.sdk-tip-title{font-size:.875rem;font-weight:700;color:var(--lt-cell-text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sdk-tip-body{display:flex;flex-direction:column;gap:.3125rem}.sdk-tip-row{display:flex;align-items:baseline;justify-content:space-between;gap:.75rem;font-size:.75rem}.sdk-tip-key{flex:0 0 auto;color:var(--groupText);font-size:.75rem}.sdk-tip-val{flex:1 1 auto;min-width:0;text-align:right;font-weight:600;color:var(--lt-cell-text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sdk-tip-empty{font-size:.75rem;font-style:italic;color:var(--groupText)}\n"] }); }
|
|
6700
|
+
}
|
|
6701
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: SdkInfoTooltipComponent, decorators: [{
|
|
6702
|
+
type: Component,
|
|
6703
|
+
args: [{ selector: 'lib-sdk-info-tooltip', standalone: false, template: "<div class=\"sdk-tip\">\n <div class=\"sdk-tip-head\">\n <span class=\"sdk-tip-title\">{{ title }}</span>\n </div>\n @if (hasInfo) {\n <div class=\"sdk-tip-body\">\n @if (sdkInfo?.appId) {\n <div class=\"sdk-tip-row\"><span class=\"sdk-tip-key\">App ID</span><span class=\"sdk-tip-val\">{{ sdkInfo.appId }}</span></div>\n }\n @if (sdkInfo?.appVersion) {\n <div class=\"sdk-tip-row\"><span class=\"sdk-tip-key\">App Version</span><span class=\"sdk-tip-val\">{{ sdkInfo.appVersion }}</span></div>\n }\n @if (sdkInfo?.version) {\n <div class=\"sdk-tip-row\"><span class=\"sdk-tip-key\">Version</span><span class=\"sdk-tip-val\">{{ sdkInfo.version }}</span></div>\n }\n @if (sdkInfo?.type) {\n <div class=\"sdk-tip-row\"><span class=\"sdk-tip-key\">Type</span><span class=\"sdk-tip-val\">{{ sdkInfo.type }}</span></div>\n }\n @if (sdkInfo?.branch) {\n <div class=\"sdk-tip-row\"><span class=\"sdk-tip-key\">Branch</span><span class=\"sdk-tip-val\">{{ sdkInfo.branch }}</span></div>\n }\n @if (sdkInfo?.revision) {\n <div class=\"sdk-tip-row\"><span class=\"sdk-tip-key\">Revision</span><span class=\"sdk-tip-val\">{{ sdkInfo.revision }}</span></div>\n }\n </div>\n } @else {\n <div class=\"sdk-tip-empty\">No SDK info reported</div>\n }\n</div>\n", styles: [":host{display:block}.sdk-tip{min-width:11rem;max-width:18rem;padding:.625rem .75rem;background:var(--lt-control-bg);border:1px solid var(--lt-border);border-radius:var(--lt-radius);box-shadow:var(--shadowLarge);font-family:var(--lt-font)}.sdk-tip-head{display:flex;align-items:center;gap:.5rem;padding-bottom:.5rem;margin-bottom:.5rem;border-bottom:1px solid var(--lt-border)}.sdk-tip-title{font-size:.875rem;font-weight:700;color:var(--lt-cell-text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sdk-tip-body{display:flex;flex-direction:column;gap:.3125rem}.sdk-tip-row{display:flex;align-items:baseline;justify-content:space-between;gap:.75rem;font-size:.75rem}.sdk-tip-key{flex:0 0 auto;color:var(--groupText);font-size:.75rem}.sdk-tip-val{flex:1 1 auto;min-width:0;text-align:right;font-weight:600;color:var(--lt-cell-text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sdk-tip-empty{font-size:.75rem;font-style:italic;color:var(--groupText)}\n"] }]
|
|
6704
|
+
}], propDecorators: { row: [{
|
|
6705
|
+
type: Input
|
|
6706
|
+
}] } });
|
|
6707
|
+
|
|
6708
|
+
/*
|
|
6709
|
+
Copyright NetFoundry Inc.
|
|
6710
|
+
|
|
6711
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6712
|
+
you may not use this file except in compliance with the License.
|
|
6713
|
+
You may obtain a copy of the License at
|
|
6714
|
+
|
|
6715
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
6716
|
+
|
|
6717
|
+
Unless required by applicable law or agreed to in writing, software
|
|
6718
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
6719
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
6720
|
+
See the License for the specific language governing permissions and
|
|
6721
|
+
limitations under the License.
|
|
6722
|
+
*/
|
|
6723
|
+
/**
|
|
6724
|
+
* Renders a truthy boolean as a green check + domain label (via `trueLabel`);
|
|
6725
|
+
* a false value renders nothing, so the column reads as a clean presence marker.
|
|
6726
|
+
*/
|
|
6727
|
+
class BooleanCellComponent {
|
|
6728
|
+
constructor() {
|
|
6729
|
+
this.trueLabel = 'Yes';
|
|
6730
|
+
}
|
|
6731
|
+
get isTrue() {
|
|
6732
|
+
return this.value === true || this.value === 'true';
|
|
6733
|
+
}
|
|
6734
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: BooleanCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6735
|
+
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:.3125rem;padding:.1875rem .5rem .1875rem .4375rem;font-family:var(--lt-font);font-size:.75rem;font-weight:600;line-height:1.2;color:#15803d;background:color-mix(in srgb,#16a34a 12%,transparent);border-radius:999px}.bool-check{flex:0 0 auto;display:block;color:#16a34a}\n"] }); }
|
|
6736
|
+
}
|
|
6737
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: BooleanCellComponent, decorators: [{
|
|
6738
|
+
type: Component,
|
|
6739
|
+
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:.3125rem;padding:.1875rem .5rem .1875rem .4375rem;font-family:var(--lt-font);font-size:.75rem;font-weight:600;line-height:1.2;color:#15803d;background:color-mix(in srgb,#16a34a 12%,transparent);border-radius:999px}.bool-check{flex:0 0 auto;display:block;color:#16a34a}\n"] }]
|
|
6740
|
+
}], propDecorators: { value: [{
|
|
6741
|
+
type: Input
|
|
6742
|
+
}], trueLabel: [{
|
|
6743
|
+
type: Input
|
|
6744
|
+
}] } });
|
|
6745
|
+
|
|
6746
|
+
/*
|
|
6747
|
+
Copyright NetFoundry Inc.
|
|
6748
|
+
|
|
6749
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6750
|
+
you may not use this file except in compliance with the License.
|
|
6751
|
+
You may obtain a copy of the License at
|
|
6752
|
+
|
|
6753
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
6754
|
+
|
|
6755
|
+
Unless required by applicable law or agreed to in writing, software
|
|
6756
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
6757
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
6758
|
+
See the License for the specific language governing permissions and
|
|
6759
|
+
limitations under the License.
|
|
6760
|
+
*/
|
|
6761
|
+
/**
|
|
6762
|
+
* Enrollment-token cell for the identities list. Shows a status chip (Available /
|
|
6763
|
+
* Expired / —) that doubles as a dropdown of enrollment actions (Download JWT, Show
|
|
6764
|
+
* QR, Re-issue). Actions are emitted via the cell context's `emitAction`, so they run
|
|
6765
|
+
* through the same page handlers as the row ⋯ menu.
|
|
6766
|
+
*/
|
|
6767
|
+
class TokenCellComponent {
|
|
6768
|
+
constructor() {
|
|
6769
|
+
this.open = false;
|
|
6770
|
+
this.menuLeft = 0;
|
|
6771
|
+
this.menuTop = 0;
|
|
6772
|
+
}
|
|
6773
|
+
get status() {
|
|
6774
|
+
if (!this.hasEnrolmentToken) {
|
|
6775
|
+
return 'none';
|
|
6776
|
+
}
|
|
6777
|
+
return this.tokenExpired ? 'expired' : 'available';
|
|
6778
|
+
}
|
|
6779
|
+
get statusLabel() {
|
|
6780
|
+
return this.status === 'expired' ? 'Expired' : 'Available';
|
|
6781
|
+
}
|
|
6782
|
+
get actions() {
|
|
6783
|
+
if (this.status === 'available') {
|
|
6784
|
+
return [
|
|
6785
|
+
{ label: 'Download JWT', action: 'download-enrollment', icon: 'icon-download-jwt' },
|
|
6786
|
+
{ label: 'Show QR code', action: 'qr-code', icon: 'icon-qr' },
|
|
6787
|
+
{ label: 'Re-issue enrollment', action: 'reissue-enrollment', icon: 'icon-refresh' },
|
|
6788
|
+
];
|
|
6789
|
+
}
|
|
6790
|
+
if (this.status === 'expired') {
|
|
6791
|
+
return [{ label: 'Re-issue enrollment', action: 'reissue-enrollment', icon: 'icon-refresh' }];
|
|
6792
|
+
}
|
|
6793
|
+
return [];
|
|
6794
|
+
}
|
|
6795
|
+
toggleMenu(event) {
|
|
6796
|
+
event.stopPropagation();
|
|
6797
|
+
if (this.open) {
|
|
6798
|
+
this.open = false;
|
|
6799
|
+
return;
|
|
6800
|
+
}
|
|
6801
|
+
const rect = this.trigger?.nativeElement.getBoundingClientRect();
|
|
6802
|
+
if (rect) {
|
|
6803
|
+
this.menuLeft = rect.left;
|
|
6804
|
+
this.menuTop = rect.bottom + 4;
|
|
6805
|
+
}
|
|
6806
|
+
this.open = true;
|
|
6807
|
+
}
|
|
6808
|
+
closeMenu() {
|
|
6809
|
+
this.open = false;
|
|
6810
|
+
}
|
|
6811
|
+
runAction(action, event) {
|
|
6812
|
+
event.stopPropagation();
|
|
6813
|
+
this.open = false;
|
|
6814
|
+
this.emitAction?.(action, this.row);
|
|
6815
|
+
}
|
|
6816
|
+
get hasEnrolmentToken() {
|
|
6817
|
+
const token = this.row?.enrollment?.ott?.jwt ||
|
|
6818
|
+
this.row?.enrollment?.ottca?.jwt ||
|
|
6819
|
+
this.row?.enrollment?.updb?.jwt;
|
|
6820
|
+
return !!(this.row?.enrollmentToken || token);
|
|
6821
|
+
}
|
|
6822
|
+
get tokenExpired() {
|
|
6823
|
+
const expiration = this.row?.enrollmentExpiresAt ||
|
|
6824
|
+
this.row?.enrollment?.ott?.expiresAt ||
|
|
6825
|
+
this.row?.enrollment?.ottca?.expiresAt ||
|
|
6826
|
+
this.row?.enrollment?.updb?.expiresAt;
|
|
6827
|
+
return expiration ? moment$1(expiration).isBefore() : false;
|
|
6828
|
+
}
|
|
6829
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: TokenCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6830
|
+
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=\"M0 0h10L5 6z\"/>\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 {\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:.3125rem;height:1.5rem;padding:0 .5rem;font-family:var(--lt-font);font-size:.75rem;font-weight:600;border:none;border-radius:.75rem;cursor:pointer;white-space:nowrap;transition:filter .15s}.token-chip .token-caret{display:block;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) 12%,var(--lt-control-bg))}.token-chip.expired{color:color-mix(in srgb,var(--highlighted) 62%,#000);background:color-mix(in srgb,var(--highlighted) 26%,var(--lt-control-bg))}.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: i3$1.ClickOutsideDirective, selector: "[clickOutside]", inputs: ["clickOutsideEnabled", "attachOutsideOnClick", "delayClickOutsideInit", "emitOnBlur", "exclude", "excludeBeforeClick", "clickOutsideEvents"], outputs: ["clickOutside"] }] }); }
|
|
6831
|
+
}
|
|
6832
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: TokenCellComponent, decorators: [{
|
|
6833
|
+
type: Component,
|
|
6834
|
+
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=\"M0 0h10L5 6z\"/>\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 {\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:.3125rem;height:1.5rem;padding:0 .5rem;font-family:var(--lt-font);font-size:.75rem;font-weight:600;border:none;border-radius:.75rem;cursor:pointer;white-space:nowrap;transition:filter .15s}.token-chip .token-caret{display:block;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) 12%,var(--lt-control-bg))}.token-chip.expired{color:color-mix(in srgb,var(--highlighted) 62%,#000);background:color-mix(in srgb,var(--highlighted) 26%,var(--lt-control-bg))}.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"] }]
|
|
6835
|
+
}], propDecorators: { row: [{
|
|
6836
|
+
type: Input
|
|
6837
|
+
}], emitAction: [{
|
|
6838
|
+
type: Input
|
|
6839
|
+
}], trigger: [{
|
|
6840
|
+
type: ViewChild,
|
|
6841
|
+
args: ['trigger']
|
|
6842
|
+
}] } });
|
|
6843
|
+
|
|
6295
6844
|
/*
|
|
6296
6845
|
Copyright NetFoundry Inc.
|
|
6297
6846
|
|
|
@@ -6343,19 +6892,21 @@ class IdentitiesPageService extends ListPageServiceClass {
|
|
|
6343
6892
|
os: '',
|
|
6344
6893
|
createdAt: '',
|
|
6345
6894
|
};
|
|
6895
|
+
// `icon` (SVG markup) is rendered before the label in the new list-table's row kebab
|
|
6896
|
+
// (3-dot) menu. The legacy ag-grid menu ignores it.
|
|
6346
6897
|
this.menuItems = [
|
|
6347
|
-
{ name: 'Edit', action: 'update' },
|
|
6348
|
-
{ name: 'Download JWT', action: 'download-enrollment' },
|
|
6349
|
-
{ name: 'View QR', action: 'qr-code' },
|
|
6350
|
-
{ name: 'Visualizer', action: 'identity-service-path' },
|
|
6351
|
-
{ name: 'Reset Enrollment', action: 'reset-enrollment' },
|
|
6352
|
-
{ name: 'Reissue Enrollment', action: 'reissue-enrollment' },
|
|
6353
|
-
{ name: 'Reset MFA', action: 'reset-mfa' },
|
|
6354
|
-
{ name: 'Override', action: 'override' },
|
|
6355
|
-
{ name: 'Delete', action: 'delete' },
|
|
6898
|
+
{ 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>' },
|
|
6899
|
+
{ name: 'Download JWT', action: 'download-enrollment', 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>' },
|
|
6900
|
+
{ name: 'View QR', action: 'qr-code', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><g fill="none" stroke="currentColor" stroke-width="1.3"><rect x="2.5" y="2.5" width="4" height="4" rx="0.5"/><rect x="9.5" y="2.5" width="4" height="4" rx="0.5"/><rect x="2.5" y="9.5" width="4" height="4" rx="0.5"/></g><rect x="10" y="10" width="3.5" height="3.5" fill="currentColor"/></svg>' },
|
|
6901
|
+
{ name: 'Visualizer', action: 'identity-service-path', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" d="M5.4 7.3 10.6 4.6M5.4 8.7l5.2 2.7"/><circle cx="4" cy="8" r="1.8" fill="currentColor"/><circle cx="12" cy="4" r="1.8" fill="currentColor"/><circle cx="12" cy="12" r="1.8" fill="currentColor"/></svg>' },
|
|
6902
|
+
{ name: 'Reset Enrollment', action: 'reset-enrollment', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" d="M3.2 8a4.8 4.8 0 1 0 1.3-3.3"/><path fill="currentColor" d="M2.8 2.8l-.3 2.9 2.8-.4z"/></svg>' },
|
|
6903
|
+
{ name: 'Reissue Enrollment', action: 'reissue-enrollment', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" d="M12.8 8a4.8 4.8 0 1 1-1.3-3.3"/><path fill="currentColor" d="M13.2 2.8l.3 2.9-2.8-.4z"/></svg>' },
|
|
6904
|
+
{ name: 'Reset MFA', action: 'reset-mfa', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" stroke-linejoin="round" d="M8 2.3 12.8 4v3.8c0 3-2.1 4.9-4.8 5.9-2.7-1-4.8-2.9-4.8-5.9V4z"/></svg>' },
|
|
6905
|
+
{ name: 'Override', action: 'override', icon: '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" d="M2.8 5h10.4M2.8 11h10.4"/><circle cx="6" cy="5" r="1.7" fill="currentColor"/><circle cx="10" cy="11" r="1.7" fill="currentColor"/></svg>' },
|
|
6906
|
+
{ 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>' },
|
|
6356
6907
|
];
|
|
6357
6908
|
this.tableHeaderActions = [
|
|
6358
|
-
{ name: 'Download All', action: 'download-all' },
|
|
6909
|
+
{ 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>' },
|
|
6359
6910
|
];
|
|
6360
6911
|
this.resourceType = 'identities';
|
|
6361
6912
|
this.validate = (formData) => {
|
|
@@ -6611,15 +7162,280 @@ class IdentitiesPageService extends ListPageServiceClass {
|
|
|
6611
7162
|
}
|
|
6612
7163
|
return tableColumns;
|
|
6613
7164
|
}
|
|
7165
|
+
/**
|
|
7166
|
+
* Column set for the new `lib-list-table` (the "beta" Identities page). Mirrors
|
|
7167
|
+
* {@link initTableColumns} but emits the declarative `ListColumn` shape instead of
|
|
7168
|
+
* ag-grid `ColDef`s: component cells via `cell`/`cellInputs`, legacy string
|
|
7169
|
+
* renderers via `cellHtml`, and header filters declared with `filterType`.
|
|
7170
|
+
* Loaded by {@link IdentitiesPageComponent} when the Beta Features toggle is on;
|
|
7171
|
+
* the legacy {@link initTableColumns} above is left untouched for the ag-grid table.
|
|
7172
|
+
*/
|
|
7173
|
+
initListTableColumns() {
|
|
7174
|
+
this.initMenuActions();
|
|
7175
|
+
const identityRolesHeaderComponentParams = {
|
|
7176
|
+
filterType: 'ATTRIBUTE',
|
|
7177
|
+
enableSorting: true,
|
|
7178
|
+
appendAttributeHash: false,
|
|
7179
|
+
getRoleAttributes: () => this.identityRoleAttributes,
|
|
7180
|
+
getNamedAttributes: () => [],
|
|
7181
|
+
getSelectedRoleAttributes: () => this.selectedIdentityRoleAttributes,
|
|
7182
|
+
getSelectedNamedAttributes: () => [],
|
|
7183
|
+
setSelectedRoleAttributes: (attributes) => {
|
|
7184
|
+
this.selectedIdentityRoleAttributes = attributes;
|
|
7185
|
+
},
|
|
7186
|
+
setSelectedNamedAttributes: (attributes) => {
|
|
7187
|
+
// no-op
|
|
7188
|
+
},
|
|
7189
|
+
getNamedAttributesMap: () => ({}),
|
|
7190
|
+
};
|
|
7191
|
+
const osRenderer = (row) => {
|
|
7192
|
+
const os = (row?.data?.envInfo?.os || '').toLowerCase();
|
|
7193
|
+
const ver = (row?.data?.envInfo?.osVersion || '').toLowerCase();
|
|
7194
|
+
let cls = 'other';
|
|
7195
|
+
if (ver.includes('windows') || os.includes('windows') || os.includes('mingw'))
|
|
7196
|
+
cls = 'windows';
|
|
7197
|
+
else if (os.includes('darwin'))
|
|
7198
|
+
cls = 'apple';
|
|
7199
|
+
else if (os.includes('linux'))
|
|
7200
|
+
cls = 'linux';
|
|
7201
|
+
else if (os.includes('android'))
|
|
7202
|
+
cls = 'android';
|
|
7203
|
+
return `<span class="os ${cls}"></span>`;
|
|
7204
|
+
};
|
|
7205
|
+
const sdkRenderer = (row) => {
|
|
7206
|
+
// detail moves to the hover popover (SdkInfoTooltipComponent); the cell
|
|
7207
|
+
// just shows the version, so drop the legacy balloon attributes
|
|
7208
|
+
const version = row?.data?.sdkInfo?.version || '-';
|
|
7209
|
+
return `<span class="oneline">${version}</span>`;
|
|
7210
|
+
};
|
|
7211
|
+
const isAdminHeaderComponentParams = {
|
|
7212
|
+
filterType: 'SELECT',
|
|
7213
|
+
enableSorting: true,
|
|
7214
|
+
filterOptions: [
|
|
7215
|
+
{ label: 'All', value: '' },
|
|
7216
|
+
{ label: 'Admins', value: true },
|
|
7217
|
+
{ label: 'Non-Admins', value: false },
|
|
7218
|
+
]
|
|
7219
|
+
};
|
|
7220
|
+
// Online when any of the connection signals is live (the status icon is drawn
|
|
7221
|
+
// via CSS ::before, since [innerHTML] strips inline <svg>).
|
|
7222
|
+
const isOnline = (v) => v === true || /online|connected|true/i.test(String(v ?? ''));
|
|
7223
|
+
const statusRenderer = (row) => {
|
|
7224
|
+
const d = row?.data || {};
|
|
7225
|
+
const online = isOnline(d.edgeRouterConnectionStatus) || isOnline(d.hasEdgeRouterConnection) || isOnline(d.hasApiSession);
|
|
7226
|
+
return `<span class="lt-status lt-status-${online ? 'online' : 'offline'}">${online ? 'Online' : 'Offline'}</span>`;
|
|
7227
|
+
};
|
|
7228
|
+
// Color-coded Type pill with an icon: Default = blue, Router = green. Icon drawn
|
|
7229
|
+
// via CSS (::before) since [innerHTML] strips inline <svg>.
|
|
7230
|
+
const typeBadgeRenderer = (row) => {
|
|
7231
|
+
const t = row?.data?.type?.name || row?.data?.type || '';
|
|
7232
|
+
const key = String(t).toLowerCase();
|
|
7233
|
+
const cls = key === 'router' ? 'lt-type-router'
|
|
7234
|
+
: key === 'default' ? 'lt-type-default'
|
|
7235
|
+
: 'lt-type-other';
|
|
7236
|
+
return `<span class="lt-type-badge ${cls}">${t}</span>`;
|
|
7237
|
+
};
|
|
7238
|
+
// Light skinned role chips (the legacy rolesRenderer paints
|
|
7239
|
+
// heavy dark overlap chips; this stays scoped to the beta page).
|
|
7240
|
+
const rolesChipRenderer = (row) => {
|
|
7241
|
+
const colId = row?.column?.colId;
|
|
7242
|
+
const attrs = row?.data?.[colId + 'Display'] || row?.data?.[colId] || [];
|
|
7243
|
+
if (!attrs?.length) {
|
|
7244
|
+
return '';
|
|
7245
|
+
}
|
|
7246
|
+
return attrs.map((attr) => {
|
|
7247
|
+
const raw = String(attr?.name ?? attr ?? '').trim();
|
|
7248
|
+
if (!raw) {
|
|
7249
|
+
return '';
|
|
7250
|
+
}
|
|
7251
|
+
// named attributes (@) use the secondary color; role attributes (#)
|
|
7252
|
+
// the primary color, matching the tag selector's distinction
|
|
7253
|
+
const isNamed = raw.charAt(0) === '@';
|
|
7254
|
+
const label = isNamed ? raw : (raw.charAt(0) === '#' ? raw : '#' + raw);
|
|
7255
|
+
const cls = isNamed ? 'lt-chip lt-chip-at' : 'lt-chip';
|
|
7256
|
+
return `<span class="${cls}">${label}</span>`;
|
|
7257
|
+
}).join('');
|
|
7258
|
+
};
|
|
7259
|
+
let tableColumns = [
|
|
7260
|
+
{
|
|
7261
|
+
key: 'name',
|
|
7262
|
+
field: 'name',
|
|
7263
|
+
label: 'Name',
|
|
7264
|
+
filterType: 'TEXTINPUT',
|
|
7265
|
+
cell: NameCellComponent,
|
|
7266
|
+
cellInputs: (ctx) => ({
|
|
7267
|
+
row: ctx.row,
|
|
7268
|
+
cellValue: ctx.value,
|
|
7269
|
+
// status now lives in its own Status column (skinned), so the
|
|
7270
|
+
// name cell no longer carries the connection dots
|
|
7271
|
+
cellConfig: { pathRoot: this.basePath, showIdentityIcons: false },
|
|
7272
|
+
}),
|
|
7273
|
+
onCellClick: (ctx) => {
|
|
7274
|
+
if (this.hasSelectedText()) {
|
|
7275
|
+
return;
|
|
7276
|
+
}
|
|
7277
|
+
this.openEditForm(ctx.row?.id);
|
|
7278
|
+
},
|
|
7279
|
+
resizable: true,
|
|
7280
|
+
cellClass: 'nf-cell-vert-align',
|
|
7281
|
+
sortable: true,
|
|
7282
|
+
onSort: this.sort.bind(this),
|
|
7283
|
+
sortDir: 'asc',
|
|
7284
|
+
width: 300,
|
|
7285
|
+
},
|
|
7286
|
+
{
|
|
7287
|
+
key: 'status',
|
|
7288
|
+
field: 'hasEdgeRouterConnection',
|
|
7289
|
+
label: 'Status',
|
|
7290
|
+
cellHtml: statusRenderer,
|
|
7291
|
+
resizable: true,
|
|
7292
|
+
cellClass: 'nf-cell-vert-align',
|
|
7293
|
+
width: 120,
|
|
7294
|
+
},
|
|
7295
|
+
{
|
|
7296
|
+
key: 'roleAttributes',
|
|
7297
|
+
field: 'roleAttributes',
|
|
7298
|
+
label: 'Roles',
|
|
7299
|
+
filterType: 'ATTRIBUTE',
|
|
7300
|
+
headerParams: identityRolesHeaderComponentParams,
|
|
7301
|
+
cellHtml: rolesChipRenderer,
|
|
7302
|
+
onCellClick: (ctx) => {
|
|
7303
|
+
if (this.hasSelectedText()) {
|
|
7304
|
+
return;
|
|
7305
|
+
}
|
|
7306
|
+
this.openEditForm(ctx.row?.id);
|
|
7307
|
+
},
|
|
7308
|
+
resizable: true,
|
|
7309
|
+
cellClass: 'nf-cell-vert-align',
|
|
7310
|
+
sortable: false,
|
|
7311
|
+
},
|
|
7312
|
+
{
|
|
7313
|
+
key: 'os',
|
|
7314
|
+
field: 'os',
|
|
7315
|
+
label: 'O/S',
|
|
7316
|
+
width: 100,
|
|
7317
|
+
cellHtml: osRenderer,
|
|
7318
|
+
tooltip: OsInfoTooltipComponent,
|
|
7319
|
+
tooltipInputs: (ctx) => ({ row: ctx.row }),
|
|
7320
|
+
// envInfo.os is a JSON blob field the controller cannot filter on
|
|
7321
|
+
// ("unknown symbol") - no O/S filter control.
|
|
7322
|
+
resizable: true,
|
|
7323
|
+
cellClass: 'nf-cell-vert-align lt-cell-center',
|
|
7324
|
+
},
|
|
7325
|
+
{
|
|
7326
|
+
key: 'sdk',
|
|
7327
|
+
field: 'sdk',
|
|
7328
|
+
label: 'SDK',
|
|
7329
|
+
cellHtml: sdkRenderer,
|
|
7330
|
+
tooltip: SdkInfoTooltipComponent,
|
|
7331
|
+
tooltipInputs: (ctx) => ({ row: ctx.row }),
|
|
7332
|
+
resizable: true,
|
|
7333
|
+
cellClass: 'nf-cell-vert-align',
|
|
7334
|
+
width: 125,
|
|
7335
|
+
},
|
|
7336
|
+
{
|
|
7337
|
+
key: 'type',
|
|
7338
|
+
field: 'type.name',
|
|
7339
|
+
label: 'Type',
|
|
7340
|
+
filterType: 'SELECT',
|
|
7341
|
+
filterField: 'type',
|
|
7342
|
+
filterPlaceholder: 'Any type',
|
|
7343
|
+
// Only Default + Router exist as identity types in Ziti 2.x (confirmed
|
|
7344
|
+
// via /edge/management/v1/identity-types); Service/Device/User are legacy
|
|
7345
|
+
// and always return 0.
|
|
7346
|
+
filterOptions: [
|
|
7347
|
+
{ label: 'Show All', value: '' },
|
|
7348
|
+
{ label: 'Default', value: 'Default', chipClass: 'lt-type-badge lt-type-default' },
|
|
7349
|
+
{ label: 'Router', value: 'Router', chipClass: 'lt-type-badge lt-type-router' },
|
|
7350
|
+
],
|
|
7351
|
+
cellHtml: typeBadgeRenderer,
|
|
7352
|
+
resizable: true,
|
|
7353
|
+
sortable: true,
|
|
7354
|
+
cellClass: 'nf-cell-vert-align',
|
|
7355
|
+
onSort: this.sort.bind(this),
|
|
7356
|
+
},
|
|
7357
|
+
{
|
|
7358
|
+
key: 'isAdmin',
|
|
7359
|
+
field: 'isAdmin',
|
|
7360
|
+
label: 'Is Admin',
|
|
7361
|
+
filterType: 'SELECT',
|
|
7362
|
+
filterOptions: isAdminHeaderComponentParams.filterOptions,
|
|
7363
|
+
cell: BooleanCellComponent,
|
|
7364
|
+
cellInputs: (ctx) => ({ value: ctx.value, trueLabel: 'Admin' }),
|
|
7365
|
+
resizable: true,
|
|
7366
|
+
sortable: true,
|
|
7367
|
+
onSort: this.sort.bind(this),
|
|
7368
|
+
cellClass: 'nf-cell-vert-align',
|
|
7369
|
+
width: 100,
|
|
7370
|
+
},
|
|
7371
|
+
{
|
|
7372
|
+
key: 'createdAt',
|
|
7373
|
+
field: 'createdAt',
|
|
7374
|
+
label: 'Created At',
|
|
7375
|
+
valueFormatter: this.createdAtFormatter,
|
|
7376
|
+
filterType: 'DATETIME',
|
|
7377
|
+
filterPlaceholder: 'Any time',
|
|
7378
|
+
resizable: true,
|
|
7379
|
+
sortable: true,
|
|
7380
|
+
onSort: this.sort.bind(this),
|
|
7381
|
+
cellClass: 'nf-cell-vert-align',
|
|
7382
|
+
},
|
|
7383
|
+
{
|
|
7384
|
+
key: 'token',
|
|
7385
|
+
field: 'token',
|
|
7386
|
+
label: 'Token',
|
|
7387
|
+
cell: TokenCellComponent,
|
|
7388
|
+
cellInputs: (ctx) => ({ row: ctx.row, emitAction: ctx.emitAction }),
|
|
7389
|
+
resizable: true,
|
|
7390
|
+
cellClass: 'nf-cell-vert-align',
|
|
7391
|
+
},
|
|
7392
|
+
{
|
|
7393
|
+
key: 'isMfaEnabled',
|
|
7394
|
+
field: 'isMfaEnabled',
|
|
7395
|
+
label: 'MFA',
|
|
7396
|
+
// isMfaEnabled is a computed field the controller cannot filter on
|
|
7397
|
+
// ("unknown symbol") - no MFA filter control.
|
|
7398
|
+
cell: BooleanCellComponent,
|
|
7399
|
+
cellInputs: (ctx) => ({ value: ctx.value, trueLabel: 'Enabled' }),
|
|
7400
|
+
resizable: true,
|
|
7401
|
+
cellClass: 'nf-cell-vert-align',
|
|
7402
|
+
width: 100,
|
|
7403
|
+
},
|
|
7404
|
+
{
|
|
7405
|
+
key: 'id',
|
|
7406
|
+
field: 'id',
|
|
7407
|
+
label: 'ID',
|
|
7408
|
+
filterType: 'TEXTINPUT',
|
|
7409
|
+
cellClass: 'nf-cell-vert-align',
|
|
7410
|
+
resizable: true,
|
|
7411
|
+
sortable: true,
|
|
7412
|
+
onSort: this.sort.bind(this),
|
|
7413
|
+
onCellClick: (ctx) => {
|
|
7414
|
+
if (this.hasSelectedText()) {
|
|
7415
|
+
return;
|
|
7416
|
+
}
|
|
7417
|
+
this.openEditForm(ctx.row?.id);
|
|
7418
|
+
},
|
|
7419
|
+
hidden: true,
|
|
7420
|
+
},
|
|
7421
|
+
];
|
|
7422
|
+
if (this.extService.processListTableColumns) {
|
|
7423
|
+
tableColumns = this.extService.processListTableColumns(tableColumns);
|
|
7424
|
+
}
|
|
7425
|
+
return tableColumns;
|
|
7426
|
+
}
|
|
6614
7427
|
getIdentityRoleAttributes() {
|
|
6615
7428
|
return this.zitiService.get('identity-role-attributes', {}, []).then((result) => {
|
|
6616
7429
|
this.identityRoleAttributes = result.data;
|
|
6617
7430
|
return result;
|
|
6618
7431
|
});
|
|
6619
7432
|
}
|
|
6620
|
-
getData(filters, sort, page) {
|
|
7433
|
+
getData(filters, sort, page, pageSize) {
|
|
6621
7434
|
// we can customize filters or sorting here before moving on...
|
|
6622
7435
|
this.paging.page = page || this.paging.page;
|
|
7436
|
+
if (pageSize) {
|
|
7437
|
+
this.paging.total = pageSize;
|
|
7438
|
+
}
|
|
6623
7439
|
return super.getTableData('identities', this.paging, filters, sort)
|
|
6624
7440
|
.then((results) => {
|
|
6625
7441
|
return this.processData(results);
|
|
@@ -9289,6 +10105,124 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
9289
10105
|
args: [SHAREDZ_EXTENSION]
|
|
9290
10106
|
}] }] });
|
|
9291
10107
|
|
|
10108
|
+
/*
|
|
10109
|
+
Copyright NetFoundry Inc.
|
|
10110
|
+
|
|
10111
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
10112
|
+
you may not use this file except in compliance with the License.
|
|
10113
|
+
You may obtain a copy of the License at
|
|
10114
|
+
|
|
10115
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
10116
|
+
|
|
10117
|
+
Unless required by applicable law or agreed to in writing, software
|
|
10118
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
10119
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
10120
|
+
See the License for the specific language governing permissions and
|
|
10121
|
+
limitations under the License.
|
|
10122
|
+
*/
|
|
10123
|
+
/**
|
|
10124
|
+
* Header for the new list-table pages: an icon tile + title + one-line subtitle
|
|
10125
|
+
* (with an optional info affordance) on the left, and a primary "Create ..." action
|
|
10126
|
+
* on the right, over an optional tab strip. Emits the same `add` / `delete` actions
|
|
10127
|
+
* as {@link ListPageHeaderComponent} so pages can swap headers without changing their
|
|
10128
|
+
* handlers. Project the page's icon into the tile with a `header-icon` attribute.
|
|
10129
|
+
*/
|
|
10130
|
+
class ListTableHeaderComponent {
|
|
10131
|
+
constructor() {
|
|
10132
|
+
this.title = '';
|
|
10133
|
+
this.subtitle = '';
|
|
10134
|
+
/** Label for the primary create button, e.g. "Create Identity". */
|
|
10135
|
+
this.createLabel = 'Create';
|
|
10136
|
+
/** Optional short helper text shown behind the (i) affordance next to the title. */
|
|
10137
|
+
this.infoText = '';
|
|
10138
|
+
this.tabs = [];
|
|
10139
|
+
this.showAdd = true;
|
|
10140
|
+
/** Hide the create control even when showAdd is true. */
|
|
10141
|
+
this.blockCreate = false;
|
|
10142
|
+
/** Hide the bulk-delete control shown when rows are selected. */
|
|
10143
|
+
this.blockDelete = false;
|
|
10144
|
+
/** When true (default) tabs navigate via routerLink and highlight by matching the
|
|
10145
|
+
* URL path. Set false for a consumer that owns navigation (e.g. query-param tabs):
|
|
10146
|
+
* tabs then only emit `tabClicked`, and the active one is driven by `activeTab`. */
|
|
10147
|
+
this.tabsUseRouter = true;
|
|
10148
|
+
/** Active tab when `tabsUseRouter` is false. Matched by identity or by the tab's
|
|
10149
|
+
* `id` / `value` / `url` / `label`. */
|
|
10150
|
+
this.activeTab = null;
|
|
10151
|
+
this.actionClicked = new EventEmitter();
|
|
10152
|
+
this.tabClicked = new EventEmitter();
|
|
10153
|
+
}
|
|
10154
|
+
clickAction(value) {
|
|
10155
|
+
this.actionClicked.emit(value);
|
|
10156
|
+
}
|
|
10157
|
+
onTabClick(tab) {
|
|
10158
|
+
this.tabClicked.emit(tab);
|
|
10159
|
+
}
|
|
10160
|
+
tabSelected(tab) {
|
|
10161
|
+
if (!this.tabsUseRouter) {
|
|
10162
|
+
return this.tabMatchesActive(tab);
|
|
10163
|
+
}
|
|
10164
|
+
if (!tab?.url) {
|
|
10165
|
+
return false;
|
|
10166
|
+
}
|
|
10167
|
+
const parsedUrl = new URL(window.location.href);
|
|
10168
|
+
let path = parsedUrl.pathname;
|
|
10169
|
+
if (document.baseURI) {
|
|
10170
|
+
const base = new URL(document.baseURI).pathname;
|
|
10171
|
+
if (path.startsWith(base)) {
|
|
10172
|
+
path = path.slice(base.length);
|
|
10173
|
+
}
|
|
10174
|
+
}
|
|
10175
|
+
let tabUrl = tab.url;
|
|
10176
|
+
if (tab.url.startsWith('/')) {
|
|
10177
|
+
tabUrl = tab.url.slice(1);
|
|
10178
|
+
}
|
|
10179
|
+
if (path.startsWith('/')) {
|
|
10180
|
+
path = path.slice(1);
|
|
10181
|
+
}
|
|
10182
|
+
return tabUrl === path;
|
|
10183
|
+
}
|
|
10184
|
+
tabMatchesActive(tab) {
|
|
10185
|
+
const active = this.activeTab;
|
|
10186
|
+
if (active == null) {
|
|
10187
|
+
return false;
|
|
10188
|
+
}
|
|
10189
|
+
if (active === tab) {
|
|
10190
|
+
return true;
|
|
10191
|
+
}
|
|
10192
|
+
return active === tab?.id || active === tab?.value || active === tab?.url || active === tab?.label;
|
|
10193
|
+
}
|
|
10194
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListTableHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
10195
|
+
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 (tabs?.length) {\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:.75rem;padding-bottom:.5rem}.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(--primary);background:color-mix(in srgb,var(--primary) 12%,var(--background));border:1px solid color-mix(in srgb,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(--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"] }] }); }
|
|
10196
|
+
}
|
|
10197
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListTableHeaderComponent, decorators: [{
|
|
10198
|
+
type: Component,
|
|
10199
|
+
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 (tabs?.length) {\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:.75rem;padding-bottom:.5rem}.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(--primary);background:color-mix(in srgb,var(--primary) 12%,var(--background));border:1px solid color-mix(in srgb,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(--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"] }]
|
|
10200
|
+
}], propDecorators: { title: [{
|
|
10201
|
+
type: Input
|
|
10202
|
+
}], subtitle: [{
|
|
10203
|
+
type: Input
|
|
10204
|
+
}], createLabel: [{
|
|
10205
|
+
type: Input
|
|
10206
|
+
}], infoText: [{
|
|
10207
|
+
type: Input
|
|
10208
|
+
}], tabs: [{
|
|
10209
|
+
type: Input
|
|
10210
|
+
}], showAdd: [{
|
|
10211
|
+
type: Input
|
|
10212
|
+
}], blockCreate: [{
|
|
10213
|
+
type: Input
|
|
10214
|
+
}], blockDelete: [{
|
|
10215
|
+
type: Input
|
|
10216
|
+
}], tabsUseRouter: [{
|
|
10217
|
+
type: Input
|
|
10218
|
+
}], activeTab: [{
|
|
10219
|
+
type: Input
|
|
10220
|
+
}], actionClicked: [{
|
|
10221
|
+
type: Output
|
|
10222
|
+
}], tabClicked: [{
|
|
10223
|
+
type: Output
|
|
10224
|
+
}] } });
|
|
10225
|
+
|
|
9292
10226
|
/*
|
|
9293
10227
|
Copyright NetFoundry Inc.
|
|
9294
10228
|
|
|
@@ -10769,6 +11703,1318 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
10769
11703
|
args: ['document:keydown.escape', ['$event']]
|
|
10770
11704
|
}] } });
|
|
10771
11705
|
|
|
11706
|
+
/**
|
|
11707
|
+
* Generic, theme-driven action menu popover. Presentational only: the host owns
|
|
11708
|
+
* open state and position and handles `(itemClick)` / `(closed)`.
|
|
11709
|
+
*/
|
|
11710
|
+
class ListMenuComponent {
|
|
11711
|
+
constructor() {
|
|
11712
|
+
/** Whether the menu is rendered. */
|
|
11713
|
+
this.open = false;
|
|
11714
|
+
/** Rows to render. */
|
|
11715
|
+
this.items = [];
|
|
11716
|
+
/** Fixed-position left offset (px). */
|
|
11717
|
+
this.left = 0;
|
|
11718
|
+
/** Fixed-position top offset (px). */
|
|
11719
|
+
this.top = 0;
|
|
11720
|
+
/** Emitted when a clickable row is selected. */
|
|
11721
|
+
this.itemClick = new EventEmitter();
|
|
11722
|
+
/** Emitted when the user clicks outside the open menu. */
|
|
11723
|
+
this.closed = new EventEmitter();
|
|
11724
|
+
this.trackItem = (_, item) => item.action ?? item.label;
|
|
11725
|
+
}
|
|
11726
|
+
onItem(item, event) {
|
|
11727
|
+
if (item.disabled) {
|
|
11728
|
+
return;
|
|
11729
|
+
}
|
|
11730
|
+
this.itemClick.emit({ item, event });
|
|
11731
|
+
}
|
|
11732
|
+
onClickOutside(event) {
|
|
11733
|
+
this.closed.emit(event);
|
|
11734
|
+
}
|
|
11735
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
11736
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: ListMenuComponent, isStandalone: false, selector: "lib-list-menu", inputs: { open: "open", items: "items", left: "left", top: "top", menuId: "menuId" }, outputs: { itemClick: "itemClick", closed: "closed" }, ngImport: i0, template: "@if (open) {\n <div\n class=\"lt-menu\"\n [attr.id]=\"menuId || null\"\n [ngStyle]=\"{ left: left + 'px', top: top + 'px' }\"\n (clickOutside)=\"onClickOutside($event)\"\n >\n @for (item of items; track trackItem($index, item)) {\n <button\n type=\"button\"\n class=\"lt-menu-item\"\n [class.has-icon]=\"!!item.icon || !!item.iconSvg\"\n [class.is-hidden]=\"item.hidden\"\n [disabled]=\"!!item.disabled\"\n [attr.id]=\"item.id || null\"\n (click)=\"onItem(item, $event)\"\n >\n @if (item.iconSvg) {\n <span class=\"lt-menu-icon\" aria-hidden=\"true\" [innerHTML]=\"item.iconSvg\"></span>\n } @else if (item.icon) {\n <span class=\"lt-menu-icon {{ item.icon }}\" aria-hidden=\"true\"></span>\n }\n <span class=\"lt-menu-label\">{{ item.label }}</span>\n </button>\n }\n </div>\n}\n", styles: [":host{display:contents}.lt-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);font-family:var(--lt-font);animation:lt-menu-in .1s ease-out}@keyframes lt-menu-in{0%{opacity:0;transform:translateY(-.25rem)}to{opacity:1;transform:translateY(0)}}.lt-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}.lt-menu-item:hover{background:var(--lt-row-hover);color:var(--lt-link)}.lt-menu-item:hover .lt-menu-icon{color:var(--lt-link)}.lt-menu-item.is-hidden{display:none}.lt-menu-item:disabled{opacity:.45;cursor:default}.lt-menu-item:disabled:hover{background:transparent;color:var(--lt-cell-text)}.lt-menu-icon{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:1rem;font-size:.9375rem;color:var(--lt-icon)}.lt-menu-icon ::ng-deep svg{display:block;width:.9375rem;height:.9375rem}\n"], dependencies: [{ kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i3$1.ClickOutsideDirective, selector: "[clickOutside]", inputs: ["clickOutsideEnabled", "attachOutsideOnClick", "delayClickOutsideInit", "emitOnBlur", "exclude", "excludeBeforeClick", "clickOutsideEvents"], outputs: ["clickOutside"] }] }); }
|
|
11737
|
+
}
|
|
11738
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListMenuComponent, decorators: [{
|
|
11739
|
+
type: Component,
|
|
11740
|
+
args: [{ selector: 'lib-list-menu', standalone: false, template: "@if (open) {\n <div\n class=\"lt-menu\"\n [attr.id]=\"menuId || null\"\n [ngStyle]=\"{ left: left + 'px', top: top + 'px' }\"\n (clickOutside)=\"onClickOutside($event)\"\n >\n @for (item of items; track trackItem($index, item)) {\n <button\n type=\"button\"\n class=\"lt-menu-item\"\n [class.has-icon]=\"!!item.icon || !!item.iconSvg\"\n [class.is-hidden]=\"item.hidden\"\n [disabled]=\"!!item.disabled\"\n [attr.id]=\"item.id || null\"\n (click)=\"onItem(item, $event)\"\n >\n @if (item.iconSvg) {\n <span class=\"lt-menu-icon\" aria-hidden=\"true\" [innerHTML]=\"item.iconSvg\"></span>\n } @else if (item.icon) {\n <span class=\"lt-menu-icon {{ item.icon }}\" aria-hidden=\"true\"></span>\n }\n <span class=\"lt-menu-label\">{{ item.label }}</span>\n </button>\n }\n </div>\n}\n", styles: [":host{display:contents}.lt-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);font-family:var(--lt-font);animation:lt-menu-in .1s ease-out}@keyframes lt-menu-in{0%{opacity:0;transform:translateY(-.25rem)}to{opacity:1;transform:translateY(0)}}.lt-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}.lt-menu-item:hover{background:var(--lt-row-hover);color:var(--lt-link)}.lt-menu-item:hover .lt-menu-icon{color:var(--lt-link)}.lt-menu-item.is-hidden{display:none}.lt-menu-item:disabled{opacity:.45;cursor:default}.lt-menu-item:disabled:hover{background:transparent;color:var(--lt-cell-text)}.lt-menu-icon{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:1rem;font-size:.9375rem;color:var(--lt-icon)}.lt-menu-icon ::ng-deep svg{display:block;width:.9375rem;height:.9375rem}\n"] }]
|
|
11741
|
+
}], propDecorators: { open: [{
|
|
11742
|
+
type: Input
|
|
11743
|
+
}], items: [{
|
|
11744
|
+
type: Input
|
|
11745
|
+
}], left: [{
|
|
11746
|
+
type: Input
|
|
11747
|
+
}], top: [{
|
|
11748
|
+
type: Input
|
|
11749
|
+
}], menuId: [{
|
|
11750
|
+
type: Input
|
|
11751
|
+
}], itemClick: [{
|
|
11752
|
+
type: Output
|
|
11753
|
+
}], closed: [{
|
|
11754
|
+
type: Output
|
|
11755
|
+
}] } });
|
|
11756
|
+
|
|
11757
|
+
/**
|
|
11758
|
+
* Row selection toggle for {@link ListTableComponent}. Router / exclusive /
|
|
11759
|
+
* reserved / system rows cannot be toggled.
|
|
11760
|
+
*/
|
|
11761
|
+
class SelectCellComponent {
|
|
11762
|
+
constructor() {
|
|
11763
|
+
this.item = {
|
|
11764
|
+
id: '',
|
|
11765
|
+
name: '',
|
|
11766
|
+
selected: false,
|
|
11767
|
+
hideSelect: false,
|
|
11768
|
+
};
|
|
11769
|
+
this.disableToggle = false;
|
|
11770
|
+
}
|
|
11771
|
+
set row(v) {
|
|
11772
|
+
this.item = v || this.item;
|
|
11773
|
+
this.disableToggle =
|
|
11774
|
+
_.get(this.item, 'typeId') === 'Router' ||
|
|
11775
|
+
_.get(this.item, 'exclusiveTo') ||
|
|
11776
|
+
_.get(this.item, 'reserved') === true ||
|
|
11777
|
+
_.get(this.item, 'isSystem') === true;
|
|
11778
|
+
}
|
|
11779
|
+
toggle(item) {
|
|
11780
|
+
if (this.disableToggle || !this.toggleItem) {
|
|
11781
|
+
return;
|
|
11782
|
+
}
|
|
11783
|
+
this.toggleItem(item);
|
|
11784
|
+
}
|
|
11785
|
+
get tooltip() {
|
|
11786
|
+
let tooltip = '';
|
|
11787
|
+
if (this.item?.isSystem) {
|
|
11788
|
+
tooltip = 'Deleting "system" entities is not allowed';
|
|
11789
|
+
}
|
|
11790
|
+
else if (this.item?.typeId === 'Router') {
|
|
11791
|
+
tooltip = 'Unable to delete "Router" Identities. Please delete the associated Router instead.';
|
|
11792
|
+
}
|
|
11793
|
+
return tooltip;
|
|
11794
|
+
}
|
|
11795
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: SelectCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
11796
|
+
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"] }] }); }
|
|
11797
|
+
}
|
|
11798
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: SelectCellComponent, decorators: [{
|
|
11799
|
+
type: Component,
|
|
11800
|
+
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"] }]
|
|
11801
|
+
}], propDecorators: { row: [{
|
|
11802
|
+
type: Input
|
|
11803
|
+
}], toggleItem: [{
|
|
11804
|
+
type: Input
|
|
11805
|
+
}] } });
|
|
11806
|
+
|
|
11807
|
+
/*
|
|
11808
|
+
Copyright NetFoundry Inc.
|
|
11809
|
+
|
|
11810
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
11811
|
+
you may not use this file except in compliance with the License.
|
|
11812
|
+
You may obtain a copy of the License at
|
|
11813
|
+
|
|
11814
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
11815
|
+
|
|
11816
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11817
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
11818
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11819
|
+
See the License for the specific language governing permissions and
|
|
11820
|
+
limitations under the License.
|
|
11821
|
+
*/
|
|
11822
|
+
/** Header cell for {@link ListTableComponent}: label, 3-state sort (asc/desc), and hide. */
|
|
11823
|
+
class ListHeaderCellComponent {
|
|
11824
|
+
constructor() {
|
|
11825
|
+
this.sortChanged = new EventEmitter();
|
|
11826
|
+
this.hideColumn = new EventEmitter();
|
|
11827
|
+
}
|
|
11828
|
+
get enableSorting() {
|
|
11829
|
+
return !!(this.column?.sortable || this.column?.enableSorting);
|
|
11830
|
+
}
|
|
11831
|
+
sort() {
|
|
11832
|
+
if (!this.enableSorting) {
|
|
11833
|
+
return;
|
|
11834
|
+
}
|
|
11835
|
+
const dir = !this.sortDir || this.sortDir === 'desc' ? 'asc' : 'desc';
|
|
11836
|
+
this.sortDir = dir;
|
|
11837
|
+
this.column.onSort?.(this.column.key, dir);
|
|
11838
|
+
this.sortChanged.emit({ colId: this.column.key, dir });
|
|
11839
|
+
}
|
|
11840
|
+
hide(event) {
|
|
11841
|
+
event.stopPropagation();
|
|
11842
|
+
this.hideColumn.emit(this.column);
|
|
11843
|
+
}
|
|
11844
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListHeaderCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
11845
|
+
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", hideColumn: "hideColumn" }, 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 @if (column.hideable !== false) {\n <span\n (click)=\"hide($event)\"\n class=\"lt-header-icon lt-col-hide-button\"\n id=\"HeaderHide_{{ column.key }}\"\n title=\"Hide Column\"\n >\n <svg viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.3\"\n d=\"M1 8s2.7-4.5 7-4.5S15 8 15 8s-2.7 4.5-7 4.5S1 8 1 8Z\"/>\n <circle cx=\"8\" cy=\"8\" r=\"1.9\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.3\"/>\n <line x1=\"2.5\" y1=\"13.5\" x2=\"13.5\" y2=\"2.5\" stroke=\"currentColor\" stroke-width=\"1.3\"/>\n </svg>\n </span>\n }\n <div class=\"lt-header-label\">\n <span\n [title]=\"column.label\"\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}.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-header-icon{display:inline-flex;align-items:center;justify-content:center;color:var(--lt-icon);cursor:pointer;transition:opacity .2s,color .2s}.lt-header-icon svg{display:block}.lt-header-icon:hover{color:var(--lt-icon-active)}.lt-col-hide-button,.lt-col-filter-button{opacity:0}.lt-header-container:hover .lt-col-hide-button,.lt-header-container:hover .lt-col-filter-button{opacity:1}.lt-col-filter-button.nf-filter-applied{opacity:1;color:var(--lt-icon-active)}.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"] }] }); }
|
|
11846
|
+
}
|
|
11847
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListHeaderCellComponent, decorators: [{
|
|
11848
|
+
type: Component,
|
|
11849
|
+
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 @if (column.hideable !== false) {\n <span\n (click)=\"hide($event)\"\n class=\"lt-header-icon lt-col-hide-button\"\n id=\"HeaderHide_{{ column.key }}\"\n title=\"Hide Column\"\n >\n <svg viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\">\n <path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.3\"\n d=\"M1 8s2.7-4.5 7-4.5S15 8 15 8s-2.7 4.5-7 4.5S1 8 1 8Z\"/>\n <circle cx=\"8\" cy=\"8\" r=\"1.9\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.3\"/>\n <line x1=\"2.5\" y1=\"13.5\" x2=\"13.5\" y2=\"2.5\" stroke=\"currentColor\" stroke-width=\"1.3\"/>\n </svg>\n </span>\n }\n <div class=\"lt-header-label\">\n <span\n [title]=\"column.label\"\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}.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-header-icon{display:inline-flex;align-items:center;justify-content:center;color:var(--lt-icon);cursor:pointer;transition:opacity .2s,color .2s}.lt-header-icon svg{display:block}.lt-header-icon:hover{color:var(--lt-icon-active)}.lt-col-hide-button,.lt-col-filter-button{opacity:0}.lt-header-container:hover .lt-col-hide-button,.lt-header-container:hover .lt-col-filter-button{opacity:1}.lt-col-filter-button.nf-filter-applied{opacity:1;color:var(--lt-icon-active)}.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"] }]
|
|
11850
|
+
}], propDecorators: { column: [{
|
|
11851
|
+
type: Input
|
|
11852
|
+
}], sortDir: [{
|
|
11853
|
+
type: Input
|
|
11854
|
+
}], sortChanged: [{
|
|
11855
|
+
type: Output
|
|
11856
|
+
}], hideColumn: [{
|
|
11857
|
+
type: Output
|
|
11858
|
+
}] } });
|
|
11859
|
+
|
|
11860
|
+
/*
|
|
11861
|
+
Copyright NetFoundry Inc.
|
|
11862
|
+
|
|
11863
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
11864
|
+
you may not use this file except in compliance with the License.
|
|
11865
|
+
You may obtain a copy of the License at
|
|
11866
|
+
|
|
11867
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
11868
|
+
|
|
11869
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11870
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
11871
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11872
|
+
See the License for the specific language governing permissions and
|
|
11873
|
+
limitations under the License.
|
|
11874
|
+
*/
|
|
11875
|
+
const DATE_PRESETS = [
|
|
11876
|
+
{ label: 'Any time', value: '' },
|
|
11877
|
+
{ label: 'Last Hour', value: 'hour' },
|
|
11878
|
+
{ label: 'Last Day', value: 'day' },
|
|
11879
|
+
{ label: 'Last Week', value: 'week' },
|
|
11880
|
+
{ label: 'Last Month', value: 'month' },
|
|
11881
|
+
];
|
|
11882
|
+
/**
|
|
11883
|
+
* A single control in the table's filter row. Renders the right widget for the
|
|
11884
|
+
* column's `filterType` (text input / single-select / multi-select / date-range)
|
|
11885
|
+
* and pushes changes through {@link DataTableFilterService}, whose value contract the
|
|
11886
|
+
* controller query-builder already understands (icontains / = / anyOf() / datetime range).
|
|
11887
|
+
*/
|
|
11888
|
+
class ListFilterCellComponent {
|
|
11889
|
+
constructor(filterService, listSvc) {
|
|
11890
|
+
this.filterService = filterService;
|
|
11891
|
+
this.listSvc = listSvc;
|
|
11892
|
+
this.mode = 'text';
|
|
11893
|
+
this.options = [];
|
|
11894
|
+
this.textValue = '';
|
|
11895
|
+
this.selectedValue = '';
|
|
11896
|
+
this.selectedValues = [];
|
|
11897
|
+
/** In-dropdown search text for the multi-select attribute combo. */
|
|
11898
|
+
this.attrSearch = '';
|
|
11899
|
+
this.open = false;
|
|
11900
|
+
this.menuLeft = 0;
|
|
11901
|
+
this.menuTop = 0;
|
|
11902
|
+
this.menuWidth = 0;
|
|
11903
|
+
// custom date range (daterange mode)
|
|
11904
|
+
this.dateRangeStart = null;
|
|
11905
|
+
this.dateRangeEnd = null;
|
|
11906
|
+
this.sub = new Subscription();
|
|
11907
|
+
this.textDebounced = _.debounce(() => this.emitText(), 400);
|
|
11908
|
+
}
|
|
11909
|
+
ngOnInit() {
|
|
11910
|
+
this.mode = this.resolveMode();
|
|
11911
|
+
this.options = this.resolveOptions();
|
|
11912
|
+
this.sub.add(this.filterService.filtersChanged.subscribe((filters) => this.syncFromFilters(filters)));
|
|
11913
|
+
// close this menu whenever another dropdown opens
|
|
11914
|
+
this.sub.add(this.listSvc.menuOpened$.subscribe((owner) => {
|
|
11915
|
+
if (owner !== this) {
|
|
11916
|
+
this.open = false;
|
|
11917
|
+
}
|
|
11918
|
+
}));
|
|
11919
|
+
}
|
|
11920
|
+
ngOnDestroy() {
|
|
11921
|
+
this.sub.unsubscribe();
|
|
11922
|
+
}
|
|
11923
|
+
// ------------------------------------------------------------------ config
|
|
11924
|
+
get field() {
|
|
11925
|
+
return this.column.filterField || this.column.field || this.column.key;
|
|
11926
|
+
}
|
|
11927
|
+
get placeholder() {
|
|
11928
|
+
return this.column.filterPlaceholder || 'All';
|
|
11929
|
+
}
|
|
11930
|
+
/** True only for the Ziti role-attribute flavor of multi-select (adds #/@ prefixing). */
|
|
11931
|
+
get isAttributeMode() {
|
|
11932
|
+
return this.column.filterType === 'ATTRIBUTE';
|
|
11933
|
+
}
|
|
11934
|
+
resolveMode() {
|
|
11935
|
+
switch (this.column.filterType) {
|
|
11936
|
+
case 'TEXTINPUT':
|
|
11937
|
+
return 'text';
|
|
11938
|
+
case 'ATTRIBUTE':
|
|
11939
|
+
case 'MULTISELECT':
|
|
11940
|
+
return 'multi';
|
|
11941
|
+
case 'DATETIME':
|
|
11942
|
+
return 'daterange';
|
|
11943
|
+
default:
|
|
11944
|
+
return 'single';
|
|
11945
|
+
}
|
|
11946
|
+
}
|
|
11947
|
+
resolveOptions() {
|
|
11948
|
+
if (this.mode === 'daterange') {
|
|
11949
|
+
return DATE_PRESETS;
|
|
11950
|
+
}
|
|
11951
|
+
if (this.mode === 'multi') {
|
|
11952
|
+
let raw;
|
|
11953
|
+
if (this.isAttributeMode) {
|
|
11954
|
+
const getAttrs = this.column.headerParams?.['getRoleAttributes'];
|
|
11955
|
+
raw = (typeof getAttrs === 'function' ? getAttrs() : null) || this.column.filterOptions || [];
|
|
11956
|
+
}
|
|
11957
|
+
else {
|
|
11958
|
+
raw = this.column.getFilterOptions ? this.column.getFilterOptions() : (this.column.filterOptions || []);
|
|
11959
|
+
}
|
|
11960
|
+
return raw.map((a) => (typeof a === 'string' ? { label: a, value: a } : a));
|
|
11961
|
+
}
|
|
11962
|
+
const raw = this.column.getFilterOptions ? this.column.getFilterOptions() : this.column.filterOptions || [];
|
|
11963
|
+
return raw;
|
|
11964
|
+
}
|
|
11965
|
+
// ------------------------------------------------------------------ display
|
|
11966
|
+
/** Short display of the current selection, shown after the field label when set. */
|
|
11967
|
+
get valueLabel() {
|
|
11968
|
+
if (this.mode === 'multi') {
|
|
11969
|
+
if (this.selectedValues.length === 1) {
|
|
11970
|
+
return this.selectedValues[0];
|
|
11971
|
+
}
|
|
11972
|
+
return `${this.selectedValues.length}`;
|
|
11973
|
+
}
|
|
11974
|
+
if (this.mode === 'daterange') {
|
|
11975
|
+
if (this.selectedValue === 'custom' && this.dateRangeStart) {
|
|
11976
|
+
const start = moment$1(this.dateRangeStart).format('M/D/YY');
|
|
11977
|
+
const end = this.dateRangeEnd ? moment$1(this.dateRangeEnd).format('M/D/YY') : '';
|
|
11978
|
+
return end ? `${start} – ${end}` : start;
|
|
11979
|
+
}
|
|
11980
|
+
const found = this.options.find((o) => o.value === this.selectedValue);
|
|
11981
|
+
return found && found.value ? found.label : '';
|
|
11982
|
+
}
|
|
11983
|
+
const match = this.options.find((o) => `${o.value}` === `${this.selectedValue}`);
|
|
11984
|
+
return match && match.value !== '' && match.value != null ? match.label : '';
|
|
11985
|
+
}
|
|
11986
|
+
get hasValue() {
|
|
11987
|
+
if (this.mode === 'multi') {
|
|
11988
|
+
return this.selectedValues.length > 0;
|
|
11989
|
+
}
|
|
11990
|
+
return this.selectedValue !== '' && this.selectedValue != null;
|
|
11991
|
+
}
|
|
11992
|
+
isOptionSelected(opt) {
|
|
11993
|
+
if (this.mode === 'multi') {
|
|
11994
|
+
return this.selectedValues.includes(opt.value);
|
|
11995
|
+
}
|
|
11996
|
+
return `${opt.value}` === `${this.selectedValue}`;
|
|
11997
|
+
}
|
|
11998
|
+
/** Attribute options filtered by the in-dropdown search box (multi mode). */
|
|
11999
|
+
get filteredOptions() {
|
|
12000
|
+
if (this.mode !== 'multi' || !this.attrSearch) {
|
|
12001
|
+
return this.options;
|
|
12002
|
+
}
|
|
12003
|
+
const q = this.attrSearch.toLowerCase();
|
|
12004
|
+
return this.options.filter((o) => `${o.label ?? o.value}`.toLowerCase().includes(q));
|
|
12005
|
+
}
|
|
12006
|
+
/** A named attribute (rendered with @ + secondary color) vs a role attribute (# + primary). */
|
|
12007
|
+
isNamedOption(opt) {
|
|
12008
|
+
return this.isAttributeMode && String(opt?.value ?? opt?.label ?? '').charAt(0) === '@';
|
|
12009
|
+
}
|
|
12010
|
+
/** Option label. The attribute flavor prefixes # (role) / keeps @ (named); others render plain. */
|
|
12011
|
+
optionLabel(opt) {
|
|
12012
|
+
const raw = String(opt?.label ?? opt?.value ?? '');
|
|
12013
|
+
if (!this.isAttributeMode) {
|
|
12014
|
+
return raw;
|
|
12015
|
+
}
|
|
12016
|
+
if (raw.charAt(0) === '@' || raw.charAt(0) === '#') {
|
|
12017
|
+
return raw;
|
|
12018
|
+
}
|
|
12019
|
+
return '#' + raw;
|
|
12020
|
+
}
|
|
12021
|
+
// ------------------------------------------------------------------ open/close
|
|
12022
|
+
toggleMenu(event) {
|
|
12023
|
+
event.stopPropagation();
|
|
12024
|
+
if (this.open) {
|
|
12025
|
+
this.open = false;
|
|
12026
|
+
return;
|
|
12027
|
+
}
|
|
12028
|
+
const rect = this.trigger?.nativeElement.getBoundingClientRect();
|
|
12029
|
+
if (rect) {
|
|
12030
|
+
this.menuLeft = rect.left;
|
|
12031
|
+
this.menuTop = rect.bottom + 4;
|
|
12032
|
+
this.menuWidth = Math.max(rect.width, this.mode === 'multi' ? 220 : 160);
|
|
12033
|
+
}
|
|
12034
|
+
// refresh dynamic option sources (e.g. role attributes) each open
|
|
12035
|
+
this.options = this.resolveOptions();
|
|
12036
|
+
this.attrSearch = '';
|
|
12037
|
+
this.open = true;
|
|
12038
|
+
this.listSvc.notifyMenuOpened(this);
|
|
12039
|
+
}
|
|
12040
|
+
closeMenu() {
|
|
12041
|
+
this.open = false;
|
|
12042
|
+
}
|
|
12043
|
+
// ------------------------------------------------------------------ text
|
|
12044
|
+
onTextInput() {
|
|
12045
|
+
this.textDebounced();
|
|
12046
|
+
}
|
|
12047
|
+
emitText() {
|
|
12048
|
+
this.filterService.updateFilter({
|
|
12049
|
+
filterName: this.column.label,
|
|
12050
|
+
columnId: this.field,
|
|
12051
|
+
value: this.textValue,
|
|
12052
|
+
label: this.textValue,
|
|
12053
|
+
type: 'TEXTINPUT',
|
|
12054
|
+
});
|
|
12055
|
+
}
|
|
12056
|
+
// ------------------------------------------------------------------ single
|
|
12057
|
+
selectOption(opt) {
|
|
12058
|
+
this.selectedValue = opt.value;
|
|
12059
|
+
this.open = false;
|
|
12060
|
+
if (opt.value === '' || opt.value == null) {
|
|
12061
|
+
this.removeThis();
|
|
12062
|
+
return;
|
|
12063
|
+
}
|
|
12064
|
+
this.filterService.updateFilter({
|
|
12065
|
+
filterName: this.column.label,
|
|
12066
|
+
columnId: this.field,
|
|
12067
|
+
value: opt.value,
|
|
12068
|
+
label: opt.label,
|
|
12069
|
+
type: this.column.filterType || 'SELECT',
|
|
12070
|
+
});
|
|
12071
|
+
}
|
|
12072
|
+
// ------------------------------------------------------------------ multi
|
|
12073
|
+
toggleOption(opt) {
|
|
12074
|
+
const idx = this.selectedValues.indexOf(opt.value);
|
|
12075
|
+
if (idx >= 0) {
|
|
12076
|
+
this.selectedValues.splice(idx, 1);
|
|
12077
|
+
}
|
|
12078
|
+
else {
|
|
12079
|
+
this.selectedValues.push(opt.value);
|
|
12080
|
+
}
|
|
12081
|
+
this.emitMulti();
|
|
12082
|
+
}
|
|
12083
|
+
emitMulti() {
|
|
12084
|
+
if (!this.selectedValues.length) {
|
|
12085
|
+
this.removeThis();
|
|
12086
|
+
return;
|
|
12087
|
+
}
|
|
12088
|
+
const filter = {
|
|
12089
|
+
filterName: this.column.label,
|
|
12090
|
+
columnId: this.field,
|
|
12091
|
+
value: [...this.selectedValues],
|
|
12092
|
+
label: this.selectedValues.join(', '),
|
|
12093
|
+
type: this.isAttributeMode ? 'ATTRIBUTE' : 'MULTISELECT',
|
|
12094
|
+
semantic: 'AnyOf',
|
|
12095
|
+
};
|
|
12096
|
+
this.filterService.updateFilter(filter);
|
|
12097
|
+
}
|
|
12098
|
+
// ------------------------------------------------------------------ date range
|
|
12099
|
+
selectDatePreset(opt) {
|
|
12100
|
+
this.selectedValue = opt.value;
|
|
12101
|
+
this.dateRangeStart = null;
|
|
12102
|
+
this.dateRangeEnd = null;
|
|
12103
|
+
this.open = false;
|
|
12104
|
+
if (!opt.value) {
|
|
12105
|
+
this.removeThis();
|
|
12106
|
+
return;
|
|
12107
|
+
}
|
|
12108
|
+
const end = moment$1();
|
|
12109
|
+
let start;
|
|
12110
|
+
switch (opt.value) {
|
|
12111
|
+
case 'hour':
|
|
12112
|
+
start = moment$1().subtract(1, 'hours');
|
|
12113
|
+
break;
|
|
12114
|
+
case 'week':
|
|
12115
|
+
start = moment$1().subtract(7, 'days');
|
|
12116
|
+
break;
|
|
12117
|
+
case 'month':
|
|
12118
|
+
start = moment$1().subtract(1, 'month');
|
|
12119
|
+
break;
|
|
12120
|
+
case 'day':
|
|
12121
|
+
default:
|
|
12122
|
+
start = moment$1().subtract(24, 'hours');
|
|
12123
|
+
break;
|
|
12124
|
+
}
|
|
12125
|
+
this.filterService.updateFilter({
|
|
12126
|
+
filterName: this.column.label,
|
|
12127
|
+
columnId: this.field,
|
|
12128
|
+
value: [encodeURIComponent(start.toISOString()), encodeURIComponent(end.toISOString())],
|
|
12129
|
+
label: opt.label,
|
|
12130
|
+
type: 'DATETIME',
|
|
12131
|
+
});
|
|
12132
|
+
}
|
|
12133
|
+
openCustomRange(event) {
|
|
12134
|
+
event.stopPropagation();
|
|
12135
|
+
this.open = false;
|
|
12136
|
+
// open the Material calendar on the next tick (after the menu closes)
|
|
12137
|
+
_.delay(() => this.rangePicker?.open(), 0);
|
|
12138
|
+
}
|
|
12139
|
+
onRangeStartChanged(date) {
|
|
12140
|
+
this.dateRangeStart = date;
|
|
12141
|
+
this.emitCustomRange();
|
|
12142
|
+
}
|
|
12143
|
+
onRangeEndChanged(date) {
|
|
12144
|
+
this.dateRangeEnd = date;
|
|
12145
|
+
this.emitCustomRange();
|
|
12146
|
+
}
|
|
12147
|
+
emitCustomRange() {
|
|
12148
|
+
if (!this.dateRangeStart || !this.dateRangeEnd) {
|
|
12149
|
+
return;
|
|
12150
|
+
}
|
|
12151
|
+
this.selectedValue = 'custom';
|
|
12152
|
+
const start = moment$1(this.dateRangeStart).startOf('day');
|
|
12153
|
+
const end = moment$1(this.dateRangeEnd).endOf('day');
|
|
12154
|
+
this.filterService.updateFilter({
|
|
12155
|
+
filterName: this.column.label,
|
|
12156
|
+
columnId: this.field,
|
|
12157
|
+
value: [encodeURIComponent(start.toISOString()), encodeURIComponent(end.toISOString())],
|
|
12158
|
+
label: `${start.format('M/D/YY')} – ${end.format('M/D/YY')}`,
|
|
12159
|
+
type: 'DATETIME',
|
|
12160
|
+
});
|
|
12161
|
+
}
|
|
12162
|
+
// ------------------------------------------------------------------ clear
|
|
12163
|
+
clear(event) {
|
|
12164
|
+
event.stopPropagation();
|
|
12165
|
+
this.selectedValue = '';
|
|
12166
|
+
this.selectedValues = [];
|
|
12167
|
+
this.textValue = '';
|
|
12168
|
+
this.dateRangeStart = null;
|
|
12169
|
+
this.dateRangeEnd = null;
|
|
12170
|
+
this.removeThis();
|
|
12171
|
+
}
|
|
12172
|
+
removeThis() {
|
|
12173
|
+
this.filterService.removeFilter({
|
|
12174
|
+
filterName: this.column.label,
|
|
12175
|
+
columnId: this.field,
|
|
12176
|
+
value: '',
|
|
12177
|
+
label: '',
|
|
12178
|
+
});
|
|
12179
|
+
}
|
|
12180
|
+
// ------------------------------------------------------------------ sync
|
|
12181
|
+
syncFromFilters(filters) {
|
|
12182
|
+
const match = filters.find((f) => f.columnId === this.field);
|
|
12183
|
+
if (!match) {
|
|
12184
|
+
this.textValue = '';
|
|
12185
|
+
this.selectedValue = '';
|
|
12186
|
+
this.selectedValues = [];
|
|
12187
|
+
this.dateRangeStart = null;
|
|
12188
|
+
this.dateRangeEnd = null;
|
|
12189
|
+
return;
|
|
12190
|
+
}
|
|
12191
|
+
if (this.mode === 'text') {
|
|
12192
|
+
this.textValue = match.value ?? '';
|
|
12193
|
+
}
|
|
12194
|
+
else if (this.mode === 'multi') {
|
|
12195
|
+
this.selectedValues = _.isArray(match.value) ? [...match.value] : [match.value];
|
|
12196
|
+
}
|
|
12197
|
+
else if (this.mode === 'daterange') {
|
|
12198
|
+
// keep the locally chosen preset label; match.value is the raw [start,end] range
|
|
12199
|
+
}
|
|
12200
|
+
else {
|
|
12201
|
+
this.selectedValue = match.value;
|
|
12202
|
+
}
|
|
12203
|
+
}
|
|
12204
|
+
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 }); }
|
|
12205
|
+
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: i3$1.ClickOutsideDirective, selector: "[clickOutside]", inputs: ["clickOutsideEnabled", "attachOutsideOnClick", "delayClickOutsideInit", "emitOnBlur", "exclude", "excludeBeforeClick", "clickOutsideEvents"], outputs: ["clickOutside"] }] }); }
|
|
12206
|
+
}
|
|
12207
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListFilterCellComponent, decorators: [{
|
|
12208
|
+
type: Component,
|
|
12209
|
+
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"] }]
|
|
12210
|
+
}], ctorParameters: () => [{ type: DataTableFilterService }, { type: ListTableService }], propDecorators: { column: [{
|
|
12211
|
+
type: Input
|
|
12212
|
+
}], trigger: [{
|
|
12213
|
+
type: ViewChild,
|
|
12214
|
+
args: ['trigger']
|
|
12215
|
+
}], rangePicker: [{
|
|
12216
|
+
type: ViewChild,
|
|
12217
|
+
args: ['rangePicker']
|
|
12218
|
+
}] } });
|
|
12219
|
+
|
|
12220
|
+
/*
|
|
12221
|
+
Copyright NetFoundry Inc.
|
|
12222
|
+
|
|
12223
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
12224
|
+
you may not use this file except in compliance with the License.
|
|
12225
|
+
You may obtain a copy of the License at
|
|
12226
|
+
|
|
12227
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
12228
|
+
|
|
12229
|
+
Unless required by applicable law or agreed to in writing, software
|
|
12230
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12231
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12232
|
+
See the License for the specific language governing permissions and
|
|
12233
|
+
limitations under the License.
|
|
12234
|
+
*/
|
|
12235
|
+
/**
|
|
12236
|
+
* Custom, token-skinnable list table. Columns are declared with {@link ListColumn};
|
|
12237
|
+
* sort, filter, and pagination flow through {@link DataTableFilterService}.
|
|
12238
|
+
*/
|
|
12239
|
+
class ListTableComponent {
|
|
12240
|
+
set tableId(id) {
|
|
12241
|
+
this._tableId = id;
|
|
12242
|
+
this.svc.tableId = id;
|
|
12243
|
+
}
|
|
12244
|
+
get tableId() {
|
|
12245
|
+
return this._tableId;
|
|
12246
|
+
}
|
|
12247
|
+
set columns(value) {
|
|
12248
|
+
this._rawColumns = value || [];
|
|
12249
|
+
if (this._initialized) {
|
|
12250
|
+
this.buildColumns();
|
|
12251
|
+
}
|
|
12252
|
+
}
|
|
12253
|
+
constructor(svc, tableFilterService, el, ngZone, sanitizer) {
|
|
12254
|
+
this.svc = svc;
|
|
12255
|
+
this.tableFilterService = tableFilterService;
|
|
12256
|
+
this.el = el;
|
|
12257
|
+
this.ngZone = ngZone;
|
|
12258
|
+
this.sanitizer = sanitizer;
|
|
12259
|
+
this._tableId = '';
|
|
12260
|
+
this.rowData = [];
|
|
12261
|
+
this.isLoading = false;
|
|
12262
|
+
this.options = { noSelect: false, noMenu: false };
|
|
12263
|
+
this.startCount = '-';
|
|
12264
|
+
this.endCount = '-';
|
|
12265
|
+
this.totalCount = '-';
|
|
12266
|
+
this.filterApplied = false;
|
|
12267
|
+
this.menuItems = [];
|
|
12268
|
+
this.headerActions = [];
|
|
12269
|
+
this.noItemsImage = 'nodata';
|
|
12270
|
+
this.showNoItemsAdd = true;
|
|
12271
|
+
this.noItemsReadonly = false;
|
|
12272
|
+
this.accessDenied = false;
|
|
12273
|
+
this.entityTypeName = '';
|
|
12274
|
+
this.filterName = 'name';
|
|
12275
|
+
this.filterColumn = 'name';
|
|
12276
|
+
this.actionRequested = new EventEmitter();
|
|
12277
|
+
this.tableReady = new EventEmitter();
|
|
12278
|
+
/** Full column list (includes hidden), after persisted state. */
|
|
12279
|
+
this.allColumns = [];
|
|
12280
|
+
/** Currently rendered columns (visible + ordered). */
|
|
12281
|
+
this.visibleColumns = [];
|
|
12282
|
+
/** Hidden columns, shaped for the shared hidden-columns bar (`headerName`). */
|
|
12283
|
+
this.hiddenColumns = [];
|
|
12284
|
+
this.entityTypeLabel = '';
|
|
12285
|
+
// ---- action menus ----
|
|
12286
|
+
this.openMenu = false;
|
|
12287
|
+
this.openHeaderMenu = false;
|
|
12288
|
+
this.menuLeft = 0;
|
|
12289
|
+
this.menuTop = 0;
|
|
12290
|
+
this.selectedItem = { actionList: [] };
|
|
12291
|
+
// ---- selection ----
|
|
12292
|
+
this.allToggled = false;
|
|
12293
|
+
// ---- column chooser (skinned show/hide + reorder panel) ----
|
|
12294
|
+
this.showColumnChooser = false;
|
|
12295
|
+
// ---- integrated toolbar: search + filter chips + pagination ----
|
|
12296
|
+
this.searchString = '';
|
|
12297
|
+
this.activeFilters = [];
|
|
12298
|
+
this.filtering = false;
|
|
12299
|
+
this.inputChangedDebounced = _.debounce(() => this.applySearch(), 400);
|
|
12300
|
+
// ---- responsive filter overflow: controls that don't fit collapse into "More" ----
|
|
12301
|
+
this.visibleFilterColumns = [];
|
|
12302
|
+
this.overflowFilterColumns = [];
|
|
12303
|
+
this.showFilterOverflow = false;
|
|
12304
|
+
this.filterWidths = new Map();
|
|
12305
|
+
this.filtersDirty = true;
|
|
12306
|
+
this.overflowRaf = 0;
|
|
12307
|
+
this.FILTER_GAP = 8; // px, matches the .lt-filter-zone/.lt-filters gap
|
|
12308
|
+
this.MORE_BTN_W = 92; // px reserved for the "More" trigger when overflowing
|
|
12309
|
+
this.onPointerMove = (e) => this.handleResizeMove(e);
|
|
12310
|
+
this.onPointerUp = () => this.handleResizeEnd();
|
|
12311
|
+
this._rawColumns = [];
|
|
12312
|
+
this._initialColumns = [];
|
|
12313
|
+
this._initialized = false;
|
|
12314
|
+
this.subscription = new Subscription();
|
|
12315
|
+
this.trackRow = (index, row) => row?.id ?? row?.name ?? index;
|
|
12316
|
+
this.trackCol = (index, col) => col.key;
|
|
12317
|
+
// ---------------------------------------------------------------- hover tooltip
|
|
12318
|
+
this.hoverTooltip = null;
|
|
12319
|
+
// ---------------------------------------------------------------- selection
|
|
12320
|
+
this.toggleItem = (item) => {
|
|
12321
|
+
item.selected = !item.selected;
|
|
12322
|
+
this.allToggled = !_.isEmpty(this.rowData) && _.every(this.rowData, { selected: true });
|
|
12323
|
+
this.actionRequested.emit({ action: 'toggleItem', item });
|
|
12324
|
+
};
|
|
12325
|
+
// ---------------------------------------------------------------- action menus
|
|
12326
|
+
this.openActionMenu = (event, item) => {
|
|
12327
|
+
this.selectedItem = item;
|
|
12328
|
+
this.openMenu = true;
|
|
12329
|
+
_.delay(() => {
|
|
12330
|
+
const height = this.contextMenu?.nativeElement?.offsetHeight || 120;
|
|
12331
|
+
const windowOffset = window.innerHeight - event.clientY;
|
|
12332
|
+
const menuOffset = windowOffset <= height ? height - windowOffset : 0;
|
|
12333
|
+
this.menuLeft = event.clientX - 100;
|
|
12334
|
+
this.menuTop = event.clientY + 5 - menuOffset;
|
|
12335
|
+
}, 10);
|
|
12336
|
+
};
|
|
12337
|
+
this.closeActionMenu = () => {
|
|
12338
|
+
this.selectedItem = { actionList: [] };
|
|
12339
|
+
this.openMenu = false;
|
|
12340
|
+
this.openHeaderMenu = false;
|
|
12341
|
+
};
|
|
12342
|
+
this.closeHeaderActionMenu = () => {
|
|
12343
|
+
this.openHeaderMenu = false;
|
|
12344
|
+
};
|
|
12345
|
+
/** Restore-default (rotate) icon for the built-in header action. */
|
|
12346
|
+
this.RESET_TABLE_ICON = '<svg viewBox="0 0 16 16" width="15" height="15"><path fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" d="M3.2 8a4.8 4.8 0 1 0 1.3-3.3"/><path fill="currentColor" d="M2.8 2.8l-.3 2.9 2.8-.4z"/></svg>';
|
|
12347
|
+
// ---- rows-per-page + numbered pagination (the skin footer) ----
|
|
12348
|
+
this.pageSizeOptions = [25, 50, 100];
|
|
12349
|
+
/** Default rows-per-page when nothing is remembered (the persisted choice wins). */
|
|
12350
|
+
this.initialPageSize = 50;
|
|
12351
|
+
// ---- auto-refresh (the skin toolbar toggle) ----
|
|
12352
|
+
this.autoRefresh = false;
|
|
12353
|
+
this.autoRefreshIntervalMs = 30000;
|
|
12354
|
+
// ---- row action icons ----
|
|
12355
|
+
// A menu item's host-supplied `icon` (SVG markup) is rendered before its label in
|
|
12356
|
+
// the row's kebab menu. Sanitized once per unique SVG and cached.
|
|
12357
|
+
this.iconCache = new Map();
|
|
12358
|
+
}
|
|
12359
|
+
ngOnInit() {
|
|
12360
|
+
this._initialized = true;
|
|
12361
|
+
// set directly (no emit) to avoid forcing a second fetch when a host pre-seeded it
|
|
12362
|
+
this.tableFilterService.pageSize = this.svc.restorePageSize(this.initialPageSize);
|
|
12363
|
+
this.buildColumns();
|
|
12364
|
+
this.updateEntityTypeLabel();
|
|
12365
|
+
this.subscription.add(this.tableFilterService.filtersChanged.subscribe((filters) => {
|
|
12366
|
+
// chips: every non-hidden filter except the free-text search (shown in the box)
|
|
12367
|
+
this.activeFilters = filters.filter((f) => f.hidden !== true && f.columnId !== this.filterColumn);
|
|
12368
|
+
const match = filters.find((f) => f.columnId === this.filterColumn);
|
|
12369
|
+
this.searchString = match ? match.value : '';
|
|
12370
|
+
// an activated filter changes which controls are pinned and how wide they render
|
|
12371
|
+
this.filtersDirty = true;
|
|
12372
|
+
this.scheduleFilterOverflow();
|
|
12373
|
+
}));
|
|
12374
|
+
this.subscription.add(this.tableFilterService.filtering.subscribe((f) => (this.filtering = f)));
|
|
12375
|
+
// close the column chooser whenever a filter dropdown (or anything else) opens
|
|
12376
|
+
this.subscription.add(this.svc.menuOpened$.subscribe((owner) => {
|
|
12377
|
+
if (owner !== this) {
|
|
12378
|
+
this.showColumnChooser = false;
|
|
12379
|
+
}
|
|
12380
|
+
}));
|
|
12381
|
+
this.tableReady.emit({ component: this });
|
|
12382
|
+
}
|
|
12383
|
+
ngAfterViewInit() {
|
|
12384
|
+
this.ensureFilterResizeObserver();
|
|
12385
|
+
}
|
|
12386
|
+
ngAfterViewChecked() {
|
|
12387
|
+
// the whole table sits behind @if(showTable), so the toolbar may not exist
|
|
12388
|
+
// until row data arrives; (re)attach the observer once/whenever it appears
|
|
12389
|
+
this.ensureFilterResizeObserver();
|
|
12390
|
+
}
|
|
12391
|
+
ngOnDestroy() {
|
|
12392
|
+
this.subscription.unsubscribe();
|
|
12393
|
+
this.detachResizeListeners();
|
|
12394
|
+
this.filterRO?.disconnect();
|
|
12395
|
+
if (this.overflowRaf) {
|
|
12396
|
+
cancelAnimationFrame(this.overflowRaf);
|
|
12397
|
+
}
|
|
12398
|
+
if (this.autoRefreshTimer) {
|
|
12399
|
+
clearInterval(this.autoRefreshTimer);
|
|
12400
|
+
}
|
|
12401
|
+
}
|
|
12402
|
+
get showTable() {
|
|
12403
|
+
return this.isLoading || this.filterApplied || this.rowData?.length > 0;
|
|
12404
|
+
}
|
|
12405
|
+
/** Columns surfaced as inline filter controls in the toolbar. Text filters are
|
|
12406
|
+
* excluded because the free-text search box already covers the primary text field. */
|
|
12407
|
+
get filterableColumns() {
|
|
12408
|
+
return this.allColumns.filter((c) => c.filterType && c.filterType !== 'TEXTINPUT');
|
|
12409
|
+
}
|
|
12410
|
+
// -------------------------------------------------- responsive filter overflow
|
|
12411
|
+
/** A filter column is "active" when it has an applied filter. */
|
|
12412
|
+
isFilterActive(col) {
|
|
12413
|
+
return this.activeFilters.some((f) => f.columnId === col.key);
|
|
12414
|
+
}
|
|
12415
|
+
/** Applied filters that are currently hidden in the overflow dropdown. */
|
|
12416
|
+
get hiddenActiveCount() {
|
|
12417
|
+
return this.overflowFilterColumns.filter((c) => this.isFilterActive(c)).length;
|
|
12418
|
+
}
|
|
12419
|
+
toggleFilterOverflow(event) {
|
|
12420
|
+
event.stopPropagation();
|
|
12421
|
+
this.showFilterOverflow = !this.showFilterOverflow;
|
|
12422
|
+
if (this.showFilterOverflow) {
|
|
12423
|
+
this.svc.notifyMenuOpened(this);
|
|
12424
|
+
}
|
|
12425
|
+
}
|
|
12426
|
+
closeFilterOverflow(event) {
|
|
12427
|
+
// keep open when the click lands in a filter's own Material overlay (e.g. the
|
|
12428
|
+
// date-range calendar), which renders outside this popover's DOM subtree
|
|
12429
|
+
const target = event?.target;
|
|
12430
|
+
if (target?.closest?.('.cdk-overlay-container')) {
|
|
12431
|
+
return;
|
|
12432
|
+
}
|
|
12433
|
+
this.showFilterOverflow = false;
|
|
12434
|
+
}
|
|
12435
|
+
ensureFilterResizeObserver() {
|
|
12436
|
+
// observe the toolbar row (not the content-sized zone) so a window resize,
|
|
12437
|
+
// which changes the row's available width, actually fires the observer
|
|
12438
|
+
const target = this.filterZone?.nativeElement?.parentElement ?? undefined;
|
|
12439
|
+
if (!target || typeof ResizeObserver === 'undefined' || target === this.observedToolbar) {
|
|
12440
|
+
return;
|
|
12441
|
+
}
|
|
12442
|
+
// ResizeObserver fires outside Angular's zone; re-enter so the recomputed
|
|
12443
|
+
// visible/overflow split actually triggers change detection.
|
|
12444
|
+
if (!this.filterRO) {
|
|
12445
|
+
this.filterRO = new ResizeObserver(() => this.ngZone.run(() => this.scheduleFilterOverflow()));
|
|
12446
|
+
}
|
|
12447
|
+
else {
|
|
12448
|
+
this.filterRO.disconnect();
|
|
12449
|
+
}
|
|
12450
|
+
this.filterRO.observe(target);
|
|
12451
|
+
this.observedToolbar = target;
|
|
12452
|
+
// compute the split for the newly-observed row (deferred, so it never mutates
|
|
12453
|
+
// bound state inside the change-detection pass that called us)
|
|
12454
|
+
this.scheduleFilterOverflow();
|
|
12455
|
+
}
|
|
12456
|
+
scheduleFilterOverflow() {
|
|
12457
|
+
if (this.overflowRaf) {
|
|
12458
|
+
cancelAnimationFrame(this.overflowRaf);
|
|
12459
|
+
}
|
|
12460
|
+
this.overflowRaf = requestAnimationFrame(() => {
|
|
12461
|
+
this.overflowRaf = 0;
|
|
12462
|
+
this.ensureFilterResizeObserver();
|
|
12463
|
+
this.recomputeFilterOverflow();
|
|
12464
|
+
});
|
|
12465
|
+
}
|
|
12466
|
+
recomputeFilterOverflow() {
|
|
12467
|
+
const cols = this.filterableColumns;
|
|
12468
|
+
if (!cols.length) {
|
|
12469
|
+
this.visibleFilterColumns = [];
|
|
12470
|
+
this.overflowFilterColumns = [];
|
|
12471
|
+
return;
|
|
12472
|
+
}
|
|
12473
|
+
const needMeasure = this.filtersDirty || cols.some((c) => !this.filterWidths.has(c.key));
|
|
12474
|
+
if (!needMeasure) {
|
|
12475
|
+
this.applyFilterSplit();
|
|
12476
|
+
return;
|
|
12477
|
+
}
|
|
12478
|
+
// render every control inline for one frame so each can be measured, then collapse
|
|
12479
|
+
this.visibleFilterColumns = cols;
|
|
12480
|
+
this.overflowFilterColumns = [];
|
|
12481
|
+
requestAnimationFrame(() => {
|
|
12482
|
+
const row = this.filtersRow?.nativeElement;
|
|
12483
|
+
if (row) {
|
|
12484
|
+
row.querySelectorAll('[data-filter-key]').forEach((el) => {
|
|
12485
|
+
const key = el.getAttribute('data-filter-key');
|
|
12486
|
+
if (key) {
|
|
12487
|
+
this.filterWidths.set(key, Math.ceil(el.getBoundingClientRect().width));
|
|
12488
|
+
}
|
|
12489
|
+
});
|
|
12490
|
+
}
|
|
12491
|
+
this.filtersDirty = false;
|
|
12492
|
+
this.applyFilterSplit();
|
|
12493
|
+
});
|
|
12494
|
+
}
|
|
12495
|
+
/** Split filter controls into inline vs. overflow, pinning active filters and
|
|
12496
|
+
* dropping inactive (then, only if forced, active) from the right until they fit. */
|
|
12497
|
+
applyFilterSplit() {
|
|
12498
|
+
const zone = this.filterZone?.nativeElement;
|
|
12499
|
+
const cols = this.filterableColumns;
|
|
12500
|
+
if (!zone || !cols.length) {
|
|
12501
|
+
return;
|
|
12502
|
+
}
|
|
12503
|
+
// budget = the toolbar row's width minus its fixed siblings (search / divider /
|
|
12504
|
+
// Columns) and the gaps between them, i.e. the space filters may take before
|
|
12505
|
+
// they'd push the Columns control off the row
|
|
12506
|
+
const toolbarLeft = zone.parentElement;
|
|
12507
|
+
const siblingWidth = (sel) => {
|
|
12508
|
+
const node = toolbarLeft?.querySelector(sel);
|
|
12509
|
+
return node ? Math.ceil(node.getBoundingClientRect().width) : 0;
|
|
12510
|
+
};
|
|
12511
|
+
const available = (toolbarLeft?.clientWidth ?? zone.clientWidth) -
|
|
12512
|
+
siblingWidth('.lt-search') -
|
|
12513
|
+
siblingWidth('.lt-divider') -
|
|
12514
|
+
siblingWidth('.lt-columns') -
|
|
12515
|
+
3 * this.FILTER_GAP;
|
|
12516
|
+
const widthOf = (c) => this.filterWidths.get(c.key) ?? 0;
|
|
12517
|
+
const totalOf = (list, withMore) => {
|
|
12518
|
+
let w = 0;
|
|
12519
|
+
list.forEach((c, i) => (w += widthOf(c) + (i > 0 ? this.FILTER_GAP : 0)));
|
|
12520
|
+
if (withMore) {
|
|
12521
|
+
w += (list.length ? this.FILTER_GAP : 0) + this.MORE_BTN_W;
|
|
12522
|
+
}
|
|
12523
|
+
return w;
|
|
12524
|
+
};
|
|
12525
|
+
if (totalOf(cols, false) <= available) {
|
|
12526
|
+
this.visibleFilterColumns = cols;
|
|
12527
|
+
this.overflowFilterColumns = [];
|
|
12528
|
+
return;
|
|
12529
|
+
}
|
|
12530
|
+
// removal priority: inactive right-to-left first, then active right-to-left
|
|
12531
|
+
const inactive = cols.filter((c) => !this.isFilterActive(c)).reverse();
|
|
12532
|
+
const active = cols.filter((c) => this.isFilterActive(c)).reverse();
|
|
12533
|
+
const removalOrder = [...inactive, ...active];
|
|
12534
|
+
const overflow = new Set();
|
|
12535
|
+
for (const c of removalOrder) {
|
|
12536
|
+
overflow.add(c.key);
|
|
12537
|
+
const visible = cols.filter((x) => !overflow.has(x.key));
|
|
12538
|
+
if (totalOf(visible, true) <= available) {
|
|
12539
|
+
break;
|
|
12540
|
+
}
|
|
12541
|
+
}
|
|
12542
|
+
this.visibleFilterColumns = cols.filter((c) => !overflow.has(c.key));
|
|
12543
|
+
this.overflowFilterColumns = cols.filter((c) => overflow.has(c.key));
|
|
12544
|
+
if (!this.overflowFilterColumns.length) {
|
|
12545
|
+
this.showFilterOverflow = false;
|
|
12546
|
+
}
|
|
12547
|
+
}
|
|
12548
|
+
// ---------------------------------------------------------------- columns
|
|
12549
|
+
buildColumns() {
|
|
12550
|
+
this._initialColumns = this._rawColumns.map((c) => ({ ...c }));
|
|
12551
|
+
this.allColumns = this.svc.applyPersistedState(this._rawColumns);
|
|
12552
|
+
this.updateVisible();
|
|
12553
|
+
// start with every filter control visible; the overflow pass collapses to fit
|
|
12554
|
+
this.visibleFilterColumns = this.filterableColumns;
|
|
12555
|
+
this.overflowFilterColumns = [];
|
|
12556
|
+
this.filtersDirty = true;
|
|
12557
|
+
this.scheduleFilterOverflow();
|
|
12558
|
+
}
|
|
12559
|
+
updateVisible() {
|
|
12560
|
+
this.visibleColumns = this.allColumns.filter((c) => !c.hidden);
|
|
12561
|
+
this.hiddenColumns = this.allColumns
|
|
12562
|
+
.filter((c) => c.hidden)
|
|
12563
|
+
.map((c) => ({ ...c, headerName: c.label }));
|
|
12564
|
+
}
|
|
12565
|
+
colWidth(col) {
|
|
12566
|
+
return col.width != null ? `${col.width}px` : null;
|
|
12567
|
+
}
|
|
12568
|
+
// ---------------------------------------------------------------- cells
|
|
12569
|
+
rawValue(col, row) {
|
|
12570
|
+
return _.get(row, col.field || col.key);
|
|
12571
|
+
}
|
|
12572
|
+
cellContext(col, row, i) {
|
|
12573
|
+
return {
|
|
12574
|
+
row,
|
|
12575
|
+
value: this.rawValue(col, row),
|
|
12576
|
+
colId: col.key,
|
|
12577
|
+
rowIndex: i,
|
|
12578
|
+
emitAction: (action, item = row) => this.actionRequested.emit({ action, item }),
|
|
12579
|
+
};
|
|
12580
|
+
}
|
|
12581
|
+
legacyShim(col, row, i) {
|
|
12582
|
+
return { data: row, value: this.rawValue(col, row), column: { colId: col.key }, rowIndex: i };
|
|
12583
|
+
}
|
|
12584
|
+
renderMode(col) {
|
|
12585
|
+
if (col.cell) {
|
|
12586
|
+
return 'component';
|
|
12587
|
+
}
|
|
12588
|
+
if (col.cellHtml) {
|
|
12589
|
+
return 'html';
|
|
12590
|
+
}
|
|
12591
|
+
return 'text';
|
|
12592
|
+
}
|
|
12593
|
+
cellInputs(col, row, i) {
|
|
12594
|
+
if (col.cellInputs) {
|
|
12595
|
+
return col.cellInputs(this.cellContext(col, row, i));
|
|
12596
|
+
}
|
|
12597
|
+
return { row, value: this.rawValue(col, row) };
|
|
12598
|
+
}
|
|
12599
|
+
cellHtml(col, row, i) {
|
|
12600
|
+
return col.cellHtml ? col.cellHtml(this.legacyShim(col, row, i)) : '';
|
|
12601
|
+
}
|
|
12602
|
+
cellText(col, row, i) {
|
|
12603
|
+
if (col.valueFormatter) {
|
|
12604
|
+
return col.valueFormatter(this.legacyShim(col, row, i));
|
|
12605
|
+
}
|
|
12606
|
+
return this.rawValue(col, row);
|
|
12607
|
+
}
|
|
12608
|
+
cellClass(col) {
|
|
12609
|
+
return col.cellClass || '';
|
|
12610
|
+
}
|
|
12611
|
+
onCellClick(col, row, i) {
|
|
12612
|
+
col.onCellClick?.(this.cellContext(col, row, i));
|
|
12613
|
+
}
|
|
12614
|
+
tooltipInputs(col, row, i) {
|
|
12615
|
+
return col.tooltipInputs ? col.tooltipInputs(this.cellContext(col, row, i)) : { row };
|
|
12616
|
+
}
|
|
12617
|
+
onCellHover(col, row, i, event) {
|
|
12618
|
+
if (!col.tooltip) {
|
|
12619
|
+
return;
|
|
12620
|
+
}
|
|
12621
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
12622
|
+
this.hoverTooltip = {
|
|
12623
|
+
component: col.tooltip,
|
|
12624
|
+
inputs: this.tooltipInputs(col, row, i),
|
|
12625
|
+
left: rect.left,
|
|
12626
|
+
top: rect.bottom + 6,
|
|
12627
|
+
};
|
|
12628
|
+
}
|
|
12629
|
+
onCellLeave() {
|
|
12630
|
+
this.hoverTooltip = null;
|
|
12631
|
+
}
|
|
12632
|
+
/** Some rows selected but the header select-all isn't fully on (indeterminate). */
|
|
12633
|
+
get someSelected() {
|
|
12634
|
+
return !this.allToggled && _.some(this.rowData, { selected: true });
|
|
12635
|
+
}
|
|
12636
|
+
toggleAll() {
|
|
12637
|
+
const newState = !this.allToggled;
|
|
12638
|
+
this.allToggled = newState;
|
|
12639
|
+
_.forEach(this.rowData, (row) => {
|
|
12640
|
+
row.selected = newState;
|
|
12641
|
+
});
|
|
12642
|
+
this.actionRequested.emit({ action: 'toggleAll' });
|
|
12643
|
+
}
|
|
12644
|
+
// ---------------------------------------------------------------- sort
|
|
12645
|
+
onHeaderSort(event) {
|
|
12646
|
+
this.allColumns.forEach((c) => {
|
|
12647
|
+
c.sortDir = c.key === event.colId ? event.dir : undefined;
|
|
12648
|
+
});
|
|
12649
|
+
}
|
|
12650
|
+
// ---------------------------------------------------------------- hide / show / reorder
|
|
12651
|
+
hideColumn(col) {
|
|
12652
|
+
const target = this.allColumns.find((c) => c.key === col.key);
|
|
12653
|
+
if (!target) {
|
|
12654
|
+
return;
|
|
12655
|
+
}
|
|
12656
|
+
target.hidden = true;
|
|
12657
|
+
this.updateVisible();
|
|
12658
|
+
this.svc.saveState(this.allColumns);
|
|
12659
|
+
}
|
|
12660
|
+
showColumn(event) {
|
|
12661
|
+
const target = this.allColumns.find((c) => c.key === event.column?.key);
|
|
12662
|
+
if (!target) {
|
|
12663
|
+
return;
|
|
12664
|
+
}
|
|
12665
|
+
target.hidden = false;
|
|
12666
|
+
this.updateVisible();
|
|
12667
|
+
this.svc.saveState(this.allColumns);
|
|
12668
|
+
}
|
|
12669
|
+
onReorder(event) {
|
|
12670
|
+
if (event.previousIndex === event.currentIndex) {
|
|
12671
|
+
return;
|
|
12672
|
+
}
|
|
12673
|
+
moveItemInArray(this.visibleColumns, event.previousIndex, event.currentIndex);
|
|
12674
|
+
const nextVisible = [...this.visibleColumns];
|
|
12675
|
+
let vi = 0;
|
|
12676
|
+
this.allColumns = this.allColumns.map((c) => (c.hidden ? c : nextVisible[vi++]));
|
|
12677
|
+
this.updateVisible();
|
|
12678
|
+
this.svc.saveState(this.allColumns);
|
|
12679
|
+
}
|
|
12680
|
+
resetTableColumns() {
|
|
12681
|
+
this.svc.reset();
|
|
12682
|
+
this.allColumns = this._initialColumns.map((c) => ({ ...c }));
|
|
12683
|
+
this.updateVisible();
|
|
12684
|
+
this.closeActionMenu();
|
|
12685
|
+
}
|
|
12686
|
+
// ---------------------------------------------------------------- column chooser
|
|
12687
|
+
/** Count of columns the user has hidden beyond the defaults (drives the badge).
|
|
12688
|
+
* Columns hidden by default don't count, so a fresh/default load shows no badge. */
|
|
12689
|
+
get hiddenColumnCount() {
|
|
12690
|
+
return this.allColumns.filter((c) => c.hidden && !this.isDefaultHidden(c)).length;
|
|
12691
|
+
}
|
|
12692
|
+
/** True when visibility + order match the originally declared columns. */
|
|
12693
|
+
get columnsAtDefault() {
|
|
12694
|
+
if (this.allColumns.length !== this._initialColumns.length) {
|
|
12695
|
+
return false;
|
|
12696
|
+
}
|
|
12697
|
+
return this.allColumns.every((c, i) => {
|
|
12698
|
+
const init = this._initialColumns[i];
|
|
12699
|
+
return init && init.key === c.key && !!init.hidden === !!c.hidden;
|
|
12700
|
+
});
|
|
12701
|
+
}
|
|
12702
|
+
/** True when the column is hidden in the originally declared defaults. */
|
|
12703
|
+
isDefaultHidden(col) {
|
|
12704
|
+
const init = this._initialColumns.find((c) => c.key === col.key);
|
|
12705
|
+
return !!init?.hidden;
|
|
12706
|
+
}
|
|
12707
|
+
toggleColumnChooser(event) {
|
|
12708
|
+
event.stopPropagation();
|
|
12709
|
+
this.showColumnChooser = !this.showColumnChooser;
|
|
12710
|
+
if (this.showColumnChooser) {
|
|
12711
|
+
this.svc.notifyMenuOpened(this);
|
|
12712
|
+
}
|
|
12713
|
+
}
|
|
12714
|
+
closeColumnChooser() {
|
|
12715
|
+
this.showColumnChooser = false;
|
|
12716
|
+
}
|
|
12717
|
+
toggleColumnVisible(col) {
|
|
12718
|
+
if (col.hideable === false) {
|
|
12719
|
+
return;
|
|
12720
|
+
}
|
|
12721
|
+
const target = this.allColumns.find((c) => c.key === col.key);
|
|
12722
|
+
if (!target) {
|
|
12723
|
+
return;
|
|
12724
|
+
}
|
|
12725
|
+
target.hidden = !target.hidden;
|
|
12726
|
+
this.updateVisible();
|
|
12727
|
+
this.svc.saveState(this.allColumns);
|
|
12728
|
+
}
|
|
12729
|
+
chooserReorder(event) {
|
|
12730
|
+
if (event.previousIndex === event.currentIndex) {
|
|
12731
|
+
return;
|
|
12732
|
+
}
|
|
12733
|
+
moveItemInArray(this.allColumns, event.previousIndex, event.currentIndex);
|
|
12734
|
+
this.updateVisible();
|
|
12735
|
+
this.svc.saveState(this.allColumns);
|
|
12736
|
+
}
|
|
12737
|
+
// ---------------------------------------------------------------- resize
|
|
12738
|
+
startResize(col, event) {
|
|
12739
|
+
if (col.resizable === false) {
|
|
12740
|
+
return;
|
|
12741
|
+
}
|
|
12742
|
+
event.preventDefault();
|
|
12743
|
+
event.stopPropagation();
|
|
12744
|
+
const th = event.target?.closest('th');
|
|
12745
|
+
const startWidth = col.width ?? th?.offsetWidth ?? 150;
|
|
12746
|
+
this.resizing = { col, startX: event.clientX, startWidth };
|
|
12747
|
+
document.addEventListener('pointermove', this.onPointerMove);
|
|
12748
|
+
document.addEventListener('pointerup', this.onPointerUp);
|
|
12749
|
+
}
|
|
12750
|
+
handleResizeMove(event) {
|
|
12751
|
+
if (!this.resizing) {
|
|
12752
|
+
return;
|
|
12753
|
+
}
|
|
12754
|
+
const delta = event.clientX - this.resizing.startX;
|
|
12755
|
+
const min = this.resizing.col.minWidth ?? 40;
|
|
12756
|
+
this.resizing.col.width = Math.max(min, Math.round(this.resizing.startWidth + delta));
|
|
12757
|
+
}
|
|
12758
|
+
handleResizeEnd() {
|
|
12759
|
+
if (this.resizing) {
|
|
12760
|
+
this.svc.saveWidth(this.resizing.col.key, this.resizing.col.width, this.allColumns);
|
|
12761
|
+
}
|
|
12762
|
+
this.resizing = undefined;
|
|
12763
|
+
this.detachResizeListeners();
|
|
12764
|
+
}
|
|
12765
|
+
detachResizeListeners() {
|
|
12766
|
+
document.removeEventListener('pointermove', this.onPointerMove);
|
|
12767
|
+
document.removeEventListener('pointerup', this.onPointerUp);
|
|
12768
|
+
}
|
|
12769
|
+
openHeaderActionMenu(event) {
|
|
12770
|
+
this.menuLeft = event.clientX - 150;
|
|
12771
|
+
this.menuTop = event.clientY + 5;
|
|
12772
|
+
_.delay(() => {
|
|
12773
|
+
this.openHeaderMenu = true;
|
|
12774
|
+
}, 100);
|
|
12775
|
+
}
|
|
12776
|
+
hideMenuItem(menuItem, selectedItem) {
|
|
12777
|
+
if (_.isFunction(menuItem.hidden)) {
|
|
12778
|
+
return menuItem.hidden(selectedItem);
|
|
12779
|
+
}
|
|
12780
|
+
else if (_.isBoolean(menuItem.hidden)) {
|
|
12781
|
+
return menuItem.hidden;
|
|
12782
|
+
}
|
|
12783
|
+
return !selectedItem.actionList?.includes(menuItem.action);
|
|
12784
|
+
}
|
|
12785
|
+
/** Header action menu rows: the reset action followed by host-provided header actions.
|
|
12786
|
+
* A host action's `icon` (SVG markup) is rendered before its label, like the row menu. */
|
|
12787
|
+
get headerMenuItems() {
|
|
12788
|
+
const items = [
|
|
12789
|
+
{ label: 'Restore Default Table', action: '__reset_table__', id: 'ResetTableButton', iconSvg: this.safeIcon(this.RESET_TABLE_ICON) },
|
|
12790
|
+
];
|
|
12791
|
+
_.forEach(this.headerActions, (ha) => {
|
|
12792
|
+
items.push({
|
|
12793
|
+
label: ha.name || ha.label,
|
|
12794
|
+
action: ha.action,
|
|
12795
|
+
id: 'HeaderAction_' + ha.action,
|
|
12796
|
+
iconSvg: ha.icon ? this.safeIcon(ha.icon) : undefined,
|
|
12797
|
+
data: ha,
|
|
12798
|
+
});
|
|
12799
|
+
});
|
|
12800
|
+
return items;
|
|
12801
|
+
}
|
|
12802
|
+
onHeaderMenuClick(evt) {
|
|
12803
|
+
if (evt.item.action === '__reset_table__') {
|
|
12804
|
+
this.resetTableColumns();
|
|
12805
|
+
}
|
|
12806
|
+
else {
|
|
12807
|
+
this.actionRequested.emit({ action: evt.item.action });
|
|
12808
|
+
}
|
|
12809
|
+
this.closeHeaderActionMenu();
|
|
12810
|
+
}
|
|
12811
|
+
/** Row action menu rows, built from `menuItems` against the currently selected row.
|
|
12812
|
+
* A menu item's `icon` (SVG markup) is rendered before its label in the menu. */
|
|
12813
|
+
get rowMenuItems() {
|
|
12814
|
+
return _.map(this.menuItems, (mi) => ({
|
|
12815
|
+
label: mi.name || mi.label,
|
|
12816
|
+
action: mi.action,
|
|
12817
|
+
id: 'TableActionButton_' + mi.action,
|
|
12818
|
+
hidden: this.hideMenuItem(mi, this.selectedItem),
|
|
12819
|
+
iconSvg: mi.icon ? this.safeIcon(mi.icon) : undefined,
|
|
12820
|
+
data: mi,
|
|
12821
|
+
}));
|
|
12822
|
+
}
|
|
12823
|
+
onRowMenuClick(evt) {
|
|
12824
|
+
this.actionRequested.emit({ action: evt.item.action, item: this.selectedItem });
|
|
12825
|
+
this.closeActionMenu();
|
|
12826
|
+
}
|
|
12827
|
+
openCreate() {
|
|
12828
|
+
this.actionRequested.emit({ action: 'create' });
|
|
12829
|
+
}
|
|
12830
|
+
// ---------------------------------------------------------------- toolbar search + pagination
|
|
12831
|
+
onSearchInput() {
|
|
12832
|
+
this.inputChangedDebounced();
|
|
12833
|
+
}
|
|
12834
|
+
applySearch() {
|
|
12835
|
+
this.tableFilterService.currentPage = 1;
|
|
12836
|
+
this.tableFilterService.updateFilter({
|
|
12837
|
+
filterName: this.filterName,
|
|
12838
|
+
columnId: this.filterColumn,
|
|
12839
|
+
value: this.searchString,
|
|
12840
|
+
label: this.searchString,
|
|
12841
|
+
});
|
|
12842
|
+
}
|
|
12843
|
+
nextPage() {
|
|
12844
|
+
if (this.nextDisabled) {
|
|
12845
|
+
return;
|
|
12846
|
+
}
|
|
12847
|
+
this.tableFilterService.changePage((this.tableFilterService.currentPage || 1) + 1);
|
|
12848
|
+
}
|
|
12849
|
+
prevPage() {
|
|
12850
|
+
if (this.prevDisabled) {
|
|
12851
|
+
return;
|
|
12852
|
+
}
|
|
12853
|
+
this.tableFilterService.changePage((this.tableFilterService.currentPage || 1) - 1);
|
|
12854
|
+
}
|
|
12855
|
+
get nextDisabled() {
|
|
12856
|
+
if (!_.isNumber(this.totalCount) || !_.isNumber(this.endCount) || this.filtering) {
|
|
12857
|
+
return true;
|
|
12858
|
+
}
|
|
12859
|
+
return Number(this.endCount) >= Number(this.totalCount);
|
|
12860
|
+
}
|
|
12861
|
+
get prevDisabled() {
|
|
12862
|
+
if (!_.isNumber(this.startCount) || !_.isNumber(this.totalCount) || this.filtering) {
|
|
12863
|
+
return true;
|
|
12864
|
+
}
|
|
12865
|
+
return Number(this.startCount) <= 1;
|
|
12866
|
+
}
|
|
12867
|
+
get pageSize() {
|
|
12868
|
+
return this.tableFilterService.pageSize;
|
|
12869
|
+
}
|
|
12870
|
+
get currentPageNum() {
|
|
12871
|
+
return this.tableFilterService.currentPage || 1;
|
|
12872
|
+
}
|
|
12873
|
+
get totalPages() {
|
|
12874
|
+
if (!_.isNumber(this.totalCount) || Number(this.totalCount) <= 0) {
|
|
12875
|
+
return 1;
|
|
12876
|
+
}
|
|
12877
|
+
return Math.max(1, Math.ceil(Number(this.totalCount) / this.pageSize));
|
|
12878
|
+
}
|
|
12879
|
+
/** Page numbers to render, with `0` marking a gap ("..."). Shows the first and
|
|
12880
|
+
* last page plus a window around the current page so long lists stay compact. */
|
|
12881
|
+
get pageWindow() {
|
|
12882
|
+
const total = this.totalPages;
|
|
12883
|
+
const cur = this.currentPageNum;
|
|
12884
|
+
if (total <= 7) {
|
|
12885
|
+
return Array.from({ length: total }, (_v, i) => i + 1);
|
|
12886
|
+
}
|
|
12887
|
+
const pages = new Set([1, total, cur, cur - 1, cur + 1]);
|
|
12888
|
+
const sorted = [...pages].filter((p) => p >= 1 && p <= total).sort((a, b) => a - b);
|
|
12889
|
+
const out = [];
|
|
12890
|
+
let prev = 0;
|
|
12891
|
+
for (const p of sorted) {
|
|
12892
|
+
if (prev && p - prev > 1) {
|
|
12893
|
+
out.push(0); // gap sentinel
|
|
12894
|
+
}
|
|
12895
|
+
out.push(p);
|
|
12896
|
+
prev = p;
|
|
12897
|
+
}
|
|
12898
|
+
return out;
|
|
12899
|
+
}
|
|
12900
|
+
goToPage(page) {
|
|
12901
|
+
if (page < 1 || page > this.totalPages || page === this.currentPageNum || this.filtering) {
|
|
12902
|
+
return;
|
|
12903
|
+
}
|
|
12904
|
+
this.tableFilterService.changePage(page);
|
|
12905
|
+
}
|
|
12906
|
+
onPageSizeChange(size) {
|
|
12907
|
+
if (!size || size === this.pageSize) {
|
|
12908
|
+
return;
|
|
12909
|
+
}
|
|
12910
|
+
this.svc.savePageSize(size);
|
|
12911
|
+
this.tableFilterService.changePageSize(size);
|
|
12912
|
+
}
|
|
12913
|
+
/** Re-fetch the current page (re-emits the page so the host reloads its data). */
|
|
12914
|
+
refresh() {
|
|
12915
|
+
if (this.filtering) {
|
|
12916
|
+
return;
|
|
12917
|
+
}
|
|
12918
|
+
this.tableFilterService.changePage(this.currentPageNum);
|
|
12919
|
+
}
|
|
12920
|
+
toggleAutoRefresh() {
|
|
12921
|
+
this.autoRefresh = !this.autoRefresh;
|
|
12922
|
+
if (this.autoRefresh) {
|
|
12923
|
+
this.autoRefreshTimer = setInterval(() => this.ngZone.run(() => this.refresh()), this.autoRefreshIntervalMs);
|
|
12924
|
+
}
|
|
12925
|
+
else if (this.autoRefreshTimer) {
|
|
12926
|
+
clearInterval(this.autoRefreshTimer);
|
|
12927
|
+
this.autoRefreshTimer = undefined;
|
|
12928
|
+
}
|
|
12929
|
+
}
|
|
12930
|
+
safeIcon(svg) {
|
|
12931
|
+
let safe = this.iconCache.get(svg);
|
|
12932
|
+
if (!safe) {
|
|
12933
|
+
safe = this.sanitizer.bypassSecurityTrustHtml(svg);
|
|
12934
|
+
this.iconCache.set(svg, safe);
|
|
12935
|
+
}
|
|
12936
|
+
return safe;
|
|
12937
|
+
}
|
|
12938
|
+
updateEntityTypeLabel() {
|
|
12939
|
+
const map = {
|
|
12940
|
+
'api-sessions': 'API Sessions',
|
|
12941
|
+
'auth-policies': 'Auth Policies',
|
|
12942
|
+
'certificate-authorities': 'Certificate Authorities',
|
|
12943
|
+
'ext-jwt-signers': 'External JWT Signers',
|
|
12944
|
+
identities: 'Identities',
|
|
12945
|
+
'posture-checks': 'Posture Checks',
|
|
12946
|
+
'edge-routers': 'Edge Routers',
|
|
12947
|
+
services: 'Services',
|
|
12948
|
+
configurations: 'Configs',
|
|
12949
|
+
'config-types': 'Config Types',
|
|
12950
|
+
'service-policies': 'Service Policies',
|
|
12951
|
+
'edge-router-policies': 'Edge Router Policies',
|
|
12952
|
+
'service-edge-router-policies': 'Service Edge Router Policies',
|
|
12953
|
+
sessions: 'Sessions',
|
|
12954
|
+
terminators: 'Terminators',
|
|
12955
|
+
'transit-routers': 'Transit Routers',
|
|
12956
|
+
};
|
|
12957
|
+
this.entityTypeLabel = map[this._tableId] || this.entityTypeName || '';
|
|
12958
|
+
}
|
|
12959
|
+
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 }); }
|
|
12960
|
+
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", 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 <button\n type=\"button\"\n class=\"lt-autorefresh-btn\"\n [class.is-on]=\"autoRefresh\"\n (click)=\"toggleAutoRefresh()\"\n [attr.aria-pressed]=\"autoRefresh\"\n id=\"AutoRefreshButton\"\n >\n <ng-container [ngTemplateOutlet]=\"refreshIcon\"></ng-container>\n <span>Auto-refresh: {{ autoRefresh ? 'On' : 'Off' }}</span>\n </button>\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 allColumns; 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 @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 <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-autorefresh-btn,.lt-refresh-btn,.lt-filter-more-btn{display:inline-flex;align-items:center;gap:.4375rem;height:var(--lt-toolbar-height);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: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-autorefresh-btn svg,.lt-refresh-btn svg,.lt-filter-more-btn svg{display:block}.lt-columns-btn:hover,.lt-autorefresh-btn:hover,.lt-refresh-btn:hover,.lt-filter-more-btn:hover,.is-open.lt-columns-btn,.is-open.lt-autorefresh-btn,.is-open.lt-refresh-btn,.is-open.lt-filter-more-btn,.is-on.lt-columns-btn,.is-on.lt-autorefresh-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: i3$1.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: 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"] }] }); }
|
|
12961
|
+
}
|
|
12962
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ListTableComponent, decorators: [{
|
|
12963
|
+
type: Component,
|
|
12964
|
+
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 <button\n type=\"button\"\n class=\"lt-autorefresh-btn\"\n [class.is-on]=\"autoRefresh\"\n (click)=\"toggleAutoRefresh()\"\n [attr.aria-pressed]=\"autoRefresh\"\n id=\"AutoRefreshButton\"\n >\n <ng-container [ngTemplateOutlet]=\"refreshIcon\"></ng-container>\n <span>Auto-refresh: {{ autoRefresh ? 'On' : 'Off' }}</span>\n </button>\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 allColumns; 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 @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 <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-autorefresh-btn,.lt-refresh-btn,.lt-filter-more-btn{display:inline-flex;align-items:center;gap:.4375rem;height:var(--lt-toolbar-height);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: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-autorefresh-btn svg,.lt-refresh-btn svg,.lt-filter-more-btn svg{display:block}.lt-columns-btn:hover,.lt-autorefresh-btn:hover,.lt-refresh-btn:hover,.lt-filter-more-btn:hover,.is-open.lt-columns-btn,.is-open.lt-autorefresh-btn,.is-open.lt-refresh-btn,.is-open.lt-filter-more-btn,.is-on.lt-columns-btn,.is-on.lt-autorefresh-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"] }]
|
|
12965
|
+
}], ctorParameters: () => [{ type: ListTableService }, { type: DataTableFilterService }, { type: i0.ElementRef }, { type: i0.NgZone }, { type: i1.DomSanitizer }], propDecorators: { tableId: [{
|
|
12966
|
+
type: Input
|
|
12967
|
+
}], columns: [{
|
|
12968
|
+
type: Input
|
|
12969
|
+
}], rowData: [{
|
|
12970
|
+
type: Input
|
|
12971
|
+
}], isLoading: [{
|
|
12972
|
+
type: Input
|
|
12973
|
+
}], options: [{
|
|
12974
|
+
type: Input
|
|
12975
|
+
}], startCount: [{
|
|
12976
|
+
type: Input
|
|
12977
|
+
}], endCount: [{
|
|
12978
|
+
type: Input
|
|
12979
|
+
}], totalCount: [{
|
|
12980
|
+
type: Input
|
|
12981
|
+
}], filterApplied: [{
|
|
12982
|
+
type: Input
|
|
12983
|
+
}], menuItems: [{
|
|
12984
|
+
type: Input
|
|
12985
|
+
}], headerActions: [{
|
|
12986
|
+
type: Input
|
|
12987
|
+
}], noItemsImage: [{
|
|
12988
|
+
type: Input
|
|
12989
|
+
}], showNoItemsAdd: [{
|
|
12990
|
+
type: Input
|
|
12991
|
+
}], noItemsReadonly: [{
|
|
12992
|
+
type: Input
|
|
12993
|
+
}], accessDenied: [{
|
|
12994
|
+
type: Input
|
|
12995
|
+
}], entityTypeName: [{
|
|
12996
|
+
type: Input
|
|
12997
|
+
}], filterName: [{
|
|
12998
|
+
type: Input
|
|
12999
|
+
}], filterColumn: [{
|
|
13000
|
+
type: Input
|
|
13001
|
+
}], actionRequested: [{
|
|
13002
|
+
type: Output
|
|
13003
|
+
}], tableReady: [{
|
|
13004
|
+
type: Output
|
|
13005
|
+
}], contextMenu: [{
|
|
13006
|
+
type: ViewChild,
|
|
13007
|
+
args: ['contextMenu']
|
|
13008
|
+
}], filterZone: [{
|
|
13009
|
+
type: ViewChild,
|
|
13010
|
+
args: ['filterZone']
|
|
13011
|
+
}], filtersRow: [{
|
|
13012
|
+
type: ViewChild,
|
|
13013
|
+
args: ['filtersRow']
|
|
13014
|
+
}], initialPageSize: [{
|
|
13015
|
+
type: Input
|
|
13016
|
+
}] } });
|
|
13017
|
+
|
|
10772
13018
|
class Link {
|
|
10773
13019
|
constructor() {
|
|
10774
13020
|
this.statusReason = null;
|
|
@@ -12828,11 +15074,11 @@ class SideModalComponent {
|
|
|
12828
15074
|
this.openChange.emit(this.open);
|
|
12829
15075
|
}
|
|
12830
15076
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: SideModalComponent, deps: [{ token: ConsoleEventsService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
12831
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: SideModalComponent, isStandalone: false, selector: "lib-side-modal", inputs: { showClose: "showClose", open: "open" }, outputs: { openChange: "openChange" }, ngImport: i0, template: "<div class=\"side-modal-container\" [ngClass]=\"{'side-modal-open': open}\">\n @if (showClose) {\n <div class=\"close icon-close\" (click)=\"close()\"></div>\n }\n <ng-content></ng-content>\n</div>\n\n", styles: [".side-modal-container{position:fixed;right:-
|
|
15077
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: SideModalComponent, isStandalone: false, selector: "lib-side-modal", inputs: { showClose: "showClose", open: "open" }, outputs: { openChange: "openChange" }, ngImport: i0, template: "<div class=\"side-modal-container\" [ngClass]=\"{'side-modal-open': open}\">\n @if (showClose) {\n <div class=\"close icon-close\" (click)=\"close()\"></div>\n }\n <ng-content></ng-content>\n</div>\n\n", styles: [".side-modal-container{position:fixed;right:-42rem;top:0;padding:1.875rem;height:100%;width:30%;min-width:28.125rem;max-width:37.5rem;overflow-y:auto;transition:right .3s ease-in-out;z-index:999999;background-color:var(--formBackground);box-shadow:-.25rem 0 1.25rem #0003;border-left:.0625rem solid var(--tableBorder)}.side-modal-container.side-modal-open{right:0}.side-modal-container .close{position:absolute;top:1rem;right:1rem;font-size:1.5rem;cursor:pointer;color:var(--tableText);transition:all .2s ease;z-index:10}.side-modal-container .close:hover{color:var(--primary);transform:scale(1.1)}::ng-deep .sideNavClosed .side-modal-container.side-modal-open{right:0}\n"], dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
|
|
12832
15078
|
}
|
|
12833
15079
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: SideModalComponent, decorators: [{
|
|
12834
15080
|
type: Component,
|
|
12835
|
-
args: [{ selector: 'lib-side-modal', standalone: false, template: "<div class=\"side-modal-container\" [ngClass]=\"{'side-modal-open': open}\">\n @if (showClose) {\n <div class=\"close icon-close\" (click)=\"close()\"></div>\n }\n <ng-content></ng-content>\n</div>\n\n", styles: [".side-modal-container{position:fixed;right:-
|
|
15081
|
+
args: [{ selector: 'lib-side-modal', standalone: false, template: "<div class=\"side-modal-container\" [ngClass]=\"{'side-modal-open': open}\">\n @if (showClose) {\n <div class=\"close icon-close\" (click)=\"close()\"></div>\n }\n <ng-content></ng-content>\n</div>\n\n", styles: [".side-modal-container{position:fixed;right:-42rem;top:0;padding:1.875rem;height:100%;width:30%;min-width:28.125rem;max-width:37.5rem;overflow-y:auto;transition:right .3s ease-in-out;z-index:999999;background-color:var(--formBackground);box-shadow:-.25rem 0 1.25rem #0003;border-left:.0625rem solid var(--tableBorder)}.side-modal-container.side-modal-open{right:0}.side-modal-container .close{position:absolute;top:1rem;right:1rem;font-size:1.5rem;cursor:pointer;color:var(--tableText);transition:all .2s ease;z-index:10}.side-modal-container .close:hover{color:var(--primary);transform:scale(1.1)}::ng-deep .sideNavClosed .side-modal-container.side-modal-open{right:0}\n"] }]
|
|
12836
15082
|
}], ctorParameters: () => [{ type: ConsoleEventsService }], propDecorators: { showClose: [{
|
|
12837
15083
|
type: Input
|
|
12838
15084
|
}], open: [{
|
|
@@ -13317,6 +15563,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
13317
15563
|
See the License for the specific language governing permissions and
|
|
13318
15564
|
limitations under the License.
|
|
13319
15565
|
*/
|
|
15566
|
+
/**
|
|
15567
|
+
* Legacy Identities page (ag-grid `lib-data-table`). Selected by the route when the
|
|
15568
|
+
* "Beta Features" flag is off. Slated for removal once the new list-table page (see
|
|
15569
|
+
* {@link IdentitiesListPageComponent}) graduates — at which point this file and its
|
|
15570
|
+
* template are deleted outright.
|
|
15571
|
+
*/
|
|
13320
15572
|
class IdentitiesPageComponent extends ListPageComponent {
|
|
13321
15573
|
constructor(svc, filterService, dialogForm, tabNames, router, consoleEvents, extService) {
|
|
13322
15574
|
super(filterService, svc, consoleEvents, dialogForm, extService);
|
|
@@ -13513,6 +15765,231 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
13513
15765
|
args: [IDENTITY_EXTENSION_SERVICE]
|
|
13514
15766
|
}] }] });
|
|
13515
15767
|
|
|
15768
|
+
/*
|
|
15769
|
+
Copyright NetFoundry Inc.
|
|
15770
|
+
|
|
15771
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
15772
|
+
you may not use this file except in compliance with the License.
|
|
15773
|
+
You may obtain a copy of the License at
|
|
15774
|
+
|
|
15775
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
15776
|
+
|
|
15777
|
+
Unless required by applicable law or agreed to in writing, software
|
|
15778
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
15779
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15780
|
+
See the License for the specific language governing permissions and
|
|
15781
|
+
limitations under the License.
|
|
15782
|
+
*/
|
|
15783
|
+
/**
|
|
15784
|
+
* New Identities page, rendered on the shared `lib-list-table`. Extends the common
|
|
15785
|
+
* {@link ListPageComponent} (which future list-table pages extend the same way).
|
|
15786
|
+
* Selected by the route when the "Beta Features" flag is on; the legacy ag-grid page
|
|
15787
|
+
* ({@link IdentitiesPageComponent}) handles the flag-off case. The two pages carry
|
|
15788
|
+
* their own copies of the identity actions during the migration so the legacy one can
|
|
15789
|
+
* be deleted outright once this graduates.
|
|
15790
|
+
*/
|
|
15791
|
+
class IdentitiesListPageComponent extends ListPageComponent {
|
|
15792
|
+
constructor(svc, filterService, dialogForm, tabNames, router, consoleEvents, extService) {
|
|
15793
|
+
super(filterService, svc, consoleEvents, dialogForm, extService);
|
|
15794
|
+
this.svc = svc;
|
|
15795
|
+
this.tabNames = tabNames;
|
|
15796
|
+
this.router = router;
|
|
15797
|
+
this.extService = extService;
|
|
15798
|
+
this.title = 'Identities';
|
|
15799
|
+
this.isLoading = false;
|
|
15800
|
+
this.formDataChanged = false;
|
|
15801
|
+
this.tableId = 'identities';
|
|
15802
|
+
this.initialPageSize = 50;
|
|
15803
|
+
}
|
|
15804
|
+
/** The new table consumes the declarative ListColumn set. */
|
|
15805
|
+
loadTableColumns() {
|
|
15806
|
+
return this.svc.initListTableColumns();
|
|
15807
|
+
}
|
|
15808
|
+
ngOnInit() {
|
|
15809
|
+
this.tabs = this.tabNames.getTabs('identities');
|
|
15810
|
+
this.svc.refreshData = this.refreshData;
|
|
15811
|
+
this.subscription.add(this.router.events.subscribe((event) => {
|
|
15812
|
+
if (event instanceof NavigationEnd) {
|
|
15813
|
+
this.refreshData();
|
|
15814
|
+
}
|
|
15815
|
+
}));
|
|
15816
|
+
this.svc.getIdentityRoleAttributes();
|
|
15817
|
+
super.ngOnInit();
|
|
15818
|
+
}
|
|
15819
|
+
headerActionClicked(action) {
|
|
15820
|
+
switch (action) {
|
|
15821
|
+
case 'add':
|
|
15822
|
+
this.svc.openEditForm();
|
|
15823
|
+
break;
|
|
15824
|
+
case 'edit':
|
|
15825
|
+
this.svc.openUpdate();
|
|
15826
|
+
break;
|
|
15827
|
+
case 'delete':
|
|
15828
|
+
const selectedItems = this.rowData.filter((row) => {
|
|
15829
|
+
return row.selected;
|
|
15830
|
+
});
|
|
15831
|
+
const label = selectedItems.length > 1 ? 'identities' : 'identity';
|
|
15832
|
+
this.openBulkDelete(selectedItems, label);
|
|
15833
|
+
break;
|
|
15834
|
+
default:
|
|
15835
|
+
}
|
|
15836
|
+
}
|
|
15837
|
+
closeModal(event) {
|
|
15838
|
+
this.svc.sideModalOpen = false;
|
|
15839
|
+
if (event?.refresh) {
|
|
15840
|
+
this.refreshData();
|
|
15841
|
+
this.svc.getIdentityRoleAttributes();
|
|
15842
|
+
}
|
|
15843
|
+
}
|
|
15844
|
+
dataChanged(event) {
|
|
15845
|
+
this.formDataChanged = event;
|
|
15846
|
+
}
|
|
15847
|
+
tableAction(event) {
|
|
15848
|
+
const extensionActionFound = this.handleExtensionActions(event);
|
|
15849
|
+
this.trackMenuAction(event?.action, event?.item);
|
|
15850
|
+
if (extensionActionFound) {
|
|
15851
|
+
return;
|
|
15852
|
+
}
|
|
15853
|
+
switch (event?.action) {
|
|
15854
|
+
case 'toggleAll':
|
|
15855
|
+
this.itemToggled(event.item);
|
|
15856
|
+
this.rowData.forEach((item) => {
|
|
15857
|
+
if (item.typeId === 'Router') {
|
|
15858
|
+
item.selected = false;
|
|
15859
|
+
}
|
|
15860
|
+
});
|
|
15861
|
+
break;
|
|
15862
|
+
case 'toggleItem':
|
|
15863
|
+
this.itemToggled(event.item);
|
|
15864
|
+
break;
|
|
15865
|
+
case 'update':
|
|
15866
|
+
this.svc.openEditForm(event?.item?.id);
|
|
15867
|
+
break;
|
|
15868
|
+
case 'create':
|
|
15869
|
+
this.svc.openEditForm();
|
|
15870
|
+
break;
|
|
15871
|
+
case 'override':
|
|
15872
|
+
this.svc.openOverridesModal(event.item);
|
|
15873
|
+
break;
|
|
15874
|
+
case 'delete':
|
|
15875
|
+
this.deleteItem(event.item);
|
|
15876
|
+
break;
|
|
15877
|
+
case 'download-enrollment':
|
|
15878
|
+
this.downloadJWT(event.item);
|
|
15879
|
+
break;
|
|
15880
|
+
case 'reset-enrollment':
|
|
15881
|
+
this.resetEnrollment(event.item);
|
|
15882
|
+
break;
|
|
15883
|
+
case 'reissue-enrollment':
|
|
15884
|
+
this.reissueEnrollment(event.item);
|
|
15885
|
+
break;
|
|
15886
|
+
case "identity-service-path":
|
|
15887
|
+
this.openIdentityVisualizer(event.item);
|
|
15888
|
+
break;
|
|
15889
|
+
case "qr-code":
|
|
15890
|
+
this.showQRCode(event.item);
|
|
15891
|
+
break;
|
|
15892
|
+
case 'download-all':
|
|
15893
|
+
this.downloadAllItems();
|
|
15894
|
+
break;
|
|
15895
|
+
case 'download-selected':
|
|
15896
|
+
this.svc.downloadItems(this.selectedItems);
|
|
15897
|
+
break;
|
|
15898
|
+
case 'reset-mfa':
|
|
15899
|
+
this.isLoading = true;
|
|
15900
|
+
this.svc.resetMFA(event.item).finally(() => {
|
|
15901
|
+
this.isLoading = false;
|
|
15902
|
+
this.refreshData();
|
|
15903
|
+
});
|
|
15904
|
+
break;
|
|
15905
|
+
default:
|
|
15906
|
+
break;
|
|
15907
|
+
}
|
|
15908
|
+
}
|
|
15909
|
+
downloadJWT(item) {
|
|
15910
|
+
const jwt = this.svc.getJWT(item);
|
|
15911
|
+
this.svc.downloadJWT(jwt, item.name);
|
|
15912
|
+
}
|
|
15913
|
+
showQRCode(item) {
|
|
15914
|
+
const data = {
|
|
15915
|
+
jwt: this.svc.getJWT(item),
|
|
15916
|
+
expiration: this.svc.getEnrollmentExpiration(item),
|
|
15917
|
+
qrCodeSize: 500,
|
|
15918
|
+
identity: item,
|
|
15919
|
+
qrOnly: true,
|
|
15920
|
+
};
|
|
15921
|
+
this.dialogRef = this.dialogForm.open(QrCodeComponent, {
|
|
15922
|
+
data: data,
|
|
15923
|
+
autoFocus: false,
|
|
15924
|
+
});
|
|
15925
|
+
}
|
|
15926
|
+
trackMenuAction(action, item) {
|
|
15927
|
+
this.extService?.consoleActionTriggered?.emit({
|
|
15928
|
+
action,
|
|
15929
|
+
page: 'identity',
|
|
15930
|
+
item,
|
|
15931
|
+
type: 'menu-action'
|
|
15932
|
+
});
|
|
15933
|
+
}
|
|
15934
|
+
deleteItem(item) {
|
|
15935
|
+
this.openBulkDelete([item], 'identity');
|
|
15936
|
+
}
|
|
15937
|
+
openIdentityVisualizer(identity) {
|
|
15938
|
+
this.dialogRef = this.dialogForm.open(IdentityServicePathComponent, {
|
|
15939
|
+
data: {
|
|
15940
|
+
identity: identity,
|
|
15941
|
+
},
|
|
15942
|
+
autoFocus: false,
|
|
15943
|
+
});
|
|
15944
|
+
}
|
|
15945
|
+
resetEnrollment(identity) {
|
|
15946
|
+
this.dialogRef = this.dialogForm.open(ResetEnrollmentComponent, {
|
|
15947
|
+
data: {
|
|
15948
|
+
identity: identity,
|
|
15949
|
+
type: 'reset',
|
|
15950
|
+
},
|
|
15951
|
+
autoFocus: false,
|
|
15952
|
+
});
|
|
15953
|
+
this.dialogRef.afterClosed().subscribe((result) => {
|
|
15954
|
+
if (result) {
|
|
15955
|
+
this.refreshData(undefined, true);
|
|
15956
|
+
}
|
|
15957
|
+
});
|
|
15958
|
+
}
|
|
15959
|
+
reissueEnrollment(identity) {
|
|
15960
|
+
this.dialogRef = this.dialogForm.open(ResetEnrollmentComponent, {
|
|
15961
|
+
data: {
|
|
15962
|
+
identity: identity,
|
|
15963
|
+
type: 'reissue',
|
|
15964
|
+
},
|
|
15965
|
+
autoFocus: false,
|
|
15966
|
+
});
|
|
15967
|
+
this.dialogRef.afterClosed().subscribe((result) => {
|
|
15968
|
+
if (result) {
|
|
15969
|
+
this.refreshData(undefined, true);
|
|
15970
|
+
}
|
|
15971
|
+
});
|
|
15972
|
+
}
|
|
15973
|
+
ngOnDestroy() {
|
|
15974
|
+
super.ngOnDestroy();
|
|
15975
|
+
}
|
|
15976
|
+
canDeactivate() {
|
|
15977
|
+
if (this.formDataChanged && this.svc.sideModalOpen) {
|
|
15978
|
+
return confirm('You have unsaved changes. Do you want to leave this page and discard your changes or stay on this page?');
|
|
15979
|
+
}
|
|
15980
|
+
return true;
|
|
15981
|
+
}
|
|
15982
|
+
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 }); }
|
|
15983
|
+
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", "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"] }] }); }
|
|
15984
|
+
}
|
|
15985
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: IdentitiesListPageComponent, decorators: [{
|
|
15986
|
+
type: Component,
|
|
15987
|
+
args: [{ selector: 'lib-identities-list', standalone: false, 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"] }]
|
|
15988
|
+
}], ctorParameters: () => [{ type: IdentitiesPageService }, { type: DataTableFilterService }, { type: i5.MatDialog }, { type: TabNameService }, { type: i4.Router }, { type: ConsoleEventsService }, { type: undefined, decorators: [{
|
|
15989
|
+
type: Inject,
|
|
15990
|
+
args: [IDENTITY_EXTENSION_SERVICE]
|
|
15991
|
+
}] }] });
|
|
15992
|
+
|
|
13516
15993
|
class EdgeRoutersPageComponent extends ListPageComponent {
|
|
13517
15994
|
constructor(svc, filterService, dialogForm, tabNames, consoleEvents, extService) {
|
|
13518
15995
|
super(filterService, svc, consoleEvents, dialogForm);
|
|
@@ -19416,8 +21893,8 @@ class NetworkVisualizerComponent extends VisualizerServiceClass {
|
|
|
19416
21893
|
})
|
|
19417
21894
|
.append('xhtml:body')
|
|
19418
21895
|
.style('background', 'transparent')
|
|
19419
|
-
.html(
|
|
19420
|
-
return `<div class="node-text-container"><span>${d.data.name}</span></div>`;
|
|
21896
|
+
.html((d) => {
|
|
21897
|
+
return `<div class="node-text-container"><span>${this.escapeHtml(d.data.name)}</span></div>`;
|
|
19421
21898
|
});
|
|
19422
21899
|
this.nodeUpdate = this.nodeEnter.merge(this.node);
|
|
19423
21900
|
this.nodeUpdate
|
|
@@ -19636,7 +22113,11 @@ class NetworkVisualizerComponent extends VisualizerServiceClass {
|
|
|
19636
22113
|
this.treetooltip.style('top', y);
|
|
19637
22114
|
document.getElementById('tooltip').innerHTML = this.readTreeKeyValues(event, s);
|
|
19638
22115
|
}
|
|
22116
|
+
escapeHtml(value) {
|
|
22117
|
+
return String(value == null ? '' : value).replace(/[&<>"]/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[c]));
|
|
22118
|
+
}
|
|
19639
22119
|
readTreeKeyValues(event, d) {
|
|
22120
|
+
const self = this;
|
|
19640
22121
|
const startIndex = d.data.name.indexOf('(');
|
|
19641
22122
|
const finIndex = d.data.name.indexOf(')');
|
|
19642
22123
|
const countStr = startIndex > 0 ? d.data.name.substring(startIndex + 1, finIndex) : 0;
|
|
@@ -19665,14 +22146,14 @@ class NetworkVisualizerComponent extends VisualizerServiceClass {
|
|
|
19665
22146
|
info =
|
|
19666
22147
|
info +
|
|
19667
22148
|
'<div class="prop-row"><div class="prop-name">' +
|
|
19668
|
-
k +
|
|
22149
|
+
self.escapeHtml(k) +
|
|
19669
22150
|
':</div><div class="prop-val">' +
|
|
19670
|
-
d[k].join('<br> ') +
|
|
22151
|
+
d[k].map((v) => self.escapeHtml(v)).join('<br> ') +
|
|
19671
22152
|
'</div></div>';
|
|
19672
22153
|
}
|
|
19673
22154
|
else {
|
|
19674
22155
|
const propVal = d.data[k] || '';
|
|
19675
|
-
info = info + '<div class="prop-row"><div class="prop-name">' + k + ':</div><div class="prop-val">' + propVal + '</div></div>';
|
|
22156
|
+
info = info + '<div class="prop-row"><div class="prop-name">' + self.escapeHtml(k) + ':</div><div class="prop-val">' + self.escapeHtml(propVal) + '</div></div>';
|
|
19676
22157
|
}
|
|
19677
22158
|
});
|
|
19678
22159
|
if (d.data.firstChild && d.data.firstChild === 'Yes' && countStr > this.maxObjectsPerNode - 1) {
|
|
@@ -19888,13 +22369,16 @@ class EdgeRouterFormComponent extends ProjectableForm {
|
|
|
19888
22369
|
get tunnelerEnabledReadOnly() {
|
|
19889
22370
|
return this.config.isOpenZiti ? true : !this.isTunnelerDisabled();
|
|
19890
22371
|
}
|
|
22372
|
+
get isCustomerHosted() {
|
|
22373
|
+
return this.extService.disabledComponents.some(item => item.key === 'customer-hosted');
|
|
22374
|
+
}
|
|
19891
22375
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: EdgeRouterFormComponent, deps: [{ token: SETTINGS_SERVICE }, { token: EdgeRouterFormService }, { token: ZITI_DATA_SERVICE }, { token: GrowlerService }, { token: EDGE_ROUTER_EXTENSION_SERVICE }, { token: DEFAULT_APP_CONFIG }, { token: i4.Router }, { token: i4.ActivatedRoute }, { token: i1$1.Location }, { token: i5.MatDialog }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
19892
22376
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: EdgeRouterFormComponent, isStandalone: false, selector: "lib-edge-router-form", inputs: { edgeRouterRoleAttributes: "edgeRouterRoleAttributes" }, outputs: { close: "close" }, providers: [
|
|
19893
22377
|
{
|
|
19894
22378
|
provide: MatDialogRef,
|
|
19895
22379
|
useValue: {}
|
|
19896
22380
|
}
|
|
19897
|
-
], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div class=\"projectable-form-wrapper\"\n (keyup.enter)=\"save($event)\"\n (keyup.escape)=\"closeModal(false)\"\n [class.projectable-form-hidden]=\"!dataInit\"\n >\n <lib-form-header\n [data]=\"formData\"\n [title]=\"formData.id ? 'Edit Edge Router: ' : 'Create New Edge Router'\"\n [moreActions]=\"moreActions\"\n [multiActions]=\"multiActions\"\n (actionRequested)=\"headerActionRequested($event)\"\n (multiActionRequested)=\"multiActionRequested($event)\"\n [(formView)]=\"formView\"\n [class.is-scrolled]=\"isScrolled\"\n [saveDisabled]=\"formPermissionSaveDisabled\"\n [saveTooltip]=\"formPermissionSaveTooltip\"\n [strictReadonlyUi]=\"useStrictReadonlyForm\"\n ></lib-form-header>\n <ng-content select=\"[slot=tabs-slot]\"></ng-content>\n <div class=\"edge-router-form-container projectable-form-container\" #formContainer>\n @if (formView === 'simple') {\n <div class=\"projectable-form-main-column form-group-row\">\n <div class=\"form-group-column three-fifths\">\n <lib-form-field-container [title]=\"'Edge Router Name'\" [label]=\"useStrictReadonlyForm ? '' : 'REQUIRED'\">\n <input\n class=\"form-field-input\"\n placeholder=\"Name this edge router\"\n [ngClass]=\"{error: errors['name']}\"\n [(ngModel)]=\"formData.name\"\n autofocus\n #nameFieldInput\n [disabled]=\"useStrictReadonlyForm\"\n />\n </lib-form-field-container>\n <lib-form-field-container\n [title]=\"'Select or create Edge Router attributes'\"\n [label]=\"'OPTIONAL'\"\n [contentStyle]=\"'z-index: 99999999'\"\n [helpText]=\"'Attributes are tags applied to an resource. Apply the same tag to other Edge Routers to form a group of Edge Routers.'\"\n >\n <lib-tag-selector\n [disableField]=\"useStrictReadonlyForm\"\n [disableCreate]=\"useStrictReadonlyForm\"\n [(selectedRoleAttributes)]=\"formData.roleAttributes\"\n [availableRoleAttributes]=\"edgeRouterRoleAttributes\"\n [placeholder]=\"'Add attributes to group Edge Routers'\"\n ></lib-tag-selector>\n </lib-form-field-container>\n <ng-content select=\"[slot=column-1-slot-1]\"></ng-content>\n <lib-form-field-toggle [(toggleOn)]=\"showMore\" style=\"margin: 0px 10px\"></lib-form-field-toggle>\n @if (showMore) {\n <div class=\"form-group-column\">\n <lib-form-field-container\n [title]=\"'TUNNELER'\"\n [title2]=\"'TRAVERSAL'\"\n [layout]=\"'row'\"\n class=\"form-field-advanced\"\n >\n <div class=\"config-item\" [class.disabled]=\"!tunnelerEnabledReadOnly\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">TUNNELER ENABLED</div>\n <div (click)=\"tunnelerEnabledReadOnly && !useStrictReadonlyForm && toggleTunnelerEnabled()\"\n [ngClass]=\"{ on: formData.isTunnelerEnabled, disabled: !tunnelerEnabledReadOnly, 'toggle-readonly': useStrictReadonlyForm }\" class=\"toggle\"\n [matTooltip]=\"useStrictReadonlyForm ? '' : (!tunnelerEnabledReadOnly ? 'Disabled because already hosted by netfoundry ' : '')\"\n matTooltipPosition=\"above\" style=\"pointer-events: auto;\">\n <span [hidden]=\"!formData.isTunnelerEnabled\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.isTunnelerEnabled\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n <div class=\"config-item\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">ALLOW TRAVERSAL</div>\n <div\n (click)=\"!useStrictReadonlyForm && toggleNoTraversal()\"\n [ngClass]=\"{ on: !formData.noTraversal, 'toggle-readonly': useStrictReadonlyForm }\"\n class=\"toggle\"\n >\n <span [hidden]=\"formData.noTraversal\" class=\"on-label\">YES</span>\n <span [hidden]=\"!formData.noTraversal\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n </lib-form-field-container>\n @if (formData?.hostname || formData?.supportedProtocols?.tls || formData?.supportedProtocols?.wss) {\n <lib-form-field-container [showHeader]=\"false\">\n @if (formData?.hostname) {\n <div class=\"config-item\">\n <div class=\"config-item-label-container\">\n <span class=\"config-title\">Domain Name</span>\n </div>\n <div class=\"config-container domain-container\">\n <div class=\"config-container-label domain-label\">\n {{ formData?.hostname }}\n </div>\n </div>\n </div>\n }\n @if (formData?.supportedProtocols?.tls || formData?.supportedProtocols?.wss) {\n <div class=\"config-item\">\n <div class=\"config-item-label-container\">\n <span class=\"config-title\">ADVERTISE ADDRESS</span>\n </div>\n <div class=\"config-container advertise-address-container\">\n <div class=\"config-container-label advertise-address-label\">\n {{ formData?.supportedProtocols?.tls }}\n <br />\n {{ formData?.supportedProtocols?.wss }}\n </div>\n </div>\n </div>\n }\n </lib-form-field-container>\n }\n <lib-form-field-container\n [title]=\"'Custom Tags'\"\n [label]=\"'OPTIONAL'\"\n class=\"form-field-advanced\"\n >\n <lib-custom-tags [(tags)]=\"formData.tags\" [readOnly]=\"useStrictReadonlyForm\"></lib-custom-tags>\n </lib-form-field-container>\n <lib-form-field-container\n [title]=\"'App Data'\"\n [label]=\"'OPTIONAL'\"\n class=\"form-field-advanced\"\n >\n <lib-json-view [(data)]=\"formData.appData\" [readOnly]=\"useStrictReadonlyForm\"></lib-json-view>\n </lib-form-field-container>\n </div>\n }\n </div>\n <div class=\"form-group-column two-fifths\">\n <ng-content select=\"[slot=column-2-slot-1]\"></ng-content>\n @if (hasEnrolmentToken && !extService['hideZitiRegistration']) {\n <lib-form-field-container\n [showHeader]=\"false\"\n >\n <lib-qr-code\n [identity]=\"formData\"\n [jwt]=\"formData.enrollmentJwt\"\n [token]=\"formData.enrollmentToken\"\n [expiration]=\"formData.enrollmentExpiresAt\"\n (doRefresh)=\"refreshEdgeRouter()\"\n [type]=\"'router'\"\n ></lib-qr-code>\n </lib-form-field-container>\n }\n @if (formData.id) {\n <lib-form-field-container\n [title]=\"'Associated Services'\"\n [count]=\"svc.associatedServices.length\"\n [class]=\"'hide-overflow'\"\n [helpText]=\"'Preview list of all services that this Edge Router is associated with.'\"\n >\n <lib-preview-list\n [clickable]=\"false\"\n [isLoading]=\"servicesLoading\"\n [allNames]=\"svc.associatedServiceNames\"\n ></lib-preview-list>\n </lib-form-field-container>\n }\n @if (formData.id) {\n <lib-form-field-container\n [title]=\"'Associated Identities'\"\n [count]=\"svc.associatedIdentities.length\"\n [helpText]=\"'Preview list of all Identities that this Edge Router is associated with.'\"\n >\n <lib-preview-list\n [clickable]=\"false\"\n [isLoading]=\"identitiesLoading\"\n [allNames]=\"svc.associatedIdentityNames\"\n ></lib-preview-list>\n </lib-form-field-container>\n }\n @if (showApiCalls) {\n <lib-form-field-container\n [title]=\"'API Calls'\"\n [label]=\"'OPTIONAL'\"\n >\n <div class=\"form-row\">\n <input class=\"form-field-input\" [value]=\"apiCallURL\"/>\n <div class=\"icon-copy copy-text\" (click)=\"copyToClipboard(apiCallURL)\"></div>\n </div>\n @if (formData) {\n <lib-json-view [(data)]=\"apiData\" [readOnly]=\"true\" [showCopy]=\"true\"></lib-json-view>\n }\n </lib-form-field-container>\n }\n </div>\n </div>\n }\n @if (formView === 'raw') {\n <div class=\"form-group-column\">\n @if (formData) {\n <lib-json-view [(data)]=\"formData\" [readOnly]=\"useStrictReadonlyForm\"></lib-json-view>\n }\n </div>\n }\n </div>\n</div>\n@if (isLoading || !dataInit) {\n <lib-loading-indicator [isLoading]=\"isLoading || !dataInit\"></lib-loading-indicator>\n}\n", styles: [".edge-router-form-container{display:flex;flex-direction:column;height:100%;width:100%;align-items:center;gap:.9375rem}.form-field-dropdown{background-image:url(/assets/svgs/ArrowDown.svg);background-position:center right .625rem;background-repeat:no-repeat;background-size:1.125rem;padding-right:1.75rem}.disabled{opacity:.5;pointer-events:none}.toggle.disabled{cursor:not-allowed}::ng-deep .admin-toggle{width:100%;width:35%;display:flex}::ng-deep .admin-toggle .form-field-line{display:none}::ng-deep .admin-toggle .toggle{width:100%}::ng-deep .is-admin-container .form-field-title-container.title-container-2{width:35%!important}.svc-test-result{position:absolute;transition:var(--transition);height:0;width:100%;background-color:var(--background);bottom:0;font-weight:600;padding-left:.625rem;padding-right:.625rem;border-color:var(--inputBorder);border-style:solid;border-width:var(--inputBorderWidth);border-bottom-right-radius:var(--inputBorderRadius);border-bottom-left-radius:var(--inputBorderRadius);border-top-style:none}.svc-test-result.test-result-open{height:fit-content;box-shadow:0 -.125rem .6875rem 0 var(--boxShadow);padding-bottom:.9375rem;padding-top:.9375rem}.svc-test-result .close.icon-close{top:.625rem;right:.625rem;font-size:1.125rem;height:1.125rem;width:1.125rem;line-height:1.125rem}::ng-deep .admin-toggle .form-field-toggle-container:focus .form-field-label{color:var(--primaryColor)}::ng-deep .admin-toggle .form-field-toggle-container:focus .form-field-line{border-color:var(--primaryColor)}::ng-deep .admin-toggle .form-field-toggle-container:focus .toggle{border-color:var(--primaryColor);border-style:solid;border-width:var(--inputBorderWidth)}::ng-deep .admin-toggle .form-field-toggle-container:focus .toggle .switch{top:.0625rem}.config-container-label.domain-label,.config-container-label.advertise-address-label{text-transform:lowercase}.config-container.domain-container,.config-container.advertise-address-container{background-color:var(--stroke)}\n"], dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: FormHeaderComponent, selector: "lib-form-header", inputs: ["data", "badges", "title", "moreActions", "formView", "saveDisabled", "saveTooltip", "actionButtonText", "moreActionsText", "showHeaderToggle", "showHeaderButton", "strictReadonlyUi", "multiActions"], outputs: ["formViewChange", "actionRequested", "multiActionRequested"] }, { kind: "component", type: FormFieldContainerComponent, selector: "lib-form-field-container", inputs: ["title", "title2", "titleIcon", "layout", "helpText", "helpText2", "label", "count", "action", "actionLabel", "class", "contentStyle", "contentClass", "showHeader", "showToggle", "headerActions", "headerToggle"], outputs: ["actionRequested", "headerToggleChange", "helpClicked"] }, { kind: "component", type: PreviewListComponent, selector: "lib-preview-list", inputs: ["label", "clickable", "isLoading", "allNames", "items", "allowRemove", "tooltip", "showfilter", "localFilter"], outputs: ["itemSelected", "itemRemoved", "filterChanged"] }, { kind: "component", type: LoadingIndicatorComponent, selector: "lib-loading-indicator", inputs: ["isLoading"] }, { kind: "component", type: FormFieldToggleComponent, selector: "lib-form-field-toggle", inputs: ["label", "orientation", "labelOn", "labelOff", "toggleOn"], outputs: ["toggleOnChange"] }, { kind: "component", type: JsonViewComponent, selector: "lib-json-view", inputs: ["data", "schema", "readOnly", "jsonInvalid", "showCopy", "showLineNumbers"], outputs: ["dataChange", "jsonChange", "jsonInvalidChange"] }, { kind: "component", type: TagSelectorComponent, selector: "lib-tag-selector", inputs: ["placeholder", "disableField", "disableCreate", "hideOption", "isLoading", "errorMessage", "focusOnInit", "namedAttributesServerFiltered", "selectedRoleAttributes", "selectedNamedAttributes", "hasError", "availableRoleAttributes", "availableNamedAttributes"], outputs: ["addRoleAttribute", "addNamedAttribute", "roleAttributeRemoved", "namedAttributeRemoved", "selectedRoleAttributesChange", "selectedNamedAttributesChange", "filterChange"] }, { kind: "component", type: QrCodeComponent, selector: "lib-qr-code", inputs: ["jwt", "token", "expiration", "identity", "type", "authenticators", "qrOnly", "canExpand"], outputs: ["doRefresh"] }, { kind: "component", type: CustomTagsComponent, selector: "lib-custom-tags", inputs: ["tags", "readOnly"], outputs: ["tagsChange"] }] }); }
|
|
22381
|
+
], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div class=\"projectable-form-wrapper\"\n (keyup.enter)=\"save($event)\"\n (keyup.escape)=\"closeModal(false)\"\n [class.projectable-form-hidden]=\"!dataInit\"\n >\n <lib-form-header\n [data]=\"formData\"\n [title]=\"formData.id ? 'Edit Edge Router: ' : 'Create New Edge Router'\"\n [moreActions]=\"moreActions\"\n [multiActions]=\"multiActions\"\n (actionRequested)=\"headerActionRequested($event)\"\n (multiActionRequested)=\"multiActionRequested($event)\"\n [(formView)]=\"formView\"\n [class.is-scrolled]=\"isScrolled\"\n [saveDisabled]=\"formPermissionSaveDisabled\"\n [saveTooltip]=\"formPermissionSaveTooltip\"\n [strictReadonlyUi]=\"useStrictReadonlyForm\"\n ></lib-form-header>\n <ng-content select=\"[slot=tabs-slot]\"></ng-content>\n <div class=\"edge-router-form-container projectable-form-container\" #formContainer>\n @if (formView === 'simple') {\n <div class=\"projectable-form-main-column form-group-row\">\n <div class=\"form-group-column three-fifths\">\n <lib-form-field-container [title]=\"'Edge Router Name'\" [label]=\"useStrictReadonlyForm ? '' : 'REQUIRED'\">\n <input\n class=\"form-field-input\"\n placeholder=\"Name this edge router\"\n [ngClass]=\"{error: errors['name']}\"\n [(ngModel)]=\"formData.name\"\n autofocus\n #nameFieldInput\n [disabled]=\"useStrictReadonlyForm\"\n />\n </lib-form-field-container>\n <lib-form-field-container\n [title]=\"'Select or create Edge Router attributes'\"\n [label]=\"'OPTIONAL'\"\n [contentStyle]=\"'z-index: 99999999'\"\n [helpText]=\"'Attributes are tags applied to an resource. Apply the same tag to other Edge Routers to form a group of Edge Routers.'\"\n >\n <lib-tag-selector\n [disableField]=\"useStrictReadonlyForm\"\n [disableCreate]=\"useStrictReadonlyForm\"\n [(selectedRoleAttributes)]=\"formData.roleAttributes\"\n [availableRoleAttributes]=\"edgeRouterRoleAttributes\"\n [placeholder]=\"'Add attributes to group Edge Routers'\"\n ></lib-tag-selector>\n </lib-form-field-container>\n <ng-content select=\"[slot=column-1-slot-1]\"></ng-content>\n <lib-form-field-toggle [(toggleOn)]=\"showMore\" style=\"margin: 0px 10px\"></lib-form-field-toggle>\n @if (showMore) {\n <div class=\"form-group-column\">\n <lib-form-field-container\n [title]=\"'TUNNELER'\"\n [title2]=\"'TRAVERSAL'\"\n [layout]=\"'row'\"\n class=\"form-field-advanced\"\n >\n <div class=\"config-item\" [class.disabled]=\"!tunnelerEnabledReadOnly\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">TUNNELER ENABLED</div>\n <div (click)=\"tunnelerEnabledReadOnly && !useStrictReadonlyForm && toggleTunnelerEnabled()\"\n [ngClass]=\"{ on: formData.isTunnelerEnabled, disabled: !tunnelerEnabledReadOnly, 'toggle-readonly': useStrictReadonlyForm }\" class=\"toggle\"\n [matTooltip]=\"useStrictReadonlyForm ? '' : (!tunnelerEnabledReadOnly ? 'Disabled because already hosted by netfoundry ' : '')\"\n matTooltipPosition=\"above\" style=\"pointer-events: auto;\">\n <span [hidden]=\"!formData.isTunnelerEnabled\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.isTunnelerEnabled\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n <div class=\"config-item\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">ALLOW TRAVERSAL</div>\n <div\n (click)=\"!useStrictReadonlyForm && toggleNoTraversal()\"\n [ngClass]=\"{ on: !formData.noTraversal, 'toggle-readonly': useStrictReadonlyForm }\"\n class=\"toggle\"\n >\n <span [hidden]=\"formData.noTraversal\" class=\"on-label\">YES</span>\n <span [hidden]=\"!formData.noTraversal\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n </lib-form-field-container>\n @if (isCustomerHosted) {\n <lib-form-field-container\n [title]=\"'LINK LISTENER'\"\n class=\"form-field-advanced\"\n >\n <div class=\"config-item disabled\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">ENABLE LINK LISTENER</div>\n <div\n [ngClass]=\"{ on: formData.linkListener, disabled: true }\"\n class=\"toggle\"\n role=\"switch\"\n aria-disabled=\"true\"\n [attr.aria-checked]=\"!!formData.linkListener\"\n matTooltip=\"This value is reported by the router and can't be changed here.\"\n matTooltipPosition=\"above\"\n >\n <span [hidden]=\"!formData.linkListener\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.linkListener\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n </lib-form-field-container>\n }\n @if (formData?.hostname || formData?.supportedProtocols?.tls || formData?.supportedProtocols?.wss) {\n <lib-form-field-container [showHeader]=\"false\">\n @if (formData?.hostname) {\n <div class=\"config-item\">\n <div class=\"config-item-label-container\">\n <span class=\"config-title\">Domain Name</span>\n </div>\n <div class=\"config-container domain-container\">\n <div class=\"config-container-label domain-label\">\n {{ formData?.hostname }}\n </div>\n </div>\n </div>\n }\n @if (formData?.supportedProtocols?.tls || formData?.supportedProtocols?.wss) {\n <div class=\"config-item\">\n <div class=\"config-item-label-container\">\n <span class=\"config-title\">ADVERTISE ADDRESS</span>\n </div>\n <div class=\"config-container advertise-address-container\">\n <div class=\"config-container-label advertise-address-label\">\n {{ formData?.supportedProtocols?.tls }}\n <br />\n {{ formData?.supportedProtocols?.wss }}\n </div>\n </div>\n </div>\n }\n </lib-form-field-container>\n }\n <lib-form-field-container\n [title]=\"'Custom Tags'\"\n [label]=\"'OPTIONAL'\"\n class=\"form-field-advanced\"\n >\n <lib-custom-tags [(tags)]=\"formData.tags\" [readOnly]=\"useStrictReadonlyForm\"></lib-custom-tags>\n </lib-form-field-container>\n <lib-form-field-container\n [title]=\"'App Data'\"\n [label]=\"'OPTIONAL'\"\n class=\"form-field-advanced\"\n >\n <lib-json-view [(data)]=\"formData.appData\" [readOnly]=\"useStrictReadonlyForm\"></lib-json-view>\n </lib-form-field-container>\n </div>\n }\n </div>\n <div class=\"form-group-column two-fifths\">\n <ng-content select=\"[slot=column-2-slot-1]\"></ng-content>\n @if (hasEnrolmentToken && !extService['hideZitiRegistration']) {\n <lib-form-field-container\n [showHeader]=\"false\"\n >\n <lib-qr-code\n [identity]=\"formData\"\n [jwt]=\"formData.enrollmentJwt\"\n [token]=\"formData.enrollmentToken\"\n [expiration]=\"formData.enrollmentExpiresAt\"\n (doRefresh)=\"refreshEdgeRouter()\"\n [type]=\"'router'\"\n ></lib-qr-code>\n </lib-form-field-container>\n }\n @if (formData.id) {\n <lib-form-field-container\n [title]=\"'Associated Services'\"\n [count]=\"svc.associatedServices.length\"\n [class]=\"'hide-overflow'\"\n [helpText]=\"'Preview list of all services that this Edge Router is associated with.'\"\n >\n <lib-preview-list\n [clickable]=\"false\"\n [isLoading]=\"servicesLoading\"\n [allNames]=\"svc.associatedServiceNames\"\n ></lib-preview-list>\n </lib-form-field-container>\n }\n @if (formData.id) {\n <lib-form-field-container\n [title]=\"'Associated Identities'\"\n [count]=\"svc.associatedIdentities.length\"\n [helpText]=\"'Preview list of all Identities that this Edge Router is associated with.'\"\n >\n <lib-preview-list\n [clickable]=\"false\"\n [isLoading]=\"identitiesLoading\"\n [allNames]=\"svc.associatedIdentityNames\"\n ></lib-preview-list>\n </lib-form-field-container>\n }\n @if (showApiCalls) {\n <lib-form-field-container\n [title]=\"'API Calls'\"\n [label]=\"'OPTIONAL'\"\n >\n <div class=\"form-row\">\n <input class=\"form-field-input\" [value]=\"apiCallURL\"/>\n <div class=\"icon-copy copy-text\" (click)=\"copyToClipboard(apiCallURL)\"></div>\n </div>\n @if (formData) {\n <lib-json-view [(data)]=\"apiData\" [readOnly]=\"true\" [showCopy]=\"true\"></lib-json-view>\n }\n </lib-form-field-container>\n }\n </div>\n </div>\n }\n @if (formView === 'raw') {\n <div class=\"form-group-column\">\n @if (formData) {\n <lib-json-view [(data)]=\"formData\" [readOnly]=\"useStrictReadonlyForm\"></lib-json-view>\n }\n </div>\n }\n </div>\n</div>\n@if (isLoading || !dataInit) {\n <lib-loading-indicator [isLoading]=\"isLoading || !dataInit\"></lib-loading-indicator>\n}\n", styles: [".edge-router-form-container{display:flex;flex-direction:column;height:100%;width:100%;align-items:center;gap:.9375rem}.form-field-dropdown{background-image:url(/assets/svgs/ArrowDown.svg);background-position:center right .625rem;background-repeat:no-repeat;background-size:1.125rem;padding-right:1.75rem}.disabled{opacity:.5;pointer-events:none}.toggle.disabled{cursor:not-allowed}::ng-deep .admin-toggle{width:100%;width:35%;display:flex}::ng-deep .admin-toggle .form-field-line{display:none}::ng-deep .admin-toggle .toggle{width:100%}::ng-deep .is-admin-container .form-field-title-container.title-container-2{width:35%!important}.svc-test-result{position:absolute;transition:var(--transition);height:0;width:100%;background-color:var(--background);bottom:0;font-weight:600;padding-left:.625rem;padding-right:.625rem;border-color:var(--inputBorder);border-style:solid;border-width:var(--inputBorderWidth);border-bottom-right-radius:var(--inputBorderRadius);border-bottom-left-radius:var(--inputBorderRadius);border-top-style:none}.svc-test-result.test-result-open{height:fit-content;box-shadow:0 -.125rem .6875rem 0 var(--boxShadow);padding-bottom:.9375rem;padding-top:.9375rem}.svc-test-result .close.icon-close{top:.625rem;right:.625rem;font-size:1.125rem;height:1.125rem;width:1.125rem;line-height:1.125rem}::ng-deep .admin-toggle .form-field-toggle-container:focus .form-field-label{color:var(--primaryColor)}::ng-deep .admin-toggle .form-field-toggle-container:focus .form-field-line{border-color:var(--primaryColor)}::ng-deep .admin-toggle .form-field-toggle-container:focus .toggle{border-color:var(--primaryColor);border-style:solid;border-width:var(--inputBorderWidth)}::ng-deep .admin-toggle .form-field-toggle-container:focus .toggle .switch{top:.0625rem}.config-container-label.domain-label,.config-container-label.advertise-address-label{text-transform:lowercase}.config-container-label.advertise-address-label{height:auto;padding:.125rem 0}.config-container.domain-container,.config-container.advertise-address-container{background-color:var(--stroke)}.config-container.advertise-address-container{height:auto;min-height:var(--defaultInputHeight);padding:0rem 1.25rem}\n"], dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: FormHeaderComponent, selector: "lib-form-header", inputs: ["data", "badges", "title", "moreActions", "formView", "saveDisabled", "saveTooltip", "actionButtonText", "moreActionsText", "showHeaderToggle", "showHeaderButton", "strictReadonlyUi", "multiActions"], outputs: ["formViewChange", "actionRequested", "multiActionRequested"] }, { kind: "component", type: FormFieldContainerComponent, selector: "lib-form-field-container", inputs: ["title", "title2", "titleIcon", "layout", "helpText", "helpText2", "label", "count", "action", "actionLabel", "class", "contentStyle", "contentClass", "showHeader", "showToggle", "headerActions", "headerToggle"], outputs: ["actionRequested", "headerToggleChange", "helpClicked"] }, { kind: "component", type: PreviewListComponent, selector: "lib-preview-list", inputs: ["label", "clickable", "isLoading", "allNames", "items", "allowRemove", "tooltip", "showfilter", "localFilter"], outputs: ["itemSelected", "itemRemoved", "filterChanged"] }, { kind: "component", type: LoadingIndicatorComponent, selector: "lib-loading-indicator", inputs: ["isLoading"] }, { kind: "component", type: FormFieldToggleComponent, selector: "lib-form-field-toggle", inputs: ["label", "orientation", "labelOn", "labelOff", "toggleOn"], outputs: ["toggleOnChange"] }, { kind: "component", type: JsonViewComponent, selector: "lib-json-view", inputs: ["data", "schema", "readOnly", "jsonInvalid", "showCopy", "showLineNumbers"], outputs: ["dataChange", "jsonChange", "jsonInvalidChange"] }, { kind: "component", type: TagSelectorComponent, selector: "lib-tag-selector", inputs: ["placeholder", "disableField", "disableCreate", "hideOption", "isLoading", "errorMessage", "focusOnInit", "namedAttributesServerFiltered", "selectedRoleAttributes", "selectedNamedAttributes", "hasError", "availableRoleAttributes", "availableNamedAttributes"], outputs: ["addRoleAttribute", "addNamedAttribute", "roleAttributeRemoved", "namedAttributeRemoved", "selectedRoleAttributesChange", "selectedNamedAttributesChange", "filterChange"] }, { kind: "component", type: QrCodeComponent, selector: "lib-qr-code", inputs: ["jwt", "token", "expiration", "identity", "type", "authenticators", "qrOnly", "canExpand"], outputs: ["doRefresh"] }, { kind: "component", type: CustomTagsComponent, selector: "lib-custom-tags", inputs: ["tags", "readOnly"], outputs: ["tagsChange"] }] }); }
|
|
19898
22382
|
}
|
|
19899
22383
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: EdgeRouterFormComponent, decorators: [{
|
|
19900
22384
|
type: Component,
|
|
@@ -19903,7 +22387,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
19903
22387
|
provide: MatDialogRef,
|
|
19904
22388
|
useValue: {}
|
|
19905
22389
|
}
|
|
19906
|
-
], standalone: false, template: "<div class=\"projectable-form-wrapper\"\n (keyup.enter)=\"save($event)\"\n (keyup.escape)=\"closeModal(false)\"\n [class.projectable-form-hidden]=\"!dataInit\"\n >\n <lib-form-header\n [data]=\"formData\"\n [title]=\"formData.id ? 'Edit Edge Router: ' : 'Create New Edge Router'\"\n [moreActions]=\"moreActions\"\n [multiActions]=\"multiActions\"\n (actionRequested)=\"headerActionRequested($event)\"\n (multiActionRequested)=\"multiActionRequested($event)\"\n [(formView)]=\"formView\"\n [class.is-scrolled]=\"isScrolled\"\n [saveDisabled]=\"formPermissionSaveDisabled\"\n [saveTooltip]=\"formPermissionSaveTooltip\"\n [strictReadonlyUi]=\"useStrictReadonlyForm\"\n ></lib-form-header>\n <ng-content select=\"[slot=tabs-slot]\"></ng-content>\n <div class=\"edge-router-form-container projectable-form-container\" #formContainer>\n @if (formView === 'simple') {\n <div class=\"projectable-form-main-column form-group-row\">\n <div class=\"form-group-column three-fifths\">\n <lib-form-field-container [title]=\"'Edge Router Name'\" [label]=\"useStrictReadonlyForm ? '' : 'REQUIRED'\">\n <input\n class=\"form-field-input\"\n placeholder=\"Name this edge router\"\n [ngClass]=\"{error: errors['name']}\"\n [(ngModel)]=\"formData.name\"\n autofocus\n #nameFieldInput\n [disabled]=\"useStrictReadonlyForm\"\n />\n </lib-form-field-container>\n <lib-form-field-container\n [title]=\"'Select or create Edge Router attributes'\"\n [label]=\"'OPTIONAL'\"\n [contentStyle]=\"'z-index: 99999999'\"\n [helpText]=\"'Attributes are tags applied to an resource. Apply the same tag to other Edge Routers to form a group of Edge Routers.'\"\n >\n <lib-tag-selector\n [disableField]=\"useStrictReadonlyForm\"\n [disableCreate]=\"useStrictReadonlyForm\"\n [(selectedRoleAttributes)]=\"formData.roleAttributes\"\n [availableRoleAttributes]=\"edgeRouterRoleAttributes\"\n [placeholder]=\"'Add attributes to group Edge Routers'\"\n ></lib-tag-selector>\n </lib-form-field-container>\n <ng-content select=\"[slot=column-1-slot-1]\"></ng-content>\n <lib-form-field-toggle [(toggleOn)]=\"showMore\" style=\"margin: 0px 10px\"></lib-form-field-toggle>\n @if (showMore) {\n <div class=\"form-group-column\">\n <lib-form-field-container\n [title]=\"'TUNNELER'\"\n [title2]=\"'TRAVERSAL'\"\n [layout]=\"'row'\"\n class=\"form-field-advanced\"\n >\n <div class=\"config-item\" [class.disabled]=\"!tunnelerEnabledReadOnly\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">TUNNELER ENABLED</div>\n <div (click)=\"tunnelerEnabledReadOnly && !useStrictReadonlyForm && toggleTunnelerEnabled()\"\n [ngClass]=\"{ on: formData.isTunnelerEnabled, disabled: !tunnelerEnabledReadOnly, 'toggle-readonly': useStrictReadonlyForm }\" class=\"toggle\"\n [matTooltip]=\"useStrictReadonlyForm ? '' : (!tunnelerEnabledReadOnly ? 'Disabled because already hosted by netfoundry ' : '')\"\n matTooltipPosition=\"above\" style=\"pointer-events: auto;\">\n <span [hidden]=\"!formData.isTunnelerEnabled\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.isTunnelerEnabled\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n <div class=\"config-item\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">ALLOW TRAVERSAL</div>\n <div\n (click)=\"!useStrictReadonlyForm && toggleNoTraversal()\"\n [ngClass]=\"{ on: !formData.noTraversal, 'toggle-readonly': useStrictReadonlyForm }\"\n class=\"toggle\"\n >\n <span [hidden]=\"formData.noTraversal\" class=\"on-label\">YES</span>\n <span [hidden]=\"!formData.noTraversal\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n </lib-form-field-container>\n @if (formData?.hostname || formData?.supportedProtocols?.tls || formData?.supportedProtocols?.wss) {\n <lib-form-field-container [showHeader]=\"false\">\n @if (formData?.hostname) {\n <div class=\"config-item\">\n <div class=\"config-item-label-container\">\n <span class=\"config-title\">Domain Name</span>\n </div>\n <div class=\"config-container domain-container\">\n <div class=\"config-container-label domain-label\">\n {{ formData?.hostname }}\n </div>\n </div>\n </div>\n }\n @if (formData?.supportedProtocols?.tls || formData?.supportedProtocols?.wss) {\n <div class=\"config-item\">\n <div class=\"config-item-label-container\">\n <span class=\"config-title\">ADVERTISE ADDRESS</span>\n </div>\n <div class=\"config-container advertise-address-container\">\n <div class=\"config-container-label advertise-address-label\">\n {{ formData?.supportedProtocols?.tls }}\n <br />\n {{ formData?.supportedProtocols?.wss }}\n </div>\n </div>\n </div>\n }\n </lib-form-field-container>\n }\n <lib-form-field-container\n [title]=\"'Custom Tags'\"\n [label]=\"'OPTIONAL'\"\n class=\"form-field-advanced\"\n >\n <lib-custom-tags [(tags)]=\"formData.tags\" [readOnly]=\"useStrictReadonlyForm\"></lib-custom-tags>\n </lib-form-field-container>\n <lib-form-field-container\n [title]=\"'App Data'\"\n [label]=\"'OPTIONAL'\"\n class=\"form-field-advanced\"\n >\n <lib-json-view [(data)]=\"formData.appData\" [readOnly]=\"useStrictReadonlyForm\"></lib-json-view>\n </lib-form-field-container>\n </div>\n }\n </div>\n <div class=\"form-group-column two-fifths\">\n <ng-content select=\"[slot=column-2-slot-1]\"></ng-content>\n @if (hasEnrolmentToken && !extService['hideZitiRegistration']) {\n <lib-form-field-container\n [showHeader]=\"false\"\n >\n <lib-qr-code\n [identity]=\"formData\"\n [jwt]=\"formData.enrollmentJwt\"\n [token]=\"formData.enrollmentToken\"\n [expiration]=\"formData.enrollmentExpiresAt\"\n (doRefresh)=\"refreshEdgeRouter()\"\n [type]=\"'router'\"\n ></lib-qr-code>\n </lib-form-field-container>\n }\n @if (formData.id) {\n <lib-form-field-container\n [title]=\"'Associated Services'\"\n [count]=\"svc.associatedServices.length\"\n [class]=\"'hide-overflow'\"\n [helpText]=\"'Preview list of all services that this Edge Router is associated with.'\"\n >\n <lib-preview-list\n [clickable]=\"false\"\n [isLoading]=\"servicesLoading\"\n [allNames]=\"svc.associatedServiceNames\"\n ></lib-preview-list>\n </lib-form-field-container>\n }\n @if (formData.id) {\n <lib-form-field-container\n [title]=\"'Associated Identities'\"\n [count]=\"svc.associatedIdentities.length\"\n [helpText]=\"'Preview list of all Identities that this Edge Router is associated with.'\"\n >\n <lib-preview-list\n [clickable]=\"false\"\n [isLoading]=\"identitiesLoading\"\n [allNames]=\"svc.associatedIdentityNames\"\n ></lib-preview-list>\n </lib-form-field-container>\n }\n @if (showApiCalls) {\n <lib-form-field-container\n [title]=\"'API Calls'\"\n [label]=\"'OPTIONAL'\"\n >\n <div class=\"form-row\">\n <input class=\"form-field-input\" [value]=\"apiCallURL\"/>\n <div class=\"icon-copy copy-text\" (click)=\"copyToClipboard(apiCallURL)\"></div>\n </div>\n @if (formData) {\n <lib-json-view [(data)]=\"apiData\" [readOnly]=\"true\" [showCopy]=\"true\"></lib-json-view>\n }\n </lib-form-field-container>\n }\n </div>\n </div>\n }\n @if (formView === 'raw') {\n <div class=\"form-group-column\">\n @if (formData) {\n <lib-json-view [(data)]=\"formData\" [readOnly]=\"useStrictReadonlyForm\"></lib-json-view>\n }\n </div>\n }\n </div>\n</div>\n@if (isLoading || !dataInit) {\n <lib-loading-indicator [isLoading]=\"isLoading || !dataInit\"></lib-loading-indicator>\n}\n", styles: [".edge-router-form-container{display:flex;flex-direction:column;height:100%;width:100%;align-items:center;gap:.9375rem}.form-field-dropdown{background-image:url(/assets/svgs/ArrowDown.svg);background-position:center right .625rem;background-repeat:no-repeat;background-size:1.125rem;padding-right:1.75rem}.disabled{opacity:.5;pointer-events:none}.toggle.disabled{cursor:not-allowed}::ng-deep .admin-toggle{width:100%;width:35%;display:flex}::ng-deep .admin-toggle .form-field-line{display:none}::ng-deep .admin-toggle .toggle{width:100%}::ng-deep .is-admin-container .form-field-title-container.title-container-2{width:35%!important}.svc-test-result{position:absolute;transition:var(--transition);height:0;width:100%;background-color:var(--background);bottom:0;font-weight:600;padding-left:.625rem;padding-right:.625rem;border-color:var(--inputBorder);border-style:solid;border-width:var(--inputBorderWidth);border-bottom-right-radius:var(--inputBorderRadius);border-bottom-left-radius:var(--inputBorderRadius);border-top-style:none}.svc-test-result.test-result-open{height:fit-content;box-shadow:0 -.125rem .6875rem 0 var(--boxShadow);padding-bottom:.9375rem;padding-top:.9375rem}.svc-test-result .close.icon-close{top:.625rem;right:.625rem;font-size:1.125rem;height:1.125rem;width:1.125rem;line-height:1.125rem}::ng-deep .admin-toggle .form-field-toggle-container:focus .form-field-label{color:var(--primaryColor)}::ng-deep .admin-toggle .form-field-toggle-container:focus .form-field-line{border-color:var(--primaryColor)}::ng-deep .admin-toggle .form-field-toggle-container:focus .toggle{border-color:var(--primaryColor);border-style:solid;border-width:var(--inputBorderWidth)}::ng-deep .admin-toggle .form-field-toggle-container:focus .toggle .switch{top:.0625rem}.config-container-label.domain-label,.config-container-label.advertise-address-label{text-transform:lowercase}.config-container.domain-container,.config-container.advertise-address-container{background-color:var(--stroke)}\n"] }]
|
|
22390
|
+
], standalone: false, template: "<div class=\"projectable-form-wrapper\"\n (keyup.enter)=\"save($event)\"\n (keyup.escape)=\"closeModal(false)\"\n [class.projectable-form-hidden]=\"!dataInit\"\n >\n <lib-form-header\n [data]=\"formData\"\n [title]=\"formData.id ? 'Edit Edge Router: ' : 'Create New Edge Router'\"\n [moreActions]=\"moreActions\"\n [multiActions]=\"multiActions\"\n (actionRequested)=\"headerActionRequested($event)\"\n (multiActionRequested)=\"multiActionRequested($event)\"\n [(formView)]=\"formView\"\n [class.is-scrolled]=\"isScrolled\"\n [saveDisabled]=\"formPermissionSaveDisabled\"\n [saveTooltip]=\"formPermissionSaveTooltip\"\n [strictReadonlyUi]=\"useStrictReadonlyForm\"\n ></lib-form-header>\n <ng-content select=\"[slot=tabs-slot]\"></ng-content>\n <div class=\"edge-router-form-container projectable-form-container\" #formContainer>\n @if (formView === 'simple') {\n <div class=\"projectable-form-main-column form-group-row\">\n <div class=\"form-group-column three-fifths\">\n <lib-form-field-container [title]=\"'Edge Router Name'\" [label]=\"useStrictReadonlyForm ? '' : 'REQUIRED'\">\n <input\n class=\"form-field-input\"\n placeholder=\"Name this edge router\"\n [ngClass]=\"{error: errors['name']}\"\n [(ngModel)]=\"formData.name\"\n autofocus\n #nameFieldInput\n [disabled]=\"useStrictReadonlyForm\"\n />\n </lib-form-field-container>\n <lib-form-field-container\n [title]=\"'Select or create Edge Router attributes'\"\n [label]=\"'OPTIONAL'\"\n [contentStyle]=\"'z-index: 99999999'\"\n [helpText]=\"'Attributes are tags applied to an resource. Apply the same tag to other Edge Routers to form a group of Edge Routers.'\"\n >\n <lib-tag-selector\n [disableField]=\"useStrictReadonlyForm\"\n [disableCreate]=\"useStrictReadonlyForm\"\n [(selectedRoleAttributes)]=\"formData.roleAttributes\"\n [availableRoleAttributes]=\"edgeRouterRoleAttributes\"\n [placeholder]=\"'Add attributes to group Edge Routers'\"\n ></lib-tag-selector>\n </lib-form-field-container>\n <ng-content select=\"[slot=column-1-slot-1]\"></ng-content>\n <lib-form-field-toggle [(toggleOn)]=\"showMore\" style=\"margin: 0px 10px\"></lib-form-field-toggle>\n @if (showMore) {\n <div class=\"form-group-column\">\n <lib-form-field-container\n [title]=\"'TUNNELER'\"\n [title2]=\"'TRAVERSAL'\"\n [layout]=\"'row'\"\n class=\"form-field-advanced\"\n >\n <div class=\"config-item\" [class.disabled]=\"!tunnelerEnabledReadOnly\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">TUNNELER ENABLED</div>\n <div (click)=\"tunnelerEnabledReadOnly && !useStrictReadonlyForm && toggleTunnelerEnabled()\"\n [ngClass]=\"{ on: formData.isTunnelerEnabled, disabled: !tunnelerEnabledReadOnly, 'toggle-readonly': useStrictReadonlyForm }\" class=\"toggle\"\n [matTooltip]=\"useStrictReadonlyForm ? '' : (!tunnelerEnabledReadOnly ? 'Disabled because already hosted by netfoundry ' : '')\"\n matTooltipPosition=\"above\" style=\"pointer-events: auto;\">\n <span [hidden]=\"!formData.isTunnelerEnabled\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.isTunnelerEnabled\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n <div class=\"config-item\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">ALLOW TRAVERSAL</div>\n <div\n (click)=\"!useStrictReadonlyForm && toggleNoTraversal()\"\n [ngClass]=\"{ on: !formData.noTraversal, 'toggle-readonly': useStrictReadonlyForm }\"\n class=\"toggle\"\n >\n <span [hidden]=\"formData.noTraversal\" class=\"on-label\">YES</span>\n <span [hidden]=\"!formData.noTraversal\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n </lib-form-field-container>\n @if (isCustomerHosted) {\n <lib-form-field-container\n [title]=\"'LINK LISTENER'\"\n class=\"form-field-advanced\"\n >\n <div class=\"config-item disabled\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">ENABLE LINK LISTENER</div>\n <div\n [ngClass]=\"{ on: formData.linkListener, disabled: true }\"\n class=\"toggle\"\n role=\"switch\"\n aria-disabled=\"true\"\n [attr.aria-checked]=\"!!formData.linkListener\"\n matTooltip=\"This value is reported by the router and can't be changed here.\"\n matTooltipPosition=\"above\"\n >\n <span [hidden]=\"!formData.linkListener\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.linkListener\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n </lib-form-field-container>\n }\n @if (formData?.hostname || formData?.supportedProtocols?.tls || formData?.supportedProtocols?.wss) {\n <lib-form-field-container [showHeader]=\"false\">\n @if (formData?.hostname) {\n <div class=\"config-item\">\n <div class=\"config-item-label-container\">\n <span class=\"config-title\">Domain Name</span>\n </div>\n <div class=\"config-container domain-container\">\n <div class=\"config-container-label domain-label\">\n {{ formData?.hostname }}\n </div>\n </div>\n </div>\n }\n @if (formData?.supportedProtocols?.tls || formData?.supportedProtocols?.wss) {\n <div class=\"config-item\">\n <div class=\"config-item-label-container\">\n <span class=\"config-title\">ADVERTISE ADDRESS</span>\n </div>\n <div class=\"config-container advertise-address-container\">\n <div class=\"config-container-label advertise-address-label\">\n {{ formData?.supportedProtocols?.tls }}\n <br />\n {{ formData?.supportedProtocols?.wss }}\n </div>\n </div>\n </div>\n }\n </lib-form-field-container>\n }\n <lib-form-field-container\n [title]=\"'Custom Tags'\"\n [label]=\"'OPTIONAL'\"\n class=\"form-field-advanced\"\n >\n <lib-custom-tags [(tags)]=\"formData.tags\" [readOnly]=\"useStrictReadonlyForm\"></lib-custom-tags>\n </lib-form-field-container>\n <lib-form-field-container\n [title]=\"'App Data'\"\n [label]=\"'OPTIONAL'\"\n class=\"form-field-advanced\"\n >\n <lib-json-view [(data)]=\"formData.appData\" [readOnly]=\"useStrictReadonlyForm\"></lib-json-view>\n </lib-form-field-container>\n </div>\n }\n </div>\n <div class=\"form-group-column two-fifths\">\n <ng-content select=\"[slot=column-2-slot-1]\"></ng-content>\n @if (hasEnrolmentToken && !extService['hideZitiRegistration']) {\n <lib-form-field-container\n [showHeader]=\"false\"\n >\n <lib-qr-code\n [identity]=\"formData\"\n [jwt]=\"formData.enrollmentJwt\"\n [token]=\"formData.enrollmentToken\"\n [expiration]=\"formData.enrollmentExpiresAt\"\n (doRefresh)=\"refreshEdgeRouter()\"\n [type]=\"'router'\"\n ></lib-qr-code>\n </lib-form-field-container>\n }\n @if (formData.id) {\n <lib-form-field-container\n [title]=\"'Associated Services'\"\n [count]=\"svc.associatedServices.length\"\n [class]=\"'hide-overflow'\"\n [helpText]=\"'Preview list of all services that this Edge Router is associated with.'\"\n >\n <lib-preview-list\n [clickable]=\"false\"\n [isLoading]=\"servicesLoading\"\n [allNames]=\"svc.associatedServiceNames\"\n ></lib-preview-list>\n </lib-form-field-container>\n }\n @if (formData.id) {\n <lib-form-field-container\n [title]=\"'Associated Identities'\"\n [count]=\"svc.associatedIdentities.length\"\n [helpText]=\"'Preview list of all Identities that this Edge Router is associated with.'\"\n >\n <lib-preview-list\n [clickable]=\"false\"\n [isLoading]=\"identitiesLoading\"\n [allNames]=\"svc.associatedIdentityNames\"\n ></lib-preview-list>\n </lib-form-field-container>\n }\n @if (showApiCalls) {\n <lib-form-field-container\n [title]=\"'API Calls'\"\n [label]=\"'OPTIONAL'\"\n >\n <div class=\"form-row\">\n <input class=\"form-field-input\" [value]=\"apiCallURL\"/>\n <div class=\"icon-copy copy-text\" (click)=\"copyToClipboard(apiCallURL)\"></div>\n </div>\n @if (formData) {\n <lib-json-view [(data)]=\"apiData\" [readOnly]=\"true\" [showCopy]=\"true\"></lib-json-view>\n }\n </lib-form-field-container>\n }\n </div>\n </div>\n }\n @if (formView === 'raw') {\n <div class=\"form-group-column\">\n @if (formData) {\n <lib-json-view [(data)]=\"formData\" [readOnly]=\"useStrictReadonlyForm\"></lib-json-view>\n }\n </div>\n }\n </div>\n</div>\n@if (isLoading || !dataInit) {\n <lib-loading-indicator [isLoading]=\"isLoading || !dataInit\"></lib-loading-indicator>\n}\n", styles: [".edge-router-form-container{display:flex;flex-direction:column;height:100%;width:100%;align-items:center;gap:.9375rem}.form-field-dropdown{background-image:url(/assets/svgs/ArrowDown.svg);background-position:center right .625rem;background-repeat:no-repeat;background-size:1.125rem;padding-right:1.75rem}.disabled{opacity:.5;pointer-events:none}.toggle.disabled{cursor:not-allowed}::ng-deep .admin-toggle{width:100%;width:35%;display:flex}::ng-deep .admin-toggle .form-field-line{display:none}::ng-deep .admin-toggle .toggle{width:100%}::ng-deep .is-admin-container .form-field-title-container.title-container-2{width:35%!important}.svc-test-result{position:absolute;transition:var(--transition);height:0;width:100%;background-color:var(--background);bottom:0;font-weight:600;padding-left:.625rem;padding-right:.625rem;border-color:var(--inputBorder);border-style:solid;border-width:var(--inputBorderWidth);border-bottom-right-radius:var(--inputBorderRadius);border-bottom-left-radius:var(--inputBorderRadius);border-top-style:none}.svc-test-result.test-result-open{height:fit-content;box-shadow:0 -.125rem .6875rem 0 var(--boxShadow);padding-bottom:.9375rem;padding-top:.9375rem}.svc-test-result .close.icon-close{top:.625rem;right:.625rem;font-size:1.125rem;height:1.125rem;width:1.125rem;line-height:1.125rem}::ng-deep .admin-toggle .form-field-toggle-container:focus .form-field-label{color:var(--primaryColor)}::ng-deep .admin-toggle .form-field-toggle-container:focus .form-field-line{border-color:var(--primaryColor)}::ng-deep .admin-toggle .form-field-toggle-container:focus .toggle{border-color:var(--primaryColor);border-style:solid;border-width:var(--inputBorderWidth)}::ng-deep .admin-toggle .form-field-toggle-container:focus .toggle .switch{top:.0625rem}.config-container-label.domain-label,.config-container-label.advertise-address-label{text-transform:lowercase}.config-container-label.advertise-address-label{height:auto;padding:.125rem 0}.config-container.domain-container,.config-container.advertise-address-container{background-color:var(--stroke)}.config-container.advertise-address-container{height:auto;min-height:var(--defaultInputHeight);padding:0rem 1.25rem}\n"] }]
|
|
19907
22391
|
}], ctorParameters: () => [{ type: SettingsService, decorators: [{
|
|
19908
22392
|
type: Inject,
|
|
19909
22393
|
args: [SETTINGS_SERVICE]
|
|
@@ -26403,6 +28887,9 @@ class JwtSigner {
|
|
|
26403
28887
|
this.targetToken = 'ACCESS';
|
|
26404
28888
|
this.enrollToCertEnabled = false;
|
|
26405
28889
|
this.enrollToTokenEnabled = false;
|
|
28890
|
+
this.enrollAuthPolicyId = '';
|
|
28891
|
+
this.enrollNameClaimsSelector = '';
|
|
28892
|
+
this.enrollAttributeClaimsSelector = '';
|
|
26406
28893
|
}
|
|
26407
28894
|
}
|
|
26408
28895
|
;
|
|
@@ -26616,6 +29103,7 @@ class JwtSignerFormComponent extends ProjectableForm {
|
|
|
26616
29103
|
this.configKey = 'oauth_test_callback_config';
|
|
26617
29104
|
this.tokenTypeKey = 'oauth_test_callback_token_type';
|
|
26618
29105
|
this.oidcVerified = false;
|
|
29106
|
+
this.authPolicies = [];
|
|
26619
29107
|
this.usePreviousLocation = false;
|
|
26620
29108
|
this.entityType = 'external-jwt-signers';
|
|
26621
29109
|
this.entityClass = JwtSigner;
|
|
@@ -26627,10 +29115,25 @@ class JwtSignerFormComponent extends ProjectableForm {
|
|
|
26627
29115
|
this.settingsService.settingsChange.subscribe((results) => {
|
|
26628
29116
|
this.settings = results;
|
|
26629
29117
|
});
|
|
29118
|
+
this.getAuthPolicies();
|
|
26630
29119
|
if (window.location.href.indexOf('test-auth') > 0) {
|
|
26631
29120
|
this.handleOAuthCallback();
|
|
26632
29121
|
}
|
|
26633
29122
|
}
|
|
29123
|
+
getAuthPolicies() {
|
|
29124
|
+
const paging = {
|
|
29125
|
+
filter: "",
|
|
29126
|
+
noSearch: true,
|
|
29127
|
+
order: "asc",
|
|
29128
|
+
page: 1,
|
|
29129
|
+
searchOn: "name",
|
|
29130
|
+
sort: "name",
|
|
29131
|
+
total: 100
|
|
29132
|
+
};
|
|
29133
|
+
this.zitiService.get('auth-policies', paging, []).then((result) => {
|
|
29134
|
+
this.authPolicies = [...result.data];
|
|
29135
|
+
});
|
|
29136
|
+
}
|
|
26634
29137
|
ngAfterViewInit() {
|
|
26635
29138
|
super.ngAfterViewInit(true);
|
|
26636
29139
|
}
|
|
@@ -26796,6 +29299,18 @@ class JwtSignerFormComponent extends ProjectableForm {
|
|
|
26796
29299
|
}
|
|
26797
29300
|
this.formData.targetToken = val;
|
|
26798
29301
|
}
|
|
29302
|
+
get enrollAuthPolicyId() {
|
|
29303
|
+
if (this.formData && isNil(this.formData.enrollAuthPolicyId)) {
|
|
29304
|
+
this.formData.enrollAuthPolicyId = '';
|
|
29305
|
+
}
|
|
29306
|
+
return this.formData?.enrollAuthPolicyId;
|
|
29307
|
+
}
|
|
29308
|
+
set enrollAuthPolicyId(val) {
|
|
29309
|
+
if (!this.formData) {
|
|
29310
|
+
return;
|
|
29311
|
+
}
|
|
29312
|
+
this.formData.enrollAuthPolicyId = val;
|
|
29313
|
+
}
|
|
26799
29314
|
get apiCallURL() {
|
|
26800
29315
|
return this.settings.selectedEdgeController + '/edge/management/v1/external-jwt-signers' + (this.formData.id ? `/${this.formData.id}` : '');
|
|
26801
29316
|
}
|
|
@@ -26822,6 +29337,11 @@ class JwtSignerFormComponent extends ProjectableForm {
|
|
|
26822
29337
|
if (!isEmpty(this.formData.targetToken) && this.showTokenType) {
|
|
26823
29338
|
data.targetToken = this.formData.targetToken;
|
|
26824
29339
|
}
|
|
29340
|
+
if (this.showAutoEnrollment) {
|
|
29341
|
+
data.enrollAuthPolicyId = this.formData.enrollAuthPolicyId || '';
|
|
29342
|
+
data.enrollNameClaimsSelector = this.formData.enrollNameClaimsSelector || '';
|
|
29343
|
+
data.enrollAttributeClaimsSelector = this.formData.enrollAttributeClaimsSelector || '';
|
|
29344
|
+
}
|
|
26825
29345
|
if (!isEmpty(this.formData.id)) {
|
|
26826
29346
|
data.id = this.formData.id;
|
|
26827
29347
|
}
|
|
@@ -27091,11 +29611,11 @@ class JwtSignerFormComponent extends ProjectableForm {
|
|
|
27091
29611
|
return !this.errors.jwksEndpoint;
|
|
27092
29612
|
}
|
|
27093
29613
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: JwtSignerFormComponent, deps: [{ token: JwtSignerFormService }, { token: SchemaService }, { token: GrowlerService }, { token: SHAREDZ_EXTENSION }, { token: SETTINGS_SERVICE }, { token: ZITI_DATA_SERVICE }, { token: i4.Router }, { token: i4.ActivatedRoute }, { token: i1$1.Location }, { token: ValidationService }, { token: AuthService }, { token: i1$6.OAuthService }, { token: i1$3.HttpClient }, { token: ZAC_LOGIN_SERVICE }, { token: i5.MatDialog }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
27094
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: JwtSignerFormComponent, isStandalone: false, selector: "lib-configuration", inputs: { errors: "errors" }, outputs: { close: "close" }, viewQueries: [{ propertyName: "filterInput", first: true, predicate: ["fileSelect"], descendants: true }, { propertyName: "oidcVerification", first: true, predicate: ["oidcVerification"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"projectable-form-wrapper\"\n (keyup.enter)=\"save($event)\"\n (keyup.escape)=\"closeModal(false)\"\n tabindex=\"0\"\n >\n <lib-form-header\n [data]=\"formData\"\n [title]=\"(formData.id ? 'JWT Signer Details' : 'Create JWT Signer')\"\n [moreActions]=\"moreActions\"\n [multiActions]=\"multiActions\"\n (actionRequested)=\"headerActionRequested($event)\"\n (multiActionRequested)=\"multiActionRequested($event)\"\n [(formView)]=\"formView\"\n [saveDisabled]=\"svc.saveDisabled || formDataInvalid || formPermissionSaveDisabled\"\n [saveTooltip]=\"formPermissionSaveTooltip\"\n [strictReadonlyUi]=\"useStrictReadonlyForm\"\n ></lib-form-header>\n <div class=\"jwt-signer-form-container projectable-form-container\" #scrollContainer>\n <div class=\"projectable-form-main-column form-group-row\" [hidden]=\"formView !== 'simple'\">\n <div class=\"form-group-column three-fifths\">\n <lib-form-field-container\n [title]=\"'Name'\"\n [label]=\"useStrictReadonlyForm ? '' : 'REQUIRED'\"\n >\n @if (!useStrictReadonlyForm) {\n <input class=\"form-field-input\" [(ngModel)]=\"formData.name\" [ngClass]=\"{error: errors['name']}\" placeholder=\"Name this JWT Signer\" #nameFieldInput/>\n } @else {\n <div class=\"form-field-readonly-value\">{{ formData.name }}</div>\n }\n </lib-form-field-container>\n <lib-form-field-container\n [layout]=\"'column'\"\n [showHeader]=\"false\"\n >\n <div class=\"form-field-label-container\">\n <div class=\"form-field-header\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Issuer</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The "issuer" field on the JWT Signer must match the "iss" field on the JWT\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <span class=\"form-field-label\" >{{ useStrictReadonlyForm ? '' : 'REQUIRED' }}</span>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter issuer\" [(ngModel)]=\"formData.issuer\" [ngClass]=\"{error: errors['issuer']}\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Audience</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The expected "aud" (audience) field on the JWT\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter audience\" [(ngModel)]=\"formData.audience\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-row\">\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Claims Property</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The field on the JWT for mapping to an identity. Matches the identity's id or externalId if "Use External Id" is set to true. Defaults to "sub"\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter claims property\" [(ngModel)]=\"formData.claimsProperty\" (keyup)=\"checkExternalIdToggle()\" [ngClass]=\"{error: errors['claimsProperty']}\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-header\">\n <div class=\"form-field-title-container\">\n <div class=\"config-container-label\" style=\"font-weight: 600; font-size: 14px;\">External ID</div>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"If enabled, will match the "claimsProperty" to an identity's "externalId" field. If false, it will match to the identity's id field.\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n </div>\n <div class=\"config-item\">\n <div class=\"config-container toggle-container\">\n <div class=\"form-field-title-container\">\n <div class=\"config-container-label\">Use External ID</div>\n </div>\n <div\n (click)=\"!useStrictReadonlyForm && toggleUseExternalId()\"\n [ngClass]=\"{ on: formData.useExternalId, 'toggle-readonly': useStrictReadonlyForm }\"\n class=\"toggle\"\n >\n <span [hidden]=\"!formData.useExternalId\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.useExternalId\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </lib-form-field-container>\n <lib-form-field-container\n [showHeader]=\"false\"\n >\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Client ID</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The client id to use when authenticating to the IDP\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter client ID\" [(ngModel)]=\"formData.clientId\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">External Auth Url</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The URL that users are directed to, to obtain a JWT\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter external auth URL\" [(ngModel)]=\"formData.externalAuthUrl\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Scopes</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"Enter as a comma or space seperated list of claims/permissions\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <lib-chips-input\n (keyup)=\"scopesOnKeyup($event)\"\n [(ngModel)]=\"formData.scopes\"\n [allowDuplicate]=\"false\"\n placeholder=\"Enter scopes\"\n [addOnBlur]=\"true\"\n separator=\",\"\n [disabled]=\"useStrictReadonlyForm\"\n ></lib-chips-input>\n </div>\n </lib-form-field-container>\n @if (showAutoEnrollment) {\n <lib-form-field-container\n [title]=\"'Auto Enrollment'\"\n [helpText]=\"'Click for more information'\"\n (helpClicked)=\"showAutoEnrollHelp()\"\n >\n <div class=\"form-field-row\">\n <div class=\"config-item\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">Auto-Enroll to Cert</div>\n <div\n (click)=\"toggleEnrollToCertEnabled()\"\n [ngClass]=\"{ on: formData.enrollToCertEnabled, 'toggle-readonly': useStrictReadonlyForm }\"\n class=\"toggle\"\n >\n <span [hidden]=\"!formData.enrollToCertEnabled\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.enrollToCertEnabled\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n <div class=\"config-item\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">Auto-Enroll to Token</div>\n <div\n (click)=\"toggleEnrollToTokenEnabled()\"\n [ngClass]=\"{ on: formData.enrollToTokenEnabled, 'toggle-readonly': useStrictReadonlyForm }\"\n class=\"toggle\"\n >\n <span [hidden]=\"!formData.enrollToTokenEnabled\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.enrollToTokenEnabled\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n </div>\n </lib-form-field-container>\n }\n <lib-form-field-toggle [(toggleOn)]=\"showMore\" (toggleOnChange)=\"showMoreChanged($event)\" style=\"margin: 0px 10px\"></lib-form-field-toggle>\n @if (showMore && showTokenType) {\n <lib-form-field-container\n [title]=\"'Target Token Type'\"\n [label]=\"'Required'\"\n [helpText]=\"'The target token type. Can be either Access or ID'\"\n class=\"form-field-advanced\"\n >\n <select\n [(ngModel)]=\"targetToken\"\n id=\"authPolicyId\"\n class=\"form-field-dropdown\"\n [disabled]=\"useStrictReadonlyForm\"\n >\n <option value=\"ACCESS\">Access</option>\n <option value=\"ID\">ID</option>\n </select>\n </lib-form-field-container>\n }\n <div [hidden]=\"!showMore\" class=\"form-group-column\">\n <lib-form-field-container\n [title]=\"'Verify OIDC Authentication'\"\n class=\"form-field-advanced\"\n [ngClass]=\"{'formFieldError': !oidcVerified && oidcErrorMessageDetail, 'formFieldSuccess': oidcVerified}\"\n >\n <div class=\"form-field-row\" #oidcVerification>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <div class=\"form-field-title\">Callback URL</div>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"This URL must be added to the list of allowed callback URLs in your OAuth provider configuration\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <div class=\"copy-link-container\">\n <pre class=\"read-only-2\" (click)=\"copyCallbackURL()\">{{ callbackURL }}</pre>\n <div class=\"copy-button\" (click)=\"copyCallbackURL()\"></div>\n </div>\n </div>\n @if (!useStrictReadonlyForm) {\n <div class=\"test-oauth-button\"\n [ngClass]=\"{'oidc-verified': oidcVerified}\"\n (click)=\"testOIDCAuthentication()\"\n >\n {{oidcVerified ? 'Verified' : 'Authenticate' }}\n @if (oauthLoading) {\n <div class=\"spinner\"></div>\n }\n @if (oidcVerified) {\n <input type=\"checkbox\" [disabled]=\"true\" [checked]=\"true\" class=\"success-check\">\n }\n </div>\n }\n </div>\n @if (oidcErrorMessageDetail) {\n <div class=\"oidc-error-message-container\">\n <code class=\"oidc-error-message-source\">{{oidcErrorMessageSource}}: </code>\n <code class=\"oidc-error-message-detail\">{{oidcErrorMessageDetail}}</code>\n @if (oidcErrorMessageDetail2) {\n <code class=\"oidc-error-message-detail2\">{{oidcErrorMessageDetail2}}</code>\n }\n @if (oidcErrorMessageDetail3) {\n <code class=\"oidc-error-message-detail2\">{{oidcErrorMessageDetail3}}</code>\n }\n </div>\n }\n @if (oidcAuthTokenClaims) {\n <div class=\"oidc-token-claims-container\">\n <code class=\"oidc-token-claims-title\">OAuth Token Claims: </code>\n <lib-json-view [showLineNumbers]=\"false\" [(data)]=\"oidcAuthTokenClaims\" [readOnly]=\"useStrictReadonlyForm\"></lib-json-view>\n </div>\n }\n </lib-form-field-container>\n <lib-form-field-container\n [title]=\"'Custom Tags'\"\n [label]=\"'OPTIONAL'\"\n class=\"form-field-advanced\"\n >\n <lib-custom-tags [(tags)]=\"formData.tags\" [readOnly]=\"useStrictReadonlyForm\"></lib-custom-tags>\n </lib-form-field-container>\n </div>\n </div>\n <div class=\"form-group-column two-fifths\">\n <lib-form-field-container\n [title]=\"'Verification'\"\n [label]=\"useStrictReadonlyForm ? '' : 'REQUIRED'\"\n >\n <div\n class=\"radio-group-container\"\n [class.radio-group-readonly]=\"useStrictReadonlyForm\"\n (keydown)=\"radioKeyDownHandler($event)\"\n [attr.tabindex]=\"useStrictReadonlyForm ? -1 : 0\"\n >\n <div\n class=\"radio-button-container\"\n [ngClass]=\"{'selected': signatureMethod === 'JWKS_ENDPOINT', 'toggle-readonly': useStrictReadonlyForm}\"\n (click)=\"!useStrictReadonlyForm && selectSignatureMethod('JWKS_ENDPOINT')\"\n >\n <div class=\"radio-button-circle\">\n <div class=\"radio-button-inner-circle\"></div>\n </div>\n <span class=\"radio-button-label\">JWKS Endpoint</span>\n </div>\n <div\n class=\"radio-button-container\"\n [ngClass]=\"{'selected': signatureMethod === 'CERT_PEM', 'toggle-readonly': useStrictReadonlyForm}\"\n (click)=\"!useStrictReadonlyForm && selectSignatureMethod('CERT_PEM')\"\n >\n <div class=\"radio-button-circle\">\n <div class=\"radio-button-inner-circle\"></div>\n </div>\n <span class=\"radio-button-label\">Cert PEM</span>\n </div>\n </div>\n @if (signatureMethod === 'JWKS_ENDPOINT') {\n <div class=\"form-field-input-group\">\n <div class=\"form-field-label-container select-file-label-container\">\n <div class=\"form-field-header\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">JWKS Endpoint</span>\n </div>\n </div>\n <input\n class=\"form-field-input\"\n placeholder=\"Enter endpoint URL\"\n [(ngModel)]=\"formData.jwksEndpoint\"\n [ngClass]=\"{error: errors['jwksEndpoint']}\"\n [disabled]=\"useStrictReadonlyForm\"\n />\n </div>\n </div>\n }\n @if (signatureMethod === 'CERT_PEM') {\n <div class=\"form-field-input-group\">\n <div class=\"form-field-label-container select-file-label-container\">\n <div class=\"form-field-header\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">PEM</span>\n </div>\n <span\n class=\"select-file-button\"\n [class.toggle-readonly]=\"useStrictReadonlyForm\"\n (click)=\"!useStrictReadonlyForm && openFileSelect($event)\"\n >\n Select File\n @if (fileSelectOpening) {\n <div class=\"spinner\"></div>\n }\n </span>\n <input\n #fileSelect\n type=\"file\"\n style=\"display:none\"\n [disabled]=\"useStrictReadonlyForm\"\n (change)=\"selectPemFile($event)\"\n >\n </div>\n <textarea\n placeholder=\"Paste pem contents or select file\"\n [(ngModel)]=\"formData.certPem\"\n [ngClass]=\"{error: errors['certPem']}\"\n [disabled]=\"useStrictReadonlyForm\"\n ></textarea>\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-header\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">KID</span>\n </div>\n <span class=\"form-field-label\" >Optional</span>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter KID\" [(ngModel)]=\"formData.kid\" [disabled]=\"useStrictReadonlyForm\"/>\n </div>\n </div>\n }\n </lib-form-field-container>\n <lib-form-field-container\n [showHeader]=\"false\"\n >\n <div class=\"config-item\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">ENABLED</div>\n <div\n (click)=\"!useStrictReadonlyForm && toggleEnabled()\"\n [ngClass]=\"{ on: formData.enabled, 'toggle-readonly': useStrictReadonlyForm }\"\n class=\"toggle\"\n >\n <span [hidden]=\"!formData.enabled\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.enabled\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n </lib-form-field-container>\n @if (showApiCalls) {\n <lib-form-field-container\n [title]=\"'API Calls'\"\n [headerActions]=\"apiOptions\"\n (actionRequested)=\"apiActionRequested($event)\"\n [class]=\"'api-data-no-wrap'\"\n >\n <div class=\"form-row\">\n <input class=\"form-field-input\" [value]=\"apiCallURL\"/>\n <div class=\"icon-copy copy-text\" (click)=\"copyToClipboard(apiCallURL)\"></div>\n </div>\n @if (formData) {\n <lib-json-view [showLineNumbers]=\"false\" [(data)]=\"apiData\" [readOnly]=\"true\" [showCopy]=\"true\"></lib-json-view>\n }\n </lib-form-field-container>\n }\n </div>\n </div>\n @if (formView === 'raw') {\n <div class=\"form-group-column\">\n @if (formData) {\n <lib-json-view [(data)]=\"formData\" [readOnly]=\"useStrictReadonlyForm\"></lib-json-view>\n }\n </div>\n }\n </div>\n</div>\n@if (isLoading) {\n <lib-loading-indicator [isLoading]=\"isLoading\"></lib-loading-indicator>\n}\n<lib-side-modal [(open)]=\"showAutoEnrollHelpModal\" [showClose]=\"true\">\n <div class=\"help-panel-content\">\n <h2 class=\"help-panel-title\">What is Auto Enrollment?</h2>\n <p class=\"help-panel-intro\">\n Auto Enrollment enables automatic identity creation when users authenticate via JWT tokens.\n </p>\n\n <div class=\"help-panel-section\">\n <h3 class=\"help-panel-subtitle\">\n <span class=\"icon-certificate\"></span>\n Auto-Enroll to Cert\n </h3>\n <p class=\"help-panel-text\">\n When enabled, the controller will automatically create an identity and enroll it with a certificate when a user authenticates using a JWT token. This is useful for certificate-based authentication workflows.\n </p>\n </div>\n\n <div class=\"help-panel-section\">\n <h3 class=\"help-panel-subtitle\">\n <span class=\"icon-key\"></span>\n Auto-Enroll to Token\n </h3>\n <p class=\"help-panel-text\">\n When enabled, the controller will automatically create an identity and enroll it with an authentication token when a user authenticates using a JWT token. This is useful for token-based authentication workflows.\n </p>\n </div>\n\n <div class=\"help-panel-note\">\n <strong>Note:</strong> These options are only available in Ziti 2.0 and later versions.\n </div>\n </div>\n</lib-side-modal>\n", styles: ["@charset \"UTF-8\";.jwt-signer-form-container{display:flex;flex-direction:column;height:100%;width:100%;align-items:center;gap:var(--gapXL)}.jwt-signer-form-container .select-file-button{padding-left:var(--paddingMedium);padding-right:var(--paddingMedium);height:1.5625rem;width:fit-content;white-space:nowrap;display:flex;align-items:center;justify-content:center;font-weight:600;font-size:.875rem;background:var(--primary);border-style:solid;border-width:.0625rem;border-color:var(--stroke);color:var(--white);cursor:pointer;border-radius:var(--inputBorderRadius);gap:var(--marginMedium);margin-top:-.3125rem}.jwt-signer-form-container .select-file-button:hover{filter:brightness(.8)}.jwt-signer-form-container .select-file-button:active{filter:grayscale(1);transform:translateY(.0625rem)}.jwt-signer-form-container .select-file-button .spinner{display:inline-block;width:.5rem;height:.5rem;border-radius:50%;background:transparent;border-top:.125rem solid white;border-right:.125rem solid white;border-bottom:.125rem solid transparent;border-left:.125rem solid transparent;-webkit-animation:loading .5s infinite linear;animation:loading .5s infinite linear}.jwt-signer-form-container .select-file-label-container{gap:var(--marginMedium)}::ng-deep .jwt-signer-form-container select:disabled,::ng-deep .jwt-signer-form-container input:disabled{opacity:.75!important;cursor:text;background-color:var(--stroke)!important}::ng-deep .api-data-no-wrap .jse-text-mode{width:100%}::ng-deep .api-data-no-wrap .jse-text-mode .cm-editor{width:100%}::ng-deep .api-data-no-wrap .jse-text-mode .cm-editor .cm-scroller{width:100%}::ng-deep .api-data-no-wrap .jse-text-mode .cm-editor .cm-scroller .cm-content{width:100%;overflow:auto}::ng-deep .api-data-no-wrap .jse-text-mode .cm-editor .cm-scroller .cm-content .\\37cr{white-space:nowrap}.radio-group-container{display:flex;gap:var(--marginLarge)}.radio-group-container:focus .radio-button-container .radio-button-circle{border-color:var(--primaryColor)}.radio-group-container .radio-button-container{display:flex;flex-direction:row;align-items:center;background-color:var(--formGroup);border-radius:var(--inputBorderRadius);width:100%;padding-left:var(--paddingMedium);padding-right:var(--paddingMedium);padding-top:var(--paddingLarge);padding-bottom:var(--paddingLarge);cursor:pointer;gap:var(--marginMedium)}.radio-group-container .radio-button-container .radio-button-circle{display:flex;width:1.3125rem;height:1.3125rem;border-radius:1.3125rem;border-width:.125rem;border-style:solid;border-color:var(--offWhite_ALWAYS);align-items:center;justify-content:center;background-color:var(--offWhite)}.radio-group-container .radio-button-container .radio-button-circle .radio-button-inner-circle{display:none;width:.9375rem;height:.9375rem;border-radius:.9375rem;align-items:center;justify-content:center;background-color:var(--primaryColor)}.radio-group-container .radio-button-container.selected .radio-button-circle .radio-button-inner-circle{display:flex}.radio-group-container .radio-button-container:active .radio-button-circle .radio-button-inner-circle{display:flex;background-color:var(--menu)}.radio-group-container .radio-button-container .radio-button-label{color:var(--offWhite_ALWAYS);font-size:.875rem;font-weight:600}.radio-button-container.toggle-readonly{cursor:default;pointer-events:none;opacity:.92}.select-file-button.toggle-readonly{cursor:default;pointer-events:none;opacity:.85}.test-oauth-button{color:var(--offWhite_ALWAYS);height:var(--defaultInputHeight);border-style:solid;border-color:var(--inputBorder);border-radius:var(--inputBorderRadius);vertical-align:middle;text-align:center;position:relative;display:flex;align-items:center;justify-content:center;overflow:hidden;transition:color .2s;font-size:.9375rem;font-weight:600;font-family:Open Sans,sans-serif;text-transform:uppercase;cursor:pointer;width:100%;background-color:var(--primaryColor);margin-top:1.5rem;max-width:15rem}.test-oauth-button.oidc-verified{filter:brightness(.95);color:var(--offWhite_ALWAYS);background-color:var(--green)}.test-oauth-button .spinner{display:inline-block;width:var(--spinnerSizeMedium);height:var(--spinnerSizeMedium);border-radius:50%;background:transparent;border-top:var(--spinnerBorderTopMedium);border-right:var(--spinnerBorderRightMedium);border-bottom:var(--spinnerBorderBottomMedium);border-left:var(--spinnerBorderLeftMedium);animation:loading .5s infinite linear;margin-left:var(--marginSmall)}.test-oauth-button:hover{filter:brightness(.95)}.test-oauth-button:active{transform:translateY(1px)}.success-check{width:1.0625rem;height:1.0625rem;cursor:pointer;background-color:var(--navigation);margin:0;margin-top:.25rem;border-radius:2rem;margin-left:var(--marginSmall)}.success-check:checked{background-color:var(--green)!important;background-image:url(/assets/images/check.png);background-size:.675rem;background-position:center center;background-repeat:no-repeat;border:none}.success-check:checked:disabled{opacity:1!important}.oidc-token-claims-container{background-color:var(--backgroundMuted);height:fit-content;display:flex;flex-direction:column;align-items:flex-start;justify-content:flex-start;padding:var(--paddingMedium);border-radius:var(--inputBorderRadius);color:var(--tableText);font-weight:600;overflow:auto}.oidc-token-claims-container .oidc-token-claims-title{font-weight:600;font-size:1rem;white-space:nowrap;margin-bottom:var(--marginMedium)}.oidc-error-message-container{background-color:var(--lightRed);height:fit-content;display:flex;flex-direction:column;align-items:flex-start;justify-content:flex-start;padding:var(--paddingMedium);border-radius:var(--inputBorderRadius);color:var(--red);font-weight:600;overflow:auto}.oidc-error-message-container .oidc-error-message-source{font-weight:600;font-size:1rem;white-space:nowrap}.oidc-error-message-container .oidc-error-message-detail2,.oidc-error-message-container .oidc-error-message-detail{margin-top:var(--marginSmall);font-weight:400;white-space:nowrap}.oidc-error-message-container::-webkit-scrollbar{height:6px;width:6px}.oidc-error-message-container::-webkit-scrollbar-thumb{background-color:var(--menu);border-radius:10px}.oidc-error-message-container:hover::-webkit-scrollbar-thumb{background-clip:unset!important}.read-only-2{display:flex;overflow:auto;white-space:nowrap;opacity:1!important;cursor:pointer;padding:var(--paddingMedium);padding-bottom:var(--paddingSmall)}.read-only-2::-webkit-scrollbar{height:6px;width:6px}.read-only-2::-webkit-scrollbar-thumb{background-color:var(--menu);border-radius:10px}.read-only-2:hover{text-decoration:underline}.read-only-2:hover::-webkit-scrollbar-thumb{background-clip:unset}.copy-link-container{display:flex;flex-direction:row;justify-content:space-between;align-items:center;opacity:1!important;cursor:text;border-radius:var(--inputBorderRadius);height:var(--defaultInputHeight);background-color:var(--backgroundMuted)!important}.copy-button{display:flex;align-items:center;justify-content:center;height:100%;width:2.575rem;margin-left:.125rem;background:url(/assets/svgs/copy.svg) no-repeat;background-size:1.125rem 1.125rem;background-position:center;cursor:pointer;border-top-right-radius:var(--inputBorderRadius);border-bottom-right-radius:var(--inputBorderRadius);background-color:#0000000f}.copy-button:hover{filter:brightness(.95);background-color:#0000001f}.help-panel-content{display:flex;flex-direction:column;padding-top:3rem}.help-panel-content .help-panel-title{margin:0 0 .25rem;color:var(--primary);font-size:1.5rem;font-weight:600;line-height:1.3;padding-right:2rem}.help-panel-content .help-panel-intro{line-height:1.6;margin-bottom:1.5rem;color:var(--tableText);font-size:.9375rem}.help-panel-content .help-panel-section{margin-bottom:1.5rem;padding:1rem;background-color:var(--navigation);border-radius:var(--inputBorderRadius);border-left:.25rem solid var(--primary)}.help-panel-content .help-panel-section .help-panel-subtitle{margin:0 0 .75rem;color:var(--primary);font-size:1.125rem;font-weight:600;display:flex;align-items:center;gap:.5rem}.help-panel-content .help-panel-section .help-panel-subtitle span[class^=icon-]{font-size:1rem;opacity:.8}.help-panel-content .help-panel-section .help-panel-text{margin:0;line-height:1.6;color:var(--tableText);font-size:.875rem}.help-panel-content .help-panel-note{padding:1rem;background-color:#ffc1071a;border-radius:var(--inputBorderRadius);border-left:.25rem solid #ffc107;color:var(--tableText);font-size:.875rem;line-height:1.6}.help-panel-content .help-panel-note strong{color:#ffc107}\n"], dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { 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: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: ChipsInputComponent, selector: "lib-chips-input", inputs: ["placeholder", "inputId", "addOnBlur", "allowDuplicate", "separator", "invalid"], outputs: ["onAdd", "onRemove", "onModelChange", "onBlur", "keyup"] }, { kind: "component", type: SideModalComponent, selector: "lib-side-modal", inputs: ["showClose", "open"], outputs: ["openChange"] }, { kind: "component", type: FormHeaderComponent, selector: "lib-form-header", inputs: ["data", "badges", "title", "moreActions", "formView", "saveDisabled", "saveTooltip", "actionButtonText", "moreActionsText", "showHeaderToggle", "showHeaderButton", "strictReadonlyUi", "multiActions"], outputs: ["formViewChange", "actionRequested", "multiActionRequested"] }, { kind: "component", type: FormFieldContainerComponent, selector: "lib-form-field-container", inputs: ["title", "title2", "titleIcon", "layout", "helpText", "helpText2", "label", "count", "action", "actionLabel", "class", "contentStyle", "contentClass", "showHeader", "showToggle", "headerActions", "headerToggle"], outputs: ["actionRequested", "headerToggleChange", "helpClicked"] }, { kind: "component", type: LoadingIndicatorComponent, selector: "lib-loading-indicator", inputs: ["isLoading"] }, { kind: "component", type: FormFieldToggleComponent, selector: "lib-form-field-toggle", inputs: ["label", "orientation", "labelOn", "labelOff", "toggleOn"], outputs: ["toggleOnChange"] }, { kind: "component", type: JsonViewComponent, selector: "lib-json-view", inputs: ["data", "schema", "readOnly", "jsonInvalid", "showCopy", "showLineNumbers"], outputs: ["dataChange", "jsonChange", "jsonInvalidChange"] }, { kind: "component", type: CustomTagsComponent, selector: "lib-custom-tags", inputs: ["tags", "readOnly"], outputs: ["tagsChange"] }] }); }
|
|
29614
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: JwtSignerFormComponent, isStandalone: false, selector: "lib-configuration", inputs: { errors: "errors" }, outputs: { close: "close" }, viewQueries: [{ propertyName: "filterInput", first: true, predicate: ["fileSelect"], descendants: true }, { propertyName: "oidcVerification", first: true, predicate: ["oidcVerification"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"projectable-form-wrapper\"\n (keyup.enter)=\"save($event)\"\n (keyup.escape)=\"closeModal(false)\"\n tabindex=\"0\"\n >\n <lib-form-header\n [data]=\"formData\"\n [title]=\"(formData.id ? 'JWT Signer Details' : 'Create JWT Signer')\"\n [moreActions]=\"moreActions\"\n [multiActions]=\"multiActions\"\n (actionRequested)=\"headerActionRequested($event)\"\n (multiActionRequested)=\"multiActionRequested($event)\"\n [(formView)]=\"formView\"\n [saveDisabled]=\"svc.saveDisabled || formDataInvalid || formPermissionSaveDisabled\"\n [saveTooltip]=\"formPermissionSaveTooltip\"\n [strictReadonlyUi]=\"useStrictReadonlyForm\"\n ></lib-form-header>\n <div class=\"jwt-signer-form-container projectable-form-container\" #scrollContainer>\n <div class=\"projectable-form-main-column form-group-row\" [hidden]=\"formView !== 'simple'\">\n <div class=\"form-group-column three-fifths\">\n <lib-form-field-container\n [title]=\"'Name'\"\n [label]=\"useStrictReadonlyForm ? '' : 'REQUIRED'\"\n >\n @if (!useStrictReadonlyForm) {\n <input class=\"form-field-input\" [(ngModel)]=\"formData.name\" [ngClass]=\"{error: errors['name']}\" placeholder=\"Name this JWT Signer\" #nameFieldInput/>\n } @else {\n <div class=\"form-field-readonly-value\">{{ formData.name }}</div>\n }\n </lib-form-field-container>\n <lib-form-field-container\n [layout]=\"'column'\"\n [showHeader]=\"false\"\n >\n <div class=\"form-field-label-container\">\n <div class=\"form-field-header\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Issuer</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The "issuer" field on the JWT Signer must match the "iss" field on the JWT\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <span class=\"form-field-label\" >{{ useStrictReadonlyForm ? '' : 'REQUIRED' }}</span>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter issuer\" [(ngModel)]=\"formData.issuer\" [ngClass]=\"{error: errors['issuer']}\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Audience</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The expected "aud" (audience) field on the JWT\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter audience\" [(ngModel)]=\"formData.audience\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-row\">\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Claims Property</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The field on the JWT for mapping to an identity. Matches the identity's id or externalId if "Use External Id" is set to true. Defaults to "sub"\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter claims property\" [(ngModel)]=\"formData.claimsProperty\" (keyup)=\"checkExternalIdToggle()\" [ngClass]=\"{error: errors['claimsProperty']}\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-header\">\n <div class=\"form-field-title-container\">\n <div class=\"config-container-label\" style=\"font-weight: 600; font-size: 14px;\">External ID</div>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"If enabled, will match the "claimsProperty" to an identity's "externalId" field. If false, it will match to the identity's id field.\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n </div>\n <div class=\"config-item\">\n <div class=\"config-container toggle-container\">\n <div class=\"form-field-title-container\">\n <div class=\"config-container-label\">Use External ID</div>\n </div>\n <div\n (click)=\"!useStrictReadonlyForm && toggleUseExternalId()\"\n [ngClass]=\"{ on: formData.useExternalId, 'toggle-readonly': useStrictReadonlyForm }\"\n class=\"toggle\"\n >\n <span [hidden]=\"!formData.useExternalId\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.useExternalId\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </lib-form-field-container>\n <lib-form-field-container\n [showHeader]=\"false\"\n >\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Client ID</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The client id to use when authenticating to the IDP\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter client ID\" [(ngModel)]=\"formData.clientId\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">External Auth Url</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The URL that users are directed to, to obtain a JWT\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter external auth URL\" [(ngModel)]=\"formData.externalAuthUrl\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Scopes</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"Enter as a comma or space seperated list of claims/permissions\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <lib-chips-input\n (keyup)=\"scopesOnKeyup($event)\"\n [(ngModel)]=\"formData.scopes\"\n [allowDuplicate]=\"false\"\n placeholder=\"Enter scopes\"\n [addOnBlur]=\"true\"\n separator=\",\"\n [disabled]=\"useStrictReadonlyForm\"\n ></lib-chips-input>\n </div>\n </lib-form-field-container>\n @if (showAutoEnrollment) {\n <lib-form-field-container\n [title]=\"'Auto Enrollment'\"\n [helpText]=\"'Click for more information'\"\n (helpClicked)=\"showAutoEnrollHelp()\"\n >\n <div class=\"form-field-row\">\n <div class=\"config-item\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">Auto-Enroll to Cert</div>\n <div\n (click)=\"toggleEnrollToCertEnabled()\"\n [ngClass]=\"{ on: formData.enrollToCertEnabled, 'toggle-readonly': useStrictReadonlyForm }\"\n class=\"toggle\"\n >\n <span [hidden]=\"!formData.enrollToCertEnabled\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.enrollToCertEnabled\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n <div class=\"config-item\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">Auto-Enroll to Token</div>\n <div\n (click)=\"toggleEnrollToTokenEnabled()\"\n [ngClass]=\"{ on: formData.enrollToTokenEnabled, 'toggle-readonly': useStrictReadonlyForm }\"\n class=\"toggle\"\n >\n <span [hidden]=\"!formData.enrollToTokenEnabled\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.enrollToTokenEnabled\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n </div>\n </lib-form-field-container>\n }\n <lib-form-field-toggle [(toggleOn)]=\"showMore\" (toggleOnChange)=\"showMoreChanged($event)\" style=\"margin: 0px 10px\"></lib-form-field-toggle>\n @if (showMore && showTokenType) {\n <lib-form-field-container\n [title]=\"'Target Token Type'\"\n [label]=\"'Required'\"\n [helpText]=\"'The target token type. Can be either Access or ID'\"\n class=\"form-field-advanced\"\n >\n <select\n [(ngModel)]=\"targetToken\"\n id=\"authPolicyId\"\n class=\"form-field-dropdown\"\n [disabled]=\"useStrictReadonlyForm\"\n >\n <option value=\"ACCESS\">Access</option>\n <option value=\"ID\">ID</option>\n </select>\n </lib-form-field-container>\n }\n <div [hidden]=\"!showMore\" class=\"form-group-column\">\n @if (showAutoEnrollment) {\n <lib-form-field-container\n [title]=\"'Auto Enrollment Options'\"\n class=\"form-field-advanced\"\n >\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Enrollment Auth Policy</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The authentication policy assigned to identities created through auto-enrollment. Defaults to the "default" policy.\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <select\n [(ngModel)]=\"enrollAuthPolicyId\"\n class=\"form-field-dropdown\"\n [disabled]=\"useStrictReadonlyForm\"\n >\n <option value=\"\">Select an Authentication Policy</option>\n @for (policy of authPolicies; track policy.id) {\n <option [value]=\"policy.id\">{{ policy.name }}</option>\n }\n </select>\n </div>\n <div class=\"form-field-row\">\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Name Claims Selector</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The claims JSON pointer selector or top level property used for the name of enrolling identities. Defaults to /sub\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter name claims selector\" [(ngModel)]=\"formData.enrollNameClaimsSelector\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Attribute Claims Selector</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The claims JSON pointer selector or top level property used for the attributes of enrolling identities.\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter attribute claims selector\" [(ngModel)]=\"formData.enrollAttributeClaimsSelector\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n </div>\n </lib-form-field-container>\n }\n <lib-form-field-container\n [title]=\"'Verify OIDC Authentication'\"\n class=\"form-field-advanced\"\n [ngClass]=\"{'formFieldError': !oidcVerified && oidcErrorMessageDetail, 'formFieldSuccess': oidcVerified}\"\n >\n <div class=\"form-field-row\" #oidcVerification>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <div class=\"form-field-title\">Callback URL</div>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"This URL must be added to the list of allowed callback URLs in your OAuth provider configuration\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <div class=\"copy-link-container\">\n <pre class=\"read-only-2\" (click)=\"copyCallbackURL()\">{{ callbackURL }}</pre>\n <div class=\"copy-button\" (click)=\"copyCallbackURL()\"></div>\n </div>\n </div>\n @if (!useStrictReadonlyForm) {\n <div class=\"test-oauth-button\"\n [ngClass]=\"{'oidc-verified': oidcVerified}\"\n (click)=\"testOIDCAuthentication()\"\n >\n {{oidcVerified ? 'Verified' : 'Authenticate' }}\n @if (oauthLoading) {\n <div class=\"spinner\"></div>\n }\n @if (oidcVerified) {\n <input type=\"checkbox\" [disabled]=\"true\" [checked]=\"true\" class=\"success-check\">\n }\n </div>\n }\n </div>\n @if (oidcErrorMessageDetail) {\n <div class=\"oidc-error-message-container\">\n <code class=\"oidc-error-message-source\">{{oidcErrorMessageSource}}: </code>\n <code class=\"oidc-error-message-detail\">{{oidcErrorMessageDetail}}</code>\n @if (oidcErrorMessageDetail2) {\n <code class=\"oidc-error-message-detail2\">{{oidcErrorMessageDetail2}}</code>\n }\n @if (oidcErrorMessageDetail3) {\n <code class=\"oidc-error-message-detail2\">{{oidcErrorMessageDetail3}}</code>\n }\n </div>\n }\n @if (oidcAuthTokenClaims) {\n <div class=\"oidc-token-claims-container\">\n <code class=\"oidc-token-claims-title\">OAuth Token Claims: </code>\n <lib-json-view [showLineNumbers]=\"false\" [(data)]=\"oidcAuthTokenClaims\" [readOnly]=\"useStrictReadonlyForm\"></lib-json-view>\n </div>\n }\n </lib-form-field-container>\n <lib-form-field-container\n [title]=\"'Custom Tags'\"\n [label]=\"'OPTIONAL'\"\n class=\"form-field-advanced\"\n >\n <lib-custom-tags [(tags)]=\"formData.tags\" [readOnly]=\"useStrictReadonlyForm\"></lib-custom-tags>\n </lib-form-field-container>\n </div>\n </div>\n <div class=\"form-group-column two-fifths\">\n <lib-form-field-container\n [title]=\"'Verification'\"\n [label]=\"useStrictReadonlyForm ? '' : 'REQUIRED'\"\n >\n <div\n class=\"radio-group-container\"\n [class.radio-group-readonly]=\"useStrictReadonlyForm\"\n (keydown)=\"radioKeyDownHandler($event)\"\n [attr.tabindex]=\"useStrictReadonlyForm ? -1 : 0\"\n >\n <div\n class=\"radio-button-container\"\n [ngClass]=\"{'selected': signatureMethod === 'JWKS_ENDPOINT', 'toggle-readonly': useStrictReadonlyForm}\"\n (click)=\"!useStrictReadonlyForm && selectSignatureMethod('JWKS_ENDPOINT')\"\n >\n <div class=\"radio-button-circle\">\n <div class=\"radio-button-inner-circle\"></div>\n </div>\n <span class=\"radio-button-label\">JWKS Endpoint</span>\n </div>\n <div\n class=\"radio-button-container\"\n [ngClass]=\"{'selected': signatureMethod === 'CERT_PEM', 'toggle-readonly': useStrictReadonlyForm}\"\n (click)=\"!useStrictReadonlyForm && selectSignatureMethod('CERT_PEM')\"\n >\n <div class=\"radio-button-circle\">\n <div class=\"radio-button-inner-circle\"></div>\n </div>\n <span class=\"radio-button-label\">Cert PEM</span>\n </div>\n </div>\n @if (signatureMethod === 'JWKS_ENDPOINT') {\n <div class=\"form-field-input-group\">\n <div class=\"form-field-label-container select-file-label-container\">\n <div class=\"form-field-header\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">JWKS Endpoint</span>\n </div>\n </div>\n <input\n class=\"form-field-input\"\n placeholder=\"Enter endpoint URL\"\n [(ngModel)]=\"formData.jwksEndpoint\"\n [ngClass]=\"{error: errors['jwksEndpoint']}\"\n [disabled]=\"useStrictReadonlyForm\"\n />\n </div>\n </div>\n }\n @if (signatureMethod === 'CERT_PEM') {\n <div class=\"form-field-input-group\">\n <div class=\"form-field-label-container select-file-label-container\">\n <div class=\"form-field-header\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">PEM</span>\n </div>\n <span\n class=\"select-file-button\"\n [class.toggle-readonly]=\"useStrictReadonlyForm\"\n (click)=\"!useStrictReadonlyForm && openFileSelect($event)\"\n >\n Select File\n @if (fileSelectOpening) {\n <div class=\"spinner\"></div>\n }\n </span>\n <input\n #fileSelect\n type=\"file\"\n style=\"display:none\"\n [disabled]=\"useStrictReadonlyForm\"\n (change)=\"selectPemFile($event)\"\n >\n </div>\n <textarea\n placeholder=\"Paste pem contents or select file\"\n [(ngModel)]=\"formData.certPem\"\n [ngClass]=\"{error: errors['certPem']}\"\n [disabled]=\"useStrictReadonlyForm\"\n ></textarea>\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-header\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">KID</span>\n </div>\n <span class=\"form-field-label\" >Optional</span>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter KID\" [(ngModel)]=\"formData.kid\" [disabled]=\"useStrictReadonlyForm\"/>\n </div>\n </div>\n }\n </lib-form-field-container>\n <lib-form-field-container\n [showHeader]=\"false\"\n >\n <div class=\"config-item\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">ENABLED</div>\n <div\n (click)=\"!useStrictReadonlyForm && toggleEnabled()\"\n [ngClass]=\"{ on: formData.enabled, 'toggle-readonly': useStrictReadonlyForm }\"\n class=\"toggle\"\n >\n <span [hidden]=\"!formData.enabled\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.enabled\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n </lib-form-field-container>\n @if (showApiCalls) {\n <lib-form-field-container\n [title]=\"'API Calls'\"\n [headerActions]=\"apiOptions\"\n (actionRequested)=\"apiActionRequested($event)\"\n [class]=\"'api-data-no-wrap'\"\n >\n <div class=\"form-row\">\n <input class=\"form-field-input\" [value]=\"apiCallURL\"/>\n <div class=\"icon-copy copy-text\" (click)=\"copyToClipboard(apiCallURL)\"></div>\n </div>\n @if (formData) {\n <lib-json-view [showLineNumbers]=\"false\" [(data)]=\"apiData\" [readOnly]=\"true\" [showCopy]=\"true\"></lib-json-view>\n }\n </lib-form-field-container>\n }\n </div>\n </div>\n @if (formView === 'raw') {\n <div class=\"form-group-column\">\n @if (formData) {\n <lib-json-view [(data)]=\"formData\" [readOnly]=\"useStrictReadonlyForm\"></lib-json-view>\n }\n </div>\n }\n </div>\n</div>\n@if (isLoading) {\n <lib-loading-indicator [isLoading]=\"isLoading\"></lib-loading-indicator>\n}\n<lib-side-modal [(open)]=\"showAutoEnrollHelpModal\" [showClose]=\"true\">\n <div class=\"help-panel-content\">\n <h2 class=\"help-panel-title\">What is Auto Enrollment?</h2>\n <p class=\"help-panel-intro\">\n Auto Enrollment enables automatic identity creation when users authenticate via JWT tokens.\n </p>\n\n <div class=\"help-panel-section\">\n <h3 class=\"help-panel-subtitle\">\n <span class=\"icon-certificate\"></span>\n Auto-Enroll to Cert\n </h3>\n <p class=\"help-panel-text\">\n When enabled, the controller will automatically create an identity and enroll it with a certificate when a user authenticates using a JWT token. This is useful for certificate-based authentication workflows.\n </p>\n </div>\n\n <div class=\"help-panel-section\">\n <h3 class=\"help-panel-subtitle\">\n <span class=\"icon-key\"></span>\n Auto-Enroll to Token\n </h3>\n <p class=\"help-panel-text\">\n When enabled, the controller will automatically create an identity and enroll it with an authentication token when a user authenticates using a JWT token. This is useful for token-based authentication workflows.\n </p>\n </div>\n\n <div class=\"help-panel-section\">\n <h3 class=\"help-panel-subtitle\">\n <span class=\"icon-lock\"></span>\n Enrollment Auth Policy\n </h3>\n <p class=\"help-panel-text\">\n The authentication policy assigned to identities that are created through auto-enrollment. When left unset, the controller's \"default\" authentication policy is used.\n </p>\n </div>\n\n <div class=\"help-panel-section\">\n <h3 class=\"help-panel-subtitle\">\n <span class=\"icon-identity\"></span>\n Name Claims Selector\n </h3>\n <p class=\"help-panel-text\">\n A JSON pointer selector (or top-level claim property) identifying which JWT claim supplies the name for enrolling identities. Defaults to <code>/sub</code> when unset.\n </p>\n </div>\n\n <div class=\"help-panel-section\">\n <h3 class=\"help-panel-subtitle\">\n <span class=\"icon-identity\"></span>\n Attribute Claims Selector\n </h3>\n <p class=\"help-panel-text\">\n A JSON pointer selector (or top-level claim property) identifying which JWT claim supplies the role attributes for enrolling identities.\n </p>\n </div>\n\n <div class=\"help-panel-note\">\n <strong>Note:</strong> These options are only available in Ziti 2.0 and later versions.\n </div>\n </div>\n</lib-side-modal>\n", styles: ["@charset \"UTF-8\";.jwt-signer-form-container{display:flex;flex-direction:column;height:100%;width:100%;align-items:center;gap:var(--gapXL)}.jwt-signer-form-container .select-file-button{padding-left:var(--paddingMedium);padding-right:var(--paddingMedium);height:1.5625rem;width:fit-content;white-space:nowrap;display:flex;align-items:center;justify-content:center;font-weight:600;font-size:.875rem;background:var(--primary);border-style:solid;border-width:.0625rem;border-color:var(--stroke);color:var(--white);cursor:pointer;border-radius:var(--inputBorderRadius);gap:var(--marginMedium);margin-top:-.3125rem}.jwt-signer-form-container .select-file-button:hover{filter:brightness(.8)}.jwt-signer-form-container .select-file-button:active{filter:grayscale(1);transform:translateY(.0625rem)}.jwt-signer-form-container .select-file-button .spinner{display:inline-block;width:.5rem;height:.5rem;border-radius:50%;background:transparent;border-top:.125rem solid white;border-right:.125rem solid white;border-bottom:.125rem solid transparent;border-left:.125rem solid transparent;-webkit-animation:loading .5s infinite linear;animation:loading .5s infinite linear}.jwt-signer-form-container .select-file-label-container{gap:var(--marginMedium)}::ng-deep .jwt-signer-form-container select:disabled,::ng-deep .jwt-signer-form-container input:disabled{opacity:.75!important;cursor:text;background-color:var(--stroke)!important}::ng-deep .api-data-no-wrap .jse-text-mode{width:100%}::ng-deep .api-data-no-wrap .jse-text-mode .cm-editor{width:100%}::ng-deep .api-data-no-wrap .jse-text-mode .cm-editor .cm-scroller{width:100%}::ng-deep .api-data-no-wrap .jse-text-mode .cm-editor .cm-scroller .cm-content{width:100%;overflow:auto}::ng-deep .api-data-no-wrap .jse-text-mode .cm-editor .cm-scroller .cm-content .\\37cr{white-space:nowrap}.radio-group-container{display:flex;gap:var(--marginLarge)}.radio-group-container:focus .radio-button-container .radio-button-circle{border-color:var(--primaryColor)}.radio-group-container .radio-button-container{display:flex;flex-direction:row;align-items:center;background-color:var(--formGroup);border-radius:var(--inputBorderRadius);width:100%;padding-left:var(--paddingMedium);padding-right:var(--paddingMedium);padding-top:var(--paddingLarge);padding-bottom:var(--paddingLarge);cursor:pointer;gap:var(--marginMedium)}.radio-group-container .radio-button-container .radio-button-circle{display:flex;width:1.3125rem;height:1.3125rem;border-radius:1.3125rem;border-width:.125rem;border-style:solid;border-color:var(--offWhite_ALWAYS);align-items:center;justify-content:center;background-color:var(--offWhite)}.radio-group-container .radio-button-container .radio-button-circle .radio-button-inner-circle{display:none;width:.9375rem;height:.9375rem;border-radius:.9375rem;align-items:center;justify-content:center;background-color:var(--primaryColor)}.radio-group-container .radio-button-container.selected .radio-button-circle .radio-button-inner-circle{display:flex}.radio-group-container .radio-button-container:active .radio-button-circle .radio-button-inner-circle{display:flex;background-color:var(--menu)}.radio-group-container .radio-button-container .radio-button-label{color:var(--offWhite_ALWAYS);font-size:.875rem;font-weight:600}.radio-button-container.toggle-readonly{cursor:default;pointer-events:none;opacity:.92}.select-file-button.toggle-readonly{cursor:default;pointer-events:none;opacity:.85}.test-oauth-button{color:var(--offWhite_ALWAYS);height:var(--defaultInputHeight);border-style:solid;border-color:var(--inputBorder);border-radius:var(--inputBorderRadius);vertical-align:middle;text-align:center;position:relative;display:flex;align-items:center;justify-content:center;overflow:hidden;transition:color .2s;font-size:.9375rem;font-weight:600;font-family:Open Sans,sans-serif;text-transform:uppercase;cursor:pointer;width:100%;background-color:var(--primaryColor);margin-top:1.5rem;max-width:15rem}.test-oauth-button.oidc-verified{filter:brightness(.95);color:var(--offWhite_ALWAYS);background-color:var(--green)}.test-oauth-button .spinner{display:inline-block;width:var(--spinnerSizeMedium);height:var(--spinnerSizeMedium);border-radius:50%;background:transparent;border-top:var(--spinnerBorderTopMedium);border-right:var(--spinnerBorderRightMedium);border-bottom:var(--spinnerBorderBottomMedium);border-left:var(--spinnerBorderLeftMedium);animation:loading .5s infinite linear;margin-left:var(--marginSmall)}.test-oauth-button:hover{filter:brightness(.95)}.test-oauth-button:active{transform:translateY(1px)}.success-check{width:1.0625rem;height:1.0625rem;cursor:pointer;background-color:var(--navigation);margin:0;margin-top:.25rem;border-radius:2rem;margin-left:var(--marginSmall)}.success-check:checked{background-color:var(--green)!important;background-image:url(/assets/images/check.png);background-size:.675rem;background-position:center center;background-repeat:no-repeat;border:none}.success-check:checked:disabled{opacity:1!important}.oidc-token-claims-container{background-color:var(--backgroundMuted);height:fit-content;display:flex;flex-direction:column;align-items:flex-start;justify-content:flex-start;padding:var(--paddingMedium);border-radius:var(--inputBorderRadius);color:var(--tableText);font-weight:600;overflow:auto}.oidc-token-claims-container .oidc-token-claims-title{font-weight:600;font-size:1rem;white-space:nowrap;margin-bottom:var(--marginMedium)}.oidc-error-message-container{background-color:var(--lightRed);height:fit-content;display:flex;flex-direction:column;align-items:flex-start;justify-content:flex-start;padding:var(--paddingMedium);border-radius:var(--inputBorderRadius);color:var(--red);font-weight:600;overflow:auto}.oidc-error-message-container .oidc-error-message-source{font-weight:600;font-size:1rem;white-space:nowrap}.oidc-error-message-container .oidc-error-message-detail2,.oidc-error-message-container .oidc-error-message-detail{margin-top:var(--marginSmall);font-weight:400;white-space:nowrap}.oidc-error-message-container::-webkit-scrollbar{height:6px;width:6px}.oidc-error-message-container::-webkit-scrollbar-thumb{background-color:var(--menu);border-radius:10px}.oidc-error-message-container:hover::-webkit-scrollbar-thumb{background-clip:unset!important}.read-only-2{display:flex;overflow:auto;white-space:nowrap;opacity:1!important;cursor:pointer;padding:var(--paddingMedium);padding-bottom:var(--paddingSmall)}.read-only-2::-webkit-scrollbar{height:6px;width:6px}.read-only-2::-webkit-scrollbar-thumb{background-color:var(--menu);border-radius:10px}.read-only-2:hover{text-decoration:underline}.read-only-2:hover::-webkit-scrollbar-thumb{background-clip:unset}.copy-link-container{display:flex;flex-direction:row;justify-content:space-between;align-items:center;opacity:1!important;cursor:text;border-radius:var(--inputBorderRadius);height:var(--defaultInputHeight);background-color:var(--backgroundMuted)!important}.copy-button{display:flex;align-items:center;justify-content:center;height:100%;width:2.575rem;margin-left:.125rem;background:url(/assets/svgs/copy.svg) no-repeat;background-size:1.125rem 1.125rem;background-position:center;cursor:pointer;border-top-right-radius:var(--inputBorderRadius);border-bottom-right-radius:var(--inputBorderRadius);background-color:#0000000f}.copy-button:hover{filter:brightness(.95);background-color:#0000001f}.help-panel-content{display:flex;flex-direction:column;padding-top:3rem}.help-panel-content .help-panel-title{margin:0 0 .25rem;color:var(--primary);font-size:1.5rem;font-weight:600;line-height:1.3;padding-right:2rem}.help-panel-content .help-panel-intro{line-height:1.6;margin-bottom:1.5rem;color:var(--tableText);font-size:.9375rem}.help-panel-content .help-panel-section{margin-bottom:1.5rem;padding:1rem;background-color:var(--navigation);border-radius:var(--inputBorderRadius);border-left:.25rem solid var(--primary)}.help-panel-content .help-panel-section .help-panel-subtitle{margin:0 0 .75rem;color:var(--primary);font-size:1.125rem;font-weight:600;display:flex;align-items:center;gap:.5rem}.help-panel-content .help-panel-section .help-panel-subtitle span[class^=icon-]{font-size:1rem;opacity:.8}.help-panel-content .help-panel-section .help-panel-text{margin:0;line-height:1.6;color:var(--tableText);font-size:.875rem}.help-panel-content .help-panel-note{padding:1rem;background-color:#ffc1071a;border-radius:var(--inputBorderRadius);border-left:.25rem solid #ffc107;color:var(--tableText);font-size:.875rem;line-height:1.6}.help-panel-content .help-panel-note strong{color:#ffc107}\n"], dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { 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: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: ChipsInputComponent, selector: "lib-chips-input", inputs: ["placeholder", "inputId", "addOnBlur", "allowDuplicate", "separator", "invalid"], outputs: ["onAdd", "onRemove", "onModelChange", "onBlur", "keyup"] }, { kind: "component", type: SideModalComponent, selector: "lib-side-modal", inputs: ["showClose", "open"], outputs: ["openChange"] }, { kind: "component", type: FormHeaderComponent, selector: "lib-form-header", inputs: ["data", "badges", "title", "moreActions", "formView", "saveDisabled", "saveTooltip", "actionButtonText", "moreActionsText", "showHeaderToggle", "showHeaderButton", "strictReadonlyUi", "multiActions"], outputs: ["formViewChange", "actionRequested", "multiActionRequested"] }, { kind: "component", type: FormFieldContainerComponent, selector: "lib-form-field-container", inputs: ["title", "title2", "titleIcon", "layout", "helpText", "helpText2", "label", "count", "action", "actionLabel", "class", "contentStyle", "contentClass", "showHeader", "showToggle", "headerActions", "headerToggle"], outputs: ["actionRequested", "headerToggleChange", "helpClicked"] }, { kind: "component", type: LoadingIndicatorComponent, selector: "lib-loading-indicator", inputs: ["isLoading"] }, { kind: "component", type: FormFieldToggleComponent, selector: "lib-form-field-toggle", inputs: ["label", "orientation", "labelOn", "labelOff", "toggleOn"], outputs: ["toggleOnChange"] }, { kind: "component", type: JsonViewComponent, selector: "lib-json-view", inputs: ["data", "schema", "readOnly", "jsonInvalid", "showCopy", "showLineNumbers"], outputs: ["dataChange", "jsonChange", "jsonInvalidChange"] }, { kind: "component", type: CustomTagsComponent, selector: "lib-custom-tags", inputs: ["tags", "readOnly"], outputs: ["tagsChange"] }] }); }
|
|
27095
29615
|
}
|
|
27096
29616
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: JwtSignerFormComponent, decorators: [{
|
|
27097
29617
|
type: Component,
|
|
27098
|
-
args: [{ selector: 'lib-configuration', standalone: false, template: "<div class=\"projectable-form-wrapper\"\n (keyup.enter)=\"save($event)\"\n (keyup.escape)=\"closeModal(false)\"\n tabindex=\"0\"\n >\n <lib-form-header\n [data]=\"formData\"\n [title]=\"(formData.id ? 'JWT Signer Details' : 'Create JWT Signer')\"\n [moreActions]=\"moreActions\"\n [multiActions]=\"multiActions\"\n (actionRequested)=\"headerActionRequested($event)\"\n (multiActionRequested)=\"multiActionRequested($event)\"\n [(formView)]=\"formView\"\n [saveDisabled]=\"svc.saveDisabled || formDataInvalid || formPermissionSaveDisabled\"\n [saveTooltip]=\"formPermissionSaveTooltip\"\n [strictReadonlyUi]=\"useStrictReadonlyForm\"\n ></lib-form-header>\n <div class=\"jwt-signer-form-container projectable-form-container\" #scrollContainer>\n <div class=\"projectable-form-main-column form-group-row\" [hidden]=\"formView !== 'simple'\">\n <div class=\"form-group-column three-fifths\">\n <lib-form-field-container\n [title]=\"'Name'\"\n [label]=\"useStrictReadonlyForm ? '' : 'REQUIRED'\"\n >\n @if (!useStrictReadonlyForm) {\n <input class=\"form-field-input\" [(ngModel)]=\"formData.name\" [ngClass]=\"{error: errors['name']}\" placeholder=\"Name this JWT Signer\" #nameFieldInput/>\n } @else {\n <div class=\"form-field-readonly-value\">{{ formData.name }}</div>\n }\n </lib-form-field-container>\n <lib-form-field-container\n [layout]=\"'column'\"\n [showHeader]=\"false\"\n >\n <div class=\"form-field-label-container\">\n <div class=\"form-field-header\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Issuer</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The "issuer" field on the JWT Signer must match the "iss" field on the JWT\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <span class=\"form-field-label\" >{{ useStrictReadonlyForm ? '' : 'REQUIRED' }}</span>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter issuer\" [(ngModel)]=\"formData.issuer\" [ngClass]=\"{error: errors['issuer']}\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Audience</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The expected "aud" (audience) field on the JWT\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter audience\" [(ngModel)]=\"formData.audience\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-row\">\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Claims Property</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The field on the JWT for mapping to an identity. Matches the identity's id or externalId if "Use External Id" is set to true. Defaults to "sub"\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter claims property\" [(ngModel)]=\"formData.claimsProperty\" (keyup)=\"checkExternalIdToggle()\" [ngClass]=\"{error: errors['claimsProperty']}\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-header\">\n <div class=\"form-field-title-container\">\n <div class=\"config-container-label\" style=\"font-weight: 600; font-size: 14px;\">External ID</div>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"If enabled, will match the "claimsProperty" to an identity's "externalId" field. If false, it will match to the identity's id field.\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n </div>\n <div class=\"config-item\">\n <div class=\"config-container toggle-container\">\n <div class=\"form-field-title-container\">\n <div class=\"config-container-label\">Use External ID</div>\n </div>\n <div\n (click)=\"!useStrictReadonlyForm && toggleUseExternalId()\"\n [ngClass]=\"{ on: formData.useExternalId, 'toggle-readonly': useStrictReadonlyForm }\"\n class=\"toggle\"\n >\n <span [hidden]=\"!formData.useExternalId\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.useExternalId\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </lib-form-field-container>\n <lib-form-field-container\n [showHeader]=\"false\"\n >\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Client ID</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The client id to use when authenticating to the IDP\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter client ID\" [(ngModel)]=\"formData.clientId\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">External Auth Url</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The URL that users are directed to, to obtain a JWT\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter external auth URL\" [(ngModel)]=\"formData.externalAuthUrl\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Scopes</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"Enter as a comma or space seperated list of claims/permissions\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <lib-chips-input\n (keyup)=\"scopesOnKeyup($event)\"\n [(ngModel)]=\"formData.scopes\"\n [allowDuplicate]=\"false\"\n placeholder=\"Enter scopes\"\n [addOnBlur]=\"true\"\n separator=\",\"\n [disabled]=\"useStrictReadonlyForm\"\n ></lib-chips-input>\n </div>\n </lib-form-field-container>\n @if (showAutoEnrollment) {\n <lib-form-field-container\n [title]=\"'Auto Enrollment'\"\n [helpText]=\"'Click for more information'\"\n (helpClicked)=\"showAutoEnrollHelp()\"\n >\n <div class=\"form-field-row\">\n <div class=\"config-item\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">Auto-Enroll to Cert</div>\n <div\n (click)=\"toggleEnrollToCertEnabled()\"\n [ngClass]=\"{ on: formData.enrollToCertEnabled, 'toggle-readonly': useStrictReadonlyForm }\"\n class=\"toggle\"\n >\n <span [hidden]=\"!formData.enrollToCertEnabled\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.enrollToCertEnabled\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n <div class=\"config-item\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">Auto-Enroll to Token</div>\n <div\n (click)=\"toggleEnrollToTokenEnabled()\"\n [ngClass]=\"{ on: formData.enrollToTokenEnabled, 'toggle-readonly': useStrictReadonlyForm }\"\n class=\"toggle\"\n >\n <span [hidden]=\"!formData.enrollToTokenEnabled\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.enrollToTokenEnabled\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n </div>\n </lib-form-field-container>\n }\n <lib-form-field-toggle [(toggleOn)]=\"showMore\" (toggleOnChange)=\"showMoreChanged($event)\" style=\"margin: 0px 10px\"></lib-form-field-toggle>\n @if (showMore && showTokenType) {\n <lib-form-field-container\n [title]=\"'Target Token Type'\"\n [label]=\"'Required'\"\n [helpText]=\"'The target token type. Can be either Access or ID'\"\n class=\"form-field-advanced\"\n >\n <select\n [(ngModel)]=\"targetToken\"\n id=\"authPolicyId\"\n class=\"form-field-dropdown\"\n [disabled]=\"useStrictReadonlyForm\"\n >\n <option value=\"ACCESS\">Access</option>\n <option value=\"ID\">ID</option>\n </select>\n </lib-form-field-container>\n }\n <div [hidden]=\"!showMore\" class=\"form-group-column\">\n <lib-form-field-container\n [title]=\"'Verify OIDC Authentication'\"\n class=\"form-field-advanced\"\n [ngClass]=\"{'formFieldError': !oidcVerified && oidcErrorMessageDetail, 'formFieldSuccess': oidcVerified}\"\n >\n <div class=\"form-field-row\" #oidcVerification>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <div class=\"form-field-title\">Callback URL</div>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"This URL must be added to the list of allowed callback URLs in your OAuth provider configuration\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <div class=\"copy-link-container\">\n <pre class=\"read-only-2\" (click)=\"copyCallbackURL()\">{{ callbackURL }}</pre>\n <div class=\"copy-button\" (click)=\"copyCallbackURL()\"></div>\n </div>\n </div>\n @if (!useStrictReadonlyForm) {\n <div class=\"test-oauth-button\"\n [ngClass]=\"{'oidc-verified': oidcVerified}\"\n (click)=\"testOIDCAuthentication()\"\n >\n {{oidcVerified ? 'Verified' : 'Authenticate' }}\n @if (oauthLoading) {\n <div class=\"spinner\"></div>\n }\n @if (oidcVerified) {\n <input type=\"checkbox\" [disabled]=\"true\" [checked]=\"true\" class=\"success-check\">\n }\n </div>\n }\n </div>\n @if (oidcErrorMessageDetail) {\n <div class=\"oidc-error-message-container\">\n <code class=\"oidc-error-message-source\">{{oidcErrorMessageSource}}: </code>\n <code class=\"oidc-error-message-detail\">{{oidcErrorMessageDetail}}</code>\n @if (oidcErrorMessageDetail2) {\n <code class=\"oidc-error-message-detail2\">{{oidcErrorMessageDetail2}}</code>\n }\n @if (oidcErrorMessageDetail3) {\n <code class=\"oidc-error-message-detail2\">{{oidcErrorMessageDetail3}}</code>\n }\n </div>\n }\n @if (oidcAuthTokenClaims) {\n <div class=\"oidc-token-claims-container\">\n <code class=\"oidc-token-claims-title\">OAuth Token Claims: </code>\n <lib-json-view [showLineNumbers]=\"false\" [(data)]=\"oidcAuthTokenClaims\" [readOnly]=\"useStrictReadonlyForm\"></lib-json-view>\n </div>\n }\n </lib-form-field-container>\n <lib-form-field-container\n [title]=\"'Custom Tags'\"\n [label]=\"'OPTIONAL'\"\n class=\"form-field-advanced\"\n >\n <lib-custom-tags [(tags)]=\"formData.tags\" [readOnly]=\"useStrictReadonlyForm\"></lib-custom-tags>\n </lib-form-field-container>\n </div>\n </div>\n <div class=\"form-group-column two-fifths\">\n <lib-form-field-container\n [title]=\"'Verification'\"\n [label]=\"useStrictReadonlyForm ? '' : 'REQUIRED'\"\n >\n <div\n class=\"radio-group-container\"\n [class.radio-group-readonly]=\"useStrictReadonlyForm\"\n (keydown)=\"radioKeyDownHandler($event)\"\n [attr.tabindex]=\"useStrictReadonlyForm ? -1 : 0\"\n >\n <div\n class=\"radio-button-container\"\n [ngClass]=\"{'selected': signatureMethod === 'JWKS_ENDPOINT', 'toggle-readonly': useStrictReadonlyForm}\"\n (click)=\"!useStrictReadonlyForm && selectSignatureMethod('JWKS_ENDPOINT')\"\n >\n <div class=\"radio-button-circle\">\n <div class=\"radio-button-inner-circle\"></div>\n </div>\n <span class=\"radio-button-label\">JWKS Endpoint</span>\n </div>\n <div\n class=\"radio-button-container\"\n [ngClass]=\"{'selected': signatureMethod === 'CERT_PEM', 'toggle-readonly': useStrictReadonlyForm}\"\n (click)=\"!useStrictReadonlyForm && selectSignatureMethod('CERT_PEM')\"\n >\n <div class=\"radio-button-circle\">\n <div class=\"radio-button-inner-circle\"></div>\n </div>\n <span class=\"radio-button-label\">Cert PEM</span>\n </div>\n </div>\n @if (signatureMethod === 'JWKS_ENDPOINT') {\n <div class=\"form-field-input-group\">\n <div class=\"form-field-label-container select-file-label-container\">\n <div class=\"form-field-header\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">JWKS Endpoint</span>\n </div>\n </div>\n <input\n class=\"form-field-input\"\n placeholder=\"Enter endpoint URL\"\n [(ngModel)]=\"formData.jwksEndpoint\"\n [ngClass]=\"{error: errors['jwksEndpoint']}\"\n [disabled]=\"useStrictReadonlyForm\"\n />\n </div>\n </div>\n }\n @if (signatureMethod === 'CERT_PEM') {\n <div class=\"form-field-input-group\">\n <div class=\"form-field-label-container select-file-label-container\">\n <div class=\"form-field-header\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">PEM</span>\n </div>\n <span\n class=\"select-file-button\"\n [class.toggle-readonly]=\"useStrictReadonlyForm\"\n (click)=\"!useStrictReadonlyForm && openFileSelect($event)\"\n >\n Select File\n @if (fileSelectOpening) {\n <div class=\"spinner\"></div>\n }\n </span>\n <input\n #fileSelect\n type=\"file\"\n style=\"display:none\"\n [disabled]=\"useStrictReadonlyForm\"\n (change)=\"selectPemFile($event)\"\n >\n </div>\n <textarea\n placeholder=\"Paste pem contents or select file\"\n [(ngModel)]=\"formData.certPem\"\n [ngClass]=\"{error: errors['certPem']}\"\n [disabled]=\"useStrictReadonlyForm\"\n ></textarea>\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-header\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">KID</span>\n </div>\n <span class=\"form-field-label\" >Optional</span>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter KID\" [(ngModel)]=\"formData.kid\" [disabled]=\"useStrictReadonlyForm\"/>\n </div>\n </div>\n }\n </lib-form-field-container>\n <lib-form-field-container\n [showHeader]=\"false\"\n >\n <div class=\"config-item\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">ENABLED</div>\n <div\n (click)=\"!useStrictReadonlyForm && toggleEnabled()\"\n [ngClass]=\"{ on: formData.enabled, 'toggle-readonly': useStrictReadonlyForm }\"\n class=\"toggle\"\n >\n <span [hidden]=\"!formData.enabled\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.enabled\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n </lib-form-field-container>\n @if (showApiCalls) {\n <lib-form-field-container\n [title]=\"'API Calls'\"\n [headerActions]=\"apiOptions\"\n (actionRequested)=\"apiActionRequested($event)\"\n [class]=\"'api-data-no-wrap'\"\n >\n <div class=\"form-row\">\n <input class=\"form-field-input\" [value]=\"apiCallURL\"/>\n <div class=\"icon-copy copy-text\" (click)=\"copyToClipboard(apiCallURL)\"></div>\n </div>\n @if (formData) {\n <lib-json-view [showLineNumbers]=\"false\" [(data)]=\"apiData\" [readOnly]=\"true\" [showCopy]=\"true\"></lib-json-view>\n }\n </lib-form-field-container>\n }\n </div>\n </div>\n @if (formView === 'raw') {\n <div class=\"form-group-column\">\n @if (formData) {\n <lib-json-view [(data)]=\"formData\" [readOnly]=\"useStrictReadonlyForm\"></lib-json-view>\n }\n </div>\n }\n </div>\n</div>\n@if (isLoading) {\n <lib-loading-indicator [isLoading]=\"isLoading\"></lib-loading-indicator>\n}\n<lib-side-modal [(open)]=\"showAutoEnrollHelpModal\" [showClose]=\"true\">\n <div class=\"help-panel-content\">\n <h2 class=\"help-panel-title\">What is Auto Enrollment?</h2>\n <p class=\"help-panel-intro\">\n Auto Enrollment enables automatic identity creation when users authenticate via JWT tokens.\n </p>\n\n <div class=\"help-panel-section\">\n <h3 class=\"help-panel-subtitle\">\n <span class=\"icon-certificate\"></span>\n Auto-Enroll to Cert\n </h3>\n <p class=\"help-panel-text\">\n When enabled, the controller will automatically create an identity and enroll it with a certificate when a user authenticates using a JWT token. This is useful for certificate-based authentication workflows.\n </p>\n </div>\n\n <div class=\"help-panel-section\">\n <h3 class=\"help-panel-subtitle\">\n <span class=\"icon-key\"></span>\n Auto-Enroll to Token\n </h3>\n <p class=\"help-panel-text\">\n When enabled, the controller will automatically create an identity and enroll it with an authentication token when a user authenticates using a JWT token. This is useful for token-based authentication workflows.\n </p>\n </div>\n\n <div class=\"help-panel-note\">\n <strong>Note:</strong> These options are only available in Ziti 2.0 and later versions.\n </div>\n </div>\n</lib-side-modal>\n", styles: ["@charset \"UTF-8\";.jwt-signer-form-container{display:flex;flex-direction:column;height:100%;width:100%;align-items:center;gap:var(--gapXL)}.jwt-signer-form-container .select-file-button{padding-left:var(--paddingMedium);padding-right:var(--paddingMedium);height:1.5625rem;width:fit-content;white-space:nowrap;display:flex;align-items:center;justify-content:center;font-weight:600;font-size:.875rem;background:var(--primary);border-style:solid;border-width:.0625rem;border-color:var(--stroke);color:var(--white);cursor:pointer;border-radius:var(--inputBorderRadius);gap:var(--marginMedium);margin-top:-.3125rem}.jwt-signer-form-container .select-file-button:hover{filter:brightness(.8)}.jwt-signer-form-container .select-file-button:active{filter:grayscale(1);transform:translateY(.0625rem)}.jwt-signer-form-container .select-file-button .spinner{display:inline-block;width:.5rem;height:.5rem;border-radius:50%;background:transparent;border-top:.125rem solid white;border-right:.125rem solid white;border-bottom:.125rem solid transparent;border-left:.125rem solid transparent;-webkit-animation:loading .5s infinite linear;animation:loading .5s infinite linear}.jwt-signer-form-container .select-file-label-container{gap:var(--marginMedium)}::ng-deep .jwt-signer-form-container select:disabled,::ng-deep .jwt-signer-form-container input:disabled{opacity:.75!important;cursor:text;background-color:var(--stroke)!important}::ng-deep .api-data-no-wrap .jse-text-mode{width:100%}::ng-deep .api-data-no-wrap .jse-text-mode .cm-editor{width:100%}::ng-deep .api-data-no-wrap .jse-text-mode .cm-editor .cm-scroller{width:100%}::ng-deep .api-data-no-wrap .jse-text-mode .cm-editor .cm-scroller .cm-content{width:100%;overflow:auto}::ng-deep .api-data-no-wrap .jse-text-mode .cm-editor .cm-scroller .cm-content .\\37cr{white-space:nowrap}.radio-group-container{display:flex;gap:var(--marginLarge)}.radio-group-container:focus .radio-button-container .radio-button-circle{border-color:var(--primaryColor)}.radio-group-container .radio-button-container{display:flex;flex-direction:row;align-items:center;background-color:var(--formGroup);border-radius:var(--inputBorderRadius);width:100%;padding-left:var(--paddingMedium);padding-right:var(--paddingMedium);padding-top:var(--paddingLarge);padding-bottom:var(--paddingLarge);cursor:pointer;gap:var(--marginMedium)}.radio-group-container .radio-button-container .radio-button-circle{display:flex;width:1.3125rem;height:1.3125rem;border-radius:1.3125rem;border-width:.125rem;border-style:solid;border-color:var(--offWhite_ALWAYS);align-items:center;justify-content:center;background-color:var(--offWhite)}.radio-group-container .radio-button-container .radio-button-circle .radio-button-inner-circle{display:none;width:.9375rem;height:.9375rem;border-radius:.9375rem;align-items:center;justify-content:center;background-color:var(--primaryColor)}.radio-group-container .radio-button-container.selected .radio-button-circle .radio-button-inner-circle{display:flex}.radio-group-container .radio-button-container:active .radio-button-circle .radio-button-inner-circle{display:flex;background-color:var(--menu)}.radio-group-container .radio-button-container .radio-button-label{color:var(--offWhite_ALWAYS);font-size:.875rem;font-weight:600}.radio-button-container.toggle-readonly{cursor:default;pointer-events:none;opacity:.92}.select-file-button.toggle-readonly{cursor:default;pointer-events:none;opacity:.85}.test-oauth-button{color:var(--offWhite_ALWAYS);height:var(--defaultInputHeight);border-style:solid;border-color:var(--inputBorder);border-radius:var(--inputBorderRadius);vertical-align:middle;text-align:center;position:relative;display:flex;align-items:center;justify-content:center;overflow:hidden;transition:color .2s;font-size:.9375rem;font-weight:600;font-family:Open Sans,sans-serif;text-transform:uppercase;cursor:pointer;width:100%;background-color:var(--primaryColor);margin-top:1.5rem;max-width:15rem}.test-oauth-button.oidc-verified{filter:brightness(.95);color:var(--offWhite_ALWAYS);background-color:var(--green)}.test-oauth-button .spinner{display:inline-block;width:var(--spinnerSizeMedium);height:var(--spinnerSizeMedium);border-radius:50%;background:transparent;border-top:var(--spinnerBorderTopMedium);border-right:var(--spinnerBorderRightMedium);border-bottom:var(--spinnerBorderBottomMedium);border-left:var(--spinnerBorderLeftMedium);animation:loading .5s infinite linear;margin-left:var(--marginSmall)}.test-oauth-button:hover{filter:brightness(.95)}.test-oauth-button:active{transform:translateY(1px)}.success-check{width:1.0625rem;height:1.0625rem;cursor:pointer;background-color:var(--navigation);margin:0;margin-top:.25rem;border-radius:2rem;margin-left:var(--marginSmall)}.success-check:checked{background-color:var(--green)!important;background-image:url(/assets/images/check.png);background-size:.675rem;background-position:center center;background-repeat:no-repeat;border:none}.success-check:checked:disabled{opacity:1!important}.oidc-token-claims-container{background-color:var(--backgroundMuted);height:fit-content;display:flex;flex-direction:column;align-items:flex-start;justify-content:flex-start;padding:var(--paddingMedium);border-radius:var(--inputBorderRadius);color:var(--tableText);font-weight:600;overflow:auto}.oidc-token-claims-container .oidc-token-claims-title{font-weight:600;font-size:1rem;white-space:nowrap;margin-bottom:var(--marginMedium)}.oidc-error-message-container{background-color:var(--lightRed);height:fit-content;display:flex;flex-direction:column;align-items:flex-start;justify-content:flex-start;padding:var(--paddingMedium);border-radius:var(--inputBorderRadius);color:var(--red);font-weight:600;overflow:auto}.oidc-error-message-container .oidc-error-message-source{font-weight:600;font-size:1rem;white-space:nowrap}.oidc-error-message-container .oidc-error-message-detail2,.oidc-error-message-container .oidc-error-message-detail{margin-top:var(--marginSmall);font-weight:400;white-space:nowrap}.oidc-error-message-container::-webkit-scrollbar{height:6px;width:6px}.oidc-error-message-container::-webkit-scrollbar-thumb{background-color:var(--menu);border-radius:10px}.oidc-error-message-container:hover::-webkit-scrollbar-thumb{background-clip:unset!important}.read-only-2{display:flex;overflow:auto;white-space:nowrap;opacity:1!important;cursor:pointer;padding:var(--paddingMedium);padding-bottom:var(--paddingSmall)}.read-only-2::-webkit-scrollbar{height:6px;width:6px}.read-only-2::-webkit-scrollbar-thumb{background-color:var(--menu);border-radius:10px}.read-only-2:hover{text-decoration:underline}.read-only-2:hover::-webkit-scrollbar-thumb{background-clip:unset}.copy-link-container{display:flex;flex-direction:row;justify-content:space-between;align-items:center;opacity:1!important;cursor:text;border-radius:var(--inputBorderRadius);height:var(--defaultInputHeight);background-color:var(--backgroundMuted)!important}.copy-button{display:flex;align-items:center;justify-content:center;height:100%;width:2.575rem;margin-left:.125rem;background:url(/assets/svgs/copy.svg) no-repeat;background-size:1.125rem 1.125rem;background-position:center;cursor:pointer;border-top-right-radius:var(--inputBorderRadius);border-bottom-right-radius:var(--inputBorderRadius);background-color:#0000000f}.copy-button:hover{filter:brightness(.95);background-color:#0000001f}.help-panel-content{display:flex;flex-direction:column;padding-top:3rem}.help-panel-content .help-panel-title{margin:0 0 .25rem;color:var(--primary);font-size:1.5rem;font-weight:600;line-height:1.3;padding-right:2rem}.help-panel-content .help-panel-intro{line-height:1.6;margin-bottom:1.5rem;color:var(--tableText);font-size:.9375rem}.help-panel-content .help-panel-section{margin-bottom:1.5rem;padding:1rem;background-color:var(--navigation);border-radius:var(--inputBorderRadius);border-left:.25rem solid var(--primary)}.help-panel-content .help-panel-section .help-panel-subtitle{margin:0 0 .75rem;color:var(--primary);font-size:1.125rem;font-weight:600;display:flex;align-items:center;gap:.5rem}.help-panel-content .help-panel-section .help-panel-subtitle span[class^=icon-]{font-size:1rem;opacity:.8}.help-panel-content .help-panel-section .help-panel-text{margin:0;line-height:1.6;color:var(--tableText);font-size:.875rem}.help-panel-content .help-panel-note{padding:1rem;background-color:#ffc1071a;border-radius:var(--inputBorderRadius);border-left:.25rem solid #ffc107;color:var(--tableText);font-size:.875rem;line-height:1.6}.help-panel-content .help-panel-note strong{color:#ffc107}\n"] }]
|
|
29618
|
+
args: [{ selector: 'lib-configuration', standalone: false, template: "<div class=\"projectable-form-wrapper\"\n (keyup.enter)=\"save($event)\"\n (keyup.escape)=\"closeModal(false)\"\n tabindex=\"0\"\n >\n <lib-form-header\n [data]=\"formData\"\n [title]=\"(formData.id ? 'JWT Signer Details' : 'Create JWT Signer')\"\n [moreActions]=\"moreActions\"\n [multiActions]=\"multiActions\"\n (actionRequested)=\"headerActionRequested($event)\"\n (multiActionRequested)=\"multiActionRequested($event)\"\n [(formView)]=\"formView\"\n [saveDisabled]=\"svc.saveDisabled || formDataInvalid || formPermissionSaveDisabled\"\n [saveTooltip]=\"formPermissionSaveTooltip\"\n [strictReadonlyUi]=\"useStrictReadonlyForm\"\n ></lib-form-header>\n <div class=\"jwt-signer-form-container projectable-form-container\" #scrollContainer>\n <div class=\"projectable-form-main-column form-group-row\" [hidden]=\"formView !== 'simple'\">\n <div class=\"form-group-column three-fifths\">\n <lib-form-field-container\n [title]=\"'Name'\"\n [label]=\"useStrictReadonlyForm ? '' : 'REQUIRED'\"\n >\n @if (!useStrictReadonlyForm) {\n <input class=\"form-field-input\" [(ngModel)]=\"formData.name\" [ngClass]=\"{error: errors['name']}\" placeholder=\"Name this JWT Signer\" #nameFieldInput/>\n } @else {\n <div class=\"form-field-readonly-value\">{{ formData.name }}</div>\n }\n </lib-form-field-container>\n <lib-form-field-container\n [layout]=\"'column'\"\n [showHeader]=\"false\"\n >\n <div class=\"form-field-label-container\">\n <div class=\"form-field-header\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Issuer</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The "issuer" field on the JWT Signer must match the "iss" field on the JWT\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <span class=\"form-field-label\" >{{ useStrictReadonlyForm ? '' : 'REQUIRED' }}</span>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter issuer\" [(ngModel)]=\"formData.issuer\" [ngClass]=\"{error: errors['issuer']}\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Audience</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The expected "aud" (audience) field on the JWT\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter audience\" [(ngModel)]=\"formData.audience\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-row\">\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Claims Property</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The field on the JWT for mapping to an identity. Matches the identity's id or externalId if "Use External Id" is set to true. Defaults to "sub"\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter claims property\" [(ngModel)]=\"formData.claimsProperty\" (keyup)=\"checkExternalIdToggle()\" [ngClass]=\"{error: errors['claimsProperty']}\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-header\">\n <div class=\"form-field-title-container\">\n <div class=\"config-container-label\" style=\"font-weight: 600; font-size: 14px;\">External ID</div>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"If enabled, will match the "claimsProperty" to an identity's "externalId" field. If false, it will match to the identity's id field.\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n </div>\n <div class=\"config-item\">\n <div class=\"config-container toggle-container\">\n <div class=\"form-field-title-container\">\n <div class=\"config-container-label\">Use External ID</div>\n </div>\n <div\n (click)=\"!useStrictReadonlyForm && toggleUseExternalId()\"\n [ngClass]=\"{ on: formData.useExternalId, 'toggle-readonly': useStrictReadonlyForm }\"\n class=\"toggle\"\n >\n <span [hidden]=\"!formData.useExternalId\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.useExternalId\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </lib-form-field-container>\n <lib-form-field-container\n [showHeader]=\"false\"\n >\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Client ID</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The client id to use when authenticating to the IDP\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter client ID\" [(ngModel)]=\"formData.clientId\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">External Auth Url</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The URL that users are directed to, to obtain a JWT\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter external auth URL\" [(ngModel)]=\"formData.externalAuthUrl\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Scopes</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"Enter as a comma or space seperated list of claims/permissions\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <lib-chips-input\n (keyup)=\"scopesOnKeyup($event)\"\n [(ngModel)]=\"formData.scopes\"\n [allowDuplicate]=\"false\"\n placeholder=\"Enter scopes\"\n [addOnBlur]=\"true\"\n separator=\",\"\n [disabled]=\"useStrictReadonlyForm\"\n ></lib-chips-input>\n </div>\n </lib-form-field-container>\n @if (showAutoEnrollment) {\n <lib-form-field-container\n [title]=\"'Auto Enrollment'\"\n [helpText]=\"'Click for more information'\"\n (helpClicked)=\"showAutoEnrollHelp()\"\n >\n <div class=\"form-field-row\">\n <div class=\"config-item\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">Auto-Enroll to Cert</div>\n <div\n (click)=\"toggleEnrollToCertEnabled()\"\n [ngClass]=\"{ on: formData.enrollToCertEnabled, 'toggle-readonly': useStrictReadonlyForm }\"\n class=\"toggle\"\n >\n <span [hidden]=\"!formData.enrollToCertEnabled\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.enrollToCertEnabled\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n <div class=\"config-item\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">Auto-Enroll to Token</div>\n <div\n (click)=\"toggleEnrollToTokenEnabled()\"\n [ngClass]=\"{ on: formData.enrollToTokenEnabled, 'toggle-readonly': useStrictReadonlyForm }\"\n class=\"toggle\"\n >\n <span [hidden]=\"!formData.enrollToTokenEnabled\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.enrollToTokenEnabled\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n </div>\n </lib-form-field-container>\n }\n <lib-form-field-toggle [(toggleOn)]=\"showMore\" (toggleOnChange)=\"showMoreChanged($event)\" style=\"margin: 0px 10px\"></lib-form-field-toggle>\n @if (showMore && showTokenType) {\n <lib-form-field-container\n [title]=\"'Target Token Type'\"\n [label]=\"'Required'\"\n [helpText]=\"'The target token type. Can be either Access or ID'\"\n class=\"form-field-advanced\"\n >\n <select\n [(ngModel)]=\"targetToken\"\n id=\"authPolicyId\"\n class=\"form-field-dropdown\"\n [disabled]=\"useStrictReadonlyForm\"\n >\n <option value=\"ACCESS\">Access</option>\n <option value=\"ID\">ID</option>\n </select>\n </lib-form-field-container>\n }\n <div [hidden]=\"!showMore\" class=\"form-group-column\">\n @if (showAutoEnrollment) {\n <lib-form-field-container\n [title]=\"'Auto Enrollment Options'\"\n class=\"form-field-advanced\"\n >\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Enrollment Auth Policy</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The authentication policy assigned to identities created through auto-enrollment. Defaults to the "default" policy.\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <select\n [(ngModel)]=\"enrollAuthPolicyId\"\n class=\"form-field-dropdown\"\n [disabled]=\"useStrictReadonlyForm\"\n >\n <option value=\"\">Select an Authentication Policy</option>\n @for (policy of authPolicies; track policy.id) {\n <option [value]=\"policy.id\">{{ policy.name }}</option>\n }\n </select>\n </div>\n <div class=\"form-field-row\">\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Name Claims Selector</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The claims JSON pointer selector or top level property used for the name of enrolling identities. Defaults to /sub\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter name claims selector\" [(ngModel)]=\"formData.enrollNameClaimsSelector\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">Attribute Claims Selector</span>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"The claims JSON pointer selector or top level property used for the attributes of enrolling identities.\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter attribute claims selector\" [(ngModel)]=\"formData.enrollAttributeClaimsSelector\" [disabled]=\"useStrictReadonlyForm\" />\n </div>\n </div>\n </lib-form-field-container>\n }\n <lib-form-field-container\n [title]=\"'Verify OIDC Authentication'\"\n class=\"form-field-advanced\"\n [ngClass]=\"{'formFieldError': !oidcVerified && oidcErrorMessageDetail, 'formFieldSuccess': oidcVerified}\"\n >\n <div class=\"form-field-row\" #oidcVerification>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-title-container\">\n <div class=\"form-field-title\">Callback URL</div>\n <div\n class=\"form-field-info infoicon\"\n matTooltip=\"This URL must be added to the list of allowed callback URLs in your OAuth provider configuration\"\n matTooltipPosition=\"below\"\n ></div>\n </div>\n <div class=\"copy-link-container\">\n <pre class=\"read-only-2\" (click)=\"copyCallbackURL()\">{{ callbackURL }}</pre>\n <div class=\"copy-button\" (click)=\"copyCallbackURL()\"></div>\n </div>\n </div>\n @if (!useStrictReadonlyForm) {\n <div class=\"test-oauth-button\"\n [ngClass]=\"{'oidc-verified': oidcVerified}\"\n (click)=\"testOIDCAuthentication()\"\n >\n {{oidcVerified ? 'Verified' : 'Authenticate' }}\n @if (oauthLoading) {\n <div class=\"spinner\"></div>\n }\n @if (oidcVerified) {\n <input type=\"checkbox\" [disabled]=\"true\" [checked]=\"true\" class=\"success-check\">\n }\n </div>\n }\n </div>\n @if (oidcErrorMessageDetail) {\n <div class=\"oidc-error-message-container\">\n <code class=\"oidc-error-message-source\">{{oidcErrorMessageSource}}: </code>\n <code class=\"oidc-error-message-detail\">{{oidcErrorMessageDetail}}</code>\n @if (oidcErrorMessageDetail2) {\n <code class=\"oidc-error-message-detail2\">{{oidcErrorMessageDetail2}}</code>\n }\n @if (oidcErrorMessageDetail3) {\n <code class=\"oidc-error-message-detail2\">{{oidcErrorMessageDetail3}}</code>\n }\n </div>\n }\n @if (oidcAuthTokenClaims) {\n <div class=\"oidc-token-claims-container\">\n <code class=\"oidc-token-claims-title\">OAuth Token Claims: </code>\n <lib-json-view [showLineNumbers]=\"false\" [(data)]=\"oidcAuthTokenClaims\" [readOnly]=\"useStrictReadonlyForm\"></lib-json-view>\n </div>\n }\n </lib-form-field-container>\n <lib-form-field-container\n [title]=\"'Custom Tags'\"\n [label]=\"'OPTIONAL'\"\n class=\"form-field-advanced\"\n >\n <lib-custom-tags [(tags)]=\"formData.tags\" [readOnly]=\"useStrictReadonlyForm\"></lib-custom-tags>\n </lib-form-field-container>\n </div>\n </div>\n <div class=\"form-group-column two-fifths\">\n <lib-form-field-container\n [title]=\"'Verification'\"\n [label]=\"useStrictReadonlyForm ? '' : 'REQUIRED'\"\n >\n <div\n class=\"radio-group-container\"\n [class.radio-group-readonly]=\"useStrictReadonlyForm\"\n (keydown)=\"radioKeyDownHandler($event)\"\n [attr.tabindex]=\"useStrictReadonlyForm ? -1 : 0\"\n >\n <div\n class=\"radio-button-container\"\n [ngClass]=\"{'selected': signatureMethod === 'JWKS_ENDPOINT', 'toggle-readonly': useStrictReadonlyForm}\"\n (click)=\"!useStrictReadonlyForm && selectSignatureMethod('JWKS_ENDPOINT')\"\n >\n <div class=\"radio-button-circle\">\n <div class=\"radio-button-inner-circle\"></div>\n </div>\n <span class=\"radio-button-label\">JWKS Endpoint</span>\n </div>\n <div\n class=\"radio-button-container\"\n [ngClass]=\"{'selected': signatureMethod === 'CERT_PEM', 'toggle-readonly': useStrictReadonlyForm}\"\n (click)=\"!useStrictReadonlyForm && selectSignatureMethod('CERT_PEM')\"\n >\n <div class=\"radio-button-circle\">\n <div class=\"radio-button-inner-circle\"></div>\n </div>\n <span class=\"radio-button-label\">Cert PEM</span>\n </div>\n </div>\n @if (signatureMethod === 'JWKS_ENDPOINT') {\n <div class=\"form-field-input-group\">\n <div class=\"form-field-label-container select-file-label-container\">\n <div class=\"form-field-header\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">JWKS Endpoint</span>\n </div>\n </div>\n <input\n class=\"form-field-input\"\n placeholder=\"Enter endpoint URL\"\n [(ngModel)]=\"formData.jwksEndpoint\"\n [ngClass]=\"{error: errors['jwksEndpoint']}\"\n [disabled]=\"useStrictReadonlyForm\"\n />\n </div>\n </div>\n }\n @if (signatureMethod === 'CERT_PEM') {\n <div class=\"form-field-input-group\">\n <div class=\"form-field-label-container select-file-label-container\">\n <div class=\"form-field-header\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">PEM</span>\n </div>\n <span\n class=\"select-file-button\"\n [class.toggle-readonly]=\"useStrictReadonlyForm\"\n (click)=\"!useStrictReadonlyForm && openFileSelect($event)\"\n >\n Select File\n @if (fileSelectOpening) {\n <div class=\"spinner\"></div>\n }\n </span>\n <input\n #fileSelect\n type=\"file\"\n style=\"display:none\"\n [disabled]=\"useStrictReadonlyForm\"\n (change)=\"selectPemFile($event)\"\n >\n </div>\n <textarea\n placeholder=\"Paste pem contents or select file\"\n [(ngModel)]=\"formData.certPem\"\n [ngClass]=\"{error: errors['certPem']}\"\n [disabled]=\"useStrictReadonlyForm\"\n ></textarea>\n </div>\n <div class=\"form-field-label-container\">\n <div class=\"form-field-header\">\n <div class=\"form-field-title-container\">\n <span class=\"form-field-title\">KID</span>\n </div>\n <span class=\"form-field-label\" >Optional</span>\n </div>\n <input class=\"form-field-input\" placeholder=\"Enter KID\" [(ngModel)]=\"formData.kid\" [disabled]=\"useStrictReadonlyForm\"/>\n </div>\n </div>\n }\n </lib-form-field-container>\n <lib-form-field-container\n [showHeader]=\"false\"\n >\n <div class=\"config-item\">\n <div class=\"config-container toggle-container\">\n <div class=\"config-container-label\">ENABLED</div>\n <div\n (click)=\"!useStrictReadonlyForm && toggleEnabled()\"\n [ngClass]=\"{ on: formData.enabled, 'toggle-readonly': useStrictReadonlyForm }\"\n class=\"toggle\"\n >\n <span [hidden]=\"!formData.enabled\" class=\"on-label\">YES</span>\n <span [hidden]=\"formData.enabled\" class=\"off-label\">NO</span>\n <div class=\"switch\"></div>\n </div>\n </div>\n </div>\n </lib-form-field-container>\n @if (showApiCalls) {\n <lib-form-field-container\n [title]=\"'API Calls'\"\n [headerActions]=\"apiOptions\"\n (actionRequested)=\"apiActionRequested($event)\"\n [class]=\"'api-data-no-wrap'\"\n >\n <div class=\"form-row\">\n <input class=\"form-field-input\" [value]=\"apiCallURL\"/>\n <div class=\"icon-copy copy-text\" (click)=\"copyToClipboard(apiCallURL)\"></div>\n </div>\n @if (formData) {\n <lib-json-view [showLineNumbers]=\"false\" [(data)]=\"apiData\" [readOnly]=\"true\" [showCopy]=\"true\"></lib-json-view>\n }\n </lib-form-field-container>\n }\n </div>\n </div>\n @if (formView === 'raw') {\n <div class=\"form-group-column\">\n @if (formData) {\n <lib-json-view [(data)]=\"formData\" [readOnly]=\"useStrictReadonlyForm\"></lib-json-view>\n }\n </div>\n }\n </div>\n</div>\n@if (isLoading) {\n <lib-loading-indicator [isLoading]=\"isLoading\"></lib-loading-indicator>\n}\n<lib-side-modal [(open)]=\"showAutoEnrollHelpModal\" [showClose]=\"true\">\n <div class=\"help-panel-content\">\n <h2 class=\"help-panel-title\">What is Auto Enrollment?</h2>\n <p class=\"help-panel-intro\">\n Auto Enrollment enables automatic identity creation when users authenticate via JWT tokens.\n </p>\n\n <div class=\"help-panel-section\">\n <h3 class=\"help-panel-subtitle\">\n <span class=\"icon-certificate\"></span>\n Auto-Enroll to Cert\n </h3>\n <p class=\"help-panel-text\">\n When enabled, the controller will automatically create an identity and enroll it with a certificate when a user authenticates using a JWT token. This is useful for certificate-based authentication workflows.\n </p>\n </div>\n\n <div class=\"help-panel-section\">\n <h3 class=\"help-panel-subtitle\">\n <span class=\"icon-key\"></span>\n Auto-Enroll to Token\n </h3>\n <p class=\"help-panel-text\">\n When enabled, the controller will automatically create an identity and enroll it with an authentication token when a user authenticates using a JWT token. This is useful for token-based authentication workflows.\n </p>\n </div>\n\n <div class=\"help-panel-section\">\n <h3 class=\"help-panel-subtitle\">\n <span class=\"icon-lock\"></span>\n Enrollment Auth Policy\n </h3>\n <p class=\"help-panel-text\">\n The authentication policy assigned to identities that are created through auto-enrollment. When left unset, the controller's \"default\" authentication policy is used.\n </p>\n </div>\n\n <div class=\"help-panel-section\">\n <h3 class=\"help-panel-subtitle\">\n <span class=\"icon-identity\"></span>\n Name Claims Selector\n </h3>\n <p class=\"help-panel-text\">\n A JSON pointer selector (or top-level claim property) identifying which JWT claim supplies the name for enrolling identities. Defaults to <code>/sub</code> when unset.\n </p>\n </div>\n\n <div class=\"help-panel-section\">\n <h3 class=\"help-panel-subtitle\">\n <span class=\"icon-identity\"></span>\n Attribute Claims Selector\n </h3>\n <p class=\"help-panel-text\">\n A JSON pointer selector (or top-level claim property) identifying which JWT claim supplies the role attributes for enrolling identities.\n </p>\n </div>\n\n <div class=\"help-panel-note\">\n <strong>Note:</strong> These options are only available in Ziti 2.0 and later versions.\n </div>\n </div>\n</lib-side-modal>\n", styles: ["@charset \"UTF-8\";.jwt-signer-form-container{display:flex;flex-direction:column;height:100%;width:100%;align-items:center;gap:var(--gapXL)}.jwt-signer-form-container .select-file-button{padding-left:var(--paddingMedium);padding-right:var(--paddingMedium);height:1.5625rem;width:fit-content;white-space:nowrap;display:flex;align-items:center;justify-content:center;font-weight:600;font-size:.875rem;background:var(--primary);border-style:solid;border-width:.0625rem;border-color:var(--stroke);color:var(--white);cursor:pointer;border-radius:var(--inputBorderRadius);gap:var(--marginMedium);margin-top:-.3125rem}.jwt-signer-form-container .select-file-button:hover{filter:brightness(.8)}.jwt-signer-form-container .select-file-button:active{filter:grayscale(1);transform:translateY(.0625rem)}.jwt-signer-form-container .select-file-button .spinner{display:inline-block;width:.5rem;height:.5rem;border-radius:50%;background:transparent;border-top:.125rem solid white;border-right:.125rem solid white;border-bottom:.125rem solid transparent;border-left:.125rem solid transparent;-webkit-animation:loading .5s infinite linear;animation:loading .5s infinite linear}.jwt-signer-form-container .select-file-label-container{gap:var(--marginMedium)}::ng-deep .jwt-signer-form-container select:disabled,::ng-deep .jwt-signer-form-container input:disabled{opacity:.75!important;cursor:text;background-color:var(--stroke)!important}::ng-deep .api-data-no-wrap .jse-text-mode{width:100%}::ng-deep .api-data-no-wrap .jse-text-mode .cm-editor{width:100%}::ng-deep .api-data-no-wrap .jse-text-mode .cm-editor .cm-scroller{width:100%}::ng-deep .api-data-no-wrap .jse-text-mode .cm-editor .cm-scroller .cm-content{width:100%;overflow:auto}::ng-deep .api-data-no-wrap .jse-text-mode .cm-editor .cm-scroller .cm-content .\\37cr{white-space:nowrap}.radio-group-container{display:flex;gap:var(--marginLarge)}.radio-group-container:focus .radio-button-container .radio-button-circle{border-color:var(--primaryColor)}.radio-group-container .radio-button-container{display:flex;flex-direction:row;align-items:center;background-color:var(--formGroup);border-radius:var(--inputBorderRadius);width:100%;padding-left:var(--paddingMedium);padding-right:var(--paddingMedium);padding-top:var(--paddingLarge);padding-bottom:var(--paddingLarge);cursor:pointer;gap:var(--marginMedium)}.radio-group-container .radio-button-container .radio-button-circle{display:flex;width:1.3125rem;height:1.3125rem;border-radius:1.3125rem;border-width:.125rem;border-style:solid;border-color:var(--offWhite_ALWAYS);align-items:center;justify-content:center;background-color:var(--offWhite)}.radio-group-container .radio-button-container .radio-button-circle .radio-button-inner-circle{display:none;width:.9375rem;height:.9375rem;border-radius:.9375rem;align-items:center;justify-content:center;background-color:var(--primaryColor)}.radio-group-container .radio-button-container.selected .radio-button-circle .radio-button-inner-circle{display:flex}.radio-group-container .radio-button-container:active .radio-button-circle .radio-button-inner-circle{display:flex;background-color:var(--menu)}.radio-group-container .radio-button-container .radio-button-label{color:var(--offWhite_ALWAYS);font-size:.875rem;font-weight:600}.radio-button-container.toggle-readonly{cursor:default;pointer-events:none;opacity:.92}.select-file-button.toggle-readonly{cursor:default;pointer-events:none;opacity:.85}.test-oauth-button{color:var(--offWhite_ALWAYS);height:var(--defaultInputHeight);border-style:solid;border-color:var(--inputBorder);border-radius:var(--inputBorderRadius);vertical-align:middle;text-align:center;position:relative;display:flex;align-items:center;justify-content:center;overflow:hidden;transition:color .2s;font-size:.9375rem;font-weight:600;font-family:Open Sans,sans-serif;text-transform:uppercase;cursor:pointer;width:100%;background-color:var(--primaryColor);margin-top:1.5rem;max-width:15rem}.test-oauth-button.oidc-verified{filter:brightness(.95);color:var(--offWhite_ALWAYS);background-color:var(--green)}.test-oauth-button .spinner{display:inline-block;width:var(--spinnerSizeMedium);height:var(--spinnerSizeMedium);border-radius:50%;background:transparent;border-top:var(--spinnerBorderTopMedium);border-right:var(--spinnerBorderRightMedium);border-bottom:var(--spinnerBorderBottomMedium);border-left:var(--spinnerBorderLeftMedium);animation:loading .5s infinite linear;margin-left:var(--marginSmall)}.test-oauth-button:hover{filter:brightness(.95)}.test-oauth-button:active{transform:translateY(1px)}.success-check{width:1.0625rem;height:1.0625rem;cursor:pointer;background-color:var(--navigation);margin:0;margin-top:.25rem;border-radius:2rem;margin-left:var(--marginSmall)}.success-check:checked{background-color:var(--green)!important;background-image:url(/assets/images/check.png);background-size:.675rem;background-position:center center;background-repeat:no-repeat;border:none}.success-check:checked:disabled{opacity:1!important}.oidc-token-claims-container{background-color:var(--backgroundMuted);height:fit-content;display:flex;flex-direction:column;align-items:flex-start;justify-content:flex-start;padding:var(--paddingMedium);border-radius:var(--inputBorderRadius);color:var(--tableText);font-weight:600;overflow:auto}.oidc-token-claims-container .oidc-token-claims-title{font-weight:600;font-size:1rem;white-space:nowrap;margin-bottom:var(--marginMedium)}.oidc-error-message-container{background-color:var(--lightRed);height:fit-content;display:flex;flex-direction:column;align-items:flex-start;justify-content:flex-start;padding:var(--paddingMedium);border-radius:var(--inputBorderRadius);color:var(--red);font-weight:600;overflow:auto}.oidc-error-message-container .oidc-error-message-source{font-weight:600;font-size:1rem;white-space:nowrap}.oidc-error-message-container .oidc-error-message-detail2,.oidc-error-message-container .oidc-error-message-detail{margin-top:var(--marginSmall);font-weight:400;white-space:nowrap}.oidc-error-message-container::-webkit-scrollbar{height:6px;width:6px}.oidc-error-message-container::-webkit-scrollbar-thumb{background-color:var(--menu);border-radius:10px}.oidc-error-message-container:hover::-webkit-scrollbar-thumb{background-clip:unset!important}.read-only-2{display:flex;overflow:auto;white-space:nowrap;opacity:1!important;cursor:pointer;padding:var(--paddingMedium);padding-bottom:var(--paddingSmall)}.read-only-2::-webkit-scrollbar{height:6px;width:6px}.read-only-2::-webkit-scrollbar-thumb{background-color:var(--menu);border-radius:10px}.read-only-2:hover{text-decoration:underline}.read-only-2:hover::-webkit-scrollbar-thumb{background-clip:unset}.copy-link-container{display:flex;flex-direction:row;justify-content:space-between;align-items:center;opacity:1!important;cursor:text;border-radius:var(--inputBorderRadius);height:var(--defaultInputHeight);background-color:var(--backgroundMuted)!important}.copy-button{display:flex;align-items:center;justify-content:center;height:100%;width:2.575rem;margin-left:.125rem;background:url(/assets/svgs/copy.svg) no-repeat;background-size:1.125rem 1.125rem;background-position:center;cursor:pointer;border-top-right-radius:var(--inputBorderRadius);border-bottom-right-radius:var(--inputBorderRadius);background-color:#0000000f}.copy-button:hover{filter:brightness(.95);background-color:#0000001f}.help-panel-content{display:flex;flex-direction:column;padding-top:3rem}.help-panel-content .help-panel-title{margin:0 0 .25rem;color:var(--primary);font-size:1.5rem;font-weight:600;line-height:1.3;padding-right:2rem}.help-panel-content .help-panel-intro{line-height:1.6;margin-bottom:1.5rem;color:var(--tableText);font-size:.9375rem}.help-panel-content .help-panel-section{margin-bottom:1.5rem;padding:1rem;background-color:var(--navigation);border-radius:var(--inputBorderRadius);border-left:.25rem solid var(--primary)}.help-panel-content .help-panel-section .help-panel-subtitle{margin:0 0 .75rem;color:var(--primary);font-size:1.125rem;font-weight:600;display:flex;align-items:center;gap:.5rem}.help-panel-content .help-panel-section .help-panel-subtitle span[class^=icon-]{font-size:1rem;opacity:.8}.help-panel-content .help-panel-section .help-panel-text{margin:0;line-height:1.6;color:var(--tableText);font-size:.875rem}.help-panel-content .help-panel-note{padding:1rem;background-color:#ffc1071a;border-radius:var(--inputBorderRadius);border-left:.25rem solid #ffc107;color:var(--tableText);font-size:.875rem;line-height:1.6}.help-panel-content .help-panel-note strong{color:#ffc107}\n"] }]
|
|
27099
29619
|
}], ctorParameters: () => [{ type: JwtSignerFormService }, { type: SchemaService }, { type: GrowlerService }, { type: undefined, decorators: [{
|
|
27100
29620
|
type: Inject,
|
|
27101
29621
|
args: [SHAREDZ_EXTENSION]
|
|
@@ -31923,11 +34443,13 @@ class SettingsComponent {
|
|
|
31923
34443
|
this.hideTags = false;
|
|
31924
34444
|
this.transitions = true;
|
|
31925
34445
|
this.isFilterAfterSave = false;
|
|
34446
|
+
this.betaFeatures = false;
|
|
31926
34447
|
}
|
|
31927
34448
|
ngOnInit() {
|
|
31928
34449
|
this.isDark = localStorage.getItem('mode') === 'dark';
|
|
31929
34450
|
this.hideTags = localStorage.getItem('hideTags') === 'yes';
|
|
31930
34451
|
this.isFilterAfterSave = localStorage.getItem('filterAfterSave') === 'on';
|
|
34452
|
+
this.betaFeatures = localStorage.getItem('betaFeatures') === 'on';
|
|
31931
34453
|
const transitions = localStorage.getItem('Transitions');
|
|
31932
34454
|
this.transitions = transitions !== 'off';
|
|
31933
34455
|
this.updateTransitions();
|
|
@@ -31945,6 +34467,10 @@ class SettingsComponent {
|
|
|
31945
34467
|
const mode = this.isFilterAfterSave ? 'on' : 'off';
|
|
31946
34468
|
localStorage.setItem('filterAfterSave', mode);
|
|
31947
34469
|
}
|
|
34470
|
+
betaFeaturesChanged() {
|
|
34471
|
+
const mode = this.betaFeatures ? 'on' : 'off';
|
|
34472
|
+
localStorage.setItem('betaFeatures', mode);
|
|
34473
|
+
}
|
|
31948
34474
|
transitionsChange() {
|
|
31949
34475
|
const mode = this.transitions ? 'on' : 'off';
|
|
31950
34476
|
localStorage.setItem('Transitions', mode);
|
|
@@ -31967,11 +34493,11 @@ class SettingsComponent {
|
|
|
31967
34493
|
document.getElementsByTagName('html')[0].style.setProperty('--secondary', color);
|
|
31968
34494
|
}
|
|
31969
34495
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: SettingsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
31970
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: SettingsComponent, isStandalone: false, selector: "lib-settings", ngImport: i0, template: "<div class=\"projectable-form-wrapper\">\n <div class=\"header\">\n <div class=\"title\">Manage <span>{{pageTitle}}</span></div>\n <div class=\"line\"></div>\n <div class=\"tabs\">\n <div class=\"tab selected\">Manage <span>{{pageTitle}}</span></div>\n <div class=\"tab\" routerLink=\"/profile\">Manage Profile</div>\n </div>\n <div class=\"constrained\">\n <div class=\"grid split\">\n <div>\n <label>Filter after Save</label>\n <div class=\"toggle\" [class.on]=\"isFilterAfterSave\" (click)=\"isFilterAfterSave = !isFilterAfterSave; filterAfter()\">\n <div class=\"switch\"></div>\n <div class=\"label\"></div>\n </div>\n </div>\n <div>\n <label>Dark mode</label>\n <div class=\"toggle\" [class.on]=\"isDark\" (click)=\"isDark = !isDark; swap()\">\n <div class=\"switch\"></div>\n <div class=\"label\"></div>\n </div>\n </div>\n <div>\n <label>Hide Tags</label>\n <div class=\"toggle\" [class.on]=\"hideTags\" (click)=\"hideTags = !hideTags; hide()\">\n <div class=\"switch\"></div>\n <div class=\"label\"></div>\n </div>\n </div>\n <div>\n <label>Transitions</label>\n <div class=\"toggle\" [class.on]=\"transitions\" (click)=\"transitions = !transitions; transitionsChange()\">\n <div class=\"switch\"></div>\n <div class=\"label\"></div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [".header .constrained .grid.split{grid-template-columns:1fr 1fr}label{color:var(--dark);text-transform:uppercase;margin-top:var(--marginMedium);position:relative;display:inline-block;width:100%;margin-bottom:.1875rem;font-size:.875rem;white-space:nowrap;font-weight:600;font-family:Open Sans;overflow:hidden;text-overflow:ellipsis;line-height:var(--defaultLineHeight)}.toggle{width:3.75rem;height:1.875rem;background-color:var(--black);color:var(--white);cursor:pointer;border-radius:6.25rem;position:relative;display:inline-block;margin-top:var(--marginMedium);transition:var(--transition);float:left;margin-right:var(--marginXL)}.toggle.on{background-color:var(--green)}.toggle.on .switch{left:2.1875rem}.toggle.on .label{left:.625rem;content:\"YES\"}.toggle.on .label:before{content:\"YES\"}.toggle .switch{width:1.25rem;height:1.25rem;border-radius:.625rem;background-color:var(--white);transition:var(--transition);position:absolute;left:.3125rem;top:.3125rem;z-index:10}.toggle .label{right:.625rem;line-height:1.875rem;font-size:.75rem;color:var(--white);position:absolute;z-index:8;transition:var(--transition);text-transform:uppercase}.toggleLabel{line-height:3.125rem}.toggle .label:before{content:\"NO\"}.constrained{width:37.5rem;position:relative;margin-left:auto;margin-right:auto}.split{display:grid;grid-gap:.625rem;grid-template-columns:auto 50%}.header{position:relative;display:inline-block;width:100%}.line{position:absolute;width:100%;top:2.5rem;height:.25rem;background-color:var(--stroke)}.tabs{position:relative;display:inline-block;width:100%;font-size:.875rem;min-height:2.5rem;padding-top:.9375rem}.tabs .tab{position:relative;float:left;margin-right:1.25rem;padding-bottom:.3125rem;margin-bottom:.625rem;font-size:.875rem;font-weight:600;cursor:pointer;transition:var(--transition)}.tabs .tab.selected{border-bottom-width:.25rem;border-bottom-color:var(--primary);border-bottom-style:solid}\n"], dependencies: [{ kind: "directive", type: i4.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] }); }
|
|
34496
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: SettingsComponent, isStandalone: false, selector: "lib-settings", ngImport: i0, template: "<div class=\"projectable-form-wrapper\">\n <div class=\"header\">\n <div class=\"title\">Manage <span>{{pageTitle}}</span></div>\n <div class=\"line\"></div>\n <div class=\"tabs\">\n <div class=\"tab selected\">Manage <span>{{pageTitle}}</span></div>\n <div class=\"tab\" routerLink=\"/profile\">Manage Profile</div>\n </div>\n <div class=\"constrained\">\n <div class=\"grid split\">\n <div>\n <label>Filter after Save</label>\n <div class=\"toggle\" [class.on]=\"isFilterAfterSave\" (click)=\"isFilterAfterSave = !isFilterAfterSave; filterAfter()\">\n <div class=\"switch\"></div>\n <div class=\"label\"></div>\n </div>\n </div>\n <div>\n <label>Dark mode</label>\n <div class=\"toggle\" [class.on]=\"isDark\" (click)=\"isDark = !isDark; swap()\">\n <div class=\"switch\"></div>\n <div class=\"label\"></div>\n </div>\n </div>\n <div>\n <label>Hide Tags</label>\n <div class=\"toggle\" [class.on]=\"hideTags\" (click)=\"hideTags = !hideTags; hide()\">\n <div class=\"switch\"></div>\n <div class=\"label\"></div>\n </div>\n </div>\n <div>\n <label>Transitions</label>\n <div class=\"toggle\" [class.on]=\"transitions\" (click)=\"transitions = !transitions; transitionsChange()\">\n <div class=\"switch\"></div>\n <div class=\"label\"></div>\n </div>\n </div>\n <div>\n <label>Beta Features</label>\n <div class=\"toggle\" [class.on]=\"betaFeatures\" (click)=\"betaFeatures = !betaFeatures; betaFeaturesChanged()\">\n <div class=\"switch\"></div>\n <div class=\"label\"></div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [".header .constrained .grid.split{grid-template-columns:1fr 1fr}label{color:var(--dark);text-transform:uppercase;margin-top:var(--marginMedium);position:relative;display:inline-block;width:100%;margin-bottom:.1875rem;font-size:.875rem;white-space:nowrap;font-weight:600;font-family:Open Sans;overflow:hidden;text-overflow:ellipsis;line-height:var(--defaultLineHeight)}.toggle{width:3.75rem;height:1.875rem;background-color:var(--black);color:var(--white);cursor:pointer;border-radius:6.25rem;position:relative;display:inline-block;margin-top:var(--marginMedium);transition:var(--transition);float:left;margin-right:var(--marginXL)}.toggle.on{background-color:var(--green)}.toggle.on .switch{left:2.1875rem}.toggle.on .label{left:.625rem;content:\"YES\"}.toggle.on .label:before{content:\"YES\"}.toggle .switch{width:1.25rem;height:1.25rem;border-radius:.625rem;background-color:var(--white);transition:var(--transition);position:absolute;left:.3125rem;top:.3125rem;z-index:10}.toggle .label{right:.625rem;line-height:1.875rem;font-size:.75rem;color:var(--white);position:absolute;z-index:8;transition:var(--transition);text-transform:uppercase}.toggleLabel{line-height:3.125rem}.toggle .label:before{content:\"NO\"}.constrained{width:37.5rem;position:relative;margin-left:auto;margin-right:auto}.split{display:grid;grid-gap:.625rem;grid-template-columns:auto 50%}.header{position:relative;display:inline-block;width:100%}.line{position:absolute;width:100%;top:2.5rem;height:.25rem;background-color:var(--stroke)}.tabs{position:relative;display:inline-block;width:100%;font-size:.875rem;min-height:2.5rem;padding-top:.9375rem}.tabs .tab{position:relative;float:left;margin-right:1.25rem;padding-bottom:.3125rem;margin-bottom:.625rem;font-size:.875rem;font-weight:600;cursor:pointer;transition:var(--transition)}.tabs .tab.selected{border-bottom-width:.25rem;border-bottom-color:var(--primary);border-bottom-style:solid}\n"], dependencies: [{ kind: "directive", type: i4.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] }); }
|
|
31971
34497
|
}
|
|
31972
34498
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: SettingsComponent, decorators: [{
|
|
31973
34499
|
type: Component,
|
|
31974
|
-
args: [{ selector: 'lib-settings', standalone: false, template: "<div class=\"projectable-form-wrapper\">\n <div class=\"header\">\n <div class=\"title\">Manage <span>{{pageTitle}}</span></div>\n <div class=\"line\"></div>\n <div class=\"tabs\">\n <div class=\"tab selected\">Manage <span>{{pageTitle}}</span></div>\n <div class=\"tab\" routerLink=\"/profile\">Manage Profile</div>\n </div>\n <div class=\"constrained\">\n <div class=\"grid split\">\n <div>\n <label>Filter after Save</label>\n <div class=\"toggle\" [class.on]=\"isFilterAfterSave\" (click)=\"isFilterAfterSave = !isFilterAfterSave; filterAfter()\">\n <div class=\"switch\"></div>\n <div class=\"label\"></div>\n </div>\n </div>\n <div>\n <label>Dark mode</label>\n <div class=\"toggle\" [class.on]=\"isDark\" (click)=\"isDark = !isDark; swap()\">\n <div class=\"switch\"></div>\n <div class=\"label\"></div>\n </div>\n </div>\n <div>\n <label>Hide Tags</label>\n <div class=\"toggle\" [class.on]=\"hideTags\" (click)=\"hideTags = !hideTags; hide()\">\n <div class=\"switch\"></div>\n <div class=\"label\"></div>\n </div>\n </div>\n <div>\n <label>Transitions</label>\n <div class=\"toggle\" [class.on]=\"transitions\" (click)=\"transitions = !transitions; transitionsChange()\">\n <div class=\"switch\"></div>\n <div class=\"label\"></div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [".header .constrained .grid.split{grid-template-columns:1fr 1fr}label{color:var(--dark);text-transform:uppercase;margin-top:var(--marginMedium);position:relative;display:inline-block;width:100%;margin-bottom:.1875rem;font-size:.875rem;white-space:nowrap;font-weight:600;font-family:Open Sans;overflow:hidden;text-overflow:ellipsis;line-height:var(--defaultLineHeight)}.toggle{width:3.75rem;height:1.875rem;background-color:var(--black);color:var(--white);cursor:pointer;border-radius:6.25rem;position:relative;display:inline-block;margin-top:var(--marginMedium);transition:var(--transition);float:left;margin-right:var(--marginXL)}.toggle.on{background-color:var(--green)}.toggle.on .switch{left:2.1875rem}.toggle.on .label{left:.625rem;content:\"YES\"}.toggle.on .label:before{content:\"YES\"}.toggle .switch{width:1.25rem;height:1.25rem;border-radius:.625rem;background-color:var(--white);transition:var(--transition);position:absolute;left:.3125rem;top:.3125rem;z-index:10}.toggle .label{right:.625rem;line-height:1.875rem;font-size:.75rem;color:var(--white);position:absolute;z-index:8;transition:var(--transition);text-transform:uppercase}.toggleLabel{line-height:3.125rem}.toggle .label:before{content:\"NO\"}.constrained{width:37.5rem;position:relative;margin-left:auto;margin-right:auto}.split{display:grid;grid-gap:.625rem;grid-template-columns:auto 50%}.header{position:relative;display:inline-block;width:100%}.line{position:absolute;width:100%;top:2.5rem;height:.25rem;background-color:var(--stroke)}.tabs{position:relative;display:inline-block;width:100%;font-size:.875rem;min-height:2.5rem;padding-top:.9375rem}.tabs .tab{position:relative;float:left;margin-right:1.25rem;padding-bottom:.3125rem;margin-bottom:.625rem;font-size:.875rem;font-weight:600;cursor:pointer;transition:var(--transition)}.tabs .tab.selected{border-bottom-width:.25rem;border-bottom-color:var(--primary);border-bottom-style:solid}\n"] }]
|
|
34500
|
+
args: [{ selector: 'lib-settings', standalone: false, template: "<div class=\"projectable-form-wrapper\">\n <div class=\"header\">\n <div class=\"title\">Manage <span>{{pageTitle}}</span></div>\n <div class=\"line\"></div>\n <div class=\"tabs\">\n <div class=\"tab selected\">Manage <span>{{pageTitle}}</span></div>\n <div class=\"tab\" routerLink=\"/profile\">Manage Profile</div>\n </div>\n <div class=\"constrained\">\n <div class=\"grid split\">\n <div>\n <label>Filter after Save</label>\n <div class=\"toggle\" [class.on]=\"isFilterAfterSave\" (click)=\"isFilterAfterSave = !isFilterAfterSave; filterAfter()\">\n <div class=\"switch\"></div>\n <div class=\"label\"></div>\n </div>\n </div>\n <div>\n <label>Dark mode</label>\n <div class=\"toggle\" [class.on]=\"isDark\" (click)=\"isDark = !isDark; swap()\">\n <div class=\"switch\"></div>\n <div class=\"label\"></div>\n </div>\n </div>\n <div>\n <label>Hide Tags</label>\n <div class=\"toggle\" [class.on]=\"hideTags\" (click)=\"hideTags = !hideTags; hide()\">\n <div class=\"switch\"></div>\n <div class=\"label\"></div>\n </div>\n </div>\n <div>\n <label>Transitions</label>\n <div class=\"toggle\" [class.on]=\"transitions\" (click)=\"transitions = !transitions; transitionsChange()\">\n <div class=\"switch\"></div>\n <div class=\"label\"></div>\n </div>\n </div>\n <div>\n <label>Beta Features</label>\n <div class=\"toggle\" [class.on]=\"betaFeatures\" (click)=\"betaFeatures = !betaFeatures; betaFeaturesChanged()\">\n <div class=\"switch\"></div>\n <div class=\"label\"></div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [".header .constrained .grid.split{grid-template-columns:1fr 1fr}label{color:var(--dark);text-transform:uppercase;margin-top:var(--marginMedium);position:relative;display:inline-block;width:100%;margin-bottom:.1875rem;font-size:.875rem;white-space:nowrap;font-weight:600;font-family:Open Sans;overflow:hidden;text-overflow:ellipsis;line-height:var(--defaultLineHeight)}.toggle{width:3.75rem;height:1.875rem;background-color:var(--black);color:var(--white);cursor:pointer;border-radius:6.25rem;position:relative;display:inline-block;margin-top:var(--marginMedium);transition:var(--transition);float:left;margin-right:var(--marginXL)}.toggle.on{background-color:var(--green)}.toggle.on .switch{left:2.1875rem}.toggle.on .label{left:.625rem;content:\"YES\"}.toggle.on .label:before{content:\"YES\"}.toggle .switch{width:1.25rem;height:1.25rem;border-radius:.625rem;background-color:var(--white);transition:var(--transition);position:absolute;left:.3125rem;top:.3125rem;z-index:10}.toggle .label{right:.625rem;line-height:1.875rem;font-size:.75rem;color:var(--white);position:absolute;z-index:8;transition:var(--transition);text-transform:uppercase}.toggleLabel{line-height:3.125rem}.toggle .label:before{content:\"NO\"}.constrained{width:37.5rem;position:relative;margin-left:auto;margin-right:auto}.split{display:grid;grid-gap:.625rem;grid-template-columns:auto 50%}.header{position:relative;display:inline-block;width:100%}.line{position:absolute;width:100%;top:2.5rem;height:.25rem;background-color:var(--stroke)}.tabs{position:relative;display:inline-block;width:100%;font-size:.875rem;min-height:2.5rem;padding-top:.9375rem}.tabs .tab{position:relative;float:left;margin-right:1.25rem;padding-bottom:.3125rem;margin-bottom:.625rem;font-size:.875rem;font-weight:600;cursor:pointer;transition:var(--transition)}.tabs .tab.selected{border-bottom-width:.25rem;border-bottom-color:var(--primary);border-bottom-style:solid}\n"] }]
|
|
31975
34501
|
}], ctorParameters: () => [] });
|
|
31976
34502
|
|
|
31977
34503
|
class ProfileComponent {
|
|
@@ -39492,11 +42018,11 @@ class HeaderBarComponent {
|
|
|
39492
42018
|
this.router.navigate(['/dashboard']);
|
|
39493
42019
|
}
|
|
39494
42020
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: HeaderBarComponent, deps: [{ token: i4.Router }, { token: i5.MatDialog }, { token: ZAC_LOGIN_SERVICE }, { token: i4.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
39495
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: HeaderBarComponent, isStandalone: false, selector: "lib-header-bar", inputs: { headerTitle: "headerTitle" }, ngImport: i0, template: "<header>\n <div class=\"overlay\"></div>\n <div class=\"left-side-buttons\">\n <div class=\"apps-button clickable\" mattooltip=\"Select Application\" mattooltipposition=\"below\" mattooltipshowdelay=\"500\" (click)=\"goToDashboard()\">\n <div class=\"icon\"></div>\n </div>\n <div class=\"divider-line\"></div>\n <div class=\"header-title-wrapper\">\n <div class=\"header-title-container\" (click)=\"goToDashboard()\">\n <div class=\"header-title-label\">{{headerTitle}}</div>\n <div class=\"title-text-row title-bottom-text\">By <a class=\"nf-name-text\" href=\"https://netfoundry.io\" target=\"_blank\">NetFoundry</a></div>\n </div>\n </div>\n </div>\n <div class=\"right-side-buttons\">\n <div\n (click)=\"openQuickAdd()\"\n [ngClass]=\"{ open: supportOpen }\"\n class=\"clickable\"\n id=\"QuickAddButton\"\n matTooltip=\"Support\"\n matTooltipPosition=\"below\"\n matTooltipShowDelay=\"500\"\n >\n <div class=\"clicked\"></div>\n <div class=\"circle\"></div>\n <div class=\"icon icon-Icon_Add\"></div>\n </div>\n <div\n class=\"clickable\"\n id=\"AttributesButton\"\n matTooltip=\"Attributes Explorer\"\n matTooltipPosition=\"below\"\n matTooltipShowDelay=\"500\"\n routerLink=\"/attributes/\"\n >\n <div class=\"circle\"></div>\n <div class=\"icon icon-hash\"></div>\n </div>\n <div\n (click)=\"openAlerts()\"\n class=\"clickable\"\n id=\"RecentAlertsButton\"\n matTooltip=\"Recent Alerts\"\n matTooltipPosition=\"below\"\n matTooltipShowDelay=\"500\"\n >\n <div class=\"circle\"></div>\n <div class=\"icon icon-Bell\"></div>\n </div>\n <div\n class=\"clickable main\"\n id=\"UserButton\"\n (clickOutside)=\"closeProfileMenu()\"\n (click)=\"openProfileMenu()\"\n >\n <div class=\"main clickable\"></div>\n <div class=\"circle\"></div>\n <div\n [ngStyle]=\"{ 'background-image': 'url(' + profilePhoto + ')' }\"\n class=\"icon icon-profile\"\n ></div>\n <div [ngClass]=\"{ open: profileOpen }\" class=\"header-menu\" id=\"UserMenu\">\n @if (profileOpen) {\n <div class=\"menutitle\">{{ username }}</div>\n }\n @if (profileOpen) {\n <div\n class=\"link\"\n id=\"EditProfile\"\n routerLink=\"/profile/\"\n >\n Edit Profile\n </div>\n }\n @if (profileOpen) {\n <div\n class=\"link\"\n id=\"PersonalSettings\"\n routerLink=\"/settings/\"\n >\n Personal Settings\n </div>\n }\n @if (profileOpen) {\n <div (click)=\"confirmLogout()\" class=\"link\" id=\"LogoutButton\">Logout</div>\n }\n </div>\n </div>\n </div>\n</header>\n", styles: ["header{position:relative;top:0rem;left:0;bottom:unset;width:100%;height:var(--headerHeight);z-index:99999999;background:var(--formBackground);border-bottom-style:solid;border-bottom-color:var(--inputBorder);border-bottom-width:1px}header .overlay{width:100%;height:100%;position:absolute;z-index:1;opacity:1!important}header .left-side-buttons{position:absolute;top:0rem;left:0rem;right:0rem;width:50%;z-index:5;height:100%;padding-left:1.25rem;display:flex;align-items:center}header .left-side-buttons .apps-button .icon{width:2.25rem;height:2.25rem;position:absolute;background-size:contain;background-repeat:no-repeat;background-position:center center;transition:.3s;top:unset;left:unset;background-image:url(/assets/svgs/ziti-logo.svg)}header .left-side-buttons #NavigationButton{height:1.5rem;width:1.625rem}header .left-side-buttons #NavigationButton .status{height:1.375rem;width:1.5rem;top:unset;left:unset;animation:none}header .left-side-buttons #NavigationButton .circle{height:1.5rem;width:1.625rem}header .left-side-buttons #NavigationButton.header-nav-icon{width:2.8125rem;height:2.75rem;cursor:pointer}header .left-side-buttons #NavigationButton.header-nav-icon .status{height:2.125rem;width:2.125rem;top:unset;left:unset;animation:none}header .left-side-buttons #NavigationButton.header-nav-icon .circle{height:2.625rem;width:2.625rem;top:unset;left:unset}header .left-side-buttons #NavigationButton.header-nav-icon.nav-logo .status{display:none}header .left-side-buttons #NavigationButton.header-nav-icon.nav-logo .icon{background-image:url(/assets/svgs/icon.svg);display:flex;top:unset;left:unset;height:2.125rem;width:2.125rem}header .right-side-buttons{position:absolute;right:0rem;bottom:unset;left:unset;z-index:5;width:50%;height:100%;display:flex;flex-direction:row;justify-content:flex-end;align-items:center;padding-right:1.25rem}header .clickable{position:relative;clear:both;float:left;width:2.8125rem;height:3.125rem;display:flex;align-items:center;justify-content:center;margin:0;cursor:pointer;transition:var(--transition)}header .clickable .icon{width:1.6875rem;height:1.6875rem;position:absolute;left:.625rem;top:.75rem;background-size:contain;background-repeat:no-repeat;background-position:center center;transition:.3s}header .clickable .icon:active{transform:scale(.95);transition:.3s}header .clickable .icon.icon-Bell{font-weight:600}header .clickable .icon:before{color:var(--headerButtonColor)!important}header .clickable .icon-profile{font-size:1.7rem;font-weight:600;margin-top:.075rem}header .clickable .icon-Bell{top:.65rem;left:.575rem}header .clickable .main{opacity:1;width:2.3125rem;height:2.3125rem;left:.5625rem;top:.5625rem;border-radius:2.3125rem;position:absolute;transition:var(--transition)}header .clickable .circle{opacity:0;z-index:-2;background-color:var(--white);width:2.8125rem;height:2.8125rem;left:1px;top:.1875rem;border-radius:2.0625rem;position:absolute;transition:var(--transition)}header .clickable.open .circle{opacity:.2}header .clickable:hover .circle{opacity:.2;background-color:var(--menu)}header .clickable:active .circle{opacity:.1}header .divider-line{height:2.8125rem;width:0;margin-right:.625rem;margin-left:.625rem;border-style:solid;border-width:1px;border-color:var(--inputBorder)}header .header-title-wrapper{display:flex;flex-direction:column;align-items:flex-start;justify-content:space-between;height:100%;padding-top:.875rem;padding-bottom:.75rem}header .header-title-wrapper .header-title-container{display:flex;flex-direction:column;align-items:flex-start;justify-content:flex-start;gap:0;height:100%;cursor:pointer}header .header-title-wrapper .header-title-container .header-title-label{font-family:Russo One;text-align:center;line-height:1.5rem;color:var(--primaryColor);filter:brightness(var(--brightnessDark));cursor:pointer;font-size:1.75rem;font-variant:small-caps;font-size-adjust:.46;word-spacing:-4px}header .header-breadcrumb{display:flex;align-items:center;justify-content:flex-start;height:100%}header .header-breadcrumb .breadcrumb-path-label{font-size:.875rem;font-weight:900;filter:brightness(var(--brightnessDark));color:var(--primary)}header .header-breadcrumb .breadcrumb-path-label.non-click{text-transform:capitalize}header .header-breadcrumb .breadcrumb-path-label:hover{text-decoration:underline;cursor:pointer}header .header-breadcrumb .breadcrumb-path-label:hover.non-click{text-decoration:none;cursor:default}header .header-breadcrumb .breadcrumb-path-divider{font-size:.875rem;font-weight:600;filter:brightness(var(--brightnessDark));text-transform:uppercase;color:var(--primary);margin-left:.3125rem;margin-right:.3125rem}header .icon{font-size:1.8125rem;text-align:center;color:#fff}header #ApplicationButton{width:3.125rem}header #ApplicationButton .icon{font-size:1.5625rem;height:2.3125rem;width:2.3125rem;display:flex;justify-content:center;align-items:center;border-radius:1.875rem;font-family:icomoon!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background-color:var(--primaryColor);color:var(--mainBackground);left:.4375rem;top:.4375rem}header #ApplicationButton .circle{left:.1875rem}header #ApplicationButton.nav-button-organization .icon:before{content:\"\\e948\"}header #ApplicationButton.nav-button-browzer .icon:before{content:\"\\e96a\"}header #ApplicationButton.nav-button-billing .icon:before{content:\"\\e932\"}#AlertButton .count{width:.8125rem;height:.8125rem;border-radius:50%;font-weight:400;font-family:Open Sans,Arial,sans-serif;background-color:var(--secondaryColor);z-index:20;color:var(--white);font-size:.5rem;line-height:.75rem;font-weight:700;position:absolute;right:.8125rem;top:.9375rem;text-align:center;box-shadow:var(--shadows)}#UserButton #UserMenu{position:absolute;top:2.5rem;right:.3125rem;bottom:unset;left:unset}#UserButton #UserMenu .menutitle{color:var(--lightText)}#UserButton #UserMenu .link{color:#fff}#UserButton #UserMenu.header-menu{background-color:var(--menu);border-radius:.4375rem;box-shadow:0 0 0 1px var(--shadow),0 .5rem 1rem var(--shadow);font-size:.875rem;font-weight:600;text-transform:uppercase;color:var(--white);letter-spacing:1px;height:0rem;opacity:0;transition:.2s;z-index:50;padding-bottom:.625rem;padding-top:.625rem}#UserButton #UserMenu.header-menu .link{cursor:pointer;line-height:2.25rem;white-space:nowrap;padding-left:1.25rem;padding-right:1.25rem;transition:.2s}#UserButton #UserMenu.header-menu .link:hover{background-color:var(--primaryColor)}#UserButton #UserMenu.header-menu.open{height:unset;opacity:1}#UserButton #UserMenu .menutitle{opacity:.8;white-space:nowrap;line-height:2.25rem;padding-left:1.25rem;padding-right:1.25rem}.title-text-row{color:var(--primaryColor)!important;filter:brightness(var(--brightnessDark));opacity:1;font-family:Russo One,Arial,sans-serif;font-size:3rem;font-weight:400!important;margin:0!important;text-align:center}.title-text-row.title-top-text{font-size:4.25rem!important;line-height:3.25rem;font-variant:small-caps;font-size-adjust:.47}.title-text-row.title-bottom-text{display:flex;justify-content:flex-start;align-items:baseline;gap:.175rem;font-size:1rem}.title-text-row.title-bottom-text .nf-name-text{font-variant:small-caps;font-size-adjust:.47;font-size:1.125rem;font-weight:400;color:var(--primaryColor)}.title-text-row.title-bottom-text .nf-name-text:hover{text-decoration:underline!important}\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: i4.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i3$1.ClickOutsideDirective, selector: "[clickOutside]", inputs: ["clickOutsideEnabled", "attachOutsideOnClick", "delayClickOutsideInit", "emitOnBlur", "exclude", "excludeBeforeClick", "clickOutsideEvents"], outputs: ["clickOutside"] }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] }); }
|
|
42021
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: HeaderBarComponent, isStandalone: false, selector: "lib-header-bar", inputs: { headerTitle: "headerTitle" }, ngImport: i0, template: "<header>\n <div class=\"overlay\"></div>\n <div class=\"left-side-buttons\">\n <div class=\"apps-button clickable\" mattooltip=\"Select Application\" mattooltipposition=\"below\" mattooltipshowdelay=\"500\" (click)=\"goToDashboard()\">\n <div class=\"icon\"></div>\n </div>\n <div class=\"divider-line\"></div>\n <div class=\"header-title-wrapper\">\n <div class=\"header-title-container\" (click)=\"goToDashboard()\">\n <div class=\"header-title-label\">{{headerTitle}}</div>\n <div class=\"title-text-row title-bottom-text\">By <a class=\"nf-name-text\" href=\"https://netfoundry.io\" target=\"_blank\">NetFoundry</a></div>\n </div>\n </div>\n </div>\n <div class=\"right-side-buttons\">\n <div\n (click)=\"openQuickAdd()\"\n class=\"clickable\"\n id=\"QuickAddButton\"\n matTooltip=\"Add Entity\"\n matTooltipPosition=\"below\"\n matTooltipShowDelay=\"500\"\n >\n <div class=\"clicked\"></div>\n <div class=\"circle\"></div>\n <div class=\"icon icon-Icon_Add\"></div>\n </div>\n <div\n class=\"clickable\"\n id=\"AttributesButton\"\n matTooltip=\"Attributes Explorer\"\n matTooltipPosition=\"below\"\n matTooltipShowDelay=\"500\"\n routerLink=\"/attributes/\"\n >\n <div class=\"circle\"></div>\n <div class=\"icon icon-hash\"></div>\n </div>\n <div\n (click)=\"openAlerts()\"\n class=\"clickable\"\n id=\"RecentAlertsButton\"\n matTooltip=\"Recent Alerts\"\n matTooltipPosition=\"below\"\n matTooltipShowDelay=\"500\"\n >\n <div class=\"circle\"></div>\n <div class=\"icon icon-Bell\"></div>\n </div>\n <div\n class=\"clickable main\"\n id=\"UserButton\"\n (clickOutside)=\"closeProfileMenu()\"\n (click)=\"openProfileMenu()\"\n >\n <div class=\"main clickable\"></div>\n <div class=\"circle\"></div>\n <div\n [ngStyle]=\"{ 'background-image': 'url(' + profilePhoto + ')' }\"\n class=\"icon icon-profile\"\n ></div>\n <div [ngClass]=\"{ open: profileOpen }\" class=\"header-menu\" id=\"UserMenu\">\n @if (profileOpen) {\n <div class=\"menutitle\">{{ username }}</div>\n }\n @if (profileOpen) {\n <div\n class=\"link\"\n id=\"EditProfile\"\n routerLink=\"/profile/\"\n >\n Edit Profile\n </div>\n }\n @if (profileOpen) {\n <div\n class=\"link\"\n id=\"PersonalSettings\"\n routerLink=\"/settings/\"\n >\n Personal Settings\n </div>\n }\n @if (profileOpen) {\n <div (click)=\"confirmLogout()\" class=\"link\" id=\"LogoutButton\">Logout</div>\n }\n </div>\n </div>\n </div>\n</header>\n", styles: ["header{position:relative;top:0rem;left:0;bottom:unset;width:100%;height:var(--headerHeight);z-index:99999999;background:var(--formBackground);border-bottom-style:solid;border-bottom-color:var(--inputBorder);border-bottom-width:1px}header .overlay{width:100%;height:100%;position:absolute;z-index:1;opacity:1!important}header .left-side-buttons{position:absolute;top:0rem;left:0rem;right:0rem;width:50%;z-index:5;height:100%;padding-left:1.25rem;display:flex;align-items:center}header .left-side-buttons .apps-button .icon{width:2.25rem;height:2.25rem;position:absolute;background-size:contain;background-repeat:no-repeat;background-position:center center;transition:.3s;top:unset;left:unset;background-image:url(/assets/svgs/ziti-logo.svg)}header .left-side-buttons #NavigationButton{height:1.5rem;width:1.625rem}header .left-side-buttons #NavigationButton .status{height:1.375rem;width:1.5rem;top:unset;left:unset;animation:none}header .left-side-buttons #NavigationButton .circle{height:1.5rem;width:1.625rem}header .left-side-buttons #NavigationButton.header-nav-icon{width:2.8125rem;height:2.75rem;cursor:pointer}header .left-side-buttons #NavigationButton.header-nav-icon .status{height:2.125rem;width:2.125rem;top:unset;left:unset;animation:none}header .left-side-buttons #NavigationButton.header-nav-icon .circle{height:2.625rem;width:2.625rem;top:unset;left:unset}header .left-side-buttons #NavigationButton.header-nav-icon.nav-logo .status{display:none}header .left-side-buttons #NavigationButton.header-nav-icon.nav-logo .icon{background-image:url(/assets/svgs/icon.svg);display:flex;top:unset;left:unset;height:2.125rem;width:2.125rem}header .right-side-buttons{position:absolute;right:0rem;bottom:unset;left:unset;z-index:5;width:50%;height:100%;display:flex;flex-direction:row;justify-content:flex-end;align-items:center;padding-right:1.25rem}header .clickable{position:relative;clear:both;float:left;width:2.8125rem;height:3.125rem;display:flex;align-items:center;justify-content:center;margin:0;cursor:pointer;transition:var(--transition)}header .clickable .icon{width:1.6875rem;height:1.6875rem;position:absolute;left:.625rem;top:.75rem;background-size:contain;background-repeat:no-repeat;background-position:center center;transition:.3s}header .clickable .icon:active{transform:scale(.95);transition:.3s}header .clickable .icon.icon-Bell{font-weight:600}header .clickable .icon:before{color:var(--headerButtonColor)!important}header .clickable .icon-profile{font-size:1.7rem;font-weight:600;margin-top:.075rem}header .clickable .icon-Bell{top:.65rem;left:.575rem}header .clickable .main{opacity:1;width:2.3125rem;height:2.3125rem;left:.5625rem;top:.5625rem;border-radius:2.3125rem;position:absolute;transition:var(--transition)}header .clickable .circle{opacity:0;z-index:-2;background-color:var(--white);width:2.8125rem;height:2.8125rem;left:1px;top:.1875rem;border-radius:2.0625rem;position:absolute;transition:var(--transition)}header .clickable.open .circle{opacity:.2}header .clickable:hover .circle{opacity:.2;background-color:var(--menu)}header .clickable:active .circle{opacity:.1}header .divider-line{height:2.8125rem;width:0;margin-right:.625rem;margin-left:.625rem;border-style:solid;border-width:1px;border-color:var(--inputBorder)}header .header-title-wrapper{display:flex;flex-direction:column;align-items:flex-start;justify-content:space-between;height:100%;padding-top:.875rem;padding-bottom:.75rem}header .header-title-wrapper .header-title-container{display:flex;flex-direction:column;align-items:flex-start;justify-content:flex-start;gap:0;height:100%;cursor:pointer}header .header-title-wrapper .header-title-container .header-title-label{font-family:Russo One;text-align:center;line-height:1.5rem;color:var(--primaryColor);filter:brightness(var(--brightnessDark));cursor:pointer;font-size:1.75rem;font-variant:small-caps;font-size-adjust:.46;word-spacing:-4px}header .header-breadcrumb{display:flex;align-items:center;justify-content:flex-start;height:100%}header .header-breadcrumb .breadcrumb-path-label{font-size:.875rem;font-weight:900;filter:brightness(var(--brightnessDark));color:var(--primary)}header .header-breadcrumb .breadcrumb-path-label.non-click{text-transform:capitalize}header .header-breadcrumb .breadcrumb-path-label:hover{text-decoration:underline;cursor:pointer}header .header-breadcrumb .breadcrumb-path-label:hover.non-click{text-decoration:none;cursor:default}header .header-breadcrumb .breadcrumb-path-divider{font-size:.875rem;font-weight:600;filter:brightness(var(--brightnessDark));text-transform:uppercase;color:var(--primary);margin-left:.3125rem;margin-right:.3125rem}header .icon{font-size:1.8125rem;text-align:center;color:#fff}header #ApplicationButton{width:3.125rem}header #ApplicationButton .icon{font-size:1.5625rem;height:2.3125rem;width:2.3125rem;display:flex;justify-content:center;align-items:center;border-radius:1.875rem;font-family:icomoon!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background-color:var(--primaryColor);color:var(--mainBackground);left:.4375rem;top:.4375rem}header #ApplicationButton .circle{left:.1875rem}header #ApplicationButton.nav-button-organization .icon:before{content:\"\\e948\"}header #ApplicationButton.nav-button-browzer .icon:before{content:\"\\e96a\"}header #ApplicationButton.nav-button-billing .icon:before{content:\"\\e932\"}#AlertButton .count{width:.8125rem;height:.8125rem;border-radius:50%;font-weight:400;font-family:Open Sans,Arial,sans-serif;background-color:var(--secondaryColor);z-index:20;color:var(--white);font-size:.5rem;line-height:.75rem;font-weight:700;position:absolute;right:.8125rem;top:.9375rem;text-align:center;box-shadow:var(--shadows)}#UserButton #UserMenu{position:absolute;top:2.5rem;right:.3125rem;bottom:unset;left:unset}#UserButton #UserMenu .menutitle{color:var(--lightText)}#UserButton #UserMenu .link{color:#fff}#UserButton #UserMenu.header-menu{background-color:var(--menu);border-radius:.4375rem;box-shadow:0 0 0 1px var(--shadow),0 .5rem 1rem var(--shadow);font-size:.875rem;font-weight:600;text-transform:uppercase;color:var(--white);letter-spacing:1px;height:0rem;opacity:0;transition:.2s;z-index:50;padding-bottom:.625rem;padding-top:.625rem}#UserButton #UserMenu.header-menu .link{cursor:pointer;line-height:2.25rem;white-space:nowrap;padding-left:1.25rem;padding-right:1.25rem;transition:.2s}#UserButton #UserMenu.header-menu .link:hover{background-color:var(--primaryColor)}#UserButton #UserMenu.header-menu.open{height:unset;opacity:1}#UserButton #UserMenu .menutitle{opacity:.8;white-space:nowrap;line-height:2.25rem;padding-left:1.25rem;padding-right:1.25rem}.title-text-row{color:var(--primaryColor)!important;filter:brightness(var(--brightnessDark));opacity:1;font-family:Russo One,Arial,sans-serif;font-size:3rem;font-weight:400!important;margin:0!important;text-align:center}.title-text-row.title-top-text{font-size:4.25rem!important;line-height:3.25rem;font-variant:small-caps;font-size-adjust:.47}.title-text-row.title-bottom-text{display:flex;justify-content:flex-start;align-items:baseline;gap:.175rem;font-size:1rem}.title-text-row.title-bottom-text .nf-name-text{font-variant:small-caps;font-size-adjust:.47;font-size:1.125rem;font-weight:400;color:var(--primaryColor)}.title-text-row.title-bottom-text .nf-name-text:hover{text-decoration:underline!important}\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: i4.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i3$1.ClickOutsideDirective, selector: "[clickOutside]", inputs: ["clickOutsideEnabled", "attachOutsideOnClick", "delayClickOutsideInit", "emitOnBlur", "exclude", "excludeBeforeClick", "clickOutsideEvents"], outputs: ["clickOutside"] }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] }); }
|
|
39496
42022
|
}
|
|
39497
42023
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: HeaderBarComponent, decorators: [{
|
|
39498
42024
|
type: Component,
|
|
39499
|
-
args: [{ selector: 'lib-header-bar', standalone: false, template: "<header>\n <div class=\"overlay\"></div>\n <div class=\"left-side-buttons\">\n <div class=\"apps-button clickable\" mattooltip=\"Select Application\" mattooltipposition=\"below\" mattooltipshowdelay=\"500\" (click)=\"goToDashboard()\">\n <div class=\"icon\"></div>\n </div>\n <div class=\"divider-line\"></div>\n <div class=\"header-title-wrapper\">\n <div class=\"header-title-container\" (click)=\"goToDashboard()\">\n <div class=\"header-title-label\">{{headerTitle}}</div>\n <div class=\"title-text-row title-bottom-text\">By <a class=\"nf-name-text\" href=\"https://netfoundry.io\" target=\"_blank\">NetFoundry</a></div>\n </div>\n </div>\n </div>\n <div class=\"right-side-buttons\">\n <div\n (click)=\"openQuickAdd()\"\n [ngClass]=\"{ open: supportOpen }\"\n class=\"clickable\"\n id=\"QuickAddButton\"\n matTooltip=\"Support\"\n matTooltipPosition=\"below\"\n matTooltipShowDelay=\"500\"\n >\n <div class=\"clicked\"></div>\n <div class=\"circle\"></div>\n <div class=\"icon icon-Icon_Add\"></div>\n </div>\n <div\n class=\"clickable\"\n id=\"AttributesButton\"\n matTooltip=\"Attributes Explorer\"\n matTooltipPosition=\"below\"\n matTooltipShowDelay=\"500\"\n routerLink=\"/attributes/\"\n >\n <div class=\"circle\"></div>\n <div class=\"icon icon-hash\"></div>\n </div>\n <div\n (click)=\"openAlerts()\"\n class=\"clickable\"\n id=\"RecentAlertsButton\"\n matTooltip=\"Recent Alerts\"\n matTooltipPosition=\"below\"\n matTooltipShowDelay=\"500\"\n >\n <div class=\"circle\"></div>\n <div class=\"icon icon-Bell\"></div>\n </div>\n <div\n class=\"clickable main\"\n id=\"UserButton\"\n (clickOutside)=\"closeProfileMenu()\"\n (click)=\"openProfileMenu()\"\n >\n <div class=\"main clickable\"></div>\n <div class=\"circle\"></div>\n <div\n [ngStyle]=\"{ 'background-image': 'url(' + profilePhoto + ')' }\"\n class=\"icon icon-profile\"\n ></div>\n <div [ngClass]=\"{ open: profileOpen }\" class=\"header-menu\" id=\"UserMenu\">\n @if (profileOpen) {\n <div class=\"menutitle\">{{ username }}</div>\n }\n @if (profileOpen) {\n <div\n class=\"link\"\n id=\"EditProfile\"\n routerLink=\"/profile/\"\n >\n Edit Profile\n </div>\n }\n @if (profileOpen) {\n <div\n class=\"link\"\n id=\"PersonalSettings\"\n routerLink=\"/settings/\"\n >\n Personal Settings\n </div>\n }\n @if (profileOpen) {\n <div (click)=\"confirmLogout()\" class=\"link\" id=\"LogoutButton\">Logout</div>\n }\n </div>\n </div>\n </div>\n</header>\n", styles: ["header{position:relative;top:0rem;left:0;bottom:unset;width:100%;height:var(--headerHeight);z-index:99999999;background:var(--formBackground);border-bottom-style:solid;border-bottom-color:var(--inputBorder);border-bottom-width:1px}header .overlay{width:100%;height:100%;position:absolute;z-index:1;opacity:1!important}header .left-side-buttons{position:absolute;top:0rem;left:0rem;right:0rem;width:50%;z-index:5;height:100%;padding-left:1.25rem;display:flex;align-items:center}header .left-side-buttons .apps-button .icon{width:2.25rem;height:2.25rem;position:absolute;background-size:contain;background-repeat:no-repeat;background-position:center center;transition:.3s;top:unset;left:unset;background-image:url(/assets/svgs/ziti-logo.svg)}header .left-side-buttons #NavigationButton{height:1.5rem;width:1.625rem}header .left-side-buttons #NavigationButton .status{height:1.375rem;width:1.5rem;top:unset;left:unset;animation:none}header .left-side-buttons #NavigationButton .circle{height:1.5rem;width:1.625rem}header .left-side-buttons #NavigationButton.header-nav-icon{width:2.8125rem;height:2.75rem;cursor:pointer}header .left-side-buttons #NavigationButton.header-nav-icon .status{height:2.125rem;width:2.125rem;top:unset;left:unset;animation:none}header .left-side-buttons #NavigationButton.header-nav-icon .circle{height:2.625rem;width:2.625rem;top:unset;left:unset}header .left-side-buttons #NavigationButton.header-nav-icon.nav-logo .status{display:none}header .left-side-buttons #NavigationButton.header-nav-icon.nav-logo .icon{background-image:url(/assets/svgs/icon.svg);display:flex;top:unset;left:unset;height:2.125rem;width:2.125rem}header .right-side-buttons{position:absolute;right:0rem;bottom:unset;left:unset;z-index:5;width:50%;height:100%;display:flex;flex-direction:row;justify-content:flex-end;align-items:center;padding-right:1.25rem}header .clickable{position:relative;clear:both;float:left;width:2.8125rem;height:3.125rem;display:flex;align-items:center;justify-content:center;margin:0;cursor:pointer;transition:var(--transition)}header .clickable .icon{width:1.6875rem;height:1.6875rem;position:absolute;left:.625rem;top:.75rem;background-size:contain;background-repeat:no-repeat;background-position:center center;transition:.3s}header .clickable .icon:active{transform:scale(.95);transition:.3s}header .clickable .icon.icon-Bell{font-weight:600}header .clickable .icon:before{color:var(--headerButtonColor)!important}header .clickable .icon-profile{font-size:1.7rem;font-weight:600;margin-top:.075rem}header .clickable .icon-Bell{top:.65rem;left:.575rem}header .clickable .main{opacity:1;width:2.3125rem;height:2.3125rem;left:.5625rem;top:.5625rem;border-radius:2.3125rem;position:absolute;transition:var(--transition)}header .clickable .circle{opacity:0;z-index:-2;background-color:var(--white);width:2.8125rem;height:2.8125rem;left:1px;top:.1875rem;border-radius:2.0625rem;position:absolute;transition:var(--transition)}header .clickable.open .circle{opacity:.2}header .clickable:hover .circle{opacity:.2;background-color:var(--menu)}header .clickable:active .circle{opacity:.1}header .divider-line{height:2.8125rem;width:0;margin-right:.625rem;margin-left:.625rem;border-style:solid;border-width:1px;border-color:var(--inputBorder)}header .header-title-wrapper{display:flex;flex-direction:column;align-items:flex-start;justify-content:space-between;height:100%;padding-top:.875rem;padding-bottom:.75rem}header .header-title-wrapper .header-title-container{display:flex;flex-direction:column;align-items:flex-start;justify-content:flex-start;gap:0;height:100%;cursor:pointer}header .header-title-wrapper .header-title-container .header-title-label{font-family:Russo One;text-align:center;line-height:1.5rem;color:var(--primaryColor);filter:brightness(var(--brightnessDark));cursor:pointer;font-size:1.75rem;font-variant:small-caps;font-size-adjust:.46;word-spacing:-4px}header .header-breadcrumb{display:flex;align-items:center;justify-content:flex-start;height:100%}header .header-breadcrumb .breadcrumb-path-label{font-size:.875rem;font-weight:900;filter:brightness(var(--brightnessDark));color:var(--primary)}header .header-breadcrumb .breadcrumb-path-label.non-click{text-transform:capitalize}header .header-breadcrumb .breadcrumb-path-label:hover{text-decoration:underline;cursor:pointer}header .header-breadcrumb .breadcrumb-path-label:hover.non-click{text-decoration:none;cursor:default}header .header-breadcrumb .breadcrumb-path-divider{font-size:.875rem;font-weight:600;filter:brightness(var(--brightnessDark));text-transform:uppercase;color:var(--primary);margin-left:.3125rem;margin-right:.3125rem}header .icon{font-size:1.8125rem;text-align:center;color:#fff}header #ApplicationButton{width:3.125rem}header #ApplicationButton .icon{font-size:1.5625rem;height:2.3125rem;width:2.3125rem;display:flex;justify-content:center;align-items:center;border-radius:1.875rem;font-family:icomoon!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background-color:var(--primaryColor);color:var(--mainBackground);left:.4375rem;top:.4375rem}header #ApplicationButton .circle{left:.1875rem}header #ApplicationButton.nav-button-organization .icon:before{content:\"\\e948\"}header #ApplicationButton.nav-button-browzer .icon:before{content:\"\\e96a\"}header #ApplicationButton.nav-button-billing .icon:before{content:\"\\e932\"}#AlertButton .count{width:.8125rem;height:.8125rem;border-radius:50%;font-weight:400;font-family:Open Sans,Arial,sans-serif;background-color:var(--secondaryColor);z-index:20;color:var(--white);font-size:.5rem;line-height:.75rem;font-weight:700;position:absolute;right:.8125rem;top:.9375rem;text-align:center;box-shadow:var(--shadows)}#UserButton #UserMenu{position:absolute;top:2.5rem;right:.3125rem;bottom:unset;left:unset}#UserButton #UserMenu .menutitle{color:var(--lightText)}#UserButton #UserMenu .link{color:#fff}#UserButton #UserMenu.header-menu{background-color:var(--menu);border-radius:.4375rem;box-shadow:0 0 0 1px var(--shadow),0 .5rem 1rem var(--shadow);font-size:.875rem;font-weight:600;text-transform:uppercase;color:var(--white);letter-spacing:1px;height:0rem;opacity:0;transition:.2s;z-index:50;padding-bottom:.625rem;padding-top:.625rem}#UserButton #UserMenu.header-menu .link{cursor:pointer;line-height:2.25rem;white-space:nowrap;padding-left:1.25rem;padding-right:1.25rem;transition:.2s}#UserButton #UserMenu.header-menu .link:hover{background-color:var(--primaryColor)}#UserButton #UserMenu.header-menu.open{height:unset;opacity:1}#UserButton #UserMenu .menutitle{opacity:.8;white-space:nowrap;line-height:2.25rem;padding-left:1.25rem;padding-right:1.25rem}.title-text-row{color:var(--primaryColor)!important;filter:brightness(var(--brightnessDark));opacity:1;font-family:Russo One,Arial,sans-serif;font-size:3rem;font-weight:400!important;margin:0!important;text-align:center}.title-text-row.title-top-text{font-size:4.25rem!important;line-height:3.25rem;font-variant:small-caps;font-size-adjust:.47}.title-text-row.title-bottom-text{display:flex;justify-content:flex-start;align-items:baseline;gap:.175rem;font-size:1rem}.title-text-row.title-bottom-text .nf-name-text{font-variant:small-caps;font-size-adjust:.47;font-size:1.125rem;font-weight:400;color:var(--primaryColor)}.title-text-row.title-bottom-text .nf-name-text:hover{text-decoration:underline!important}\n"] }]
|
|
42025
|
+
args: [{ selector: 'lib-header-bar', standalone: false, template: "<header>\n <div class=\"overlay\"></div>\n <div class=\"left-side-buttons\">\n <div class=\"apps-button clickable\" mattooltip=\"Select Application\" mattooltipposition=\"below\" mattooltipshowdelay=\"500\" (click)=\"goToDashboard()\">\n <div class=\"icon\"></div>\n </div>\n <div class=\"divider-line\"></div>\n <div class=\"header-title-wrapper\">\n <div class=\"header-title-container\" (click)=\"goToDashboard()\">\n <div class=\"header-title-label\">{{headerTitle}}</div>\n <div class=\"title-text-row title-bottom-text\">By <a class=\"nf-name-text\" href=\"https://netfoundry.io\" target=\"_blank\">NetFoundry</a></div>\n </div>\n </div>\n </div>\n <div class=\"right-side-buttons\">\n <div\n (click)=\"openQuickAdd()\"\n class=\"clickable\"\n id=\"QuickAddButton\"\n matTooltip=\"Add Entity\"\n matTooltipPosition=\"below\"\n matTooltipShowDelay=\"500\"\n >\n <div class=\"clicked\"></div>\n <div class=\"circle\"></div>\n <div class=\"icon icon-Icon_Add\"></div>\n </div>\n <div\n class=\"clickable\"\n id=\"AttributesButton\"\n matTooltip=\"Attributes Explorer\"\n matTooltipPosition=\"below\"\n matTooltipShowDelay=\"500\"\n routerLink=\"/attributes/\"\n >\n <div class=\"circle\"></div>\n <div class=\"icon icon-hash\"></div>\n </div>\n <div\n (click)=\"openAlerts()\"\n class=\"clickable\"\n id=\"RecentAlertsButton\"\n matTooltip=\"Recent Alerts\"\n matTooltipPosition=\"below\"\n matTooltipShowDelay=\"500\"\n >\n <div class=\"circle\"></div>\n <div class=\"icon icon-Bell\"></div>\n </div>\n <div\n class=\"clickable main\"\n id=\"UserButton\"\n (clickOutside)=\"closeProfileMenu()\"\n (click)=\"openProfileMenu()\"\n >\n <div class=\"main clickable\"></div>\n <div class=\"circle\"></div>\n <div\n [ngStyle]=\"{ 'background-image': 'url(' + profilePhoto + ')' }\"\n class=\"icon icon-profile\"\n ></div>\n <div [ngClass]=\"{ open: profileOpen }\" class=\"header-menu\" id=\"UserMenu\">\n @if (profileOpen) {\n <div class=\"menutitle\">{{ username }}</div>\n }\n @if (profileOpen) {\n <div\n class=\"link\"\n id=\"EditProfile\"\n routerLink=\"/profile/\"\n >\n Edit Profile\n </div>\n }\n @if (profileOpen) {\n <div\n class=\"link\"\n id=\"PersonalSettings\"\n routerLink=\"/settings/\"\n >\n Personal Settings\n </div>\n }\n @if (profileOpen) {\n <div (click)=\"confirmLogout()\" class=\"link\" id=\"LogoutButton\">Logout</div>\n }\n </div>\n </div>\n </div>\n</header>\n", styles: ["header{position:relative;top:0rem;left:0;bottom:unset;width:100%;height:var(--headerHeight);z-index:99999999;background:var(--formBackground);border-bottom-style:solid;border-bottom-color:var(--inputBorder);border-bottom-width:1px}header .overlay{width:100%;height:100%;position:absolute;z-index:1;opacity:1!important}header .left-side-buttons{position:absolute;top:0rem;left:0rem;right:0rem;width:50%;z-index:5;height:100%;padding-left:1.25rem;display:flex;align-items:center}header .left-side-buttons .apps-button .icon{width:2.25rem;height:2.25rem;position:absolute;background-size:contain;background-repeat:no-repeat;background-position:center center;transition:.3s;top:unset;left:unset;background-image:url(/assets/svgs/ziti-logo.svg)}header .left-side-buttons #NavigationButton{height:1.5rem;width:1.625rem}header .left-side-buttons #NavigationButton .status{height:1.375rem;width:1.5rem;top:unset;left:unset;animation:none}header .left-side-buttons #NavigationButton .circle{height:1.5rem;width:1.625rem}header .left-side-buttons #NavigationButton.header-nav-icon{width:2.8125rem;height:2.75rem;cursor:pointer}header .left-side-buttons #NavigationButton.header-nav-icon .status{height:2.125rem;width:2.125rem;top:unset;left:unset;animation:none}header .left-side-buttons #NavigationButton.header-nav-icon .circle{height:2.625rem;width:2.625rem;top:unset;left:unset}header .left-side-buttons #NavigationButton.header-nav-icon.nav-logo .status{display:none}header .left-side-buttons #NavigationButton.header-nav-icon.nav-logo .icon{background-image:url(/assets/svgs/icon.svg);display:flex;top:unset;left:unset;height:2.125rem;width:2.125rem}header .right-side-buttons{position:absolute;right:0rem;bottom:unset;left:unset;z-index:5;width:50%;height:100%;display:flex;flex-direction:row;justify-content:flex-end;align-items:center;padding-right:1.25rem}header .clickable{position:relative;clear:both;float:left;width:2.8125rem;height:3.125rem;display:flex;align-items:center;justify-content:center;margin:0;cursor:pointer;transition:var(--transition)}header .clickable .icon{width:1.6875rem;height:1.6875rem;position:absolute;left:.625rem;top:.75rem;background-size:contain;background-repeat:no-repeat;background-position:center center;transition:.3s}header .clickable .icon:active{transform:scale(.95);transition:.3s}header .clickable .icon.icon-Bell{font-weight:600}header .clickable .icon:before{color:var(--headerButtonColor)!important}header .clickable .icon-profile{font-size:1.7rem;font-weight:600;margin-top:.075rem}header .clickable .icon-Bell{top:.65rem;left:.575rem}header .clickable .main{opacity:1;width:2.3125rem;height:2.3125rem;left:.5625rem;top:.5625rem;border-radius:2.3125rem;position:absolute;transition:var(--transition)}header .clickable .circle{opacity:0;z-index:-2;background-color:var(--white);width:2.8125rem;height:2.8125rem;left:1px;top:.1875rem;border-radius:2.0625rem;position:absolute;transition:var(--transition)}header .clickable.open .circle{opacity:.2}header .clickable:hover .circle{opacity:.2;background-color:var(--menu)}header .clickable:active .circle{opacity:.1}header .divider-line{height:2.8125rem;width:0;margin-right:.625rem;margin-left:.625rem;border-style:solid;border-width:1px;border-color:var(--inputBorder)}header .header-title-wrapper{display:flex;flex-direction:column;align-items:flex-start;justify-content:space-between;height:100%;padding-top:.875rem;padding-bottom:.75rem}header .header-title-wrapper .header-title-container{display:flex;flex-direction:column;align-items:flex-start;justify-content:flex-start;gap:0;height:100%;cursor:pointer}header .header-title-wrapper .header-title-container .header-title-label{font-family:Russo One;text-align:center;line-height:1.5rem;color:var(--primaryColor);filter:brightness(var(--brightnessDark));cursor:pointer;font-size:1.75rem;font-variant:small-caps;font-size-adjust:.46;word-spacing:-4px}header .header-breadcrumb{display:flex;align-items:center;justify-content:flex-start;height:100%}header .header-breadcrumb .breadcrumb-path-label{font-size:.875rem;font-weight:900;filter:brightness(var(--brightnessDark));color:var(--primary)}header .header-breadcrumb .breadcrumb-path-label.non-click{text-transform:capitalize}header .header-breadcrumb .breadcrumb-path-label:hover{text-decoration:underline;cursor:pointer}header .header-breadcrumb .breadcrumb-path-label:hover.non-click{text-decoration:none;cursor:default}header .header-breadcrumb .breadcrumb-path-divider{font-size:.875rem;font-weight:600;filter:brightness(var(--brightnessDark));text-transform:uppercase;color:var(--primary);margin-left:.3125rem;margin-right:.3125rem}header .icon{font-size:1.8125rem;text-align:center;color:#fff}header #ApplicationButton{width:3.125rem}header #ApplicationButton .icon{font-size:1.5625rem;height:2.3125rem;width:2.3125rem;display:flex;justify-content:center;align-items:center;border-radius:1.875rem;font-family:icomoon!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background-color:var(--primaryColor);color:var(--mainBackground);left:.4375rem;top:.4375rem}header #ApplicationButton .circle{left:.1875rem}header #ApplicationButton.nav-button-organization .icon:before{content:\"\\e948\"}header #ApplicationButton.nav-button-browzer .icon:before{content:\"\\e96a\"}header #ApplicationButton.nav-button-billing .icon:before{content:\"\\e932\"}#AlertButton .count{width:.8125rem;height:.8125rem;border-radius:50%;font-weight:400;font-family:Open Sans,Arial,sans-serif;background-color:var(--secondaryColor);z-index:20;color:var(--white);font-size:.5rem;line-height:.75rem;font-weight:700;position:absolute;right:.8125rem;top:.9375rem;text-align:center;box-shadow:var(--shadows)}#UserButton #UserMenu{position:absolute;top:2.5rem;right:.3125rem;bottom:unset;left:unset}#UserButton #UserMenu .menutitle{color:var(--lightText)}#UserButton #UserMenu .link{color:#fff}#UserButton #UserMenu.header-menu{background-color:var(--menu);border-radius:.4375rem;box-shadow:0 0 0 1px var(--shadow),0 .5rem 1rem var(--shadow);font-size:.875rem;font-weight:600;text-transform:uppercase;color:var(--white);letter-spacing:1px;height:0rem;opacity:0;transition:.2s;z-index:50;padding-bottom:.625rem;padding-top:.625rem}#UserButton #UserMenu.header-menu .link{cursor:pointer;line-height:2.25rem;white-space:nowrap;padding-left:1.25rem;padding-right:1.25rem;transition:.2s}#UserButton #UserMenu.header-menu .link:hover{background-color:var(--primaryColor)}#UserButton #UserMenu.header-menu.open{height:unset;opacity:1}#UserButton #UserMenu .menutitle{opacity:.8;white-space:nowrap;line-height:2.25rem;padding-left:1.25rem;padding-right:1.25rem}.title-text-row{color:var(--primaryColor)!important;filter:brightness(var(--brightnessDark));opacity:1;font-family:Russo One,Arial,sans-serif;font-size:3rem;font-weight:400!important;margin:0!important;text-align:center}.title-text-row.title-top-text{font-size:4.25rem!important;line-height:3.25rem;font-variant:small-caps;font-size-adjust:.47}.title-text-row.title-bottom-text{display:flex;justify-content:flex-start;align-items:baseline;gap:.175rem;font-size:1rem}.title-text-row.title-bottom-text .nf-name-text{font-variant:small-caps;font-size-adjust:.47;font-size:1.125rem;font-weight:400;color:var(--primaryColor)}.title-text-row.title-bottom-text .nf-name-text:hover{text-decoration:underline!important}\n"] }]
|
|
39500
42026
|
}], ctorParameters: () => [{ type: i4.Router }, { type: i5.MatDialog }, { type: LoginServiceClass, decorators: [{
|
|
39501
42027
|
type: Inject,
|
|
39502
42028
|
args: [ZAC_LOGIN_SERVICE]
|
|
@@ -39542,12 +42068,24 @@ class OpenZitiConsoleLibModule {
|
|
|
39542
42068
|
ConfigTypesPageComponent,
|
|
39543
42069
|
ConfigTypeFormComponent,
|
|
39544
42070
|
ListPageHeaderComponent,
|
|
42071
|
+
ListTableHeaderComponent,
|
|
39545
42072
|
FilterBarComponent,
|
|
39546
42073
|
ListPageFormComponent,
|
|
39547
42074
|
IdentitiesPageComponent,
|
|
42075
|
+
IdentitiesListPageComponent,
|
|
39548
42076
|
EdgeRoutersPageComponent,
|
|
39549
42077
|
TransitRoutersPageComponent,
|
|
39550
42078
|
DataTableComponent,
|
|
42079
|
+
ListTableComponent,
|
|
42080
|
+
ListMenuComponent,
|
|
42081
|
+
NameCellComponent,
|
|
42082
|
+
SelectCellComponent,
|
|
42083
|
+
ListHeaderCellComponent,
|
|
42084
|
+
ListFilterCellComponent,
|
|
42085
|
+
OsInfoTooltipComponent,
|
|
42086
|
+
SdkInfoTooltipComponent,
|
|
42087
|
+
BooleanCellComponent,
|
|
42088
|
+
TokenCellComponent,
|
|
39551
42089
|
TableCellSelectComponent,
|
|
39552
42090
|
TableColumnSelectComponent,
|
|
39553
42091
|
TableCellMenuComponent,
|
|
@@ -39650,6 +42188,7 @@ class OpenZitiConsoleLibModule {
|
|
|
39650
42188
|
MatButtonModule,
|
|
39651
42189
|
MatIconModule,
|
|
39652
42190
|
OverlayModule,
|
|
42191
|
+
DragDropModule,
|
|
39653
42192
|
AgGridModule,
|
|
39654
42193
|
QRCodeComponent,
|
|
39655
42194
|
ClickOutsideModule,
|
|
@@ -39678,6 +42217,7 @@ class OpenZitiConsoleLibModule {
|
|
|
39678
42217
|
EdgeRouterFormComponent,
|
|
39679
42218
|
TransitRouterFormComponent,
|
|
39680
42219
|
IdentitiesPageComponent,
|
|
42220
|
+
IdentitiesListPageComponent,
|
|
39681
42221
|
EdgeRoutersPageComponent,
|
|
39682
42222
|
TransitRoutersPageComponent,
|
|
39683
42223
|
ServicesPageComponent,
|
|
@@ -39721,7 +42261,9 @@ class OpenZitiConsoleLibModule {
|
|
|
39721
42261
|
SideNavigatorComponent,
|
|
39722
42262
|
FilterSelectComponent,
|
|
39723
42263
|
FilterSelectOptionTemplateDirective,
|
|
39724
|
-
FilterSelectTriggerTemplateDirective
|
|
42264
|
+
FilterSelectTriggerTemplateDirective,
|
|
42265
|
+
ListTableComponent,
|
|
42266
|
+
ListTableHeaderComponent] }); }
|
|
39725
42267
|
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: OpenZitiConsoleLibModule, providers: [
|
|
39726
42268
|
{ provide: SHAREDZ_EXTENSION, useClass: ExtensionsNoopService },
|
|
39727
42269
|
{ provide: ZITI_NAVIGATOR, useValue: {} },
|
|
@@ -39746,6 +42288,7 @@ class OpenZitiConsoleLibModule {
|
|
|
39746
42288
|
MatButtonModule,
|
|
39747
42289
|
MatIconModule,
|
|
39748
42290
|
OverlayModule,
|
|
42291
|
+
DragDropModule,
|
|
39749
42292
|
AgGridModule,
|
|
39750
42293
|
QRCodeComponent,
|
|
39751
42294
|
ClickOutsideModule,
|
|
@@ -39777,12 +42320,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
39777
42320
|
ConfigTypesPageComponent,
|
|
39778
42321
|
ConfigTypeFormComponent,
|
|
39779
42322
|
ListPageHeaderComponent,
|
|
42323
|
+
ListTableHeaderComponent,
|
|
39780
42324
|
FilterBarComponent,
|
|
39781
42325
|
ListPageFormComponent,
|
|
39782
42326
|
IdentitiesPageComponent,
|
|
42327
|
+
IdentitiesListPageComponent,
|
|
39783
42328
|
EdgeRoutersPageComponent,
|
|
39784
42329
|
TransitRoutersPageComponent,
|
|
39785
42330
|
DataTableComponent,
|
|
42331
|
+
ListTableComponent,
|
|
42332
|
+
ListMenuComponent,
|
|
42333
|
+
NameCellComponent,
|
|
42334
|
+
SelectCellComponent,
|
|
42335
|
+
ListHeaderCellComponent,
|
|
42336
|
+
ListFilterCellComponent,
|
|
42337
|
+
OsInfoTooltipComponent,
|
|
42338
|
+
SdkInfoTooltipComponent,
|
|
42339
|
+
BooleanCellComponent,
|
|
42340
|
+
TokenCellComponent,
|
|
39786
42341
|
TableCellSelectComponent,
|
|
39787
42342
|
TableColumnSelectComponent,
|
|
39788
42343
|
TableCellMenuComponent,
|
|
@@ -39896,6 +42451,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
39896
42451
|
EdgeRouterFormComponent,
|
|
39897
42452
|
TransitRouterFormComponent,
|
|
39898
42453
|
IdentitiesPageComponent,
|
|
42454
|
+
IdentitiesListPageComponent,
|
|
39899
42455
|
EdgeRoutersPageComponent,
|
|
39900
42456
|
TransitRoutersPageComponent,
|
|
39901
42457
|
ServicesPageComponent,
|
|
@@ -39939,7 +42495,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
39939
42495
|
SideNavigatorComponent,
|
|
39940
42496
|
FilterSelectComponent,
|
|
39941
42497
|
FilterSelectOptionTemplateDirective,
|
|
39942
|
-
FilterSelectTriggerTemplateDirective
|
|
42498
|
+
FilterSelectTriggerTemplateDirective,
|
|
42499
|
+
ListTableComponent,
|
|
42500
|
+
ListTableHeaderComponent
|
|
39943
42501
|
], imports: [
|
|
39944
42502
|
CommonModule,
|
|
39945
42503
|
FormsModule,
|
|
@@ -39954,6 +42512,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
39954
42512
|
MatButtonModule,
|
|
39955
42513
|
MatIconModule,
|
|
39956
42514
|
OverlayModule,
|
|
42515
|
+
DragDropModule,
|
|
39957
42516
|
AgGridModule,
|
|
39958
42517
|
QRCodeComponent,
|
|
39959
42518
|
ClickOutsideModule,
|
|
@@ -40360,6 +42919,10 @@ class NodeDataService extends ZitiDataService {
|
|
|
40360
42919
|
paging.rawFilter = true;
|
|
40361
42920
|
filterVal = this.getAttributeFilter(filter.value, filter.columnId);
|
|
40362
42921
|
break;
|
|
42922
|
+
case 'MULTISELECT':
|
|
42923
|
+
paging.rawFilter = true;
|
|
42924
|
+
filterVal = this.getMultiSelectFilter(filter.value, filter.columnId, filter.semantic);
|
|
42925
|
+
break;
|
|
40363
42926
|
default:
|
|
40364
42927
|
filterVal = `${filter.columnId} contains "${filter.value}"`;
|
|
40365
42928
|
break;
|
|
@@ -40801,6 +43364,9 @@ class ZitiControllerDataService extends ZitiDataService {
|
|
|
40801
43364
|
case 'ATTRIBUTE':
|
|
40802
43365
|
filterVal = this.getAttributeFilter(filter.value, filter.columnId, filter.semantic);
|
|
40803
43366
|
break;
|
|
43367
|
+
case 'MULTISELECT':
|
|
43368
|
+
filterVal = this.getMultiSelectFilter(filter.value, filter.columnId, filter.semantic);
|
|
43369
|
+
break;
|
|
40804
43370
|
case 'BOOLEAN':
|
|
40805
43371
|
filterVal = `${filter.columnId}=${filter.value}`;
|
|
40806
43372
|
break;
|
|
@@ -41410,8 +43976,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
41410
43976
|
args: [SETTINGS_SERVICE]
|
|
41411
43977
|
}] }, { type: ZitiOidcService }, { type: GrowlerService }, { type: i0.Injector }] });
|
|
41412
43978
|
|
|
43979
|
+
/*
|
|
43980
|
+
Copyright NetFoundry Inc.
|
|
43981
|
+
|
|
43982
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
43983
|
+
you may not use this file except in compliance with the License.
|
|
43984
|
+
You may obtain a copy of the License at
|
|
43985
|
+
|
|
43986
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
43987
|
+
|
|
43988
|
+
Unless required by applicable law or agreed to in writing, software
|
|
43989
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
43990
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
43991
|
+
See the License for the specific language governing permissions and
|
|
43992
|
+
limitations under the License.
|
|
43993
|
+
*/
|
|
43994
|
+
|
|
41413
43995
|
const ZAC_VERSION = {
|
|
41414
|
-
"version": "4.5.
|
|
43996
|
+
"version": "4.5.4"
|
|
41415
43997
|
};
|
|
41416
43998
|
|
|
41417
43999
|
/*
|
|
@@ -41422,5 +44004,5 @@ const ZAC_VERSION = {
|
|
|
41422
44004
|
* Generated bundle index. Do not edit.
|
|
41423
44005
|
*/
|
|
41424
44006
|
|
|
41425
|
-
export { APISessionFormComponent, APISessionsPageComponent, API_RESOURCE_TO_ENTITY_PERMISSION, ApiSessionsPageService, AttributesComponent, AuthPoliciesPageComponent, AuthPoliciesPageService, AuthPolicyFormComponent, AuthPolicyFormService, AuthService, BooleanToggleInputComponent, CallbackComponent, CardListComponent, CertificateAuthoritiesPageComponent, CertificateAuthoritiesPageService, CertificateAuthorityFormComponent, CertificateAuthorityFormService, CheckboxListInputComponent, ChipsInputComponent, 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, IdentitiesPageComponent, IdentitiesPageService, Identity$1 as Identity, IdentityFormComponent, IdentityFormService, IdentityServicePathComponent, InsecureContextError, JsonViewComponent, JwtSignerFormComponent, JwtSignerFormService, JwtSignersPageComponent, JwtSignersPageService, KEY_CODES, ListPageComponent, ListPageServiceClass, LoadingIndicatorComponent, LoggerService, LoginDialogComponent, LoginServiceClass, ManagementPermissionsService, NetworkVisualizerComponent, NodeDataService, NoopLoginService, NoopTabInterceptorService, NumberInputComponent, OIDC_CLIENT_ID, OIDC_CLIENT_ID_LEGACY, ObjectComponent, OidcEnvironmentalError, OidcSessionUnrecoverableError, OpenZitiConsoleLibModule, 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, 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, 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 };
|
|
44007
|
+
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, 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, 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 };
|
|
41426
44008
|
//# sourceMappingURL=openziti-ziti-console-lib.mjs.map
|