From 2a45b4d46f0a08dfeb8a354dede94448e7147981 Mon Sep 17 00:00:00 2001 From: fabiangigler Date: Wed, 23 Sep 2026 12:21:26 +0200 Subject: [PATCH 1/5] Persist monitor list sorting --- client/src/Features/UI/uiSlice.ts | 18 +++++++++++ client/src/Hooks/useMonitorListController.ts | 31 +++++++++++++++---- .../monitors/monitor.repository.mongo.ts | 4 ++- .../integration/monitorRepository.test.ts | 28 +++++++++++++++++ 4 files changed, 74 insertions(+), 7 deletions(-) diff --git a/client/src/Features/UI/uiSlice.ts b/client/src/Features/UI/uiSlice.ts index 55e83333c..644d411a6 100644 --- a/client/src/Features/UI/uiSlice.ts +++ b/client/src/Features/UI/uiSlice.ts @@ -15,6 +15,8 @@ type TableName = interface TableState { rowsPerPage: number; + sortField?: string; + sortOrder?: "asc" | "desc"; } interface SidebarState { @@ -94,6 +96,20 @@ const uiSlice = createSlice({ const { table, value } = action.payload; state[table].rowsPerPage = value; }, + setTableSortField: ( + state, + action: PayloadAction<{ table: TableName; value: string }> + ) => { + const { table, value } = action.payload; + state[table].sortField = value; + }, + setTableSortOrder: ( + state, + action: PayloadAction<{ table: TableName; value: "asc" | "desc" }> + ) => { + const { table, value } = action.payload; + state[table].sortOrder = value; + }, toggleSidebar: (state) => { state.sidebar.collapsed = !state.sidebar.collapsed; }, @@ -131,6 +147,8 @@ export type { UIState, ThemeMode, ChartType, TableName }; export default uiSlice.reducer; export const { setRowsPerPage, + setTableSortField, + setTableSortOrder, toggleSidebar, setCollapsed, setMode, diff --git a/client/src/Hooks/useMonitorListController.ts b/client/src/Hooks/useMonitorListController.ts index cd6852594..245210b3c 100644 --- a/client/src/Hooks/useMonitorListController.ts +++ b/client/src/Hooks/useMonitorListController.ts @@ -1,4 +1,9 @@ -import { setRowsPerPage, type TableName } from "@/Features/UI/uiSlice"; +import { + setRowsPerPage, + setTableSortField, + setTableSortOrder, + type TableName, +} from "@/Features/UI/uiSlice"; import { useDelete, useGet } from "@/Hooks/UseApi"; import { useBulkMonitorActions } from "@/Hooks/useBulkMonitorActions"; import useDebounce from "@/Hooks/useDebounce"; @@ -24,10 +29,12 @@ interface MonitorListConfig { export const useMonitorListController = (config: MonitorListConfig) => { const dispatch = useDispatch(); - const rowsPerPage = useSelector( - (state: RootState) => - state.ui?.[config.rowsPerPageTable]?.rowsPerPage ?? config.rowsPerPageDefault + const tableState = useSelector( + (state: RootState) => state.ui?.[config.rowsPerPageTable] ); + const rowsPerPage = tableState?.rowsPerPage ?? config.rowsPerPageDefault; + const sortField = tableState?.sortField ?? config.initialSortField ?? ""; + const sortOrder = tableState?.sortOrder ?? "asc"; // Filter states const [selectedTypes, setSelectedTypes] = useState([]); @@ -36,8 +43,6 @@ export const useMonitorListController = (config: MonitorListConfig) => { const [selectedTags, setSelectedTags] = useState([]); const [page, setPage] = useState(0); const [search, setSearch] = useState(""); - const [sortField, setSortField] = useState(config.initialSortField ?? ""); - const [sortOrder, setSortOrder] = useState<"asc" | "desc">("asc"); const [selectedMonitor, setSelectedMonitor] = useState(null); const debouncedSearch = useDebounce(search, 300); @@ -135,6 +140,20 @@ export const useMonitorListController = (config: MonitorListConfig) => { setPage(0); }; + const setSortField = useCallback( + (value: string) => { + dispatch(setTableSortField({ value, table: config.rowsPerPageTable })); + }, + [config.rowsPerPageTable, dispatch] + ); + + const setSortOrder = useCallback( + (value: "asc" | "desc") => { + dispatch(setTableSortOrder({ value, table: config.rowsPerPageTable })); + }, + [config.rowsPerPageTable, dispatch] + ); + // Check for active filters const hasActiveFilters = Boolean( selectedTypes.length > 0 || diff --git a/server/src/domain/monitors/monitor.repository.mongo.ts b/server/src/domain/monitors/monitor.repository.mongo.ts index 385dcebab..b5a7f651d 100644 --- a/server/src/domain/monitors/monitor.repository.mongo.ts +++ b/server/src/domain/monitors/monitor.repository.mongo.ts @@ -101,7 +101,9 @@ class MongoMonitorsRepository implements IMonitorsRepository { private pageOptions = (config: TeamQueryConfig) => { const { page = 0, rowsPerPage = 0, field = "createdAt", order = "desc" } = config ?? {}; - return { sort: { [field]: order === "asc" ? 1 : -1 } as const, skip: Math.max(page, 0) * rowsPerPage, limit: rowsPerPage }; + const direction: 1 | -1 = order === "asc" ? 1 : -1; + const sort: Record = field === "createdAt" ? { createdAt: direction } : { [field]: direction, createdAt: 1 }; + return { sort, skip: Math.max(page, 0) * rowsPerPage, limit: rowsPerPage }; }; findByTeamId = async (teamId: string, config: TeamQueryConfig, options?: { includeRecentChecks?: boolean }): Promise => { diff --git a/server/test/integration/monitorRepository.test.ts b/server/test/integration/monitorRepository.test.ts index 63ef4a105..446085a0e 100644 --- a/server/test/integration/monitorRepository.test.ts +++ b/server/test/integration/monitorRepository.test.ts @@ -69,6 +69,34 @@ describe("MongoMonitorsRepository", () => { }); }); + describe("sorting", () => { + it("uses creation time as the fallback for equal primary values", async () => { + const repo = new MongoMonitorsRepository(); + const teamId = new mongoose.Types.ObjectId(); + const createMonitor = (name: string, type: string, status: string, createdAt: Date) => + MonitorModel.create({ + userId: new mongoose.Types.ObjectId(), + teamId, + name, + type, + status, + url: "https://example.com", + createdAt, + }); + + await createMonitor("newer-up", "hardware", "up", new Date("2026-03-01T00:00:00.000Z")); + await createMonitor("down", "http", "down", new Date("2026-04-01T00:00:00.000Z")); + await createMonitor("older-up", "pagespeed", "up", new Date("2026-01-01T00:00:00.000Z")); + await createMonitor("middle-up", "docker", "up", new Date("2026-02-01T00:00:00.000Z")); + + const ascending = await repo.findByTeamIdWithStats(teamId.toString(), { field: "status", order: "asc" }); + const descending = await repo.findByTeamIdWithStats(teamId.toString(), { field: "status", order: "desc" }); + + expect(ascending.map((monitor) => monitor.name)).toEqual(["down", "older-up", "middle-up", "newer-up"]); + expect(descending.map((monitor) => monitor.name)).toEqual(["older-up", "middle-up", "newer-up", "down"]); + }); + }); + describe("findByIds recentChecks modes", () => { const seedFixtures = async () => { const teamId = new mongoose.Types.ObjectId(); From 22d012396692dd1c5fc5d3cd665de342f9b5f414 Mon Sep 17 00:00:00 2001 From: fabiangigler Date: Wed, 23 Sep 2026 12:37:45 +0200 Subject: [PATCH 2/5] Reset monitor pages when sorting --- client/src/Hooks/useMonitorListController.ts | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/client/src/Hooks/useMonitorListController.ts b/client/src/Hooks/useMonitorListController.ts index 245210b3c..1c73c8a19 100644 --- a/client/src/Hooks/useMonitorListController.ts +++ b/client/src/Hooks/useMonitorListController.ts @@ -140,19 +140,15 @@ export const useMonitorListController = (config: MonitorListConfig) => { setPage(0); }; - const setSortField = useCallback( - (value: string) => { - dispatch(setTableSortField({ value, table: config.rowsPerPageTable })); - }, - [config.rowsPerPageTable, dispatch] - ); + const setSortField = (value: string) => { + dispatch(setTableSortField({ value, table: config.rowsPerPageTable })); + setPage(0); + }; - const setSortOrder = useCallback( - (value: "asc" | "desc") => { - dispatch(setTableSortOrder({ value, table: config.rowsPerPageTable })); - }, - [config.rowsPerPageTable, dispatch] - ); + const setSortOrder = (value: "asc" | "desc") => { + dispatch(setTableSortOrder({ value, table: config.rowsPerPageTable })); + setPage(0); + }; // Check for active filters const hasActiveFilters = Boolean( From 0cb48596a0ff299377ee18f7eccbe31ccf431655 Mon Sep 17 00:00:00 2001 From: fabiangigler Date: Wed, 23 Sep 2026 12:38:57 +0200 Subject: [PATCH 3/5] Clarify monitor sort fallback --- server/src/domain/monitors/monitor.repository.mongo.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server/src/domain/monitors/monitor.repository.mongo.ts b/server/src/domain/monitors/monitor.repository.mongo.ts index b5a7f651d..33faab55f 100644 --- a/server/src/domain/monitors/monitor.repository.mongo.ts +++ b/server/src/domain/monitors/monitor.repository.mongo.ts @@ -102,7 +102,10 @@ class MongoMonitorsRepository implements IMonitorsRepository { private pageOptions = (config: TeamQueryConfig) => { const { page = 0, rowsPerPage = 0, field = "createdAt", order = "desc" } = config ?? {}; const direction: 1 | -1 = order === "asc" ? 1 : -1; - const sort: Record = field === "createdAt" ? { createdAt: direction } : { [field]: direction, createdAt: 1 }; + const sort: Record = { [field]: direction }; + if (field !== "createdAt") { + sort.createdAt = 1; + } return { sort, skip: Math.max(page, 0) * rowsPerPage, limit: rowsPerPage }; }; From 380968472fa76c21f1011c85d668d747e3415dea Mon Sep 17 00:00:00 2001 From: fabiangigler Date: Wed, 23 Sep 2026 13:35:01 +0200 Subject: [PATCH 4/5] Allow monitor sort headers to reset to default --- .../Monitors/Components/DockerMonitorsTable.tsx | 11 ++++------- .../Monitors/Components/MonitorsTable.tsx | 11 ++++------- .../Monitors/Components/PageSpeedMonitorsTable.tsx | 11 ++++------- .../Monitors/Components/UptimeMonitorsTable.tsx | 12 ++++-------- client/src/Utils/MonitorUtils.ts | 10 ++++++++++ 5 files changed, 26 insertions(+), 29 deletions(-) diff --git a/client/src/Pages/Docker/Monitors/Components/DockerMonitorsTable.tsx b/client/src/Pages/Docker/Monitors/Components/DockerMonitorsTable.tsx index ea06557f6..45569b521 100644 --- a/client/src/Pages/Docker/Monitors/Components/DockerMonitorsTable.tsx +++ b/client/src/Pages/Docker/Monitors/Components/DockerMonitorsTable.tsx @@ -8,6 +8,7 @@ import { ColoredLabel, } from "@/Components/design-elements"; import { SPACING } from "@/Utils/Theme/constants"; +import { getNextMonitorSort } from "@/Utils/MonitorUtils"; import type { Header } from "@/Components/design-elements/Table"; import { ActionsMenu, type ActionMenuItem } from "@/Components/actions-menu"; import { ArrowUp, ArrowDown } from "lucide-react"; @@ -105,13 +106,9 @@ export const DockerMonitorsTable = ({ const handleSort = (e: React.MouseEvent, field: string) => { e.preventDefault(); e.stopPropagation(); - if (sortField === field) { - const newOrder = sortOrder === "asc" ? "desc" : "asc"; - setSortOrder(newOrder); - } else { - setSortField(field); - setSortOrder("asc"); - } + const nextSort = getNextMonitorSort(field, sortField, sortOrder); + setSortField(nextSort.field); + setSortOrder(nextSort.order); refetch(); }; diff --git a/client/src/Pages/Infrastructure/Monitors/Components/MonitorsTable.tsx b/client/src/Pages/Infrastructure/Monitors/Components/MonitorsTable.tsx index 567fd3f9e..23bd05056 100644 --- a/client/src/Pages/Infrastructure/Monitors/Components/MonitorsTable.tsx +++ b/client/src/Pages/Infrastructure/Monitors/Components/MonitorsTable.tsx @@ -9,6 +9,7 @@ import { ColoredLabel, } from "@/Components/design-elements"; import { SPACING } from "@/Utils/Theme/constants"; +import { getNextMonitorSort } from "@/Utils/MonitorUtils"; import type { Header } from "@/Components/design-elements/Table"; import { ActionsMenu, type ActionMenuItem } from "@/Components/actions-menu"; import { ArrowUp, ArrowDown } from "lucide-react"; @@ -100,13 +101,9 @@ export const InfraMonitorsTable = ({ const handleSort = (e: React.MouseEvent, field: string) => { e.preventDefault(); e.stopPropagation(); - if (sortField === field) { - const newOrder = sortOrder === "asc" ? "desc" : "asc"; - setSortOrder(newOrder); - } else { - setSortField(field); - setSortOrder("asc"); - } + const nextSort = getNextMonitorSort(field, sortField, sortOrder); + setSortField(nextSort.field); + setSortOrder(nextSort.order); refetch(); }; diff --git a/client/src/Pages/PageSpeed/Monitors/Components/PageSpeedMonitorsTable.tsx b/client/src/Pages/PageSpeed/Monitors/Components/PageSpeedMonitorsTable.tsx index 9d1789264..f4421b3ed 100644 --- a/client/src/Pages/PageSpeed/Monitors/Components/PageSpeedMonitorsTable.tsx +++ b/client/src/Pages/PageSpeed/Monitors/Components/PageSpeedMonitorsTable.tsx @@ -9,6 +9,7 @@ import { ColoredLabel, } from "@/Components/design-elements"; import { LAYOUT, SPACING } from "@/Utils/Theme/constants"; +import { getNextMonitorSort } from "@/Utils/MonitorUtils"; import { HistogramPageSpeed } from "@/Components/monitors"; import { ArrowDown, ArrowUp } from "lucide-react"; import type { Header } from "@/Components/design-elements/Table"; @@ -81,13 +82,9 @@ export const PageSpeedMonitorsTable = ({ const handleSort = (e: any, field: string) => { e.preventDefault(); e.stopPropagation(); - if (sortField === field) { - const newOrder = sortOrder === "asc" ? "desc" : "asc"; - setSortOrder(newOrder); - } else { - setSortField(field); - setSortOrder("asc"); - } + const nextSort = getNextMonitorSort(field, sortField, sortOrder); + setSortField(nextSort.field); + setSortOrder(nextSort.order); refetch(); }; diff --git a/client/src/Pages/Uptime/Monitors/Components/UptimeMonitorsTable.tsx b/client/src/Pages/Uptime/Monitors/Components/UptimeMonitorsTable.tsx index 1d98ddc79..e605439b9 100644 --- a/client/src/Pages/Uptime/Monitors/Components/UptimeMonitorsTable.tsx +++ b/client/src/Pages/Uptime/Monitors/Components/UptimeMonitorsTable.tsx @@ -25,7 +25,7 @@ import type { RootState } from "@/Types/state"; import { Checkbox } from "@/Components/inputs"; import type { Tag } from "@/Types/Tag"; import { SPACING } from "@/Utils/Theme/constants"; -import { getUptimePercentageColor } from "@/Utils/MonitorUtils"; +import { getNextMonitorSort, getUptimePercentageColor } from "@/Utils/MonitorUtils"; import { formatPercentage } from "@/Utils/FormatUtils"; interface MonitorTableProps { @@ -91,13 +91,9 @@ export const MonitorTable = ({ const handleSort = (e: React.MouseEvent, field: string) => { e.preventDefault(); e.stopPropagation(); - if (sortField === field) { - const newOrder = sortOrder === "asc" ? "desc" : "asc"; - setSortOrder(newOrder); - } else { - setSortField(field); - setSortOrder("asc"); - } + const nextSort = getNextMonitorSort(field, sortField, sortOrder); + setSortField(nextSort.field); + setSortOrder(nextSort.order); refetch(); }; diff --git a/client/src/Utils/MonitorUtils.ts b/client/src/Utils/MonitorUtils.ts index c8bbca168..681b2f637 100644 --- a/client/src/Utils/MonitorUtils.ts +++ b/client/src/Utils/MonitorUtils.ts @@ -10,6 +10,16 @@ import { type DockerLogLine, } from "@/Types/Check"; +export const getNextMonitorSort = ( + field: string, + sortField: string, + sortOrder: "asc" | "desc" +): { field: string; order: "asc" | "desc" } => { + if (field !== sortField) return { field, order: "asc" }; + if (sortOrder === "asc") return { field, order: "desc" }; + return { field: "", order: "asc" }; +}; + export const getMonitorPath = (type: MonitorType): string => { const pathMap: Record = { http: "uptime", From ced90211a022c5f70f86dc36be79b4c21fb9988e Mon Sep 17 00:00:00 2001 From: fabiangigler Date: Fri, 25 Sep 2026 11:04:24 +0200 Subject: [PATCH 5/5] apply monitor sorting feedback --- client/src/Features/UI/uiSlice.ts | 22 +++++++------------ client/src/Hooks/useMonitorListController.ts | 20 +++++------------ .../Components/DockerMonitorsTable.tsx | 13 +++++------ client/src/Pages/Docker/Monitors/index.tsx | 3 +-- .../Monitors/Components/MonitorsTable.tsx | 13 +++++------ .../Pages/Infrastructure/Monitors/index.tsx | 3 +-- .../Components/PageSpeedMonitorsTable.tsx | 13 +++++------ client/src/Pages/PageSpeed/Monitors/index.tsx | 3 +-- .../Components/UptimeMonitorsTable.tsx | 13 +++++------ client/src/Pages/Uptime/Monitors/index.tsx | 3 +-- client/src/Types/Query.ts | 3 +++ client/src/Utils/MonitorUtils.ts | 5 +++-- 12 files changed, 43 insertions(+), 71 deletions(-) diff --git a/client/src/Features/UI/uiSlice.ts b/client/src/Features/UI/uiSlice.ts index 644d411a6..9a19b7c64 100644 --- a/client/src/Features/UI/uiSlice.ts +++ b/client/src/Features/UI/uiSlice.ts @@ -1,4 +1,5 @@ import { dashboardCardKeys, type DashboardCardKey } from "@/Types/Dashboard"; +import type { SortOrder } from "@/Types/Query"; import { createSlice, type PayloadAction } from "@reduxjs/toolkit"; type ThemeMode = "light" | "dark"; @@ -16,7 +17,7 @@ type TableName = interface TableState { rowsPerPage: number; sortField?: string; - sortOrder?: "asc" | "desc"; + sortOrder?: SortOrder; } interface SidebarState { @@ -96,19 +97,13 @@ const uiSlice = createSlice({ const { table, value } = action.payload; state[table].rowsPerPage = value; }, - setTableSortField: ( + setTableSort: ( state, - action: PayloadAction<{ table: TableName; value: string }> + action: PayloadAction<{ table: TableName; field: string; order: SortOrder }> ) => { - const { table, value } = action.payload; - state[table].sortField = value; - }, - setTableSortOrder: ( - state, - action: PayloadAction<{ table: TableName; value: "asc" | "desc" }> - ) => { - const { table, value } = action.payload; - state[table].sortOrder = value; + const { table, field, order } = action.payload; + state[table].sortField = field; + state[table].sortOrder = order; }, toggleSidebar: (state) => { state.sidebar.collapsed = !state.sidebar.collapsed; @@ -147,8 +142,7 @@ export type { UIState, ThemeMode, ChartType, TableName }; export default uiSlice.reducer; export const { setRowsPerPage, - setTableSortField, - setTableSortOrder, + setTableSort, toggleSidebar, setCollapsed, setMode, diff --git a/client/src/Hooks/useMonitorListController.ts b/client/src/Hooks/useMonitorListController.ts index 1c73c8a19..a7364cd60 100644 --- a/client/src/Hooks/useMonitorListController.ts +++ b/client/src/Hooks/useMonitorListController.ts @@ -1,9 +1,4 @@ -import { - setRowsPerPage, - setTableSortField, - setTableSortOrder, - type TableName, -} from "@/Features/UI/uiSlice"; +import { setRowsPerPage, setTableSort, type TableName } from "@/Features/UI/uiSlice"; import { useDelete, useGet } from "@/Hooks/UseApi"; import { useBulkMonitorActions } from "@/Hooks/useBulkMonitorActions"; import useDebounce from "@/Hooks/useDebounce"; @@ -15,6 +10,7 @@ import { type MonitorType, } from "@/Types/Monitor"; import type { Tag } from "@/Types/Tag"; +import type { SortOrder } from "@/Types/Query"; import { useCallback, useMemo, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; @@ -140,13 +136,8 @@ export const useMonitorListController = (config: MonitorListConfig) => { setPage(0); }; - const setSortField = (value: string) => { - dispatch(setTableSortField({ value, table: config.rowsPerPageTable })); - setPage(0); - }; - - const setSortOrder = (value: "asc" | "desc") => { - dispatch(setTableSortOrder({ value, table: config.rowsPerPageTable })); + const setSort = (field: string, order: SortOrder) => { + dispatch(setTableSort({ field, order, table: config.rowsPerPageTable })); setPage(0); }; @@ -204,9 +195,8 @@ export const useMonitorListController = (config: MonitorListConfig) => { rowsPerPage, handleSetRowsPerPage, sortField, - setSortField, sortOrder, - setSortOrder, + setSort, // Delete selectedMonitor, diff --git a/client/src/Pages/Docker/Monitors/Components/DockerMonitorsTable.tsx b/client/src/Pages/Docker/Monitors/Components/DockerMonitorsTable.tsx index 45569b521..714ca0c49 100644 --- a/client/src/Pages/Docker/Monitors/Components/DockerMonitorsTable.tsx +++ b/client/src/Pages/Docker/Monitors/Components/DockerMonitorsTable.tsx @@ -21,6 +21,7 @@ import { usePost } from "@/Hooks/UseApi"; import type { Monitor } from "@/Types/Monitor"; import type { Tag } from "@/Types/Tag"; +import type { SortOrder } from "@/Types/Query"; import type { DockerContainerSummary } from "@/Types/Check"; import { Checkbox } from "@/Components/inputs"; @@ -35,9 +36,8 @@ interface DockerMonitorsTableProps { refetch: () => void; setSelectedMonitor: (monitor: Monitor | null) => void; sortField: string; - setSortField: (field: string) => void; - sortOrder: "asc" | "desc"; - setSortOrder: (order: "asc" | "desc") => void; + sortOrder: SortOrder; + setSort: (field: string, order: SortOrder) => void; count: number; page: number; setPage: (page: number) => void; @@ -53,9 +53,8 @@ export const DockerMonitorsTable = ({ refetch, setSelectedMonitor, sortField, - setSortField, sortOrder, - setSortOrder, + setSort, count, page, setPage, @@ -107,9 +106,7 @@ export const DockerMonitorsTable = ({ e.preventDefault(); e.stopPropagation(); const nextSort = getNextMonitorSort(field, sortField, sortOrder); - setSortField(nextSort.field); - setSortOrder(nextSort.order); - refetch(); + setSort(nextSort.field, nextSort.order); }; const getActions = (monitor: Monitor): ActionMenuItem[] => { diff --git a/client/src/Pages/Docker/Monitors/index.tsx b/client/src/Pages/Docker/Monitors/index.tsx index 96d13abbf..f71bc7b9c 100644 --- a/client/src/Pages/Docker/Monitors/index.tsx +++ b/client/src/Pages/Docker/Monitors/index.tsx @@ -30,9 +30,8 @@ const DockerMonitorsPage = () => { setPage={c.setPage} rowsPerPage={c.rowsPerPage} sortField={c.sortField} - setSortField={c.setSortField} sortOrder={c.sortOrder} - setSortOrder={c.setSortOrder} + setSort={c.setSort} setRowsPerPage={c.handleSetRowsPerPage} selectedRows={c.selectedRows} onSelectionChange={c.setSelectedRows} diff --git a/client/src/Pages/Infrastructure/Monitors/Components/MonitorsTable.tsx b/client/src/Pages/Infrastructure/Monitors/Components/MonitorsTable.tsx index 23bd05056..aaa9cb660 100644 --- a/client/src/Pages/Infrastructure/Monitors/Components/MonitorsTable.tsx +++ b/client/src/Pages/Infrastructure/Monitors/Components/MonitorsTable.tsx @@ -22,6 +22,7 @@ import { usePost } from "@/Hooks/UseApi"; import type { Monitor } from "@/Types/Monitor"; import type { Tag } from "@/Types/Tag"; +import type { SortOrder } from "@/Types/Query"; import { Checkbox } from "@/Components/inputs"; interface InfraMonitorsTableProps { @@ -30,9 +31,8 @@ interface InfraMonitorsTableProps { refetch: () => void; setSelectedMonitor: (monitor: Monitor | null) => void; sortField: string; - setSortField: (field: string) => void; - sortOrder: "asc" | "desc"; - setSortOrder: (order: "asc" | "desc") => void; + sortOrder: SortOrder; + setSort: (field: string, order: SortOrder) => void; count: number; page: number; setPage: (page: number) => void; @@ -48,9 +48,8 @@ export const InfraMonitorsTable = ({ refetch, setSelectedMonitor, sortField, - setSortField, sortOrder, - setSortOrder, + setSort, count, page, setPage, @@ -102,9 +101,7 @@ export const InfraMonitorsTable = ({ e.preventDefault(); e.stopPropagation(); const nextSort = getNextMonitorSort(field, sortField, sortOrder); - setSortField(nextSort.field); - setSortOrder(nextSort.order); - refetch(); + setSort(nextSort.field, nextSort.order); }; const getActions = (monitor: Monitor): ActionMenuItem[] => { diff --git a/client/src/Pages/Infrastructure/Monitors/index.tsx b/client/src/Pages/Infrastructure/Monitors/index.tsx index 5346f353c..e5bda316a 100644 --- a/client/src/Pages/Infrastructure/Monitors/index.tsx +++ b/client/src/Pages/Infrastructure/Monitors/index.tsx @@ -31,9 +31,8 @@ const InfrastructureMonitors = () => { setPage={c.setPage} rowsPerPage={c.rowsPerPage} sortField={c.sortField} - setSortField={c.setSortField} sortOrder={c.sortOrder} - setSortOrder={c.setSortOrder} + setSort={c.setSort} setRowsPerPage={c.handleSetRowsPerPage} selectedRows={c.selectedRows} onSelectionChange={c.setSelectedRows} diff --git a/client/src/Pages/PageSpeed/Monitors/Components/PageSpeedMonitorsTable.tsx b/client/src/Pages/PageSpeed/Monitors/Components/PageSpeedMonitorsTable.tsx index f4421b3ed..a75adadf8 100644 --- a/client/src/Pages/PageSpeed/Monitors/Components/PageSpeedMonitorsTable.tsx +++ b/client/src/Pages/PageSpeed/Monitors/Components/PageSpeedMonitorsTable.tsx @@ -23,6 +23,7 @@ import { usePatch } from "@/Hooks/UseApi"; import type { Monitor, MonitorWithChecks } from "@/Types/Monitor"; import type { Tag } from "@/Types/Tag"; +import type { SortOrder } from "@/Types/Query"; import type { ActionMenuItem } from "@/Components/actions-menu"; export const PageSpeedMonitorsTable = ({ @@ -31,9 +32,8 @@ export const PageSpeedMonitorsTable = ({ refetch, setSelectedMonitor, sortField, - setSortField, sortOrder, - setSortOrder, + setSort, count, page, setPage, @@ -45,9 +45,8 @@ export const PageSpeedMonitorsTable = ({ refetch: Function; setSelectedMonitor: Function; sortField: string; - setSortField: (field: string) => void; - sortOrder: "asc" | "desc"; - setSortOrder: (order: "asc" | "desc") => void; + sortOrder: SortOrder; + setSort: (field: string, order: SortOrder) => void; count: number; page: number; setPage: (page: number) => void; @@ -83,9 +82,7 @@ export const PageSpeedMonitorsTable = ({ e.preventDefault(); e.stopPropagation(); const nextSort = getNextMonitorSort(field, sortField, sortOrder); - setSortField(nextSort.field); - setSortOrder(nextSort.order); - refetch(); + setSort(nextSort.field, nextSort.order); }; const getActions = (monitor: Monitor): ActionMenuItem[] => { diff --git a/client/src/Pages/PageSpeed/Monitors/index.tsx b/client/src/Pages/PageSpeed/Monitors/index.tsx index 3eb597fa6..05ed838b3 100644 --- a/client/src/Pages/PageSpeed/Monitors/index.tsx +++ b/client/src/Pages/PageSpeed/Monitors/index.tsx @@ -46,9 +46,8 @@ const PageSpeedMonitorsPage = () => { setPage={c.setPage} rowsPerPage={c.rowsPerPage} sortField={c.sortField} - setSortField={c.setSortField} sortOrder={c.sortOrder} - setSortOrder={c.setSortOrder} + setSort={c.setSort} setRowsPerPage={c.handleSetRowsPerPage} /> diff --git a/client/src/Pages/Uptime/Monitors/Components/UptimeMonitorsTable.tsx b/client/src/Pages/Uptime/Monitors/Components/UptimeMonitorsTable.tsx index e605439b9..726938380 100644 --- a/client/src/Pages/Uptime/Monitors/Components/UptimeMonitorsTable.tsx +++ b/client/src/Pages/Uptime/Monitors/Components/UptimeMonitorsTable.tsx @@ -24,6 +24,7 @@ import type { ActionMenuItem } from "@/Components/actions-menu"; import type { RootState } from "@/Types/state"; import { Checkbox } from "@/Components/inputs"; import type { Tag } from "@/Types/Tag"; +import type { SortOrder } from "@/Types/Query"; import { SPACING } from "@/Utils/Theme/constants"; import { getNextMonitorSort, getUptimePercentageColor } from "@/Utils/MonitorUtils"; import { formatPercentage } from "@/Utils/FormatUtils"; @@ -34,9 +35,8 @@ interface MonitorTableProps { refetch: () => void; setSelectedMonitor: (monitor: Monitor | null) => void; sortField: string; - setSortField: (field: string) => void; - sortOrder: "asc" | "desc"; - setSortOrder: (order: "asc" | "desc") => void; + sortOrder: SortOrder; + setSort: (field: string, order: SortOrder) => void; count: number; page: number; setPage: (page: number) => void; @@ -52,9 +52,8 @@ export const MonitorTable = ({ refetch, setSelectedMonitor, sortField, - setSortField, sortOrder, - setSortOrder, + setSort, count, page, setPage, @@ -92,9 +91,7 @@ export const MonitorTable = ({ e.preventDefault(); e.stopPropagation(); const nextSort = getNextMonitorSort(field, sortField, sortOrder); - setSortField(nextSort.field); - setSortOrder(nextSort.order); - refetch(); + setSort(nextSort.field, nextSort.order); }; const isBrowserOpenable = (monitor: Monitor): boolean => { diff --git a/client/src/Pages/Uptime/Monitors/index.tsx b/client/src/Pages/Uptime/Monitors/index.tsx index 642d871d3..f3321ce94 100644 --- a/client/src/Pages/Uptime/Monitors/index.tsx +++ b/client/src/Pages/Uptime/Monitors/index.tsx @@ -30,9 +30,8 @@ const UptimeMonitorsPage = () => { setPage={monitorListController.setPage} rowsPerPage={monitorListController.rowsPerPage} sortField={monitorListController.sortField} - setSortField={monitorListController.setSortField} sortOrder={monitorListController.sortOrder} - setSortOrder={monitorListController.setSortOrder} + setSort={monitorListController.setSort} setRowsPerPage={monitorListController.handleSetRowsPerPage} selectedRows={monitorListController.selectedRows} onSelectionChange={monitorListController.setSelectedRows} diff --git a/client/src/Types/Query.ts b/client/src/Types/Query.ts index 6c0b819b9..1eba5e1c7 100644 --- a/client/src/Types/Query.ts +++ b/client/src/Types/Query.ts @@ -1,2 +1,5 @@ export const DateRanges = ["recent", "hour", "day", "week", "month", "all"] as const; export type DateRange = (typeof DateRanges)[number]; + +export const SortOrders = ["asc", "desc"] as const; +export type SortOrder = (typeof SortOrders)[number]; diff --git a/client/src/Utils/MonitorUtils.ts b/client/src/Utils/MonitorUtils.ts index 681b2f637..8b76c8ded 100644 --- a/client/src/Utils/MonitorUtils.ts +++ b/client/src/Utils/MonitorUtils.ts @@ -1,4 +1,5 @@ import type { MonitorStatus, MonitorType } from "@/Types/Monitor"; +import type { SortOrder } from "@/Types/Query"; import type { PaletteKey } from "@/Utils/Theme/Theme"; import type { ValueType } from "@/Components/design-elements/StatusLabel"; import { @@ -13,8 +14,8 @@ import { export const getNextMonitorSort = ( field: string, sortField: string, - sortOrder: "asc" | "desc" -): { field: string; order: "asc" | "desc" } => { + sortOrder: SortOrder +): { field: string; order: SortOrder } => { if (field !== sortField) return { field, order: "asc" }; if (sortOrder === "asc") return { field, order: "desc" }; return { field: "", order: "asc" };