@serve.zone/dcrouter 13.18.0 → 13.19.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/dist_serve/bundle.js +6 -5
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.dcrouter.d.ts +2 -0
- package/dist_ts/classes.dcrouter.js +50 -39
- package/dist_ts/config/classes.route-config-manager.d.ts +13 -5
- package/dist_ts/config/classes.route-config-manager.js +76 -36
- package/dist_ts/db/documents/classes.route.doc.d.ts +2 -0
- package/dist_ts/db/documents/classes.route.doc.js +11 -2
- package/dist_ts/email/classes.email-domain.manager.js +9 -28
- package/dist_ts/email/email-dns-records.d.ts +14 -0
- package/dist_ts/email/email-dns-records.js +34 -0
- package/dist_ts/email/index.d.ts +1 -0
- package/dist_ts/email/index.js +2 -1
- package/dist_ts/opsserver/handlers/route-management.handler.js +5 -7
- package/dist_ts_interfaces/data/route-management.d.ts +2 -0
- package/dist_ts_migrations/index.js +25 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/appstate.js +13 -4
- package/dist_ts_web/elements/network/ops-view-routes.d.ts +2 -0
- package/dist_ts_web/elements/network/ops-view-routes.js +44 -21
- package/package.json +2 -3
- package/readme.md +190 -1543
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.dcrouter.ts +61 -47
- package/ts/config/classes.route-config-manager.ts +97 -42
- package/ts/db/documents/classes.route.doc.ts +7 -0
- package/ts/email/classes.email-domain.manager.ts +8 -28
- package/ts/email/email-dns-records.ts +53 -0
- package/ts/email/index.ts +1 -0
- package/ts/opsserver/handlers/route-management.handler.ts +4 -6
- package/ts_apiclient/readme.md +69 -195
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/appstate.ts +16 -4
- package/ts_web/elements/network/ops-view-routes.ts +47 -29
- package/ts_web/readme.md +41 -242
package/ts_apiclient/readme.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @serve.zone/dcrouter-apiclient
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Typed, object-oriented API client for operating a running dcrouter instance. 🔧
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Use this package when you want a clean TypeScript client instead of manually firing TypedRequest calls. It wraps the OpsServer API in resource managers and resource classes such as routes, certificates, tokens, edges, emails, stats, logs, config, and RADIUS.
|
|
6
6
|
|
|
7
7
|
## Issue Reporting and Security
|
|
8
8
|
|
|
@@ -14,7 +14,7 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
|
|
|
14
14
|
pnpm add @serve.zone/dcrouter-apiclient
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
Or import
|
|
17
|
+
Or import through the main package:
|
|
18
18
|
|
|
19
19
|
```typescript
|
|
20
20
|
import { DcRouterApiClient } from '@serve.zone/dcrouter/apiclient';
|
|
@@ -23,239 +23,113 @@ import { DcRouterApiClient } from '@serve.zone/dcrouter/apiclient';
|
|
|
23
23
|
## Quick Start
|
|
24
24
|
|
|
25
25
|
```typescript
|
|
26
|
-
import { DcRouterApiClient } from '@serve.zone/dcrouter
|
|
26
|
+
import { DcRouterApiClient } from '@serve.zone/dcrouter-apiclient';
|
|
27
27
|
|
|
28
|
-
const client = new DcRouterApiClient({
|
|
28
|
+
const client = new DcRouterApiClient({
|
|
29
|
+
baseUrl: 'https://dcrouter.example.com',
|
|
30
|
+
});
|
|
29
31
|
|
|
30
|
-
// Authenticate
|
|
31
32
|
await client.login('admin', 'password');
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
console.log(`${routes.length} routes, ${warnings.length} warnings`);
|
|
34
|
+
const { routes } = await client.routes.list();
|
|
35
|
+
console.log(routes.map((route) => `${route.origin}:${route.name}`));
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
await client.routes.build()
|
|
38
|
+
.setName('api-gateway')
|
|
39
|
+
.setMatch({ ports: 443, domains: ['api.example.com'] })
|
|
40
|
+
.setAction({ type: 'forward', targets: [{ host: '127.0.0.1', port: 8080 }] })
|
|
41
|
+
.save();
|
|
40
42
|
```
|
|
41
43
|
|
|
42
|
-
##
|
|
44
|
+
## Authentication Modes
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
| Mode | How it works |
|
|
47
|
+
| --- | --- |
|
|
48
|
+
| Admin login | Call `login(username, password)` and the client stores the returned identity for later requests |
|
|
49
|
+
| API token | Pass `apiToken` into the constructor for token-based automation |
|
|
45
50
|
|
|
46
51
|
```typescript
|
|
47
|
-
// Login with credentials — identity is stored and auto-injected into all subsequent requests
|
|
48
|
-
const identity = await client.login('admin', 'password');
|
|
49
|
-
|
|
50
|
-
// Verify current session
|
|
51
|
-
const { valid } = await client.verifyIdentity();
|
|
52
|
-
|
|
53
|
-
// Logout
|
|
54
|
-
await client.logout();
|
|
55
|
-
|
|
56
|
-
// Or use an API token for programmatic access (route management only)
|
|
57
52
|
const client = new DcRouterApiClient({
|
|
58
53
|
baseUrl: 'https://dcrouter.example.com',
|
|
59
54
|
apiToken: 'dcr_your_token_here',
|
|
60
55
|
});
|
|
61
56
|
```
|
|
62
57
|
|
|
63
|
-
|
|
58
|
+
## Main Managers
|
|
64
59
|
|
|
65
|
-
|
|
60
|
+
| Manager | Purpose |
|
|
61
|
+
| --- | --- |
|
|
62
|
+
| `client.routes` | List routes and create API-managed routes |
|
|
63
|
+
| `client.certificates` | Inspect and operate on certificate records |
|
|
64
|
+
| `client.apiTokens` | Create, list, toggle, roll, revoke API tokens |
|
|
65
|
+
| `client.remoteIngress` | Manage registered remote ingress edges |
|
|
66
|
+
| `client.stats` | Read operational metrics and health data |
|
|
67
|
+
| `client.config` | Read current configuration view |
|
|
68
|
+
| `client.logs` | Read recent logs or stream them |
|
|
69
|
+
| `client.emails` | List emails and trigger resend flows |
|
|
70
|
+
| `client.radius` | Operate on RADIUS clients, VLANs, sessions, and accounting |
|
|
66
71
|
|
|
67
|
-
|
|
68
|
-
// List all routes (hardcoded + programmatic)
|
|
69
|
-
const { routes, warnings } = await client.routes.list();
|
|
72
|
+
## Route Behavior
|
|
70
73
|
|
|
71
|
-
|
|
72
|
-
const route = routes[0];
|
|
73
|
-
console.log(route.name, route.source, route.enabled);
|
|
74
|
+
Routes are returned as `Route` instances with:
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
- `id`
|
|
77
|
+
- `name`
|
|
78
|
+
- `enabled`
|
|
79
|
+
- `origin`
|
|
79
80
|
|
|
80
|
-
|
|
81
|
-
const hardcodedRoute = routes.find(r => r.source === 'hardcoded');
|
|
82
|
-
await hardcodedRoute.setOverride(false);
|
|
83
|
-
await hardcodedRoute.removeOverride();
|
|
84
|
-
```
|
|
81
|
+
Important behavior:
|
|
85
82
|
|
|
86
|
-
|
|
83
|
+
- API routes can be created, updated, deleted, and toggled.
|
|
84
|
+
- System routes can be listed and toggled, but not edited or deleted.
|
|
85
|
+
- A system route is any route whose `origin !== 'api'`.
|
|
87
86
|
|
|
88
87
|
```typescript
|
|
89
|
-
const
|
|
90
|
-
.setName('api-gateway')
|
|
91
|
-
.setMatch({ ports: 443, domains: ['api.example.com'] })
|
|
92
|
-
.setAction({ type: 'forward', targets: [{ host: 'backend', port: 8080 }] })
|
|
93
|
-
.setTls({ mode: 'terminate', certificate: 'auto' })
|
|
94
|
-
.setEnabled(true)
|
|
95
|
-
.save();
|
|
88
|
+
const { routes } = await client.routes.list();
|
|
96
89
|
|
|
97
|
-
|
|
98
|
-
|
|
90
|
+
for (const route of routes) {
|
|
91
|
+
if (route.origin !== 'api') {
|
|
92
|
+
await route.toggle(false);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
99
95
|
```
|
|
100
96
|
|
|
101
|
-
|
|
97
|
+
## Builder Example
|
|
102
98
|
|
|
103
99
|
```typescript
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
.
|
|
111
|
-
|
|
112
|
-
|
|
100
|
+
const route = await client.routes.build()
|
|
101
|
+
.setName('internal-app')
|
|
102
|
+
.setMatch({
|
|
103
|
+
ports: 80,
|
|
104
|
+
domains: ['internal.example.com'],
|
|
105
|
+
})
|
|
106
|
+
.setAction({
|
|
107
|
+
type: 'forward',
|
|
108
|
+
targets: [{ host: '127.0.0.1', port: 3000 }],
|
|
109
|
+
})
|
|
110
|
+
.setEnabled(true)
|
|
113
111
|
.save();
|
|
114
112
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
// Manage tokens
|
|
118
|
-
await token.toggle(false); // Disable
|
|
119
|
-
const newValue = await token.roll(); // Regenerate secret
|
|
120
|
-
await token.revoke(); // Delete
|
|
113
|
+
await route.toggle(false);
|
|
121
114
|
```
|
|
122
115
|
|
|
123
|
-
|
|
116
|
+
## Example: Certificates and Stats
|
|
124
117
|
|
|
125
118
|
```typescript
|
|
126
119
|
const { certificates, summary } = await client.certificates.list();
|
|
127
|
-
console.log(
|
|
128
|
-
|
|
129
|
-
// Operate on individual certificates
|
|
130
|
-
const cert = certificates[0];
|
|
131
|
-
await cert.reprovision();
|
|
132
|
-
const exported = await cert.export();
|
|
133
|
-
await cert.delete();
|
|
134
|
-
|
|
135
|
-
// Import a certificate
|
|
136
|
-
await client.certificates.import({
|
|
137
|
-
id: 'cert-id',
|
|
138
|
-
domainName: 'example.com',
|
|
139
|
-
created: Date.now(),
|
|
140
|
-
validUntil: Date.now() + 90 * 24 * 3600 * 1000,
|
|
141
|
-
privateKey: '...',
|
|
142
|
-
publicKey: '...',
|
|
143
|
-
csr: '...',
|
|
144
|
-
});
|
|
145
|
-
```
|
|
120
|
+
console.log(summary.valid, summary.failed);
|
|
146
121
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
```typescript
|
|
150
|
-
// List edges and their statuses
|
|
151
|
-
const edges = await client.remoteIngress.list();
|
|
152
|
-
const statuses = await client.remoteIngress.getStatuses();
|
|
153
|
-
|
|
154
|
-
// Create with builder
|
|
155
|
-
const edge = await client.remoteIngress.build()
|
|
156
|
-
.setName('edge-nyc-01')
|
|
157
|
-
.setListenPorts([80, 443])
|
|
158
|
-
.setAutoDerivePorts(true)
|
|
159
|
-
.setTags(['us-east'])
|
|
160
|
-
.save();
|
|
161
|
-
|
|
162
|
-
// Manage an edge
|
|
163
|
-
await edge.update({ name: 'edge-nyc-02' });
|
|
164
|
-
const newSecret = await edge.regenerateSecret();
|
|
165
|
-
const token = await edge.getConnectionToken();
|
|
166
|
-
await edge.delete();
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
### 📊 Statistics (Read-Only)
|
|
170
|
-
|
|
171
|
-
```typescript
|
|
172
|
-
const serverStats = await client.stats.getServer({ timeRange: '24h', includeHistory: true });
|
|
173
|
-
const emailStats = await client.stats.getEmail({ domain: 'example.com' });
|
|
174
|
-
const dnsStats = await client.stats.getDns();
|
|
175
|
-
const security = await client.stats.getSecurity({ includeDetails: true });
|
|
176
|
-
const connections = await client.stats.getConnections({ protocol: 'https' });
|
|
177
|
-
const queues = await client.stats.getQueues();
|
|
178
|
-
const health = await client.stats.getHealth(true);
|
|
179
|
-
const network = await client.stats.getNetwork();
|
|
180
|
-
const combined = await client.stats.getCombined({ server: true, email: true });
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
### ⚙️ Configuration & Logs
|
|
184
|
-
|
|
185
|
-
```typescript
|
|
186
|
-
// Read-only configuration
|
|
187
|
-
const config = await client.config.get();
|
|
188
|
-
const emailSection = await client.config.get('email');
|
|
189
|
-
|
|
190
|
-
// Logs
|
|
191
|
-
const { logs, total, hasMore } = await client.logs.getRecent({
|
|
192
|
-
level: 'error',
|
|
193
|
-
category: 'smtp',
|
|
194
|
-
limit: 50,
|
|
195
|
-
});
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
### 📧 Email Operations
|
|
199
|
-
|
|
200
|
-
```typescript
|
|
201
|
-
const emails = await client.emails.list();
|
|
202
|
-
const email = emails[0];
|
|
203
|
-
const detail = await email.getDetail();
|
|
204
|
-
await email.resend();
|
|
205
|
-
|
|
206
|
-
// Or use the manager directly
|
|
207
|
-
const detail2 = await client.emails.getDetail('email-id');
|
|
208
|
-
await client.emails.resend('email-id');
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
### 📡 RADIUS
|
|
212
|
-
|
|
213
|
-
```typescript
|
|
214
|
-
// Client management
|
|
215
|
-
const clients = await client.radius.clients.list();
|
|
216
|
-
await client.radius.clients.set({
|
|
217
|
-
name: 'switch-1',
|
|
218
|
-
ipRange: '192.168.1.0/24',
|
|
219
|
-
secret: 'shared-secret',
|
|
220
|
-
enabled: true,
|
|
221
|
-
});
|
|
222
|
-
await client.radius.clients.remove('switch-1');
|
|
223
|
-
|
|
224
|
-
// VLAN management
|
|
225
|
-
const { mappings, config: vlanConfig } = await client.radius.vlans.list();
|
|
226
|
-
await client.radius.vlans.set({ mac: 'aa:bb:cc:dd:ee:ff', vlan: 10, enabled: true });
|
|
227
|
-
const result = await client.radius.vlans.testAssignment('aa:bb:cc:dd:ee:ff');
|
|
228
|
-
await client.radius.vlans.updateConfig({ defaultVlan: 200 });
|
|
229
|
-
|
|
230
|
-
// Sessions
|
|
231
|
-
const { sessions } = await client.radius.sessions.list({ vlanId: 10 });
|
|
232
|
-
await client.radius.sessions.disconnect('session-id', 'Admin disconnect');
|
|
233
|
-
|
|
234
|
-
// Statistics & Accounting
|
|
235
|
-
const stats = await client.radius.getStatistics();
|
|
236
|
-
const summary = await client.radius.getAccountingSummary(startTime, endTime);
|
|
122
|
+
const health = await client.stats.getHealth();
|
|
123
|
+
const recentLogs = await client.logs.getRecent({ level: 'error', limit: 20 });
|
|
237
124
|
```
|
|
238
125
|
|
|
239
|
-
##
|
|
240
|
-
|
|
241
|
-
| Manager | Methods |
|
|
242
|
-
|---------|---------|
|
|
243
|
-
| `client.login()` / `logout()` / `verifyIdentity()` | Authentication |
|
|
244
|
-
| `client.routes` | `list()`, `create()`, `build()` → Route: `update()`, `delete()`, `toggle()`, `setOverride()`, `removeOverride()` |
|
|
245
|
-
| `client.certificates` | `list()`, `import()` → Certificate: `reprovision()`, `delete()`, `export()` |
|
|
246
|
-
| `client.apiTokens` | `list()`, `create()`, `build()` → ApiToken: `revoke()`, `roll()`, `toggle()` |
|
|
247
|
-
| `client.remoteIngress` | `list()`, `getStatuses()`, `create()`, `build()` → RemoteIngress: `update()`, `delete()`, `regenerateSecret()`, `getConnectionToken()` |
|
|
248
|
-
| `client.stats` | `getServer()`, `getEmail()`, `getDns()`, `getRateLimits()`, `getSecurity()`, `getConnections()`, `getQueues()`, `getHealth()`, `getNetwork()`, `getCombined()` |
|
|
249
|
-
| `client.config` | `get(section?)` |
|
|
250
|
-
| `client.logs` | `getRecent()`, `getStream()` |
|
|
251
|
-
| `client.emails` | `list()`, `getDetail()`, `resend()` → Email: `getDetail()`, `resend()` |
|
|
252
|
-
| `client.radius` | `.clients.list/set/remove()`, `.vlans.list/set/remove/updateConfig/testAssignment()`, `.sessions.list/disconnect()`, `getStatistics()`, `getAccountingSummary()` |
|
|
253
|
-
|
|
254
|
-
## Architecture
|
|
126
|
+
## What This Package Does Not Do
|
|
255
127
|
|
|
256
|
-
|
|
128
|
+
- It does not start dcrouter.
|
|
129
|
+
- It does not embed the dashboard.
|
|
130
|
+
- It does not replace the request interfaces package if you only need raw types.
|
|
257
131
|
|
|
258
|
-
|
|
132
|
+
Use `@serve.zone/dcrouter` to run the server, `@serve.zone/dcrouter-web` for the dashboard bundle/components, and `@serve.zone/dcrouter-interfaces` for raw API contracts.
|
|
259
133
|
|
|
260
134
|
## License and Legal Information
|
|
261
135
|
|
package/ts_web/appstate.ts
CHANGED
|
@@ -2150,7 +2150,7 @@ export const updateRouteAction = routeManagementStatePart.createAction<{
|
|
|
2150
2150
|
interfaces.requests.IReq_UpdateRoute
|
|
2151
2151
|
>('/typedrequest', 'updateRoute');
|
|
2152
2152
|
|
|
2153
|
-
await request.fire({
|
|
2153
|
+
const response = await request.fire({
|
|
2154
2154
|
identity: context.identity!,
|
|
2155
2155
|
id: dataArg.id,
|
|
2156
2156
|
route: dataArg.route,
|
|
@@ -2158,6 +2158,10 @@ export const updateRouteAction = routeManagementStatePart.createAction<{
|
|
|
2158
2158
|
metadata: dataArg.metadata,
|
|
2159
2159
|
});
|
|
2160
2160
|
|
|
2161
|
+
if (!response.success) {
|
|
2162
|
+
throw new Error(response.message || 'Failed to update route');
|
|
2163
|
+
}
|
|
2164
|
+
|
|
2161
2165
|
return await actionContext!.dispatch(fetchMergedRoutesAction, null);
|
|
2162
2166
|
} catch (error: unknown) {
|
|
2163
2167
|
return {
|
|
@@ -2177,11 +2181,15 @@ export const deleteRouteAction = routeManagementStatePart.createAction<string>(
|
|
|
2177
2181
|
interfaces.requests.IReq_DeleteRoute
|
|
2178
2182
|
>('/typedrequest', 'deleteRoute');
|
|
2179
2183
|
|
|
2180
|
-
await request.fire({
|
|
2184
|
+
const response = await request.fire({
|
|
2181
2185
|
identity: context.identity!,
|
|
2182
2186
|
id: routeId,
|
|
2183
2187
|
});
|
|
2184
2188
|
|
|
2189
|
+
if (!response.success) {
|
|
2190
|
+
throw new Error(response.message || 'Failed to delete route');
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2185
2193
|
return await actionContext!.dispatch(fetchMergedRoutesAction, null);
|
|
2186
2194
|
} catch (error: unknown) {
|
|
2187
2195
|
return {
|
|
@@ -2204,12 +2212,16 @@ export const toggleRouteAction = routeManagementStatePart.createAction<{
|
|
|
2204
2212
|
interfaces.requests.IReq_ToggleRoute
|
|
2205
2213
|
>('/typedrequest', 'toggleRoute');
|
|
2206
2214
|
|
|
2207
|
-
await request.fire({
|
|
2215
|
+
const response = await request.fire({
|
|
2208
2216
|
identity: context.identity!,
|
|
2209
2217
|
id: dataArg.id,
|
|
2210
2218
|
enabled: dataArg.enabled,
|
|
2211
2219
|
});
|
|
2212
2220
|
|
|
2221
|
+
if (!response.success) {
|
|
2222
|
+
throw new Error(response.message || 'Failed to toggle route');
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2213
2225
|
return await actionContext!.dispatch(fetchMergedRoutesAction, null);
|
|
2214
2226
|
} catch (error: unknown) {
|
|
2215
2227
|
return {
|
|
@@ -2765,4 +2777,4 @@ startAutoRefresh();
|
|
|
2765
2777
|
// Connect TypedSocket if already logged in (e.g., persistent session)
|
|
2766
2778
|
if (loginStatePart.getState()!.isLoggedIn) {
|
|
2767
2779
|
connectSocket();
|
|
2768
|
-
}
|
|
2780
|
+
}
|
|
@@ -272,15 +272,13 @@ export class OpsViewRoutes extends DeesElement {
|
|
|
272
272
|
const clickedRoute = e.detail;
|
|
273
273
|
if (!clickedRoute) return;
|
|
274
274
|
|
|
275
|
-
|
|
276
|
-
const merged = this.routeState.mergedRoutes.find(
|
|
277
|
-
(mr) => mr.route.name === clickedRoute.name,
|
|
278
|
-
);
|
|
275
|
+
const merged = this.findMergedRoute(clickedRoute);
|
|
279
276
|
if (!merged) return;
|
|
280
277
|
|
|
281
278
|
const { DeesModal } = await import('@design.estate/dees-catalog');
|
|
282
279
|
|
|
283
280
|
const meta = merged.metadata;
|
|
281
|
+
const isSystemManaged = this.isSystemManagedRoute(merged);
|
|
284
282
|
await DeesModal.createAndShow({
|
|
285
283
|
heading: `Route: ${merged.route.name}`,
|
|
286
284
|
content: html`
|
|
@@ -288,6 +286,7 @@ export class OpsViewRoutes extends DeesElement {
|
|
|
288
286
|
<p>Origin: <strong style="color: #0af;">${merged.origin}</strong></p>
|
|
289
287
|
<p>Status: <strong>${merged.enabled ? 'Enabled' : 'Disabled'}</strong></p>
|
|
290
288
|
<p>ID: <code style="color: #888;">${merged.id}</code></p>
|
|
289
|
+
${isSystemManaged ? html`<p>This route is system-managed. Change its source config to modify it directly.</p>` : ''}
|
|
291
290
|
${meta?.sourceProfileName ? html`<p>Source Profile: <strong style="color: #a78bfa;">${meta.sourceProfileName}</strong></p>` : ''}
|
|
292
291
|
${meta?.networkTargetName ? html`<p>Network Target: <strong style="color: #a78bfa;">${meta.networkTargetName}</strong></p>` : ''}
|
|
293
292
|
</div>
|
|
@@ -304,25 +303,29 @@ export class OpsViewRoutes extends DeesElement {
|
|
|
304
303
|
await modalArg.destroy();
|
|
305
304
|
},
|
|
306
305
|
},
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
306
|
+
...(!isSystemManaged
|
|
307
|
+
? [
|
|
308
|
+
{
|
|
309
|
+
name: 'Edit',
|
|
310
|
+
iconName: 'lucide:pencil',
|
|
311
|
+
action: async (modalArg: any) => {
|
|
312
|
+
await modalArg.destroy();
|
|
313
|
+
this.showEditRouteDialog(merged);
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
name: 'Delete',
|
|
318
|
+
iconName: 'lucide:trash-2',
|
|
319
|
+
action: async (modalArg: any) => {
|
|
320
|
+
await appstate.routeManagementStatePart.dispatchAction(
|
|
321
|
+
appstate.deleteRouteAction,
|
|
322
|
+
merged.id,
|
|
323
|
+
);
|
|
324
|
+
await modalArg.destroy();
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
]
|
|
328
|
+
: []),
|
|
326
329
|
{
|
|
327
330
|
name: 'Close',
|
|
328
331
|
iconName: 'lucide:x',
|
|
@@ -336,10 +339,9 @@ export class OpsViewRoutes extends DeesElement {
|
|
|
336
339
|
const clickedRoute = e.detail;
|
|
337
340
|
if (!clickedRoute) return;
|
|
338
341
|
|
|
339
|
-
const merged = this.
|
|
340
|
-
(mr) => mr.route.name === clickedRoute.name,
|
|
341
|
-
);
|
|
342
|
+
const merged = this.findMergedRoute(clickedRoute);
|
|
342
343
|
if (!merged) return;
|
|
344
|
+
if (this.isSystemManagedRoute(merged)) return;
|
|
343
345
|
|
|
344
346
|
this.showEditRouteDialog(merged);
|
|
345
347
|
}
|
|
@@ -348,10 +350,9 @@ export class OpsViewRoutes extends DeesElement {
|
|
|
348
350
|
const clickedRoute = e.detail;
|
|
349
351
|
if (!clickedRoute) return;
|
|
350
352
|
|
|
351
|
-
const merged = this.
|
|
352
|
-
(mr) => mr.route.name === clickedRoute.name,
|
|
353
|
-
);
|
|
353
|
+
const merged = this.findMergedRoute(clickedRoute);
|
|
354
354
|
if (!merged) return;
|
|
355
|
+
if (this.isSystemManagedRoute(merged)) return;
|
|
355
356
|
|
|
356
357
|
const { DeesModal } = await import('@design.estate/dees-catalog');
|
|
357
358
|
await DeesModal.createAndShow({
|
|
@@ -675,6 +676,23 @@ export class OpsViewRoutes extends DeesElement {
|
|
|
675
676
|
appstate.routeManagementStatePart.dispatchAction(appstate.fetchMergedRoutesAction, null);
|
|
676
677
|
}
|
|
677
678
|
|
|
679
|
+
private findMergedRoute(clickedRoute: { id?: string; name?: string }): interfaces.data.IMergedRoute | undefined {
|
|
680
|
+
if (clickedRoute.id) {
|
|
681
|
+
const routeById = this.routeState.mergedRoutes.find((mr) => mr.id === clickedRoute.id);
|
|
682
|
+
if (routeById) return routeById;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
if (clickedRoute.name) {
|
|
686
|
+
return this.routeState.mergedRoutes.find((mr) => mr.route.name === clickedRoute.name);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
return undefined;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
private isSystemManagedRoute(merged: interfaces.data.IMergedRoute): boolean {
|
|
693
|
+
return merged.origin !== 'api';
|
|
694
|
+
}
|
|
695
|
+
|
|
678
696
|
async firstUpdated() {
|
|
679
697
|
await appstate.routeManagementStatePart.dispatchAction(appstate.fetchMergedRoutesAction, null);
|
|
680
698
|
|