mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-22 21:06:37 +00:00
✨serverside filter+paginate client resources table
This commit is contained in:
@@ -25,6 +25,11 @@ import CreateInternalResourceDialog from "@app/components/CreateInternalResource
|
||||
import EditInternalResourceDialog from "@app/components/EditInternalResourceDialog";
|
||||
import { orgQueries } from "@app/lib/queries";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { PaginationState } from "@tanstack/react-table";
|
||||
import { ControlledDataTable } from "./ui/controlled-data-table";
|
||||
import { useNavigationContext } from "@app/hooks/useNavigationContext";
|
||||
import { useDebouncedCallback } from "use-debounce";
|
||||
import { ColumnFilterButton } from "./ColumnFilterButton";
|
||||
|
||||
export type InternalResourceRow = {
|
||||
id: number;
|
||||
@@ -51,18 +56,22 @@ export type InternalResourceRow = {
|
||||
type ClientResourcesTableProps = {
|
||||
internalResources: InternalResourceRow[];
|
||||
orgId: string;
|
||||
defaultSort?: {
|
||||
id: string;
|
||||
desc: boolean;
|
||||
};
|
||||
pagination: PaginationState;
|
||||
rowCount: number;
|
||||
};
|
||||
|
||||
export default function ClientResourcesTable({
|
||||
internalResources,
|
||||
orgId,
|
||||
defaultSort
|
||||
pagination,
|
||||
rowCount
|
||||
}: ClientResourcesTableProps) {
|
||||
const router = useRouter();
|
||||
const {
|
||||
navigate: filter,
|
||||
isNavigating: isFiltering,
|
||||
searchParams
|
||||
} = useNavigationContext();
|
||||
const t = useTranslations();
|
||||
|
||||
const { env } = useEnvContext();
|
||||
@@ -180,9 +189,24 @@ export default function ClientResourcesTable({
|
||||
accessorKey: "mode",
|
||||
friendlyName: t("editInternalResourceDialogMode"),
|
||||
header: () => (
|
||||
<span className="p-3">
|
||||
{t("editInternalResourceDialogMode")}
|
||||
</span>
|
||||
<ColumnFilterButton
|
||||
options={[
|
||||
{
|
||||
value: "host",
|
||||
label: t("editInternalResourceDialogModeHost")
|
||||
},
|
||||
{
|
||||
value: "cidr",
|
||||
label: t("editInternalResourceDialogModeCidr")
|
||||
}
|
||||
]}
|
||||
selectedValue={searchParams.get("mode") ?? undefined}
|
||||
onValueChange={(value) => handleFilterChange("mode", value)}
|
||||
searchPlaceholder={t("searchPlaceholder")}
|
||||
emptyMessage={t("emptySearchOptions")}
|
||||
label={t("editInternalResourceDialogMode")}
|
||||
className="p-3"
|
||||
/>
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const resourceRow = row.original;
|
||||
@@ -300,6 +324,37 @@ export default function ClientResourcesTable({
|
||||
}
|
||||
];
|
||||
|
||||
function handleFilterChange(
|
||||
column: string,
|
||||
value: string | undefined | null
|
||||
) {
|
||||
searchParams.delete(column);
|
||||
searchParams.delete("page");
|
||||
|
||||
if (value) {
|
||||
searchParams.set(column, value);
|
||||
}
|
||||
filter({
|
||||
searchParams
|
||||
});
|
||||
}
|
||||
|
||||
const handlePaginationChange = (newPage: PaginationState) => {
|
||||
searchParams.set("page", (newPage.pageIndex + 1).toString());
|
||||
searchParams.set("pageSize", newPage.pageSize.toString());
|
||||
filter({
|
||||
searchParams
|
||||
});
|
||||
};
|
||||
|
||||
const handleSearchChange = useDebouncedCallback((query: string) => {
|
||||
searchParams.set("query", query);
|
||||
searchParams.delete("page");
|
||||
filter({
|
||||
searchParams
|
||||
});
|
||||
}, 300);
|
||||
|
||||
return (
|
||||
<>
|
||||
{selectedInternalResource && (
|
||||
@@ -327,19 +382,20 @@ export default function ClientResourcesTable({
|
||||
/>
|
||||
)}
|
||||
|
||||
<DataTable
|
||||
<ControlledDataTable
|
||||
columns={internalColumns}
|
||||
data={internalResources}
|
||||
persistPageSize="internal-resources"
|
||||
rows={internalResources}
|
||||
tableId="internal-resources"
|
||||
searchPlaceholder={t("resourcesSearch")}
|
||||
searchColumn="name"
|
||||
onAdd={() => setIsCreateDialogOpen(true)}
|
||||
addButtonText={t("resourceAdd")}
|
||||
onSearch={handleSearchChange}
|
||||
onRefresh={refreshData}
|
||||
onPaginationChange={handlePaginationChange}
|
||||
pagination={pagination}
|
||||
rowCount={rowCount}
|
||||
isRefreshing={isRefreshing}
|
||||
defaultSort={defaultSort}
|
||||
enableColumnVisibility={true}
|
||||
persistColumnVisibility="internal-resources"
|
||||
enableColumnVisibility
|
||||
columnVisibility={{
|
||||
niceId: false,
|
||||
aliasAddress: false
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
|
||||
import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog";
|
||||
import CopyToClipboard from "@app/components/CopyToClipboard";
|
||||
import { DataTable } from "@app/components/ui/data-table";
|
||||
import { ExtendedColumnDef } from "@app/components/ui/data-table";
|
||||
import { Button } from "@app/components/ui/button";
|
||||
import { ExtendedColumnDef } from "@app/components/ui/data-table";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
@@ -14,13 +13,14 @@ import {
|
||||
import { InfoPopup } from "@app/components/ui/info-popup";
|
||||
import { Switch } from "@app/components/ui/switch";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
import { useNavigationContext } from "@app/hooks/useNavigationContext";
|
||||
import { toast } from "@app/hooks/useToast";
|
||||
import { createApiClient, formatAxiosError } from "@app/lib/api";
|
||||
import { UpdateResourceResponse } from "@server/routers/resource";
|
||||
import type { PaginationState } from "@tanstack/react-table";
|
||||
import { AxiosResponse } from "axios";
|
||||
import {
|
||||
ArrowRight,
|
||||
ArrowUpDown,
|
||||
CheckCircle2,
|
||||
ChevronDown,
|
||||
Clock,
|
||||
@@ -31,14 +31,12 @@ import {
|
||||
} from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import Link from "next/link";
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState, useTransition } from "react";
|
||||
import { ControlledDataTable } from "./ui/controlled-data-table";
|
||||
import type { PaginationState } from "@tanstack/react-table";
|
||||
import { useNavigationContext } from "@app/hooks/useNavigationContext";
|
||||
import { useDebouncedCallback } from "use-debounce";
|
||||
import z from "zod";
|
||||
import { ColumnFilterButton } from "./ColumnFilterButton";
|
||||
import { ControlledDataTable } from "./ui/controlled-data-table";
|
||||
|
||||
export type TargetHealth = {
|
||||
targetId: number;
|
||||
@@ -584,10 +582,6 @@ export default function ProxyResourcesTable({
|
||||
});
|
||||
}, 300);
|
||||
|
||||
console.log({
|
||||
rowCount
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{selectedResource && (
|
||||
|
||||
@@ -130,7 +130,8 @@ export function ControlledDataTable<TData, TValue>({
|
||||
});
|
||||
|
||||
console.log({
|
||||
pagination
|
||||
pagination,
|
||||
rowCount
|
||||
});
|
||||
|
||||
const table = useReactTable({
|
||||
|
||||
Reference in New Issue
Block a user