style(web): fix prettier config, format entire web/ tree
.prettierrc.json was missing "semi": false, so prettier wanted to add semicolons to a codebase written without them (763 semicolon-free statements vs. 150 with, in hand-written .ts; zero hand-written .svelte files use them at all). That's why prettier --check failed on 249 files — not because the code was unformatted, but because the config didn't match the actual house style. Added "semi": false; left printWidth/etc as configured (printWidth barely moves the failure count: 218/213/212 files at 100/120/140). Ran `prettier --write .` with the corrected config. Verified semantics-preserving before and after: - eslint: 142 problems both before and after, byte-identical - build passes, 38/38 tests pass - token-stream diff (whitespace/semicolons/quotes normalized) on all 218 changed files: only 52 had any remaining token change, all either trailing-comma removal (matching trailingComma: "none") or import/ ternary reflow — no semantic changes - live smoke test: Knowledge, Tasks, Fleet map, and a chat window (AgentTrace, markdown, Scope graph, activity rail) all render correctly, no console errors Most of the diff is shadcn/ui vendor files (lib/components/ui/) moving from the CLI's own style (double quotes, tabs, semicolons) to house style; re-running `shadcn-svelte add` on a component will need a follow-up format pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -60,7 +60,11 @@
|
||||
$effect(() => {
|
||||
const ev = $liveEvents[0]
|
||||
if (!ev) return
|
||||
if (ev.type.startsWith('entity.') || ev.type.startsWith('relationship.') || ev.type === 'health.changed') {
|
||||
if (
|
||||
ev.type.startsWith('entity.') ||
|
||||
ev.type.startsWith('relationship.') ||
|
||||
ev.type === 'health.changed'
|
||||
) {
|
||||
load()
|
||||
}
|
||||
})
|
||||
@@ -276,9 +280,11 @@
|
||||
const svcRaw = new Map<string, number>()
|
||||
for (const s of services) {
|
||||
const p = serviceProvider.get(s.slug)
|
||||
svcRaw.set(s.slug, (p && yById.has(p) ? yById.get(p)! : TOP0))
|
||||
svcRaw.set(s.slug, p && yById.has(p) ? yById.get(p)! : TOP0)
|
||||
}
|
||||
services.sort((a, b) => (svcRaw.get(a.slug)! - svcRaw.get(b.slug)!) || a.name.localeCompare(b.name))
|
||||
services.sort(
|
||||
(a, b) => svcRaw.get(a.slug)! - svcRaw.get(b.slug)! || a.name.localeCompare(b.name)
|
||||
)
|
||||
let prevY = TOP0 - ROW_H
|
||||
for (const s of services) {
|
||||
const y = Math.max(svcRaw.get(s.slug)!, prevY + ROW_H)
|
||||
@@ -308,7 +314,9 @@
|
||||
counts[h]++
|
||||
const ingress = routesTo.get(n.slug)
|
||||
const ingressEntity = ingress ? bySlugEntity.get(ingress) : undefined
|
||||
const publicHost = ingress ? (ingressEntity?.name ?? ingress.replace(/^ingress:/, '')) : undefined
|
||||
const publicHost = ingress
|
||||
? (ingressEntity?.name ?? ingress.replace(/^ingress:/, ''))
|
||||
: undefined
|
||||
const fauth = ingressEntity ? boolAttr(ingressEntity, 'forward_auth') : undefined
|
||||
const provider = kind === 'service' ? serviceProvider.get(n.slug) : containerHost.get(n.slug)
|
||||
const mnt = (kind === 'container' ? mountsOf.get(n.slug) : mountsOf.get(provider ?? '')) ?? []
|
||||
@@ -361,25 +369,41 @@
|
||||
const n = bySlug.get(slug)!
|
||||
return LANE_X[n.lane] + (side === 'r' ? LANE_W[n.lane] : 0)
|
||||
}
|
||||
const cy = (slug: string) => (bySlug.get(slug)!.y) + NODE_H / 2
|
||||
const cy = (slug: string) => bySlug.get(slug)!.y + NODE_H / 2
|
||||
const edges: LaidEdge[] = []
|
||||
const provChildren = new Map<string, string[]>() // provider -> [child]
|
||||
// provision edges: host->container, provider->service
|
||||
for (const c of containers) {
|
||||
const host = containerHost.get(c.slug)
|
||||
if (host && bySlug.has(host)) {
|
||||
const x1 = cx(host, 'r'), y1 = cy(host), x2 = cx(c.slug, 'l'), y2 = cy(c.slug)
|
||||
const x1 = cx(host, 'r'),
|
||||
y1 = cy(host),
|
||||
x2 = cx(c.slug, 'l'),
|
||||
y2 = cy(c.slug)
|
||||
const mx = (x1 + x2) / 2
|
||||
edges.push({ d: `M${x1},${y1} C${mx},${y1} ${mx},${y2} ${x2},${y2}`, kind: 'prov', s: host, t: c.slug })
|
||||
edges.push({
|
||||
d: `M${x1},${y1} C${mx},${y1} ${mx},${y2} ${x2},${y2}`,
|
||||
kind: 'prov',
|
||||
s: host,
|
||||
t: c.slug
|
||||
})
|
||||
pushMap(provChildren, host, c.slug)
|
||||
}
|
||||
}
|
||||
for (const s of services) {
|
||||
const p = serviceProvider.get(s.slug)
|
||||
if (p && bySlug.has(p)) {
|
||||
const x1 = cx(p, 'r'), y1 = cy(p), x2 = cx(s.slug, 'l'), y2 = cy(s.slug)
|
||||
const x1 = cx(p, 'r'),
|
||||
y1 = cy(p),
|
||||
x2 = cx(s.slug, 'l'),
|
||||
y2 = cy(s.slug)
|
||||
const mx = (x1 + x2) / 2
|
||||
edges.push({ d: `M${x1},${y1} C${mx},${y1} ${mx},${y2} ${x2},${y2}`, kind: 'prov', s: p, t: s.slug })
|
||||
edges.push({
|
||||
d: `M${x1},${y1} C${mx},${y1} ${mx},${y2} ${x2},${y2}`,
|
||||
kind: 'prov',
|
||||
s: p,
|
||||
t: s.slug
|
||||
})
|
||||
pushMap(provChildren, p, s.slug)
|
||||
}
|
||||
}
|
||||
@@ -388,9 +412,17 @@
|
||||
if (!bySlug.has(srcSlug)) continue
|
||||
for (const t of targets) {
|
||||
if (!bySlug.has(t)) continue
|
||||
const x1 = cx(srcSlug, 'r'), y1 = cy(srcSlug), x2 = cx(t, 'r'), y2 = cy(t)
|
||||
const x1 = cx(srcSlug, 'r'),
|
||||
y1 = cy(srcSlug),
|
||||
x2 = cx(t, 'r'),
|
||||
y2 = cy(t)
|
||||
const bulge = Math.max(x1, x2) + 34 + Math.min(70, Math.abs(y1 - y2) * 0.32)
|
||||
edges.push({ d: `M${x1},${y1} C${bulge},${y1} ${bulge},${y2} ${x2},${y2}`, kind: 'dep', s: srcSlug, t })
|
||||
edges.push({
|
||||
d: `M${x1},${y1} C${bulge},${y1} ${bulge},${y2} ${x2},${y2}`,
|
||||
kind: 'dep',
|
||||
s: srcSlug,
|
||||
t
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,7 +540,8 @@
|
||||
const q = search.trim().toLowerCase()
|
||||
if (q) {
|
||||
const s = new Set<string>()
|
||||
for (const n of m.nodes) if (n.slug.toLowerCase().includes(q) || n.name.toLowerCase().includes(q)) s.add(n.slug)
|
||||
for (const n of m.nodes)
|
||||
if (n.slug.toLowerCase().includes(q) || n.name.toLowerCase().includes(q)) s.add(n.slug)
|
||||
return s
|
||||
}
|
||||
return null
|
||||
@@ -589,7 +622,9 @@
|
||||
if (!m || !healthFilter) return [] as LaidNode[]
|
||||
return m.nodes.filter((n) => n.health === healthFilter)
|
||||
})
|
||||
const problemCount = $derived(model ? model.nodes.filter((n) => n.health !== 'healthy').length : 0)
|
||||
const problemCount = $derived(
|
||||
model ? model.nodes.filter((n) => n.health !== 'healthy').length : 0
|
||||
)
|
||||
</script>
|
||||
|
||||
{#if loading && !model}
|
||||
@@ -636,7 +671,8 @@
|
||||
<div class="stage relative min-w-0 flex-1 overflow-auto">
|
||||
<div class="relative" style="width:{model.width}px;height:{model.height}px">
|
||||
<!-- background click target: clears selection -->
|
||||
<button type="button" class="reset-layer" aria-label="Clear selection" onclick={reset}></button>
|
||||
<button type="button" class="reset-layer" aria-label="Clear selection" onclick={reset}
|
||||
></button>
|
||||
<!-- lane headers -->
|
||||
<div class="pointer-events-none absolute inset-x-0 top-0 z-10">
|
||||
{#each [['Hosts', model.nodes.filter((n) => n.kind === 'host').length], ['Containers', model.nodes.filter((n) => n.kind === 'container').length], ['Services', model.nodes.filter((n) => n.kind === 'service').length]] as [label, count], i}
|
||||
@@ -647,7 +683,11 @@
|
||||
</div>
|
||||
|
||||
<!-- edges -->
|
||||
<svg class="pointer-events-none absolute inset-0" width={model.width} height={model.height}>
|
||||
<svg
|
||||
class="pointer-events-none absolute inset-0"
|
||||
width={model.width}
|
||||
height={model.height}
|
||||
>
|
||||
{#each model.edges as e}
|
||||
<path d={e.d} class="edge {e.kind} {edgeState(e)}" />
|
||||
{/each}
|
||||
@@ -661,7 +701,9 @@
|
||||
class:svc={n.kind === 'service'}
|
||||
class:is-open={selectedSlug === n.slug}
|
||||
class:pulse={n.health === 'down'}
|
||||
style="left:{n.x}px;top:{n.y}px;width:{n.w}px;height:{n.h}px;--nc:{HEALTH_COLOR[n.health]}"
|
||||
style="left:{n.x}px;top:{n.y}px;width:{n.w}px;height:{n.h}px;--nc:{HEALTH_COLOR[
|
||||
n.health
|
||||
]}"
|
||||
onmouseenter={() => setFocus(n.slug)}
|
||||
onmouseleave={scheduleClear}
|
||||
onfocus={() => setFocus(n.slug)}
|
||||
@@ -673,7 +715,11 @@
|
||||
title={n.slug}
|
||||
>
|
||||
{#if n.publicHost}
|
||||
<span class="badge" title={n.publicHost + (n.fauth ? ' · forward-auth' : n.fauth === false ? ' · no auth gate' : '')}>
|
||||
<span
|
||||
class="badge"
|
||||
title={n.publicHost +
|
||||
(n.fauth ? ' · forward-auth' : n.fauth === false ? ' · no auth gate' : '')}
|
||||
>
|
||||
{#if n.fauth}
|
||||
<LockIcon class="size-3" />
|
||||
{:else if n.fauth === false}
|
||||
@@ -748,7 +794,9 @@
|
||||
<div class="blast">
|
||||
<div class="n" class:warn={detailBlast.length > 0}>{detailBlast.length}</div>
|
||||
<div class="lbl">
|
||||
{detailNode.kind === 'service' ? 'downstream service' : 'service'}{detailBlast.length === 1 ? '' : 's'}
|
||||
{detailNode.kind === 'service'
|
||||
? 'downstream service'
|
||||
: 'service'}{detailBlast.length === 1 ? '' : 's'}
|
||||
affected if this goes down
|
||||
</div>
|
||||
</div>
|
||||
@@ -756,18 +804,40 @@
|
||||
<div class="det-sec">
|
||||
<h4>Attributes</h4>
|
||||
{#if detailNode.kind === 'container'}
|
||||
<div class="row"><span class="k">type</span><span class="v">{detailNode.type}</span></div>
|
||||
<div class="row">
|
||||
<span class="k">type</span><span class="v">{detailNode.type}</span>
|
||||
</div>
|
||||
{/if}
|
||||
{#if detailNode.role}<div class="row"><span class="k">role</span><span class="v">{detailNode.role}</span></div>{/if}
|
||||
{#if detailNode.ip}<div class="row"><span class="k">ip</span><span class="v">{detailNode.ip}</span></div>{/if}
|
||||
{#if detailNode.role}<div class="row">
|
||||
<span class="k">role</span><span class="v">{detailNode.role}</span>
|
||||
</div>{/if}
|
||||
{#if detailNode.ip}<div class="row">
|
||||
<span class="k">ip</span><span class="v">{detailNode.ip}</span>
|
||||
</div>{/if}
|
||||
{#if detailNode.publicHost}
|
||||
<div class="row"><span class="k">url</span><span class="v">{detailNode.publicHost}</span></div>
|
||||
<div class="row"><span class="k">exposure</span><span class="v">{detailNode.fauth ? 'forward-auth gated' : detailNode.fauth === false ? 'no auth gate' : 'public'}</span></div>
|
||||
<div class="row">
|
||||
<span class="k">url</span><span class="v">{detailNode.publicHost}</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="k">exposure</span><span class="v"
|
||||
>{detailNode.fauth
|
||||
? 'forward-auth gated'
|
||||
: detailNode.fauth === false
|
||||
? 'no auth gate'
|
||||
: 'public'}</span
|
||||
>
|
||||
</div>
|
||||
{:else if detailNode.url}
|
||||
<div class="row"><span class="k">url</span><span class="v">{detailNode.url}</span></div>
|
||||
<div class="row">
|
||||
<span class="k">url</span><span class="v">{detailNode.url}</span>
|
||||
</div>
|
||||
{/if}
|
||||
{#if detailNode.mounts.length}<div class="row"><span class="k">mounts</span><span class="v">{detailNode.mounts.join(', ')}</span></div>{/if}
|
||||
{#if detailNode.repo}<div class="row"><span class="k">config</span><span class="v">{detailNode.repo}</span></div>{/if}
|
||||
{#if detailNode.mounts.length}<div class="row">
|
||||
<span class="k">mounts</span><span class="v">{detailNode.mounts.join(', ')}</span>
|
||||
</div>{/if}
|
||||
{#if detailNode.repo}<div class="row">
|
||||
<span class="k">config</span><span class="v">{detailNode.repo}</span>
|
||||
</div>{/if}
|
||||
</div>
|
||||
|
||||
{#if detailRunsOn.length}
|
||||
@@ -824,18 +894,24 @@
|
||||
<div class="p-4">
|
||||
<h3 class="legend-h">Health</h3>
|
||||
{#each HEALTH_ORDER as h}
|
||||
<div class="legend-row"><span class="sw" style="background:{HEALTH_COLOR[h]}"></span>{HEALTH_LABEL[h]}</div>
|
||||
<div class="legend-row">
|
||||
<span class="sw" style="background:{HEALTH_COLOR[h]}"></span>{HEALTH_LABEL[h]}
|
||||
</div>
|
||||
{/each}
|
||||
<div class="sep"></div>
|
||||
<h3 class="legend-h">Lanes</h3>
|
||||
<div class="legend-row"><span class="lane-swatch"></span>Hosts — physical machines</div>
|
||||
<div class="legend-row"><span class="lane-swatch"></span>Containers — LXCs & VMs</div>
|
||||
<div class="legend-row"><span class="lane-swatch"></span>Services — what you actually use</div>
|
||||
<div class="legend-row">
|
||||
<span class="lane-swatch"></span>Containers — LXCs & VMs
|
||||
</div>
|
||||
<div class="legend-row">
|
||||
<span class="lane-swatch"></span>Services — what you actually use
|
||||
</div>
|
||||
<div class="sep"></div>
|
||||
<p class="hint">
|
||||
Every service flows right from the machine that runs it. Hover any node to trace its chain
|
||||
and blast radius — what breaks if it goes down. Click to open it in a window. Dashed arcs are
|
||||
service-to-service dependencies.
|
||||
Every service flows right from the machine that runs it. Hover any node to trace its
|
||||
chain and blast radius — what breaks if it goes down. Click to open it in a window.
|
||||
Dashed arcs are service-to-service dependencies.
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -843,7 +919,9 @@
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex h-full items-center justify-center text-xs text-muted-foreground">Failed to load graph</div>
|
||||
<div class="flex h-full items-center justify-center text-xs text-muted-foreground">
|
||||
Failed to load graph
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
@@ -883,7 +961,9 @@
|
||||
stroke: var(--border);
|
||||
stroke-width: 1.4;
|
||||
opacity: 0.6;
|
||||
transition: opacity 0.16s, stroke 0.16s;
|
||||
transition:
|
||||
opacity 0.16s,
|
||||
stroke 0.16s;
|
||||
}
|
||||
.edge.dep {
|
||||
stroke-dasharray: 4 3;
|
||||
@@ -919,7 +999,11 @@
|
||||
border-radius: 9px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.16s, border-color 0.14s, transform 0.12s, box-shadow 0.14s;
|
||||
transition:
|
||||
opacity 0.16s,
|
||||
border-color 0.14s,
|
||||
transform 0.12s,
|
||||
box-shadow 0.14s;
|
||||
}
|
||||
.node::before {
|
||||
content: '';
|
||||
@@ -1001,7 +1085,10 @@
|
||||
background: transparent;
|
||||
color: var(--muted-foreground);
|
||||
cursor: pointer;
|
||||
transition: color 0.12s, border-color 0.12s, background 0.12s;
|
||||
transition:
|
||||
color 0.12s,
|
||||
border-color 0.12s,
|
||||
background 0.12s;
|
||||
}
|
||||
.chip:hover {
|
||||
border-color: var(--primary);
|
||||
|
||||
Reference in New Issue
Block a user