This is an automated email from the ASF dual-hosted git repository. zqr10159 pushed a commit to branch 2.0.0 in repository https://gitbox.apache.org/repos/asf/hertzbeat.git
commit 0e284d69c30ef4b59e15067c3f9086ecedd8d2f9 Author: Logic <[email protected]> AuthorDate: Fri May 29 21:58:31 2026 +0800 feat(web-next): expose source-backed topology node legend --- web-next/app/topology/page.test.tsx | 54 ++++++++++++++--------- web-next/app/topology/topology-page.tsx | 23 +++++++++- web-next/app/ui-lab/page.test.tsx | 42 +++++++++++------- web-next/app/ui-lab/page.tsx | 24 +++++++++- web-next/lib/i18n-runtime-messages.ts | 22 ++++++++- web-next/packages/hertzbeat-ui/src/index.test.tsx | 34 ++++++++++---- web-next/packages/hertzbeat-ui/src/index.tsx | 30 +++++++++++-- web-next/test/i18n-test-helper.ts | 22 ++++++++- 8 files changed, 193 insertions(+), 58 deletions(-) diff --git a/web-next/app/topology/page.test.tsx b/web-next/app/topology/page.test.tsx index 3b9495c28f..5f5f377db7 100644 --- a/web-next/app/topology/page.test.tsx +++ b/web-next/app/topology/page.test.tsx @@ -947,31 +947,41 @@ describe('topology page', () => { expect(html).toContain('data-hz-topology-legend-header-owner="hertzbeat-ui-legend-header"'); expect(html).toContain('data-hz-topology-legend-title-owner="hertzbeat-ui-legend-title"'); expect(html).toContain('data-hz-topology-legend-summary-owner="hertzbeat-ui-legend-summary"'); - expect(html).toContain('data-hz-topology-legend-section="status"'); - expect(html).toContain('data-hz-topology-legend-section-owner="hertzbeat-ui-legend-section"'); - expect(html).toContain('data-hz-topology-legend-section-label-owner="hertzbeat-ui-legend-section-label"'); - expect(html).toContain('data-hz-topology-legend-section="interaction"'); - expect(html).not.toContain('data-hz-topology-legend-section="source-kind"'); - expect(html).not.toContain('data-hz-topology-legend-section="confidence"'); - expect(html).toContain('data-hz-topology-legend-item="healthy-node"'); - expect(html).toContain('data-hz-topology-legend-item="warning-node"'); - expect(html).toContain('data-hz-topology-legend-item="critical-node"'); + expect(html).toContain('data-hz-topology-legend-section="status"'); + expect(html).toContain('data-hz-topology-legend-section-owner="hertzbeat-ui-legend-section"'); + expect(html).toContain('data-hz-topology-legend-section-label-owner="hertzbeat-ui-legend-section-label"'); + expect(html).toContain('data-hz-topology-legend-section="node-type"'); + expect(html).toContain('data-hz-topology-legend-section="interaction"'); + expect(html).not.toContain('data-hz-topology-legend-section="source-kind"'); + expect(html).not.toContain('data-hz-topology-legend-section="confidence"'); + expect(html).toContain('data-hz-topology-legend-item="node-type-service"'); + expect(html).toContain('data-hz-topology-legend-item="node-type-database"'); + expect(html).toContain('data-hz-topology-legend-icon-library="lucide-react"'); + expect(html).toContain('data-hz-topology-legend-icon-source="entity-type-catalog"'); + expect(html).toContain('data-hz-topology-legend-icon-name="blocks"'); + expect(html).toContain('data-hz-topology-legend-icon-name="database"'); + expect(html).toContain('data-hz-topology-legend-icon-no-handdrawn="true"'); + expect(html).toContain('data-hz-topology-legend-item="healthy-node"'); + expect(html).toContain('data-hz-topology-legend-item="warning-node"'); + expect(html).toContain('data-hz-topology-legend-item="critical-node"'); expect(html).toContain('data-hz-topology-legend-item="selected-node"'); expect(html).toContain('data-hz-topology-legend-item="directional-edge"'); expect(html).toContain('data-hz-topology-legend-item="dimmed-edge"'); - expect(html).toContain('data-hz-topology-legend-color="#22c55e"'); - expect(html).toContain('data-hz-topology-legend-color="#f59e0b"'); - expect(html).toContain('data-hz-topology-legend-color="#ef4444"'); - expect(html).toContain('data-hz-topology-legend-swatch-shape="line"'); - expect(html).toContain('data-hz-topology-legend-visual-source="hertzbeat-status-token"'); - expect(html).toContain('data-hz-topology-legend-visual-source="hertzbeat-interaction-token"'); - expect(html).toContain('data-hz-topology-legend-visual-source="hertzbeat-edge-token"'); - expect(html).toContain('data-hz-topology-legend-no-handdrawn-icon="true"'); - expect(html).not.toContain('data-hz-topology-legend-swatch-shape="node-ring"'); - expect(html).not.toContain('data-hz-topology-legend-swatch-shape="selected-ring"'); - expect(html).toContain('data-hz-topology-legend-item-owner="hertzbeat-ui-legend-item"'); - expect(html).toContain('data-hz-topology-legend-swatch-owner="hertzbeat-ui-legend-swatch"'); - expect(html).toContain('data-hz-topology-legend-item-label-owner="hertzbeat-ui-legend-item-label"'); + expect(html).toContain('data-hz-topology-legend-color="#22c55e"'); + expect(html).toContain('data-hz-topology-legend-color="#f59e0b"'); + expect(html).toContain('data-hz-topology-legend-color="#ef4444"'); + expect(html).toContain('data-hz-topology-legend-visual-mode="source-backed-text"'); + expect(html).toContain('data-hz-topology-legend-visual-source="lucide-react"'); + expect(html).toContain('data-hz-topology-legend-visual-source="hertzbeat-status-token"'); + expect(html).toContain('data-hz-topology-legend-visual-source="hertzbeat-interaction-token"'); + expect(html).toContain('data-hz-topology-legend-visual-source="hertzbeat-edge-token"'); + expect(html).toContain('data-hz-topology-legend-no-handdrawn-icon="true"'); + expect(html).not.toContain('data-hz-topology-legend-swatch-owner='); + expect(html).not.toContain('data-hz-topology-legend-swatch-shape='); + expect(html).not.toContain('data-hz-topology-legend-swatch-shape="node-ring"'); + expect(html).not.toContain('data-hz-topology-legend-swatch-shape="selected-ring"'); + expect(html).toContain('data-hz-topology-legend-item-owner="hertzbeat-ui-legend-item"'); + expect(html).toContain('data-hz-topology-legend-item-label-owner="hertzbeat-ui-legend-item-label"'); expect(html).toContain('data-hz-topology-legend-item-value-owner="hertzbeat-ui-legend-item-value"'); expect(html).not.toContain('data-hz-topology-legend-pattern="dashed"'); expect(html).toContain('data-topology-detail-drawer-owner="hertzbeat-ui-detail-drawer"'); diff --git a/web-next/app/topology/topology-page.tsx b/web-next/app/topology/topology-page.tsx index 5dd9ec494b..f40c4c4d33 100644 --- a/web-next/app/topology/topology-page.tsx +++ b/web-next/app/topology/topology-page.tsx @@ -42,6 +42,7 @@ import { } from '@hertzbeat/ui'; import { HzTopologyG6Canvas, + HZ_TOPOLOGY_G6_NODE_ICON_CATALOG, buildHzTopologyG6LargeGraphStrategy, buildHzTopologyG6RenderWindow, type HzTopologyG6GraphInput, @@ -1122,8 +1123,28 @@ export default function TopologyPage({ : topologyEmptyStateKind === 'degraded' ? t('topology.degraded.api.source') : 'API'; + const topologyLegendNodeTypeItems = React.useMemo( + () => + HZ_TOPOLOGY_G6_NODE_ICON_CATALOG.filter(icon => icon.kind !== 'unknown').map(icon => ({ + id: `node-type-${icon.kind}`, + label: t(`topology.legend.node-type.${icon.kind}`), + value: icon.iconName, + iconSrc: icon.iconSrc, + iconAlt: '', + iconLibrary: icon.iconLibrary, + iconName: icon.iconName, + iconSource: icon.iconSource, + visualSource: 'lucide-react' as const + })), + [t] + ); const topologyLegendSections = React.useMemo( () => [ + { + id: 'node-type', + label: t('topology.legend.node-type'), + items: topologyLegendNodeTypeItems + }, { id: 'status', label: t('topology.legend.status'), @@ -1181,7 +1202,7 @@ export default function TopologyPage({ ] } ], - [t] + [t, topologyLegendNodeTypeItems] ); const topologyEdgeIds = React.useMemo( () => new Set(map.edges.map(edge => edge.id)), diff --git a/web-next/app/ui-lab/page.test.tsx b/web-next/app/ui-lab/page.test.tsx index 0297d90fcf..6b600075e3 100644 --- a/web-next/app/ui-lab/page.test.tsx +++ b/web-next/app/ui-lab/page.test.tsx @@ -2688,23 +2688,31 @@ describe('HertzBeat UI lab page', () => { expect(html).toContain('data-hz-topology-primitive="legend"'); expect(html).toContain('data-hz-topology-legend-boundary="flush"'); expect(html).toContain('data-hz-topology-legend-boundary-owner="hertzbeat-ui-legend-boundary"'); - expect(html).toContain('data-hz-topology-legend-header-owner="hertzbeat-ui-legend-header"'); - expect(html).toContain('data-hz-topology-legend-section="status"'); - expect(html).toContain('data-hz-topology-legend-section-owner="hertzbeat-ui-legend-section"'); - expect(html).toContain('data-hz-topology-legend-section-label-owner="hertzbeat-ui-legend-section-label"'); - expect(html).toContain('data-hz-topology-legend-section="interaction"'); - expect(html).not.toContain('data-hz-topology-legend-section="confidence"'); - expect(html).toContain('data-hz-topology-legend-swatch-shape="line"'); - expect(html).toContain('data-hz-topology-legend-visual-source="hertzbeat-status-token"'); - expect(html).toContain('data-hz-topology-legend-visual-source="hertzbeat-interaction-token"'); - expect(html).toContain('data-hz-topology-legend-visual-source="hertzbeat-edge-token"'); - expect(html).toContain('data-hz-topology-legend-no-handdrawn-icon="true"'); - expect(html).not.toContain('data-hz-topology-legend-swatch-shape="node-ring"'); - expect(html).not.toContain('data-hz-topology-legend-swatch-shape="selected-ring"'); - expect(html).toContain('data-hz-topology-legend-color="#22c55e"'); - expect(html).toContain('data-hz-topology-legend-item-owner="hertzbeat-ui-legend-item"'); - expect(html).toContain('data-hz-topology-legend-swatch-owner="hertzbeat-ui-legend-swatch"'); - expect(html).toContain('data-hz-topology-legend-item-label-owner="hertzbeat-ui-legend-item-label"'); + expect(html).toContain('data-hz-topology-legend-header-owner="hertzbeat-ui-legend-header"'); + expect(html).toContain('data-hz-topology-legend-section="status"'); + expect(html).toContain('data-hz-topology-legend-section-owner="hertzbeat-ui-legend-section"'); + expect(html).toContain('data-hz-topology-legend-section-label-owner="hertzbeat-ui-legend-section-label"'); + expect(html).toContain('data-hz-topology-legend-section="node-type"'); + expect(html).toContain('data-hz-topology-legend-section="interaction"'); + expect(html).not.toContain('data-hz-topology-legend-section="confidence"'); + expect(html).toContain('data-hz-topology-legend-item="node-type-service"'); + expect(html).toContain('data-hz-topology-legend-item="node-type-database"'); + expect(html).toContain('data-hz-topology-legend-icon-library="lucide-react"'); + expect(html).toContain('data-hz-topology-legend-icon-source="entity-type-catalog"'); + expect(html).toContain('data-hz-topology-legend-icon-no-handdrawn="true"'); + expect(html).toContain('data-hz-topology-legend-visual-source="lucide-react"'); + expect(html).toContain('data-hz-topology-legend-visual-mode="source-backed-text"'); + expect(html).toContain('data-hz-topology-legend-visual-source="hertzbeat-status-token"'); + expect(html).toContain('data-hz-topology-legend-visual-source="hertzbeat-interaction-token"'); + expect(html).toContain('data-hz-topology-legend-visual-source="hertzbeat-edge-token"'); + expect(html).toContain('data-hz-topology-legend-no-handdrawn-icon="true"'); + expect(html).not.toContain('data-hz-topology-legend-swatch-owner='); + expect(html).not.toContain('data-hz-topology-legend-swatch-shape='); + expect(html).not.toContain('data-hz-topology-legend-swatch-shape="node-ring"'); + expect(html).not.toContain('data-hz-topology-legend-swatch-shape="selected-ring"'); + expect(html).toContain('data-hz-topology-legend-color="#22c55e"'); + expect(html).toContain('data-hz-topology-legend-item-owner="hertzbeat-ui-legend-item"'); + expect(html).toContain('data-hz-topology-legend-item-label-owner="hertzbeat-ui-legend-item-label"'); expect(html).not.toContain('data-hz-topology-legend-pattern="dashed"'); expect(html).toContain('data-hz-ui-lab-topology-detail-drawer="shared"'); expect(html).toContain('data-hz-ui="topology-detail-drawer"'); diff --git a/web-next/app/ui-lab/page.tsx b/web-next/app/ui-lab/page.tsx index f49f175e4c..6d4aa16b02 100644 --- a/web-next/app/ui-lab/page.tsx +++ b/web-next/app/ui-lab/page.tsx @@ -204,6 +204,7 @@ import { } from '@hertzbeat/ui'; import { HzTopologyG6Canvas, + HZ_TOPOLOGY_G6_NODE_ICON_CATALOG, buildHzTopologyG6LargeGraphStrategy, buildHzTopologyG6RenderWindow, buildHzTopologyG6ScaleFixture, @@ -494,6 +495,17 @@ const topologyG6LargeGraphStrategy500 = buildHzTopologyG6LargeGraphStrategy(topo const topologyG6ScaleLabRenderWindow500 = buildHzTopologyG6RenderWindow(topologyG6ScaleLabGraph500, topologyG6LargeGraphStrategy500, { priorityNodeIds: ['scale-svc-420'] }); +const topologyG6NodeTypeLegendItems = HZ_TOPOLOGY_G6_NODE_ICON_CATALOG.filter(icon => icon.kind !== 'unknown').map(icon => ({ + id: `node-type-${icon.kind}`, + label: icon.label, + value: icon.iconName, + iconSrc: icon.iconSrc, + iconAlt: '', + iconLibrary: icon.iconLibrary, + iconName: icon.iconName, + iconSource: icon.iconSource, + visualSource: 'lucide-react' as const +})); const monitorRows = [ { name: 'mysql-prod-01', app: 'MySQL', collector: 'collector-a', signal: 'metrics', status: '可用', latency: '38 ms', tone: 'success' as const }, @@ -7000,6 +7012,11 @@ export default function HertzBeatUiLabPage() { boundary="flush" density="canvas-dock" sections={[ + { + id: 'node-type', + label: 'Node type', + items: topologyG6NodeTypeLegendItems + }, { id: 'status', label: 'Status', @@ -7262,9 +7279,14 @@ export default function HertzBeatUiLabPage() { <HzTopologyLegend data-hz-ui-lab-topology-legend="shared" title="Topology legend" - summaryLabel="2 groups" + summaryLabel="3 groups" boundary="flush" sections={[ + { + id: 'node-type', + label: 'Node type', + items: topologyG6NodeTypeLegendItems + }, { id: 'status', label: 'Status', diff --git a/web-next/lib/i18n-runtime-messages.ts b/web-next/lib/i18n-runtime-messages.ts index 84396b91be..74fe659faf 100644 --- a/web-next/lib/i18n-runtime-messages.ts +++ b/web-next/lib/i18n-runtime-messages.ts @@ -984,7 +984,7 @@ export const SUPPLEMENTAL_MESSAGES: Partial<Record<LocaleCode, Messages>> = { 'topology.alert-impact.open': 'Open alert impact', 'topology.alert-impact.copy': 'Keep the selected edge, entity, and signal scope.', 'topology.legend.title': 'Legend', - 'topology.legend.summary': '2 groups', + 'topology.legend.summary': '3 groups', 'topology.legend.health': 'Health', 'topology.legend.health.healthy': 'Healthy', 'topology.legend.health.healthy-value': 'good', @@ -1016,6 +1016,15 @@ export const SUPPLEMENTAL_MESSAGES: Partial<Record<LocaleCode, Messages>> = { 'topology.legend.confidence': 'Confidence', 'topology.legend.confidence.live': 'Current evidence', 'topology.legend.confidence.stale': 'Low confidence / stale', + 'topology.legend.node-type': 'Node type', + 'topology.legend.node-type.application': 'Application', + 'topology.legend.node-type.service': 'Service', + 'topology.legend.node-type.database': 'Database', + 'topology.legend.node-type.middleware': 'Middleware', + 'topology.legend.node-type.k8s-workload': 'Workload', + 'topology.legend.node-type.monitor': 'Monitor', + 'topology.legend.node-type.resource': 'Resource', + 'topology.legend.node-type.alert': 'Alert', 'topology.timeline.title': 'Impact timeline', 'topology.timeline.copy': 'Recent entity, relationship, and monitor evidence that changed this topology view.', 'topology.timeline.detail.fallback': 'Topology evidence changed', @@ -4492,7 +4501,7 @@ export const SUPPLEMENTAL_MESSAGES: Partial<Record<LocaleCode, Messages>> = { 'topology.alert-impact.open': '打开告警影响面', 'topology.alert-impact.copy': '保留当前边、实体和三信号范围。', 'topology.legend.title': '图例', - 'topology.legend.summary': '2 组', + 'topology.legend.summary': '3 组', 'topology.legend.health': '健康状态', 'topology.legend.health.healthy': '健康', 'topology.legend.health.healthy-value': '正常', @@ -4524,6 +4533,15 @@ export const SUPPLEMENTAL_MESSAGES: Partial<Record<LocaleCode, Messages>> = { 'topology.legend.confidence': '可信度', 'topology.legend.confidence.live': '当前窗口证据', 'topology.legend.confidence.stale': '低可信 / 过期', + 'topology.legend.node-type': '节点类型', + 'topology.legend.node-type.application': '应用', + 'topology.legend.node-type.service': '服务', + 'topology.legend.node-type.database': '数据库', + 'topology.legend.node-type.middleware': '中间件', + 'topology.legend.node-type.k8s-workload': '工作负载', + 'topology.legend.node-type.monitor': '监控', + 'topology.legend.node-type.resource': '资源', + 'topology.legend.node-type.alert': '告警', 'topology.timeline.title': '影响时间线', 'topology.timeline.copy': '最近改变当前拓扑视图的实体、关系和监控对象证据。', 'topology.timeline.detail.fallback': '拓扑证据已变更', diff --git a/web-next/packages/hertzbeat-ui/src/index.test.tsx b/web-next/packages/hertzbeat-ui/src/index.test.tsx index a36e11afc9..e045fa1fc7 100644 --- a/web-next/packages/hertzbeat-ui/src/index.test.tsx +++ b/web-next/packages/hertzbeat-ui/src/index.test.tsx @@ -5202,11 +5202,20 @@ describe('@hertzbeat/ui', () => { { id: 'status', label: 'Status', - items: [ - { id: 'healthy-node', label: 'Healthy node', color: '#22c55e', visualSource: 'hertzbeat-status-token' }, - { id: 'critical-node', label: 'Critical node', color: '#ef4444', visualSource: 'hertzbeat-status-token' } - ] - }, + items: [ + { + id: 'service-node', + label: 'Service node', + iconSrc: 'data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%3E%3C/svg%3E', + iconLibrary: 'lucide-react', + iconName: 'blocks', + iconSource: 'entity-type-catalog', + visualSource: 'lucide-react' + }, + { id: 'healthy-node', label: 'Healthy node', color: '#22c55e', visualSource: 'hertzbeat-status-token' }, + { id: 'critical-node', label: 'Critical node', color: '#ef4444', visualSource: 'hertzbeat-status-token' } + ] + }, { id: 'interaction', label: 'Interaction', @@ -5227,10 +5236,17 @@ describe('@hertzbeat/ui', () => { expect(html).toContain('data-hz-topology-legend-summary-visibility="hidden"'); expect(html).toContain('data-hz-topology-legend-section="status"'); expect(html).toContain('data-hz-topology-legend-section="interaction"'); - expect(html).toContain('data-hz-topology-legend-visual-mode="source-backed-text"'); - expect(html).toContain('data-hz-topology-legend-visual-source="hertzbeat-status-token"'); - expect(html).toContain('data-hz-topology-legend-visual-source="hertzbeat-interaction-token"'); - expect(html).toContain('data-hz-topology-legend-visual-source="hertzbeat-edge-token"'); + expect(html).toContain('data-hz-topology-legend-visual-mode="source-backed-text"'); + expect(html).toContain('data-hz-topology-legend-visual-source="lucide-react"'); + expect(html).toContain('data-hz-topology-legend-source-label="lucide-react"'); + expect(html).toContain('data-hz-topology-legend-icon-owner="hertzbeat-ui-legend-source-icon"'); + expect(html).toContain('data-hz-topology-legend-icon-library="lucide-react"'); + expect(html).toContain('data-hz-topology-legend-icon-name="blocks"'); + expect(html).toContain('data-hz-topology-legend-icon-source="entity-type-catalog"'); + expect(html).toContain('data-hz-topology-legend-icon-no-handdrawn="true"'); + expect(html).toContain('data-hz-topology-legend-visual-source="hertzbeat-status-token"'); + expect(html).toContain('data-hz-topology-legend-visual-source="hertzbeat-interaction-token"'); + expect(html).toContain('data-hz-topology-legend-visual-source="hertzbeat-edge-token"'); expect(html).toContain('data-hz-topology-legend-source-label="status token"'); expect(html).toContain('data-hz-topology-legend-source-label="interaction token"'); expect(html).toContain('data-hz-topology-legend-source-label="edge token"'); diff --git a/web-next/packages/hertzbeat-ui/src/index.tsx b/web-next/packages/hertzbeat-ui/src/index.tsx index b3f3fd412a..f9cfcc8d04 100644 --- a/web-next/packages/hertzbeat-ui/src/index.tsx +++ b/web-next/packages/hertzbeat-ui/src/index.tsx @@ -10493,7 +10493,12 @@ export type HzTopologyLegendItem = { color?: string; fill?: string; swatch?: 'line'; - visualSource?: 'hertzbeat-status-token' | 'hertzbeat-interaction-token' | 'hertzbeat-edge-token'; + visualSource?: 'hertzbeat-status-token' | 'hertzbeat-interaction-token' | 'hertzbeat-edge-token' | 'lucide-react'; + iconSrc?: string; + iconAlt?: string; + iconLibrary?: 'lucide-react'; + iconName?: string; + iconSource?: 'entity-type-catalog'; }; export type HzTopologyLegendSection = { @@ -10523,7 +10528,8 @@ const topologyLegendBoundaryClassName: Record<HzTopologyLegendBoundary, string> const topologyLegendVisualSourceLabel: Record<NonNullable<HzTopologyLegendItem['visualSource']>, string> = { 'hertzbeat-status-token': 'status token', 'hertzbeat-interaction-token': 'interaction token', - 'hertzbeat-edge-token': 'edge token' + 'hertzbeat-edge-token': 'edge token', + 'lucide-react': 'lucide-react' }; export type HzTopologyHoverTooltipKind = 'node' | 'edge'; @@ -11288,8 +11294,8 @@ export function HzTopologyLegend({ <div key={item.id} className={cn( - 'grid min-w-0 items-center text-[11px]', - isCanvasDock ? 'min-h-4 grid-cols-[auto] gap-1' : 'min-h-5 grid-cols-[minmax(0,1fr)_auto] gap-2' + 'flex min-w-0 items-center text-[11px]', + isCanvasDock ? 'min-h-4 gap-1' : 'min-h-5 gap-2' )} data-hz-topology-legend-item={item.id} data-hz-topology-legend-item-owner="hertzbeat-ui-legend-item" @@ -11302,6 +11308,22 @@ export function HzTopologyLegend({ data-hz-topology-legend-source-label={sourceLabel} data-hz-topology-legend-no-handdrawn-icon="true" > + {item.iconSrc ? ( + <span + aria-label={item.iconAlt} + role={item.iconAlt ? 'img' : undefined} + className={cn( + 'h-3.5 w-3.5 shrink-0 bg-contain bg-center bg-no-repeat opacity-80', + isCanvasDock ? 'mr-1 inline-block' : 'mr-1.5 inline-block' + )} + style={{ backgroundImage: `url("${item.iconSrc}")` }} + data-hz-topology-legend-icon-owner="hertzbeat-ui-legend-source-icon" + data-hz-topology-legend-icon-library={item.iconLibrary} + data-hz-topology-legend-icon-name={item.iconName} + data-hz-topology-legend-icon-source={item.iconSource} + data-hz-topology-legend-icon-no-handdrawn="true" + /> + ) : null} <span className="min-w-0 truncate text-[#cbd3df]" data-hz-topology-legend-item-label-owner="hertzbeat-ui-legend-item-label" diff --git a/web-next/test/i18n-test-helper.ts b/web-next/test/i18n-test-helper.ts index ed498db025..1f955f4fdd 100644 --- a/web-next/test/i18n-test-helper.ts +++ b/web-next/test/i18n-test-helper.ts @@ -585,7 +585,7 @@ const SUPPLEMENTAL_MESSAGES: Partial<Record<LocaleCode, Messages>> = { 'topology.alert-impact.open': 'Open alert impact', 'topology.alert-impact.copy': 'Keep the selected edge, entity, and signal scope.', 'topology.legend.title': 'Legend', - 'topology.legend.summary': '2 groups', + 'topology.legend.summary': '3 groups', 'topology.legend.health': 'Health', 'topology.legend.health.healthy': 'Healthy', 'topology.legend.health.healthy-value': 'good', @@ -617,6 +617,15 @@ const SUPPLEMENTAL_MESSAGES: Partial<Record<LocaleCode, Messages>> = { 'topology.legend.confidence': 'Confidence', 'topology.legend.confidence.live': 'Current evidence', 'topology.legend.confidence.stale': 'Low confidence / stale', + 'topology.legend.node-type': 'Node type', + 'topology.legend.node-type.application': 'Application', + 'topology.legend.node-type.service': 'Service', + 'topology.legend.node-type.database': 'Database', + 'topology.legend.node-type.middleware': 'Middleware', + 'topology.legend.node-type.k8s-workload': 'Workload', + 'topology.legend.node-type.monitor': 'Monitor', + 'topology.legend.node-type.resource': 'Resource', + 'topology.legend.node-type.alert': 'Alert', 'topology.timeline.title': 'Impact timeline', 'topology.timeline.copy': 'Recent entity, relationship, and monitor evidence that changed this topology view.', 'topology.timeline.detail.fallback': 'Topology evidence changed', @@ -3366,7 +3375,7 @@ const SUPPLEMENTAL_MESSAGES: Partial<Record<LocaleCode, Messages>> = { 'topology.alert-impact.open': '打开告警影响面', 'topology.alert-impact.copy': '保留当前边、实体和三信号范围。', 'topology.legend.title': '图例', - 'topology.legend.summary': '2 组', + 'topology.legend.summary': '3 组', 'topology.legend.health': '健康状态', 'topology.legend.health.healthy': '健康', 'topology.legend.health.healthy-value': '正常', @@ -3398,6 +3407,15 @@ const SUPPLEMENTAL_MESSAGES: Partial<Record<LocaleCode, Messages>> = { 'topology.legend.confidence': '可信度', 'topology.legend.confidence.live': '当前窗口证据', 'topology.legend.confidence.stale': '低可信 / 过期', + 'topology.legend.node-type': '节点类型', + 'topology.legend.node-type.application': '应用', + 'topology.legend.node-type.service': '服务', + 'topology.legend.node-type.database': '数据库', + 'topology.legend.node-type.middleware': '中间件', + 'topology.legend.node-type.k8s-workload': '工作负载', + 'topology.legend.node-type.monitor': '监控', + 'topology.legend.node-type.resource': '资源', + 'topology.legend.node-type.alert': '告警', 'topology.timeline.title': '影响时间线', 'topology.timeline.copy': '最近改变当前拓扑视图的实体、关系和监控对象证据。', 'topology.timeline.detail.fallback': '拓扑证据已变更', --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
