fix: skipped display, namespace link crash, overview redesign

- Fix skipped count showing empty by rendering as plain text instead
  of StatusLabel with empty status (which renders near-invisible)
- Fix namespace link crash by using Router.createRouteURL to generate
  cluster-prefixed URLs with react-router-dom Link, instead of
  Headlamp's Link component which crashes on plugin-registered routes
- Redesign overview page with PercentageCircle score chart and
  PercentageBar check distribution for a better visual experience

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-07 14:45:39 -05:00
parent 3784b9b1c8
commit 50caae256d
3 changed files with 29 additions and 24 deletions
+20 -20
View File
@@ -1,6 +1,8 @@
import { import {
Loader, Loader,
NameValueTable, NameValueTable,
PercentageBar,
PercentageCircle,
SectionBox, SectionBox,
SectionHeader, SectionHeader,
StatusLabel, StatusLabel,
@@ -9,30 +11,31 @@ import React from 'react';
import { AuditData, computeScore, countResults, ResultCounts } from '../api/polaris'; import { AuditData, computeScore, countResults, ResultCounts } from '../api/polaris';
import { usePolarisDataContext } from '../api/PolarisDataContext'; import { usePolarisDataContext } from '../api/PolarisDataContext';
function scoreStatus(score: number): 'success' | 'warning' | 'error' { const COLORS = {
if (score >= 80) return 'success'; pass: '#4caf50',
if (score >= 50) return 'warning'; warning: '#ff9800',
return 'error'; danger: '#f44336',
} skipped: '#9e9e9e',
};
function OverviewSection(props: { data: AuditData; counts: ResultCounts }) { function OverviewSection(props: { data: AuditData; counts: ResultCounts }) {
const { counts } = props; const { counts } = props;
const score = computeScore(counts); const score = computeScore(counts);
const status = scoreStatus(score);
const chartData = [
{ name: 'Pass', value: counts.pass, fill: COLORS.pass },
{ name: 'Warning', value: counts.warning, fill: COLORS.warning },
{ name: 'Danger', value: counts.danger, fill: COLORS.danger },
{ name: 'Skipped', value: counts.skipped, fill: COLORS.skipped },
];
return ( return (
<> <>
<SectionBox title="Score"> <SectionBox title="Cluster Score">
<NameValueTable <PercentageCircle data={chartData} total={counts.total} label={`${score}%`} />
rows={[
{
name: 'Cluster Score',
value: <StatusLabel status={status}>{score}%</StatusLabel>,
},
]}
/>
</SectionBox> </SectionBox>
<SectionBox title="Check Summary"> <SectionBox title="Check Distribution">
<PercentageBar data={chartData} total={counts.total} />
<NameValueTable <NameValueTable
rows={[ rows={[
{ name: 'Total Checks', value: String(counts.total) }, { name: 'Total Checks', value: String(counts.total) },
@@ -48,10 +51,7 @@ function OverviewSection(props: { data: AuditData; counts: ResultCounts }) {
name: 'Danger', name: 'Danger',
value: <StatusLabel status="error">{counts.danger}</StatusLabel>, value: <StatusLabel status="error">{counts.danger}</StatusLabel>,
}, },
{ { name: 'Skipped', value: String(counts.skipped) },
name: 'Skipped',
value: <StatusLabel status="">{counts.skipped}</StatusLabel>,
},
]} ]}
/> />
</SectionBox> </SectionBox>
+1 -1
View File
@@ -120,7 +120,7 @@ export default function NamespaceDetailView() {
}, },
{ {
name: 'Skipped', name: 'Skipped',
value: <StatusLabel status="">{counts.skipped}</StatusLabel>, value: String(counts.skipped),
}, },
]} ]}
/> />
+8 -3
View File
@@ -1,5 +1,5 @@
import { Router } from '@kinvolk/headlamp-plugin/lib';
import { import {
Link,
Loader, Loader,
NameValueTable, NameValueTable,
SectionBox, SectionBox,
@@ -8,6 +8,7 @@ import {
StatusLabel, StatusLabel,
} from '@kinvolk/headlamp-plugin/lib/CommonComponents'; } from '@kinvolk/headlamp-plugin/lib/CommonComponents';
import React from 'react'; import React from 'react';
import { Link } from 'react-router-dom';
import { import {
computeScore, computeScore,
countResultsForItems, countResultsForItems,
@@ -91,7 +92,11 @@ export default function NamespacesListView() {
{ {
label: 'Namespace', label: 'Namespace',
getter: (row: NamespaceRow) => ( getter: (row: NamespaceRow) => (
<Link routeName="polaris-namespace" params={{ namespace: row.namespace }}> <Link
to={Router.createRouteURL('polaris-namespace', {
namespace: row.namespace,
})}
>
{row.namespace} {row.namespace}
</Link> </Link>
), ),
@@ -118,7 +123,7 @@ export default function NamespacesListView() {
}, },
{ {
label: 'Skipped', label: 'Skipped',
getter: (row: NamespaceRow) => <StatusLabel status="">{row.skipped}</StatusLabel>, getter: (row: NamespaceRow) => String(row.skipped),
}, },
]} ]}
data={rows} data={rows}