feat: choose probe/agent links from the admin, fix the overview popover [CI]

The panel decides which probes link to which agents (probes dial out): an
auto-link setting plus per-pair manual overrides with a link matrix in the
admin, and the hovered overview card is lifted above its neighbours.
This commit is contained in:
justme committed 2026-10-06 23:22:45 +08:00
1 parent d449e50791
commit 6e945657c1
32 files changed
+788 -39

No files matched your search

+39 -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,41 @@ 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;
}
/* 悬浮提示弹在卡片右边,会盖到下一张卡片上:每张卡片都有自己的层叠上下文(毛玻璃),所以悬停(提示打开)的那张要整张抬到兄弟卡片之上 */
.agent-card:hover,
.agent-card:has(.pop.open) {
z-index: 30;
}
+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>