@serve.zone/dcrouter 12.3.0 → 12.5.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 +1157 -1030
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/appstate.d.ts +6 -0
- package/dist_ts_web/appstate.js +22 -1
- package/dist_ts_web/elements/ops-view-network.js +5 -15
- package/dist_ts_web/elements/ops-view-overview.js +5 -1
- package/dist_ts_web/elements/ops-view-routes.d.ts +3 -0
- package/dist_ts_web/elements/ops-view-routes.js +153 -6
- package/package.json +2 -2
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/appstate.ts +31 -0
- package/ts_web/elements/ops-view-network.ts +4 -14
- package/ts_web/elements/ops-view-overview.ts +4 -0
- package/ts_web/elements/ops-view-routes.ts +170 -5
|
@@ -204,7 +204,10 @@ export class OpsViewRoutes extends DeesElement {
|
|
|
204
204
|
? html`
|
|
205
205
|
<sz-route-list-view
|
|
206
206
|
.routes=${szRoutes}
|
|
207
|
+
.showActionsFilter=${(route: any) => route.tags?.includes('programmatic') ?? false}
|
|
207
208
|
@route-click=${(e: CustomEvent) => this.handleRouteClick(e)}
|
|
209
|
+
@route-edit=${(e: CustomEvent) => this.handleRouteEdit(e)}
|
|
210
|
+
@route-delete=${(e: CustomEvent) => this.handleRouteDelete(e)}
|
|
208
211
|
></sz-route-list-view>
|
|
209
212
|
`
|
|
210
213
|
: html`
|
|
@@ -337,6 +340,165 @@ export class OpsViewRoutes extends DeesElement {
|
|
|
337
340
|
}
|
|
338
341
|
}
|
|
339
342
|
|
|
343
|
+
private async handleRouteEdit(e: CustomEvent) {
|
|
344
|
+
const clickedRoute = e.detail;
|
|
345
|
+
if (!clickedRoute) return;
|
|
346
|
+
|
|
347
|
+
const merged = this.routeState.mergedRoutes.find(
|
|
348
|
+
(mr) => mr.route.name === clickedRoute.name,
|
|
349
|
+
);
|
|
350
|
+
if (!merged || !merged.storedRouteId) return;
|
|
351
|
+
|
|
352
|
+
this.showEditRouteDialog(merged);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
private async handleRouteDelete(e: CustomEvent) {
|
|
356
|
+
const clickedRoute = e.detail;
|
|
357
|
+
if (!clickedRoute) return;
|
|
358
|
+
|
|
359
|
+
const merged = this.routeState.mergedRoutes.find(
|
|
360
|
+
(mr) => mr.route.name === clickedRoute.name,
|
|
361
|
+
);
|
|
362
|
+
if (!merged || !merged.storedRouteId) return;
|
|
363
|
+
|
|
364
|
+
const { DeesModal } = await import('@design.estate/dees-catalog');
|
|
365
|
+
await DeesModal.createAndShow({
|
|
366
|
+
heading: `Delete Route: ${merged.route.name}`,
|
|
367
|
+
content: html`
|
|
368
|
+
<div style="color: #ccc; padding: 8px 0;">
|
|
369
|
+
<p>Are you sure you want to delete this route? This action cannot be undone.</p>
|
|
370
|
+
</div>
|
|
371
|
+
`,
|
|
372
|
+
menuOptions: [
|
|
373
|
+
{
|
|
374
|
+
name: 'Cancel',
|
|
375
|
+
iconName: 'lucide:x',
|
|
376
|
+
action: async (modalArg: any) => await modalArg.destroy(),
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
name: 'Delete',
|
|
380
|
+
iconName: 'lucide:trash-2',
|
|
381
|
+
action: async (modalArg: any) => {
|
|
382
|
+
await appstate.routeManagementStatePart.dispatchAction(
|
|
383
|
+
appstate.deleteRouteAction,
|
|
384
|
+
merged.storedRouteId!,
|
|
385
|
+
);
|
|
386
|
+
await modalArg.destroy();
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
],
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
private async showEditRouteDialog(merged: interfaces.data.IMergedRoute) {
|
|
394
|
+
const { DeesModal } = await import('@design.estate/dees-catalog');
|
|
395
|
+
const profiles = this.profilesTargetsState.profiles;
|
|
396
|
+
const targets = this.profilesTargetsState.targets;
|
|
397
|
+
|
|
398
|
+
const profileOptions = [
|
|
399
|
+
{ key: '', option: '(none — inline security)' },
|
|
400
|
+
...profiles.map((p) => ({
|
|
401
|
+
key: p.id,
|
|
402
|
+
option: `${p.name}${p.description ? ' — ' + p.description : ''}`,
|
|
403
|
+
})),
|
|
404
|
+
];
|
|
405
|
+
const targetOptions = [
|
|
406
|
+
{ key: '', option: '(none — inline target)' },
|
|
407
|
+
...targets.map((t) => ({
|
|
408
|
+
key: t.id,
|
|
409
|
+
option: `${t.name} (${Array.isArray(t.host) ? t.host.join(',') : t.host}:${t.port})`,
|
|
410
|
+
})),
|
|
411
|
+
];
|
|
412
|
+
|
|
413
|
+
const route = merged.route;
|
|
414
|
+
const currentPorts = Array.isArray(route.match.ports)
|
|
415
|
+
? route.match.ports.map((p: any) => typeof p === 'number' ? String(p) : `${p.from}-${p.to}`).join(', ')
|
|
416
|
+
: String(route.match.ports);
|
|
417
|
+
const currentDomains: string[] = route.match.domains
|
|
418
|
+
? (Array.isArray(route.match.domains) ? route.match.domains : [route.match.domains])
|
|
419
|
+
: [];
|
|
420
|
+
const firstTarget = route.action.targets?.[0];
|
|
421
|
+
const currentTargetHost = firstTarget
|
|
422
|
+
? (Array.isArray(firstTarget.host) ? firstTarget.host[0] : firstTarget.host)
|
|
423
|
+
: '';
|
|
424
|
+
const currentTargetPort = firstTarget?.port != null ? String(firstTarget.port) : '';
|
|
425
|
+
|
|
426
|
+
await DeesModal.createAndShow({
|
|
427
|
+
heading: `Edit Route: ${route.name}`,
|
|
428
|
+
content: html`
|
|
429
|
+
<dees-form>
|
|
430
|
+
<dees-input-text .key=${'name'} .label=${'Route Name'} .value=${route.name || ''} .required=${true}></dees-input-text>
|
|
431
|
+
<dees-input-text .key=${'ports'} .label=${'Ports (comma-separated)'} .value=${currentPorts} .required=${true}></dees-input-text>
|
|
432
|
+
<dees-input-list .key=${'domains'} .label=${'Domains'} .placeholder=${'Add domain...'} .value=${currentDomains}></dees-input-list>
|
|
433
|
+
<dees-input-text .key=${'priority'} .label=${'Priority (higher = matched first)'} .value=${route.priority != null ? String(route.priority) : ''}></dees-input-text>
|
|
434
|
+
<dees-input-dropdown .key=${'securityProfileRef'} .label=${'Security Profile'} .options=${profileOptions} .selectedKey=${merged.metadata?.securityProfileRef || ''}></dees-input-dropdown>
|
|
435
|
+
<dees-input-dropdown .key=${'networkTargetRef'} .label=${'Network Target'} .options=${targetOptions} .selectedKey=${merged.metadata?.networkTargetRef || ''}></dees-input-dropdown>
|
|
436
|
+
<dees-input-text .key=${'targetHost'} .label=${'Target Host (if no target selected)'} .value=${currentTargetHost}></dees-input-text>
|
|
437
|
+
<dees-input-text .key=${'targetPort'} .label=${'Target Port (if no target selected)'} .value=${currentTargetPort}></dees-input-text>
|
|
438
|
+
</dees-form>
|
|
439
|
+
`,
|
|
440
|
+
menuOptions: [
|
|
441
|
+
{
|
|
442
|
+
name: 'Cancel',
|
|
443
|
+
iconName: 'lucide:x',
|
|
444
|
+
action: async (modalArg: any) => await modalArg.destroy(),
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
name: 'Save',
|
|
448
|
+
iconName: 'lucide:check',
|
|
449
|
+
action: async (modalArg: any) => {
|
|
450
|
+
const form = modalArg.shadowRoot?.querySelector('.content')?.querySelector('dees-form');
|
|
451
|
+
if (!form) return;
|
|
452
|
+
const formData = await form.collectFormData();
|
|
453
|
+
if (!formData.name || !formData.ports) return;
|
|
454
|
+
|
|
455
|
+
const ports = formData.ports.split(',').map((p: string) => parseInt(p.trim(), 10)).filter((p: number) => !isNaN(p));
|
|
456
|
+
const domains: string[] = Array.isArray(formData.domains)
|
|
457
|
+
? formData.domains.filter(Boolean)
|
|
458
|
+
: [];
|
|
459
|
+
const priority = formData.priority ? parseInt(formData.priority, 10) : undefined;
|
|
460
|
+
|
|
461
|
+
const updatedRoute: any = {
|
|
462
|
+
name: formData.name,
|
|
463
|
+
match: {
|
|
464
|
+
ports,
|
|
465
|
+
...(domains.length > 0 ? { domains } : {}),
|
|
466
|
+
},
|
|
467
|
+
action: {
|
|
468
|
+
type: 'forward',
|
|
469
|
+
targets: [
|
|
470
|
+
{
|
|
471
|
+
host: formData.targetHost || 'localhost',
|
|
472
|
+
port: parseInt(formData.targetPort, 10) || 443,
|
|
473
|
+
},
|
|
474
|
+
],
|
|
475
|
+
},
|
|
476
|
+
...(priority != null && !isNaN(priority) ? { priority } : {}),
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
const metadata: any = {};
|
|
480
|
+
if (formData.securityProfileRef) {
|
|
481
|
+
metadata.securityProfileRef = formData.securityProfileRef;
|
|
482
|
+
}
|
|
483
|
+
if (formData.networkTargetRef) {
|
|
484
|
+
metadata.networkTargetRef = formData.networkTargetRef;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
await appstate.routeManagementStatePart.dispatchAction(
|
|
488
|
+
appstate.updateRouteAction,
|
|
489
|
+
{
|
|
490
|
+
id: merged.storedRouteId!,
|
|
491
|
+
route: updatedRoute,
|
|
492
|
+
metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
|
|
493
|
+
},
|
|
494
|
+
);
|
|
495
|
+
await modalArg.destroy();
|
|
496
|
+
},
|
|
497
|
+
},
|
|
498
|
+
],
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
|
|
340
502
|
private async showCreateRouteDialog() {
|
|
341
503
|
const { DeesModal } = await import('@design.estate/dees-catalog');
|
|
342
504
|
const profiles = this.profilesTargetsState.profiles;
|
|
@@ -364,7 +526,8 @@ export class OpsViewRoutes extends DeesElement {
|
|
|
364
526
|
<dees-form>
|
|
365
527
|
<dees-input-text .key=${'name'} .label=${'Route Name'} .required=${true}></dees-input-text>
|
|
366
528
|
<dees-input-text .key=${'ports'} .label=${'Ports (comma-separated)'} .required=${true}></dees-input-text>
|
|
367
|
-
<dees-input-
|
|
529
|
+
<dees-input-list .key=${'domains'} .label=${'Domains'} .placeholder=${'Add domain...'}></dees-input-list>
|
|
530
|
+
<dees-input-text .key=${'priority'} .label=${'Priority (higher = matched first)'}></dees-input-text>
|
|
368
531
|
<dees-input-dropdown .key=${'securityProfileRef'} .label=${'Security Profile'} .options=${profileOptions} .selectedKey=${''}></dees-input-dropdown>
|
|
369
532
|
<dees-input-dropdown .key=${'networkTargetRef'} .label=${'Network Target'} .options=${targetOptions} .selectedKey=${''}></dees-input-dropdown>
|
|
370
533
|
<dees-input-text .key=${'targetHost'} .label=${'Target Host (if no target selected)'} .value=${'localhost'}></dees-input-text>
|
|
@@ -387,15 +550,16 @@ export class OpsViewRoutes extends DeesElement {
|
|
|
387
550
|
if (!formData.name || !formData.ports) return;
|
|
388
551
|
|
|
389
552
|
const ports = formData.ports.split(',').map((p: string) => parseInt(p.trim(), 10)).filter((p: number) => !isNaN(p));
|
|
390
|
-
const domains = formData.domains
|
|
391
|
-
? formData.domains.
|
|
392
|
-
:
|
|
553
|
+
const domains: string[] = Array.isArray(formData.domains)
|
|
554
|
+
? formData.domains.filter(Boolean)
|
|
555
|
+
: [];
|
|
556
|
+
const priority = formData.priority ? parseInt(formData.priority, 10) : undefined;
|
|
393
557
|
|
|
394
558
|
const route: any = {
|
|
395
559
|
name: formData.name,
|
|
396
560
|
match: {
|
|
397
561
|
ports,
|
|
398
|
-
...(domains
|
|
562
|
+
...(domains.length > 0 ? { domains } : {}),
|
|
399
563
|
},
|
|
400
564
|
action: {
|
|
401
565
|
type: 'forward',
|
|
@@ -406,6 +570,7 @@ export class OpsViewRoutes extends DeesElement {
|
|
|
406
570
|
},
|
|
407
571
|
],
|
|
408
572
|
},
|
|
573
|
+
...(priority != null && !isNaN(priority) ? { priority } : {}),
|
|
409
574
|
};
|
|
410
575
|
|
|
411
576
|
// Build metadata if profile/target selected
|