fix(ops-view-routes): correct route form dropdown selection handling for security profiles and network targets
This commit is contained in:
@@ -1,5 +1,12 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2026-04-04 - 12.8.1 - fix(ops-view-routes)
|
||||||
|
correct route form dropdown selection handling for security profiles and network targets
|
||||||
|
|
||||||
|
- Update route edit and create forms to use selectedOption for dropdowns backed by the newer dees-catalog version
|
||||||
|
- Normalize submitted dropdown values to extract option keys before storing securityProfileRef and networkTargetRef
|
||||||
|
- Refresh documentation to reflect expanded stats coverage for network, RADIUS, and VPN metrics
|
||||||
|
|
||||||
## 2026-04-03 - 12.8.0 - feat(certificates)
|
## 2026-04-03 - 12.8.0 - feat(certificates)
|
||||||
add force renew option for domain certificate reprovisioning
|
add force renew option for domain certificate reprovisioning
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
"@api.global/typedserver": "^8.4.6",
|
"@api.global/typedserver": "^8.4.6",
|
||||||
"@api.global/typedsocket": "^4.1.2",
|
"@api.global/typedsocket": "^4.1.2",
|
||||||
"@apiclient.xyz/cloudflare": "^7.1.0",
|
"@apiclient.xyz/cloudflare": "^7.1.0",
|
||||||
"@design.estate/dees-catalog": "^3.52.3",
|
"@design.estate/dees-catalog": "^3.55.1",
|
||||||
"@design.estate/dees-element": "^2.2.4",
|
"@design.estate/dees-element": "^2.2.4",
|
||||||
"@push.rocks/lik": "^6.4.0",
|
"@push.rocks/lik": "^6.4.0",
|
||||||
"@push.rocks/projectinfo": "^5.1.0",
|
"@push.rocks/projectinfo": "^5.1.0",
|
||||||
|
|||||||
14
pnpm-lock.yaml
generated
14
pnpm-lock.yaml
generated
@@ -24,8 +24,8 @@ importers:
|
|||||||
specifier: ^7.1.0
|
specifier: ^7.1.0
|
||||||
version: 7.1.0
|
version: 7.1.0
|
||||||
'@design.estate/dees-catalog':
|
'@design.estate/dees-catalog':
|
||||||
specifier: ^3.52.3
|
specifier: ^3.55.1
|
||||||
version: 3.52.3(@tiptap/pm@2.27.2)
|
version: 3.55.1(@tiptap/pm@2.27.2)
|
||||||
'@design.estate/dees-element':
|
'@design.estate/dees-element':
|
||||||
specifier: ^2.2.4
|
specifier: ^2.2.4
|
||||||
version: 2.2.4
|
version: 2.2.4
|
||||||
@@ -350,8 +350,8 @@ packages:
|
|||||||
'@configvault.io/interfaces@1.0.17':
|
'@configvault.io/interfaces@1.0.17':
|
||||||
resolution: {integrity: sha512-bEcCUR2VBDJsTin8HQh8Uw/mlYl2v8A3jMIaQ+MTB9Hrqd6CZL2dL7iJdWyFl/3EIX+LDxWFR+Oq7liIq7w+1Q==}
|
resolution: {integrity: sha512-bEcCUR2VBDJsTin8HQh8Uw/mlYl2v8A3jMIaQ+MTB9Hrqd6CZL2dL7iJdWyFl/3EIX+LDxWFR+Oq7liIq7w+1Q==}
|
||||||
|
|
||||||
'@design.estate/dees-catalog@3.52.3':
|
'@design.estate/dees-catalog@3.55.1':
|
||||||
resolution: {integrity: sha512-4/vybRZQtdkpa3IOZQ/EbL6gGjIMO+430db43RRfdw+HPXird7Jl+oIXz6pDh+rGah2H2+Srb/c+eve46xAhtQ==}
|
resolution: {integrity: sha512-UXBC68Dg+L2cGJynvrXyaJATlSLnmiA5SMrE1SWVcp2H1niXqHph6KVi9+E52YSLoEmsCS23cf+XjUjoRNgZTw==}
|
||||||
|
|
||||||
'@design.estate/dees-comms@1.0.30':
|
'@design.estate/dees-comms@1.0.30':
|
||||||
resolution: {integrity: sha512-KchMlklJfKAjQiJiR0xmofXtQ27VgZtBIxcMwPE9d+h3jJRv+lPZxzBQVOM0eyM0uS44S5vJMZ11IeV4uDXSHg==}
|
resolution: {integrity: sha512-KchMlklJfKAjQiJiR0xmofXtQ27VgZtBIxcMwPE9d+h3jJRv+lPZxzBQVOM0eyM0uS44S5vJMZ11IeV4uDXSHg==}
|
||||||
@@ -4342,7 +4342,7 @@ snapshots:
|
|||||||
'@api.global/typedrequest-interfaces': 3.0.19
|
'@api.global/typedrequest-interfaces': 3.0.19
|
||||||
'@api.global/typedsocket': 4.1.2(@push.rocks/smartserve@2.0.3)
|
'@api.global/typedsocket': 4.1.2(@push.rocks/smartserve@2.0.3)
|
||||||
'@cloudflare/workers-types': 4.20260317.1
|
'@cloudflare/workers-types': 4.20260317.1
|
||||||
'@design.estate/dees-catalog': 3.52.3(@tiptap/pm@2.27.2)
|
'@design.estate/dees-catalog': 3.55.1(@tiptap/pm@2.27.2)
|
||||||
'@design.estate/dees-comms': 1.0.30
|
'@design.estate/dees-comms': 1.0.30
|
||||||
'@push.rocks/lik': 6.4.0
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
@@ -4871,7 +4871,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@api.global/typedrequest-interfaces': 3.0.19
|
'@api.global/typedrequest-interfaces': 3.0.19
|
||||||
|
|
||||||
'@design.estate/dees-catalog@3.52.3(@tiptap/pm@2.27.2)':
|
'@design.estate/dees-catalog@3.55.1(@tiptap/pm@2.27.2)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@design.estate/dees-domtools': 2.5.4
|
'@design.estate/dees-domtools': 2.5.4
|
||||||
'@design.estate/dees-element': 2.2.4
|
'@design.estate/dees-element': 2.2.4
|
||||||
@@ -6909,7 +6909,7 @@ snapshots:
|
|||||||
|
|
||||||
'@serve.zone/catalog@2.11.0(@tiptap/pm@2.27.2)':
|
'@serve.zone/catalog@2.11.0(@tiptap/pm@2.27.2)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@design.estate/dees-catalog': 3.52.3(@tiptap/pm@2.27.2)
|
'@design.estate/dees-catalog': 3.55.1(@tiptap/pm@2.27.2)
|
||||||
'@design.estate/dees-domtools': 2.5.4
|
'@design.estate/dees-domtools': 2.5.4
|
||||||
'@design.estate/dees-element': 2.2.4
|
'@design.estate/dees-element': 2.2.4
|
||||||
'@design.estate/dees-wcctools': 3.8.0
|
'@design.estate/dees-wcctools': 3.8.0
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
|
|||||||
- [Remote Ingress](#remote-ingress)
|
- [Remote Ingress](#remote-ingress)
|
||||||
- [VPN Access Control](#vpn-access-control)
|
- [VPN Access Control](#vpn-access-control)
|
||||||
- [Certificate Management](#certificate-management)
|
- [Certificate Management](#certificate-management)
|
||||||
- [Storage & Caching](#storage--caching)
|
- [Storage & Database](#storage--database)
|
||||||
- [Security Features](#security-features)
|
- [Security Features](#security-features)
|
||||||
- [OpsServer Dashboard](#opsserver-dashboard)
|
- [OpsServer Dashboard](#opsserver-dashboard)
|
||||||
- [API Client](#api-client)
|
- [API Client](#api-client)
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@serve.zone/dcrouter',
|
name: '@serve.zone/dcrouter',
|
||||||
version: '12.8.0',
|
version: '12.8.1',
|
||||||
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,6 +80,8 @@ interface IIdentity {
|
|||||||
| `IQueueStatus` | Queue name, size, processing/failed/retrying counts |
|
| `IQueueStatus` | Queue name, size, processing/failed/retrying counts |
|
||||||
| `IHealthStatus` | Healthy flag, uptime, per-service status map |
|
| `IHealthStatus` | Healthy flag, uptime, per-service status map |
|
||||||
| `INetworkMetrics` | Bandwidth, connection counts, top endpoints |
|
| `INetworkMetrics` | Bandwidth, connection counts, top endpoints |
|
||||||
|
| `IRadiusStats` | Running, uptime, auth requests/accepts/rejects, sessions, data transfer |
|
||||||
|
| `IVpnStats` | Running, subnet, registered/connected clients, WireGuard port |
|
||||||
| `ILogEntry` | Timestamp, level, category, message, metadata |
|
| `ILogEntry` | Timestamp, level, category, message, metadata |
|
||||||
|
|
||||||
#### Route Management Interfaces
|
#### Route Management Interfaces
|
||||||
@@ -135,7 +137,8 @@ TypedRequest interfaces for the OpsServer API, organized by domain:
|
|||||||
| `IReq_GetActiveConnections` | `getActiveConnections` | Active connection list |
|
| `IReq_GetActiveConnections` | `getActiveConnections` | Active connection list |
|
||||||
| `IReq_GetQueueStatus` | `getQueueStatus` | Email queue status |
|
| `IReq_GetQueueStatus` | `getQueueStatus` | Email queue status |
|
||||||
| `IReq_GetHealthStatus` | `getHealthStatus` | System health check |
|
| `IReq_GetHealthStatus` | `getHealthStatus` | System health check |
|
||||||
| `IReq_GetCombinedMetrics` | `getCombinedMetrics` | All metrics in one request |
|
| `IReq_GetNetworkStats` | `getNetworkStats` | Network throughput and connection analytics |
|
||||||
|
| `IReq_GetCombinedMetrics` | `getCombinedMetrics` | All metrics in one request (server, email, DNS, security, network, RADIUS, VPN) |
|
||||||
|
|
||||||
#### ⚙️ Configuration
|
#### ⚙️ Configuration
|
||||||
| Interface | Method | Description |
|
| Interface | Method | Description |
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@serve.zone/dcrouter',
|
name: '@serve.zone/dcrouter',
|
||||||
version: '12.8.0',
|
version: '12.8.1',
|
||||||
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -431,8 +431,8 @@ export class OpsViewRoutes extends DeesElement {
|
|||||||
<dees-input-text .key=${'ports'} .label=${'Ports (comma-separated)'} .value=${currentPorts} .required=${true}></dees-input-text>
|
<dees-input-text .key=${'ports'} .label=${'Ports (comma-separated)'} .value=${currentPorts} .required=${true}></dees-input-text>
|
||||||
<dees-input-list .key=${'domains'} .label=${'Domains'} .placeholder=${'Add domain...'} .value=${currentDomains}></dees-input-list>
|
<dees-input-list .key=${'domains'} .label=${'Domains'} .placeholder=${'Add domain...'} .value=${currentDomains}></dees-input-list>
|
||||||
<dees-input-text .key=${'priority'} .label=${'Priority (higher = matched first)'} .value=${route.priority != null ? String(route.priority) : ''}></dees-input-text>
|
<dees-input-text .key=${'priority'} .label=${'Priority (higher = matched first)'} .value=${route.priority != null ? String(route.priority) : ''}></dees-input-text>
|
||||||
<dees-input-dropdown .key=${'securityProfileRef'} .label=${'Security Profile'} .options=${profileOptions} .selectedKey=${merged.metadata?.securityProfileRef || ''}></dees-input-dropdown>
|
<dees-input-dropdown .key=${'securityProfileRef'} .label=${'Security Profile'} .options=${profileOptions} .selectedOption=${profileOptions.find((o) => o.key === (merged.metadata?.securityProfileRef || '')) || null}></dees-input-dropdown>
|
||||||
<dees-input-dropdown .key=${'networkTargetRef'} .label=${'Network Target'} .options=${targetOptions} .selectedKey=${merged.metadata?.networkTargetRef || ''}></dees-input-dropdown>
|
<dees-input-dropdown .key=${'networkTargetRef'} .label=${'Network Target'} .options=${targetOptions} .selectedOption=${targetOptions.find((o) => o.key === (merged.metadata?.networkTargetRef || '')) || null}></dees-input-dropdown>
|
||||||
<dees-input-text .key=${'targetHost'} .label=${'Target Host (if no target selected)'} .value=${currentTargetHost}></dees-input-text>
|
<dees-input-text .key=${'targetHost'} .label=${'Target Host (if no target selected)'} .value=${currentTargetHost}></dees-input-text>
|
||||||
<dees-input-text .key=${'targetPort'} .label=${'Target Port (if no target selected)'} .value=${currentTargetPort}></dees-input-text>
|
<dees-input-text .key=${'targetPort'} .label=${'Target Port (if no target selected)'} .value=${currentTargetPort}></dees-input-text>
|
||||||
</dees-form>
|
</dees-form>
|
||||||
@@ -477,11 +477,15 @@ export class OpsViewRoutes extends DeesElement {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const metadata: any = {};
|
const metadata: any = {};
|
||||||
if (formData.securityProfileRef) {
|
const profileRefValue = formData.securityProfileRef as any;
|
||||||
metadata.securityProfileRef = formData.securityProfileRef;
|
const profileKey = typeof profileRefValue === 'string' ? profileRefValue : profileRefValue?.key;
|
||||||
|
if (profileKey) {
|
||||||
|
metadata.securityProfileRef = profileKey;
|
||||||
}
|
}
|
||||||
if (formData.networkTargetRef) {
|
const targetRefValue = formData.networkTargetRef as any;
|
||||||
metadata.networkTargetRef = formData.networkTargetRef;
|
const targetKey = typeof targetRefValue === 'string' ? targetRefValue : targetRefValue?.key;
|
||||||
|
if (targetKey) {
|
||||||
|
metadata.networkTargetRef = targetKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
await appstate.routeManagementStatePart.dispatchAction(
|
await appstate.routeManagementStatePart.dispatchAction(
|
||||||
@@ -528,8 +532,8 @@ export class OpsViewRoutes extends DeesElement {
|
|||||||
<dees-input-text .key=${'ports'} .label=${'Ports (comma-separated)'} .required=${true}></dees-input-text>
|
<dees-input-text .key=${'ports'} .label=${'Ports (comma-separated)'} .required=${true}></dees-input-text>
|
||||||
<dees-input-list .key=${'domains'} .label=${'Domains'} .placeholder=${'Add domain...'}></dees-input-list>
|
<dees-input-list .key=${'domains'} .label=${'Domains'} .placeholder=${'Add domain...'}></dees-input-list>
|
||||||
<dees-input-text .key=${'priority'} .label=${'Priority (higher = matched first)'}></dees-input-text>
|
<dees-input-text .key=${'priority'} .label=${'Priority (higher = matched first)'}></dees-input-text>
|
||||||
<dees-input-dropdown .key=${'securityProfileRef'} .label=${'Security Profile'} .options=${profileOptions} .selectedKey=${''}></dees-input-dropdown>
|
<dees-input-dropdown .key=${'securityProfileRef'} .label=${'Security Profile'} .options=${profileOptions}></dees-input-dropdown>
|
||||||
<dees-input-dropdown .key=${'networkTargetRef'} .label=${'Network Target'} .options=${targetOptions} .selectedKey=${''}></dees-input-dropdown>
|
<dees-input-dropdown .key=${'networkTargetRef'} .label=${'Network Target'} .options=${targetOptions}></dees-input-dropdown>
|
||||||
<dees-input-text .key=${'targetHost'} .label=${'Target Host (if no target selected)'} .value=${'localhost'}></dees-input-text>
|
<dees-input-text .key=${'targetHost'} .label=${'Target Host (if no target selected)'} .value=${'localhost'}></dees-input-text>
|
||||||
<dees-input-text .key=${'targetPort'} .label=${'Target Port (if no target selected)'}></dees-input-text>
|
<dees-input-text .key=${'targetPort'} .label=${'Target Port (if no target selected)'}></dees-input-text>
|
||||||
</dees-form>
|
</dees-form>
|
||||||
@@ -575,11 +579,15 @@ export class OpsViewRoutes extends DeesElement {
|
|||||||
|
|
||||||
// Build metadata if profile/target selected
|
// Build metadata if profile/target selected
|
||||||
const metadata: any = {};
|
const metadata: any = {};
|
||||||
if (formData.securityProfileRef) {
|
const profileRefValue = formData.securityProfileRef as any;
|
||||||
metadata.securityProfileRef = formData.securityProfileRef;
|
const profileKey = typeof profileRefValue === 'string' ? profileRefValue : profileRefValue?.key;
|
||||||
|
if (profileKey) {
|
||||||
|
metadata.securityProfileRef = profileKey;
|
||||||
}
|
}
|
||||||
if (formData.networkTargetRef) {
|
const targetRefValue = formData.networkTargetRef as any;
|
||||||
metadata.networkTargetRef = formData.networkTargetRef;
|
const targetKey = typeof targetRefValue === 'string' ? targetRefValue : targetRefValue?.key;
|
||||||
|
if (targetKey) {
|
||||||
|
metadata.networkTargetRef = targetKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
await appstate.routeManagementStatePart.dispatchAction(
|
await appstate.routeManagementStatePart.dispatchAction(
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ The app uses `@push.rocks/smartstate` v2.3+ with multiple state parts, scheduled
|
|||||||
| State Part | Mode | Description |
|
| State Part | Mode | Description |
|
||||||
|-----------|------|-------------|
|
|-----------|------|-------------|
|
||||||
| `loginStatePart` | Persistent (IndexedDB) | JWT identity and login status |
|
| `loginStatePart` | Persistent (IndexedDB) | JWT identity and login status |
|
||||||
| `statsStatePart` | Soft (memory) | Server, email, DNS, security metrics |
|
| `statsStatePart` | Soft (memory) | Server, email, DNS, security, RADIUS, VPN metrics |
|
||||||
| `configStatePart` | Soft | Current system configuration |
|
| `configStatePart` | Soft | Current system configuration |
|
||||||
| `uiStatePart` | Soft | Active view, sidebar, auto-refresh, theme |
|
| `uiStatePart` | Soft | Active view, sidebar, auto-refresh, theme |
|
||||||
| `logStatePart` | Soft | Recent logs, streaming status, filters |
|
| `logStatePart` | Soft | Recent logs, streaming status, filters |
|
||||||
|
|||||||
Reference in New Issue
Block a user