From bbea15dea4af69b03731d6da562cd8ddf8cf57e8 Mon Sep 17 00:00:00 2001 From: ppanel-web Date: Fri, 20 Feb 2026 05:11:10 +0000 Subject: [PATCH] Fix unstable node sorting order --- apps/admin/src/sections/nodes/index.tsx | 13 ++++++++++++- packages/ui/src/composed/pro-table/wrapper.tsx | 14 ++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/admin/src/sections/nodes/index.tsx b/apps/admin/src/sections/nodes/index.tsx index f87dbb0..60f2ec8 100644 --- a/apps/admin/src/sections/nodes/index.tsx +++ b/apps/admin/src/sections/nodes/index.tsx @@ -278,7 +278,18 @@ export default function Nodes() { size: pagination.size, search: filter?.search || undefined, }); - const list = (data?.data?.list || []) as API.Node[]; + const rawList = (data?.data?.list || []) as API.Node[]; + // Backend should ideally return nodes already sorted, but we also sort on the + // frontend to keep the UI stable (and avoid "random" order after refresh). + const list = rawList.slice().sort((a, b) => { + const as = a.sort; + const bs = b.sort; + const an = typeof as === "number" ? as : Number.POSITIVE_INFINITY; + const bn = typeof bs === "number" ? bs : Number.POSITIVE_INFINITY; + if (an !== bn) return an - bn; + // Tie-breaker to keep a stable order. + return Number(a.id) - Number(b.id); + }); const total = Number(data?.data?.total || list.length); return { list, total }; }} diff --git a/packages/ui/src/composed/pro-table/wrapper.tsx b/packages/ui/src/composed/pro-table/wrapper.tsx index ec2f0bc..59355c6 100644 --- a/packages/ui/src/composed/pro-table/wrapper.tsx +++ b/packages/ui/src/composed/pro-table/wrapper.tsx @@ -35,10 +35,16 @@ export function ProTableWrapper({ const handleDragEnd = async (event: DragEndEvent) => { const { active, over } = event; - if (onSort) { - const updatedData = await onSort(active.id, over?.id || null, data); - setData(updatedData); - } + + // If the pointer is released outside of any droppable row, `over` can be null. + // In that case we should keep the current order (and avoid firing a sort API call). + if (!(onSort && over)) return; + + // No-op when dropping onto itself. + if (String(active.id) === String(over.id)) return; + + const updatedData = await onSort(active.id, over.id, data); + setData(updatedData); }; if (!onSort) return children; return (