@serve.zone/dcrouter 13.1.3 → 13.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.
Files changed (69) hide show
  1. package/dist_serve/bundle.js +1202 -1133
  2. package/dist_ts/00_commitinfo_data.js +1 -1
  3. package/dist_ts_web/00_commitinfo_data.js +1 -1
  4. package/dist_ts_web/appstate.d.ts +1 -0
  5. package/dist_ts_web/appstate.js +9 -22
  6. package/dist_ts_web/elements/index.d.ts +2 -6
  7. package/dist_ts_web/elements/index.js +3 -7
  8. package/dist_ts_web/elements/network/index.d.ts +6 -0
  9. package/dist_ts_web/elements/network/index.js +7 -0
  10. package/dist_ts_web/elements/{ops-view-network.d.ts → network/ops-view-network-activity.d.ts} +3 -3
  11. package/dist_ts_web/elements/{ops-view-network.js → network/ops-view-network-activity.js} +20 -30
  12. package/dist_ts_web/elements/network/ops-view-network.d.ts +24 -0
  13. package/dist_ts_web/elements/network/ops-view-network.js +151 -0
  14. package/dist_ts_web/elements/{ops-view-networktargets.d.ts → network/ops-view-networktargets.d.ts} +1 -1
  15. package/dist_ts_web/elements/{ops-view-networktargets.js → network/ops-view-networktargets.js} +6 -6
  16. package/dist_ts_web/elements/{ops-view-routes.d.ts → network/ops-view-routes.d.ts} +1 -1
  17. package/dist_ts_web/elements/{ops-view-routes.js → network/ops-view-routes.js} +5 -6
  18. package/dist_ts_web/elements/{ops-view-sourceprofiles.d.ts → network/ops-view-sourceprofiles.d.ts} +1 -1
  19. package/dist_ts_web/elements/{ops-view-sourceprofiles.js → network/ops-view-sourceprofiles.js} +6 -6
  20. package/dist_ts_web/elements/{ops-view-targetprofiles.d.ts → network/ops-view-targetprofiles.d.ts} +2 -2
  21. package/dist_ts_web/elements/{ops-view-targetprofiles.js → network/ops-view-targetprofiles.js} +7 -7
  22. package/dist_ts_web/elements/ops-dashboard.js +4 -27
  23. package/dist_ts_web/elements/ops-view-apitokens.js +2 -1
  24. package/dist_ts_web/elements/ops-view-certificates.js +2 -1
  25. package/dist_ts_web/elements/ops-view-config.js +3 -3
  26. package/dist_ts_web/elements/ops-view-remoteingress.js +2 -1
  27. package/dist_ts_web/elements/ops-view-vpn.js +2 -1
  28. package/dist_ts_web/elements/security/index.d.ts +5 -0
  29. package/dist_ts_web/elements/security/index.js +6 -0
  30. package/dist_ts_web/elements/security/ops-view-security-authentication.d.ts +13 -0
  31. package/dist_ts_web/elements/security/ops-view-security-authentication.js +156 -0
  32. package/dist_ts_web/elements/security/ops-view-security-blocked.d.ts +15 -0
  33. package/dist_ts_web/elements/security/ops-view-security-blocked.js +152 -0
  34. package/dist_ts_web/elements/security/ops-view-security-emailsecurity.d.ts +14 -0
  35. package/dist_ts_web/elements/security/ops-view-security-emailsecurity.js +196 -0
  36. package/dist_ts_web/elements/security/ops-view-security-overview.d.ts +16 -0
  37. package/dist_ts_web/elements/security/ops-view-security-overview.js +204 -0
  38. package/dist_ts_web/elements/security/ops-view-security.d.ts +23 -0
  39. package/dist_ts_web/elements/security/ops-view-security.js +146 -0
  40. package/dist_ts_web/router.d.ts +5 -3
  41. package/dist_ts_web/router.js +69 -17
  42. package/package.json +1 -1
  43. package/ts/00_commitinfo_data.ts +1 -1
  44. package/ts_web/00_commitinfo_data.ts +1 -1
  45. package/ts_web/appstate.ts +10 -24
  46. package/ts_web/elements/index.ts +2 -6
  47. package/ts_web/elements/network/index.ts +6 -0
  48. package/ts_web/elements/{ops-view-network.ts → network/ops-view-network-activity.ts} +43 -53
  49. package/ts_web/elements/network/ops-view-network.ts +119 -0
  50. package/ts_web/elements/{ops-view-networktargets.ts → network/ops-view-networktargets.ts} +5 -5
  51. package/ts_web/elements/{ops-view-routes.ts → network/ops-view-routes.ts} +4 -5
  52. package/ts_web/elements/{ops-view-sourceprofiles.ts → network/ops-view-sourceprofiles.ts} +5 -5
  53. package/ts_web/elements/{ops-view-targetprofiles.ts → network/ops-view-targetprofiles.ts} +6 -6
  54. package/ts_web/elements/ops-dashboard.ts +3 -26
  55. package/ts_web/elements/ops-view-apitokens.ts +1 -0
  56. package/ts_web/elements/ops-view-certificates.ts +1 -0
  57. package/ts_web/elements/ops-view-config.ts +2 -2
  58. package/ts_web/elements/ops-view-remoteingress.ts +1 -0
  59. package/ts_web/elements/ops-view-vpn.ts +1 -0
  60. package/ts_web/elements/security/index.ts +5 -0
  61. package/ts_web/elements/security/ops-view-security-authentication.ts +120 -0
  62. package/ts_web/elements/security/ops-view-security-blocked.ts +117 -0
  63. package/ts_web/elements/security/ops-view-security-emailsecurity.ts +159 -0
  64. package/ts_web/elements/security/ops-view-security-overview.ts +171 -0
  65. package/ts_web/elements/security/ops-view-security.ts +114 -0
  66. package/ts_web/router.ts +75 -17
  67. package/dist_ts_web/elements/ops-view-security.d.ts +0 -24
  68. package/dist_ts_web/elements/ops-view-security.js +0 -481
  69. package/ts_web/elements/ops-view-security.ts +0 -453
