Polish dashboard charts and add frontend tests (Stage 6)
Task 6.1 - Consistent loading/error/empty states across all charts: - Add ChartStateWrapper shared component with Spinner, error MessageBar + Retry button, and friendly empty message - Expose reload() in useBanTrend, useJailDistribution, useDashboardCountryData hooks - Update BanTrendChart and JailDistributionChart to use ChartStateWrapper - Add empty state to TopCountriesBarChart and TopCountriesPieChart - Replace manual loading/error logic in DashboardPage with ChartStateWrapper Task 6.2 - Frontend tests (5 files, 20 tests): - Install Vitest v4, jsdom, @testing-library/react, @testing-library/jest-dom - Add vitest.config.ts (separate from vite.config.ts to avoid Vite v5/v7 clash) - Add src/setupTests.ts with jest-dom matchers and ResizeObserver/matchMedia stubs - Tests: ChartStateWrapper (7), BanTrendChart (4), JailDistributionChart (4), TopCountriesPieChart (2), TopCountriesBarChart (3) Task 6.3 - Full QA: - ruff: clean - mypy --strict: 52 files, no issues - pytest: 497 passed - tsc --noEmit: clean - eslint: clean (added test-file override for explicit-function-return-type) - vite build: success
This commit is contained in:
@@ -8,15 +8,13 @@
|
||||
|
||||
import { useState } from "react";
|
||||
import {
|
||||
MessageBar,
|
||||
MessageBarBody,
|
||||
Spinner,
|
||||
Text,
|
||||
ToggleButton,
|
||||
Toolbar,
|
||||
makeStyles,
|
||||
tokens,
|
||||
} from "@fluentui/react-components";
|
||||
import { ChartStateWrapper } from "../components/ChartStateWrapper";
|
||||
import { BanTable } from "../components/BanTable";
|
||||
import { BanTrendChart } from "../components/BanTrendChart";
|
||||
import { JailDistributionChart } from "../components/JailDistributionChart";
|
||||
@@ -109,7 +107,7 @@ export function DashboardPage(): React.JSX.Element {
|
||||
const [timeRange, setTimeRange] = useState<TimeRange>("24h");
|
||||
const [originFilter, setOriginFilter] = useState<BanOriginFilter>("all");
|
||||
|
||||
const { countries, countryNames, isLoading: countryLoading, error: countryError } =
|
||||
const { countries, countryNames, isLoading: countryLoading, error: countryError, reload: reloadCountry } =
|
||||
useDashboardCountryData(timeRange, originFilter);
|
||||
|
||||
return (
|
||||
@@ -143,27 +141,28 @@ export function DashboardPage(): React.JSX.Element {
|
||||
</Text>
|
||||
</div>
|
||||
<div className={styles.tabContent}>
|
||||
{countryError != null && (
|
||||
<MessageBar intent="error">
|
||||
<MessageBarBody>{countryError}</MessageBarBody>
|
||||
</MessageBar>
|
||||
)}
|
||||
{countryLoading && countryError == null ? (
|
||||
<Spinner label="Loading chart data…" />
|
||||
) : (
|
||||
<ChartStateWrapper
|
||||
isLoading={countryLoading}
|
||||
error={countryError}
|
||||
onRetry={reloadCountry}
|
||||
isEmpty={!countryLoading && Object.keys(countries).length === 0}
|
||||
emptyMessage="No ban data for the selected period."
|
||||
>
|
||||
<div className={styles.chartsRow}>
|
||||
<div className={styles.chartCard}>
|
||||
<TopCountriesPieChart
|
||||
countries={countries}
|
||||
countryNames={countryNames}
|
||||
/>
|
||||
</div> <div className={styles.chartCard}>
|
||||
</div>
|
||||
<div className={styles.chartCard}>
|
||||
<TopCountriesBarChart
|
||||
countries={countries}
|
||||
countryNames={countryNames}
|
||||
/>
|
||||
</div> </div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</ChartStateWrapper>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user