Relocate misplaced frontend files

This commit is contained in:
2026-04-19 18:36:55 +02:00
parent d44a667592
commit e7582c4bae
23 changed files with 92 additions and 40 deletions

View File

@@ -420,6 +420,8 @@ Reference: `Docs/Refactoring.md` for full analysis of each issue.
**Goal:** Move `areHistoryQueriesEqual` to `frontend/src/utils/` (either into a new `queryUtils.ts` or an existing utility file if a suitable one exists). Import it back into `HistoryPage.tsx` from that location. Verify the function has no implicit dependency on page-local types — if it relies on `HistoryQuery` from `types/history.ts`, it can still live in utils by importing that type. **Goal:** Move `areHistoryQueriesEqual` to `frontend/src/utils/` (either into a new `queryUtils.ts` or an existing utility file if a suitable one exists). Import it back into `HistoryPage.tsx` from that location. Verify the function has no implicit dependency on page-local types — if it relies on `HistoryQuery` from `types/history.ts`, it can still live in utils by importing that type.
**Status:** Completed.
**Possible traps and issues:** **Possible traps and issues:**
- This is a mechanical move with no behavioral change. The only risk is a stale import if the function is used in more than one place (confirm with a search before moving). - This is a mechanical move with no behavioral change. The only risk is a stale import if the function is used in more than one place (confirm with a search before moving).
- If similar utility functions exist in other page files (a search for `function` declarations inside page files is worthwhile), extract them in the same pass. - If similar utility functions exist in other page files (a search for `function` declarations inside page files is worthwhile), extract them in the same pass.
@@ -445,6 +447,8 @@ Reference: `Docs/Refactoring.md` for full analysis of each issue.
- Move `theme/commonStyles.ts`: if the styles in it are shared across multiple components with no better home, move them to the component directory that uses them most, or rename the file to `components/commonStyles.ts`. The `theme/` directory must contain only `customTheme.ts` and token-related files. - Move `theme/commonStyles.ts`: if the styles in it are shared across multiple components with no better home, move them to the component directory that uses them most, or rename the file to `components/commonStyles.ts`. The `theme/` directory must contain only `customTheme.ts` and token-related files.
- For `configStyles.ts` and `blocklistStyles.ts`: inline each exported `makeStyles` hook into the component file that uses it, or keep the file in the same directory as the components but document that it is a style helper rather than a theme definition. The architecture rule is "co-locate styles in the same file as the component" — a shared styles file is acceptable only if documented as an explicit exception for styles used by multiple components in the same subdirectory. - For `configStyles.ts` and `blocklistStyles.ts`: inline each exported `makeStyles` hook into the component file that uses it, or keep the file in the same directory as the components but document that it is a style helper rather than a theme definition. The architecture rule is "co-locate styles in the same file as the component" — a shared styles file is acceptable only if documented as an explicit exception for styles used by multiple components in the same subdirectory.
**Status:** Completed.
**Possible traps and issues:** **Possible traps and issues:**
- Moving `isoNumericToAlpha2.ts` changes its import path in `WorldMap.tsx` and any other consumer — update all import sites. - Moving `isoNumericToAlpha2.ts` changes its import path in `WorldMap.tsx` and any other consumer — update all import sites.
- Moving `api/map.test.ts` to a `__tests__` subdirectory requires the test runner config (`vitest.config.ts`) to include `api/__tests__/` if it only scans `__tests__/` top-level directories — verify the glob pattern first. - Moving `api/map.test.ts` to a `__tests__` subdirectory requires the test runner config (`vitest.config.ts`) to include `api/__tests__/` if it only scans `__tests__/` top-level directories — verify the glob pattern first.

View File

@@ -1,10 +1,10 @@
import { beforeEach, describe, expect, it, vi } from "vitest"; import { beforeEach, describe, expect, it, vi } from "vitest";
import type { Mock } from "vitest"; import type { Mock } from "vitest";
import { ENDPOINTS } from "./endpoints"; import { ENDPOINTS } from "../endpoints";
import { fetchBansByCountry } from "./map"; import { fetchBansByCountry } from "../map";
import { get } from "./client"; import { get } from "../client";
vi.mock("./client", () => ({ vi.mock("../client", () => ({
get: vi.fn(), get: vi.fn(),
})); }));

View File

