@anyshift/backstage-plugin-anyshift 0.1.0-beta.20 → 0.1.0-beta.21

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.
Files changed (49) hide show
  1. package/LICENSE +1 -0
  2. package/README.md +3 -11
  3. package/dist/api/AnyshiftApi.esm.js +5 -56
  4. package/dist/api/AnyshiftApi.esm.js.map +1 -1
  5. package/dist/components/cloud/CloudResourceContent.esm.js +45 -444
  6. package/dist/components/cloud/CloudResourceContent.esm.js.map +1 -1
  7. package/dist/components/entity/AnyshiftEntityContent.esm.js +23 -128
  8. package/dist/components/entity/AnyshiftEntityContent.esm.js.map +1 -1
  9. package/dist/components/entity/BriefSections.esm.js +4 -24
  10. package/dist/components/entity/BriefSections.esm.js.map +1 -1
  11. package/dist/components/entity/DatadogLiveSignal.esm.js +23 -85
  12. package/dist/components/entity/DatadogLiveSignal.esm.js.map +1 -1
  13. package/dist/components/entity/MermaidArchitecture.esm.js +43 -202
  14. package/dist/components/entity/MermaidArchitecture.esm.js.map +1 -1
  15. package/dist/components/entity/SectionPresenters.esm.js +82 -145
  16. package/dist/components/entity/SectionPresenters.esm.js.map +1 -1
  17. package/dist/components/entity/architectureDiagram.esm.js +15 -48
  18. package/dist/components/entity/architectureDiagram.esm.js.map +1 -1
  19. package/dist/components/explorer/AnyshiftExplorerPage.esm.js +19 -154
  20. package/dist/components/explorer/AnyshiftExplorerPage.esm.js.map +1 -1
  21. package/dist/components/explorer/DatadogOperationsRadar.esm.js +31 -92
  22. package/dist/components/explorer/DatadogOperationsRadar.esm.js.map +1 -1
  23. package/dist/index.d.ts +4 -18
  24. package/dist/index.esm.js +1 -1
  25. package/dist/package.json.esm.js +13 -13
  26. package/dist/plugin.esm.js +2 -6
  27. package/dist/plugin.esm.js.map +1 -1
  28. package/package.json +15 -15
  29. package/CHANGELOG.md +0 -87
  30. package/dist/components/ask/AskAnyshiftCard.esm.js +0 -348
  31. package/dist/components/ask/AskAnyshiftCard.esm.js.map +0 -1
  32. package/dist/components/ask/askPresenters.esm.js +0 -1203
  33. package/dist/components/ask/askPresenters.esm.js.map +0 -1
  34. package/dist/components/ask/askScope.esm.js +0 -27
  35. package/dist/components/ask/askScope.esm.js.map +0 -1
  36. package/dist/components/ask/askSuggestions.esm.js +0 -41
  37. package/dist/components/ask/askSuggestions.esm.js.map +0 -1
  38. package/dist/components/cloud/CloudImpactSection.esm.js +0 -54
  39. package/dist/components/cloud/CloudImpactSection.esm.js.map +0 -1
  40. package/dist/components/cloud/CloudRelationshipSections.esm.js +0 -43
  41. package/dist/components/cloud/CloudRelationshipSections.esm.js.map +0 -1
  42. package/dist/components/entity/ArchitectureOperationDetails.esm.js +0 -107
  43. package/dist/components/entity/ArchitectureOperationDetails.esm.js.map +0 -1
  44. package/dist/components/entity/architectureGraph.esm.js +0 -145
  45. package/dist/components/entity/architectureGraph.esm.js.map +0 -1
  46. package/dist/components/entity/entityIdentity.esm.js +0 -40
  47. package/dist/components/entity/entityIdentity.esm.js.map +0 -1
  48. package/dist/components/entity/relatedCatalogEntities.esm.js +0 -60
  49. package/dist/components/entity/relatedCatalogEntities.esm.js.map +0 -1