@@ -0,0 +1,114 @@
1
+ import * as appstate from '../../appstate.js';
2
+ import { appRouter } from '../../router.js';
3
+ import { viewHostCss } from '../shared/css.js';
4
+
5
+ import {
6
+ DeesElement,
7
+ customElement,
8
+ html,
9
+ state,
10
+ css,
11
+ cssManager,
12
+ type TemplateResult,
13
+ } from '@design.estate/dees-element';
14
+
15
+ // Side-effect imports register the subview custom elements
16
+ import './ops-view-security-overview.js';
17
+ import './ops-view-security-blocked.js';
18
+ import './ops-view-security-authentication.js';
19
+ import './ops-view-security-emailsecurity.js';
20
+
21
+ declare global {
22
+ interface HTMLElementTagNameMap {
23
+ 'ops-view-security': OpsViewSecurity;
24
+ }
25
+ }
26
+
27
+ type TSecurityTab = 'overview' | 'blocked' | 'authentication' | 'emailsecurity';
28
+
29
+ @customElement('ops-view-security')
30
+ export class OpsViewSecurity extends DeesElement {
31
+ @state()
32
+ accessor selectedTab: TSecurityTab = 'overview';
33
+
34
+ private tabLabelMap: Record<TSecurityTab, string> = {
35
+ 'overview': 'Overview',
36
+ 'blocked': 'Blocked IPs',
37
+ 'authentication': 'Authentication',
38
+ 'emailsecurity': 'Email Security',
39
+ };
40
+
41
+ private labelToTab: Record<string, TSecurityTab> = {
42
+ 'Overview': 'overview',
43
+ 'Blocked IPs': 'blocked',
44
+ 'Authentication': 'authentication',
45
+ 'Email Security': 'emailsecurity',
46
+ };
47
+
48
+ private static isSecurityTab(s: string | null): s is TSecurityTab {
49
+ return s === 'overview' || s === 'blocked' || s === 'authentication' || s === 'emailsecurity';
50
+ }
51
+
52
+ constructor() {
53
+ super();
54
+ // Read initial subview from state (URL-driven)
55
+ const initialState = appstate.uiStatePart.getState()!;
56
+ if (OpsViewSecurity.isSecurityTab(initialState.activeSubview)) {
57
+ this.selectedTab = initialState.activeSubview;
58
+ }
59
+ // Subscribe to future changes (back/forward navigation, direct URL entry)
60
+ const sub = appstate.uiStatePart.select((s) => s.activeSubview).subscribe((sub) => {
61
+ if (OpsViewSecurity.isSecurityTab(sub) && sub !== this.selectedTab) {
62
+ this.selectedTab = sub;
63
+ }
64
+ });
65
+ this.rxSubscriptions.push(sub);
66
+ }
67
+
68
+ async firstUpdated() {
69
+ const toggle = this.shadowRoot!.querySelector('dees-input-multitoggle') as any;
70
+ if (toggle) {
71
+ const sub = toggle.changeSubject.subscribe(() => {
72
+ const tab = this.labelToTab[toggle.selectedOption];
73
+ if (tab && tab !== this.selectedTab) {
74
+ // Push URL → router updates state → subscription updates selectedTab
75
+ appRouter.navigateToView('security', tab);
76
+ }
77
+ });
78
+ this.rxSubscriptions.push(sub);
79
+ }
80
+ }
81
+
82
+ public static styles = [
83
+ cssManager.defaultStyles,
84
+ viewHostCss,
85
+ css`
86
+ dees-input-multitoggle {
87
+ margin-bottom: 24px;
88
+ }
89
+ `,
90
+ ];
91
+
92
+ public render(): TemplateResult {
93
+ return html`
94
+ <dees-heading level="2">Security</dees-heading>
95
+
96
+ <dees-input-multitoggle
97
+ .type=${'single'}
98
+ .options=${['Overview', 'Blocked IPs', 'Authentication', 'Email Security']}
99
+ .selectedOption=${this.tabLabelMap[this.selectedTab]}
100
+ ></dees-input-multitoggle>
101
+
102
+ ${this.renderTabContent()}
103
+ `;
104
+ }
105
+
106
+ private renderTabContent(): TemplateResult {
107
+ switch (this.selectedTab) {
108
+ case 'overview': return html`<ops-view-security-overview></ops-view-security-overview>`;
109
+ case 'blocked': return html`<ops-view-security-blocked></ops-view-security-blocked>`;
110
+ case 'authentication': return html`<ops-view-security-authentication></ops-view-security-authentication>`;
111
+ case 'emailsecurity': return html`<ops-view-security-emailsecurity></ops-view-security-emailsecurity>`;
112
+ }
113
+ }
114
+ }
package/ts_web/router.ts CHANGED
@@ -3,9 +3,31 @@ import * as appstate from './appstate.js';
3
3
 
