Skip to content

Commit 9f680d8

Browse files
committed
Use tanstack query consitently for all table view.
1 parent 3c83c74 commit 9f680d8

File tree

7 files changed

+291
-310
lines changed

7 files changed

+291
-310
lines changed

trailbase-assets/js/admin/src/components/Table.tsx

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,6 @@ export function safeParseInt(v: string | undefined): number | undefined {
5252
return undefined;
5353
}
5454

55-
export function defaultPaginationState(opts?: {
56-
index?: number;
57-
size?: number;
58-
}): PaginationState {
59-
return {
60-
pageIndex: opts?.index ?? 0,
61-
pageSize: opts?.size ?? 20,
62-
};
63-
}
64-
6555
type Props<TData, TValue> = {
6656
columns: Accessor<ColumnDef<TData, TValue>[]>;
6757
data: Accessor<TData[] | undefined>;
@@ -280,7 +270,7 @@ function PaginationControl<TData>(props: {
280270
const table = () => props.table;
281271

282272
const PerPage = () => (
283-
<div class="flex items-center space-x-2">
273+
<div class="flex items-center space-x-2 py-1">
284274
<Select
285275
value={table().getState().pagination.pageSize}
286276
onChange={(value) => {

trailbase-assets/js/admin/src/components/accounts/AccountsPage.tsx

Lines changed: 52 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { createSignal, Match, Show, Switch, Suspense } from "solid-js";
2+
import { createWritableMemo } from "@solid-primitives/memo";
23
import type { Setter } from "solid-js";
34
import { useSearchParams } from "@solidjs/router";
45
import { TbRefresh, TbCrown, TbEdit, TbTrash } from "solid-icons/tb";
56
import type { DialogTriggerProps } from "@kobalte/core/dialog";
67
import { createForm } from "@tanstack/solid-form";
7-
import { useInfiniteQuery, useQueryClient } from "@tanstack/solid-query";
8+
import { useQuery, useQueryClient } from "@tanstack/solid-query";
89
import { createColumnHelper } from "@tanstack/solid-table";
910
import type { ColumnDef, PaginationState } from "@tanstack/solid-table";
1011

@@ -40,7 +41,6 @@ import { SafeSheet, SheetContainer } from "@/components/SafeSheet";
4041

4142
import type { UpdateUserRequest } from "@bindings/UpdateUserRequest";
4243
import type { UserJson } from "@bindings/UserJson";
43-
import { ListUsersResponse } from "@bindings/ListUsersResponse";
4444

4545
const columnHelper = createColumnHelper<UserJson>();
4646

@@ -242,13 +242,22 @@ function EditSheetContent(props: {
242242
}
243243

244244
export function AccountsPage() {
245-
// NOTE: pageIndex is not controlled via the search params since we cannot
246-
// just jump to page N, we need to cursor from the beginning.
247-
const [pageIndex, setPageIndex] = createSignal(0);
248245
const [searchParams, setSearchParams] = useSearchParams<{
249246
filter?: string;
250247
pageSize?: string;
251248
}>();
249+
// Reset when search params change
250+
const reset = () => {
251+
return [searchParams.pageSize, searchParams.filter];
252+
};
253+
const [pageIndex, setPageIndex] = createWritableMemo<number>(() => {
254+
reset();
255+
return 0;
256+
});
257+
const [cursors, setCursors] = createWritableMemo<string[]>(() => {
258+
reset();
259+
return [];
260+
});
252261

253262
const pagination = (): PaginationState => {
254263
return {
@@ -257,27 +266,39 @@ export function AccountsPage() {
257266
};
258267
};
259268

260-
const setFilter = (filter: string | undefined) =>
269+
const setFilter = (filter: string | undefined) => {
270+
setPageIndex(0);
261271
setSearchParams({
262272
...searchParams,
263273
filter,
264274
});
275+
};
265276

266277
// NOTE: admin user endpoint doesn't support offset, we have to cursor through
267278
// and cannot just jump to page N.
268-
const users = useInfiniteQuery(() => ({
269-
queryKey: ["users", searchParams],
270-
initialPageParam: null,
271-
getNextPageParam: (lastPage: ListUsersResponse, _pages) => lastPage.cursor,
272-
queryFn: async ({ pageParam }: { pageParam: string | null }) => {
273-
const cursor: string | null = pageParam;
274-
console.debug("account cursor", cursor);
275-
276-
return await fetchUsers(
279+
const users = useQuery(() => ({
280+
queryKey: [
281+
"users",
282+
searchParams.filter,
283+
pagination().pageSize,
284+
pagination().pageIndex,
285+
],
286+
queryFn: async () => {
287+
const p = pagination();
288+
const c = cursors();
289+
290+
const response = await fetchUsers(
277291
searchParams.filter,
278292
pagination().pageSize,
279-
cursor,
293+
c[p.pageIndex - 1],
280294
);
295+
296+
const cursor = response.cursor;
297+
if (cursor && p.pageIndex >= c.length) {
298+
setCursors([...c, cursor]);
299+
}
300+
301+
return response;
281302
},
282303
}));
283304
const client = useQueryClient();
@@ -290,8 +311,6 @@ export function AccountsPage() {
290311
const [editUser, setEditUser] = createSignal<UserJson | undefined>();
291312

292313
const columns = () => buildColumns(setEditUser, refetch);
293-
const currentPage = (): ListUsersResponse | undefined =>
294-
(users.data?.pages ?? [])[pagination().pageIndex];
295314

296315
return (
297316
<div class="h-dvh overflow-y-auto">
@@ -335,12 +354,12 @@ export function AccountsPage() {
335354
<span>Loading</span>
336355
</Match>
337356

338-
<Match when={currentPage()}>
357+
<Match when={users.data}>
339358
<div class="w-full space-y-2.5">
340359
<DataTable
341360
columns={columns}
342-
data={() => currentPage()?.users}
343-
rowCount={Number(users.data?.pages[0]?.total_row_count ?? -1)}
361+
data={() => users.data!.users}
362+
rowCount={Number(users.data!.total_row_count ?? -1)}
344363
pagination={pagination()}
345364
onPaginationChange={(
346365
p:
@@ -351,13 +370,18 @@ export function AccountsPage() {
351370
pageSize,
352371
pageIndex,
353372
}: PaginationState) {
354-
setPageIndex(pageIndex);
355-
users.fetchNextPage();
356-
357-
setSearchParams({
358-
...searchParams,
359-
pageSize,
360-
});
373+
const current = pagination();
374+
if (current.pageSize !== pageSize) {
375+
setSearchParams({
376+
...searchParams,
377+
pageSize,
378+
});
379+
return;
380+
}
381+
382+
if (current.pageIndex != pageIndex) {
383+
setPageIndex(pageIndex);
384+
}
361385
}
362386

363387
if (typeof p === "function") {

trailbase-assets/js/admin/src/components/logs/LogsPage.tsx

Lines changed: 70 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ import {
88
onMount,
99
} from "solid-js";
1010
import { useSearchParams } from "@solidjs/router";
11+
import { createWritableMemo } from "@solid-primitives/memo";
1112
import { createColumnHelper } from "@tanstack/solid-table";
1213
import type { ColumnDef, PaginationState } from "@tanstack/solid-table";
13-
import { useInfiniteQuery, useQueryClient } from "@tanstack/solid-query";
14+
import { useQuery, useQueryClient } from "@tanstack/solid-query";
1415
import { Chart } from "chart.js/auto";
1516
import type {
1617
ChartData,
@@ -41,7 +42,6 @@ import { DataTable, safeParseInt } from "@/components/Table";
4142
import { FilterBar } from "@/components/FilterBar";
4243

4344
import { getLogs } from "@/lib/logs";
44-
import type { ListLogsResponse } from "@bindings/ListLogsResponse";
4545

4646
import countriesGeoJSON from "@/assets/countries-110m.json";
4747

@@ -119,13 +119,22 @@ const columns: ColumnDef<LogJson>[] = [
119119

120120
// Value is the previous value in case this isn't the first fetch.
121121
export function LogsPage() {
122-
// NOTE: pageIndex is not controlled via the search params since we cannot
123-
// just jump to page N, we need to cursor from the beginning.
124-
const [pageIndex, setPageIndex] = createSignal(0);
125122
const [searchParams, setSearchParams] = useSearchParams<{
126123
filter?: string;
127124
pageSize?: string;
128125
}>();
126+
// Reset when search params change
127+
const reset = () => {
128+
return [searchParams.pageSize, searchParams.filter];
129+
};
130+
const [pageIndex, setPageIndex] = createWritableMemo<number>(() => {
131+
reset();
132+
return 0;
133+
});
134+
const [cursors, setCursors] = createWritableMemo<string[]>(() => {
135+
reset();
136+
return [];
137+
});
129138

130139
const pagination = (): PaginationState => {
131140
return {
@@ -134,24 +143,39 @@ export function LogsPage() {
134143
};
135144
};
136145

137-
const setFilter = (filter: string | undefined) =>
146+
const setFilter = (filter: string | undefined) => {
147+
setPageIndex(0);
138148
setSearchParams({
139149
...searchParams,
140150
filter,
141151
});
152+
};
142153

143154
// NOTE: admin user endpoint doesn't support offset, we have to cursor through
144155
// and cannot just jump to page N.
145-
const logsFetch = useInfiniteQuery(() => ({
146-
queryKey: ["logs", searchParams],
147-
initialPageParam: null,
148-
getNextPageParam: (lastPage: ListLogsResponse, _pages): string | null => {
149-
return lastPage.cursor;
150-
},
151-
queryFn: async ({ pageParam }: { pageParam: string | null }) => {
152-
const cursor: string | null = pageParam;
153-
console.debug("logs cursor", cursor);
154-
return await getLogs(pagination().pageSize, searchParams.filter, cursor);
156+
const logsFetch = useQuery(() => ({
157+
queryKey: [
158+
"logs",
159+
searchParams.filter,
160+
pagination().pageSize,
161+
pagination().pageIndex,
162+
],
163+
queryFn: async () => {
164+
const p = pagination();
165+
const c = cursors();
166+
167+
const response = await getLogs(
168+
p.pageSize,
169+
searchParams.filter,
170+
c[p.pageIndex - 1],
171+
);
172+
173+
const cursor = response.cursor;
174+
if (cursor && p.pageIndex >= c.length) {
175+
setCursors([...c, cursor]);
176+
}
177+
178+
return response;
155179
},
156180
}));
157181
const client = useQueryClient();
@@ -161,9 +185,6 @@ export function LogsPage() {
161185
});
162186
};
163187

164-
const currentPage = (): ListLogsResponse | undefined =>
165-
(logsFetch.data?.pages ?? [])[pagination().pageIndex];
166-
167188
const [showMap, setShowMap] = createSignal(true);
168189
const [showGeoipDialog, setShowGeoipDialog] = createSignal(false);
169190

@@ -200,9 +221,9 @@ export function LogsPage() {
200221
</DialogContent>
201222

202223
<IconButton
203-
disabled={logsFetch.isSuccess}
224+
disabled={!logsFetch.isSuccess}
204225
onClick={() => {
205-
if (logsFetch.data?.pages[0]?.stats?.country_codes) {
226+
if (logsFetch.data?.stats?.country_codes) {
206227
setShowMap((v) => !v);
207228
} else {
208229
setShowGeoipDialog((v) => !v);
@@ -225,26 +246,22 @@ export function LogsPage() {
225246
<span>Loading</span>
226247
</Match>
227248

228-
<Match when={logsFetch.isSuccess}>
229-
{pagination().pageIndex === 0 &&
230-
logsFetch.data?.pages[0]?.stats && (
231-
<div class="mb-4 flex h-[300px] w-full gap-4">
232-
<div class={showMap() ? "w-1/2 grow" : "w-full"}>
233-
<LogsChart stats={logsFetch.data!.pages[0]!.stats!} />
234-
</div>
235-
236-
{showMap() &&
237-
logsFetch.data!.pages[0].stats!.country_codes && (
238-
<div class="flex w-1/2 max-w-[500px] items-center">
239-
<WorldMap
240-
country_codes={
241-
logsFetch.data!.pages[0].stats!.country_codes!
242-
}
243-
/>
244-
</div>
245-
)}
249+
<Match when={logsFetch.data}>
250+
{pagination().pageIndex === 0 && logsFetch.data!.stats && (
251+
<div class="mb-4 flex h-[300px] w-full gap-4">
252+
<div class={showMap() ? "w-1/2 grow" : "w-full"}>
253+
<LogsChart stats={logsFetch.data!.stats!} />
246254
</div>
247-
)}
255+
256+
{showMap() && logsFetch.data!.stats!.country_codes && (
257+
<div class="flex w-1/2 max-w-[500px] items-center">
258+
<WorldMap
259+
country_codes={logsFetch.data!.stats!.country_codes!}
260+
/>
261+
</div>
262+
)}
263+
</div>
264+
)}
248265

249266
<FilterBar
250267
initial={searchParams.filter}
@@ -267,8 +284,8 @@ export function LogsPage() {
267284

268285
<DataTable
269286
columns={() => columns}
270-
data={() => currentPage()?.entries}
271-
rowCount={Number(logsFetch.data?.pages[0]?.total_row_count ?? -1)}
287+
data={() => logsFetch.data!.entries}
288+
rowCount={Number(logsFetch.data!.total_row_count ?? -1)}
272289
pagination={pagination()}
273290
onPaginationChange={(
274291
p:
@@ -279,13 +296,18 @@ export function LogsPage() {
279296
pageSize,
280297
pageIndex,
281298
}: PaginationState) {
282-
setPageIndex(pageIndex);
283-
logsFetch.fetchNextPage();
299+
const current = pagination();
300+
if (current.pageSize !== pageSize) {
301+
setSearchParams({
302+
...searchParams,
303+
pageSize,
304+
});
305+
return;
306+
}
284307

285-
setSearchParams({
286-
...searchParams,
287-
pageSize,
288-
});
308+
if (current.pageIndex != pageIndex) {
309+
setPageIndex(pageIndex);
310+
}
289311
}
290312

291313
if (typeof p === "function") {

0 commit comments

Comments
 (0)