@@ -15,7 +15,7 @@ import {
makeStyles, makeStyles,
tokens, tokens,
} from "@fluentui/react-components"; } from "@fluentui/react-components";
import { useCardStyles } from "../theme/commonStyles"; import { useCardStyles } from "../components/commonStyles";
import type { BanOriginFilter, TimeRange } from "../types/ban"; import type { BanOriginFilter, TimeRange } from "../types/ban";
import { import {
BAN_ORIGIN_FILTER_LABELS, BAN_ORIGIN_FILTER_LABELS,

View File

@@ -18,7 +18,7 @@ import {
tokens, tokens,
Tooltip, Tooltip,
} from "@fluentui/react-components"; } from "@fluentui/react-components";
import { useCardStyles } from "../theme/commonStyles"; import { useCardStyles } from "../components/commonStyles";
import { ArrowClockwiseRegular, ShieldRegular } from "@fluentui/react-icons"; import { ArrowClockwiseRegular, ShieldRegular } from "@fluentui/react-icons";
import { useServerStatus } from "../hooks/useServerStatus"; import { useServerStatus } from "../hooks/useServerStatus";

View File

@@ -22,8 +22,8 @@ import type {
Topology, Topology,
} from "topojson-specification"; } from "topojson-specification";
import worldData from "world-atlas/countries-110m.json"; import worldData from "world-atlas/countries-110m.json";
import { useCardStyles } from "../theme/commonStyles"; import { useCardStyles } from "../components/commonStyles";
import { ISO_NUMERIC_TO_ALPHA2 } from "../data/isoNumericToAlpha2"; import { ISO_NUMERIC_TO_ALPHA2 } from "../utils/isoNumericToAlpha2";
import { getBanCountColor } from "../utils/mapColors"; import { getBanCountColor } from "../utils/mapColors";
const MAP_WIDTH = 800; const MAP_WIDTH = 800;

View File

@@ -1,6 +1,6 @@
import { Button, Badge, Table, TableBody, TableCell, TableCellLayout, TableHeader, TableHeaderCell, TableRow, Text, MessageBar, MessageBarBody, Spinner } from "@fluentui/react-components"; import { Button, Badge, Table, TableBody, TableCell, TableCellLayout, TableHeader, TableHeaderCell, TableRow, Text, MessageBar, MessageBarBody, Spinner } from "@fluentui/react-components";
import { ArrowClockwiseRegular } from "@fluentui/react-icons"; import { ArrowClockwiseRegular } from "@fluentui/react-icons";
import { useCommonSectionStyles } from "../../theme/commonStyles"; import { useCommonSectionStyles } from "../../components/commonStyles";
import { useImportLog } from "../../hooks/useBlocklist"; import { useImportLog } from "../../hooks/useBlocklist";
import { useBlocklistStyles } from "./blocklistStyles"; import { useBlocklistStyles } from "./blocklistStyles";

View File

@@ -1,7 +1,7 @@
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
import { Button, Field, Input, MessageBar, MessageBarBody, Select, Spinner, Text } from "@fluentui/react-components"; import { Button, Field, Input, MessageBar, MessageBarBody, Select, Spinner, Text } from "@fluentui/react-components";
import { PlayRegular } from "@fluentui/react-icons"; import { PlayRegular } from "@fluentui/react-icons";
import { useCommonSectionStyles } from "../../theme/commonStyles"; import { useCommonSectionStyles } from "../../components/commonStyles";
import { useSchedule } from "../../hooks/useBlocklist"; import { useSchedule } from "../../hooks/useBlocklist";
import { useBlocklistStyles } from "./blocklistStyles"; import { useBlocklistStyles } from "./blocklistStyles";
import type { ScheduleConfig, ScheduleFrequency } from "../../types/blocklist"; import type { ScheduleConfig, ScheduleFrequency } from "../../types/blocklist";

View File

