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>
This commit is contained in:
@@ -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/`
|
### 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).
|
**Where found:** `frontend/src/pages/jail/` — `JailInfoSection`, `PatternsSection`, `BantimeEscalationSection`, `IgnoreListSection`, `jailDetailPageStyles.ts`. `BannedIpsSection` is in `frontend/src/components/jail/` (correct location).
|
||||||
|
|||||||
@@ -153,6 +153,22 @@ frontend/
|
|||||||
> container network `localhost` resolves to the frontend container itself and
|
> container network `localhost` resolves to the frontend container itself and
|
||||||
> causes `ECONNREFUSED`.
|
> 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
|
### Separation of Concerns
|
||||||
|
|
||||||
- **Pages** handle routing and compose layout + components — they contain no business logic.
|
- **Pages** handle routing and compose layout + components — they contain no business logic.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Badge, Text } from "@fluentui/react-components";
|
import { Badge, Text } from "@fluentui/react-components";
|
||||||
import { useCommonSectionStyles } from "../../components/commonStyles";
|
import { useCommonSectionStyles } from "../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";
|
||||||
@@ -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 "../../components/commonStyles";
|
import { useCommonSectionStyles } from "../commonStyles";
|
||||||
import { useJailDetailPageStyles } from "./jailDetailPageStyles";
|
import { useJailDetailPageStyles } from "./jailDetailPageStyles";
|
||||||
|
|
||||||
interface IgnoreListSectionProps {
|
interface IgnoreListSectionProps {
|
||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
PlayRegular,
|
PlayRegular,
|
||||||
StopRegular,
|
StopRegular,
|
||||||
} from "@fluentui/react-icons";
|
} from "@fluentui/react-icons";
|
||||||
import { useCommonSectionStyles } from "../../components/commonStyles";
|
import { useCommonSectionStyles } from "../commonStyles";
|
||||||
import { useJailDetailPageStyles } from "./jailDetailPageStyles";
|
import { useJailDetailPageStyles } from "./jailDetailPageStyles";
|
||||||
import type { Jail } from "../../types/jail";
|
import type { Jail } from "../../types/jail";
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Text, makeStyles, tokens } from "@fluentui/react-components";
|
import { Text, makeStyles, tokens } from "@fluentui/react-components";
|
||||||
import { useCommonSectionStyles } from "../../components/commonStyles";
|
import { useCommonSectionStyles } from "../commonStyles";
|
||||||
import type { Jail } from "../../types/jail";
|
import type { Jail } from "../../types/jail";
|
||||||
import { CodeList } from "./CodeList";
|
import { CodeList } from "./CodeList";
|
||||||
|
|
||||||
@@ -12,11 +12,11 @@ import { useJailData } from "../hooks/useJailData";
|
|||||||
import { useJailCommands } from "../hooks/useJailCommands";
|
import { useJailCommands } from "../hooks/useJailCommands";
|
||||||
import { useJailBannedIps } from "../hooks/useJailBannedIps";
|
import { useJailBannedIps } from "../hooks/useJailBannedIps";
|
||||||
import { BannedIpsSection } from "../components/jail/BannedIpsSection";
|
import { BannedIpsSection } from "../components/jail/BannedIpsSection";
|
||||||
import { JailInfoSection } from "./jail/JailInfoSection";
|
import { JailInfoSection } from "../components/jail/JailInfoSection";
|
||||||
import { PatternsSection } from "./jail/PatternsSection";
|
import { PatternsSection } from "../components/jail/PatternsSection";
|
||||||
import { BantimeEscalationSection } from "./jail/BantimeEscalationSection";
|
import { BantimeEscalationSection } from "../components/jail/BantimeEscalationSection";
|
||||||
import { IgnoreListSection } from "./jail/IgnoreListSection";
|
import { IgnoreListSection } from "../components/jail/IgnoreListSection";
|
||||||
import { useJailDetailPageStyles } from "./jail/jailDetailPageStyles";
|
import { useJailDetailPageStyles } from "../components/jail/jailDetailPageStyles";
|
||||||
|
|
||||||
export function JailDetailPage(): React.JSX.Element {
|
export function JailDetailPage(): React.JSX.Element {
|
||||||
const styles = useJailDetailPageStyles();
|
const styles = useJailDetailPageStyles();
|
||||||
|
|||||||
Reference in New Issue
Block a user