Persist monitor list sorting
This commit is contained in:
1 parent
a5e66318b5
commit
2a45b4d46f
4 files changed
+74
-7
No files matched your search
@@ -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,
|
||||
|
||||
@@ -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<MonitorType[]>([]);
|
||||
@@ -36,8 +43,6 @@ export const useMonitorListController = (config: MonitorListConfig) => {
|
||||
const [selectedTags, setSelectedTags] = useState<string[]>([]);
|
||||
const [page, setPage] = useState<number>(0);
|
||||
const [search, setSearch] = useState<string>("");
|
||||
const [sortField, setSortField] = useState<string>(config.initialSortField ?? "");
|
||||
const [sortOrder, setSortOrder] = useState<"asc" | "desc">("asc");
|
||||
const [selectedMonitor, setSelectedMonitor] = useState<Monitor | null>(null);
|
||||
const debouncedSearch = useDebounce<string>(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 ||
|
||||
|
||||
@@ -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<string, 1 | -1> = 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<Monitor[]> => {
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in new issue
Block a user