Memoize dashboard and history table columns
This commit is contained in:
@@ -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.
|
**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:**
|
**Where found:**
|
||||||
- `frontend/src/components/BanTable.tsx` — `buildBanColumns(styles)` called unconditionally in the render body.
|
- `frontend/src/components/BanTable.tsx` — `buildBanColumns(styles)` called unconditionally in the render body.
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
* Columns: Time, IP, Service, Country, Jail, Ban Count.
|
* Columns: Time, IP, Service, Country, Jail, Ban Count.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { useMemo } from "react";
|
||||||
import {
|
import {
|
||||||
Badge,
|
Badge,
|
||||||
Button,
|
Button,
|
||||||
@@ -194,7 +195,7 @@ export function BanTable({ timeRange, origin = "all", source = "fail2ban" }: Ban
|
|||||||
const styles = useStyles();
|
const styles = useStyles();
|
||||||
const { banItems, total, page, setPage, loading, error, refresh } = useBans(timeRange, origin, source);
|
const { banItems, total, page, setPage, loading, error, refresh } = useBans(timeRange, origin, source);
|
||||||
|
|
||||||
const banColumns = buildBanColumns(styles);
|
const banColumns = useMemo(() => buildBanColumns(styles), [styles]);
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// Loading state
|
// Loading state
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* Rows with repeatedly-banned IPs are highlighted in amber.
|
* Rows with repeatedly-banned IPs are highlighted in amber.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import {
|
import {
|
||||||
Badge,
|
Badge,
|
||||||
Button,
|
Button,
|
||||||
@@ -214,6 +214,15 @@ export function HistoryPage(): React.JSX.Element {
|
|||||||
const { items, total, page, loading, error, setPage, refresh } =
|
const { items, total, page, loading, error, setPage, refresh } =
|
||||||
useHistory(appliedQuery);
|
useHistory(appliedQuery);
|
||||||
|
|
||||||
|
const handleIpClick = useCallback((ip: string): void => {
|
||||||
|
setSelectedIp(ip);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const columns = useMemo(
|
||||||
|
() => HISTORY_COLUMNS(handleIpClick, styles),
|
||||||
|
[handleIpClick, styles],
|
||||||
|
);
|
||||||
|
|
||||||
useEffect((): void => {
|
useEffect((): void => {
|
||||||
const nextQuery: HistoryQuery = {
|
const nextQuery: HistoryQuery = {
|
||||||
range,
|
range,
|
||||||
@@ -236,14 +245,6 @@ export function HistoryPage(): React.JSX.Element {
|
|||||||
|
|
||||||
const totalPages = Math.max(1, Math.ceil(total / PAGE_SIZE));
|
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 an IP is selected, show the detail view.
|
||||||
if (selectedIp !== null) {
|
if (selectedIp !== null) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user