@serve.zone/dcrouter 16.2.1 → 16.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/deno.json +1 -1
- package/dist_serve/bundle.js +1024 -960
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/config/helpers.http-redirects.d.ts +1 -1
- package/dist_ts/config/helpers.http-redirects.js +4 -3
- package/dist_ts_interfaces/data/route-management.d.ts +2 -0
- package/dist_ts_interfaces/data/route-management.js +6 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/access/ops-view-apitokens.js +3 -3
- package/dist_ts_web/elements/access/ops-view-gatewayclients.js +3 -3
- package/dist_ts_web/elements/network/ops-view-network-activity.js +6 -6
- package/dist_ts_web/elements/network/ops-view-redirects.d.ts +2 -0
- package/dist_ts_web/elements/network/ops-view-redirects.js +14 -3
- package/dist_ts_web/elements/network/ops-view-remoteingress.js +3 -3
- package/dist_ts_web/elements/network/ops-view-routes.d.ts +6 -7
- package/dist_ts_web/elements/network/ops-view-routes.js +178 -132
- package/dist_ts_web/elements/network/ops-view-special-forwards.d.ts +2 -0
- package/dist_ts_web/elements/network/ops-view-special-forwards.js +38 -10
- package/dist_ts_web/elements/network/ops-view-vpn.js +3 -3
- package/dist_ts_web/elements/network/route-view-filters.d.ts +6 -0
- package/dist_ts_web/elements/network/route-view-filters.js +29 -0
- package/dist_ts_web/elements/security/ops-view-security-blocked.js +6 -6
- package/package.json +2 -2
- package/readme.md +1 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/config/helpers.http-redirects.ts +6 -3
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/access/ops-view-apitokens.ts +2 -2
- package/ts_web/elements/access/ops-view-gatewayclients.ts +2 -2
- package/ts_web/elements/network/ops-view-network-activity.ts +5 -5
- package/ts_web/elements/network/ops-view-redirects.ts +9 -1
- package/ts_web/elements/network/ops-view-remoteingress.ts +2 -2
- package/ts_web/elements/network/ops-view-routes.ts +197 -138
- package/ts_web/elements/network/ops-view-special-forwards.ts +35 -7
- package/ts_web/elements/network/ops-view-vpn.ts +2 -2
- package/ts_web/elements/network/route-view-filters.ts +43 -0
- package/ts_web/elements/security/ops-view-security-blocked.ts +5 -5
- package/ts_web/readme.md +4 -4
|
@@ -133,7 +133,7 @@ export class OpsViewApiTokens extends DeesElement {
|
|
|
133
133
|
name: 'Enable',
|
|
134
134
|
iconName: 'lucide:play',
|
|
135
135
|
type: ['inRow', 'contextmenu'] as any,
|
|
136
|
-
actionRelevancyCheckFunc: (
|
|
136
|
+
actionRelevancyCheckFunc: (token: any) => !token.enabled,
|
|
137
137
|
actionFunc: async (actionData: any) => {
|
|
138
138
|
const token = actionData.item as interfaces.data.IApiTokenInfo;
|
|
139
139
|
await appstate.routeManagementStatePart.dispatchAction(
|
|
@@ -146,7 +146,7 @@ export class OpsViewApiTokens extends DeesElement {
|
|
|
146
146
|
name: 'Disable',
|
|
147
147
|
iconName: 'lucide:pause',
|
|
148
148
|
type: ['inRow', 'contextmenu'] as any,
|
|
149
|
-
actionRelevancyCheckFunc: (
|
|
149
|
+
actionRelevancyCheckFunc: (token: any) => token.enabled,
|
|
150
150
|
actionFunc: async (actionData: any) => {
|
|
151
151
|
const token = actionData.item as interfaces.data.IApiTokenInfo;
|
|
152
152
|
await appstate.routeManagementStatePart.dispatchAction(
|
|
@@ -97,7 +97,7 @@ export class OpsViewGatewayClients extends DeesElement {
|
|
|
97
97
|
name: 'Enable',
|
|
98
98
|
iconName: 'lucide:play',
|
|
99
99
|
type: ['inRow', 'contextmenu'] as any,
|
|
100
|
-
actionRelevancyCheckFunc: (
|
|
100
|
+
actionRelevancyCheckFunc: (client: any) => !client.enabled,
|
|
101
101
|
actionFunc: async (actionData: any) => {
|
|
102
102
|
await appstate.routeManagementStatePart.dispatchAction(appstate.updateGatewayClientAction, {
|
|
103
103
|
id: actionData.item.id,
|
|
@@ -109,7 +109,7 @@ export class OpsViewGatewayClients extends DeesElement {
|
|
|
109
109
|
name: 'Disable',
|
|
110
110
|
iconName: 'lucide:pause',
|
|
111
111
|
type: ['inRow', 'contextmenu'] as any,
|
|
112
|
-
actionRelevancyCheckFunc: (
|
|
112
|
+
actionRelevancyCheckFunc: (client: any) => client.enabled,
|
|
113
113
|
actionFunc: async (actionData: any) => {
|
|
114
114
|
await appstate.routeManagementStatePart.dispatchAction(appstate.updateGatewayClientAction, {
|
|
115
115
|
id: actionData.item.id,
|
|
@@ -415,7 +415,7 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
415
415
|
name: 'Block Network Range',
|
|
416
416
|
iconName: 'lucide:network',
|
|
417
417
|
type: ['contextmenu'] as any,
|
|
418
|
-
actionRelevancyCheckFunc: (
|
|
418
|
+
actionRelevancyCheckFunc: (entry: any) => Boolean(this.getIpIntelligence(entry.ip)?.networkRange),
|
|
419
419
|
actionFunc: async (actionData: any) => {
|
|
420
420
|
const record = this.getIpIntelligence(actionData.item.ip);
|
|
421
421
|
await this.createBlockRuleDialog('cidr', record!.networkRange!, 'Blocked network range from Network Activity');
|
|
@@ -425,7 +425,7 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
425
425
|
name: 'Block ASN',
|
|
426
426
|
iconName: 'lucide:radio-tower',
|
|
427
427
|
type: ['contextmenu'] as any,
|
|
428
|
-
actionRelevancyCheckFunc: (
|
|
428
|
+
actionRelevancyCheckFunc: (entry: any) => Boolean(this.getIpIntelligence(entry.ip)?.asn),
|
|
429
429
|
actionFunc: async (actionData: any) => {
|
|
430
430
|
const record = this.getIpIntelligence(actionData.item.ip);
|
|
431
431
|
await this.createBlockRuleDialog('asn', String(record!.asn), 'Blocked ASN from Network Activity');
|
|
@@ -435,7 +435,7 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
435
435
|
name: 'Block Organization',
|
|
436
436
|
iconName: 'lucide:building-2',
|
|
437
437
|
type: ['contextmenu'] as any,
|
|
438
|
-
actionRelevancyCheckFunc: (
|
|
438
|
+
actionRelevancyCheckFunc: (entry: any) => Boolean(this.getIpOrganization(this.getIpIntelligence(entry.ip))),
|
|
439
439
|
actionFunc: async (actionData: any) => {
|
|
440
440
|
const record = this.getIpIntelligence(actionData.item.ip);
|
|
441
441
|
await this.createBlockRuleDialog('organization', this.getIpOrganization(record), 'Blocked organization from Network Activity');
|
|
@@ -445,7 +445,7 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
445
445
|
name: 'View Intelligence',
|
|
446
446
|
iconName: 'lucide:info',
|
|
447
447
|
type: ['doubleClick', 'contextmenu'] as any,
|
|
448
|
-
actionRelevancyCheckFunc: (
|
|
448
|
+
actionRelevancyCheckFunc: (entry: any) => Boolean(this.getIpIntelligence(entry.ip)),
|
|
449
449
|
actionFunc: async (actionData: any) => {
|
|
450
450
|
await this.showIpIntelligenceDetails(actionData.item.ip);
|
|
451
451
|
},
|
|
@@ -467,7 +467,7 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
467
467
|
name: 'Block Organization',
|
|
468
468
|
iconName: 'lucide:building-2',
|
|
469
469
|
type: ['contextmenu'] as any,
|
|
470
|
-
actionRelevancyCheckFunc: (
|
|
470
|
+
actionRelevancyCheckFunc: (entry: any) => Boolean(entry.organization),
|
|
471
471
|
actionFunc: async (actionData: any) => {
|
|
472
472
|
await this.createBlockRuleDialog('organization', actionData.item.organization, 'Blocked organization from Network Activity');
|
|
473
473
|
},
|
|
@@ -12,6 +12,10 @@ import { type IStatsTile } from '@design.estate/dees-catalog';
|
|
|
12
12
|
import * as appstate from '../../appstate.js';
|
|
13
13
|
import * as interfaces from '../../../dist_ts_interfaces/index.js';
|
|
14
14
|
import { viewHostCss } from '../shared/css.js';
|
|
15
|
+
import {
|
|
16
|
+
redirectMatchesOwner,
|
|
17
|
+
type TRouteOwnerFilter,
|
|
18
|
+
} from './route-view-filters.js';
|
|
15
19
|
|
|
16
20
|
declare global {
|
|
17
21
|
interface HTMLElementTagNameMap {
|
|
@@ -23,6 +27,8 @@ declare global {
|
|
|
23
27
|
export class OpsViewRedirects extends DeesElement {
|
|
24
28
|
@property({ type: Boolean })
|
|
25
29
|
accessor embedded = false;
|
|
30
|
+
@property({ type: String })
|
|
31
|
+
accessor ownerFilter: TRouteOwnerFilter = 'all';
|
|
26
32
|
|
|
27
33
|
@state()
|
|
28
34
|
accessor routeState: appstate.IRouteManagementState = appstate.routeManagementStatePart.getState()!;
|
|
@@ -72,7 +78,9 @@ export class OpsViewRedirects extends DeesElement {
|
|
|
72
78
|
];
|
|
73
79
|
|
|
74
80
|
public render(): TemplateResult {
|
|
75
|
-
const redirects = this.routeState.httpRedirects || []
|
|
81
|
+
const redirects = (this.routeState.httpRedirects || []).filter((redirect) => {
|
|
82
|
+
return redirectMatchesOwner(redirect, this.routeState.mergedRoutes, this.ownerFilter);
|
|
83
|
+
});
|
|
76
84
|
const activeCount = redirects.filter((redirect) => redirect.status === 'active').length;
|
|
77
85
|
const coveredCount = redirects.filter((redirect) => redirect.status === 'covered').length;
|
|
78
86
|
const skippedCount = redirects.filter((redirect) => redirect.status === 'skipped').length;
|
|
@@ -344,7 +344,7 @@ export class OpsViewRemoteIngress extends DeesElement {
|
|
|
344
344
|
name: 'Enable',
|
|
345
345
|
iconName: 'lucide:play',
|
|
346
346
|
type: ['inRow', 'contextmenu'] as any,
|
|
347
|
-
actionRelevancyCheckFunc: (
|
|
347
|
+
actionRelevancyCheckFunc: (endpoint: any) => !endpoint.enabled,
|
|
348
348
|
actionFunc: async (actionData: any) => {
|
|
349
349
|
const edge = actionData.item as interfaces.data.IRemoteIngress;
|
|
350
350
|
await appstate.remoteIngressStatePart.dispatchAction(
|
|
@@ -357,7 +357,7 @@ export class OpsViewRemoteIngress extends DeesElement {
|
|
|
357
357
|
name: 'Disable',
|
|
358
358
|
iconName: 'lucide:pause',
|
|
359
359
|
type: ['inRow', 'contextmenu'] as any,
|
|
360
|
-
actionRelevancyCheckFunc: (
|
|
360
|
+
actionRelevancyCheckFunc: (endpoint: any) => endpoint.enabled,
|
|
361
361
|
actionFunc: async (actionData: any) => {
|
|
362
362
|
const edge = actionData.item as interfaces.data.IRemoteIngress;
|
|
363
363
|
await appstate.remoteIngressStatePart.dispatchAction(
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import * as appstate from '../../appstate.js';
|
|
2
2
|
import * as interfaces from '../../../dist_ts_interfaces/index.js';
|
|
3
3
|
import { viewHostCss } from '../shared/css.js';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
type DeesInputMultitoggle,
|
|
6
|
+
type IStatsTile,
|
|
7
|
+
} from '@design.estate/dees-catalog';
|
|
5
8
|
import './ops-view-redirects.js';
|
|
6
9
|
import './ops-view-special-forwards.js';
|
|
10
|
+
import {
|
|
11
|
+
getRouteOwner,
|
|
12
|
+
routeMatchesOwner,
|
|
13
|
+
type TRouteOwnerFilter,
|
|
14
|
+
} from './route-view-filters.js';
|
|
7
15
|
import type {
|
|
8
16
|
IRoutePathClassOption as ISzRoutePathClassOption,
|
|
9
17
|
IRouteSourcePolicyPreset as ISzRouteSourcePolicyPreset,
|
|
@@ -21,9 +29,10 @@ import {
|
|
|
21
29
|
type TemplateResult,
|
|
22
30
|
} from '@design.estate/dees-element';
|
|
23
31
|
|
|
24
|
-
type TRoutesSection = '
|
|
25
|
-
|
|
26
|
-
|
|
32
|
+
type TRoutesSection = 'all' | 'standard' | 'redirects' | 'special';
|
|
33
|
+
|
|
34
|
+
const routeTypeOptions = ['All', 'Standard', 'Redirect', 'Special'];
|
|
35
|
+
const routeOwnerOptions = ['All', 'User', 'Gateway Client', 'System'];
|
|
27
36
|
|
|
28
37
|
// TLS dropdown options shared by create and edit dialogs
|
|
29
38
|
const tlsModeOptions = [
|
|
@@ -327,34 +336,6 @@ export class OpsViewRoutes extends DeesElement {
|
|
|
327
336
|
@state() accessor activeSection: TRoutesSection = 'standard';
|
|
328
337
|
@state() accessor ownerFilter: TRouteOwnerFilter = 'all';
|
|
329
338
|
|
|
330
|
-
private readonly sectionTabs: IMenuItem[] = [
|
|
331
|
-
{
|
|
332
|
-
key: 'Standard Routes',
|
|
333
|
-
iconName: 'lucide:route',
|
|
334
|
-
action: () => this.setRouteView('standard'),
|
|
335
|
-
},
|
|
336
|
-
{
|
|
337
|
-
key: 'Special Forwards',
|
|
338
|
-
iconName: 'lucide:split',
|
|
339
|
-
action: () => this.setRouteView('special'),
|
|
340
|
-
},
|
|
341
|
-
{
|
|
342
|
-
key: 'Redirects',
|
|
343
|
-
iconName: 'lucide:cornerDownRight',
|
|
344
|
-
action: () => this.setRouteView('redirects'),
|
|
345
|
-
},
|
|
346
|
-
];
|
|
347
|
-
|
|
348
|
-
private readonly ownerTabs: IMenuItem[] = [
|
|
349
|
-
{ key: 'All', action: () => this.setRouteOwnerFilter('all') },
|
|
350
|
-
{ key: 'Operator', action: () => this.setRouteOwnerFilter('operator') },
|
|
351
|
-
{
|
|
352
|
-
key: 'Gateway Client',
|
|
353
|
-
action: () => this.setRouteOwnerFilter('gatewayClient'),
|
|
354
|
-
},
|
|
355
|
-
{ key: 'System', action: () => this.setRouteOwnerFilter('system') },
|
|
356
|
-
];
|
|
357
|
-
|
|
358
339
|
private readonly popStateHandler = () => {
|
|
359
340
|
const urlState = this.readUrlState();
|
|
360
341
|
this.activeSection = urlState.section;
|
|
@@ -433,6 +414,25 @@ export class OpsViewRoutes extends DeesElement {
|
|
|
433
414
|
gap: 24px;
|
|
434
415
|
}
|
|
435
416
|
|
|
417
|
+
.routeFilters {
|
|
418
|
+
display: flex;
|
|
419
|
+
align-items: flex-start;
|
|
420
|
+
gap: 16px;
|
|
421
|
+
flex-wrap: wrap;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.routeFilter {
|
|
425
|
+
min-width: 0;
|
|
426
|
+
max-width: 100%;
|
|
427
|
+
overflow-x: auto;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
@media (max-width: 760px) {
|
|
431
|
+
.routeFilters {
|
|
432
|
+
flex-direction: column;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
436
|
.warnings-bar {
|
|
437
437
|
background: ${cssManager.bdTheme('rgba(255, 170, 0, 0.08)', 'rgba(255, 170, 0, 0.1)')};
|
|
438
438
|
border: 1px solid ${cssManager.bdTheme('rgba(255, 170, 0, 0.25)', 'rgba(255, 170, 0, 0.3)')};
|
|
@@ -467,41 +467,41 @@ export class OpsViewRoutes extends DeesElement {
|
|
|
467
467
|
|
|
468
468
|
public render(): TemplateResult {
|
|
469
469
|
const { mergedRoutes, warnings } = this.routeState;
|
|
470
|
+
const standardRoutes = mergedRoutes.filter((route) => !route.metadata?.managedRouteKind);
|
|
471
|
+
const filteredRoutes = standardRoutes.filter((route) => {
|
|
472
|
+
return routeMatchesOwner(route, this.ownerFilter);
|
|
473
|
+
});
|
|
470
474
|
|
|
471
|
-
const disabledCount =
|
|
472
|
-
const
|
|
473
|
-
const
|
|
474
|
-
return mr.origin === 'api'
|
|
475
|
-
&& mr.metadata?.ownerType !== 'gatewayClient'
|
|
476
|
-
&& !mr.metadata?.managedRouteKind;
|
|
477
|
-
}).length;
|
|
475
|
+
const disabledCount = filteredRoutes.filter((route) => !route.enabled).length;
|
|
476
|
+
const systemCount = filteredRoutes.filter((route) => getRouteOwner(route) === 'system').length;
|
|
477
|
+
const userCount = filteredRoutes.filter((route) => getRouteOwner(route) === 'operator').length;
|
|
478
478
|
|
|
479
479
|
const statsTiles: IStatsTile[] = [
|
|
480
480
|
{
|
|
481
481
|
id: 'totalRoutes',
|
|
482
|
-
title: '
|
|
482
|
+
title: 'Standard Routes',
|
|
483
483
|
type: 'number',
|
|
484
|
-
value:
|
|
484
|
+
value: filteredRoutes.length,
|
|
485
485
|
icon: 'lucide:route',
|
|
486
|
-
description: '
|
|
486
|
+
description: 'Matching non-special routes',
|
|
487
487
|
color: '#3b82f6',
|
|
488
488
|
},
|
|
489
489
|
{
|
|
490
490
|
id: 'configRoutes',
|
|
491
491
|
title: 'System Routes',
|
|
492
492
|
type: 'number',
|
|
493
|
-
value:
|
|
493
|
+
value: systemCount,
|
|
494
494
|
icon: 'lucide:settings',
|
|
495
495
|
description: 'From config, email, and DNS',
|
|
496
496
|
color: '#8b5cf6',
|
|
497
497
|
},
|
|
498
498
|
{
|
|
499
|
-
id: '
|
|
500
|
-
title: '
|
|
499
|
+
id: 'userRoutes',
|
|
500
|
+
title: 'User Routes',
|
|
501
501
|
type: 'number',
|
|
502
|
-
value:
|
|
502
|
+
value: userCount,
|
|
503
503
|
icon: 'lucide:code',
|
|
504
|
-
description: 'Created directly by
|
|
504
|
+
description: 'Created directly by users',
|
|
505
505
|
color: '#0ea5e9',
|
|
506
506
|
},
|
|
507
507
|
{
|
|
@@ -515,20 +515,6 @@ export class OpsViewRoutes extends DeesElement {
|
|
|
515
515
|
},
|
|
516
516
|
];
|
|
517
517
|
|
|
518
|
-
const standardRoutes = mergedRoutes.filter((route) => !route.metadata?.managedRouteKind);
|
|
519
|
-
const filteredRoutes = standardRoutes.filter((route) => {
|
|
520
|
-
switch (this.ownerFilter) {
|
|
521
|
-
case 'operator':
|
|
522
|
-
return route.origin === 'api' && route.metadata?.ownerType !== 'gatewayClient';
|
|
523
|
-
case 'gatewayClient':
|
|
524
|
-
return route.metadata?.ownerType === 'gatewayClient';
|
|
525
|
-
case 'system':
|
|
526
|
-
return route.origin !== 'api' || route.metadata?.ownerType === 'system';
|
|
527
|
-
default:
|
|
528
|
-
return true;
|
|
529
|
-
}
|
|
530
|
-
});
|
|
531
|
-
|
|
532
518
|
// Map filtered routes to sz-route-list-view format
|
|
533
519
|
const szRoutes = filteredRoutes.map((mr) => {
|
|
534
520
|
const tags = [...(mr.route.tags || [])];
|
|
@@ -549,69 +535,97 @@ export class OpsViewRoutes extends DeesElement {
|
|
|
549
535
|
<dees-heading level="3">Route Management</dees-heading>
|
|
550
536
|
|
|
551
537
|
<div class="routesContainer">
|
|
552
|
-
<
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
iconName: 'lucide:refreshCw',
|
|
573
|
-
action: () => this.refreshData(),
|
|
574
|
-
},
|
|
575
|
-
]}
|
|
576
|
-
></dees-statsgrid>
|
|
577
|
-
|
|
578
|
-
<dees-appui-tabs
|
|
579
|
-
.tabs=${this.ownerTabs}
|
|
580
|
-
.selectedTab=${this.getSelectedOwnerTab()}
|
|
581
|
-
></dees-appui-tabs>
|
|
582
|
-
|
|
583
|
-
${warnings.length > 0
|
|
538
|
+
<div class="routeFilters">
|
|
539
|
+
<div class="routeFilter">
|
|
540
|
+
<dees-input-multitoggle
|
|
541
|
+
id="routeTypeFilter"
|
|
542
|
+
.label=${'Type'}
|
|
543
|
+
.options=${routeTypeOptions}
|
|
544
|
+
.value=${this.getSelectedRouteTypeOption()}
|
|
545
|
+
></dees-input-multitoggle>
|
|
546
|
+
</div>
|
|
547
|
+
<div class="routeFilter">
|
|
548
|
+
<dees-input-multitoggle
|
|
549
|
+
id="routeOwnerFilter"
|
|
550
|
+
.label=${'Owner'}
|
|
551
|
+
.options=${routeOwnerOptions}
|
|
552
|
+
.value=${this.getSelectedOwnerOption()}
|
|
553
|
+
></dees-input-multitoggle>
|
|
554
|
+
</div>
|
|
555
|
+
</div>
|
|
556
|
+
|
|
557
|
+
${this.activeSection === 'all' || this.activeSection === 'standard'
|
|
584
558
|
? html`
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
559
|
+
${this.activeSection === 'all'
|
|
560
|
+
? html`<dees-heading level="4">Standard Routes</dees-heading>`
|
|
561
|
+
: ''}
|
|
562
|
+
<dees-statsgrid
|
|
563
|
+
.tiles=${statsTiles}
|
|
564
|
+
.gridActions=${[
|
|
565
|
+
{
|
|
566
|
+
name: 'Add Route',
|
|
567
|
+
iconName: 'lucide:plus',
|
|
568
|
+
action: () => this.showCreateRouteDialog(),
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
name: 'Refresh',
|
|
572
|
+
iconName: 'lucide:refreshCw',
|
|
573
|
+
action: () => this.refreshData(),
|
|
574
|
+
},
|
|
575
|
+
]}
|
|
576
|
+
></dees-statsgrid>
|
|
577
|
+
|
|
578
|
+
${warnings.length > 0
|
|
579
|
+
? html`
|
|
580
|
+
<div class="warnings-bar">
|
|
581
|
+
${warnings.map(
|
|
582
|
+
(warning) => html`
|
|
583
|
+
<div class="warning-item">
|
|
584
|
+
<span class="warning-icon">⚠</span>
|
|
585
|
+
<span>${warning.message}</span>
|
|
586
|
+
</div>
|
|
587
|
+
`,
|
|
588
|
+
)}
|
|
589
|
+
</div>
|
|
590
|
+
`
|
|
591
|
+
: ''}
|
|
592
|
+
|
|
593
|
+
${szRoutes.length > 0
|
|
594
|
+
? html`
|
|
595
|
+
<sz-route-list-view
|
|
596
|
+
.routes=${szRoutes}
|
|
597
|
+
.showActionsFilter=${(route: { id?: string; name?: string }) =>
|
|
598
|
+
this.canEditRoute(route)}
|
|
599
|
+
@route-click=${(event: CustomEvent) => this.handleRouteClick(event)}
|
|
600
|
+
@route-edit=${(event: CustomEvent) => this.handleRouteEdit(event)}
|
|
601
|
+
@route-delete=${(event: CustomEvent) => this.handleRouteDelete(event)}
|
|
602
|
+
></sz-route-list-view>
|
|
603
|
+
`
|
|
604
|
+
: html`
|
|
605
|
+
<div class="empty-state">
|
|
606
|
+
<p>No standard routes match these filters</p>
|
|
607
|
+
<p>Choose another ownership filter or add a user route.</p>
|
|
591
608
|
</div>
|
|
592
|
-
|
|
593
|
-
)}
|
|
594
|
-
</div>
|
|
609
|
+
`}
|
|
595
610
|
`
|
|
596
611
|
: ''}
|
|
597
612
|
|
|
598
|
-
${
|
|
613
|
+
${this.activeSection === 'all' || this.activeSection === 'special'
|
|
599
614
|
? html`
|
|
600
|
-
<
|
|
601
|
-
.
|
|
602
|
-
|
|
603
|
-
@route-click=${(e: CustomEvent) => this.handleRouteClick(e)}
|
|
604
|
-
@route-edit=${(e: CustomEvent) => this.handleRouteEdit(e)}
|
|
605
|
-
@route-delete=${(e: CustomEvent) => this.handleRouteDelete(e)}
|
|
606
|
-
></sz-route-list-view>
|
|
615
|
+
<ops-view-special-forwards
|
|
616
|
+
.ownerFilter=${this.ownerFilter}
|
|
617
|
+
></ops-view-special-forwards>
|
|
607
618
|
`
|
|
608
|
-
:
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
619
|
+
: ''}
|
|
620
|
+
|
|
621
|
+
${this.activeSection === 'all' || this.activeSection === 'redirects'
|
|
622
|
+
? html`
|
|
623
|
+
<ops-view-redirects
|
|
624
|
+
.embedded=${true}
|
|
625
|
+
.ownerFilter=${this.ownerFilter}
|
|
626
|
+
></ops-view-redirects>
|
|
627
|
+
`
|
|
628
|
+
: ''}
|
|
615
629
|
</div>
|
|
616
630
|
`;
|
|
617
631
|
}
|
|
@@ -1107,28 +1121,52 @@ export class OpsViewRoutes extends DeesElement {
|
|
|
1107
1121
|
appstate.routeManagementStatePart.dispatchAction(appstate.fetchMergedRoutesAction, null);
|
|
1108
1122
|
}
|
|
1109
1123
|
|
|
1110
|
-
private
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1124
|
+
private getSelectedRouteTypeOption(): string {
|
|
1125
|
+
switch (this.activeSection) {
|
|
1126
|
+
case 'all':
|
|
1127
|
+
return 'All';
|
|
1128
|
+
case 'redirects':
|
|
1129
|
+
return 'Redirect';
|
|
1130
|
+
case 'special':
|
|
1131
|
+
return 'Special';
|
|
1132
|
+
default:
|
|
1133
|
+
return 'Standard';
|
|
1134
|
+
}
|
|
1117
1135
|
}
|
|
1118
1136
|
|
|
1119
|
-
private
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1137
|
+
private getSelectedOwnerOption(): string {
|
|
1138
|
+
switch (this.ownerFilter) {
|
|
1139
|
+
case 'operator':
|
|
1140
|
+
return 'User';
|
|
1141
|
+
case 'gatewayClient':
|
|
1142
|
+
return 'Gateway Client';
|
|
1143
|
+
case 'system':
|
|
1144
|
+
return 'System';
|
|
1145
|
+
default:
|
|
1146
|
+
return 'All';
|
|
1147
|
+
}
|
|
1128
1148
|
}
|
|
1129
1149
|
|
|
1130
|
-
private
|
|
1131
|
-
|
|
1150
|
+
private handleRouteTypeChange(toggle: DeesInputMultitoggle): void {
|
|
1151
|
+
const section: TRoutesSection = toggle.selectedOption === 'All'
|
|
1152
|
+
? 'all'
|
|
1153
|
+
: toggle.selectedOption === 'Redirect'
|
|
1154
|
+
? 'redirects'
|
|
1155
|
+
: toggle.selectedOption === 'Special'
|
|
1156
|
+
? 'special'
|
|
1157
|
+
: 'standard';
|
|
1158
|
+
this.setRouteView(section);
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
private handleRouteOwnerChange(toggle: DeesInputMultitoggle): void {
|
|
1162
|
+
const owner: TRouteOwnerFilter = toggle.selectedOption === 'User'
|
|
1163
|
+
? 'operator'
|
|
1164
|
+
: toggle.selectedOption === 'Gateway Client'
|
|
1165
|
+
? 'gatewayClient'
|
|
1166
|
+
: toggle.selectedOption === 'System'
|
|
1167
|
+
? 'system'
|
|
1168
|
+
: 'all';
|
|
1169
|
+
this.setRouteOwnerFilter(owner);
|
|
1132
1170
|
}
|
|
1133
1171
|
|
|
1134
1172
|
private setRouteView(section: TRoutesSection): void {
|
|
@@ -1147,7 +1185,11 @@ export class OpsViewRoutes extends DeesElement {
|
|
|
1147
1185
|
const params = new URL(window.location.href).searchParams;
|
|
1148
1186
|
const tabParam = params.get('tab');
|
|
1149
1187
|
const ownerParam = params.get('owner');
|
|
1150
|
-
const section: TRoutesSection =
|
|
1188
|
+
const section: TRoutesSection = (
|
|
1189
|
+
tabParam === 'all'
|
|
1190
|
+
|| tabParam === 'special'
|
|
1191
|
+
|| tabParam === 'redirects'
|
|
1192
|
+
)
|
|
1151
1193
|
? tabParam
|
|
1152
1194
|
: 'standard';
|
|
1153
1195
|
const owner: TRouteOwnerFilter = (
|
|
@@ -1214,12 +1256,29 @@ export class OpsViewRoutes extends DeesElement {
|
|
|
1214
1256
|
}
|
|
1215
1257
|
|
|
1216
1258
|
private isSystemManagedRoute(merged: interfaces.data.IMergedRoute): boolean {
|
|
1217
|
-
return merged
|
|
1218
|
-
|| merged.metadata?.ownerType === 'gatewayClient'
|
|
1259
|
+
return getRouteOwner(merged) !== 'operator'
|
|
1219
1260
|
|| Boolean(merged.metadata?.managedRouteKind);
|
|
1220
1261
|
}
|
|
1221
1262
|
|
|
1222
1263
|
async firstUpdated() {
|
|
1264
|
+
const typeToggle = this.shadowRoot?.querySelector(
|
|
1265
|
+
'#routeTypeFilter',
|
|
1266
|
+
) as DeesInputMultitoggle | null;
|
|
1267
|
+
const ownerToggle = this.shadowRoot?.querySelector(
|
|
1268
|
+
'#routeOwnerFilter',
|
|
1269
|
+
) as DeesInputMultitoggle | null;
|
|
1270
|
+
|
|
1271
|
+
if (typeToggle) {
|
|
1272
|
+
this.rxSubscriptions.push(typeToggle.changeSubject.subscribe((toggle) => {
|
|
1273
|
+
this.handleRouteTypeChange(toggle);
|
|
1274
|
+
}));
|
|
1275
|
+
}
|
|
1276
|
+
if (ownerToggle) {
|
|
1277
|
+
this.rxSubscriptions.push(ownerToggle.changeSubject.subscribe((toggle) => {
|
|
1278
|
+
this.handleRouteOwnerChange(toggle);
|
|
1279
|
+
}));
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1223
1282
|
await appstate.routeManagementStatePart.dispatchAction(appstate.fetchMergedRoutesAction, null);
|
|
1224
1283
|
}
|
|
1225
1284
|
}
|