fix: update Configuration Status card labels and add new rows

Notifications section: renamed Notification agents to Channels,
Notification routing to Routing, added Mute Rules row linking to
notification-suppression settings.

Security section: added Trivy installed Yes/No row, renamed
Vulnerability scanning to Scan policies.

Backend: added trivyInstalled and suppressionRules fields to
the /dashboard/configuration payload.
This commit is contained in:
SaelixCode
2026-07-05 23:19:39 -04:00
parent 5d798b36bf
commit eef1b72249
4 changed files with 31 additions and 8 deletions
+8
View File
@@ -1,6 +1,7 @@
import { Router, type Request, type Response } from 'express';
import { DatabaseService, type StackRestartSummary } from '../services/DatabaseService';
import { CloudBackupService } from '../services/CloudBackupService';
import TrivyService from '../services/TrivyService';
import { effectiveTier } from '../middleware/tierGates';
import { isDebugEnabled } from '../utils/debug';
import type { LicenseTier } from '../services/license-types';
@@ -18,6 +19,7 @@ export interface ConfigurationStatus {
agents: { discord: AgentStatus; slack: AgentStatus; webhook: AgentStatus };
alertRules: number;
routingRules: { count: number; enabledCount: number; locked: boolean };
suppressionRules: { total: number; enabledCount: number };
};
automation: {
autoHeal: { total: number; enabled: number };
@@ -29,6 +31,7 @@ export interface ConfigurationStatus {
mfaEnabled: boolean | null;
ssoEnabled: boolean;
ssoProvider: string | null;
trivyInstalled: boolean;
scanPolicies: { total: number; enabled: number; locked: boolean };
};
thresholds: {
@@ -101,6 +104,10 @@ export function buildLocalConfigurationStatus(
enabledCount: notifRoutes.filter(r => r.enabled).length,
locked: false,
},
suppressionRules: (() => {
const rules = db.getNotificationSuppressionRules();
return { total: rules.length, enabledCount: rules.filter(r => r.enabled).length };
})(),
},
automation: {
autoHeal: {
@@ -128,6 +135,7 @@ export function buildLocalConfigurationStatus(
mfaEnabled: mfaRow ? mfaRow.enabled === 1 : null,
ssoEnabled: !!enabledSso,
ssoProvider: enabledSso?.provider ?? null,
trivyInstalled: TrivyService.getInstance().getSource() !== 'none',
// Scan policies are available on every tier.
scanPolicies: {
total: scanPolicies.length,
@@ -141,7 +141,7 @@ export function ConfigurationStatus({ onOpenSection }: ConfigurationStatusProps
<CardContent className="pt-0">
<div className="space-y-0">
<SectionHeader icon={Bell} label="Notifications" />
<Row label="Notification agents" value={agentSummary} onClick={open('notifications')} />
<Row label="Channels" value={agentSummary} onClick={open('notifications')} />
<Row
label="Alert rules"
value={formatCount(notifications.alertRules, 'rule')}
@@ -149,11 +149,16 @@ export function ConfigurationStatus({ onOpenSection }: ConfigurationStatusProps
/>
{!notifications.routingRules.locked && (
<Row
label="Notification routing"
label="Routing"
value={formatCount(notifications.routingRules.enabledCount, 'route')}
onClick={open('notification-routing')}
/>
)}
<Row
label="Mute Rules"
value={formatCount(notifications.suppressionRules.enabledCount, 'rule')}
onClick={open('notification-suppression')}
/>
<SectionHeader icon={Zap} label="Automation" />
<Row
@@ -188,9 +193,13 @@ export function ConfigurationStatus({ onOpenSection }: ConfigurationStatusProps
onClick={open('account')}
/>
<Row label="SSO" value={ssoLabel} onClick={open('sso')} />
<Row
label="Trivy installed"
value={security.trivyInstalled ? 'Yes' : 'No'}
/>
{!security.scanPolicies.locked && (
<Row
label="Vulnerability scanning"
label="Scan policies"
value={formatCount(security.scanPolicies.enabled, 'policy')}
onClick={() => window.dispatchEvent(
new CustomEvent<SenchoNavigateDetail>(SENCHO_NAVIGATE_EVENT, { detail: { view: 'security', tab: 'policies' } }),
@@ -20,6 +20,7 @@ function makePayload(overrides: Partial<ConfigurationStatusPayload> = {}): Confi
},
alertRules: 0,
routingRules: { count: 0, enabledCount: 0, locked: true },
suppressionRules: { total: 0, enabledCount: 0 },
},
automation: {
autoHeal: { total: 0, enabled: 0 },
@@ -31,6 +32,7 @@ function makePayload(overrides: Partial<ConfigurationStatusPayload> = {}): Confi
mfaEnabled: null,
ssoEnabled: false,
ssoProvider: null,
trivyInstalled: false,
scanPolicies: { total: 0, enabled: 0, locked: false },
},
thresholds: { cpuLimit: 90, ramLimit: 90, diskLimit: 90, dockerJanitorGb: 5, globalCrash: false, hostAlertsEnabled: true },
@@ -68,11 +70,11 @@ describe('ConfigurationStatus row visibility', () => {
expect(screen.getByText('Auto-heal policies')).toBeDefined();
expect(screen.getByText('Auto-update schedules')).toBeDefined();
// Rows whose payload reports locked stay hidden.
expect(screen.queryByText('Notification routing')).toBeNull();
expect(screen.queryByText('Routing')).toBeNull();
expect(screen.queryByText('Webhooks')).toBeNull();
expect(screen.queryByText('Scheduled tasks')).toBeNull();
// Scan policies are free, so the Vulnerability scanning row renders.
expect(screen.getByText('Vulnerability scanning')).toBeDefined();
// Scan policies are free, so the row renders.
expect(screen.getByText('Scan policies')).toBeDefined();
// Cloud Backup row is universal (Custom S3 is open to every tier).
expect(screen.getByText('Cloud Backup')).toBeDefined();
});
@@ -89,6 +91,7 @@ describe('ConfigurationStatus row visibility', () => {
},
alertRules: 2,
routingRules: { count: 1, enabledCount: 1, locked: false },
suppressionRules: { total: 0, enabledCount: 0 },
},
automation: {
autoHeal: { total: 3, enabled: 2 },
@@ -100,6 +103,7 @@ describe('ConfigurationStatus row visibility', () => {
mfaEnabled: true,
ssoEnabled: true,
ssoProvider: 'oidc_google',
trivyInstalled: true,
scanPolicies: { total: 2, enabled: 2, locked: false },
},
}),
@@ -110,10 +114,10 @@ describe('ConfigurationStatus row visibility', () => {
expect(screen.getByText('Automation')).toBeDefined();
expect(screen.getByText('Auto-heal policies')).toBeDefined();
expect(screen.getByText('Auto-update schedules')).toBeDefined();
expect(screen.getByText('Notification routing')).toBeDefined();
expect(screen.getByText('Routing')).toBeDefined();
expect(screen.getByText('Webhooks')).toBeDefined();
expect(screen.getByText('Scheduled tasks')).toBeDefined();
expect(screen.getByText('Vulnerability scanning')).toBeDefined();
expect(screen.getByText('Scan policies')).toBeDefined();
expect(screen.getByText('Cloud Backup')).toBeDefined();
// SSO label maps the provider to a friendly name.
expect(screen.getByText('Google')).toBeDefined();
@@ -18,6 +18,7 @@ export interface ConfigurationStatus {
agents: { discord: AgentStatus; slack: AgentStatus; webhook: AgentStatus };
alertRules: number;
routingRules: { count: number; enabledCount: number; locked: boolean };
suppressionRules: { total: number; enabledCount: number };
};
automation: {
autoHeal: { total: number; enabled: number };
@@ -29,6 +30,7 @@ export interface ConfigurationStatus {
mfaEnabled: boolean | null;
ssoEnabled: boolean;
ssoProvider: string | null;
trivyInstalled: boolean;
scanPolicies: { total: number; enabled: number; locked: boolean };
};
thresholds: {