Files
BanGUI/frontend/src/pages/JailDetailPage.tsx
Lukas 045c8048fe Refactor: Replace inline style objects with makeStyles classes
Moved all static layout properties (display, gap, margin, padding, colour)
from inline style props to makeStyles classes in:

- MapBansTable.tsx: Pagination row flexbox layout
- JailDetailPage.tsx: Link styling for textDecoration
- HistoryPage.tsx: Summary text styling
- IpDetailView.tsx: Loading container and text formatting

Kept inline styles only for genuinely dynamic values:
- WorldMap.tsx: Tooltip position (follows mouse)
- TopCountriesPieChart.tsx: Legend color (from recharts data)
- TopCountriesBarChart.tsx: Chart height (derives from data length)

This change improves performance by leveraging Griffel's atomic CSS cache
and ensures consistency with the established Fluent UI pattern.

Updated Docs/Web-Development.md with explicit rule: inline styles only
for runtime-dynamic values, all static properties go in makeStyles.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-25 19:48:25 +02:00

119 lines
3.5 KiB
TypeScript

/**
* Jail detail page.
*
* Fetches and displays the full configuration and state of a single jail
* identified by the `:name` route parameter.
*/
import { Button, MessageBar, MessageBarBody, Spinner, Text, makeStyles } from "@fluentui/react-components";
import { ArrowLeftRegular } from "@fluentui/react-icons";
import { Link, useParams } from "react-router-dom";
import { useJailData } from "../hooks/useJailData";
import { useJailCommands } from "../hooks/useJailCommands";
import { useJailBannedIps } from "../hooks/useJailBannedIps";
import { BannedIpsSection } from "../components/jail/BannedIpsSection";
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";
const useLinkStyles = makeStyles({
link: {
textDecoration: "none",
},
});
export function JailDetailPage(): React.JSX.Element {
const linkStyles = useLinkStyles();
const styles = useJailDetailPageStyles();
const { name = "" } = useParams<{ name: string }>();
const { jail, ignoreList, ignoreSelf, loading, error, refresh } = useJailData(name);
const { addIp, removeIp, toggleIgnoreSelf, start, stop, reload, setIdle } = useJailCommands(name, refresh);
const {
items,
total,
page,
pageSize,
search,
loading: bannedLoading,
error: bannedError,
opError,
refresh: refreshBanned,
setPage,
setPageSize,
setSearch,
unban,
} = useJailBannedIps(name);
if (loading && !jail) {
return (
<div className={styles.centred}>
<Spinner label={`Loading jail ${name}`} />
</div>
);
}
if (error) {
return (
<div className={styles.root}>
<Link to="/jails" className={linkStyles.link}>
<Button appearance="subtle" icon={<ArrowLeftRegular />}>
Back to Jails
</Button>
</Link>
<MessageBar intent="error">
<MessageBarBody>Failed to load jail {name}: {error}</MessageBarBody>
</MessageBar>
</div>
);
}
if (!jail) return <></>;
return (
<div className={styles.root}>
<div className={styles.breadcrumb}>
<Link to="/jails" className={linkStyles.link}>
<Button appearance="subtle" size="small" icon={<ArrowLeftRegular />}>
Jails
</Button>
</Link>
<Text size={200} style={{ color: "var(--colorNeutralForeground3)" }}>
/
</Text>
<Text size={200} className={styles.mono}>
{name}
</Text>
</div>
<JailInfoSection jail={jail} onRefresh={refresh} onStart={start} onStop={stop} onReload={reload} onSetIdle={setIdle} />
<BannedIpsSection
items={items}
total={total}
page={page}
pageSize={pageSize}
search={search}
loading={bannedLoading}
error={bannedError}
opError={opError}
onSearch={setSearch}
onPageChange={setPage}
onPageSizeChange={setPageSize}
onRefresh={refreshBanned}
onUnban={unban}
/>
<PatternsSection jail={jail} />
<BantimeEscalationSection jail={jail} />
<IgnoreListSection
jailName={name}
ignoreList={ignoreList}
ignoreSelf={ignoreSelf}
onAdd={addIp}
onRemove={removeIp}
onToggleIgnoreSelf={toggleIgnoreSelf}
/>
</div>
);
}