From 61e8bed3e0b942fbc9c62c77671bcd18c2ed8ad1 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Sun, 31 May 2026 22:01:10 +0200 Subject: [PATCH] refactor(inbounds): remove column sorter from inbound list Drop the table header sorter on the inbounds page: the sortKey/sortOrder state, the sortedInbounds memo and onChange handler, the per-column sorterFor spreads, the SORT_FNS comparator map, and the now-unused SortKey/SortOrder types. The list renders in DB order. --- .../src/pages/inbounds/list/InboundList.tsx | 37 +++++-------------- frontend/src/pages/inbounds/list/helpers.ts | 19 +--------- frontend/src/pages/inbounds/list/types.ts | 13 ------- .../pages/inbounds/list/useInboundColumns.tsx | 26 ++----------- 4 files changed, 13 insertions(+), 82 deletions(-) diff --git a/frontend/src/pages/inbounds/list/InboundList.tsx b/frontend/src/pages/inbounds/list/InboundList.tsx index 5dfb51fd..d16b6b1b 100644 --- a/frontend/src/pages/inbounds/list/InboundList.tsx +++ b/frontend/src/pages/inbounds/list/InboundList.tsx @@ -25,11 +25,10 @@ import { import { HttpUtil } from '@/utils'; -import { SORT_FNS } from './helpers'; import { buildRowActionsMenu } from './RowActions'; import { useInboundColumns } from './useInboundColumns'; import InboundStatsModal from './InboundStatsModal'; -import type { DBInboundRecord, GeneralAction, InboundListProps, RowAction, SortKey, SortOrder } from './types'; +import type { DBInboundRecord, GeneralAction, InboundListProps, RowAction } from './types'; import './InboundList.css'; export default function InboundList({ @@ -49,8 +48,6 @@ export default function InboundList({ onBulkDelete, }: InboundListProps) { const { t } = useTranslation(); - const [sortKey, setSortKey] = useState(null); - const [sortOrder, setSortOrder] = useState(null); const [statsRecord, setStatsRecord] = useState(null); const [selectedRowKeys, setSelectedRowKeys] = useState([]); @@ -67,14 +64,6 @@ export default function InboundList({ } }, []); - const sortedInbounds = useMemo(() => { - if (!sortKey || !sortOrder) return dbInbounds; - const fn = SORT_FNS[sortKey]; - if (!fn) return dbInbounds; - const sorted = [...dbInbounds].sort((a, b) => fn(a, b, { nodesById, clientCount })); - return sortOrder === 'descend' ? sorted.reverse() : sorted; - }, [dbInbounds, sortKey, sortOrder, nodesById, clientCount]); - const hasAnyRemark = useMemo( () => dbInbounds.some((i) => typeof i.remark === 'string' && i.remark.trim() !== ''), [dbInbounds], @@ -89,11 +78,11 @@ export default function InboundList({ }, []); const selectAll = useCallback((checked: boolean) => { - setSelectedRowKeys(checked ? sortedInbounds.map((i) => i.id) : []); - }, [sortedInbounds]); + setSelectedRowKeys(checked ? dbInbounds.map((i) => i.id) : []); + }, [dbInbounds]); - const allSelected = sortedInbounds.length > 0 && selectedRowKeys.length === sortedInbounds.length; - const someSelected = selectedRowKeys.length > 0 && selectedRowKeys.length < sortedInbounds.length; + const allSelected = dbInbounds.length > 0 && selectedRowKeys.length === dbInbounds.length; + const someSelected = selectedRowKeys.length > 0 && selectedRowKeys.length < dbInbounds.length; const handleBulkDelete = useCallback(async () => { const ok = await onBulkDelete(selectedRowKeys); @@ -108,8 +97,6 @@ export default function InboundList({ subEnable, expireDiff, trafficDiff, - sortKey, - sortOrder, onRowAction, onSwitchEnable, }); @@ -160,7 +147,7 @@ export default function InboundList({ {isMobile ? (
- {sortedInbounds.length === 0 ? ( + {dbInbounds.length === 0 ? (
{t('noData')}
@@ -179,7 +166,7 @@ export default function InboundList({ {selectedRowKeys.length} )}
- {sortedInbounds.map((record) => ( + {dbInbounds.map((record) => (
r.id} rowSelection={{ selectedRowKeys, onChange: (keys: Key[]) => setSelectedRowKeys(keys as number[]), }} - pagination={paginationFor(sortedInbounds)} + pagination={paginationFor(dbInbounds)} scroll={{ x: 1000 }} style={{ marginTop: 10 }} size="small" @@ -235,12 +222,6 @@ export default function InboundList({
), }} - onChange={(_p, _f, sorter) => { - const single = Array.isArray(sorter) ? sorter[0] : sorter; - const colKey = (single?.columnKey || single?.field) as SortKey | undefined; - setSortKey(colKey || null); - setSortOrder((single?.order as SortOrder) || null); - }} /> )} diff --git a/frontend/src/pages/inbounds/list/helpers.ts b/frontend/src/pages/inbounds/list/helpers.ts index ba5be2ce..7e50c4bb 100644 --- a/frontend/src/pages/inbounds/list/helpers.ts +++ b/frontend/src/pages/inbounds/list/helpers.ts @@ -1,8 +1,7 @@ -import type { NodeRecord } from '@/api/queries/useNodesQuery'; import { isSSMultiUser } from '@/lib/xray/protocol-capabilities'; import { coerceInboundJsonField } from '@/models/dbinbound'; -import type { ClientCountEntry, DBInboundRecord, SortKey, StreamHints } from './types'; +import type { DBInboundRecord, StreamHints } from './types'; export function readStreamHints(streamSettings: unknown): StreamHints { const stream = coerceInboundJsonField(streamSettings) as { network?: string; security?: string }; @@ -88,19 +87,3 @@ export function showQrCodeMenu(dbInbound: DBInboundRecord): boolean { } return false; } - -export const SORT_FNS: Record; clientCount: Record }) => number> = { - id: (a, b) => a.id - b.id, - enable: (a, b) => Number(a.enable) - Number(b.enable), - remark: (a, b) => (a.remark || '').localeCompare(b.remark || ''), - port: (a, b) => a.port - b.port, - protocol: (a, b) => a.protocol.localeCompare(b.protocol), - traffic: (a, b) => (a.up + a.down) - (b.up + b.down), - expiryTime: (a, b) => (a.expiryTime || Infinity) - (b.expiryTime || Infinity), - node: (a, b, ctx) => { - const nameA = ctx.nodesById.get(a.nodeId ?? -1)?.name ?? (a.nodeId == null ? '￿' : `node #${a.nodeId}`); - const nameB = ctx.nodesById.get(b.nodeId ?? -1)?.name ?? (b.nodeId == null ? '￿' : `node #${b.nodeId}`); - return nameA.localeCompare(nameB); - }, - clients: (a, b, ctx) => (ctx.clientCount[a.id]?.clients || 0) - (ctx.clientCount[b.id]?.clients || 0), -}; diff --git a/frontend/src/pages/inbounds/list/types.ts b/frontend/src/pages/inbounds/list/types.ts index 1f6230e9..3efdf4bd 100644 --- a/frontend/src/pages/inbounds/list/types.ts +++ b/frontend/src/pages/inbounds/list/types.ts @@ -74,16 +74,3 @@ export interface InboundListProps { onRowAction: (action: { key: RowAction; dbInbound: DBInboundRecord }) => void; onBulkDelete: (ids: number[]) => Promise; } - -export type SortKey = - | 'id' - | 'enable' - | 'remark' - | 'port' - | 'protocol' - | 'traffic' - | 'expiryTime' - | 'node' - | 'clients'; - -export type SortOrder = 'ascend' | 'descend' | null; diff --git a/frontend/src/pages/inbounds/list/useInboundColumns.tsx b/frontend/src/pages/inbounds/list/useInboundColumns.tsx index 90bd6831..7cffdca0 100644 --- a/frontend/src/pages/inbounds/list/useInboundColumns.tsx +++ b/frontend/src/pages/inbounds/list/useInboundColumns.tsx @@ -1,4 +1,4 @@ -import { useCallback, useMemo, type ReactElement } from 'react'; +import { useMemo, type ReactElement } from 'react'; import { useTranslation } from 'react-i18next'; import { Popover, Switch, Tag, type TableColumnType } from 'antd'; @@ -16,7 +16,7 @@ import { tunnelNetworkLabel, mixedNetworkLabel, } from './helpers'; -import type { ClientCountEntry, DBInboundRecord, RowAction, SortKey, SortOrder } from './types'; +import type { ClientCountEntry, DBInboundRecord, RowAction } from './types'; interface UseInboundColumnsParams { hasAnyRemark: boolean; @@ -26,8 +26,6 @@ interface UseInboundColumnsParams { subEnable: boolean; expireDiff: number; trafficDiff: number; - sortKey: SortKey | null; - sortOrder: SortOrder; onRowAction: (action: { key: RowAction; dbInbound: DBInboundRecord }) => void; onSwitchEnable: (dbInbound: DBInboundRecord, next: boolean) => void; } @@ -40,21 +38,12 @@ export function useInboundColumns({ subEnable, expireDiff, trafficDiff, - sortKey, - sortOrder, onRowAction, onSwitchEnable, }: UseInboundColumnsParams): TableColumnType[] { const { t } = useTranslation(); const { datepicker } = useDatepicker(); - const sorterFor = useCallback((key: SortKey) => ({ - sorter: true as const, - showSorterTooltip: false, - sortOrder: sortKey === key ? sortOrder : null, - sortDirections: ['ascend' as const, 'descend' as const], - }), [sortKey, sortOrder]); - return useMemo(() => { const cols: TableColumnType[] = [ { @@ -63,7 +52,6 @@ export function useInboundColumns({ key: 'id', align: 'right', width: 30, - ...sorterFor('id'), }, { title: t('pages.inbounds.operate'), @@ -84,7 +72,6 @@ export function useInboundColumns({ key: 'enable', align: 'center', width: 35, - ...sorterFor('enable'), render: (_, record) => ( { if (record.nodeId == null) { return {t('pages.inbounds.localPanel')}; @@ -134,14 +119,12 @@ export function useInboundColumns({ key: 'port', align: 'center', width: 40, - ...sorterFor('port'), }, { title: t('pages.inbounds.protocol'), key: 'protocol', align: 'left', width: 130, - ...sorterFor('protocol'), render: (_, record) => { const tags: ReactElement[] = [{record.protocol}]; if (record.isWireguard || record.isHysteria) { @@ -170,7 +153,6 @@ export function useInboundColumns({ key: 'clients', align: 'left', width: 50, - ...sorterFor('clients'), render: (_, record) => { const cc = clientCount[record.id]; if (!cc) return null; @@ -236,7 +218,6 @@ export function useInboundColumns({ key: 'traffic', align: 'center', width: 90, - ...sorterFor('traffic'), render: (_, record) => ( { if (record.expiryTime > 0) { return ( @@ -286,5 +266,5 @@ export function useInboundColumns({ ); return cols; - }, [t, hasAnyRemark, hasActiveNode, nodesById, clientCount, subEnable, expireDiff, trafficDiff, datepicker, onRowAction, onSwitchEnable, sorterFor]); + }, [t, hasAnyRemark, hasActiveNode, nodesById, clientCount, subEnable, expireDiff, trafficDiff, datepicker, onRowAction, onSwitchEnable]); }