Memoize dashboard and history table columns

This commit is contained in:
2026-04-20 19:28:29 +02:00
parent e593498de5
commit 20412dd94b
3 changed files with 16 additions and 12 deletions

View File

@@ -128,7 +128,7 @@ Issues are grouped by category and ordered roughly by severity. Each entry descr
---
### TASK-007 — Setup page password validation too weak
### TASK-007 — Setup page password validation too weak (done)
**Where found:** `frontend/src/pages/SetupPage.tsx`, `validate()` function. Only `masterPassword.length < 8` is checked.
@@ -148,7 +148,9 @@ Issues are grouped by category and ordered roughly by severity. Each entry descr
---
### TASK-008 — `buildBanColumns` and `HISTORY_COLUMNS` recreated on every render
### TASK-008 — `buildBanColumns` and `HISTORY_COLUMNS` recreated on every render (done)
**Where fixed:** `frontend/src/components/BanTable.tsx`, `frontend/src/pages/HistoryPage.tsx`
**Where found:**
- `frontend/src/components/BanTable.tsx``buildBanColumns(styles)` called unconditionally in the render body.

View File

@@ -8,6 +8,7 @@
* Columns: Time, IP, Service, Country, Jail, Ban Count.
*/
import { useMemo } from "react";
import {
Badge,
Button,
@@ -194,7 +195,7 @@ export function BanTable({ timeRange, origin = "all", source = "fail2ban" }: Ban
const styles = useStyles();
const { banItems, total, page, setPage, loading, error, refresh } = useBans(timeRange, origin, source);
const banColumns = buildBanColumns(styles);
const banColumns = useMemo(() => buildBanColumns(styles), [styles]);
// --------------------------------------------------------------------------
// Loading state

View File

@@ -6,7 +6,7 @@
* Rows with repeatedly-banned IPs are highlighted in amber.
*/
import { useEffect, useRef, useState } from "react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import {
Badge,
Button,
@@ -214,6 +214,15 @@ export function HistoryPage(): React.JSX.Element {
const { items, total, page, loading, error, setPage, refresh } =
useHistory(appliedQuery);
const handleIpClick = useCallback((ip: string): void => {
setSelectedIp(ip);
}, []);
const columns = useMemo(
() => HISTORY_COLUMNS(handleIpClick, styles),
[handleIpClick, styles],
);
useEffect((): void => {
const nextQuery: HistoryQuery = {
range,
@@ -236,14 +245,6 @@ export function HistoryPage(): React.JSX.Element {
const totalPages = Math.max(1, Math.ceil(total / PAGE_SIZE));
/** History table columns with IP click handler. */
const columns = HISTORY_COLUMNS(
(ip: string): void => {
setSelectedIp(ip);
},
styles,
);
// If an IP is selected, show the detail view.
if (selectedIp !== null) {
return (