fix(network-map): подписать unbound-пути парой серверов
Docker images / prepare-release (push) Successful in 7s
Docker images / backend-test (push) Successful in 2m22s
Docker images / frontend-image (push) Successful in 3m29s
Docker images / updater-image (push) Successful in 52s
Docker images / backend-image (push) Successful in 2m41s
Docker images / notify-webhook (push) Skipped
Docker images / publish-release (push) Successful in 12s
Docker images / prepare-release (push) Successful in 7s
Docker images / backend-test (push) Successful in 2m22s
Docker images / frontend-image (push) Successful in 3m29s
Docker images / updater-image (push) Successful in 52s
Docker images / backend-image (push) Successful in 2m41s
Docker images / notify-webhook (push) Skipped
Docker images / publish-release (push) Successful in 12s
Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -67,6 +67,7 @@ import {
|
|||||||
CableIcon, CopyIcon, ActivityIcon, ExternalLinkIcon,
|
CableIcon, CopyIcon, ActivityIcon, ExternalLinkIcon,
|
||||||
} from "lucide-react"
|
} from "lucide-react"
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
|
import { formatServicePathLabel, formatServicePathTitle } from "@/lib/format-service-path-label"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { Flag } from "@/components/flag"
|
import { Flag } from "@/components/flag"
|
||||||
|
|
||||||
@@ -820,9 +821,15 @@ function ServicePathList({
|
|||||||
{paths.map((p) => {
|
{paths.map((p) => {
|
||||||
const rowKey = servicePathKey(p)
|
const rowKey = servicePathKey(p)
|
||||||
const via = servers.find((s) => s.id === p.viaId)
|
const via = servers.find((s) => s.id === p.viaId)
|
||||||
const viaLabel = via?.site || p.viaName
|
const en = servers.find((s) => s.id === p.enId)
|
||||||
const svc = services.find((s) => s.id === p.serviceId)
|
const svc = services.find((s) => s.id === p.serviceId)
|
||||||
const mid = viaMode === "via" ? viaLabel : (svc?.label ?? p.serviceId)
|
const label = formatServicePathLabel(p, viaMode, {
|
||||||
|
viaName: via?.name,
|
||||||
|
viaSite: via?.site,
|
||||||
|
enName: en?.name,
|
||||||
|
serviceLabel: svc?.label,
|
||||||
|
})
|
||||||
|
const title = formatServicePathTitle(label, svc?.label ?? p.serviceId)
|
||||||
const active = Boolean(
|
const active = Boolean(
|
||||||
highlight
|
highlight
|
||||||
&& highlight.viaId === p.viaId
|
&& highlight.viaId === p.viaId
|
||||||
@@ -833,13 +840,14 @@ function ServicePathList({
|
|||||||
<button
|
<button
|
||||||
key={rowKey}
|
key={rowKey}
|
||||||
type="button"
|
type="button"
|
||||||
|
title={title}
|
||||||
onClick={() => onToggle(p)}
|
onClick={() => onToggle(p)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center justify-between gap-2 rounded-md px-2 py-1.5 text-left text-xs transition-colors",
|
"flex items-center justify-between gap-2 rounded-md px-2 py-1.5 text-left text-xs transition-colors",
|
||||||
active ? "bg-cyan-500/15 ring-1 ring-cyan-500/40" : "hover:bg-muted/50",
|
active ? "bg-cyan-500/15 ring-1 ring-cyan-500/40" : "hover:bg-muted/50",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span className="font-mono truncate min-w-0">{p.clientName} · {mid}</span>
|
<span className="font-mono truncate min-w-0">{label}</span>
|
||||||
<span className="font-mono text-emerald-400 tabular-nums shrink-0">
|
<span className="font-mono text-emerald-400 tabular-nums shrink-0">
|
||||||
{formatNetflowRate({ bytes: p.bytes, bps: p.bps, bpsFwd: p.bps, bpsRev: 0 })}
|
{formatNetflowRate({ bytes: p.bytes, bps: p.bps, bpsFwd: p.bps, bpsRev: 0 })}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import assert from "node:assert/strict"
|
||||||
|
import {
|
||||||
|
formatServicePathLabel,
|
||||||
|
formatServicePathTitle,
|
||||||
|
isUnboundServicePath,
|
||||||
|
} from "./format-service-path-label.ts"
|
||||||
|
|
||||||
|
const bound = {
|
||||||
|
clientId: "u1",
|
||||||
|
clientName: "D",
|
||||||
|
viaId: "7",
|
||||||
|
viaName: "nsk-gw01",
|
||||||
|
enId: "9",
|
||||||
|
enName: "arn-gw01",
|
||||||
|
serviceId: "svc:cdn",
|
||||||
|
}
|
||||||
|
|
||||||
|
const jhEn = {
|
||||||
|
clientId: "—",
|
||||||
|
clientName: "—",
|
||||||
|
viaId: "7",
|
||||||
|
viaName: "msk-gw01",
|
||||||
|
enId: "9",
|
||||||
|
enName: "arn-gw01",
|
||||||
|
serviceId: "svc:cdn",
|
||||||
|
}
|
||||||
|
|
||||||
|
const enOnly = {
|
||||||
|
clientId: "—",
|
||||||
|
clientName: "—",
|
||||||
|
viaId: "9",
|
||||||
|
viaName: "arn-gw01",
|
||||||
|
enId: "9",
|
||||||
|
enName: "arn-gw01",
|
||||||
|
serviceId: "svc:cdn",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.equal(isUnboundServicePath(jhEn), true)
|
||||||
|
assert.equal(isUnboundServicePath(bound), false)
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
formatServicePathLabel(jhEn, "via", { viaName: "msk-gw01.rtnt.top", enName: "arn-gw01.rtnt.top" }),
|
||||||
|
"msk-gw01.rtnt.top → arn-gw01.rtnt.top",
|
||||||
|
)
|
||||||
|
assert.equal(formatServicePathLabel(enOnly, "via"), "arn-gw01 · без привязки")
|
||||||
|
assert.equal(formatServicePathLabel(enOnly, "service"), "arn-gw01 · без привязки")
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
formatServicePathLabel(bound, "via", { viaSite: "NSK" }),
|
||||||
|
"D · NSK",
|
||||||
|
)
|
||||||
|
assert.equal(
|
||||||
|
formatServicePathLabel(bound, "service", { serviceLabel: "CDN" }),
|
||||||
|
"D · CDN",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
formatServicePathTitle("msk-gw01 → arn-gw01", "CDN"),
|
||||||
|
"msk-gw01 → arn-gw01 · CDN",
|
||||||
|
)
|
||||||
|
|
||||||
|
console.log("format-service-path-label.test.ts: ok")
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
export const UNBOUND_PATH_CLIENT = "—"
|
||||||
|
|
||||||
|
export interface ServicePathLabelInput {
|
||||||
|
clientId: string
|
||||||
|
clientName: string
|
||||||
|
viaId: string
|
||||||
|
viaName: string
|
||||||
|
enId: string
|
||||||
|
enName: string
|
||||||
|
serviceId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServicePathLabelNames {
|
||||||
|
viaName?: string
|
||||||
|
viaSite?: string
|
||||||
|
enName?: string
|
||||||
|
serviceLabel?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isUnboundServicePath(p: Pick<ServicePathLabelInput, "clientId" | "clientName">): boolean {
|
||||||
|
return p.clientId === UNBOUND_PATH_CLIENT || p.clientName === UNBOUND_PATH_CLIENT
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatServicePathLabel(
|
||||||
|
p: ServicePathLabelInput,
|
||||||
|
viaMode: "via" | "service",
|
||||||
|
names: ServicePathLabelNames = {},
|
||||||
|
): string {
|
||||||
|
const viaName = names.viaName || p.viaName
|
||||||
|
const enName = names.enName || p.enName
|
||||||
|
if (isUnboundServicePath(p)) {
|
||||||
|
if (p.viaId !== p.enId) return `${viaName} → ${enName}`
|
||||||
|
return `${enName} · без привязки`
|
||||||
|
}
|
||||||
|
const viaLabel = names.viaSite || p.viaName
|
||||||
|
const mid = viaMode === "via" ? viaLabel : (names.serviceLabel || p.serviceId)
|
||||||
|
return `${p.clientName} · ${mid}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatServicePathTitle(label: string, serviceLabel: string): string {
|
||||||
|
const svc = serviceLabel.trim()
|
||||||
|
if (!svc) return label
|
||||||
|
if (label.includes(svc)) return label
|
||||||
|
return `${label} · ${svc}`
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user