4
4
  const SmartRouter = plugins.domtools.plugins.smartrouter.SmartRouter;
5
5
 
6
- export const validViews = ['overview', 'network', 'emails', 'logs', 'routes', 'apitokens', 'configuration', 'security', 'certificates', 'remoteingress', 'vpn', 'sourceprofiles', 'networktargets', 'targetprofiles'] as const;
6
+ // Flat top-level views (no subviews)
7
+ const flatViews = ['overview', 'configuration', 'emails', 'logs', 'apitokens', 'certificates', 'remoteingress', 'vpn'] as const;
8
+
9
+ // Tabbed views and their valid subviews
10
+ const subviewMap: Record<string, readonly string[]> = {
11
+ network: ['activity', 'routes', 'sourceprofiles', 'networktargets', 'targetprofiles'] as const,
12
+ security: ['overview', 'blocked', 'authentication', 'emailsecurity'] as const,
13
+ };
14
+
15
+ // Default subview when user visits the bare parent URL
16
+ const defaultSubview: Record<string, string> = {
17
+ network: 'activity',
18
+ security: 'overview',
19
+ };
20
+
21
+ export const validTopLevelViews = [...flatViews, ...Object.keys(subviewMap)] as const;
22
+ export type TValidView = typeof validTopLevelViews[number];
23
+
24
+ export function isValidView(view: string): boolean {
25
+ return (validTopLevelViews as readonly string[]).includes(view);
26
+ }
7
27
 
8
- export type TValidView = typeof validViews[number];
28
+ export function isValidSubview(view: string, subview: string): boolean {
29
+ return subviewMap[view]?.includes(subview) ?? false;
30
+ }
9
31
 
