diff --git a/src/lib/components/Chart.svelte b/src/lib/components/Chart.svelte index 44539d1..f0ebaa3 100644 --- a/src/lib/components/Chart.svelte +++ b/src/lib/components/Chart.svelte @@ -48,10 +48,41 @@ const fmtY = $derived(unit === 'bytes' ? formatBytes : formatNumber) + // Every pod of one deployment shares a long, identical name prefix — the k8s + // resource name and project id (`web-123-…`, or `0d456-123-…` for id-named + // deployments). That prefix is the same on every line, so in the legend it's + // pure noise that pushes the part that actually differs (the pod hash) off + // the edge. Strip the longest prefix common to all lines, trimmed back to a + // '-' boundary so whole name segments are removed (never a hash mid-token). + // This also hides the otherwise-opaque `0d` resource name. + const podPrefixLen = $derived.by(() => { + /** @type {string[]} */ + const names = [] + for (const s of series ?? []) { + for (const l of (s.lines ?? [])) names.push(l.name ?? '') + } + if (names.length < 2) return 0 + let p = names[0] + for (let i = 1; i < names.length && p; i++) { + const n = names[i] + let j = 0 + while (j < p.length && j < n.length && p[j] === n[j]) j++ + p = p.slice(0, j) + } + const cut = p.lastIndexOf('-') + return cut >= 0 ? cut + 1 : 0 + }) + + /** @param {string} name */ + function podLabel (name) { + return name.slice(podPrefixLen) || name + } + // Flatten {prefix, lines[]} into one drawable line each. A single-line series // keeps the bare prefix ("Usage"); multi-line series disambiguate with the - // line's own name ("Usage · web"). The first solid line gets the area fill so - // the panel reads as one primary trend with reference lines layered over it. + // pod's distinguishing suffix ("Usage · x2k9p"). The first solid line gets the + // area fill so the panel reads as one primary trend with reference lines + // layered over it. const flat = $derived.by(() => { let areaUsed = false /** @type {import('$lib/charts/util').LineSeries[]} */ @@ -63,7 +94,7 @@ const area = !dashed && !areaUsed if (area) areaUsed = true out.push({ - name: lines.length > 1 ? `${s.prefix} · ${l.name}` : s.prefix, + name: lines.length > 1 ? `${s.prefix} · ${podLabel(l.name)}` : s.prefix, color: resolveColor(s.color), dashed, area, diff --git a/src/lib/deployment/podName.js b/src/lib/deployment/podName.js new file mode 100644 index 0000000..6c7bd13 --- /dev/null +++ b/src/lib/deployment/podName.js @@ -0,0 +1,35 @@ +// Pod names are `---`. The +// `-` part is the deployment's k8s service name — exactly +// what the API returns as `internalAddress` — and is identical on every pod, so +// repeating it (in the logs pod chip, or inside event messages) is pure noise +// that buries the part identifying the individual pod. For id-named deployments +// it's also the opaque `d` resource name the user never chose. These +// helpers strip that prefix wherever it appears, leaving just the pod-specific +// suffix (`-`). + +/** @param {string} s */ +function escapeRegExp (s) { + return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') +} + +/** + * Build a function that strips the deployment's `--` prefix + * from any text — a bare pod name (logs) or pod references embedded in free-text + * event messages. + * + * @param {{ internalAddress?: string }} [deployment] + * @returns {(text?: string) => string} + */ +export function podPrefixStripper (deployment) { + const addr = (deployment?.internalAddress ?? '').trim() + const alts = [] + // Primary: the exact service name (`-`). Guard against + // the field ever being an IP or empty by requiring the `-` + // shape so we never build a prefix that matches arbitrary text. + if (/^[a-z0-9-]+-\d+$/i.test(addr)) alts.push(escapeRegExp(addr)) + // Fallback: any id-based prefix (`d-`), so the opaque + // resource name is still hidden even when internalAddress is unavailable. + alts.push('d\\d+-\\d+') + const re = new RegExp('(?:' + alts.join('|') + ')-', 'g') + return (text) => (text ?? '').replace(re, '') +} diff --git a/src/lib/server/mock.js b/src/lib/server/mock.js index 77a329e..ae23c07 100644 --- a/src/lib/server/mock.js +++ b/src/lib/server/mock.js @@ -48,6 +48,17 @@ function metricLine (name, base) { return [{ name, points }] } +// Two pods of one id-named deployment (`d---`), +// matching how the live (non-aggregate) `deployment.metrics` lines are keyed by +// full pod name. Lets the metrics page exercise the legend's shared-prefix +// stripping (only the trailing pod hash should show). +const MOCK_PODS = ['d128-77-7d8f9b6c5-x2k9p', 'd128-77-7d8f9b6c5-q8m2t'] + +/** @param {number} base */ +function metricPodLines (base) { + return MOCK_PODS.map((name, i) => metricLine(name, base * (i === 0 ? 1 : 0.72))[0]) +} + /** * dailyMetricLine builds a single daily series — one [unixSeconds, value] point * per day at midnight for the trailing 30 days — for the daily usage charts. @@ -163,7 +174,9 @@ function deployment (project = 'acme') { podsUrl: '', statusUrl: HEALTHY_STATUS_URL, address: '203.0.113.10', - internalAddress: '10.0.0.10', + // `-` (the in-cluster service name); id-named here so + // the logs/events pages exercise pod-name prefix stripping. + internalAddress: 'd128-77', status: 'success', action: 'deploy', allocatedPrice: 120.5, @@ -870,13 +883,13 @@ const handlers = { } })), 'deployment.metrics': () => ok({ - cpuUsage: metricLine('web', 0.3), - cpuLimit: metricLine('limit', 0.5), - memoryUsage: metricLine('web', 268435456), - memory: metricLine('allocated', 402653184), - memoryLimit: metricLine('limit', 536870912), - requests: metricLine('web', 120), - egress: metricLine('web', 1048576) + cpuUsage: metricPodLines(0.3), + cpuLimit: metricPodLines(0.5), + memoryUsage: metricPodLines(268435456), + memory: metricPodLines(402653184), + memoryLimit: metricPodLines(536870912), + requests: metricPodLines(120), + egress: metricPodLines(1048576) }), 'disk.list': () => list(disks), diff --git a/src/routes/(auth)/(project)/deployment/(detail)/events/+page.svelte b/src/routes/(auth)/(project)/deployment/(detail)/events/+page.svelte index e4e8a2a..1fed42a 100644 --- a/src/routes/(auth)/(project)/deployment/(detail)/events/+page.svelte +++ b/src/routes/(auth)/(project)/deployment/(detail)/events/+page.svelte @@ -1,10 +1,16 @@