fix(ci): add eslint config, fix conditional hook, add checks permission

- Add .eslintrc.json (was missing, causing lint to always fail)
- Move useMemo above early return in OverviewPage to fix rules-of-hooks
- Remove unused imports in OverviewPage
- Add checks:write permission to test job for dorny/test-reporter

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-26 17:20:19 +00:00
parent fa401afecf
commit f7592d69db
3 changed files with 55 additions and 22 deletions
+34
View File
@@ -0,0 +1,34 @@
{
"env": {
"browser": true,
"es2021": true
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": { "jsx": true },
"sourceType": "module"
},
"plugins": ["react", "react-hooks", "@typescript-eslint"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended"
],
"settings": {
"react": { "version": "detect" }
},
"rules": {
"react/react-in-jsx-scope": "off",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-unused-vars": "warn"
},
"overrides": [
{
"files": ["**/*.test.ts", "**/*.test.tsx"],
"rules": {
"@typescript-eslint/no-require-imports": "off"
}
}
]
}
+2
View File
@@ -34,6 +34,8 @@ jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
checks: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
+19 -22
View File
@@ -18,7 +18,7 @@ import React, { useCallback, useEffect, useState } from 'react';
import { useTnsCsiContext } from '../api/TnsCsiDataContext';
import { formatAge, formatProtocol, phaseToStatus } from '../api/k8s';
import type { TnsCsiMetrics } from '../api/metrics';
import { extractTnsCsiMetrics, fetchControllerMetrics, parsePrometheusText } from '../api/metrics';
import { fetchControllerMetrics } from '../api/metrics';
import DriverStatusCard from './DriverStatusCard';
// ---------------------------------------------------------------------------
@@ -85,6 +85,24 @@ export default function OverviewPage() {
void fetchMetrics();
}, [fetchMetrics]);
const capacityByPool: Map<string, number> = React.useMemo(() => {
const map = new Map<string, number>();
if (!metrics) return map;
const handleToPool = new Map<string, string>();
for (const pv of persistentVolumes) {
const handle = pv.spec.csi?.volumeHandle;
const pool = pv.spec.csi?.volumeAttributes?.['pool'];
if (handle && pool) handleToPool.set(handle, pool);
}
for (const sample of metrics.volumeCapacityBytes) {
const volumeId = sample.labels['volume_id'];
if (!volumeId) continue;
const pool = handleToPool.get(volumeId) ?? 'unknown';
map.set(pool, (map.get(pool) ?? 0) + sample.value);
}
return map;
}, [metrics, persistentVolumes]);
if (loading) {
return <Loader title="Loading TNS-CSI data..." />;
}
@@ -111,27 +129,6 @@ export default function OverviewPage() {
const chartData = protocolChartData(storageClasses);
const totalScs = storageClasses.length;
// Capacity by pool: join volumeCapacityBytes samples (volume_id, protocol)
// with PV volumeHandle → pool name from volumeAttributes.
const capacityByPool: Map<string, number> = React.useMemo(() => {
const map = new Map<string, number>();
if (!metrics) return map;
// Build lookup: volumeHandle → pool name
const handleToPool = new Map<string, string>();
for (const pv of persistentVolumes) {
const handle = pv.spec.csi?.volumeHandle;
const pool = pv.spec.csi?.volumeAttributes?.['pool'];
if (handle && pool) handleToPool.set(handle, pool);
}
for (const sample of metrics.volumeCapacityBytes) {
const volumeId = sample.labels['volume_id'];
if (!volumeId) continue;
const pool = handleToPool.get(volumeId) ?? 'unknown';
map.set(pool, (map.get(pool) ?? 0) + sample.value);
}
return map;
}, [metrics, persistentVolumes]);
return (
<>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px' }}>