@neat.is/web 0.2.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/api/events/route.ts +54 -0
- package/app/api/graph/blast-radius/[id]/route.ts +19 -0
- package/app/api/graph/node/[id]/route.ts +17 -0
- package/app/api/graph/root-cause/[id]/route.ts +17 -0
- package/app/api/graph/route.ts +12 -0
- package/app/api/health/route.ts +13 -0
- package/app/api/incidents/route.ts +16 -0
- package/app/api/policies/violations/route.ts +11 -0
- package/app/api/projects/route.ts +11 -0
- package/app/api/search/route.ts +17 -0
- package/app/api/stale-events/route.ts +15 -0
- package/app/claude-design/Neat Graph View.html +925 -0
- package/app/claude-design/app.js +604 -0
- package/app/components/AppShell.tsx +109 -0
- package/app/components/GraphCanvas.tsx +607 -0
- package/app/components/Inspector.tsx +329 -0
- package/app/components/Rail.tsx +124 -0
- package/app/components/StatusBar.tsx +72 -0
- package/app/components/TopBar.tsx +211 -0
- package/app/favicon.ico +0 -0
- package/app/globals.css +891 -0
- package/app/incidents/page.tsx +145 -0
- package/app/layout.tsx +27 -0
- package/app/page.tsx +5 -0
- package/lib/fixtures.ts +94 -0
- package/lib/proxy.ts +16 -0
- package/package.json +53 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,925 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<title>NEAT — Graph</title>
|
|
6
|
+
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
|
7
|
+
|
|
8
|
+
<!-- Type: serif primary, mono for technical surfaces, sans only where serif/mono can't carry the UX -->
|
|
9
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
+
<link href="https://fonts.googleapis.com/css2?family=Spectral:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400&family=JetBrains+Mono:wght@400;500;600&family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
|
|
12
|
+
|
|
13
|
+
<script src="https://unpkg.com/cytoscape@3.28.1/dist/cytoscape.min.js"></script>
|
|
14
|
+
<script src="graph-data.js"></script>
|
|
15
|
+
|
|
16
|
+
<style>
|
|
17
|
+
/* ------------------------------------------------------------------
|
|
18
|
+
PALETTE — "ink and paper, in the dark"
|
|
19
|
+
The neat.is palette is restrained off-white on a near-black ink.
|
|
20
|
+
We carry that to the product: warm-paper text on a deep ink ground,
|
|
21
|
+
with arbitrary saturated hues reserved EXCLUSIVELY for provenance.
|
|
22
|
+
------------------------------------------------------------------ */
|
|
23
|
+
:root {
|
|
24
|
+
--ink-0: #0a0a0b; /* page */
|
|
25
|
+
--ink-1: #111114; /* panels */
|
|
26
|
+
--ink-2: #16161a; /* raised */
|
|
27
|
+
--ink-3: #1d1d22; /* hover */
|
|
28
|
+
--ink-4: #26262d; /* divider strong */
|
|
29
|
+
--rule: #232328; /* hairlines */
|
|
30
|
+
--rule-soft: #1a1a1f;
|
|
31
|
+
|
|
32
|
+
--paper-0: #f4efe6; /* primary text (warm) */
|
|
33
|
+
--paper-1: #d8d3c9; /* body */
|
|
34
|
+
--paper-2: #9b968c; /* secondary */
|
|
35
|
+
--paper-3: #6a675f; /* tertiary */
|
|
36
|
+
--paper-4: #46443f; /* faint */
|
|
37
|
+
|
|
38
|
+
--accent: #c8a25a; /* singular brand accent — used sparingly */
|
|
39
|
+
|
|
40
|
+
/* PROVENANCE — these are the only "color" colors in the UI.
|
|
41
|
+
Picked to be perceptually distinct, all desaturated enough to
|
|
42
|
+
sit on dark without screaming. */
|
|
43
|
+
--prov-static: #6ea8ff; /* cool blue — declared in code */
|
|
44
|
+
--prov-observed: #5fcf9e; /* green — seen at runtime */
|
|
45
|
+
--prov-inferred: #d27ad8; /* magenta — model's best guess */
|
|
46
|
+
|
|
47
|
+
/* node-type tinting — neutral grays with subtle hue shifts */
|
|
48
|
+
--n-service: #d8d3c9;
|
|
49
|
+
--n-db: #b8c7c2;
|
|
50
|
+
--n-cache: #c2b8a8;
|
|
51
|
+
--n-stream: #b8b0c8;
|
|
52
|
+
--n-queue: #b8b0c8;
|
|
53
|
+
--n-lambda: #c8c0a8;
|
|
54
|
+
--n-cron: #b09c8a;
|
|
55
|
+
--n-api: #a8b8c8;
|
|
56
|
+
--n-apigw: #98a8b8;
|
|
57
|
+
--n-compute: #c8b098;
|
|
58
|
+
--n-storage: #a8a89c;
|
|
59
|
+
--n-external: #888278;
|
|
60
|
+
--n-search: #c4b6a0;
|
|
61
|
+
--n-cluster: #5a5750;
|
|
62
|
+
--n-namespace: #45433d;
|
|
63
|
+
--n-vpc: #38362f;
|
|
64
|
+
--n-env: #2a2823;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
* { box-sizing: border-box; }
|
|
68
|
+
html, body {
|
|
69
|
+
margin: 0; padding: 0;
|
|
70
|
+
height: 100%; width: 100%;
|
|
71
|
+
background: var(--ink-0);
|
|
72
|
+
color: var(--paper-1);
|
|
73
|
+
font-family: 'Spectral', 'Iowan Old Style', Georgia, serif;
|
|
74
|
+
font-feature-settings: "ss01", "kern", "liga";
|
|
75
|
+
-webkit-font-smoothing: antialiased;
|
|
76
|
+
overflow: hidden;
|
|
77
|
+
}
|
|
78
|
+
.mono { font-family: 'JetBrains Mono', ui-monospace, monospace; font-feature-settings: "ss02", "calt", "zero"; }
|
|
79
|
+
.sans { font-family: 'Inter', -apple-system, system-ui, sans-serif; }
|
|
80
|
+
.serif { font-family: 'Spectral', Georgia, serif; }
|
|
81
|
+
|
|
82
|
+
/* ------------------------------------------------------------------
|
|
83
|
+
APP SHELL — top bar / left rail / canvas / right panel / status
|
|
84
|
+
------------------------------------------------------------------ */
|
|
85
|
+
.app {
|
|
86
|
+
display: grid;
|
|
87
|
+
grid-template-columns: 56px 1fr 360px;
|
|
88
|
+
grid-template-rows: 44px 1fr 28px;
|
|
89
|
+
grid-template-areas:
|
|
90
|
+
"topbar topbar topbar"
|
|
91
|
+
"rail canvas inspect"
|
|
92
|
+
"rail status status";
|
|
93
|
+
height: 100vh;
|
|
94
|
+
width: 100vw;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* ---- TOP BAR ------------------------------------------------------ */
|
|
98
|
+
.topbar {
|
|
99
|
+
grid-area: topbar;
|
|
100
|
+
display: flex;
|
|
101
|
+
align-items: center;
|
|
102
|
+
border-bottom: 1px solid var(--rule);
|
|
103
|
+
background: var(--ink-1);
|
|
104
|
+
padding-right: 8px;
|
|
105
|
+
user-select: none;
|
|
106
|
+
}
|
|
107
|
+
.brand {
|
|
108
|
+
width: 56px;
|
|
109
|
+
height: 100%;
|
|
110
|
+
display: flex;
|
|
111
|
+
align-items: center;
|
|
112
|
+
justify-content: center;
|
|
113
|
+
border-right: 1px solid var(--rule);
|
|
114
|
+
font-family: 'Spectral', Georgia, serif;
|
|
115
|
+
font-weight: 500;
|
|
116
|
+
font-style: italic;
|
|
117
|
+
font-size: 22px;
|
|
118
|
+
color: var(--paper-0);
|
|
119
|
+
letter-spacing: 0.01em;
|
|
120
|
+
}
|
|
121
|
+
.brand::after {
|
|
122
|
+
content: "";
|
|
123
|
+
width: 4px; height: 4px;
|
|
124
|
+
background: var(--accent);
|
|
125
|
+
border-radius: 50%;
|
|
126
|
+
margin-left: 2px;
|
|
127
|
+
margin-bottom: -10px;
|
|
128
|
+
}
|
|
129
|
+
.crumbs {
|
|
130
|
+
display: flex;
|
|
131
|
+
align-items: center;
|
|
132
|
+
gap: 8px;
|
|
133
|
+
padding: 0 14px;
|
|
134
|
+
color: var(--paper-2);
|
|
135
|
+
font-size: 13px;
|
|
136
|
+
letter-spacing: 0.01em;
|
|
137
|
+
}
|
|
138
|
+
.crumbs .sep { color: var(--paper-4); }
|
|
139
|
+
.crumbs .here { color: var(--paper-0); font-style: italic; }
|
|
140
|
+
.crumbs .repo {
|
|
141
|
+
font-family: 'JetBrains Mono', monospace;
|
|
142
|
+
font-size: 12px;
|
|
143
|
+
color: var(--paper-1);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.topbar-spacer { flex: 1; }
|
|
147
|
+
|
|
148
|
+
.top-search {
|
|
149
|
+
display: flex;
|
|
150
|
+
align-items: center;
|
|
151
|
+
gap: 8px;
|
|
152
|
+
background: var(--ink-2);
|
|
153
|
+
border: 1px solid var(--rule);
|
|
154
|
+
border-radius: 4px;
|
|
155
|
+
padding: 4px 10px;
|
|
156
|
+
width: 320px;
|
|
157
|
+
color: var(--paper-2);
|
|
158
|
+
font-family: 'JetBrains Mono', monospace;
|
|
159
|
+
font-size: 12px;
|
|
160
|
+
}
|
|
161
|
+
.top-search input {
|
|
162
|
+
background: transparent;
|
|
163
|
+
border: 0; outline: 0;
|
|
164
|
+
color: var(--paper-0);
|
|
165
|
+
font: inherit;
|
|
166
|
+
flex: 1;
|
|
167
|
+
}
|
|
168
|
+
.top-search .kbd {
|
|
169
|
+
color: var(--paper-3);
|
|
170
|
+
font-size: 10.5px;
|
|
171
|
+
border: 1px solid var(--rule-soft);
|
|
172
|
+
padding: 1px 5px;
|
|
173
|
+
border-radius: 3px;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.top-actions { display: flex; align-items: center; gap: 4px; margin-left: 10px; }
|
|
177
|
+
.top-btn {
|
|
178
|
+
height: 28px;
|
|
179
|
+
padding: 0 10px;
|
|
180
|
+
background: transparent;
|
|
181
|
+
color: var(--paper-1);
|
|
182
|
+
border: 1px solid transparent;
|
|
183
|
+
border-radius: 4px;
|
|
184
|
+
font-family: 'Spectral', Georgia, serif;
|
|
185
|
+
font-size: 13px;
|
|
186
|
+
cursor: pointer;
|
|
187
|
+
display: flex; align-items: center; gap: 6px;
|
|
188
|
+
}
|
|
189
|
+
.top-btn:hover { background: var(--ink-2); border-color: var(--rule); }
|
|
190
|
+
.top-btn.primary {
|
|
191
|
+
background: var(--paper-0);
|
|
192
|
+
color: var(--ink-0);
|
|
193
|
+
font-weight: 500;
|
|
194
|
+
}
|
|
195
|
+
.top-btn.primary:hover { background: #fff; }
|
|
196
|
+
.top-btn .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--prov-observed); }
|
|
197
|
+
|
|
198
|
+
.env-pill {
|
|
199
|
+
display: inline-flex; align-items: center; gap: 6px;
|
|
200
|
+
padding: 3px 8px 3px 7px;
|
|
201
|
+
background: var(--ink-2);
|
|
202
|
+
border: 1px solid var(--rule);
|
|
203
|
+
border-radius: 3px;
|
|
204
|
+
color: var(--paper-1);
|
|
205
|
+
font-family: 'JetBrains Mono', monospace;
|
|
206
|
+
font-size: 11.5px;
|
|
207
|
+
}
|
|
208
|
+
.env-pill .dot {
|
|
209
|
+
width: 6px; height: 6px; border-radius: 50%;
|
|
210
|
+
background: var(--prov-observed);
|
|
211
|
+
box-shadow: 0 0 0 2px rgba(95, 207, 158, 0.18);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* ---- LEFT RAIL ---------------------------------------------------- */
|
|
215
|
+
.rail {
|
|
216
|
+
grid-area: rail;
|
|
217
|
+
background: var(--ink-1);
|
|
218
|
+
border-right: 1px solid var(--rule);
|
|
219
|
+
display: flex;
|
|
220
|
+
flex-direction: column;
|
|
221
|
+
align-items: center;
|
|
222
|
+
padding: 6px 0;
|
|
223
|
+
gap: 2px;
|
|
224
|
+
}
|
|
225
|
+
.rail-group {
|
|
226
|
+
display: flex; flex-direction: column; align-items: center;
|
|
227
|
+
gap: 2px;
|
|
228
|
+
padding: 4px 0;
|
|
229
|
+
}
|
|
230
|
+
.rail-group + .rail-group { border-top: 1px solid var(--rule); margin-top: 4px; }
|
|
231
|
+
.rail-btn {
|
|
232
|
+
width: 36px; height: 36px;
|
|
233
|
+
border-radius: 4px;
|
|
234
|
+
display: flex; align-items: center; justify-content: center;
|
|
235
|
+
color: var(--paper-2);
|
|
236
|
+
cursor: pointer;
|
|
237
|
+
position: relative;
|
|
238
|
+
}
|
|
239
|
+
.rail-btn:hover { background: var(--ink-2); color: var(--paper-0); }
|
|
240
|
+
.rail-btn.active {
|
|
241
|
+
background: var(--ink-3);
|
|
242
|
+
color: var(--paper-0);
|
|
243
|
+
}
|
|
244
|
+
.rail-btn.active::before {
|
|
245
|
+
content: "";
|
|
246
|
+
position: absolute; left: -1px; top: 8px; bottom: 8px;
|
|
247
|
+
width: 2px; background: var(--accent);
|
|
248
|
+
border-radius: 0 2px 2px 0;
|
|
249
|
+
}
|
|
250
|
+
.rail-btn svg { width: 18px; height: 18px; stroke-width: 1.4; }
|
|
251
|
+
.rail-btn .badge {
|
|
252
|
+
position: absolute; top: 4px; right: 4px;
|
|
253
|
+
min-width: 14px; height: 14px;
|
|
254
|
+
background: var(--prov-inferred);
|
|
255
|
+
color: var(--ink-0);
|
|
256
|
+
border-radius: 7px;
|
|
257
|
+
font-family: 'JetBrains Mono', monospace;
|
|
258
|
+
font-size: 9px;
|
|
259
|
+
font-weight: 600;
|
|
260
|
+
display: flex; align-items: center; justify-content: center;
|
|
261
|
+
padding: 0 3px;
|
|
262
|
+
}
|
|
263
|
+
.rail-tip {
|
|
264
|
+
position: absolute; left: 44px; top: 50%; transform: translateY(-50%);
|
|
265
|
+
background: var(--ink-3);
|
|
266
|
+
border: 1px solid var(--rule);
|
|
267
|
+
color: var(--paper-0);
|
|
268
|
+
padding: 4px 8px;
|
|
269
|
+
border-radius: 3px;
|
|
270
|
+
font-size: 11.5px;
|
|
271
|
+
font-family: 'Spectral', serif;
|
|
272
|
+
white-space: nowrap;
|
|
273
|
+
pointer-events: none;
|
|
274
|
+
opacity: 0;
|
|
275
|
+
transition: opacity 0.12s;
|
|
276
|
+
z-index: 50;
|
|
277
|
+
}
|
|
278
|
+
.rail-tip .k { color: var(--paper-3); margin-left: 8px; font-family: 'JetBrains Mono', monospace; font-size: 10.5px;}
|
|
279
|
+
.rail-btn:hover .rail-tip { opacity: 1; }
|
|
280
|
+
.rail-spacer { flex: 1; }
|
|
281
|
+
|
|
282
|
+
/* ---- CANVAS ------------------------------------------------------- */
|
|
283
|
+
.canvas-wrap {
|
|
284
|
+
grid-area: canvas;
|
|
285
|
+
position: relative;
|
|
286
|
+
overflow: hidden;
|
|
287
|
+
background:
|
|
288
|
+
radial-gradient(circle at 20% 0%, rgba(110, 168, 255, 0.04) 0%, transparent 40%),
|
|
289
|
+
radial-gradient(circle at 80% 100%, rgba(210, 122, 216, 0.03) 0%, transparent 45%),
|
|
290
|
+
var(--ink-0);
|
|
291
|
+
}
|
|
292
|
+
/* faint paper grid */
|
|
293
|
+
.canvas-wrap::before {
|
|
294
|
+
content: "";
|
|
295
|
+
position: absolute; inset: 0;
|
|
296
|
+
background-image:
|
|
297
|
+
linear-gradient(to right, rgba(244, 239, 230, 0.018) 1px, transparent 1px),
|
|
298
|
+
linear-gradient(to bottom, rgba(244, 239, 230, 0.018) 1px, transparent 1px);
|
|
299
|
+
background-size: 24px 24px;
|
|
300
|
+
pointer-events: none;
|
|
301
|
+
}
|
|
302
|
+
#cy {
|
|
303
|
+
position: absolute; inset: 0;
|
|
304
|
+
width: 100%; height: 100%;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/* canvas-overlay chrome */
|
|
308
|
+
.canvas-tag {
|
|
309
|
+
position: absolute; top: 12px; left: 14px;
|
|
310
|
+
display: flex; align-items: baseline; gap: 10px;
|
|
311
|
+
color: var(--paper-2);
|
|
312
|
+
pointer-events: none;
|
|
313
|
+
z-index: 5;
|
|
314
|
+
}
|
|
315
|
+
.canvas-tag .title {
|
|
316
|
+
font-family: 'Spectral', serif;
|
|
317
|
+
font-style: italic;
|
|
318
|
+
font-size: 18px;
|
|
319
|
+
color: var(--paper-0);
|
|
320
|
+
}
|
|
321
|
+
.canvas-tag .meta {
|
|
322
|
+
font-family: 'JetBrains Mono', monospace;
|
|
323
|
+
font-size: 11px;
|
|
324
|
+
color: var(--paper-3);
|
|
325
|
+
letter-spacing: 0.02em;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.canvas-toolbar {
|
|
329
|
+
position: absolute; top: 12px; right: 14px;
|
|
330
|
+
display: flex; gap: 4px;
|
|
331
|
+
background: var(--ink-1);
|
|
332
|
+
border: 1px solid var(--rule);
|
|
333
|
+
border-radius: 4px;
|
|
334
|
+
padding: 3px;
|
|
335
|
+
z-index: 5;
|
|
336
|
+
}
|
|
337
|
+
.canvas-toolbar button {
|
|
338
|
+
height: 26px;
|
|
339
|
+
padding: 0 9px;
|
|
340
|
+
background: transparent;
|
|
341
|
+
border: 0;
|
|
342
|
+
color: var(--paper-1);
|
|
343
|
+
font-family: 'Spectral', serif;
|
|
344
|
+
font-size: 12.5px;
|
|
345
|
+
cursor: pointer;
|
|
346
|
+
border-radius: 3px;
|
|
347
|
+
display: flex; align-items: center; gap: 6px;
|
|
348
|
+
}
|
|
349
|
+
.canvas-toolbar button:hover { background: var(--ink-3); color: var(--paper-0); }
|
|
350
|
+
.canvas-toolbar button.on {
|
|
351
|
+
background: var(--ink-3);
|
|
352
|
+
color: var(--paper-0);
|
|
353
|
+
}
|
|
354
|
+
.canvas-toolbar .div { width: 1px; background: var(--rule); margin: 4px 2px; }
|
|
355
|
+
.canvas-toolbar .mono { font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--paper-2); }
|
|
356
|
+
|
|
357
|
+
/* PROVENANCE LEGEND */
|
|
358
|
+
.legend {
|
|
359
|
+
position: absolute;
|
|
360
|
+
left: 14px; bottom: 14px;
|
|
361
|
+
background: var(--ink-1);
|
|
362
|
+
border: 1px solid var(--rule);
|
|
363
|
+
border-radius: 4px;
|
|
364
|
+
padding: 10px 12px 11px;
|
|
365
|
+
z-index: 6;
|
|
366
|
+
min-width: 220px;
|
|
367
|
+
}
|
|
368
|
+
.legend h4 {
|
|
369
|
+
margin: 0 0 8px;
|
|
370
|
+
font-family: 'Spectral', serif;
|
|
371
|
+
font-style: italic;
|
|
372
|
+
font-weight: 500;
|
|
373
|
+
font-size: 12px;
|
|
374
|
+
color: var(--paper-2);
|
|
375
|
+
letter-spacing: 0.04em;
|
|
376
|
+
text-transform: uppercase;
|
|
377
|
+
}
|
|
378
|
+
.legend-row {
|
|
379
|
+
display: flex; align-items: center; gap: 9px;
|
|
380
|
+
padding: 4px 0;
|
|
381
|
+
font-size: 12.5px;
|
|
382
|
+
color: var(--paper-1);
|
|
383
|
+
cursor: pointer;
|
|
384
|
+
}
|
|
385
|
+
.legend-row .swatch {
|
|
386
|
+
width: 18px; height: 2px; border-radius: 1px;
|
|
387
|
+
flex-shrink: 0;
|
|
388
|
+
}
|
|
389
|
+
.legend-row .swatch.dashed {
|
|
390
|
+
background: transparent;
|
|
391
|
+
border-top: 1.5px dashed var(--prov-observed);
|
|
392
|
+
height: 0;
|
|
393
|
+
}
|
|
394
|
+
.legend-row .swatch.dotted {
|
|
395
|
+
background: transparent;
|
|
396
|
+
border-top: 2px dotted var(--prov-inferred);
|
|
397
|
+
height: 0;
|
|
398
|
+
}
|
|
399
|
+
.legend-row .name {
|
|
400
|
+
font-family: 'Spectral', serif;
|
|
401
|
+
font-style: italic;
|
|
402
|
+
flex: 1;
|
|
403
|
+
}
|
|
404
|
+
.legend-row .ct {
|
|
405
|
+
font-family: 'JetBrains Mono', monospace;
|
|
406
|
+
font-size: 11px;
|
|
407
|
+
color: var(--paper-3);
|
|
408
|
+
}
|
|
409
|
+
.legend-rule {
|
|
410
|
+
height: 1px;
|
|
411
|
+
background: var(--rule);
|
|
412
|
+
margin: 8px -12px 8px;
|
|
413
|
+
}
|
|
414
|
+
.legend .nodes-grid {
|
|
415
|
+
display: grid; grid-template-columns: 1fr 1fr; column-gap: 12px; row-gap: 4px;
|
|
416
|
+
font-size: 11px;
|
|
417
|
+
}
|
|
418
|
+
.legend .nodes-grid .nrow {
|
|
419
|
+
display: flex; align-items: center; gap: 7px;
|
|
420
|
+
color: var(--paper-2);
|
|
421
|
+
}
|
|
422
|
+
.legend .nodes-grid .nrow .nsq {
|
|
423
|
+
width: 9px; height: 9px; border-radius: 2px;
|
|
424
|
+
flex-shrink: 0;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/* MINIMAP */
|
|
428
|
+
.minimap {
|
|
429
|
+
position: absolute;
|
|
430
|
+
right: 14px; bottom: 14px;
|
|
431
|
+
width: 220px; height: 150px;
|
|
432
|
+
background: var(--ink-1);
|
|
433
|
+
border: 1px solid var(--rule);
|
|
434
|
+
border-radius: 4px;
|
|
435
|
+
z-index: 6;
|
|
436
|
+
overflow: hidden;
|
|
437
|
+
}
|
|
438
|
+
.minimap canvas { width: 100%; height: 100%; display: block; }
|
|
439
|
+
.minimap .frame {
|
|
440
|
+
position: absolute;
|
|
441
|
+
border: 1px solid var(--accent);
|
|
442
|
+
background: rgba(200, 162, 90, 0.08);
|
|
443
|
+
pointer-events: none;
|
|
444
|
+
}
|
|
445
|
+
.minimap-label {
|
|
446
|
+
position: absolute; top: 4px; left: 6px;
|
|
447
|
+
font-family: 'Spectral', serif;
|
|
448
|
+
font-style: italic;
|
|
449
|
+
font-size: 11px;
|
|
450
|
+
color: var(--paper-3);
|
|
451
|
+
pointer-events: none;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/* ZOOM CONTROLS */
|
|
455
|
+
.zoomctl {
|
|
456
|
+
position: absolute;
|
|
457
|
+
right: 14px; top: 56px;
|
|
458
|
+
display: flex; flex-direction: column;
|
|
459
|
+
background: var(--ink-1);
|
|
460
|
+
border: 1px solid var(--rule);
|
|
461
|
+
border-radius: 4px;
|
|
462
|
+
z-index: 5;
|
|
463
|
+
overflow: hidden;
|
|
464
|
+
}
|
|
465
|
+
.zoomctl button {
|
|
466
|
+
width: 30px; height: 28px;
|
|
467
|
+
background: transparent;
|
|
468
|
+
border: 0;
|
|
469
|
+
color: var(--paper-1);
|
|
470
|
+
cursor: pointer;
|
|
471
|
+
display: flex; align-items: center; justify-content: center;
|
|
472
|
+
}
|
|
473
|
+
.zoomctl button:hover { background: var(--ink-3); color: var(--paper-0); }
|
|
474
|
+
.zoomctl button + button { border-top: 1px solid var(--rule); }
|
|
475
|
+
|
|
476
|
+
/* ---- INSPECTOR --------------------------------------------------- */
|
|
477
|
+
.inspect {
|
|
478
|
+
grid-area: inspect;
|
|
479
|
+
background: var(--ink-1);
|
|
480
|
+
border-left: 1px solid var(--rule);
|
|
481
|
+
overflow-y: auto;
|
|
482
|
+
overflow-x: hidden;
|
|
483
|
+
}
|
|
484
|
+
.inspect-tabs {
|
|
485
|
+
display: flex;
|
|
486
|
+
border-bottom: 1px solid var(--rule);
|
|
487
|
+
padding: 0 10px;
|
|
488
|
+
gap: 4px;
|
|
489
|
+
}
|
|
490
|
+
.inspect-tab {
|
|
491
|
+
padding: 10px 8px 9px;
|
|
492
|
+
font-family: 'Spectral', serif;
|
|
493
|
+
font-size: 13px;
|
|
494
|
+
color: var(--paper-2);
|
|
495
|
+
cursor: pointer;
|
|
496
|
+
border-bottom: 1px solid transparent;
|
|
497
|
+
margin-bottom: -1px;
|
|
498
|
+
}
|
|
499
|
+
.inspect-tab.on {
|
|
500
|
+
color: var(--paper-0);
|
|
501
|
+
border-bottom-color: var(--accent);
|
|
502
|
+
font-style: italic;
|
|
503
|
+
}
|
|
504
|
+
.inspect-tab .ct {
|
|
505
|
+
font-family: 'JetBrains Mono', monospace;
|
|
506
|
+
font-size: 10.5px;
|
|
507
|
+
color: var(--paper-3);
|
|
508
|
+
margin-left: 4px;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
.insp-section { padding: 14px 16px 18px; }
|
|
512
|
+
.insp-section + .insp-section { border-top: 1px solid var(--rule); }
|
|
513
|
+
|
|
514
|
+
.insp-eyebrow {
|
|
515
|
+
font-family: 'JetBrains Mono', monospace;
|
|
516
|
+
font-size: 10.5px;
|
|
517
|
+
color: var(--paper-3);
|
|
518
|
+
text-transform: uppercase;
|
|
519
|
+
letter-spacing: 0.08em;
|
|
520
|
+
margin-bottom: 6px;
|
|
521
|
+
}
|
|
522
|
+
.insp-title {
|
|
523
|
+
font-family: 'Spectral', serif;
|
|
524
|
+
font-size: 22px;
|
|
525
|
+
line-height: 1.2;
|
|
526
|
+
color: var(--paper-0);
|
|
527
|
+
font-weight: 400;
|
|
528
|
+
word-break: break-word;
|
|
529
|
+
}
|
|
530
|
+
.insp-title .stem { font-style: italic; color: var(--paper-2); margin-right: 4px; }
|
|
531
|
+
.insp-sub {
|
|
532
|
+
font-family: 'JetBrains Mono', monospace;
|
|
533
|
+
font-size: 11px;
|
|
534
|
+
color: var(--paper-2);
|
|
535
|
+
margin-top: 6px;
|
|
536
|
+
word-break: break-all;
|
|
537
|
+
}
|
|
538
|
+
.insp-tags {
|
|
539
|
+
display: flex; flex-wrap: wrap; gap: 5px;
|
|
540
|
+
margin-top: 10px;
|
|
541
|
+
}
|
|
542
|
+
.tag {
|
|
543
|
+
font-family: 'JetBrains Mono', monospace;
|
|
544
|
+
font-size: 10.5px;
|
|
545
|
+
padding: 2px 6px;
|
|
546
|
+
border-radius: 2px;
|
|
547
|
+
background: var(--ink-3);
|
|
548
|
+
color: var(--paper-1);
|
|
549
|
+
border: 1px solid var(--rule);
|
|
550
|
+
}
|
|
551
|
+
.tag.alive { color: var(--prov-observed); border-color: rgba(95,207,158,0.25); }
|
|
552
|
+
.tag.warn { color: var(--prov-inferred); border-color: rgba(210,122,216,0.25); }
|
|
553
|
+
|
|
554
|
+
.kv {
|
|
555
|
+
display: grid;
|
|
556
|
+
grid-template-columns: 110px 1fr;
|
|
557
|
+
column-gap: 12px;
|
|
558
|
+
row-gap: 4px;
|
|
559
|
+
font-size: 12px;
|
|
560
|
+
}
|
|
561
|
+
.kv dt {
|
|
562
|
+
font-family: 'Spectral', serif;
|
|
563
|
+
font-style: italic;
|
|
564
|
+
color: var(--paper-3);
|
|
565
|
+
}
|
|
566
|
+
.kv dd {
|
|
567
|
+
margin: 0;
|
|
568
|
+
font-family: 'JetBrains Mono', monospace;
|
|
569
|
+
color: var(--paper-1);
|
|
570
|
+
word-break: break-all;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
.insp-h {
|
|
574
|
+
font-family: 'Spectral', serif;
|
|
575
|
+
font-style: italic;
|
|
576
|
+
font-weight: 500;
|
|
577
|
+
color: var(--paper-0);
|
|
578
|
+
font-size: 13px;
|
|
579
|
+
margin: 0 0 8px;
|
|
580
|
+
display: flex; align-items: baseline; justify-content: space-between;
|
|
581
|
+
}
|
|
582
|
+
.insp-h .ct {
|
|
583
|
+
font-family: 'JetBrains Mono', monospace;
|
|
584
|
+
font-size: 10.5px;
|
|
585
|
+
font-style: normal;
|
|
586
|
+
color: var(--paper-3);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
.edge-list { list-style: none; margin: 0; padding: 0; }
|
|
590
|
+
.edge-list li {
|
|
591
|
+
display: flex; align-items: center; gap: 8px;
|
|
592
|
+
padding: 5px 0;
|
|
593
|
+
font-size: 12px;
|
|
594
|
+
border-bottom: 1px dashed var(--rule-soft);
|
|
595
|
+
}
|
|
596
|
+
.edge-list li:last-child { border-bottom: 0; }
|
|
597
|
+
.edge-list .verb {
|
|
598
|
+
font-family: 'Spectral', serif;
|
|
599
|
+
font-style: italic;
|
|
600
|
+
color: var(--paper-2);
|
|
601
|
+
width: 70px;
|
|
602
|
+
flex-shrink: 0;
|
|
603
|
+
}
|
|
604
|
+
.edge-list .target {
|
|
605
|
+
font-family: 'JetBrains Mono', monospace;
|
|
606
|
+
color: var(--paper-1);
|
|
607
|
+
flex: 1;
|
|
608
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
609
|
+
}
|
|
610
|
+
.edge-list .pdot {
|
|
611
|
+
width: 6px; height: 6px; border-radius: 50%;
|
|
612
|
+
flex-shrink: 0;
|
|
613
|
+
}
|
|
614
|
+
.edge-list .pdot.STATIC { background: var(--prov-static); }
|
|
615
|
+
.edge-list .pdot.OBSERVED { background: var(--prov-observed); }
|
|
616
|
+
.edge-list .pdot.INFERRED { background: var(--prov-inferred); }
|
|
617
|
+
.edge-list .conf {
|
|
618
|
+
font-family: 'JetBrains Mono', monospace;
|
|
619
|
+
font-size: 10.5px;
|
|
620
|
+
color: var(--paper-3);
|
|
621
|
+
width: 32px;
|
|
622
|
+
text-align: right;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/* metric strip */
|
|
626
|
+
.metrics {
|
|
627
|
+
display: grid;
|
|
628
|
+
grid-template-columns: 1fr 1fr 1fr;
|
|
629
|
+
gap: 10px;
|
|
630
|
+
}
|
|
631
|
+
.metric {
|
|
632
|
+
background: var(--ink-2);
|
|
633
|
+
border: 1px solid var(--rule);
|
|
634
|
+
border-radius: 3px;
|
|
635
|
+
padding: 8px 10px;
|
|
636
|
+
}
|
|
637
|
+
.metric .lbl {
|
|
638
|
+
font-family: 'Spectral', serif;
|
|
639
|
+
font-style: italic;
|
|
640
|
+
font-size: 11px;
|
|
641
|
+
color: var(--paper-3);
|
|
642
|
+
}
|
|
643
|
+
.metric .val {
|
|
644
|
+
font-family: 'JetBrains Mono', monospace;
|
|
645
|
+
font-size: 16px;
|
|
646
|
+
color: var(--paper-0);
|
|
647
|
+
margin-top: 2px;
|
|
648
|
+
}
|
|
649
|
+
.metric .delta {
|
|
650
|
+
font-family: 'JetBrains Mono', monospace;
|
|
651
|
+
font-size: 10.5px;
|
|
652
|
+
color: var(--prov-observed);
|
|
653
|
+
margin-top: 1px;
|
|
654
|
+
}
|
|
655
|
+
.metric .delta.bad { color: #e87a7a; }
|
|
656
|
+
|
|
657
|
+
/* ---- STATUS BAR -------------------------------------------------- */
|
|
658
|
+
.status {
|
|
659
|
+
grid-area: status;
|
|
660
|
+
border-top: 1px solid var(--rule);
|
|
661
|
+
background: var(--ink-1);
|
|
662
|
+
display: flex;
|
|
663
|
+
align-items: center;
|
|
664
|
+
padding: 0 10px;
|
|
665
|
+
gap: 14px;
|
|
666
|
+
color: var(--paper-2);
|
|
667
|
+
font-family: 'JetBrains Mono', monospace;
|
|
668
|
+
font-size: 11px;
|
|
669
|
+
}
|
|
670
|
+
.status .st-item { display: flex; align-items: center; gap: 6px; }
|
|
671
|
+
.status .st-item .k { color: var(--paper-3); }
|
|
672
|
+
.status .st-item .v { color: var(--paper-1); }
|
|
673
|
+
.status .st-spacer { flex: 1; }
|
|
674
|
+
.status .live::before {
|
|
675
|
+
content: ""; display: inline-block;
|
|
676
|
+
width: 6px; height: 6px; border-radius: 50%;
|
|
677
|
+
background: var(--prov-observed);
|
|
678
|
+
margin-right: 6px;
|
|
679
|
+
box-shadow: 0 0 0 0 rgba(95,207,158,0.5);
|
|
680
|
+
animation: pulse 1.8s infinite;
|
|
681
|
+
}
|
|
682
|
+
@keyframes pulse {
|
|
683
|
+
0% { box-shadow: 0 0 0 0 rgba(95,207,158,0.45); }
|
|
684
|
+
70% { box-shadow: 0 0 0 6px rgba(95,207,158,0); }
|
|
685
|
+
100% { box-shadow: 0 0 0 0 rgba(95,207,158,0); }
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/* time scrubber */
|
|
689
|
+
.scrub {
|
|
690
|
+
display: flex; align-items: center; gap: 8px;
|
|
691
|
+
background: var(--ink-2);
|
|
692
|
+
border: 1px solid var(--rule);
|
|
693
|
+
border-radius: 3px;
|
|
694
|
+
padding: 2px 8px;
|
|
695
|
+
height: 20px;
|
|
696
|
+
}
|
|
697
|
+
.scrub .bar {
|
|
698
|
+
width: 220px; height: 4px;
|
|
699
|
+
background: var(--ink-3);
|
|
700
|
+
border-radius: 2px;
|
|
701
|
+
position: relative;
|
|
702
|
+
}
|
|
703
|
+
.scrub .bar .fill {
|
|
704
|
+
position: absolute; left: 0; top: 0; bottom: 0;
|
|
705
|
+
width: 78%;
|
|
706
|
+
background: linear-gradient(to right, rgba(110,168,255,0.4), rgba(95,207,158,0.6));
|
|
707
|
+
border-radius: 2px;
|
|
708
|
+
}
|
|
709
|
+
.scrub .bar .head {
|
|
710
|
+
position: absolute; left: 78%; top: -3px;
|
|
711
|
+
width: 2px; height: 10px; background: var(--accent);
|
|
712
|
+
}
|
|
713
|
+
.scrub .now { color: var(--paper-1); }
|
|
714
|
+
|
|
715
|
+
/* scrollbars */
|
|
716
|
+
::-webkit-scrollbar { width: 8px; height: 8px; }
|
|
717
|
+
::-webkit-scrollbar-track { background: transparent; }
|
|
718
|
+
::-webkit-scrollbar-thumb { background: var(--ink-3); border-radius: 4px; }
|
|
719
|
+
::-webkit-scrollbar-thumb:hover { background: var(--ink-4); }
|
|
720
|
+
</style>
|
|
721
|
+
</head>
|
|
722
|
+
<body>
|
|
723
|
+
|
|
724
|
+
<div class="app" data-screen-label="Graph View">
|
|
725
|
+
|
|
726
|
+
<!-- ============================ TOP BAR ============================ -->
|
|
727
|
+
<header class="topbar">
|
|
728
|
+
<div class="brand" title="NEAT">N</div>
|
|
729
|
+
|
|
730
|
+
<div class="crumbs">
|
|
731
|
+
<span class="repo">bloomberg-platform</span>
|
|
732
|
+
<span class="sep">/</span>
|
|
733
|
+
<span class="env-pill"><span class="dot"></span>prod-bbg-terminal</span>
|
|
734
|
+
<span class="sep">/</span>
|
|
735
|
+
<span class="here">graph view</span>
|
|
736
|
+
</div>
|
|
737
|
+
|
|
738
|
+
<div class="topbar-spacer"></div>
|
|
739
|
+
|
|
740
|
+
<div class="top-search">
|
|
741
|
+
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><circle cx="11" cy="11" r="7"/><path d="m20 20-3-3"/></svg>
|
|
742
|
+
<input placeholder="find · query · @author · #service" />
|
|
743
|
+
<span class="kbd">⌘K</span>
|
|
744
|
+
</div>
|
|
745
|
+
|
|
746
|
+
<div class="top-actions">
|
|
747
|
+
<button class="top-btn"><span class="dot"></span>Live</button>
|
|
748
|
+
<button class="top-btn">
|
|
749
|
+
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M12 8v4l3 2"/><circle cx="12" cy="12" r="9"/></svg>
|
|
750
|
+
History
|
|
751
|
+
</button>
|
|
752
|
+
<button class="top-btn">
|
|
753
|
+
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M4 17V7l8-4 8 4v10l-8 4-8-4Z"/><path d="m4 7 8 4 8-4"/><path d="M12 11v10"/></svg>
|
|
754
|
+
Share
|
|
755
|
+
</button>
|
|
756
|
+
</div>
|
|
757
|
+
</header>
|
|
758
|
+
|
|
759
|
+
<!-- ============================ LEFT RAIL ========================== -->
|
|
760
|
+
<nav class="rail">
|
|
761
|
+
<div class="rail-group">
|
|
762
|
+
<div class="rail-btn active">
|
|
763
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="6" cy="6" r="2.5"/><circle cx="18" cy="6" r="2.5"/><circle cx="6" cy="18" r="2.5"/><circle cx="18" cy="18" r="2.5"/><path d="M8 6h8M6 8v8M18 8v8M8 18h8"/></svg>
|
|
764
|
+
<span class="rail-tip">Graph<span class="k">G</span></span>
|
|
765
|
+
</div>
|
|
766
|
+
<div class="rail-btn">
|
|
767
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 7h16M4 12h10M4 17h16"/></svg>
|
|
768
|
+
<span class="rail-tip">Layers<span class="k">L</span></span>
|
|
769
|
+
</div>
|
|
770
|
+
<div class="rail-btn">
|
|
771
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="11" cy="11" r="6"/><path d="m20 20-4-4"/></svg>
|
|
772
|
+
<span class="rail-tip">Find<span class="k">F</span></span>
|
|
773
|
+
</div>
|
|
774
|
+
</div>
|
|
775
|
+
|
|
776
|
+
<div class="rail-group">
|
|
777
|
+
<div class="rail-btn">
|
|
778
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 4h6v6H4zM14 4h6v6h-6zM4 14h6v6H4zM14 14h6v6h-6z"/></svg>
|
|
779
|
+
<span class="rail-tip">NeatScript<span class="k">N</span></span>
|
|
780
|
+
</div>
|
|
781
|
+
<div class="rail-btn">
|
|
782
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>
|
|
783
|
+
<span class="rail-tip">Time travel<span class="k">T</span></span>
|
|
784
|
+
</div>
|
|
785
|
+
<div class="rail-btn">
|
|
786
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><circle cx="12" cy="12" r="7"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2"/></svg>
|
|
787
|
+
<span class="rail-tip">Blast radius<span class="k">B</span></span>
|
|
788
|
+
<span class="badge">3</span>
|
|
789
|
+
</div>
|
|
790
|
+
<div class="rail-btn">
|
|
791
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M8 4 4 8l4 4M16 12l4 4-4 4M14 4l-4 16"/></svg>
|
|
792
|
+
<span class="rail-tip">Diff<span class="k">D</span></span>
|
|
793
|
+
</div>
|
|
794
|
+
</div>
|
|
795
|
+
|
|
796
|
+
<div class="rail-group">
|
|
797
|
+
<div class="rail-btn">
|
|
798
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 6c0-1 1-2 2-2h12c1 0 2 1 2 2v9c0 1-1 2-2 2h-7l-4 4v-4H6c-1 0-2-1-2-2z"/></svg>
|
|
799
|
+
<span class="rail-tip">Comments<span class="k">C</span></span>
|
|
800
|
+
</div>
|
|
801
|
+
<div class="rail-btn">
|
|
802
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 3v3M12 18v3M5 12H2M22 12h-3M6 6l2 2M16 16l2 2M6 18l2-2M16 8l2-2"/><circle cx="12" cy="12" r="3"/></svg>
|
|
803
|
+
<span class="rail-tip">Agents<span class="k">A</span></span>
|
|
804
|
+
</div>
|
|
805
|
+
</div>
|
|
806
|
+
|
|
807
|
+
<div class="rail-spacer"></div>
|
|
808
|
+
|
|
809
|
+
<div class="rail-group" style="border-top:1px solid var(--rule)">
|
|
810
|
+
<div class="rail-btn">
|
|
811
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><path d="M19 12a7 7 0 0 1-.4 2.3l2 1.5-2 3.4-2.3-1a7 7 0 0 1-4 2.3l-.4 2.5h-4l-.4-2.5a7 7 0 0 1-4-2.3l-2.3 1-2-3.4 2-1.5A7 7 0 0 1 5 12a7 7 0 0 1 .4-2.3l-2-1.5 2-3.4 2.3 1a7 7 0 0 1 4-2.3L12 1h4l.4 2.5a7 7 0 0 1 4 2.3l2.3-1 2 3.4-2 1.5"/></svg>
|
|
812
|
+
<span class="rail-tip">Settings</span>
|
|
813
|
+
</div>
|
|
814
|
+
</div>
|
|
815
|
+
</nav>
|
|
816
|
+
|
|
817
|
+
<!-- ============================ CANVAS ============================= -->
|
|
818
|
+
<main class="canvas-wrap">
|
|
819
|
+
<div id="cy"></div>
|
|
820
|
+
|
|
821
|
+
<div class="canvas-tag">
|
|
822
|
+
<span class="title">Bloomberg Platform</span>
|
|
823
|
+
<span class="meta">live · 78 nodes · 102 edges · cose-bilkent</span>
|
|
824
|
+
</div>
|
|
825
|
+
|
|
826
|
+
<div class="canvas-toolbar">
|
|
827
|
+
<button class="on" title="Locked view">
|
|
828
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><rect x="5" y="11" width="14" height="9" rx="1.5"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></svg>
|
|
829
|
+
Locked
|
|
830
|
+
</button>
|
|
831
|
+
<span class="div"></span>
|
|
832
|
+
<button>Fit</button>
|
|
833
|
+
<button>Center</button>
|
|
834
|
+
<span class="div"></span>
|
|
835
|
+
<button>Layout: <span class="mono">cose</span></button>
|
|
836
|
+
<button>Group: <span class="mono">namespace</span></button>
|
|
837
|
+
</div>
|
|
838
|
+
|
|
839
|
+
<div class="zoomctl">
|
|
840
|
+
<button id="z-in" title="Zoom in">+</button>
|
|
841
|
+
<button id="z-out" title="Zoom out">−</button>
|
|
842
|
+
<button id="z-fit" title="Fit">⌖</button>
|
|
843
|
+
</div>
|
|
844
|
+
|
|
845
|
+
<!-- legend -->
|
|
846
|
+
<aside class="legend" id="legend">
|
|
847
|
+
<h4>Edge provenance</h4>
|
|
848
|
+
<div class="legend-row" data-prov="STATIC">
|
|
849
|
+
<span class="swatch" style="background: var(--prov-static)"></span>
|
|
850
|
+
<span class="name">Static</span>
|
|
851
|
+
<span class="ct mono" id="ct-static">—</span>
|
|
852
|
+
</div>
|
|
853
|
+
<div class="legend-row" data-prov="OBSERVED">
|
|
854
|
+
<span class="swatch dashed"></span>
|
|
855
|
+
<span class="name">Observed</span>
|
|
856
|
+
<span class="ct mono" id="ct-observed">—</span>
|
|
857
|
+
</div>
|
|
858
|
+
<div class="legend-row" data-prov="INFERRED">
|
|
859
|
+
<span class="swatch dotted"></span>
|
|
860
|
+
<span class="name">Inferred</span>
|
|
861
|
+
<span class="ct mono" id="ct-inferred">—</span>
|
|
862
|
+
</div>
|
|
863
|
+
|
|
864
|
+
<div class="legend-rule"></div>
|
|
865
|
+
|
|
866
|
+
<h4 style="margin-top:0">Node kind</h4>
|
|
867
|
+
<div class="nodes-grid">
|
|
868
|
+
<div class="nrow"><span class="nsq" style="background:var(--n-service)"></span>service</div>
|
|
869
|
+
<div class="nrow"><span class="nsq" style="background:var(--n-db)"></span>db</div>
|
|
870
|
+
<div class="nrow"><span class="nsq" style="background:var(--n-cache)"></span>cache</div>
|
|
871
|
+
<div class="nrow"><span class="nsq" style="background:var(--n-stream)"></span>stream</div>
|
|
872
|
+
<div class="nrow"><span class="nsq" style="background:var(--n-lambda)"></span>lambda</div>
|
|
873
|
+
<div class="nrow"><span class="nsq" style="background:var(--n-cron)"></span>cron</div>
|
|
874
|
+
<div class="nrow"><span class="nsq" style="background:var(--n-api)"></span>api</div>
|
|
875
|
+
<div class="nrow"><span class="nsq" style="background:var(--n-compute)"></span>compute</div>
|
|
876
|
+
<div class="nrow"><span class="nsq" style="background:var(--n-storage)"></span>storage</div>
|
|
877
|
+
<div class="nrow"><span class="nsq" style="background:var(--n-external)"></span>external</div>
|
|
878
|
+
</div>
|
|
879
|
+
</aside>
|
|
880
|
+
|
|
881
|
+
<!-- minimap -->
|
|
882
|
+
<div class="minimap" id="minimap">
|
|
883
|
+
<span class="minimap-label">overview</span>
|
|
884
|
+
<canvas id="minimap-canvas"></canvas>
|
|
885
|
+
<div class="frame" id="minimap-frame"></div>
|
|
886
|
+
</div>
|
|
887
|
+
|
|
888
|
+
</main>
|
|
889
|
+
|
|
890
|
+
<!-- ============================ INSPECTOR ========================== -->
|
|
891
|
+
<aside class="inspect" id="inspect">
|
|
892
|
+
<div class="inspect-tabs">
|
|
893
|
+
<div class="inspect-tab on">Inspect</div>
|
|
894
|
+
<div class="inspect-tab">Edges<span class="ct">14</span></div>
|
|
895
|
+
<div class="inspect-tab">Owners</div>
|
|
896
|
+
<div class="inspect-tab">History</div>
|
|
897
|
+
</div>
|
|
898
|
+
|
|
899
|
+
<div id="inspect-body">
|
|
900
|
+
<!-- populated by JS based on selection; default is svc/order-mgmt -->
|
|
901
|
+
</div>
|
|
902
|
+
</aside>
|
|
903
|
+
|
|
904
|
+
<!-- ============================ STATUS BAR ========================= -->
|
|
905
|
+
<footer class="status">
|
|
906
|
+
<div class="st-item live"><span class="k">stream</span> <span class="v">otel-prod</span></div>
|
|
907
|
+
<div class="st-item"><span class="k">graph</span> <span class="v">v0.3.0-rc4</span></div>
|
|
908
|
+
<div class="st-item"><span class="k">nodes</span> <span class="v" id="st-nodes">—</span></div>
|
|
909
|
+
<div class="st-item"><span class="k">edges</span> <span class="v" id="st-edges">—</span></div>
|
|
910
|
+
<div class="st-item"><span class="k">last sync</span> <span class="v">2s ago</span></div>
|
|
911
|
+
|
|
912
|
+
<div class="st-spacer"></div>
|
|
913
|
+
|
|
914
|
+
<div class="scrub">
|
|
915
|
+
<span class="k">t</span>
|
|
916
|
+
<div class="bar"><div class="fill"></div><div class="head"></div></div>
|
|
917
|
+
<span class="now">now ⌐ 14:22:03 GMT</span>
|
|
918
|
+
</div>
|
|
919
|
+
</footer>
|
|
920
|
+
|
|
921
|
+
</div>
|
|
922
|
+
|
|
923
|
+
<script src="app.js?v=1"></script>
|
|
924
|
+
</body>
|
|
925
|
+
</html>
|