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:
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -34,6 +34,8 @@ jobs:
|
|||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
|
permissions:
|
||||||
|
checks: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import React, { useCallback, useEffect, useState } from 'react';
|
|||||||
import { useTnsCsiContext } from '../api/TnsCsiDataContext';
|
import { useTnsCsiContext } from '../api/TnsCsiDataContext';
|
||||||
import { formatAge, formatProtocol, phaseToStatus } from '../api/k8s';
|
import { formatAge, formatProtocol, phaseToStatus } from '../api/k8s';
|
||||||
import type { TnsCsiMetrics } from '../api/metrics';
|
import type { TnsCsiMetrics } from '../api/metrics';
|
||||||
import { extractTnsCsiMetrics, fetchControllerMetrics, parsePrometheusText } from '../api/metrics';
|
import { fetchControllerMetrics } from '../api/metrics';
|
||||||
import DriverStatusCard from './DriverStatusCard';
|
import DriverStatusCard from './DriverStatusCard';
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -85,6 +85,24 @@ export default function OverviewPage() {
|
|||||||
void fetchMetrics();
|
void fetchMetrics();
|
||||||
}, [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) {
|
if (loading) {
|
||||||
return <Loader title="Loading TNS-CSI data..." />;
|
return <Loader title="Loading TNS-CSI data..." />;
|
||||||
}
|
}
|
||||||
@@ -111,27 +129,6 @@ export default function OverviewPage() {
|
|||||||
const chartData = protocolChartData(storageClasses);
|
const chartData = protocolChartData(storageClasses);
|
||||||
const totalScs = storageClasses.length;
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px' }}>
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px' }}>
|
||||||
|
|||||||
Reference in New Issue
Block a user