@@ -14,7 +14,7 @@ import {
TableRow, TableRow,
Text, Text,
} from "@fluentui/react-components"; } from "@fluentui/react-components";
import { useCommonSectionStyles } from "../../theme/commonStyles"; import { useCommonSectionStyles } from "../../components/commonStyles";
import { import {
AddRegular, AddRegular,
ArrowClockwiseRegular, ArrowClockwiseRegular,

View File

@@ -33,7 +33,7 @@ import {
type TableColumnDefinition, type TableColumnDefinition,
createTableColumn, createTableColumn,
} from "@fluentui/react-components"; } from "@fluentui/react-components";
import { useCommonSectionStyles } from "../../theme/commonStyles"; import { useCommonSectionStyles } from "../../components/commonStyles";
import { formatTimestamp } from "../../utils/formatDate"; import { formatTimestamp } from "../../utils/formatDate";
import { import {
ArrowClockwiseRegular, ArrowClockwiseRegular,

View File

@@ -15,7 +15,7 @@ import { DashboardFilterBar } from "../components/DashboardFilterBar";
import { ServerStatusBar } from "../components/ServerStatusBar"; import { ServerStatusBar } from "../components/ServerStatusBar";
import { TopCountriesBarChart } from "../components/TopCountriesBarChart"; import { TopCountriesBarChart } from "../components/TopCountriesBarChart";
import { TopCountriesPieChart } from "../components/TopCountriesPieChart"; import { TopCountriesPieChart } from "../components/TopCountriesPieChart";
import { useCommonSectionStyles } from "../theme/commonStyles"; import { useCommonSectionStyles } from "../components/commonStyles";
import { useDashboardCountryData } from "../hooks/useDashboardCountryData"; import { useDashboardCountryData } from "../hooks/useDashboardCountryData";
import type { BanOriginFilter, TimeRange } from "../types/ban"; import type { BanOriginFilter, TimeRange } from "../types/ban";

View File

@@ -32,6 +32,7 @@ import {
import { DashboardFilterBar } from "../components/DashboardFilterBar"; import { DashboardFilterBar } from "../components/DashboardFilterBar";
import { useHistory } from "../hooks/useHistory"; import { useHistory } from "../hooks/useHistory";
import { IpDetailView } from "./history/IpDetailView"; import { IpDetailView } from "./history/IpDetailView";
import { areHistoryQueriesEqual } from "../utils/queryUtils";
import type { HistoryBanItem, HistoryQuery, TimeRange } from "../types/history"; import type { HistoryBanItem, HistoryQuery, TimeRange } from "../types/history";
import type { BanOriginFilter } from "../types/ban"; import type { BanOriginFilter } from "../types/ban";
@@ -119,25 +120,6 @@ const useStyles = makeStyles({
}, },
}); });
// ---------------------------------------------------------------------------
// Utilities
// ---------------------------------------------------------------------------
function areHistoryQueriesEqual(
a: HistoryQuery,
b: HistoryQuery,
): boolean {
return (
a.range === b.range &&
a.origin === b.origin &&
a.jail === b.jail &&
a.ip === b.ip &&
a.source === b.source &&
a.page === b.page &&
a.page_size === b.page_size
);
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Column definitions for the main history table // Column definitions for the main history table
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@@ -15,7 +15,7 @@ import {
tokens, tokens,
} from "@fluentui/react-components"; } from "@fluentui/react-components";
import { ArrowCounterclockwiseRegular, ArrowLeftRegular } from "@fluentui/react-icons"; import { ArrowCounterclockwiseRegular, ArrowLeftRegular } from "@fluentui/react-icons";
import { useCardStyles } from "../../theme/commonStyles"; import { useCardStyles } from "../../components/commonStyles";
import { useIpHistory } from "../../hooks/useHistory"; import { useIpHistory } from "../../hooks/useHistory";
interface IpDetailViewProps { interface IpDetailViewProps {

View File

@@ -1,5 +1,5 @@
import { Badge, Text } from "@fluentui/react-components"; import { Badge, Text } from "@fluentui/react-components";
import { useCommonSectionStyles } from "../../theme/commonStyles"; import { useCommonSectionStyles } from "../../components/commonStyles";
import { useJailDetailPageStyles } from "./jailDetailPageStyles"; import { useJailDetailPageStyles } from "./jailDetailPageStyles";
import type { Jail } from "../../types/jail"; import type { Jail } from "../../types/jail";
import { formatSeconds } from "../../utils/formatDate"; import { formatSeconds } from "../../utils/formatDate";

View File

@@ -11,7 +11,7 @@ import {
Tooltip, Tooltip,
} from "@fluentui/react-components"; } from "@fluentui/react-components";
import { DismissRegular } from "@fluentui/react-icons"; import { DismissRegular } from "@fluentui/react-icons";
import { useCommonSectionStyles } from "../../theme/commonStyles"; import { useCommonSectionStyles } from "../../components/commonStyles";
import { useJailDetailPageStyles } from "./jailDetailPageStyles"; import { useJailDetailPageStyles } from "./jailDetailPageStyles";
interface IgnoreListSectionProps { interface IgnoreListSectionProps {

View File

@@ -14,7 +14,7 @@ import {
PlayRegular, PlayRegular,
StopRegular, StopRegular,
} from "@fluentui/react-icons"; } from "@fluentui/react-icons";
import { useCommonSectionStyles } from "../../theme/commonStyles"; import { useCommonSectionStyles } from "../../components/commonStyles";
import { useJailDetailPageStyles } from "./jailDetailPageStyles"; import { useJailDetailPageStyles } from "./jailDetailPageStyles";
import type { Jail } from "../../types/jail"; import type { Jail } from "../../types/jail";

View File

@@ -1,5 +1,5 @@
import { Text } from "@fluentui/react-components"; import { Text } from "@fluentui/react-components";
import { useCommonSectionStyles } from "../../theme/commonStyles"; import { useCommonSectionStyles } from "../../components/commonStyles";
import type { Jail } from "../../types/jail"; import type { Jail } from "../../types/jail";
import { CodeList } from "./CodeList"; import { CodeList } from "./CodeList";

View File

@@ -10,7 +10,7 @@ import {
tokens, tokens,
} from "@fluentui/react-components"; } from "@fluentui/react-components";
import { LockClosedRegular, LockOpenRegular } from "@fluentui/react-icons"; import { LockClosedRegular, LockOpenRegular } from "@fluentui/react-icons";
import { useCommonSectionStyles } from "../../theme/commonStyles"; import { useCommonSectionStyles } from "../../components/commonStyles";
import { useJailsPageStyles } from "./jailsPageStyles"; import { useJailsPageStyles } from "./jailsPageStyles";
import { ApiError } from "../../api/client"; import { ApiError } from "../../api/client";

View File

@@ -10,7 +10,7 @@ import {
Text, Text,
} from "@fluentui/react-components"; } from "@fluentui/react-components";
import { SearchRegular } from "@fluentui/react-icons"; import { SearchRegular } from "@fluentui/react-icons";
import { useCommonSectionStyles } from "../../theme/commonStyles"; import { useCommonSectionStyles } from "../../components/commonStyles";
import { useJailsPageStyles } from "./jailsPageStyles"; import { useJailsPageStyles } from "./jailsPageStyles";
import { useIpLookup } from "../../hooks/useJails"; import { useIpLookup } from "../../hooks/useJails";

