@@ -129,11 +129,12 @@ import {
129129 podMatchesProblemCategory ,
130130 SEVERITY_DOT_COLOR ,
131131} from './resource-utils'
132- import { SEVERITY_BADGE , EVENT_TYPE_COLORS } from '../../utils/badge-colors'
132+ import { SEVERITY_BADGE , EVENT_TYPE_COLORS , SEVERITY_TEXT } from '../../utils/badge-colors'
133133import { pluralize } from '../../utils/pluralize'
134134import { getPodGpuCount , getNodeGpuCount } from '../../utils/extended-resources'
135135import { type CustomColumnDef , type CustomColumnSource , customColumnKey , readCustomColumnValue , sanitizeCustomColumnDefs } from '../../utils/custom-columns'
136136import { Tooltip } from '../ui/Tooltip'
137+ import { AuditBadgeTooltip , type AuditBadgeMessage } from '../audit/AuditBadgeTooltip'
137138// CRD-specific cell components (extracted)
138139import { GitRepositoryCell , OCIRepositoryCell , HelmRepositoryCell , KustomizationCell , FluxHelmReleaseCell , FluxAlertCell } from './renderers/flux-cells'
139140import { ArgoApplicationCell , ArgoApplicationSetCell , ArgoAppProjectCell } from './renderers/argo-cells'
@@ -1800,6 +1801,9 @@ interface ResourcesViewData {
18001801 onNavigate ?: ( path : string , options ?: { replace ?: boolean } ) => void
18011802 certExpiry ?: Record < string , { expired ?: boolean ; daysLeft : number } >
18021803 certExpiryError ?: boolean
1804+ // Cluster Audit findings for the listed kind, keyed by "namespace/name" (the
1805+ // list shows one kind at a time, so ns/name is unambiguous). Host-injected.
1806+ auditBadges ?: Record < string , { danger : number ; warning : number ; messages ?: AuditBadgeMessage [ ] } >
18031807 onOpenLogs ?: ( params : { namespace : string ; podName : string ; containers : string [ ] ; containerName ?: string } ) => void
18041808 onOpenWorkloadLogs ?: ( params : { namespace : string ; workloadKind : string ; workloadName : string } ) => void
18051809}
@@ -1852,6 +1856,8 @@ interface ResourcesViewProps {
18521856 topNodeMetrics ?: TopNodeMetrics [ ]
18531857 certExpiry ?: Record < string , { expired ?: boolean ; daysLeft : number } >
18541858 certExpiryError ?: boolean
1859+ // Cluster Audit findings for the selected kind, keyed by "namespace/name".
1860+ auditBadges ?: Record < string , { danger : number ; warning : number ; messages ?: AuditBadgeMessage [ ] } >
18551861 // Pinned kinds
18561862 pinned ?: Array < { name : string ; kind : string ; group : string } >
18571863 togglePin ?: ( kind : { name : string ; kind : string ; group : string } ) => void
@@ -2070,6 +2076,7 @@ export function ResourcesView({
20702076 topNodeMetrics,
20712077 certExpiry,
20722078 certExpiryError,
2079+ auditBadges,
20732080 pinned = [ ] ,
20742081 togglePin = ( ) => { } ,
20752082 isPinned = ( ) => false ,
@@ -4014,9 +4021,10 @@ export function ResourcesView({
40144021 onNavigate,
40154022 certExpiry,
40164023 certExpiryError,
4024+ auditBadges,
40174025 onOpenLogs,
40184026 onOpenWorkloadLogs,
4019- } ) , [ onNavigate , certExpiry , certExpiryError , onOpenLogs , onOpenWorkloadLogs ] )
4027+ } ) , [ onNavigate , certExpiry , certExpiryError , auditBadges , onOpenLogs , onOpenWorkloadLogs ] )
40204028
40214029 return (
40224030 < ResourcesViewDataContext . Provider value = { resourcesViewDataContextValue } >
@@ -5155,6 +5163,7 @@ interface CellContentProps {
51555163}
51565164
51575165function CellContent ( { resource, kind, column, group, majorityNodeMinorVersion, extraColumn, nameHref } : CellContentProps ) {
5166+ const { auditBadges } = useContext ( ResourcesViewDataContext )
51585167 // Parent-injected extra columns short-circuit the built-in switch.
51595168 // Used by hosts that inject leading columns (e.g. a multi-cluster Cluster column).
51605169 if ( extraColumn ) {
@@ -5167,6 +5176,8 @@ function CellContent({ resource, kind, column, group, majorityNodeMinorVersion,
51675176 if ( column === 'name' ) {
51685177 const isTerminating = ! ! meta . deletionTimestamp
51695178 const nameClass = clsx ( 'text-sm font-medium truncate block' , isTerminating ? 'text-theme-text-tertiary line-through' : 'text-theme-text-primary' )
5179+ const audit = auditBadges ?. [ `${ meta . namespace || '' } /${ meta . name } ` ]
5180+ const auditTotal = audit ? audit . danger + audit . warning : 0
51705181 return (
51715182 < div className = "flex items-center gap-1.5 min-w-0" >
51725183 < Tooltip content = { meta . name } >
@@ -5184,6 +5195,16 @@ function CellContent({ resource, kind, column, group, majorityNodeMinorVersion,
51845195 ) }
51855196 </ Tooltip >
51865197 < CopyNameButton name = { meta . name } />
5198+ { auditTotal > 0 && audit && (
5199+ < Tooltip content = { audit . messages && audit . messages . length > 0
5200+ ? < AuditBadgeTooltip messages = { audit . messages } />
5201+ : `${ auditTotal } audit ${ auditTotal === 1 ? 'finding' : 'findings' } ${ audit . danger > 0 ? ` · ${ audit . danger } danger` : '' } ` } >
5202+ < span className = { clsx ( 'shrink-0 inline-flex items-center gap-0.5 text-[10px] font-medium cursor-help' , audit . danger > 0 ? SEVERITY_TEXT . error : SEVERITY_TEXT . warning ) } >
5203+ < AlertTriangle className = "w-3 h-3" />
5204+ { auditTotal }
5205+ </ span >
5206+ </ Tooltip >
5207+ ) }
51875208 { isTerminating && (
51885209 < Tooltip content = "Resource is being deleted (has deletionTimestamp set). May be stuck due to finalizers." >
51895210 < span className = "shrink-0 flex items-center gap-1 px-1.5 py-0.5 text-[10px] font-medium bg-red-500/15 text-red-600 dark:text-red-400 rounded" >
@@ -6022,6 +6043,7 @@ function ReplicaSetCell({ resource, column }: { resource: any; column: string })
60226043}
60236044
60246045function ServiceCell ( { resource, column } : { resource : any ; column : string } ) {
6046+ const { auditBadges } = useContext ( ResourcesViewDataContext )
60256047 switch ( column ) {
60266048 case 'type' : {
60276049 const status = getServiceStatus ( resource )
@@ -6042,6 +6064,20 @@ function ServiceCell({ resource, column }: { resource: any; column: string }) {
60426064 )
60436065 }
60446066 case 'endpoints' : {
6067+ // getServiceEndpointsStatus can't see live pods, so it optimistically
6068+ // reports "Active" for any service with a selector. The audit's
6069+ // serviceNoMatchingPods check DOES resolve the selector against live pods —
6070+ // the only badge-worthy finding a Service can carry — so when it fired,
6071+ // trust it over the guess instead of showing a false-green "Active".
6072+ const meta = resource . metadata || { }
6073+ const flagged = auditBadges ?. [ `${ meta . namespace || '' } /${ meta . name } ` ]
6074+ if ( flagged && flagged . danger + flagged . warning > 0 ) {
6075+ return (
6076+ < span className = { clsx ( 'badge' , flagged . danger > 0 ? 'status-unhealthy' : 'status-degraded' ) } >
6077+ No endpoints
6078+ </ span >
6079+ )
6080+ }
60456081 const { status, color } = getServiceEndpointsStatus ( resource )
60466082 return (
60476083 < span className = { clsx ( 'badge' , color ) } >
0 commit comments