mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2026-05-18 07:40:35 +00:00
Adds column sorting to Nginx tables
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import { IconArrowsSort, IconChevronDown, IconChevronUp } from "@tabler/icons-react";
|
||||
import { flexRender } from "@tanstack/react-table";
|
||||
import type { TableLayoutProps } from "src/components";
|
||||
|
||||
function TableHeader<T>(props: TableLayoutProps<T>) {
|
||||
@@ -11,9 +13,34 @@ function TableHeader<T>(props: TableLayoutProps<T>) {
|
||||
{headerGroup.headers.map((header: any) => {
|
||||
const { column } = header;
|
||||
const { className } = (column.columnDef.meta as any) ?? {};
|
||||
const canSort = column.getCanSort();
|
||||
const sortDir = column.getIsSorted();
|
||||
|
||||
const headerContent = header.isPlaceholder
|
||||
? null
|
||||
: typeof column.columnDef.header === "string"
|
||||
? column.columnDef.header
|
||||
: flexRender(column.columnDef.header, header.getContext());
|
||||
|
||||
const sortIcon = canSort ? (
|
||||
sortDir === "asc" ? (
|
||||
<IconChevronUp size={14} className="ms-1" />
|
||||
) : sortDir === "desc" ? (
|
||||
<IconChevronDown size={14} className="ms-1" />
|
||||
) : (
|
||||
<IconArrowsSort size={14} className="ms-1 opacity-50" />
|
||||
)
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<th key={header.id} className={className}>
|
||||
{typeof column.columnDef.header === "string" ? `${column.columnDef.header}` : null}
|
||||
<th
|
||||
key={header.id}
|
||||
className={className}
|
||||
onClick={canSort ? column.getToggleSortingHandler() : undefined}
|
||||
style={canSort ? { cursor: "pointer", userSelect: "none" } : undefined}
|
||||
>
|
||||
{headerContent}
|
||||
{sortIcon}
|
||||
</th>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { IconDotsVertical, IconEdit, IconPower, IconTrash } from "@tabler/icons-react";
|
||||
import { createColumnHelper, getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
||||
import { useMemo } from "react";
|
||||
import {
|
||||
createColumnHelper,
|
||||
getCoreRowModel,
|
||||
getSortedRowModel,
|
||||
type SortingState,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
import { useMemo, useState } from "react";
|
||||
import type { DeadHost } from "src/api/backend";
|
||||
import {
|
||||
CertificateFormatter,
|
||||
@@ -29,6 +35,7 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog
|
||||
() => [
|
||||
columnHelper.accessor((row: any) => row.owner, {
|
||||
id: "owner",
|
||||
enableSorting: false,
|
||||
cell: (info: any) => {
|
||||
const value = info.getValue();
|
||||
return <GravatarFormatter url={value ? value.avatar : ""} name={value ? value.name : ""} />;
|
||||
@@ -40,6 +47,11 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog
|
||||
columnHelper.accessor((row: any) => row, {
|
||||
id: "domainNames",
|
||||
header: intl.formatMessage({ id: "column.source" }),
|
||||
sortingFn: (a, b) => {
|
||||
const aVal = a.original.domainNames?.[0] ?? "";
|
||||
const bVal = b.original.domainNames?.[0] ?? "";
|
||||
return aVal.localeCompare(bVal);
|
||||
},
|
||||
cell: (info: any) => {
|
||||
const value = info.getValue();
|
||||
return <DomainsFormatter domains={value.domainNames} createdOn={value.createdOn} />;
|
||||
@@ -47,6 +59,7 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog
|
||||
}),
|
||||
columnHelper.accessor((row: any) => row.certificate, {
|
||||
id: "certificate",
|
||||
enableSorting: false,
|
||||
header: intl.formatMessage({ id: "column.ssl" }),
|
||||
cell: (info: any) => {
|
||||
return <CertificateFormatter certificate={info.getValue()} />;
|
||||
@@ -128,10 +141,15 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog
|
||||
[columnHelper, onDelete, onEdit, onDisableToggle],
|
||||
);
|
||||
|
||||
const [sorting, setSorting] = useState<SortingState>([]);
|
||||
|
||||
const tableInstance = useReactTable<DeadHost>({
|
||||
columns,
|
||||
data,
|
||||
state: { sorting },
|
||||
onSortingChange: setSorting,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
rowCount: data.length,
|
||||
meta: {
|
||||
isFetching,
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { IconDotsVertical, IconEdit, IconPower, IconTrash } from "@tabler/icons-react";
|
||||
import { createColumnHelper, getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
||||
import { useMemo } from "react";
|
||||
import {
|
||||
createColumnHelper,
|
||||
getCoreRowModel,
|
||||
getSortedRowModel,
|
||||
type SortingState,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
import { useMemo, useState } from "react";
|
||||
import type { ProxyHost } from "src/api/backend";
|
||||
import {
|
||||
AccessListFormatter,
|
||||
@@ -30,6 +36,7 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog
|
||||
() => [
|
||||
columnHelper.accessor((row: any) => row.owner, {
|
||||
id: "owner",
|
||||
enableSorting: false,
|
||||
cell: (info: any) => {
|
||||
const value = info.getValue();
|
||||
return <GravatarFormatter url={value ? value.avatar : ""} name={value ? value.name : ""} />;
|
||||
@@ -41,6 +48,11 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog
|
||||
columnHelper.accessor((row: any) => row, {
|
||||
id: "domainNames",
|
||||
header: intl.formatMessage({ id: "column.source" }),
|
||||
sortingFn: (a, b) => {
|
||||
const aVal = a.original.domainNames?.[0] ?? "";
|
||||
const bVal = b.original.domainNames?.[0] ?? "";
|
||||
return aVal.localeCompare(bVal);
|
||||
},
|
||||
cell: (info: any) => {
|
||||
const value = info.getValue();
|
||||
return <DomainsFormatter domains={value.domainNames} createdOn={value.createdOn} />;
|
||||
@@ -49,6 +61,11 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog
|
||||
columnHelper.accessor((row: any) => row, {
|
||||
id: "forwardHost",
|
||||
header: intl.formatMessage({ id: "column.destination" }),
|
||||
sortingFn: (a, b) => {
|
||||
const aVal = `${a.original.forwardHost}:${a.original.forwardPort}`;
|
||||
const bVal = `${b.original.forwardHost}:${b.original.forwardPort}`;
|
||||
return aVal.localeCompare(bVal);
|
||||
},
|
||||
cell: (info: any) => {
|
||||
const value = info.getValue();
|
||||
return `${value.forwardScheme}://${value.forwardHost}:${value.forwardPort}`;
|
||||
@@ -56,6 +73,7 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog
|
||||
}),
|
||||
columnHelper.accessor((row: any) => row.certificate, {
|
||||
id: "certificate",
|
||||
enableSorting: false,
|
||||
header: intl.formatMessage({ id: "column.ssl" }),
|
||||
cell: (info: any) => {
|
||||
return <CertificateFormatter certificate={info.getValue()} />;
|
||||
@@ -63,6 +81,7 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog
|
||||
}),
|
||||
columnHelper.accessor((row: any) => row.accessList, {
|
||||
id: "accessList",
|
||||
enableSorting: false,
|
||||
header: intl.formatMessage({ id: "column.access" }),
|
||||
cell: (info: any) => {
|
||||
return <AccessListFormatter access={info.getValue()} />;
|
||||
@@ -144,10 +163,15 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog
|
||||
[columnHelper, onEdit, onDisableToggle, onDelete],
|
||||
);
|
||||
|
||||
const [sorting, setSorting] = useState<SortingState>([]);
|
||||
|
||||
const tableInstance = useReactTable<ProxyHost>({
|
||||
columns,
|
||||
data,
|
||||
state: { sorting },
|
||||
onSortingChange: setSorting,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
rowCount: data.length,
|
||||
meta: {
|
||||
isFetching,
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { IconDotsVertical, IconEdit, IconPower, IconTrash } from "@tabler/icons-react";
|
||||
import { createColumnHelper, getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
||||
import { useMemo } from "react";
|
||||
import {
|
||||
createColumnHelper,
|
||||
getCoreRowModel,
|
||||
getSortedRowModel,
|
||||
type SortingState,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
import { useMemo, useState } from "react";
|
||||
import type { RedirectionHost } from "src/api/backend";
|
||||
import {
|
||||
CertificateFormatter,
|
||||
@@ -29,6 +35,7 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog
|
||||
() => [
|
||||
columnHelper.accessor((row: any) => row.owner, {
|
||||
id: "owner",
|
||||
enableSorting: false,
|
||||
cell: (info: any) => {
|
||||
const value = info.getValue();
|
||||
return <GravatarFormatter url={value ? value.avatar : ""} name={value ? value.name : ""} />;
|
||||
@@ -40,6 +47,11 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog
|
||||
columnHelper.accessor((row: any) => row, {
|
||||
id: "domainNames",
|
||||
header: intl.formatMessage({ id: "column.source" }),
|
||||
sortingFn: (a, b) => {
|
||||
const aVal = a.original.domainNames?.[0] ?? "";
|
||||
const bVal = b.original.domainNames?.[0] ?? "";
|
||||
return aVal.localeCompare(bVal);
|
||||
},
|
||||
cell: (info: any) => {
|
||||
const value = info.getValue();
|
||||
return <DomainsFormatter domains={value.domainNames} createdOn={value.createdOn} />;
|
||||
@@ -68,6 +80,7 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog
|
||||
}),
|
||||
columnHelper.accessor((row: any) => row.certificate, {
|
||||
id: "certificate",
|
||||
enableSorting: false,
|
||||
header: intl.formatMessage({ id: "column.ssl" }),
|
||||
cell: (info: any) => {
|
||||
return <CertificateFormatter certificate={info.getValue()} />;
|
||||
@@ -149,10 +162,15 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog
|
||||
[columnHelper, onEdit, onDisableToggle, onDelete],
|
||||
);
|
||||
|
||||
const [sorting, setSorting] = useState<SortingState>([]);
|
||||
|
||||
const tableInstance = useReactTable<RedirectionHost>({
|
||||
columns,
|
||||
data,
|
||||
state: { sorting },
|
||||
onSortingChange: setSorting,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
rowCount: data.length,
|
||||
meta: {
|
||||
isFetching,
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { IconDotsVertical, IconEdit, IconPower, IconTrash } from "@tabler/icons-react";
|
||||
import { createColumnHelper, getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
||||
import { useMemo } from "react";
|
||||
import {
|
||||
createColumnHelper,
|
||||
getCoreRowModel,
|
||||
getSortedRowModel,
|
||||
type SortingState,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
import { useMemo, useState } from "react";
|
||||
import type { Stream } from "src/api/backend";
|
||||
import {
|
||||
CertificateFormatter,
|
||||
@@ -29,6 +35,7 @@ export default function Table({ data, isFetching, isFiltered, onEdit, onDelete,
|
||||
() => [
|
||||
columnHelper.accessor((row: any) => row.owner, {
|
||||
id: "owner",
|
||||
enableSorting: false,
|
||||
cell: (info: any) => {
|
||||
const value = info.getValue();
|
||||
return <GravatarFormatter url={value ? value.avatar : ""} name={value ? value.name : ""} />;
|
||||
@@ -40,6 +47,7 @@ export default function Table({ data, isFetching, isFiltered, onEdit, onDelete,
|
||||
columnHelper.accessor((row: any) => row, {
|
||||
id: "incomingPort",
|
||||
header: intl.formatMessage({ id: "column.incoming-port" }),
|
||||
sortingFn: (a, b) => (a.original.incomingPort ?? 0) - (b.original.incomingPort ?? 0),
|
||||
cell: (info: any) => {
|
||||
const value = info.getValue();
|
||||
return <ValueWithDateFormatter value={value.incomingPort} createdOn={value.createdOn} />;
|
||||
@@ -48,6 +56,11 @@ export default function Table({ data, isFetching, isFiltered, onEdit, onDelete,
|
||||
columnHelper.accessor((row: any) => row, {
|
||||
id: "forwardHttpCode",
|
||||
header: intl.formatMessage({ id: "column.destination" }),
|
||||
sortingFn: (a, b) => {
|
||||
const aVal = `${a.original.forwardingHost}:${a.original.forwardingPort}`;
|
||||
const bVal = `${b.original.forwardingHost}:${b.original.forwardingPort}`;
|
||||
return aVal.localeCompare(bVal);
|
||||
},
|
||||
cell: (info: any) => {
|
||||
const value = info.getValue();
|
||||
return `${value.forwardingHost}:${value.forwardingPort}`;
|
||||
@@ -55,6 +68,7 @@ export default function Table({ data, isFetching, isFiltered, onEdit, onDelete,
|
||||
}),
|
||||
columnHelper.accessor((row: any) => row, {
|
||||
id: "tcpForwarding",
|
||||
enableSorting: false,
|
||||
header: intl.formatMessage({ id: "column.protocol" }),
|
||||
cell: (info: any) => {
|
||||
const value = info.getValue();
|
||||
@@ -76,6 +90,7 @@ export default function Table({ data, isFetching, isFiltered, onEdit, onDelete,
|
||||
}),
|
||||
columnHelper.accessor((row: any) => row.certificate, {
|
||||
id: "certificate",
|
||||
enableSorting: false,
|
||||
header: intl.formatMessage({ id: "column.ssl" }),
|
||||
cell: (info: any) => {
|
||||
return <CertificateFormatter certificate={info.getValue()} />;
|
||||
@@ -157,10 +172,15 @@ export default function Table({ data, isFetching, isFiltered, onEdit, onDelete,
|
||||
[columnHelper, onEdit, onDisableToggle, onDelete],
|
||||
);
|
||||
|
||||
const [sorting, setSorting] = useState<SortingState>([]);
|
||||
|
||||
const tableInstance = useReactTable<Stream>({
|
||||
columns,
|
||||
data,
|
||||
state: { sorting },
|
||||
onSortingChange: setSorting,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
rowCount: data.length,
|
||||
meta: {
|
||||
isFetching,
|
||||
|
||||
Reference in New Issue
Block a user