From 6a062a72a7671d89aca49fab98c6e6d32e0fa858 Mon Sep 17 00:00:00 2001 From: Lukas Date: Sat, 25 Apr 2026 19:17:03 +0200 Subject: [PATCH] refactor: move jail detail sub-sections from pages/jail to components/jail Move reusable UI section components (JailInfoSection, PatternsSection, BantimeEscalationSection, IgnoreListSection, CodeList) from pages/jail/ to components/jail/, aligning with the project convention that pages/ contains only route-level entry points while components/ contains reusable UI building blocks. Changes: - Move 5 section components + jailDetailPageStyles.ts to components/jail/ - Update import paths in moved components (relative paths to commonStyles) - Update JailDetailPage.tsx imports to reference components/jail/ - Delete empty pages/jail/ directory - Document pages/ vs components/ distinction in Web-Development.md All components use standard import structure and TypeScript passes type checking. BannedIpsSection was already correctly placed in components/jail/. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Docs/Tasks.md | 24 ------------------- Docs/Web-Development.md | 16 +++++++++++++ .../jail/BantimeEscalationSection.tsx | 2 +- .../{pages => components}/jail/CodeList.tsx | 0 .../jail/IgnoreListSection.tsx | 2 +- .../jail/JailInfoSection.tsx | 2 +- .../jail/PatternsSection.tsx | 2 +- .../jail/jailDetailPageStyles.ts | 0 frontend/src/pages/JailDetailPage.tsx | 10 ++++---- 9 files changed, 25 insertions(+), 33 deletions(-) rename frontend/src/{pages => components}/jail/BantimeEscalationSection.tsx (96%) rename frontend/src/{pages => components}/jail/CodeList.tsx (100%) rename frontend/src/{pages => components}/jail/IgnoreListSection.tsx (98%) rename frontend/src/{pages => components}/jail/JailInfoSection.tsx (98%) rename frontend/src/{pages => components}/jail/PatternsSection.tsx (95%) rename frontend/src/{pages => components}/jail/jailDetailPageStyles.ts (100%) diff --git a/Docs/Tasks.md b/Docs/Tasks.md index 34917e3..21a84fd 100644 --- a/Docs/Tasks.md +++ b/Docs/Tasks.md @@ -1,27 +1,3 @@ -### T-13 · Split `useJailDetail` — SRP violation (read state + write commands in one hook) - -**Where found:** `frontend/src/hooks/useJailDetail.ts` - -**Why this is needed:** The hook manages fetch state AND exposes 8 write operations (`start`, `stop`, `reload`, `setIdle`, `addIp`, `removeIp`, `toggleIgnoreSelf`, `load`). Read concerns and command concerns are independent. The consumer (`JailDetailPage`) passes them separately through props anyway, so the UI doesn't depend on them being co-located. - -**Goal:** `useJailData(name)` for reading, `useJailCommands(name, onSuccess)` for mutations. - -**What to do:** -1. Create `useJailData(name): { jail, ignoreList, ignoreSelf, loading, error, refresh }` using `useListData` or the abort-controller pattern. -2. Create `useJailCommands(name, onSuccess: () => void): { start, stop, reload, setIdle, addIp, removeIp, toggleIgnoreSelf }` — each command calls the API and then calls `onSuccess()` to trigger a refresh. -3. In `JailDetailPage`, call both hooks and pass results to child components. -4. Delete `useJailDetail.ts`. - -**Possible traps and issues:** -- `JailDetailPage` destructures all properties from `useJailDetail` in a single line — update the destructuring. -- Commands currently call `load()` directly. The `onSuccess` callback pattern keeps them decoupled from the data hook's internals. - -**Docs changes needed:** None. - -**Doc references:** `frontend/src/hooks/useJailDetail.ts`, `frontend/src/pages/JailDetailPage.tsx` - ---- - ### T-14 · Move jail detail sub-sections from `pages/jail/` to `components/jail/` **Where found:** `frontend/src/pages/jail/` — `JailInfoSection`, `PatternsSection`, `BantimeEscalationSection`, `IgnoreListSection`, `jailDetailPageStyles.ts`. `BannedIpsSection` is in `frontend/src/components/jail/` (correct location). diff --git a/Docs/Web-Development.md b/Docs/Web-Development.md index cced1a4..82713ff 100644 --- a/Docs/Web-Development.md +++ b/Docs/Web-Development.md @@ -153,6 +153,22 @@ frontend/ > container network `localhost` resolves to the frontend container itself and > causes `ECONNREFUSED`. +### Pages vs Components + +The distinction between **`pages/`** and **`components/`** is fundamental to the project structure: + +- **`pages/`** contains route-level entry point components — exactly **one component per route**. Pages map directly to URL paths (e.g., `JailDetailPage.tsx` → `/jail/:name`). Pages orchestrate the layout and compose multiple components, but contain **no reusable UI logic**. Pages should rarely be reused. + +- **`components/`** contains **reusable UI building blocks** — anything that could plausibly be used on multiple pages or in multiple contexts. This includes: + - Presentation components (Button wrappers, Cards, custom form fields, data tables) + - Feature sub-sections (e.g., `JailInfoSection`, `BannedIpsSection` — components that render a logical grouping of related UI within a page) + - Modals, dialogs, popovers + - Complex, stateful UI patterns + +**Rule of thumb:** If a component is only ever used on a single page, it **still belongs in `components/`** if it represents a coherent, self-contained piece of UI that could logically be reused on another page in the future. Pages are entry points; components are building blocks. + +**Example:** `BannedIpsSection` lives in `components/jail/` (not `pages/jail/`) because it is a reusable UI section that presents banned IPs. If a future report or dashboard also needed to show banned IPs, the same component could be imported and reused. By contrast, `JailDetailPage.tsx` lives in `pages/` because it is the top-level route component. + ### Separation of Concerns - **Pages** handle routing and compose layout + components — they contain no business logic. diff --git a/frontend/src/pages/jail/BantimeEscalationSection.tsx b/frontend/src/components/jail/BantimeEscalationSection.tsx similarity index 96% rename from frontend/src/pages/jail/BantimeEscalationSection.tsx rename to frontend/src/components/jail/BantimeEscalationSection.tsx index c11339b..2d5bd84 100644 --- a/frontend/src/pages/jail/BantimeEscalationSection.tsx +++ b/frontend/src/components/jail/BantimeEscalationSection.tsx @@ -1,5 +1,5 @@ import { Badge, Text } from "@fluentui/react-components"; -import { useCommonSectionStyles } from "../../components/commonStyles"; +import { useCommonSectionStyles } from "../commonStyles"; import { useJailDetailPageStyles } from "./jailDetailPageStyles"; import type { Jail } from "../../types/jail"; import { formatSeconds } from "../../utils/formatDate"; diff --git a/frontend/src/pages/jail/CodeList.tsx b/frontend/src/components/jail/CodeList.tsx similarity index 100% rename from frontend/src/pages/jail/CodeList.tsx rename to frontend/src/components/jail/CodeList.tsx diff --git a/frontend/src/pages/jail/IgnoreListSection.tsx b/frontend/src/components/jail/IgnoreListSection.tsx similarity index 98% rename from frontend/src/pages/jail/IgnoreListSection.tsx rename to frontend/src/components/jail/IgnoreListSection.tsx index 64ffe80..b9965f7 100644 --- a/frontend/src/pages/jail/IgnoreListSection.tsx +++ b/frontend/src/components/jail/IgnoreListSection.tsx @@ -11,7 +11,7 @@ import { Tooltip, } from "@fluentui/react-components"; import { DismissRegular } from "@fluentui/react-icons"; -import { useCommonSectionStyles } from "../../components/commonStyles"; +import { useCommonSectionStyles } from "../commonStyles"; import { useJailDetailPageStyles } from "./jailDetailPageStyles"; interface IgnoreListSectionProps { diff --git a/frontend/src/pages/jail/JailInfoSection.tsx b/frontend/src/components/jail/JailInfoSection.tsx similarity index 98% rename from frontend/src/pages/jail/JailInfoSection.tsx rename to frontend/src/components/jail/JailInfoSection.tsx index 2305428..4cc5fe5 100644 --- a/frontend/src/pages/jail/JailInfoSection.tsx +++ b/frontend/src/components/jail/JailInfoSection.tsx @@ -14,7 +14,7 @@ import { PlayRegular, StopRegular, } from "@fluentui/react-icons"; -import { useCommonSectionStyles } from "../../components/commonStyles"; +import { useCommonSectionStyles } from "../commonStyles"; import { useJailDetailPageStyles } from "./jailDetailPageStyles"; import type { Jail } from "../../types/jail"; diff --git a/frontend/src/pages/jail/PatternsSection.tsx b/frontend/src/components/jail/PatternsSection.tsx similarity index 95% rename from frontend/src/pages/jail/PatternsSection.tsx rename to frontend/src/components/jail/PatternsSection.tsx index 79ab564..65500de 100644 --- a/frontend/src/pages/jail/PatternsSection.tsx +++ b/frontend/src/components/jail/PatternsSection.tsx @@ -1,5 +1,5 @@ import { Text, makeStyles, tokens } from "@fluentui/react-components"; -import { useCommonSectionStyles } from "../../components/commonStyles"; +import { useCommonSectionStyles } from "../commonStyles"; import type { Jail } from "../../types/jail"; import { CodeList } from "./CodeList"; diff --git a/frontend/src/pages/jail/jailDetailPageStyles.ts b/frontend/src/components/jail/jailDetailPageStyles.ts similarity index 100% rename from frontend/src/pages/jail/jailDetailPageStyles.ts rename to frontend/src/components/jail/jailDetailPageStyles.ts diff --git a/frontend/src/pages/JailDetailPage.tsx b/frontend/src/pages/JailDetailPage.tsx index 73c9c08..30013fd 100644 --- a/frontend/src/pages/JailDetailPage.tsx +++ b/frontend/src/pages/JailDetailPage.tsx @@ -12,11 +12,11 @@ import { useJailData } from "../hooks/useJailData"; import { useJailCommands } from "../hooks/useJailCommands"; import { useJailBannedIps } from "../hooks/useJailBannedIps"; import { BannedIpsSection } from "../components/jail/BannedIpsSection"; -import { JailInfoSection } from "./jail/JailInfoSection"; -import { PatternsSection } from "./jail/PatternsSection"; -import { BantimeEscalationSection } from "./jail/BantimeEscalationSection"; -import { IgnoreListSection } from "./jail/IgnoreListSection"; -import { useJailDetailPageStyles } from "./jail/jailDetailPageStyles"; +import { JailInfoSection } from "../components/jail/JailInfoSection"; +import { PatternsSection } from "../components/jail/PatternsSection"; +import { BantimeEscalationSection } from "../components/jail/BantimeEscalationSection"; +import { IgnoreListSection } from "../components/jail/IgnoreListSection"; +import { useJailDetailPageStyles } from "../components/jail/jailDetailPageStyles"; export function JailDetailPage(): React.JSX.Element { const styles = useJailDetailPageStyles();