This is an automated email from the ASF dual-hosted git repository.

lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git


The following commit(s) were added to refs/heads/rocketmq-studio by this push:
     new 391348c8 fix(instance): sort unavailable resource counts last (#1704)
391348c8 is described below

commit 391348c86edfcbdaa54cd8cdc97ae148521c6f87
Author: aias00 <[email protected]>
AuthorDate: Tue Aug 11 20:51:00 2026 +0800

    fix(instance): sort unavailable resource counts last (#1704)
---
 .../pages/instance/__tests__/InstancePage.test.tsx | 26 ++++++++++++++++++++++
 web/src/pages/instance/index.tsx                   | 24 ++++++++++++++++++--
 2 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/web/src/pages/instance/__tests__/InstancePage.test.tsx 
b/web/src/pages/instance/__tests__/InstancePage.test.tsx
index 866d436c..2ad44b25 100644
--- a/web/src/pages/instance/__tests__/InstancePage.test.tsx
+++ b/web/src/pages/instance/__tests__/InstancePage.test.tsx
@@ -147,6 +147,32 @@ describe('InstancePage', () => {
     );
   });
 
+  it('keeps unavailable resource counts after available values in both sort 
directions', async () => {
+    vi.mocked(instanceService.listInstances).mockResolvedValue([
+      { ...instance('unavailable', 'unavailable-instance'), topicCount: 0, 
resourceCountsAvailable: false },
+      { ...instance('zero', 'zero-instance'), topicCount: 0 },
+      { ...instance('many', 'many-instance'), topicCount: 10 },
+    ]);
+    const { container } = renderPage();
+
+    await screen.findByText('unavailable-instance');
+    const topicHeader = screen.getByRole('columnheader', { name: 'Topic' });
+    const rowNames = () =>
+      Array.from(container.querySelectorAll('tbody tr')).map(
+        (row) => row.querySelector('td')?.textContent,
+      );
+
+    fireEvent.click(topicHeader);
+    await waitFor(() => {
+      expect(rowNames()).toEqual(['zero-instance', 'many-instance', 
'unavailable-instance']);
+    });
+
+    fireEvent.click(topicHeader);
+    await waitFor(() => {
+      expect(rowNames()).toEqual(['many-instance', 'zero-instance', 
'unavailable-instance']);
+    });
+  });
+
   it('ignores an older search response that finishes after the latest 
request', async () => {
     let resolveOldSearch!: (instances: Instance[]) => void;
     let resolveLatestSearch!: (instances: Instance[]) => void;
diff --git a/web/src/pages/instance/index.tsx b/web/src/pages/instance/index.tsx
index 0f507e28..bee86e14 100644
--- a/web/src/pages/instance/index.tsx
+++ b/web/src/pages/instance/index.tsx
@@ -37,6 +37,7 @@ import { useLang } from '../../i18n/LangContext';
 import { Plus, MagnifyingGlass } from '@phosphor-icons/react';
 import { EditOutlined, DeleteOutlined } from '@ant-design/icons';
 import type { ColumnsType } from 'antd/es/table';
+import type { SortOrder } from 'antd/es/table/interface';
 import type { Instance, InstanceQuery } from '../../api/instance';
 import { listCloudCredentials, type CloudCredential } from 
'../../api/cloudCredential';
 import {
@@ -70,6 +71,24 @@ const typeLabel: Record<string, { text: string; color: 
string }> = {
 
 type InstanceTypeFilter = 'ALL' | Instance['type'];
 
+function compareResourceCounts(
+  left: Instance,
+  right: Instance,
+  field: 'topicCount' | 'consumerGroupCount',
+  sortOrder?: SortOrder,
+): number {
+  const leftUnavailable = left.resourceCountsAvailable === false;
+  const rightUnavailable = right.resourceCountsAvailable === false;
+  if (leftUnavailable || rightUnavailable) {
+    if (leftUnavailable === rightUnavailable) return 0;
+    // Ant Design reverses the comparator for descending order, so invert this
+    // branch to keep unavailable counts after numeric values in either order.
+    const unavailableAfterAvailable = sortOrder === 'descend' ? -1 : 1;
+    return leftUnavailable ? unavailableAfterAvailable : 
-unavailableAfterAvailable;
+  }
+  return left[field] - right[field];
+}
+
 /* ═══════════════════════════════════════════
    InstancePage
    ═══════════════════════════════════════════ */
@@ -407,7 +426,7 @@ const InstancePage = () => {
       key: 'topicCount',
       width: 80,
       align: 'center' as const,
-      sorter: (a, b) => a.topicCount - b.topicCount,
+      sorter: (a, b, sortOrder) => compareResourceCounts(a, b, 'topicCount', 
sortOrder),
       render: (count: number, record: Instance) =>
         record.resourceCountsAvailable === false ? '不可用' : count,
     },
@@ -417,7 +436,8 @@ const InstancePage = () => {
       key: 'consumerGroupCount',
       width: 80,
       align: 'center' as const,
-      sorter: (a, b) => a.consumerGroupCount - b.consumerGroupCount,
+      sorter: (a, b, sortOrder) =>
+        compareResourceCounts(a, b, 'consumerGroupCount', sortOrder),
       render: (count: number, record: Instance) =>
         record.resourceCountsAvailable === false ? '不可用' : count,
     },

Reply via email to