Files
headlamp-polaris-plugin/src/components/PolarisSettings.tsx
T
gandalf-the-greybeard[bot] e800adfc19 fix: restore badge emoji, fix aria-label, and correct service proxy URL (#19)
* fix: restore badge emoji, fix aria-label, and correct service proxy URL

Three root causes for E2E test failures since March 4:

1. Service proxy URL missing http: protocol prefix — Kubernetes requires
   the format http:service-name:port, not service-name:port. This caused
   all data fetches to fail, making data-dependent components render
   empty states instead of expected content.

2. AppBarScoreBadge aria-label "Polaris cluster score: X%" doesn't match
   the E2E test regex /Polaris: \d+%/. Simplified to "Polaris: X%".

3. Shield emoji was removed from badge in commit 514de78 but E2E tests
   still assert its presence.

Fixes PRI-20

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style: format polaris.ts to pass prettier check

The service proxy URL fix in 61bf1fe exceeded the line length limit.
Run prettier to split the long line.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: gandalf-the-greybeard[bot] <gandalf-the-greybeard[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 22:13:28 -05:00

173 lines
5.3 KiB
TypeScript

import { ApiProxy } from '@kinvolk/headlamp-plugin/lib';
import {
NameValueTable,
SectionBox,
StatusLabel,
} from '@kinvolk/headlamp-plugin/lib/CommonComponents';
import { useTheme } from '@mui/material/styles';
import React from 'react';
import {
AuditData,
getDashboardUrl,
getPolarisApiPath,
getRefreshInterval,
INTERVAL_OPTIONS,
isFullUrl,
setDashboardUrl,
setRefreshInterval,
} from '../api/polaris';
interface PluginSettingsProps {
data?: { [key: string]: string | number | boolean };
onDataChange?: (data: { [key: string]: string | number | boolean }) => void;
}
export default function PolarisSettings(props: PluginSettingsProps) {
const theme = useTheme();
const { data, onDataChange } = props;
const currentInterval = (data?.refreshInterval as number) ?? getRefreshInterval();
const currentUrl = (data?.dashboardUrl as string) ?? getDashboardUrl();
const [testing, setTesting] = React.useState(false);
const [testResult, setTestResult] = React.useState<{ success: boolean; message: string } | null>(
null
);
function handleIntervalChange(e: React.ChangeEvent<HTMLSelectElement>) {
const seconds = Number(e.target.value);
setRefreshInterval(seconds);
onDataChange?.({ ...data, refreshInterval: seconds });
}
function handleUrlChange(e: React.ChangeEvent<HTMLInputElement>) {
const url = e.target.value;
setDashboardUrl(url);
onDataChange?.({ ...data, dashboardUrl: url });
}
async function testConnection() {
setTesting(true);
setTestResult(null);
try {
const apiPath = getPolarisApiPath();
let result: AuditData;
if (isFullUrl(apiPath)) {
const response = await fetch(apiPath);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
result = await response.json();
} else {
result = await ApiProxy.request(apiPath, {
method: 'GET',
});
}
setTestResult({
success: true,
message: `Connected successfully! Version: ${
result.PolarisOutputVersion
}, Last audit: ${new Date(result.AuditTime).toLocaleString()}`,
});
} catch (err) {
setTestResult({
success: false,
message: `Connection failed: ${String(err)}`,
});
} finally {
setTesting(false);
}
}
return (
<SectionBox title="Polaris Settings">
<NameValueTable
rows={[
{
name: 'Refresh Interval',
value: (
<select value={currentInterval} onChange={handleIntervalChange}>
{INTERVAL_OPTIONS.map(opt => (
<option key={opt.value} value={opt.value}>
{opt.label}
</option>
))}
</select>
),
},
{
name: 'Dashboard URL',
value: (
<div>
<input
type="text"
value={currentUrl}
onChange={handleUrlChange}
placeholder="/api/v1/namespaces/polaris/services/http:polaris-dashboard:80/proxy/"
style={{
width: '100%',
padding: '4px 8px',
border: `1px solid ${theme.palette.divider}`,
borderRadius: '4px',
fontSize: '14px',
backgroundColor: theme.palette.background.paper,
color: theme.palette.text.primary,
}}
/>
<div
style={{
fontSize: '12px',
color: theme.palette.text.secondary,
marginTop: '4px',
}}
>
Examples:
<br /> K8s proxy:{' '}
<code>/api/v1/namespaces/polaris/services/http:polaris-dashboard:80/proxy/</code>
<br /> Full URL: <code>https://my-polaris.example.com</code>
</div>
</div>
),
},
{
name: 'Connection Test',
value: (
<div>
<button
onClick={testConnection}
disabled={testing}
style={{
padding: '6px 16px',
backgroundColor: testing
? theme.palette.action.disabledBackground
: theme.palette.primary.main,
color: testing
? theme.palette.action.disabled
: theme.palette.primary.contrastText,
border: 'none',
borderRadius: '4px',
cursor: testing ? 'not-allowed' : 'pointer',
fontSize: '13px',
fontWeight: 500,
}}
>
{testing ? 'Testing...' : 'Test Connection'}
</button>
{testResult && (
<div style={{ marginTop: '8px' }}>
<StatusLabel status={testResult.success ? 'success' : 'error'}>
{testResult.message}
</StatusLabel>
</div>
)}
</div>
),
},
]}
/>
</SectionBox>
);
}