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 8002d6509 fix(web): stop tag columns wrapping and tidy six layout 
mismatches (#6533)
8002d6509 is described below

commit 8002d650994bc3aacb3785f1587527bf66e4437e
Author: lizhimins <[email protected]>
AuthorDate: Wed Oct 14 10:10:36 2026 +0800

    fix(web): stop tag columns wrapping and tidy six layout mismatches (#6533)
    
    Thirteen table columns render an array of antd Tags inside a wrapping
    Space or Flex. Two things made them wrap: `.ant-tag` carries its own
    `margin-inline-end: 8px`, which stacks on top of the container's `gap: 4`
    and renders as 12px of spacing, and the declared column widths were sized
    without that margin. AuditRiskInsights had already hand-written
    `marginInlineEnd: 0` for exactly this reason; the other twelve had not.
    
    Add TagList and route all thirteen through it: the tag margin is
    cancelled so the container gap is the only spacing, `wrap={false}` makes
    wrapping impossible, `max` collapses the overflow into a `+N` tag that
    lists the rest on hover, and `tagMaxWidth` clips one long label with a
    native title. AuditRiskInsights previously did `slice(0, 3)`, dropping
    the fourth token silently; it now shows `+1`.
    
    The widths are re-derived from measured tag widths, not estimated. Two
    measurement traps are worth recording because both produce plausible
    numbers: injecting a bare `<span class="ant-tag">` misses antd 5's
    component styles (they are scoped to `:where(.css-hash).ant-tag`), and
    reading `getBoundingClientRect()` on a tag already inside a constrained
    flex container returns the shrunk width — `scrollWidth` gives the natural
    one. Clone a rendered tag, or read scrollWidth.
    
    audit.tsx also needed `width` rather than `minWidth`. antd only emits a
    `<col>` for `width`, so under `table-layout: fixed` a column carrying only
    `minWidth` merely shares the leftover with the other unsized columns.
    That table has two, so the detail column stayed at 290px whatever
    `minWidth` said, and nowrap then clipped the third tag mid-word.
    
    Six layout mismatches, each measured in a browser before and after:
    
    | where | before | after |
    |:--|:--|:--|
    | group detail modal, health tab | 1080px wide for a table needing 384; 
four `span={6}` Statistic cards | 800px, one `#fafafa` summary bar matching the 
progress tab |
    | group detail modal, settings tab | 480x548 vertical form, three switches 
each on its own row | 752x204, three-column grid |
    | message query, by-key input | 240px beside the by-message-id input's 
400px | 400px |
    | client diagnostics table | resource and type stacked in one cell, 2 lines 
/ 61px | type in its own column, 1 line / 40px |
    | system alerts filter bar | control heights 24 / 26 / 22px mixed; four 
independent buttons for one mutually-exclusive filter | all 32px; Segmented, 
the idiom the message page and settings already use |
    | dashboard cluster health card | body padding `0 20px 16px`, table 1px 
above the head border | `16px 20px`, 15px clear |
    
    The datetime-local inputs need an explicit `height: 32`: dropping
    `size="small"` brings every other control to 32px but leaves the native
    picker at 34px. The Selects use `minWidth` rather than `width` so the
    English labels ("All delivery statuses", ~204px) are not truncated.
    
    Tag defaults to 12px, below this project's 14px floor, so TagList sets
    14px; the columns it now covers were a mix of 12px and hand-set 14px.
    
    Verified: `tsc -b` clean, eslint 0 errors on every touched file,
    `vitest run` 160 files / 1612 tests green (8 new for TagList), and every
    row of the table above re-measured against the deployed build.
    
    One test needed updating: Segmented's radio input carries
    `pointer-events: none`, so `user.click` refuses it — the test now clicks
    the wrapping `.ant-segmented-item`.
---
 web/src/components/AlertRuleAssetList.tsx          |  18 +-
 web/src/components/GrafanaDashboardList.tsx        |  17 +-
 web/src/components/TagList.tsx                     |  83 +++++++
 web/src/components/__tests__/TagList.test.tsx      |  84 ++++++++
 web/src/pages/cluster/clients.tsx                  |  57 ++---
 web/src/pages/cluster/index.tsx                    |  46 ++--
 web/src/pages/home/dashboard.tsx                   |   2 +-
 web/src/pages/instance/acl.tsx                     |  54 +++--
 web/src/pages/instance/consumer.tsx                | 238 ++++++++++++---------
 web/src/pages/instance/message.tsx                 |   2 +-
 web/src/pages/instance/topic.tsx                   |  25 ++-
 web/src/pages/ops/AuditRiskInsights.tsx            |  19 +-
 .../pages/ops/__tests__/SystemAlertsPage.test.tsx  |   7 +-
 web/src/pages/ops/alerts.tsx                       |  18 +-
 web/src/pages/ops/audit.tsx                        |  25 ++-
 web/src/pages/ops/systemAlerts.tsx                 |  76 ++++---
 16 files changed, 495 insertions(+), 276 deletions(-)

diff --git a/web/src/components/AlertRuleAssetList.tsx 
b/web/src/components/AlertRuleAssetList.tsx
index 7338735f3..78fcd4de8 100644
--- a/web/src/components/AlertRuleAssetList.tsx
+++ b/web/src/components/AlertRuleAssetList.tsx
@@ -20,6 +20,7 @@ import { Alert, App, Button, Input, Modal, Select, Space, 
Table, Tag, Typography
 import type { ColumnsType } from 'antd/es/table';
 import { ArrowClockwise, DownloadSimple, Eye } from '@phosphor-icons/react';
 import { useLang } from '../i18n/LangContext';
+import TagList from './TagList';
 import {
   exportAlertRuleAsset,
   getAlertRuleAsset,
@@ -177,15 +178,16 @@ export const AlertRuleAssetList: React.FC = () => {
       title: t('alertAssets.severity'),
       dataIndex: 'severities',
       key: 'severities',
-      width: 180,
+      // CRITICAL + WARNING + INFO 三个标签并排实测需 239px
+      width: 240,
       render: (severities: string[]) => (
-        <Space size={[0, 4]} wrap>
-          {(severities || []).map((severity) => (
-            <Tag key={severity} color={SEVERITY_COLORS[severity] || 'default'}>
-              {severity.toUpperCase()}
-            </Tag>
-          ))}
-        </Space>
+        <TagList
+          items={(severities || []).map((severity) => ({
+            key: severity,
+            label: severity.toUpperCase(),
+            color: SEVERITY_COLORS[severity] || 'default',
+          }))}
+        />
       ),
     },
     {
diff --git a/web/src/components/GrafanaDashboardList.tsx 
b/web/src/components/GrafanaDashboardList.tsx
index 167da1438..bf35092d8 100644
--- a/web/src/components/GrafanaDashboardList.tsx
+++ b/web/src/components/GrafanaDashboardList.tsx
@@ -16,10 +16,11 @@
  */
 
 import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
-import { Alert, App, Button, Input, Modal, Select, Space, Table, Tag, 
Typography } from 'antd';
+import { Alert, App, Button, Input, Modal, Select, Space, Table, Typography } 
from 'antd';
 import type { ColumnsType } from 'antd/es/table';
 import { ArrowClockwise, DownloadSimple, Eye } from '@phosphor-icons/react';
 import { useLang } from '../i18n/LangContext';
+import TagList from './TagList';
 import {
   getGrafanaDashboard,
   exportGrafanaDashboard,
@@ -184,15 +185,13 @@ export const GrafanaDashboardList: React.FC = () => {
       title: t('grafana.tags'),
       dataIndex: 'tags',
       key: 'tags',
-      width: 140,
+      width: 200,
       render: (tags: string[]) => (
-        <Space size={[0, 4]} wrap>
-          {(tags || []).map((tag) => (
-            <Tag key={tag} color="blue">
-              {tag}
-            </Tag>
-          ))}
-        </Space>
+        <TagList
+          items={(tags || []).map((tag) => ({ key: tag, label: tag, color: 
'blue' }))}
+          max={2}
+          tagMaxWidth={70}
+        />
       ),
     },
     {
diff --git a/web/src/components/TagList.tsx b/web/src/components/TagList.tsx
new file mode 100644
index 000000000..b1f2ea182
--- /dev/null
+++ b/web/src/components/TagList.tsx
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import type { CSSProperties } from 'react';
+import { Flex, Tag, Tooltip } from 'antd';
+
+export interface TagListItem {
+  key: string;
+  label: string;
+  color?: string;
+}
+
+interface TagListProps {
+  items: TagListItem[];
+  /**
+   * How many tags to render before collapsing the rest into a `+N` tag that 
lists them on hover.
+   * Leave unset only when the value set is bounded and the column is wide 
enough for all of it.
+   */
+  max?: number;
+  /** Truncates each tag to this width; the full label stays reachable via the 
native title. */
+  tagMaxWidth?: number;
+  gap?: number;
+  style?: CSSProperties;
+}
+
+// antd gives `.ant-tag` an 8px `margin-inline-end`, which stacks on top of 
the container's own gap
+// and makes the real spacing 12px when 4px was asked for. The container is 
the single source of
+// truth for spacing here, so the tag margin is cancelled. 14px is the 
project-wide font floor;
+// antd's own default for Tag is 12px.
+const TAG_STYLE: CSSProperties = { marginInlineEnd: 0, fontSize: 14 };
+
+const TagList = ({ items, max, tagMaxWidth, gap = 4, style }: TagListProps) => 
{
+  const visible = max === undefined ? items : items.slice(0, max);
+  const hidden = max === undefined ? [] : items.slice(max);
+  const clip: CSSProperties | undefined = tagMaxWidth
+    ? {
+        maxWidth: tagMaxWidth,
+        overflow: 'hidden',
+        textOverflow: 'ellipsis',
+        whiteSpace: 'nowrap',
+      }
+    : undefined;
+
+  return (
+    <Flex gap={gap} wrap={false} align="center" style={{ minWidth: 0, ...style 
}}>
+      {visible.map((item) => (
+        <Tag
+          key={item.key}
+          color={item.color}
+          style={{ ...TAG_STYLE, ...clip }}
+          title={tagMaxWidth ? item.label : undefined}
+        >
+          {item.label}
+        </Tag>
+      ))}
+      {hidden.length > 0 && (
+        <Tooltip
+          title={hidden.map((item) => (
+            <div key={item.key}>{item.label}</div>
+          ))}
+        >
+          <Tag style={TAG_STYLE}>+{hidden.length}</Tag>
+        </Tooltip>
+      )}
+    </Flex>
+  );
+};
+
+export default TagList;
diff --git a/web/src/components/__tests__/TagList.test.tsx 
b/web/src/components/__tests__/TagList.test.tsx
new file mode 100644
index 000000000..8ef360681
--- /dev/null
+++ b/web/src/components/__tests__/TagList.test.tsx
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { describe, it, expect } from 'vitest';
+import { render, screen, fireEvent } from '@testing-library/react';
+import TagList from '../TagList';
+
+const items = [
+  { key: 'dingtalk', label: 'DingTalk', color: 'blue' },
+  { key: 'email', label: 'Email', color: 'green' },
+  { key: 'sms', label: 'SMS', color: 'orange' },
+];
+
+describe('TagList', () => {
+  it('renders every item when no max is givenTest', () => {
+    render(<TagList items={items} />);
+    expect(screen.getByText('DingTalk')).toBeInTheDocument();
+    expect(screen.getByText('Email')).toBeInTheDocument();
+    expect(screen.getByText('SMS')).toBeInTheDocument();
+    expect(screen.queryByText('+1')).not.toBeInTheDocument();
+  });
+
+  it('renders nothing when there are no itemsTest', () => {
+    const { container } = render(<TagList items={[]} />);
+    expect(container.querySelectorAll('.ant-tag')).toHaveLength(0);
+  });
+
+  it('cancels the antd tag margin so the container gap is the only 
spacingTest', () => {
+    render(<TagList items={items} />);
+    // antd's own `.ant-tag` carries margin-inline-end: 8px, which would stack 
on top of gap={4}
+    // and render as 12px of spacing. Every tag has to cancel it.
+    screen
+      .getAllByText(/DingTalk|Email|SMS/)
+      .forEach((tag) => expect(tag.style.marginInlineEnd).toBe('0px'));
+  });
+
+  it('never wraps onto a second lineTest', () => {
+    const { container } = render(<TagList items={items} />);
+    expect(container.querySelector('.ant-flex-wrap-wrap')).toBeNull();
+  });
+
+  it('collapses the overflow into a +N tag that lists the hidden labelsTest', 
async () => {
+    render(<TagList items={items} max={1} />);
+    expect(screen.getByText('DingTalk')).toBeInTheDocument();
+    expect(screen.queryByText('Email')).not.toBeInTheDocument();
+
+    fireEvent.mouseEnter(screen.getByText('+2'));
+    expect(await screen.findByText('Email')).toBeInTheDocument();
+    expect(screen.getByText('SMS')).toBeInTheDocument();
+  });
+
+  it('keeps every item when max is above the item countTest', () => {
+    render(<TagList items={items} max={5} />);
+    expect(screen.getByText('SMS')).toBeInTheDocument();
+    expect(screen.queryByText(/\+\d/)).not.toBeInTheDocument();
+  });
+
+  it('truncates long labels but keeps them reachable through the titleTest', 
() => {
+    render(<TagList items={[{ key: 't', label: 'a-very-long-topic-name' }]} 
tagMaxWidth={80} />);
+    const tag = screen.getByText('a-very-long-topic-name');
+    expect(tag.style.maxWidth).toBe('80px');
+    expect(tag.style.textOverflow).toBe('ellipsis');
+    expect(tag.getAttribute('title')).toBe('a-very-long-topic-name');
+  });
+
+  it('does not add a title when labels are not truncatedTest', () => {
+    render(<TagList items={[{ key: 't', label: 'SMS' }]} />);
+    expect(screen.getByText('SMS').getAttribute('title')).toBeNull();
+  });
+});
diff --git a/web/src/pages/cluster/clients.tsx 
b/web/src/pages/cluster/clients.tsx
index 8c2e67b1f..780aac7b7 100644
--- a/web/src/pages/cluster/clients.tsx
+++ b/web/src/pages/cluster/clients.tsx
@@ -38,6 +38,7 @@ import type { ColumnsType } from 'antd/es/table';
 import type { TableProps } from 'antd';
 
 import PageHeader from '../../components/PageHeader';
+import TagList from '../../components/TagList';
 import { useLang } from '../../i18n/LangContext';
 import type { ClientConnection } from '../../api/connections';
 import { listConnections } from '../../services/connectionsService';
@@ -553,18 +554,21 @@ const ClientsPage = () => {
       width: 220,
       // Unbounded resource names (_INNER_TRACE_PRODUCER-…-CONSUME-1) must 
clip inside the
       // cell: the project-wide `.ant-table-cell { white-space: nowrap }` 
otherwise lets them
-      // spill over the neighbouring column. Each line ellipsises on its own 
with a native
-      // title tooltip, the ConversationListModal title-column idiom.
+      // spill over the neighbouring column.
       ellipsis: { showTitle: false },
       render: (_: unknown, record) => (
-        <div style={{ minWidth: 0 }}>
-          <Text strong style={diagnosticCellLine} title={record.resource}>
-            {record.resource}
-          </Text>
-          <Text type="secondary" style={diagnosticCellLine}>
-            {record.type}
-          </Text>
-        </div>
+        <Text strong style={diagnosticCellLine} title={record.resource}>
+          {record.resource}
+        </Text>
+      ),
+    },
+    {
+      title: t('common.type'),
+      dataIndex: 'type',
+      key: 'resourceType',
+      width: 100,
+      render: (type: string) => (
+        <Text style={{ fontSize: 14 }}>{(typeConfig[type] ?? { label: type 
}).label}</Text>
       ),
     },
     {
@@ -586,15 +590,16 @@ const ClientsPage = () => {
       title: t('clients.protocol'),
       dataIndex: 'protocols',
       key: 'protocols',
+      // gRPC + Remoting 两个标签并排实测需 157px
       width: 160,
       render: (protocols: string[]) => (
-        <Space size={4} wrap>
-          {protocols.map((protocol) => (
-            <Tag key={protocol} color={protocolConfig[protocol]?.color ?? 
'default'}>
-              {protocol}
-            </Tag>
-          ))}
-        </Space>
+        <TagList
+          items={protocols.map((protocol) => ({
+            key: protocol,
+            label: protocol,
+            color: protocolConfig[protocol]?.color ?? 'default',
+          }))}
+        />
       ),
     },
     {
@@ -602,18 +607,22 @@ const ClientsPage = () => {
       key: 'versions',
       width: 220,
       render: (_: unknown, record) => (
-        <Space size={4} wrap>
-          {record.languages.map((language) => (
-            <Tag key={language} color={languageConfig[language]?.color ?? 
'default'}>
-              {languageConfig[language]?.label ?? language}
-            </Tag>
-          ))}
+        <Flex gap={4} wrap={false} align="center" style={{ minWidth: 0 }}>
+          <TagList
+            items={record.languages.map((language) => ({
+              key: language,
+              label: languageConfig[language]?.label ?? language,
+              color: languageConfig[language]?.color ?? 'default',
+            }))}
+            max={2}
+            tagMaxWidth={64}
+          />
           {record.versions.map((version) => (
             <Text key={version} code>
               {version}
             </Text>
           ))}
-        </Space>
+        </Flex>
       ),
     },
     {
diff --git a/web/src/pages/cluster/index.tsx b/web/src/pages/cluster/index.tsx
index cf33221c9..2cbdae3c2 100644
--- a/web/src/pages/cluster/index.tsx
+++ b/web/src/pages/cluster/index.tsx
@@ -52,6 +52,7 @@ import {
 } from '@ant-design/icons';
 import { Cpu, HardDrives, Globe } from '@phosphor-icons/react';
 import PageHeader from '../../components/PageHeader';
+import TagList from '../../components/TagList';
 import InfoBanner from '../../components/InfoBanner';
 import { useLang } from '../../i18n/LangContext';
 import { countClusterComponents } from './clusterStats';
@@ -945,15 +946,17 @@ const ClusterPage = () => {
         dataIndex: 'values',
         key: 'values',
         render: (values: NameServerConfigDifference['values']) => (
-          <Space size={[0, 4]} wrap>
-            {values.map((value) => (
-              <Tag key={value.address} color={value.configured ? 'blue' : 
'default'}>
-                {`${value.address}: ${
-                  value.configured ? (value.value ?? '-') : 
t('cluster.nsConfigDiffUnconfigured')
-                }`}
-              </Tag>
-            ))}
-          </Space>
+          <TagList
+            items={values.map((value) => ({
+              key: value.address,
+              label: `${value.address}: ${
+                value.configured ? (value.value ?? '-') : 
t('cluster.nsConfigDiffUnconfigured')
+              }`,
+              color: value.configured ? 'blue' : 'default',
+            }))}
+            max={3}
+            tagMaxWidth={200}
+          />
         ),
       },
     ];
@@ -1092,20 +1095,17 @@ const ClusterPage = () => {
         dataIndex: 'values',
         key: 'values',
         render: (values: BrokerConfigDifference['values']) => (
-          <Space size={[0, 4]} wrap>
-            {values.map((value) => (
-              <Tag
-                key={`${value.address}-${value.value ?? 'missing'}`}
-                color={value.configured ? 'blue' : 'default'}
-              >
-                {`${value.brokerName || value.address}: ${
-                  value.configured
-                    ? (value.value ?? '-')
-                    : t('cluster.brokerConfigDiffUnconfigured')
-                }`}
-              </Tag>
-            ))}
-          </Space>
+          <TagList
+            items={values.map((value) => ({
+              key: `${value.address}-${value.value ?? 'missing'}`,
+              label: `${value.brokerName || value.address}: ${
+                value.configured ? (value.value ?? '-') : 
t('cluster.brokerConfigDiffUnconfigured')
+              }`,
+              color: value.configured ? 'blue' : 'default',
+            }))}
+            max={3}
+            tagMaxWidth={200}
+          />
         ),
       },
     ];
diff --git a/web/src/pages/home/dashboard.tsx b/web/src/pages/home/dashboard.tsx
index 87561e9ae..1e4a8be31 100644
--- a/web/src/pages/home/dashboard.tsx
+++ b/web/src/pages/home/dashboard.tsx
@@ -385,7 +385,7 @@ const DashboardPage = () => {
       <Card
         title={t('dashboard.clusterHealth')}
         extra={<a onClick={() => 
navigate(clusterPagePath)}>{t('common.viewAll')}</a>}
-        styles={{ body: { padding: '0 20px 16px' } }}
+        styles={{ body: { padding: '16px 20px' } }}
       >
         <Table
           dataSource={clusters}
diff --git a/web/src/pages/instance/acl.tsx b/web/src/pages/instance/acl.tsx
index d09dbff54..2cf13d667 100644
--- a/web/src/pages/instance/acl.tsx
+++ b/web/src/pages/instance/acl.tsx
@@ -50,6 +50,7 @@ import {
 import { EditOutlined, DeleteOutlined } from '@ant-design/icons';
 import type { ColumnsType } from 'antd/es/table';
 import PageHeader from '../../components/PageHeader';
+import TagList from '../../components/TagList';
 import InfoBanner from '../../components/InfoBanner';
 import { InstanceSelect } from '../../components/InstanceSelect';
 import { useLang } from '../../i18n/LangContext';
@@ -625,15 +626,16 @@ const AclPageContent = ({
       title: t('acl.permissions'),
       dataIndex: 'actions',
       key: 'actions',
-      width: 180,
+      // 规则表单里 PUB / SUB / ALL 是三个独立 Checkbox、可以同时勾上;三个标签并排实测需 252px
+      width: 260,
       render: (actions: AclRule['actions']) => (
-        <Space size={4} wrap>
-          {actions.map((action) => (
-            <Tag key={action} color={actionTagColor[action]} style={{ 
fontSize: 14 }}>
-              {actionLabel[action] ?? action}
-            </Tag>
-          ))}
-        </Space>
+        <TagList
+          items={actions.map((action) => ({
+            key: action,
+            label: actionLabel[action] ?? action,
+            color: actionTagColor[action],
+          }))}
+        />
       ),
     },
     {
@@ -810,13 +812,11 @@ const AclPageContent = ({
       width: 280,
       sorter: (a, b) => a.clusters.length - b.clusters.length,
       render: (clusters: string[]) => (
-        <Space size={4} wrap>
-          {clusters.map((c) => (
-            <Tag key={c} color="processing" style={{ fontSize: 14 }}>
-              {c}
-            </Tag>
-          ))}
-        </Space>
+        <TagList
+          items={clusters.map((c) => ({ key: c, label: c, color: 'processing' 
}))}
+          max={2}
+          tagMaxWidth={110}
+        />
       ),
     },
     {
@@ -928,13 +928,11 @@ const AclPageContent = ({
       key: 'topicPerms',
       width: 220,
       render: (perms: string[]) => (
-        <Space size={4} wrap>
-          {(perms ?? []).map((p) => (
-            <Tag key={p} color="blue" style={{ fontSize: 14 }}>
-              {p}
-            </Tag>
-          ))}
-        </Space>
+        <TagList
+          items={(perms ?? []).map((p) => ({ key: p, label: p, color: 'blue' 
}))}
+          max={2}
+          tagMaxWidth={80}
+        />
       ),
     },
     {
@@ -943,13 +941,11 @@ const AclPageContent = ({
       key: 'groupPerms',
       width: 200,
       render: (perms: string[]) => (
-        <Space size={4} wrap>
-          {(perms ?? []).map((p) => (
-            <Tag key={p} color="green" style={{ fontSize: 14 }}>
-              {p}
-            </Tag>
-          ))}
-        </Space>
+        <TagList
+          items={(perms ?? []).map((p) => ({ key: p, label: p, color: 'green' 
}))}
+          max={2}
+          tagMaxWidth={70}
+        />
       ),
     },
     {
diff --git a/web/src/pages/instance/consumer.tsx 
b/web/src/pages/instance/consumer.tsx
index 59294a7ca..ae78fe23a 100644
--- a/web/src/pages/instance/consumer.tsx
+++ b/web/src/pages/instance/consumer.tsx
@@ -178,6 +178,18 @@ const healthStatusTagColor = (status: 
ConsumerGroupHealthStatus) => {
   return 'green';
 };
 
+const healthStatusColor = (status: ConsumerGroupHealthStatus) => {
+  if (status === 'critical') return '#ff4d4f';
+  if (status === 'warning') return '#faad14';
+  return '#52c41a';
+};
+
+const healthProgressStatus = (status: ConsumerGroupHealthStatus) => {
+  if (status === 'critical') return 'exception' as const;
+  if (status === 'warning') return 'active' as const;
+  return 'success' as const;
+};
+
 const issueSeverityTagColor = (severity: ConsumerGroupHealthIssue['severity']) 
=> {
   if (severity === 'critical') return 'red';
   if (severity === 'warning') return 'orange';
@@ -1682,7 +1694,7 @@ const ConsumerPageContent = ({
           originalSettingsRef.current = null;
           settingsForm.resetFields();
         }}
-        width={detailTab === 'progress' || detailTab === 'health' ? 1080 : 800}
+        width={detailTab === 'progress' ? 1080 : 800}
         destroyOnHidden
         footer={null}
       >
@@ -1970,85 +1982,83 @@ const ConsumerPageContent = ({
                       />
                     )}
 
-                    <Row gutter={16}>
-                      <Col span={6}>
-                        <Card size="small" style={{ borderRadius: 8 }}>
-                          <Statistic
-                            title="健康分"
-                            value={selectedGroupHealth.summary.healthScore}
-                            suffix="/ 100"
-                            valueStyle={{
-                              color:
-                                selectedGroupHealth.status === 'critical'
-                                  ? '#ff4d4f'
-                                  : selectedGroupHealth.status === 'warning'
-                                    ? '#faad14'
-                                    : '#52c41a',
-                            }}
-                          />
-                          <Progress
-                            percent={selectedGroupHealth.summary.healthScore}
-                            showInfo={false}
-                            status={
-                              selectedGroupHealth.status === 'critical'
-                                ? 'exception'
-                                : selectedGroupHealth.status === 'warning'
-                                  ? 'active'
-                                  : 'success'
-                            }
-                          />
-                        </Card>
-                      </Col>
-                      <Col span={6}>
-                        <Card size="small" style={{ borderRadius: 8 }}>
-                          <Statistic
-                            title="已知堆积"
-                            value={selectedGroupHealth.summary.totalKnownLag}
-                            valueStyle={{
-                              color: 
lagColor(selectedGroupHealth.summary.totalKnownLag),
-                            }}
-                          />
-                          <Text type="secondary">
-                            报告堆积:
+                    <Card
+                      size="small"
+                      style={{
+                        background: '#fafafa',
+                        borderRadius: 8,
+                      }}
+                      styles={{ body: { padding: '8px 16px' } }}
+                    >
+                      <Space size={24} wrap>
+                        <Space size={4}>
+                          <Text type="secondary">健康分:</Text>
+                          <Text
+                            strong
+                            style={{ color: 
healthStatusColor(selectedGroupHealth.status) }}
+                          >
+                            {selectedGroupHealth.summary.healthScore} / 100
+                          </Text>
+                        </Space>
+                        <Space size={4}>
+                          <Text type="secondary">已知堆积:</Text>
+                          <Text
+                            strong
+                            style={{ color: 
lagColor(selectedGroupHealth.summary.totalKnownLag) }}
+                          >
+                            
{selectedGroupHealth.summary.totalKnownLag.toLocaleString()}
+                          </Text>
+                        </Space>
+                        <Space size={4}>
+                          <Text type="secondary">报告堆积:</Text>
+                          <Text strong>
                             {selectedGroupHealth.summary.reportedLag === null
                               ? UNAVAILABLE_LAG_LABEL
                               : 
selectedGroupHealth.summary.reportedLag.toLocaleString()}
                           </Text>
-                        </Card>
-                      </Col>
-                      <Col span={6}>
-                        <Card size="small" style={{ borderRadius: 8 }}>
-                          <Statistic
-                            title="Queue 覆盖"
-                            value={selectedGroupHealth.summary.queueCount}
-                            
suffix={`/${selectedGroupHealth.summary.subscribedTopicCount} Topic`}
-                          />
-                          <Text type="secondary">
+                        </Space>
+                        <Space size={4}>
+                          <Text type="secondary">Queue 覆盖:</Text>
+                          <Text strong>
+                            {selectedGroupHealth.summary.queueCount} /{' '}
+                            {selectedGroupHealth.summary.subscribedTopicCount} 
Topic
+                          </Text>
+                        </Space>
+                        <Space size={4}>
+                          <Text type="secondary">Queue 堆积:</Text>
+                          <Text strong>
                             {selectedGroupHealth.summary.unknownQueueCount > 0
-                              ? 
`${selectedGroupHealth.summary.unknownQueueCount} 个 Queue 堆积不可用`
-                              : 'Queue 堆积均可计算'}
+                              ? 
`${selectedGroupHealth.summary.unknownQueueCount} 个不可用`
+                              : '均可计算'}
                           </Text>
-                        </Card>
-                      </Col>
-                      <Col span={6}>
-                        <Card size="small" style={{ borderRadius: 8 }}>
-                          <Statistic
-                            title="客户端"
-                            value={selectedGroupHealth.summary.onlineInstances}
-                            formatter={(value) =>
-                              formatOnlineInstances(Number(value), 
UNAVAILABLE_LAG_LABEL)
-                            }
-                          />
-                          <Text type="secondary">
+                        </Space>
+                        <Space size={4}>
+                          <Text type="secondary">客户端:</Text>
+                          <Text strong>
+                            {formatOnlineInstances(
+                              selectedGroupHealth.summary.onlineInstances,
+                              UNAVAILABLE_LAG_LABEL,
+                            )}
+                          </Text>
+                        </Space>
+                        <Space size={4}>
+                          <Text type="secondary">心跳:</Text>
+                          <Text strong>
                             {selectedGroupHealth.summary.onlineInstances < 0
-                              ? '客户端连接信息不可用'
+                              ? '连接信息不可用'
                               : selectedGroupHealth.summary.staleClientCount > 0
-                                ? 
`${selectedGroupHealth.summary.staleClientCount} 个心跳过期`
-                                : '心跳状态正常'}
+                                ? 
`${selectedGroupHealth.summary.staleClientCount} 个过期`
+                                : '正常'}
                           </Text>
-                        </Card>
-                      </Col>
-                    </Row>
+                        </Space>
+                      </Space>
+                      <Progress
+                        percent={selectedGroupHealth.summary.healthScore}
+                        showInfo={false}
+                        style={{ marginTop: 8, marginBottom: 0 }}
+                        
status={healthProgressStatus(selectedGroupHealth.status)}
+                      />
+                    </Card>
 
                     {selectedGroupHealth.issues.length > 0 ? (
                       <Table
@@ -2190,41 +2200,57 @@ const ConsumerPageContent = ({
                 disabled: isCloudInstance,
                 children: (
                   <Spin spinning={settingsLoading}>
-                    <Form form={settingsForm} layout="vertical" style={{ 
maxWidth: 480 }}>
-                      <Form.Item label="Group 名称">
-                        <Text strong>{selectedGroup.name}</Text>
-                      </Form.Item>
-                      <Form.Item
-                        label="重试队列数"
-                        name="retryQueueNums"
-                        rules={[{ required: true, message: '请输入重试队列数' }]}
-                      >
-                        <InputNumber min={1} max={128} style={{ width: '100%' 
}} />
-                      </Form.Item>
-                      <Form.Item
-                        label="最大重试次数"
-                        name="retryMaxTimes"
-                        rules={[{ required: true, message: '请输入最大重试次数' }]}
-                      >
-                        <InputNumber min={1} max={128} style={{ width: '100%' 
}} />
-                      </Form.Item>
-                      <Form.Item label="启用消费" name="consumeEnable" 
valuePropName="checked">
-                        <Switch />
-                      </Form.Item>
-                      <Form.Item
-                        label="顺序消费"
-                        name="consumeMessageOrderly"
-                        valuePropName="checked"
-                      >
-                        <Switch />
-                      </Form.Item>
-                      <Form.Item
-                        label="广播消费"
-                        name="consumeBroadcastEnable"
-                        valuePropName="checked"
-                      >
-                        <Switch />
-                      </Form.Item>
+                    <Form form={settingsForm} layout="vertical">
+                      <Row gutter={16}>
+                        <Col span={8}>
+                          <Form.Item label="Group 名称">
+                            <Text strong>{selectedGroup.name}</Text>
+                          </Form.Item>
+                        </Col>
+                        <Col span={8}>
+                          <Form.Item
+                            label="重试队列数"
+                            name="retryQueueNums"
+                            rules={[{ required: true, message: '请输入重试队列数' }]}
+                          >
+                            <InputNumber min={1} max={128} style={{ width: 
'100%' }} />
+                          </Form.Item>
+                        </Col>
+                        <Col span={8}>
+                          <Form.Item
+                            label="最大重试次数"
+                            name="retryMaxTimes"
+                            rules={[{ required: true, message: '请输入最大重试次数' }]}
+                          >
+                            <InputNumber min={1} max={128} style={{ width: 
'100%' }} />
+                          </Form.Item>
+                        </Col>
+                      </Row>
+                      <Row gutter={16}>
+                        <Col span={8}>
+                          <Form.Item label="启用消费" name="consumeEnable" 
valuePropName="checked">
+                            <Switch />
+                          </Form.Item>
+                        </Col>
+                        <Col span={8}>
+                          <Form.Item
+                            label="顺序消费"
+                            name="consumeMessageOrderly"
+                            valuePropName="checked"
+                          >
+                            <Switch />
+                          </Form.Item>
+                        </Col>
+                        <Col span={8}>
+                          <Form.Item
+                            label="广播消费"
+                            name="consumeBroadcastEnable"
+                            valuePropName="checked"
+                          >
+                            <Switch />
+                          </Form.Item>
+                        </Col>
+                      </Row>
                       <Form.Item style={{ marginBottom: 0 }}>
                         <Button
                           type="primary"
diff --git a/web/src/pages/instance/message.tsx 
b/web/src/pages/instance/message.tsx
index 475ab9ed9..1adb5b378 100644
--- a/web/src/pages/instance/message.tsx
+++ b/web/src/pages/instance/message.tsx
@@ -1190,7 +1190,7 @@ const MessagePageContent = ({
                   />
                   <Input
                     placeholder={t('messagePage.inputKeyPlaceholder')}
-                    style={{ width: 240 }}
+                    style={{ width: 400 }}
                     value={keyInput}
                     onChange={(e) => setKeyInput(e.target.value)}
                   />
diff --git a/web/src/pages/instance/topic.tsx b/web/src/pages/instance/topic.tsx
index 1be6ee7a4..538111051 100644
--- a/web/src/pages/instance/topic.tsx
+++ b/web/src/pages/instance/topic.tsx
@@ -63,6 +63,7 @@ import PageHeader from '../../components/PageHeader';
 import InfoBanner from '../../components/InfoBanner';
 import { InstanceSelect } from '../../components/InstanceSelect';
 import TopicConfigComparisonDrawer from 
'../../components/TopicConfigComparisonDrawer';
+import TagList from '../../components/TagList';
 import { useLang } from '../../i18n/LangContext';
 import { TOPIC_TYPE_MAP, CLUSTER_TYPE_MAP } from '../../constants/theme';
 import type { Topic, BrokerRoute, ConsumerGroupInfo, TopicConsumerPage } from 
'../../api/metadata';
@@ -924,17 +925,19 @@ const TopicPageContent = ({
               Master {record.masterAddr}
             </Text>
           )}
-          <Space size={4} wrap>
-            {record.brokerIds.length > 0 ? (
-              record.brokerIds.map((id) => (
-                <Tag key={id} color={id === '0' ? 'blue' : undefined}>
-                  {id === '0' ? 'Master' : `Replica ${id}`}
-                </Tag>
-              ))
-            ) : (
-              <Tag color="warning">地址未知</Tag>
-            )}
-          </Space>
+          {record.brokerIds.length > 0 ? (
+            <TagList
+              items={record.brokerIds.map((id) => ({
+                key: id,
+                label: id === '0' ? 'Master' : `Replica ${id}`,
+                color: id === '0' ? 'blue' : undefined,
+              }))}
+              max={2}
+              tagMaxWidth={90}
+            />
+          ) : (
+            <Tag color="warning">地址未知</Tag>
+          )}
         </Space>
       ),
     },
diff --git a/web/src/pages/ops/AuditRiskInsights.tsx 
b/web/src/pages/ops/AuditRiskInsights.tsx
index a26828098..45267f2cf 100644
--- a/web/src/pages/ops/AuditRiskInsights.tsx
+++ b/web/src/pages/ops/AuditRiskInsights.tsx
@@ -24,7 +24,6 @@ import {
   Progress,
   Row,
   Skeleton,
-  Space,
   Statistic,
   Table,
   Tag,
@@ -36,6 +35,7 @@ import type { AuditRecord } from '../../api/ops';
 import { useLang } from '../../i18n/LangContext';
 import { formatDateTime, formatNumber } from '../../utils/format';
 import { tableScrollX } from '../../utils/table';
+import TagList from '../../components/TagList';
 import {
   auditRiskOperationLabel,
   buildAuditRiskInsights,
@@ -151,14 +151,17 @@ const AuditRiskInsights = ({ summary, records, loading }: 
Props) => {
       title: t('audit.opType'),
       dataIndex: 'operationTypes',
       key: 'operationTypes',
+      width: 240,
+      // 原来 slice(0, 3) 把第 4 个起静默丢掉,换成 TagList 的 +N 至少悬停能看到
       render: (operationTypes: string[]) => (
-        <Space size={[4, 4]} wrap>
-          {operationTypes.slice(0, 3).map((operationType) => (
-            <Tag key={operationType} style={{ marginInlineEnd: 0 }}>
-              {formatOperationLabel(operationType, t)}
-            </Tag>
-          ))}
-        </Space>
+        <TagList
+          items={operationTypes.map((operationType) => ({
+            key: operationType,
+            label: formatOperationLabel(operationType, t),
+          }))}
+          max={2}
+          tagMaxWidth={88}
+        />
       ),
     },
     {
diff --git a/web/src/pages/ops/__tests__/SystemAlertsPage.test.tsx 
b/web/src/pages/ops/__tests__/SystemAlertsPage.test.tsx
index 684879f3b..44929e8b4 100644
--- a/web/src/pages/ops/__tests__/SystemAlertsPage.test.tsx
+++ b/web/src/pages/ops/__tests__/SystemAlertsPage.test.tsx
@@ -322,7 +322,12 @@ describe('SystemAlertsPage', () => {
     renderPage();
     await screen.findByText('Mixed-case error');
 
-    await user.click(screen.getByRole('button', { name: /严重/ }));
+    // 级别筛选是 Segmented:里面的 radio input 带 pointer-events: none,user.click 点不动,
+    // 要点它外层的 .ant-segmented-item label。不能用 getByText('严重')——告警卡片里也渲染同一个词。
+    const severeFilter = screen
+      .getByRole('radio', { name: /严重/ })
+      .closest('.ant-segmented-item') as HTMLElement;
+    await user.click(severeFilter);
 
     await waitFor(() => {
       expect(screen.getByText('Mixed-case error')).toBeInTheDocument();
diff --git a/web/src/pages/ops/alerts.tsx b/web/src/pages/ops/alerts.tsx
index cd40b629b..373e88a46 100644
--- a/web/src/pages/ops/alerts.tsx
+++ b/web/src/pages/ops/alerts.tsx
@@ -40,6 +40,7 @@ import {
 } from 'antd';
 import type { ColumnsType, TableRowSelection } from 'antd/es/table/interface';
 import PageHeader from '../../components/PageHeader';
+import TagList from '../../components/TagList';
 import { useLang } from '../../i18n/LangContext';
 import type {
   AlertRule,
@@ -675,15 +676,16 @@ const AlertsPageContent = ({ domain = 'CLUSTER' }: 
AlertsPageProps) => {
     },
     {
       title: t('alerts.channels'),
-      width: 130,
+      // DingTalk + Email + SMS 三个标签并排实测需 201px(TagList 已把标签自带的 8px margin 归零)
+      width: 210,
       render: (_, record) => (
-        <Flex gap={4} wrap="wrap">
-          {(record.channels ?? []).map((ch) => (
-            <Tag key={ch} color={channelColors[ch]}>
-              {channelLabels[ch]}
-            </Tag>
-          ))}
-        </Flex>
+        <TagList
+          items={(record.channels ?? []).map((ch) => ({
+            key: ch,
+            label: channelLabels[ch],
+            color: channelColors[ch],
+          }))}
+        />
       ),
     },
     {
diff --git a/web/src/pages/ops/audit.tsx b/web/src/pages/ops/audit.tsx
index 498e70402..01b027618 100644
--- a/web/src/pages/ops/audit.tsx
+++ b/web/src/pages/ops/audit.tsx
@@ -29,7 +29,6 @@ import {
   InputNumber,
   Typography,
   message,
-  Space,
   Tooltip,
 } from 'antd';
 import { Trash } from '@phosphor-icons/react';
@@ -38,6 +37,7 @@ import type { ColumnsType } from 'antd/es/table';
 import dayjs from 'dayjs';
 import type { Dayjs } from 'dayjs';
 import PageHeader from '../../components/PageHeader';
+import TagList from '../../components/TagList';
 import { useLang } from '../../i18n/LangContext';
 import type { AuditFilter, AuditFilterOptions, AuditSummary } from 
'../../api/audit';
 import type { AuditRecord } from '../../api/ops';
@@ -280,13 +280,14 @@ const AuditPage: React.FC = () => {
       );
     }
     return (
-      <Space size={[4, 4]} wrap>
-        {tokens.map((token) => (
-          <Tag key={`${token.label}:${token.value}`} style={{ marginInlineEnd: 
0 }}>
-            {token.label}: {token.value}
-          </Tag>
-        ))}
-      </Space>
+      <TagList
+        items={tokens.map((token) => ({
+          key: `${token.label}:${token.value}`,
+          label: `${token.label}: ${token.value}`,
+        }))}
+        max={3}
+        tagMaxWidth={190}
+      />
     );
   };
 
@@ -401,6 +402,14 @@ const AuditPage: React.FC = () => {
     {
       title: t('audit.detail'),
       dataIndex: 'detail',
+      // 三个 token 的自然宽实测 209 + 123 + 104(量 scrollWidth,不能量 
getBoundingClientRect:
+      // 后者在已被 flex-shrink 压窄的单元格里量到的是收缩后的值,拿它算列宽会循环论证)。
+      // 必须用 `width` 不能用 `minWidth`:antd 只把 `width` 落成 <col>,`minWidth` 仅参与
+      // tableScrollX 求和;table-layout:fixed 下没有 width 的列只会和「失败原因」平分余量
+      // (实测各 290),配合 TagList 的 nowrap 会把标签压窄到逐个带省略号。
+      // 450 = 190(tagMaxWidth 上限) + 123 + 104 + gap 8 + 单元格内边距 16,留 9px 余量;
+      // 全表合计 1640,1920 视口下容器 1650,不会引出横向滚动条。
+      width: 450,
       ellipsis: true,
       render: renderDetail,
     },
diff --git a/web/src/pages/ops/systemAlerts.tsx 
b/web/src/pages/ops/systemAlerts.tsx
index 8a01dd885..2347178d3 100644
--- a/web/src/pages/ops/systemAlerts.tsx
+++ b/web/src/pages/ops/systemAlerts.tsx
@@ -31,6 +31,7 @@ import {
   Form,
   Input,
   Popconfirm,
+  Segmented,
 } from 'antd';
 import { CheckCircle, DownloadSimple, Trash } from '@phosphor-icons/react';
 import PageHeader from '../../components/PageHeader';
@@ -509,35 +510,38 @@ const SystemAlertsPage = () => {
         }
       />
 
+      {/* 筛选条:全部控件统一默认尺寸(32px 高),宽度按内容分三档,不再混用 size="small"
+          —— 原来 4 个级别按钮 + 3 个 Select + 4 个 Input 高矮不一(datetime-local 在 small
+          下压不到 24px、实测 26px),宽度也是 132/150/190/124 各写各的。 */}
       <Flex gap={8} wrap align="center" style={{ marginBottom: 16 }}>
-        {['all', 'error', 'warning', 'info'].map((level) => (
-          <Button
-            key={level}
-            type={levelFilter === level ? 'primary' : 'default'}
-            size="small"
-            onClick={() => {
-              setLevelFilter(level);
-              setPage(1);
-            }}
-          >
-            {level === 'all' ? t('common.all') : 
alertLevelConfig[level]?.label}
-            {level !== 'all' && (
-              <Badge
-                count={alerts.filter((a) => normalizeAlertLevel(a.level) === 
level).length}
-                style={{
-                  marginLeft: 4,
-                  backgroundColor:
-                    level === 'error' ? '#ff4d4f' : level === 'warning' ? 
'#fa8c16' : '#1677ff',
-                }}
-                size="small"
-              />
-            )}
-          </Button>
-        ))}
+        <Segmented
+          value={levelFilter}
+          onChange={(value) => {
+            setLevelFilter(String(value));
+            setPage(1);
+          }}
+          options={['all', 'error', 'warning', 'info'].map((level) => ({
+            value: level,
+            label: (
+              <span style={{ display: 'inline-flex', alignItems: 'center', 
gap: 4 }}>
+                {level === 'all' ? t('common.all') : 
alertLevelConfig[level]?.label}
+                {level !== 'all' && (
+                  <Badge
+                    count={alerts.filter((a) => normalizeAlertLevel(a.level) 
=== level).length}
+                    style={{
+                      backgroundColor:
+                        level === 'error' ? '#ff4d4f' : level === 'warning' ? 
'#fa8c16' : '#1677ff',
+                    }}
+                    size="small"
+                  />
+                )}
+              </span>
+            ),
+          }))}
+        />
         <Select
           value={domainFilter}
-          size="small"
-          style={{ minWidth: 132 }}
+          style={{ minWidth: 140 }}
           onChange={(value) => {
             setDomainFilter(value);
             setPage(1);
@@ -550,9 +554,8 @@ const SystemAlertsPage = () => {
         />
         <Input
           aria-label={t('sysAlerts.instanceFilter')}
-          size="small"
           placeholder={t('sysAlerts.instanceId')}
-          style={{ width: 150, flex: 'none' }}
+          style={{ width: 180, flex: 'none' }}
           value={instanceFilter}
           onChange={(event) => {
             setInstanceFilter(event.target.value);
@@ -561,9 +564,8 @@ const SystemAlertsPage = () => {
         />
         <Input
           aria-label={t('sysAlerts.labelsFilter')}
-          size="small"
           placeholder={t('sysAlerts.labelsPlaceholder')}
-          style={{ width: 190, flex: 'none' }}
+          style={{ width: 180, flex: 'none' }}
           value={labelFilter}
           onChange={(event) => {
             setLabelFilter(event.target.value);
@@ -573,8 +575,7 @@ const SystemAlertsPage = () => {
         <Input
           aria-label={t('sysAlerts.startTimeFilter')}
           type="datetime-local"
-          size="small"
-          style={{ width: 190, flex: 'none' }}
+          style={{ width: 210, height: 32, flex: 'none' }}
           value={fromFilter}
           onChange={(event) => {
             setFromFilter(event.target.value);
@@ -584,8 +585,7 @@ const SystemAlertsPage = () => {
         <Input
           aria-label={t('sysAlerts.endTimeFilter')}
           type="datetime-local"
-          size="small"
-          style={{ width: 190, flex: 'none' }}
+          style={{ width: 210, height: 32, flex: 'none' }}
           value={toFilter}
           onChange={(event) => {
             setToFilter(event.target.value);
@@ -594,8 +594,7 @@ const SystemAlertsPage = () => {
         />
         <Select
           value={transitionFilter}
-          size="small"
-          style={{ minWidth: 124 }}
+          style={{ minWidth: 140 }}
           onChange={(value) => {
             setTransitionFilter(value);
             setPage(1);
@@ -609,8 +608,7 @@ const SystemAlertsPage = () => {
         <Select
           aria-label={t('sysAlerts.suppressionFilter')}
           value={suppressionFilter}
-          size="small"
-          style={{ minWidth: 132 }}
+          style={{ minWidth: 160 }}
           onChange={(value) => {
             setSuppressionFilter(value);
             setPage(1);
@@ -622,7 +620,7 @@ const SystemAlertsPage = () => {
           ]}
         />
         {collectorStatus && (
-          <Tag color="success" style={{ marginInlineEnd: 0 }}>
+          <Tag color="success" style={{ marginInlineEnd: 0, fontSize: 14 }}>
             {t('sysAlerts.nativeCollectionEnabled')}
           </Tag>
         )}

Reply via email to