@@ -1,1203 +0,0 @@
1
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import { Box, Chip, Typography, Grid, Table, TableHead, TableRow, TableCell, TableBody } from '@material-ui/core';
3
- import { ImpactPresenter, TimelinePresenter } from '../entity/SectionPresenters.esm.js';
4
- import { ArchitectureDiagram } from '../entity/MermaidArchitecture.esm.js';
5
-
6
- const MAX_ROWS = 10;
7
- const MAX_GRAPH_NODES = 30;
8
- const MAX_GRAPH_EDGES = 50;
9
- const MAX_GRAPH_EDGE_SCAN = 200;
10
- const MAX_DETAIL_ITEMS = 3;
11
- function presentAskResult(result) {
12
- switch (result.intent) {
13
- case "connections":
14
- case "topology":
15
- return graphPresentation(result.nodes, result.edges, {
16
- nodes: [],
17
- edges: []
18
- });
19
- case "blast":
20
- return graphPresentation(
21
- result.nodes,
22
- result.edges,
23
- graphFromBlast(result)
24
- );
25
- case "spof":
26
- return graphPresentation(
27
- result.nodes,
28
- result.edges,
29
- graphFromSpof(result)
30
- );
31
- case "path":
32
- return graphPresentation(
33
- result.nodes,
34
- result.edges,
35
- graphFromPath(result)
36
- );
37
- case "cascade":
38
- return graphPresentation(
39
- result.nodes,
40
- result.edges,
41
- graphFromCascade(result)
42
- );
43
- case "servicetree":
44
- return graphPresentation(
45
- result.nodes,
46
- result.edges,
47
- graphFromServiceTree(result)
48
- );
49
- case "calls":
50
- return graphPresentation(
51
- result.nodes,
52
- result.edges,
53
- graphFromCalls(result)
54
- );
55
- case "flow":
56
- return graphPresentation(
57
- result.nodes,
58
- result.edges,
59
- graphFromFlow(result)
60
- );
61
- case "events":
62
- return {
63
- kind: "timeline",
64
- items: timelineFromEvents(result.events?.recent ?? [])
65
- };
66
- case "deployments":
67
- return {
68
- kind: "timeline",
69
- items: (result.deployments?.recent ?? []).slice(0, MAX_ROWS).map((item, index) => ({
70
- id: `${item.ts}-${index}`,
71
- type: "Deployment",
72
- timestamp: item.ts,
73
- target: item.target,
74
- namespace: item.namespace,
75
- summary: deploymentSummary(item.images)
76
- }))
77
- };
78
- case "cloudevents":
79
- return {
80
- kind: "timeline",
81
- items: (result.cloudEvents?.items ?? []).slice(0, MAX_ROWS).map((item) => ({
82
- id: item.id,
83
- type: item.type,
84
- timestamp: item.timestamp,
85
- target: item.target.name ?? item.target.id,
86
- summary: item.summary
87
- }))
88
- };
89
- case "deliveryevents":
90
- return {
91
- kind: "timeline",
92
- items: (result.deliveryEvents?.items ?? []).slice(0, MAX_ROWS).map((item) => ({
93
- id: item.id,
94
- type: item.type,
95
- timestamp: item.timestamp,
96
- target: item.target.name ?? item.target.id,
97
- summary: item.summary
98
- }))
99
- };
100
- case "audit":
101
- return {
102
- kind: "timeline",
103
- items: timelineFromEvents(result.audit?.recent ?? [])
104
- };
105
- case "nodes":
106
- return {
107
- kind: "timeline",
108
- items: timelineFromEvents(result.nodeEvents?.recent ?? [])
109
- };
110
- case "impact":
111
- return {
112
- kind: "impact",
113
- summary: result.impact ? { label: "Affected resources", total: result.impact.total } : void 0,
114
- rows: (result.impact?.items ?? []).slice(0, MAX_ROWS).map((item) => ({
115
- label: item.name ?? item.id ?? item.hashedID,
116
- value: `${item.pathCount} ${item.pathCount === 1 ? "path" : "paths"}`,
117
- detail: [
118
- item.kind ? readableLabel(item.kind) : void 0,
119
- `depth ${item.depth}`
120
- ].filter(Boolean).join(" \xB7 ")
121
- }))
122
- };
123
- case "alertimpact": {
124
- const evidence = result.alertImpact;
125
- const rows = [];
126
- if (evidence) {
127
- appendMapped(rows, evidence.monitors, (item) => ({
128
- label: item.name,
129
- value: "Monitor",
130
- detail: item.service
131
- }));
132
- appendMapped(rows, evidence.slos, (item) => ({
133
- label: item.name,
134
- value: "SLO",
135
- detail: item.service
136
- }));
137
- }
138
- return {
139
- kind: "impact",
140
- summary: evidence ? {
141
- label: "Affected resources",
142
- total: evidence.workloads + evidence.services
143
- } : void 0,
144
- rows
145
- };
146
- }
147
- case "deployimpact": {
148
- const evidence = result.deployImpact;
149
- const rows = evidence ? evidence.recent.length > 0 ? evidence.recent.slice(0, MAX_ROWS).map((item) => eventEvidenceRow(item)) : evidence.ranking.slice(0, MAX_ROWS).map((item) => ({
150
- label: item.deployed,
151
- value: `${item.fallout} correlated failures`,
152
- detail: `${item.rollouts} rollouts`
153
- })) : [];
154
- return { kind: "impact", rows };
155
- }
156
- case "incident": {
157
- const evidence = result.incident;
158
- const events = evidence ? evidence.rootCauses.length > 0 ? evidence.rootCauses : evidence.chain : [];
159
- return {
160
- kind: "impact",
161
- rows: events.slice(0, MAX_ROWS).map((item) => eventEvidenceRow(item))
162
- };
163
- }
164
- case "failures":
165
- return {
166
- kind: "impact",
167
- rows: (result.failures?.recent ?? []).slice(0, MAX_ROWS).map((item) => eventEvidenceRow(item))
168
- };
169
- case "commoncause": {
170
- const evidence = result.commonCause;
171
- const rows = [];
172
- if (evidence) {
173
- appendMapped(rows, evidence.byNode, (item) => causeRow(item, "Node"));
174
- appendMapped(
175
- rows,
176
- evidence.byWorkload,
177
- (item) => causeRow(item, "Workload")
178
- );
179
- appendMapped(
180
- rows,
181
- evidence.byDatastore,
182
- (item) => causeRow(item, "Datastore")
183
- );
184
- appendMapped(
185
- rows,
186
- evidence.byExternal,
187
- (item) => causeRow(item, "External")
188
- );
189
- }
190
- return { kind: "impact", rows };
191
- }
192
- case "alertcause":
193
- return {
194
- kind: "impact",
195
- rows: (result.alertCause?.changes ?? []).slice(0, MAX_ROWS).map((item) => ({
196
- label: item.target ?? result.alertCause?.workload ?? "Change",
197
- value: item.type,
198
- detail: item.summary,
199
- timestamp: item.ts
200
- }))
201
- };
202
- case "inventory": {
203
- const evidence = result.inventory;
204
- return {
205
- kind: "inventory",
206
- total: evidence?.total,
207
- rows: (evidence?.sample ?? []).slice(0, MAX_ROWS).map((item) => ({
208
- name: item.name,
209
- namespace: item.namespace,
210
- type: evidence?.type,
211
- detail: item.resourceId ?? item.externalId
212
- }))
213
- };
214
- }
215
- case "cloudresources": {
216
- const evidence = result.cloudResources;
217
- return {
218
- kind: "inventory",
219
- total: evidence?.counts.total,
220
- rows: (evidence?.items ?? []).slice(0, MAX_ROWS).map((item) => ({
221
- name: item.name ?? item.id ?? item.hashedID,
222
- namespace: item.region ?? item.scope,
223
- type: item.kind ?? `${item.provider} resource`,
224
- detail: `${readableLabel(item.freshness)} \xB7 ${readableLabel(
225
- item.provenance.status
226
- )}`,
227
- timestamp: item.observedAt
228
- }))
229
- };
230
- }
231
- case "storage": {
232
- const evidence = result.storage;
233
- const rows = [];
234
- if (evidence) {
235
- appendMapped(rows, evidence.claims, (item) => ({
236
- name: item.pvc,
237
- namespace: item.pvcNamespace,
238
- type: "Persistent volume claim",
239
- detail: item.storageClass
240
- }));
241
- appendMapped(rows, evidence.orphanPvs, (item) => ({
242
- name: item.name,
243
- type: "Orphan persistent volume",
244
- detail: item.storageClass
245
- }));
246
- appendMapped(rows, evidence.unclaimedPvcs, (item) => ({
247
- name: item.name,
248
- namespace: item.namespace,
249
- type: "Unclaimed persistent volume claim",
250
- detail: item.storageClass
251
- }));
252
- appendMapped(rows, evidence.classes, (item) => ({
253
- name: item.name,
254
- type: "Storage class",
255
- detail: `${item.pvs} PVs \xB7 ${item.pvcs} PVCs`
256
- }));
257
- }
258
- return {
259
- kind: "inventory",
260
- total: evidence ? evidence.claims.length + evidence.orphanPvs.length + evidence.unclaimedPvcs.length + evidence.classes.length : 0,
261
- rows
262
- };
263
- }
264
- case "image": {
265
- const evidence = result.image;
266
- const rows = [];
267
- if (evidence) {
268
- appendMapped(rows, evidence.ranking, (item) => ({
269
- name: item.image,
270
- type: "Container image",
271
- detail: `${item.containers} containers \xB7 ${item.pods} pods`
272
- }));
273
- appendMapped(rows, evidence.byImage?.workloads ?? [], (item) => ({
274
- name: item.name,
275
- namespace: item.namespace,
276
- type: item.kind ?? "Workload"
277
- }));
278
- appendMapped(rows, evidence.workload?.containers ?? [], (item) => ({
279
- name: item.image,
280
- type: item.isInit ? "Init container" : "Container",
281
- detail: item.name
282
- }));
283
- appendMapped(rows, evidence.hygiene?.items ?? [], (item) => ({
284
- name: item.workload,
285
- namespace: item.namespace,
286
- type: evidence.hygiene?.kind,
287
- detail: item.image
288
- }));
289
- }
290
- return {
291
- kind: "inventory",
292
- total: evidence ? evidence.ranking.length + (evidence.byImage?.workloads.length ?? 0) + (evidence.workload?.containers.length ?? 0) + (evidence.hygiene?.items.length ?? 0) : 0,
293
- rows
294
- };
295
- }
296
- case "datastore": {
297
- const evidence = result.dataStore;
298
- const rows = evidence?.target ? [
299
- {
300
- name: evidence.target.name,
301
- type: "Datastore",
302
- detail: `${evidence.target.services} services`
303
- }
304
- ] : (evidence?.ranking ?? []).slice(0, MAX_ROWS).map((item) => ({
305
- name: item.name,
306
- type: "Datastore",
307
- detail: `${item.services} services`
308
- }));
309
- return {
310
- kind: "inventory",
311
- total: evidence?.target ? 1 : evidence?.ranking.length ?? 0,
312
- rows
313
- };
314
- }
315
- case "monitor": {
316
- const evidence = result.monitor;
317
- const rows = [];
318
- if (evidence) {
319
- appendMapped(rows, evidence.monitors, (name) => ({
320
- name,
321
- type: "Monitor"
322
- }));
323
- appendMapped(rows, evidence.slos, (name) => ({ name, type: "SLO" }));
324
- appendMapped(rows, evidence.workloads, (item) => ({
325
- name: item.name,
326
- namespace: item.namespace,
327
- type: item.type ?? "Workload"
328
- }));
329
- }
330
- return {
331
- kind: "inventory",
332
- total: evidence ? evidence.monitors.length + evidence.slos.length + evidence.workloads.length : 0,
333
- rows
334
- };
335
- }
336
- case "slo": {
337
- const evidence = result.slo;
338
- const rows = evidence?.target ? [
339
- {
340
- name: evidence.target.name,
341
- type: "SLO",
342
- detail: evidence.target.status
343
- }
344
- ] : (evidence?.ranking ?? []).slice(0, MAX_ROWS).map((item) => ({
345
- name: item.name,
346
- type: "SLO",
347
- detail: item.status
348
- }));
349
- return {
350
- kind: "inventory",
351
- total: evidence?.target ? 1 : evidence?.ranking.length ?? 0,
352
- rows
353
- };
354
- }
355
- case "coverage":
356
- return {
357
- kind: "coverage",
358
- rows: (result.coverage?.items ?? []).slice(0, MAX_ROWS).map((item) => ({
359
- name: item.name,
360
- namespace: item.namespace,
361
- status: "gap",
362
- detail: item.kind
363
- }))
364
- };
365
- case "graphcoverage":
366
- return {
367
- kind: "coverage",
368
- rows: (result.graphCoverage?.sources ?? []).slice(0, MAX_ROWS).map((item) => ({
369
- name: readableLabel(item.source),
370
- status: item.status === "observed" ? "covered" : "gap",
371
- detail: `${item.nodes} nodes \xB7 ${item.relationships} relationships \xB7 ${item.events} events`
372
- }))
373
- };
374
- case "orphans":
375
- return {
376
- kind: "coverage",
377
- rows: (result.orphans?.items ?? []).slice(0, MAX_ROWS).map((item) => ({
378
- name: item.name,
379
- namespace: item.namespace,
380
- status: "gap",
381
- detail: result.orphans?.kind
382
- }))
383
- };
384
- case "netpol": {
385
- const evidence = result.netpol;
386
- const rows = [];
387
- if (evidence) {
388
- appendMapped(rows, evidence.uncovered, (item) => ({
389
- name: item.namespace,
390
- status: "gap",
391
- detail: `${item.pods} pods`
392
- }));
393
- appendMapped(rows, evidence.policies, (item) => ({
394
- name: item.name,
395
- namespace: item.namespace,
396
- status: "covered",
397
- detail: boundedJoinedList(item.policyTypes)
398
- }));
399
- appendMapped(rows, evidence.reachers, (item) => ({
400
- name: item.name,
401
- namespace: item.namespace,
402
- status: "unknown",
403
- detail: item.type
404
- }));
405
- }
406
- return { kind: "coverage", rows };
407
- }
408
- case "pdb":
409
- return {
410
- kind: "coverage",
411
- rows: (result.pdb?.items ?? []).slice(0, MAX_ROWS).map((item) => ({
412
- name: item.name,
413
- namespace: item.namespace,
414
- status: "gap",
415
- detail: item.kind
416
- }))
417
- };
418
- case "gitops": {
419
- const evidence = result.gitops;
420
- const rows = [];
421
- if (evidence) {
422
- appendMapped(rows, evidence.drift, (item) => ({
423
- name: item.name,
424
- status: item.syncStatus === "Synced" ? "covered" : item.syncStatus ? "gap" : "unknown",
425
- detail: item.syncStatus ?? item.healthStatus
426
- }));
427
- appendMapped(rows, evidence.unmanaged, (item) => ({
428
- name: item.name,
429
- namespace: item.namespace,
430
- status: "gap",
431
- detail: item.kind
432
- }));
433
- if (evidence.owner) {
434
- appendMapped(rows, [evidence.owner], (owner) => ({
435
- name: owner.workload,
436
- namespace: owner.namespace,
437
- status: owner.application ? "covered" : "unknown",
438
- detail: owner.application
439
- }));
440
- }
441
- }
442
- return { kind: "coverage", rows };
443
- }
444
- case "iac":
445
- return {
446
- kind: "coverage",
447
- rows: (result.iac?.resources ?? []).slice(0, MAX_ROWS).map((item) => ({
448
- name: item.terraform.address,
449
- status: item.status === "managed" ? "covered" : item.status === "ambiguous" || item.status === "stale" ? "unknown" : "gap",
450
- detail: readableLabel(item.status),
451
- timestamp: item.directClouds[0]?.observedAt ?? item.clouds[0]?.observedAt ?? null
452
- }))
453
- };
454
- case "iacdrift":
455
- return {
456
- kind: "coverage",
457
- rows: (result.iacDrift?.items ?? []).slice(0, MAX_ROWS).map((item) => ({
458
- name: item.terraform.address,
459
- status: item.status === "in_sync" ? "covered" : item.status === "drifted" ? "gap" : "unknown",
460
- detail: readableLabel(item.reason),
461
- timestamp: item.cloud?.observedAt
462
- }))
463
- };
464
- case "hotspots":
465
- return {
466
- kind: "ranking",
467
- rows: (result.hotspots?.ranking ?? []).slice(0, MAX_ROWS).map((item) => ({
468
- label: item.key,
469
- value: item.total,
470
- detail: item.namespace
471
- }))
472
- };
473
- case "scaling": {
474
- const evidence = result.scaling;
475
- const rows = evidence?.target ? evidence.target.hpas.slice(0, MAX_ROWS).map((item) => ({
476
- label: item.name,
477
- value: item.maxReplicas ?? item.minReplicas ?? 0,
478
- detail: item.namespace
479
- })) : (evidence?.items ?? []).slice(0, MAX_ROWS).map((item) => ({
480
- label: item.name,
481
- value: item.maxReplicas ?? item.replicas ?? 0,
482
- detail: item.namespace
483
- }));
484
- return { kind: "ranking", rows };
485
- }
486
- case "priority": {
487
- const evidence = result.priority;
488
- const rows = [];
489
- if (evidence?.kind === "nopriority") {
490
- appendMapped(rows, evidence.nopriority, (item) => ({
491
- label: item.name,
492
- value: item.pods,
493
- detail: item.namespace
494
- }));
495
- } else if (evidence) {
496
- appendMapped(rows, evidence.ladder, (item) => ({
497
- label: item.name,
498
- value: item.value,
499
- detail: `${item.pods} pods`
500
- }));
501
- appendMapped(rows, evidence.classes, (item) => ({
502
- label: item.name,
503
- value: item.value,
504
- detail: `${item.pods} pods`
505
- }));
506
- }
507
- return { kind: "ranking", rows };
508
- }
509
- case "alertnoise":
510
- return {
511
- kind: "ranking",
512
- rows: (result.alertNoise?.monitors ?? []).slice(0, MAX_ROWS).map((item) => ({
513
- label: item.name,
514
- value: item.fires,
515
- detail: `${readableLabel(item.noiseKind)} \xB7 ${item.recovers} recoveries`
516
- }))
517
- };
518
- case "alerts": {
519
- const rows = isNormalizedAlertsAskResult(result) ? result.alerts.items.filter((item) => item.status === "firing").slice(0, MAX_ROWS).map((item) => ({
520
- label: item.title,
521
- value: 1,
522
- detail: [
523
- readableLabel(item.provider),
524
- readableLabel(item.severity),
525
- item.providerStatus,
526
- item.service?.name
527
- ].filter(Boolean).join(" \xB7 "),
528
- timestamp: item.observedAt ?? item.updatedAt
529
- })) : [];
530
- return {
531
- kind: "ranking",
532
- rows,
533
- ...isNormalizedAlertsAskResult(result) ? { alertEvidence: alertEvidencePresentation(result) } : {}
534
- };
535
- }
536
- case "resolve": {
537
- const candidates = result.resolve?.candidates ?? [];
538
- return candidates.length > 1 ? {
539
- kind: "candidates",
540
- candidates: candidates.slice(0, MAX_ROWS)
541
- } : summaryPresentation([
542
- { label: "Candidates", value: candidates.length }
543
- ]);
544
- }
545
- case "externaldep": {
546
- const evidence = result.externalDep;
547
- return summaryPresentation([
548
- { label: "Ranked dependencies", value: evidence?.ranking.length ?? 0 },
549
- { label: "Affected services", value: evidence?.target?.services ?? 0 }
550
- ]);
551
- }
552
- case "provenance": {
553
- const evidence = result.provenance;
554
- return summaryPresentation([
555
- { label: "Provenance paths", value: evidence?.total ?? 0 },
556
- { label: "Releases", value: evidence?.items.length ?? 0 }
557
- ]);
558
- }
559
- case "ownership": {
560
- const evidence = result.ownership;
561
- return summaryPresentation([
562
- { label: "Owners", value: evidence?.total ?? 0 },
563
- {
564
- label: "People",
565
- value: evidence?.items.reduce(
566
- (total, item) => total + item.people.length,
567
- 0
568
- ) ?? 0
569
- }
570
- ]);
571
- }
572
- case "access": {
573
- const evidence = result.access;
574
- return summaryPresentation([
575
- {
576
- label: "Service accounts",
577
- value: evidence?.serviceAccounts.length ?? 0
578
- },
579
- { label: "Roles", value: evidence?.roles.length ?? 0 },
580
- { label: "Subjects", value: evidence?.subjects.length ?? 0 },
581
- {
582
- label: "Privileged subjects",
583
- value: evidence?.privileged.length ?? 0
584
- }
585
- ]);
586
- }
587
- case "exposure": {
588
- const evidence = result.exposure;
589
- return summaryPresentation([
590
- { label: "Services", value: evidence?.services.length ?? 0 },
591
- { label: "Ingresses", value: evidence?.ingresses.length ?? 0 }
592
- ]);
593
- }
594
- case "tenancy": {
595
- const evidence = result.tenancy;
596
- return summaryPresentation([
597
- { label: "Nodes", value: evidence?.nodes.length ?? 0 },
598
- { label: "Own pods", value: evidence?.ownPods ?? 0 },
599
- { label: "Neighbors", value: evidence?.neighbors.length ?? 0 }
600
- ]);
601
- }
602
- case "sharedconfig": {
603
- const evidence = result.sharedConfig;
604
- return summaryPresentation([
605
- { label: "Config maps", value: evidence?.configmaps.length ?? 0 },
606
- { label: "Own pods", value: evidence?.ownPods ?? 0 },
607
- { label: "Sibling workloads", value: evidence?.siblings.length ?? 0 }
608
- ]);
609
- }
610
- case "alertrules": {
611
- const evidence = result.alertRules;
612
- return summaryPresentation([
613
- { label: "Coverage gaps", value: evidence?.coverage.length ?? 0 },
614
- { label: "Rules", value: evidence?.inventory.length ?? 0 },
615
- { label: "Target rules", value: evidence?.target?.rules.length ?? 0 }
616
- ]);
617
- }
618
- default:
619
- return assertNever(result);
620
- }
621
- }
622
- function isNormalizedAlertsAskResult(result) {
623
- return result.intent === "alerts" && result.alerts !== null && result.alerts !== void 0 && "items" in result.alerts && Array.isArray(result.alerts.items);
624
- }
625
- function alertEvidencePresentation(result) {
626
- const coverage = result.alerts.providers.flatMap(
627
- (provider) => provider.status === "available" ? [] : [
628
- `${readableLabel(provider.provider)} alert coverage is ${provider.status}.`
629
- ]
630
- );
631
- const warnings = result.alerts.warnings.map((warning) => warning.message);
632
- return {
633
- partial: result.alerts.partial,
634
- coverage,
635
- warnings
636
- };
637
- }
638
- const AskResultPresenter = ({
639
- result,
640
- effectiveQuestion,
641
- answeredAt,
642
- onQuestion
643
- }) => {
644
- const presentation = presentAskResult(result);
645
- const timestamps = evidenceTimes(presentation);
646
- return /* @__PURE__ */ jsxs(Box, { "aria-label": "Anyshift answer", children: [
647
- /* @__PURE__ */ jsxs(Box, { display: "flex", flexWrap: "wrap", alignItems: "center", gridGap: 8, children: [
648
- /* @__PURE__ */ jsx(
649
- Chip,
650
- {
651
- size: "small",
652
- color: "primary",
653
- label: `Intent \xB7 ${INTENT_LABELS[result.intent]}`
654
- }
655
- ),
656
- /* @__PURE__ */ jsxs(Typography, { variant: "caption", color: "textSecondary", title: answeredAt, children: [
657
- "Answered just now",
658
- typeof result.elapsedMs === "number" ? ` \xB7 Graph API ${result.elapsedMs} ms` : ""
659
- ] })
660
- ] }),
661
- /* @__PURE__ */ jsx(Box, { mt: 2, mb: 2, children: /* @__PURE__ */ jsx(Typography, { variant: "body1", children: result.summary }) }),
662
- /* @__PURE__ */ jsx(Presentation, { presentation, onQuestion }),
663
- /* @__PURE__ */ jsx(Disclosure, { title: "How this was interpreted", children: /* @__PURE__ */ jsx(Typography, { variant: "body2", children: effectiveQuestion }) }),
664
- /* @__PURE__ */ jsx(Disclosure, { title: "Supporting evidence and timestamps", children: /* @__PURE__ */ jsx(Box, { component: "dl", m: 0, children: timestamps.map((item, index) => /* @__PURE__ */ jsxs(
665
- Box,
666
- {
667
- display: "flex",
668
- justifyContent: "space-between",
669
- gridGap: 16,
670
- py: 0.5,
671
- children: [
672
- /* @__PURE__ */ jsx(Typography, { component: "dt", variant: "body2", children: item.label }),
673
- /* @__PURE__ */ jsx(
674
- Typography,
675
- {
676
- component: "dd",
677
- variant: "body2",
678
- color: "textSecondary",
679
- style: { margin: 0 },
680
- children: /* @__PURE__ */ jsx(EvidenceTimestamp, { timestamp: item.timestamp })
681
- }
682
- )
683
- ]
684
- },
685
- `${item.label}-${index}`
686
- )) }) })
687
- ] });
688
- };
689
- const Presentation = ({
690
- presentation,
691
- onQuestion
692
- }) => {
693
- switch (presentation.kind) {
694
- case "graph":
695
- return /* @__PURE__ */ jsxs(EvidenceSection, { title: "Dependency evidence", children: [
696
- /* @__PURE__ */ jsxs(Box, { display: "flex", flexWrap: "wrap", gridGap: 8, mb: 1, children: [
697
- /* @__PURE__ */ jsx(
698
- Chip,
699
- {
700
- size: "small",
701
- variant: "outlined",
702
- label: `${presentation.nodes.length} nodes`
703
- }
704
- ),
705
- /* @__PURE__ */ jsx(
706
- Chip,
707
- {
708
- size: "small",
709
- variant: "outlined",
710
- label: `${presentation.edges.length} ${presentation.edges.length === 1 ? "relation" : "relations"}`
711
- }
712
- )
713
- ] }),
714
- presentation.nodes.length > 0 ? /* @__PURE__ */ jsx(
715
- ArchitectureDiagram,
716
- {
717
- graph: {
718
- nodes: presentation.nodes,
719
- edges: presentation.edges
720
- },
721
- view: "context"
722
- }
723
- ) : /* @__PURE__ */ jsx(EmptyEvidence, {})
724
- ] });
725
- case "timeline":
726
- return /* @__PURE__ */ jsx(EvidenceSection, { title: "Change timeline", children: presentation.items.length > 0 ? /* @__PURE__ */ jsx(
727
- TimelinePresenter,
728
- {
729
- data: {
730
- recent: presentation.items.map((item) => ({
731
- id: item.id,
732
- ts: item.timestamp,
733
- type: item.type,
734
- target: item.target,
735
- namespace: item.namespace,
736
- summary: item.summary
737
- }))
738
- },
739
- showEvidence: false
740
- }
741
- ) : /* @__PURE__ */ jsx(EmptyEvidence, {}) });
742
- case "impact":
743
- return /* @__PURE__ */ jsx(EvidenceSection, { title: "Impact evidence", children: presentation.rows.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
744
- /* @__PURE__ */ jsx(
745
- ImpactPresenter,
746
- {
747
- data: {
748
- affected: presentation.rows.map((row) => ({ name: row.label }))
749
- },
750
- showEvidence: false,
751
- summaryMetric: presentation.summary ?? false
752
- }
753
- ),
754
- /* @__PURE__ */ jsx(EvidenceDetails, { rows: presentation.rows })
755
- ] }) : /* @__PURE__ */ jsx(EmptyEvidence, {}) });
756
- case "inventory":
757
- return /* @__PURE__ */ jsxs(EvidenceSection, { title: "Resources", children: [
758
- typeof presentation.total === "number" && /* @__PURE__ */ jsxs(Typography, { variant: "subtitle2", children: [
759
- presentation.total,
760
- " total"
761
- ] }),
762
- /* @__PURE__ */ jsx(ResourceTable, { rows: presentation.rows })
763
- ] });
764
- case "coverage":
765
- return /* @__PURE__ */ jsx(EvidenceSection, { title: "Coverage evidence", children: /* @__PURE__ */ jsx(CoverageTable, { rows: presentation.rows }) });
766
- case "ranking":
767
- return /* @__PURE__ */ jsxs(EvidenceSection, { title: "Ranking", children: [
768
- presentation.alertEvidence && /* @__PURE__ */ jsxs(Box, { mb: 1, children: [
769
- presentation.alertEvidence.partial && /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "error", children: "Alert coverage is partial." }),
770
- presentation.alertEvidence.coverage.map((message) => /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "textSecondary", children: message }, message)),
771
- presentation.alertEvidence.warnings.map((message) => /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "textSecondary", children: message }, message))
772
- ] }),
773
- /* @__PURE__ */ jsx(RankingTable, { rows: presentation.rows })
774
- ] });
775
- case "candidates":
776
- return /* @__PURE__ */ jsx(EvidenceSection, { title: "Choose a resource", children: /* @__PURE__ */ jsx(Box, { display: "flex", flexWrap: "wrap", gridGap: 8, children: presentation.candidates.map((candidate) => {
777
- const question = questionForCandidate(candidate);
778
- return /* @__PURE__ */ jsx(
779
- "button",
780
- {
781
- type: "button",
782
- onClick: () => onQuestion?.(question),
783
- style: {
784
- border: "1px solid currentColor",
785
- borderRadius: 16,
786
- background: "transparent",
787
- cursor: "pointer",
788
- padding: "4px 12px"
789
- },
790
- children: candidateLabel(candidate)
791
- },
792
- candidate.id
793
- );
794
- }) }) });
795
- case "summary":
796
- return /* @__PURE__ */ jsx(EvidenceSection, { title: "Known counts", children: presentation.counts.length > 0 ? /* @__PURE__ */ jsx(Grid, { container: true, spacing: 2, children: presentation.counts.map((metric) => /* @__PURE__ */ jsxs(Grid, { item: true, xs: 6, sm: 4, children: [
797
- /* @__PURE__ */ jsx(Typography, { variant: "h6", children: metric.value }),
798
- /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "textSecondary", children: metric.label })
799
- ] }, metric.label)) }) : /* @__PURE__ */ jsx(EmptyEvidence, {}) });
800
- default:
801
- return assertNever(presentation);
802
- }
803
- };
804
- const EvidenceSection = ({
805
- title,
806
- children
807
- }) => /* @__PURE__ */ jsxs(Box, { mb: 2, children: [
808
- /* @__PURE__ */ jsx(Typography, { component: "h3", variant: "subtitle1", gutterBottom: true, children: title }),
809
- children
810
- ] });
811
- const Disclosure = ({
812
- title,
813
- children
814
- }) => /* @__PURE__ */ jsxs("details", { style: { marginTop: 12 }, children: [
815
- /* @__PURE__ */ jsx("summary", { style: { cursor: "pointer", fontWeight: 500 }, children: title }),
816
- /* @__PURE__ */ jsx(Box, { mt: 1, children })
817
- ] });
818
- const EvidenceDetails = ({ rows }) => /* @__PURE__ */ jsx(Box, { component: "ul", m: 0, mt: 1, pl: 2, children: rows.map((row, index) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(Typography, { variant: "body2", children: [
819
- row.label,
820
- row.value !== void 0 ? ` \xB7 ${row.value}` : "",
821
- row.detail ? ` \xB7 ${row.detail}` : ""
822
- ] }) }, `${row.label}-${index}`)) });
823
- const ResourceTable = ({ rows }) => rows.length > 0 ? /* @__PURE__ */ jsxs(Table, { size: "small", "aria-label": "Ask resources", children: [
824
- /* @__PURE__ */ jsx(TableHead, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
825
- /* @__PURE__ */ jsx(TableCell, { children: "Name" }),
826
- /* @__PURE__ */ jsx(TableCell, { children: "Type" }),
827
- /* @__PURE__ */ jsx(TableCell, { children: "Namespace / region" }),
828
- /* @__PURE__ */ jsx(TableCell, { children: "Detail" })
829
- ] }) }),
830
- /* @__PURE__ */ jsx(TableBody, { children: rows.map((row, index) => /* @__PURE__ */ jsxs(TableRow, { children: [
831
- /* @__PURE__ */ jsx(TableCell, { children: row.name }),
832
- /* @__PURE__ */ jsx(TableCell, { children: row.type || "Unknown" }),
833
- /* @__PURE__ */ jsx(TableCell, { children: row.namespace || "Unknown" }),
834
- /* @__PURE__ */ jsx(TableCell, { children: row.detail || "Unknown" })
835
- ] }, `${row.name}-${index}`)) })
836
- ] }) : /* @__PURE__ */ jsx(EmptyEvidence, {});
837
- const CoverageTable = ({ rows }) => rows.length > 0 ? /* @__PURE__ */ jsxs(Table, { size: "small", "aria-label": "Ask coverage evidence", children: [
838
- /* @__PURE__ */ jsx(TableHead, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
839
- /* @__PURE__ */ jsx(TableCell, { children: "Resource" }),
840
- /* @__PURE__ */ jsx(TableCell, { children: "Status" }),
841
- /* @__PURE__ */ jsx(TableCell, { children: "Evidence" })
842
- ] }) }),
843
- /* @__PURE__ */ jsx(TableBody, { children: rows.map((row, index) => /* @__PURE__ */ jsxs(TableRow, { children: [
844
- /* @__PURE__ */ jsxs(TableCell, { children: [
845
- row.name,
846
- row.namespace ? ` \xB7 ${row.namespace}` : ""
847
- ] }),
848
- /* @__PURE__ */ jsx(TableCell, { children: readableLabel(row.status) }),
849
- /* @__PURE__ */ jsx(TableCell, { children: row.detail || "Unknown" })
850
- ] }, `${row.name}-${index}`)) })
851
- ] }) : /* @__PURE__ */ jsx(EmptyEvidence, {});
852
- const RankingTable = ({ rows }) => rows.length > 0 ? /* @__PURE__ */ jsxs(Table, { size: "small", "aria-label": "Ask ranking", children: [
853
- /* @__PURE__ */ jsx(TableHead, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
854
- /* @__PURE__ */ jsx(TableCell, { children: "Resource" }),
855
- /* @__PURE__ */ jsx(TableCell, { align: "right", children: "Count" }),
856
- /* @__PURE__ */ jsx(TableCell, { children: "Detail" })
857
- ] }) }),
858
- /* @__PURE__ */ jsx(TableBody, { children: rows.map((row, index) => /* @__PURE__ */ jsxs(TableRow, { children: [
859
- /* @__PURE__ */ jsx(TableCell, { children: row.label }),
860
- /* @__PURE__ */ jsx(TableCell, { align: "right", children: row.value }),
861
- /* @__PURE__ */ jsx(TableCell, { children: row.detail || "Unknown" })
862
- ] }, `${row.label}-${index}`)) })
863
- ] }) : /* @__PURE__ */ jsx(EmptyEvidence, {});
864
- const EmptyEvidence = () => /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "textSecondary", children: "The connected graph does not currently contain enough typed evidence." });
865
- const EvidenceTimestamp = ({ timestamp }) => {
866
- if (!timestamp) return /* @__PURE__ */ jsx(Fragment, { children: "Unknown" });
867
- const parsed = Date.parse(timestamp);
868
- return Number.isNaN(parsed) ? /* @__PURE__ */ jsx(Fragment, { children: "Unknown" }) : /* @__PURE__ */ jsx("time", { dateTime: timestamp, children: new Date(parsed).toLocaleString() });
869
- };
870
- function graphPresentation(nodes, edges, fallback) {
871
- const selectedNodes = (nodes?.length ? nodes : fallback.nodes).slice(
872
- 0,
873
- MAX_GRAPH_NODES
874
- );
875
- const visibleIds = new Set(selectedNodes.map((node) => node.id));
876
- const edgeSource = nodes?.length ? edges ?? [] : fallback.edges;
877
- const selectedEdges = [];
878
- for (let index = 0; index < edgeSource.length && index < MAX_GRAPH_EDGE_SCAN && selectedEdges.length < MAX_GRAPH_EDGES; index += 1) {
879
- const edge = edgeSource[index];
880
- if (visibleIds.has(edge.from) && visibleIds.has(edge.to)) {
881
- selectedEdges.push(edge);
882
- }
883
- }
884
- return { kind: "graph", nodes: selectedNodes, edges: selectedEdges };
885
- }
886
- function graphFromBlast(result) {
887
- const root = result.resolved ? graphNode(
888
- result.resolved.name,
889
- result.resolved.type ?? "resource",
890
- null,
891
- result.resolved.hashedID
892
- ) : void 0;
893
- const dependencies = [];
894
- if (result.blastRadius) {
895
- appendMapped(
896
- dependencies,
897
- result.blastRadius.workloads,
898
- (item) => graphNode(item.name, "workload", item.namespace)
899
- );
900
- appendMapped(
901
- dependencies,
902
- result.blastRadius.services,
903
- (item) => graphNode(item.name, "service", item.namespace)
904
- );
905
- }
906
- return {
907
- nodes: root ? [root, ...dependencies] : dependencies,
908
- edges: root ? dependencies.map((item) => graphEdge(root.id, item.id, "AFFECTS")) : []
909
- };
910
- }
911
- function graphFromSpof(result) {
912
- return {
913
- nodes: (result.spof?.items ?? []).slice(0, MAX_ROWS).map(
914
- (item) => graphNode(item.name, result.spof?.kind ?? "resource", item.namespace)
915
- ),
916
- edges: []
917
- };
918
- }
919
- function graphFromPath(result) {
920
- const nodes = (result.path?.chain ?? []).slice(0, MAX_ROWS).map((item) => graphNode(item.name, item.type ?? "resource", item.namespace));
921
- return {
922
- nodes,
923
- edges: nodes.slice(1).map(
924
- (node, index) => graphEdge(
925
- nodes[index].id,
926
- node.id,
927
- result.path?.rels[index] ?? "DEPENDS_ON"
928
- )
929
- )
930
- };
931
- }
932
- function graphFromCascade(result) {
933
- const rootValue = result.cascade?.root;
934
- const root = rootValue?.target ? graphNode(
935
- rootValue.target,
936
- rootValue.kind ?? "event target",
937
- rootValue.namespace
938
- ) : void 0;
939
- const steps = (result.cascade?.steps ?? []).slice(0, MAX_ROWS).map((item) => graphNode(item.resource, "affected resource", item.namespace));
940
- return {
941
- nodes: root ? [root, ...steps] : steps,
942
- edges: root ? steps.map((item) => graphEdge(root.id, item.id, "PROPAGATED_TO")) : []
943
- };
944
- }
945
- function graphFromServiceTree(result) {
946
- const target = result.serviceTree?.target;
947
- if (!target) {
948
- return {
949
- nodes: (result.serviceTree?.ranking ?? []).slice(0, MAX_ROWS).map((item) => ({
950
- ...graphNode(item.name, "service footprint", null),
951
- image: `${item.footprint} resources \xB7 ${item.serviceCount} services \xB7 ${item.leafCount} leaves`
952
- })),
953
- edges: []
954
- };
955
- }
956
- const root = graphNode(target.name, "service", null);
957
- const dependencies = [];
958
- appendMapped(
959
- dependencies,
960
- target.services,
961
- (name) => graphNode(name, "service", null)
962
- );
963
- appendMapped(
964
- dependencies,
965
- target.datastores,
966
- (name) => graphNode(name, "datastore", null)
967
- );
968
- appendMapped(
969
- dependencies,
970
- target.externals,
971
- (name) => graphNode(name, "external", null)
972
- );
973
- return {
974
- nodes: [root, ...dependencies],
975
- edges: dependencies.map((item) => graphEdge(root.id, item.id, "DEPENDS_ON"))
976
- };
977
- }
978
- function graphFromCalls(result) {
979
- const target = result.calls?.target;
980
- if (!target) {
981
- return {
982
- nodes: (result.calls?.ranking ?? []).slice(0, MAX_ROWS).map((item) => graphNode(item.name, "service", null)),
983
- edges: []
984
- };
985
- }
986
- const root = graphNode(target.name, "service", null);
987
- const callers = target.callers.slice(0, MAX_ROWS).map((name) => graphNode(name, "service", null));
988
- const callees = target.callees.slice(0, Math.max(0, MAX_ROWS - callers.length)).map((name) => graphNode(name, "service", null));
989
- return {
990
- nodes: [root, ...callers, ...callees],
991
- edges: [
992
- ...callers.map((item) => graphEdge(item.id, root.id, "CALLS")),
993
- ...callees.map((item) => graphEdge(root.id, item.id, "CALLS"))
994
- ]
995
- };
996
- }
997
- function graphFromFlow(result) {
998
- const target = result.flow?.target;
999
- if (!target) {
1000
- return {
1001
- nodes: (result.flow?.ranking ?? []).slice(0, MAX_ROWS).map((item) => graphNode(item.name, "stream", null)),
1002
- edges: []
1003
- };
1004
- }
1005
- const root = graphNode(target.name, "stream", null);
1006
- const producers = target.producers.slice(0, MAX_ROWS).map((name) => graphNode(name, "service", null));
1007
- const consumers = target.consumers.slice(0, Math.max(0, MAX_ROWS - producers.length)).map((name) => graphNode(name, "service", null));
1008
- return {
1009
- nodes: [root, ...producers, ...consumers],
1010
- edges: [
1011
- ...producers.map((item) => graphEdge(item.id, root.id, "PRODUCES")),
1012
- ...consumers.map((item) => graphEdge(root.id, item.id, "CONSUMED_BY"))
1013
- ]
1014
- };
1015
- }
1016
- function graphNode(name, type, namespace, id = `${type}:${namespace ?? "_"}:${name}`) {
1017
- return { id, anyshiftID: null, name, type, namespace };
1018
- }
1019
- function graphEdge(from, to, type) {
1020
- return {
1021
- from,
1022
- to,
1023
- type,
1024
- direction: "downstream",
1025
- semantic: "dependency",
1026
- impact: true
1027
- };
1028
- }
1029
- function timelineFromEvents(events) {
1030
- return events.slice(0, MAX_ROWS).map((item, index) => ({
1031
- id: `${item.ts}-${item.type}-${index}`,
1032
- type: item.type,
1033
- timestamp: item.ts,
1034
- target: item.target,
1035
- namespace: item.namespace,
1036
- summary: item.summary
1037
- }));
1038
- }
1039
- function deploymentSummary(images) {
1040
- const visibleImages = images.slice(0, MAX_DETAIL_ITEMS);
1041
- const changes = visibleImages.flatMap((image) => {
1042
- if (image.from && image.to) return [`${image.from} \u2192 ${image.to}`];
1043
- if (image.to) return [`Deployed ${image.to}`];
1044
- return [];
1045
- });
1046
- if (changes.length === 0) return void 0;
1047
- const remaining = images.length - visibleImages.length;
1048
- const suffix = remaining > 0 ? ` \xB7 ${remaining} more image ${remaining === 1 ? "change" : "changes"}` : "";
1049
- return `${changes.join(", ")}${suffix}`;
1050
- }
1051
- function eventEvidenceRow(item) {
1052
- return {
1053
- label: item.target ?? readableLabel(item.type),
1054
- value: readableLabel(item.type),
1055
- detail: item.summary ?? item.namespace,
1056
- timestamp: item.ts
1057
- };
1058
- }
1059
- function causeRow(item, kind) {
1060
- return {
1061
- label: item.name,
1062
- value: `${item.affected} affected`,
1063
- detail: item.namespace ? `${kind} \xB7 ${item.namespace}` : kind
1064
- };
1065
- }
1066
- function appendMapped(target, source, mapper, limit = MAX_ROWS) {
1067
- const remaining = Math.max(0, limit - target.length);
1068
- if (remaining === 0) return;
1069
- target.push(...source.slice(0, remaining).map(mapper));
1070
- }
1071
- function boundedJoinedList(items) {
1072
- const visible = items.slice(0, MAX_DETAIL_ITEMS);
1073
- const remaining = items.length - visible.length;
1074
- return `${visible.join(", ")}${remaining > 0 ? `, +${remaining} more` : ""}`;
1075
- }
1076
- function summaryPresentation(counts) {
1077
- return { kind: "summary", counts, timestamps: [] };
1078
- }
1079
- function evidenceTimes(presentation) {
1080
- let timestamps;
1081
- switch (presentation.kind) {
1082
- case "graph":
1083
- timestamps = [{ label: "Graph evidence", timestamp: null }];
1084
- break;
1085
- case "timeline":
1086
- timestamps = presentation.items.map((item) => ({
1087
- label: item.target ?? item.type,
1088
- timestamp: item.timestamp
1089
- }));
1090
- break;
1091
- case "impact":
1092
- timestamps = presentation.rows.map((row) => ({
1093
- label: row.label,
1094
- timestamp: row.timestamp
1095
- }));
1096
- break;
1097
- case "inventory":
1098
- timestamps = presentation.rows.map((row) => ({
1099
- label: row.name,
1100
- timestamp: row.timestamp
1101
- }));
1102
- break;
1103
- case "coverage":
1104
- timestamps = presentation.rows.map((row) => ({
1105
- label: row.name,
1106
- timestamp: row.timestamp
1107
- }));
1108
- break;
1109
- case "ranking":
1110
- timestamps = presentation.rows.map((row) => ({
1111
- label: row.label,
1112
- timestamp: row.timestamp
1113
- }));
1114
- break;
1115
- case "candidates":
1116
- timestamps = [{ label: "Resolution evidence", timestamp: null }];
1117
- break;
1118
- case "summary":
1119
- timestamps = presentation.timestamps;
1120
- break;
1121
- default:
1122
- return assertNever(presentation);
1123
- }
1124
- return timestamps.length > 0 ? timestamps.slice(0, MAX_ROWS) : [{ label: "Evidence timestamp", timestamp: null }];
1125
- }
1126
- function candidateLabel(candidate) {
1127
- return [
1128
- candidate.name,
1129
- candidate.type ? readableLabel(candidate.type) : "type unknown",
1130
- candidate.namespace ?? "namespace unknown"
1131
- ].join(" \xB7 ");
1132
- }
1133
- function questionForCandidate(candidate) {
1134
- const type = candidate.type?.trim().toLocaleLowerCase();
1135
- const typedName = type ? `${type} ${candidate.name}` : candidate.name;
1136
- const namespace = candidate.namespace ? ` in namespace ${candidate.namespace}` : "";
1137
- return `What depends on ${typedName}${namespace}?`;
1138
- }
1139
- function readableLabel(value) {
1140
- const normalized = value.replace(/[_-]+/g, " ");
1141
- return normalized.charAt(0).toLocaleUpperCase() + normalized.slice(1);
1142
- }
1143
- function assertNever(value) {
1144
- throw new Error(
1145
- `Unsupported Ask presentation discriminant: ${String(value)}`
1146
- );
1147
- }
1148
- const INTENT_LABELS = {
1149
- resolve: "Resolve",
1150
- connections: "Connections",
1151
- inventory: "Inventory",
1152
- events: "Events",
1153
- cloudevents: "Cloud events",
1154
- cloudresources: "Cloud resources",
1155
- deliveryevents: "Delivery events",
1156
- provenance: "Provenance",
1157
- ownership: "Ownership",
1158
- graphcoverage: "Graph coverage",
1159
- hotspots: "Hotspots",
1160
- incident: "Incident",
1161
- failures: "Failures",
1162
- deployments: "Deployments",
1163
- audit: "Audit",
1164
- nodes: "Node events",
1165
- deployimpact: "Deployment impact",
1166
- commoncause: "Common cause",
1167
- blast: "Blast radius",
1168
- impact: "Impact",
1169
- spof: "Single points of failure",
1170
- path: "Dependency path",
1171
- cascade: "Cascade",
1172
- alertimpact: "Alert impact",
1173
- monitor: "Monitor",
1174
- datastore: "Datastore",
1175
- flow: "Flow",
1176
- externaldep: "External dependency",
1177
- alerts: "Alerts",
1178
- alertnoise: "Alert noise",
1179
- calls: "Service calls",
1180
- servicetree: "Service tree",
1181
- alertcause: "Alert cause",
1182
- access: "Access",
1183
- exposure: "Exposure",
1184
- orphans: "Orphans",
1185
- coverage: "Coverage",
1186
- slo: "SLO",
1187
- tenancy: "Tenancy",
1188
- sharedconfig: "Shared configuration",
1189
- alertrules: "Alert rules",
1190
- gitops: "GitOps",
1191
- image: "Images",
1192
- netpol: "Network policy",
1193
- storage: "Storage",
1194
- pdb: "Pod disruption budget",
1195
- scaling: "Scaling",
1196
- topology: "Topology",
1197
- priority: "Priority",
1198
- iac: "Infrastructure as code",
1199
- iacdrift: "Infrastructure drift"
1200
- };
1201
-
1202
- export { AskResultPresenter, presentAskResult };
1203
- //# sourceMappingURL=askPresenters.esm.js.map