10
32
  class AppRouter {
11
33
  private router: InstanceType<typeof SmartRouter>;
@@ -25,10 +47,25 @@ class AppRouter {
25
47
  }
26
48
 
27
49
  private setupRoutes(): void {
28
- for (const view of validViews) {
50
+ // Flat views
51
+ for (const view of flatViews) {
52
+ this.router.on(`/${view}`, async () => {
53
+ this.updateViewState(view, null);
54
+ });
55
+ }
56
+
57
+ // Tabbed views
58
+ for (const view of Object.keys(subviewMap)) {
59
+ // Bare parent → redirect to default subview
29
60
  this.router.on(`/${view}`, async () => {
30
- this.updateViewState(view);
61
+ this.navigateTo(`/${view}/${defaultSubview[view]}`);
31
62
  });
63
+ // Each valid subview
64
+ for (const sub of subviewMap[view]) {
65
+ this.router.on(`/${view}/${sub}`, async () => {
66
+ this.updateViewState(view, sub);
67
+ });
68
+ }
32
69
  }
33
70
 
34
71
  // Root redirect
@@ -42,7 +79,9 @@ class AppRouter {
42
79
  if (this.suppressStateUpdate) return;
43
80
 
44
81
  const currentPath = window.location.pathname;
45
- const expectedPath = `/${uiState.activeView}`;
82
+ const expectedPath = uiState.activeSubview
83
+ ? `/${uiState.activeView}/${uiState.activeSubview}`
84
+ : `/${uiState.activeView}`;
46
85
 
47
86
  if (currentPath !== expectedPath) {
48
87
  this.suppressStateUpdate = true;
@@ -57,25 +96,38 @@ class AppRouter {
57
96
 
58
97
  if (!path || path === '/') {
59
98
  this.router.pushUrl('/overview');
60
- } else {
61
- const segments = path.split('/').filter(Boolean);
62
- const view = segments[0];
99
+ return;
100
+ }
101
+
102
+ const segments = path.split('/').filter(Boolean);
103
+ const view = segments[0];
104
+ const sub = segments[1];
63
105
 
64
- if (validViews.includes(view as TValidView)) {
65
- this.updateViewState(view as TValidView);
106
+ if (!isValidView(view)) {
107
+ this.router.pushUrl('/overview');
108
+ return;
109
+ }
110
+
111
+ if (subviewMap[view]) {
112
+ if (sub && isValidSubview(view, sub)) {
113
+ this.updateViewState(view, sub);
66
114
  } else {
67
- this.router.pushUrl('/overview');
115
+ // Bare parent or invalid sub → default subview
116
+ this.router.pushUrl(`/${view}/${defaultSubview[view]}`);
68
117
  }
118
+ } else {
119
+ this.updateViewState(view, null);
69
120
  }
70
121
  }
71
122
 
72
- private updateViewState(view: string): void {
123
+ private updateViewState(view: string, subview: string | null): void {
73
124
  this.suppressStateUpdate = true;
74
125
  const currentState = appstate.uiStatePart.getState()!;
75
- if (currentState.activeView !== view) {
126
+ if (currentState.activeView !== view || currentState.activeSubview !== subview) {
76
127
  appstate.uiStatePart.setState({
77
128
  ...currentState,
78
129
  activeView: view,
130
+ activeSubview: subview,
79
131
  } as appstate.IUiState);
80
132
  }
81
133
  this.suppressStateUpdate = false;
@@ -85,11 +137,17 @@ class AppRouter {
85
137
  this.router.pushUrl(path);
86
138
  }
87
139
 
88
- public navigateToView(view: string): void {
89
- if (validViews.includes(view as TValidView)) {
90
- this.navigateTo(`/${view}`);
91
- } else {
140
+ public navigateToView(view: string, subview?: string): void {
141
+ if (!isValidView(view)) {
92
142
  this.navigateTo('/overview');
143
+ return;
144
+ }
145
+ if (subview && isValidSubview(view, subview)) {
146
+ this.navigateTo(`/${view}/${subview}`);
147
+ } else if (subviewMap[view]) {
148
+ this.navigateTo(`/${view}/${defaultSubview[view]}`);
149
+ } else {
150
+ this.navigateTo(`/${view}`);
93
151
  }
94
152
  }
95
153
 
@@ -1,24 +0,0 @@
1
- import * as plugins from '../plugins.js';
2
- import * as appstate from '../appstate.js';
3
- import { DeesElement } from '@design.estate/dees-element';
4
- export declare class OpsViewSecurity extends DeesElement {
5
- accessor statsState: appstate.IStatsState;
6
- accessor selectedTab: 'overview' | 'blocked' | 'authentication' | 'email-security';
7
- private tabLabelMap;
8
- private labelToTab;
9
- constructor();
10
- firstUpdated(): Promise<void>;
11
- static styles: plugins.deesElement.CSSResult[];
12
- render(): plugins.deesElement.TemplateResult<1>;
13
- private renderTabContent;
14
- private renderOverview;
15
- private renderBlockedIPs;
16
- private renderAuthentication;
17
- private renderEmailSecurity;
18
- private calculateThreatLevel;
19
- private getThreatScore;
20
- private getSecurityEvents;
21
- private clearBlockedIPs;
22
- private unblockIP;
23
- private saveEmailSecuritySettings;
24
- }