feat: choose which probes link to which agents from the admin

The panel decides the probe/agent pairs and probes always dial out. A new
fleet.auto_link setting connects every probe to every agent (default); with it
off only the pairs chosen by hand connect, and any pair can be forced on or
off. The Probes page has a link matrix with the switch and per-pair toggles.
This commit is contained in:
justme committed 2026-10-06 23:19:32 +08:00
1 parent d69581dcb5
commit 3a751a0f89
24 files changed
+731 -33

No files matched your search

+33 -9
View File
@@ -1205,19 +1205,11 @@ input {
}
/* 版本、tag:等宽的小字 */
.fact .v.mono-tag,
.probe-tag {
.fact .v.mono-tag {
font-family: var(--font-mono);
font-size: 11px;
}
.probe-tag {
padding: 0 6px;
border-radius: 6px;
background: color-mix(in srgb, var(--app-ink) 6%, transparent);
color: var(--app-ink-muted);
}
.build-info {
display: flex;
flex-wrap: wrap;
@@ -1227,3 +1219,35 @@ input {
font-family: var(--font-mono);
font-size: 11px;
}
/* 总览卡片里的线路标题:名字太长就省略号,右边只放一个短标签,不换行 */
.line-top {
min-width: 0;
}
.line-top .line-name {
flex: 1 1 auto;
min-width: 0;
white-space: nowrap;
}
.line-top .line-name .arrow {
flex: none;
}
.line-top .line-name .name {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
}
.line-top .line-name .flag,
.line-top .line-name .isp {
flex: none;
}
.line-top .line-range,
.line-top .chip {
flex: none;
white-space: nowrap;
}
+6 -11
View File
@@ -95,18 +95,13 @@ function Card({ agent, host, range, infos }: { agent: AgentCard; host: HostItem
return (
<Link key={l.id} to={`/line/${encodeURIComponent(l.id)}`} className="line-link">
<div className="line-top">
<span className="line-name">
→ {infos.get(l.probe_id)?.country ? <Flag code={infos.get(l.probe_id)!.country!} /> : null}
{l.probe_name}
<span className="line-name" title={[l.probe_name, infos.get(l.probe_id)?.tag || infos.get(l.probe_id)?.version].filter(Boolean).join(' · ')}>
<span className="arrow">→</span>
{infos.get(l.probe_id)?.country ? <Flag code={infos.get(l.probe_id)!.country!} /> : null}
<span className="name">{l.probe_name}</span>
{infos.get(l.probe_id)?.isp_key ? <IspIcon ispKey={infos.get(l.probe_id)!.isp_key!} name={infos.get(l.probe_id)!.isp_name} /> : null}
</span>
{infos.get(l.probe_id)?.isp_key ? <IspIcon ispKey={infos.get(l.probe_id)!.isp_key!} name={infos.get(l.probe_id)!.isp_name} /> : null}
{infos.get(l.probe_id)?.tag || infos.get(l.probe_id)?.version ? (
<span className="probe-tag" title="Probe 版本">
{infos.get(l.probe_id)?.tag || infos.get(l.probe_id)?.version}
</span>
) : null}
<span className="faint">近 {OVERVIEW_RANGES.find((r) => r.value === range)?.label ?? range}</span>
{!l.probe_connected && l.online ? <Chip tone="warn">Probe 未连接</Chip> : null}
{!l.probe_connected && l.online ? <Chip tone="warn">未连接</Chip> : <span className="faint line-range">{OVERVIEW_RANGES.find((r) => r.value === range)?.label ?? range}</span>}
</div>
<LineStrips lineId={l.id} range={range} m={m} />
</Link>