Relocate misplaced frontend files
This commit is contained in:
@@ -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.
|
||||
|
||||
**Status:** Completed.
|
||||
|
||||
**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).
|
||||
- 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.
|
||||
- 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:**
|
||||
- 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.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { Mock } from "vitest";
|
||||
import { ENDPOINTS } from "./endpoints";
|
||||
import { fetchBansByCountry } from "./map";
|
||||
import { get } from "./client";
|
||||
import { ENDPOINTS } from "../endpoints";
|
||||
import { fetchBansByCountry } from "../map";
|
||||
import { get } from "../client";
|
||||
|
||||
vi.mock("./client", () => ({
|
||||
vi.mock("../client", () => ({
|
||||
get: vi.fn(),
|
||||
}));
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
makeStyles,
|
||||
tokens,
|
||||
} from "@fluentui/react-components";
|
||||
import { useCardStyles } from "../theme/commonStyles";
|
||||
import { useCardStyles } from "../components/commonStyles";
|
||||
import type { BanOriginFilter, TimeRange } from "../types/ban";
|
||||
import {
|
||||
BAN_ORIGIN_FILTER_LABELS,
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
tokens,
|
||||
Tooltip,
|
||||
} from "@fluentui/react-components";
|
||||
import { useCardStyles } from "../theme/commonStyles";
|
||||
import { useCardStyles } from "../components/commonStyles";
|
||||
import { ArrowClockwiseRegular, ShieldRegular } from "@fluentui/react-icons";
|
||||
import { useServerStatus } from "../hooks/useServerStatus";
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ import type {
|
||||
Topology,
|
||||
} from "topojson-specification";
|
||||
import worldData from "world-atlas/countries-110m.json";
|
||||
import { useCardStyles } from "../theme/commonStyles";
|
||||
import { ISO_NUMERIC_TO_ALPHA2 } from "../data/isoNumericToAlpha2";
|
||||
import { useCardStyles } from "../components/commonStyles";
|
||||
import { ISO_NUMERIC_TO_ALPHA2 } from "../utils/isoNumericToAlpha2";
|
||||
import { getBanCountColor } from "../utils/mapColors";
|
||||
|
||||
const MAP_WIDTH = 800;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
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 { useCommonSectionStyles } from "../../theme/commonStyles";
|
||||
import { useCommonSectionStyles } from "../../components/commonStyles";
|
||||
import { useImportLog } from "../../hooks/useBlocklist";
|
||||
import { useBlocklistStyles } from "./blocklistStyles";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { Button, Field, Input, MessageBar, MessageBarBody, Select, Spinner, Text } from "@fluentui/react-components";
|
||||
import { PlayRegular } from "@fluentui/react-icons";
|
||||
import { useCommonSectionStyles } from "../../theme/commonStyles";
|
||||
import { useCommonSectionStyles } from "../../components/commonStyles";
|
||||
import { useSchedule } from "../../hooks/useBlocklist";
|
||||
import { useBlocklistStyles } from "./blocklistStyles";
|
||||
import type { ScheduleConfig, ScheduleFrequency } from "../../types/blocklist";
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
TableRow,
|
||||
Text,
|
||||
} from "@fluentui/react-components";
|
||||
import { useCommonSectionStyles } from "../../theme/commonStyles";
|
||||
import { useCommonSectionStyles } from "../../components/commonStyles";
|
||||
import {
|
||||
AddRegular,
|
||||
ArrowClockwiseRegular,
|
||||
|
||||
@@ -33,7 +33,7 @@ import {
|
||||
type TableColumnDefinition,
|
||||
createTableColumn,
|
||||
} from "@fluentui/react-components";
|
||||
import { useCommonSectionStyles } from "../../theme/commonStyles";
|
||||
import { useCommonSectionStyles } from "../../components/commonStyles";
|
||||
import { formatTimestamp } from "../../utils/formatDate";
|
||||
import {
|
||||
ArrowClockwiseRegular,
|
||||
|
||||
@@ -15,7 +15,7 @@ import { DashboardFilterBar } from "../components/DashboardFilterBar";
|
||||
import { ServerStatusBar } from "../components/ServerStatusBar";
|
||||
import { TopCountriesBarChart } from "../components/TopCountriesBarChart";
|
||||
import { TopCountriesPieChart } from "../components/TopCountriesPieChart";
|
||||
import { useCommonSectionStyles } from "../theme/commonStyles";
|
||||
import { useCommonSectionStyles } from "../components/commonStyles";
|
||||
import { useDashboardCountryData } from "../hooks/useDashboardCountryData";
|
||||
import type { BanOriginFilter, TimeRange } from "../types/ban";
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
import { DashboardFilterBar } from "../components/DashboardFilterBar";
|
||||
import { useHistory } from "../hooks/useHistory";
|
||||
import { IpDetailView } from "./history/IpDetailView";
|
||||
import { areHistoryQueriesEqual } from "../utils/queryUtils";
|
||||
import type { HistoryBanItem, HistoryQuery, TimeRange } from "../types/history";
|
||||
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
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
tokens,
|
||||
} from "@fluentui/react-components";
|
||||
import { ArrowCounterclockwiseRegular, ArrowLeftRegular } from "@fluentui/react-icons";
|
||||
import { useCardStyles } from "../../theme/commonStyles";
|
||||
import { useCardStyles } from "../../components/commonStyles";
|
||||
import { useIpHistory } from "../../hooks/useHistory";
|
||||
|
||||
interface IpDetailViewProps {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Badge, Text } from "@fluentui/react-components";
|
||||
import { useCommonSectionStyles } from "../../theme/commonStyles";
|
||||
import { useCommonSectionStyles } from "../../components/commonStyles";
|
||||
import { useJailDetailPageStyles } from "./jailDetailPageStyles";
|
||||
import type { Jail } from "../../types/jail";
|
||||
import { formatSeconds } from "../../utils/formatDate";
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
Tooltip,
|
||||
} from "@fluentui/react-components";
|
||||
import { DismissRegular } from "@fluentui/react-icons";
|
||||
import { useCommonSectionStyles } from "../../theme/commonStyles";
|
||||
import { useCommonSectionStyles } from "../../components/commonStyles";
|
||||
import { useJailDetailPageStyles } from "./jailDetailPageStyles";
|
||||
|
||||
interface IgnoreListSectionProps {
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
PlayRegular,
|
||||
StopRegular,
|
||||
} from "@fluentui/react-icons";
|
||||
import { useCommonSectionStyles } from "../../theme/commonStyles";
|
||||
import { useCommonSectionStyles } from "../../components/commonStyles";
|
||||
import { useJailDetailPageStyles } from "./jailDetailPageStyles";
|
||||
import type { Jail } from "../../types/jail";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Text } from "@fluentui/react-components";
|
||||
import { useCommonSectionStyles } from "../../theme/commonStyles";
|
||||
import { useCommonSectionStyles } from "../../components/commonStyles";
|
||||
import type { Jail } from "../../types/jail";
|
||||
import { CodeList } from "./CodeList";
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
tokens,
|
||||
} from "@fluentui/react-components";
|
||||
import { LockClosedRegular, LockOpenRegular } from "@fluentui/react-icons";
|
||||
import { useCommonSectionStyles } from "../../theme/commonStyles";
|
||||
import { useCommonSectionStyles } from "../../components/commonStyles";
|
||||
import { useJailsPageStyles } from "./jailsPageStyles";
|
||||
import { ApiError } from "../../api/client";
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
Text,
|
||||
} from "@fluentui/react-components";
|
||||
import { SearchRegular } from "@fluentui/react-icons";
|
||||
import { useCommonSectionStyles } from "../../theme/commonStyles";
|
||||
import { useCommonSectionStyles } from "../../components/commonStyles";
|
||||
import { useJailsPageStyles } from "./jailsPageStyles";
|
||||
import { useIpLookup } from "../../hooks/useJails";
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
PlayRegular,
|
||||
StopRegular,
|
||||
} from "@fluentui/react-icons";
|
||||
import { useCommonSectionStyles } from "../../theme/commonStyles";
|
||||
import { useCommonSectionStyles } from "../../components/commonStyles";
|
||||
import { useJailsPageStyles } from "./jailsPageStyles";
|
||||
import { useJails } from "../../hooks/useJails";
|
||||
import type { JailSummary } from "../../types/jail";
|
||||
|
||||
39
frontend/src/utils/__tests__/queryUtils.test.ts
Normal file
39
frontend/src/utils/__tests__/queryUtils.test.ts
Normal 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);
|
||||
});
|
||||
});
|
||||
27
frontend/src/utils/queryUtils.ts
Normal file
27
frontend/src/utils/queryUtils.ts
Normal 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
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user