feat(nodes-ui): agent 行地址纯文本显示 IP+更新徽标防误亮(第13条)

地址列: agent 行渲染 ipv4/ipv6 纯文本(两行), 不再是面板 URL 链接;
传统行保持链接。面板版本列: agent 行不参与"有可用更新"判定
(版本比较对 "agent x.y" 字符串走不等回退会恒亮)。
This commit is contained in:
Muse
2026-10-22 11:33:58 +00:00
parent 3536d4174e
commit 487b074801
2 changed files with 37 additions and 10 deletions
+25 -2
View File
@@ -363,7 +363,24 @@ export default function NodeList({
), ),
dataIndex: 'url', dataIndex: 'url',
ellipsis: true, ellipsis: true,
render: (_value, record) => ( render: (_value, record) => {
if (record.nodeType === 'agent') {
// Agent nodes have no panel to link to: show the host IPs the
// agent reports with its heartbeat as plain text (P13).
const ips = [record.ipv4, record.ipv6].filter(Boolean) as string[];
return (
<span className={showAddress ? 'address-visible' : 'address-hidden'}>
{ips.length > 0
? ips.map((ip) => (
<span key={ip} style={{ display: 'block' }}>
{ip}
</span>
))
: '-'}
</span>
);
}
return (
<a <a
href={record.url} href={record.url}
target="_blank" target="_blank"
@@ -372,7 +389,8 @@ export default function NodeList({
> >
{record.url} {record.url}
</a> </a>
), );
},
}, },
{ {
title: t('pages.nodes.status'), title: t('pages.nodes.status'),
@@ -418,7 +436,12 @@ export default function NodeList({
dataIndex: 'panelVersion', dataIndex: 'panelVersion',
align: 'center', align: 'center',
render: (_value, record) => { render: (_value, record) => {
// Agent rows carry an "agent <version>" label, not an upstream
// panel version: the update badge must never light up for them
// (the version comparator falls back to string inequality for
// unparseable versions, which would always differ) (P13).
const canUpdate = const canUpdate =
record.nodeType !== 'agent' &&
isUpdateEligible(record) && isUpdateEligible(record) &&
isPanelUpdateAvailable(latestVersion, record.panelVersion || ''); isPanelUpdateAvailable(latestVersion, record.panelVersion || '');
return ( return (
+4
View File
@@ -47,6 +47,10 @@ export const NodeRecordSchema = z
// P7: node kind, annotated by the backend for nodes registered by an // P7: node kind, annotated by the backend for nodes registered by an
// agent. Absent/traditional for classic panel-to-panel nodes. // agent. Absent/traditional for classic panel-to-panel nodes.
nodeType: z.enum(['traditional', 'agent']).optional(), nodeType: z.enum(['traditional', 'agent']).optional(),
// P13: host IPv4/IPv6 an agent reports with its heartbeat telemetry.
// Rendered as plain text in the address column for agent rows.
ipv4: z.string().optional(),
ipv6: z.string().optional(),
}) })
.loose(); .loose();