View File

@@ -25,7 +25,7 @@ import {
PlayRegular, PlayRegular,
StopRegular, StopRegular,
} from "@fluentui/react-icons"; } from "@fluentui/react-icons";
import { useCommonSectionStyles } from "../../theme/commonStyles"; import { useCommonSectionStyles } from "../../components/commonStyles";
import { useJailsPageStyles } from "./jailsPageStyles"; import { useJailsPageStyles } from "./jailsPageStyles";
import { useJails } from "../../hooks/useJails"; import { useJails } from "../../hooks/useJails";
import type { JailSummary } from "../../types/jail"; import type { JailSummary } from "../../types/jail";

View File

@@ -0,0 +1,39 @@
import { describe, expect, it } from "vitest";
import { areHistoryQueriesEqual } from "../queryUtils";
describe("areHistoryQueriesEqual", () => {
it("returns true for identical history queries", () => {
const a = {
range: "7d",
origin: "blocklist",
jail: "ssh",
ip: "192.0.2.1",
source: "archive",
page: 2,
page_size: 50,
};
const b = { ...a };
expect(areHistoryQueriesEqual(a, b)).toBe(true);
});
it("returns false when a single query field differs", () => {
const base = {
range: "7d",
origin: "all",
jail: "ssh",
ip: "192.0.2.1",
source: "archive",
page: 2,
page_size: 50,
};
expect(
areHistoryQueriesEqual(base, { ...base, page: 3 }),
).toBe(false);
expect(
areHistoryQueriesEqual(base, { ...base, ip: "198.51.100.1" }),
).toBe(false);
});
});

View File

@@ -0,0 +1,27 @@
/**
* Shared query utilities used by pages and hooks.
*/
import type { HistoryQuery } from "../types/history";
/**
* Compare two history query objects for semantic equality.
*
* @param a - First query object.
* @param b - Second query object.
* @returns True when every query field has the same value.
*/
export function areHistoryQueriesEqual(
a: HistoryQuery,
b: HistoryQuery,
): boolean {
return (
a.range === b.range &&
a.origin === b.origin &&
a.jail === b.jail &&
a.ip === b.ip &&
a.source === b.source &&
a.page === b.page &&
a.page_size === b.page_size
);
}