@skyhook-io/radar-app 1.13.5 → 1.14.0
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/package.json +8 -8
- package/src/App.tsx +60 -24
- package/src/api/client.authRedirect.test.ts +12 -1
- package/src/api/client.prometheusStatus.test.ts +24 -0
- package/src/api/client.ts +321 -16
- package/src/api/diagnose.ts +1 -0
- package/src/api/drain-plan.test.ts +86 -0
- package/src/api/quotas.test.ts +26 -0
- package/src/api/quotas.ts +20 -0
- package/src/api/workloadMetrics.test.ts +40 -0
- package/src/api/workloadMetrics.ts +68 -0
- package/src/components/CloudConnectFlow.tsx +179 -42
- package/src/components/CloudFunnelButton.tsx +107 -36
- package/src/components/SyncProgressPanel.tsx +73 -0
- package/src/components/audit/AuditView.tsx +2 -0
- package/src/components/cloudConnectHandoff.test.ts +140 -0
- package/src/components/cloudConnectHandoff.ts +124 -0
- package/src/components/diagnose/DiagnoseContext.tsx +2 -1
- package/src/components/diagnose/investigationEvidence/adapters/changes.ts +60 -0
- package/src/components/diagnose/investigationEvidence/adapters/diagnose.test.ts +573 -0
- package/src/components/diagnose/investigationEvidence/adapters/diagnose.ts +935 -0
- package/src/components/diagnose/investigationEvidence/adapters/events.ts +96 -0
- package/src/components/diagnose/investigationEvidence/adapters/helm.test.ts +242 -0
- package/src/components/diagnose/investigationEvidence/adapters/helm.ts +208 -0
- package/src/components/diagnose/investigationEvidence/adapters/issues.ts +172 -0
- package/src/components/diagnose/investigationEvidence/adapters/logs.test.ts +283 -0
- package/src/components/diagnose/investigationEvidence/adapters/logs.ts +183 -0
- package/src/components/diagnose/investigationEvidence/adapters/permissions.test.ts +528 -0
- package/src/components/diagnose/investigationEvidence/adapters/permissions.ts +292 -0
- package/src/components/diagnose/investigationEvidence/adapters/prometheus.test.ts +1641 -0
- package/src/components/diagnose/investigationEvidence/adapters/prometheus.ts +769 -0
- package/src/components/diagnose/investigationEvidence/adapters/resource.test.ts +54 -0
- package/src/components/diagnose/investigationEvidence/adapters/resource.ts +257 -0
- package/src/components/diagnose/investigationEvidence/adapters/topology.ts +207 -0
- package/src/components/diagnose/investigationEvidence/builder.ts +418 -0
- package/src/components/diagnose/investigationEvidence/evidenceFixtures.ts +179 -0
- package/src/components/diagnose/investigationEvidence/identity.test.ts +614 -0
- package/src/components/diagnose/investigationEvidence/identity.ts +261 -0
- package/src/components/diagnose/investigationEvidence/index.ts +55 -0
- package/src/components/diagnose/investigationEvidence/observations.ts +954 -0
- package/src/components/diagnose/investigationEvidence/parse.ts +467 -0
- package/src/components/diagnose/investigationEvidence/projection.test.ts +2703 -0
- package/src/components/diagnose/investigationEvidence/types.ts +512 -0
- package/src/components/diagnose/target.test.ts +19 -0
- package/src/components/diagnose/target.ts +3 -2
- package/src/components/gitops/GitOpsView.tsx +7 -0
- package/src/components/gitops/RemoteDestinationCloudHint.tsx +26 -0
- package/src/components/resource/PrometheusCharts.overlays.test.ts +22 -0
- package/src/components/resource/PrometheusCharts.tsx +4 -3
- package/src/components/resource/PrometheusChartsGrid.render.test.tsx +99 -0
- package/src/components/resource/PrometheusChartsGrid.tsx +75 -35
- package/src/components/resource/RightsizingStrip.test.ts +38 -0
- package/src/components/resource/RightsizingStrip.tsx +15 -3
- package/src/components/resource/WorkloadMetricsHelpDialog.test.tsx +79 -0
- package/src/components/resource/WorkloadMetricsHelpDialog.tsx +145 -0
- package/src/components/resource/WorkloadMetricsSection.render.test.tsx +351 -0
- package/src/components/resource/WorkloadMetricsSection.tsx +486 -0
- package/src/components/resource/workloadMetricValues.test.ts +65 -0
- package/src/components/resource/workloadMetricValues.ts +30 -0
- package/src/components/resources/ResourcesView.tsx +44 -6
- package/src/components/resources/renderers/NamespaceRenderer.tsx +7 -1
- package/src/components/resources/renderers/PodRenderer.tsx +4 -0
- package/src/components/resources/renderers/RolloutRenderer.tsx +15 -1
- package/src/components/resources/renderers/WorkloadRenderer.tsx +3 -0
- package/src/components/rightsizing/RightsizingScanView.tsx +21 -0
- package/src/components/settings/SettingsDialog.tsx +94 -14
- package/src/components/traffic/TrafficFlowList.tsx +229 -70
- package/src/components/traffic/TrafficGraph.tsx +6 -6
- package/src/components/traffic/TrafficView.tsx +10 -9
- package/src/components/traffic/trafficFilters.test.ts +28 -1
- package/src/components/traffic/trafficFilters.ts +31 -0
- package/src/components/workload/WorkloadView.tsx +19 -8
- package/src/context/ConnectionContext.tsx +48 -3
- package/src/context/DiagnoseCustomization.tsx +1 -0
- package/src/index.css +17 -0
- package/src/utils/navigation.ts +1 -1
- package/src/utils/topology-namespace.test.ts +64 -0
- package/src/utils/topology-namespace.ts +18 -0
- package/src/components/diagnose/investigationEvidence.test.ts +0 -6617
- package/src/components/diagnose/investigationEvidence.ts +0 -5572
- package/src/components/gitops/GitOpsActions.tsx +0 -1
- package/src/components/gitops/GitOpsStatusBadge.tsx +0 -1
- package/src/components/gitops/ManagedResourcesList.tsx +0 -1
- package/src/components/gitops/SyncCountdown.tsx +0 -1
- package/src/components/gitops/index.ts +0 -4
- package/src/components/helm/ManifestDiffViewer.tsx +0 -69
- package/src/components/logs/JsonLogLine.tsx +0 -1
- package/src/components/logs/LogCore.tsx +0 -2
- package/src/components/logs/useLogBuffer.ts +0 -2
- package/src/components/logs/useLogSearch.ts +0 -1
- package/src/components/resource-drawer/ResourceDrawer.tsx +0 -216
- package/src/components/resources/drawer-components.tsx +0 -1
- package/src/components/resources/renderers/AlertRenderer.tsx +0 -1
- package/src/components/resources/renderers/CNPGBackupRenderer.tsx +0 -1
- package/src/components/resources/renderers/CNPGPoolerRenderer.tsx +0 -1
- package/src/components/resources/renderers/CNPGScheduledBackupRenderer.tsx +0 -1
- package/src/components/resources/renderers/CertificateRenderer.tsx +0 -1
- package/src/components/resources/renderers/CertificateRequestRenderer.tsx +0 -1
- package/src/components/resources/renderers/ChallengeRenderer.tsx +0 -1
- package/src/components/resources/renderers/ClusterComplianceReportRenderer.tsx +0 -1
- package/src/components/resources/renderers/ClusterExternalSecretRenderer.tsx +0 -1
- package/src/components/resources/renderers/ClusterIssuerRenderer.tsx +0 -1
- package/src/components/resources/renderers/ConfigAuditReportRenderer.tsx +0 -1
- package/src/components/resources/renderers/ConfigMapRenderer.tsx +0 -1
- package/src/components/resources/renderers/CronJobRenderer.tsx +0 -1
- package/src/components/resources/renderers/CronWorkflowRenderer.tsx +0 -1
- package/src/components/resources/renderers/EventRenderer.tsx +0 -1
- package/src/components/resources/renderers/ExposedSecretReportRenderer.tsx +0 -1
- package/src/components/resources/renderers/ExternalSecretRenderer.tsx +0 -1
- package/src/components/resources/renderers/FluxHelmReleaseRenderer.tsx +0 -1
- package/src/components/resources/renderers/GRPCRouteRenderer.tsx +0 -1
- package/src/components/resources/renderers/GatewayClassRenderer.tsx +0 -1
- package/src/components/resources/renderers/GatewayRenderer.tsx +0 -1
- package/src/components/resources/renderers/GenericRenderer.tsx +0 -1
- package/src/components/resources/renderers/GitRepositoryRenderer.tsx +0 -1
- package/src/components/resources/renderers/HTTPRouteRenderer.tsx +0 -1
- package/src/components/resources/renderers/HelmRepositoryRenderer.tsx +0 -1
- package/src/components/resources/renderers/IngressClassRenderer.tsx +0 -1
- package/src/components/resources/renderers/IngressRenderer.tsx +0 -1
- package/src/components/resources/renderers/IstioAuthorizationPolicyRenderer.tsx +0 -1
- package/src/components/resources/renderers/IstioDestinationRuleRenderer.tsx +0 -1
- package/src/components/resources/renderers/IstioGatewayRenderer.tsx +0 -1
- package/src/components/resources/renderers/IstioPeerAuthenticationRenderer.tsx +0 -1
- package/src/components/resources/renderers/IstioServiceEntryRenderer.tsx +0 -1
- package/src/components/resources/renderers/IstioVirtualServiceRenderer.tsx +0 -1
- package/src/components/resources/renderers/JobRenderer.tsx +0 -1
- package/src/components/resources/renderers/KarpenterEC2NodeClassRenderer.tsx +0 -1
- package/src/components/resources/renderers/KarpenterNodeClaimRenderer.tsx +0 -1
- package/src/components/resources/renderers/KedaScaledJobRenderer.tsx +0 -1
- package/src/components/resources/renderers/KedaScaledObjectRenderer.tsx +0 -1
- package/src/components/resources/renderers/KedaTriggerAuthRenderer.tsx +0 -1
- package/src/components/resources/renderers/KnativeConfigurationRenderer.tsx +0 -1
- package/src/components/resources/renderers/KnativeEventingRenderer.tsx +0 -1
- package/src/components/resources/renderers/KnativeFlowRenderer.tsx +0 -1
- package/src/components/resources/renderers/KnativeNetworkingRenderer.tsx +0 -1
- package/src/components/resources/renderers/KnativeRevisionRenderer.tsx +0 -1
- package/src/components/resources/renderers/KnativeRouteRenderer.tsx +0 -1
- package/src/components/resources/renderers/KnativeServiceRenderer.tsx +0 -1
- package/src/components/resources/renderers/KnativeSourceRenderer.tsx +0 -1
- package/src/components/resources/renderers/KustomizationRenderer.tsx +0 -1
- package/src/components/resources/renderers/KyvernoPolicyReportRenderer.tsx +0 -1
- package/src/components/resources/renderers/LeaseRenderer.tsx +0 -1
- package/src/components/resources/renderers/NetworkPolicyRenderer.tsx +0 -1
- package/src/components/resources/renderers/OCIRepositoryRenderer.tsx +0 -1
- package/src/components/resources/renderers/OrderRenderer.tsx +0 -1
- package/src/components/resources/renderers/PersistentVolumeRenderer.tsx +0 -1
- package/src/components/resources/renderers/PodDisruptionBudgetRenderer.tsx +0 -1
- package/src/components/resources/renderers/PodMonitorRenderer.tsx +0 -1
- package/src/components/resources/renderers/PriorityClassRenderer.tsx +0 -1
- package/src/components/resources/renderers/PrometheusRuleRenderer.tsx +0 -1
- package/src/components/resources/renderers/ReplicaSetRenderer.tsx +0 -1
- package/src/components/resources/renderers/RuntimeClassRenderer.tsx +0 -1
- package/src/components/resources/renderers/SbomReportRenderer.tsx +0 -1
- package/src/components/resources/renderers/SealedSecretRenderer.tsx +0 -1
- package/src/components/resources/renderers/SecretRenderer.tsx +0 -1
- package/src/components/resources/renderers/SecretStoreRenderer.tsx +0 -1
- package/src/components/resources/renderers/ServiceMonitorRenderer.tsx +0 -1
- package/src/components/resources/renderers/SimpleRouteRenderer.tsx +0 -1
- package/src/components/resources/renderers/StorageClassRenderer.tsx +0 -1
- package/src/components/resources/renderers/TraefikIngressRouteRenderer.tsx +0 -1
- package/src/components/resources/renderers/VPARenderer.tsx +0 -1
- package/src/components/resources/renderers/VeleroScheduleRenderer.tsx +0 -1
- package/src/components/resources/renderers/VeleroVSLRenderer.tsx +0 -1
- package/src/components/resources/renderers/VulnerabilityReportRenderer.tsx +0 -1
- package/src/components/resources/renderers/WebhookConfigRenderer.tsx +0 -1
- package/src/components/resources/renderers/WorkflowRenderer.tsx +0 -1
- package/src/components/resources/renderers/WorkflowTemplateRenderer.tsx +0 -1
- package/src/components/resources/renderers/argo-cells.tsx +0 -1
- package/src/components/resources/renderers/certmanager-cells.tsx +0 -1
- package/src/components/resources/renderers/cnpg-cells.tsx +0 -1
- package/src/components/resources/renderers/eso-cells.tsx +0 -1
- package/src/components/resources/renderers/flux-cells.tsx +0 -1
- package/src/components/resources/renderers/index.ts +0 -94
- package/src/components/resources/renderers/istio-cells.tsx +0 -1
- package/src/components/resources/renderers/karpenter-cells.tsx +0 -1
- package/src/components/resources/renderers/keda-cells.tsx +0 -1
- package/src/components/resources/renderers/knative-cells.tsx +0 -1
- package/src/components/resources/renderers/kyverno-cells.tsx +0 -1
- package/src/components/resources/renderers/prometheus-cells.tsx +0 -1
- package/src/components/resources/renderers/traefik-cells.tsx +0 -1
- package/src/components/resources/renderers/trivy-cells.tsx +0 -1
- package/src/components/resources/renderers/trivy-shared.tsx +0 -1
- package/src/components/resources/renderers/velero-cells.tsx +0 -1
- package/src/components/resources/resource-utils-argo.ts +0 -2
- package/src/components/resources/resource-utils-certmanager.ts +0 -2
- package/src/components/resources/resource-utils-eso.ts +0 -2
- package/src/components/resources/resource-utils-flux.ts +0 -2
- package/src/components/resources/resource-utils-istio.ts +0 -2
- package/src/components/resources/resource-utils-karpenter.ts +0 -2
- package/src/components/resources/resource-utils-knative.ts +0 -2
- package/src/components/resources/resource-utils-kyverno.ts +0 -2
- package/src/components/resources/resource-utils-prometheus.ts +0 -2
- package/src/components/resources/resource-utils-traefik.ts +0 -1
- package/src/components/resources/resource-utils-trivy.ts +0 -2
- package/src/components/resources/resource-utils-velero.ts +0 -2
- package/src/components/shared/EditableYamlView.tsx +0 -24
- package/src/components/timeline/DiffViewer.tsx +0 -1
- package/src/components/traffic/index.ts +0 -3
- package/src/components/ui/ForceDeleteConfirmDialog.tsx +0 -1
- package/src/components/ui/MetricsChart.tsx +0 -1
- package/src/components/ui/ResourceBar.tsx +0 -1
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
import { type Issue, type IssueRecentChange } from "@skyhook-io/k8s-ui";
|
|
2
|
+
import { type TimeSeries } from "@skyhook-io/k8s-ui/components/charts";
|
|
3
|
+
import {
|
|
4
|
+
type DiagnosisChangeContext,
|
|
5
|
+
type DiagnosisCrashCause,
|
|
6
|
+
type DiagnosisDNSContext,
|
|
7
|
+
type DiagnosisEvidenceLimitationBase,
|
|
8
|
+
type DiagnosisEvidenceTone,
|
|
9
|
+
type DiagnosisFilteredLogs,
|
|
10
|
+
type DiagnosisResourceContext,
|
|
11
|
+
type DiagnosisResourceRef,
|
|
12
|
+
type DiagnosisStartupBlocker,
|
|
13
|
+
} from "../diagnoseEvidenceTypes";
|
|
14
|
+
/**
|
|
15
|
+
* The projection deliberately consumes only the small, structural portion of
|
|
16
|
+
* Turn that it needs. TimelineItem is private to parts.tsx today; Turn[] is
|
|
17
|
+
* structurally assignable to this type without coupling evidence extraction to
|
|
18
|
+
* the transcript renderer.
|
|
19
|
+
*/
|
|
20
|
+
export interface InvestigationEvidenceTurn {
|
|
21
|
+
timeline: readonly InvestigationEvidenceTimelineItem[];
|
|
22
|
+
question?: string;
|
|
23
|
+
apply?: boolean;
|
|
24
|
+
verify?: boolean;
|
|
25
|
+
status?: "running" | "done" | "error";
|
|
26
|
+
}
|
|
27
|
+
/** The resource the investigation was opened for. */
|
|
28
|
+
export interface InvestigationEvidenceTarget {
|
|
29
|
+
kind: string;
|
|
30
|
+
/** Kubernetes API group; empty means core. */
|
|
31
|
+
group: string;
|
|
32
|
+
namespace?: string;
|
|
33
|
+
name: string;
|
|
34
|
+
}
|
|
35
|
+
export type InvestigationEvidencePhase =
|
|
36
|
+
"initial" | "followup" | "verification" | "apply";
|
|
37
|
+
export type InvestigationEvidenceTimelineItem =
|
|
38
|
+
| { kind: "thinking"; text: string }
|
|
39
|
+
| {
|
|
40
|
+
kind: "tool";
|
|
41
|
+
id: string;
|
|
42
|
+
tool: string;
|
|
43
|
+
status: string;
|
|
44
|
+
summary?: string;
|
|
45
|
+
result?: string;
|
|
46
|
+
evidenceRef?: string;
|
|
47
|
+
radarEvidence?: boolean;
|
|
48
|
+
truncated?: boolean;
|
|
49
|
+
isError?: boolean;
|
|
50
|
+
};
|
|
51
|
+
export type InvestigationEvidenceTier =
|
|
52
|
+
"key" | "supporting" | "context" | "checked";
|
|
53
|
+
export type InvestigationEvidenceRelevance =
|
|
54
|
+
"target" | "producer-related" | "broader";
|
|
55
|
+
export type InvestigationEvidenceKind =
|
|
56
|
+
| "issue"
|
|
57
|
+
| "startup"
|
|
58
|
+
| "crash"
|
|
59
|
+
| "resource"
|
|
60
|
+
| "logs"
|
|
61
|
+
| "events"
|
|
62
|
+
| "changes"
|
|
63
|
+
| "dns"
|
|
64
|
+
| "network"
|
|
65
|
+
| "relationships"
|
|
66
|
+
| "topology"
|
|
67
|
+
| "inventory"
|
|
68
|
+
| "receipt"
|
|
69
|
+
| "alerts"
|
|
70
|
+
| "helm"
|
|
71
|
+
| "permissions"
|
|
72
|
+
| "metrics";
|
|
73
|
+
export type InvestigationSemanticDomain = "issue" | "startup" | "crash" | "dns";
|
|
74
|
+
export interface InvestigationEvidenceSource {
|
|
75
|
+
/** DOM-safe stable identity derived from turn index + the agent step ID. */
|
|
76
|
+
id: string;
|
|
77
|
+
turnIndex: number;
|
|
78
|
+
timelineIndex: number;
|
|
79
|
+
stepId: string;
|
|
80
|
+
tool: string;
|
|
81
|
+
/** The exact agent-emitted tool input shown in Activity. */
|
|
82
|
+
args?: string;
|
|
83
|
+
/** Stable flattened transcript order. */
|
|
84
|
+
order: number;
|
|
85
|
+
/** Which chronological phase of the run produced this source. */
|
|
86
|
+
phase: InvestigationEvidencePhase;
|
|
87
|
+
/** True only when the agent transport explicitly marked the tool result successful. */
|
|
88
|
+
confirmedSuccess: boolean;
|
|
89
|
+
/** Server-issued, turn-scoped identity for this exact retained result. */
|
|
90
|
+
evidenceRef?: string;
|
|
91
|
+
/**
|
|
92
|
+
* The highest-priority evidence group produced by this call. Evidence panes
|
|
93
|
+
* use it for one unique Activity → Evidence anchor even when a bundle fans
|
|
94
|
+
* out into several cards.
|
|
95
|
+
*/
|
|
96
|
+
primaryGroupId?: string;
|
|
97
|
+
}
|
|
98
|
+
export interface InvestigationResourceContext extends DiagnosisResourceContext {
|
|
99
|
+
issueSummary?: {
|
|
100
|
+
count: number;
|
|
101
|
+
highestSeverity?: string;
|
|
102
|
+
topReason?: string;
|
|
103
|
+
bySource?: Record<string, number>;
|
|
104
|
+
};
|
|
105
|
+
auditSummary?: {
|
|
106
|
+
count: number;
|
|
107
|
+
highestSeverity?: string;
|
|
108
|
+
topFinding?: string;
|
|
109
|
+
};
|
|
110
|
+
policySummary?: unknown;
|
|
111
|
+
podSummary?: unknown;
|
|
112
|
+
}
|
|
113
|
+
export interface InvestigationGitOpsDiagnosis {
|
|
114
|
+
tool: "argocd" | "flux";
|
|
115
|
+
sync?: string;
|
|
116
|
+
health?: string;
|
|
117
|
+
operationPhase?: string;
|
|
118
|
+
suspended?: boolean;
|
|
119
|
+
ready?: string;
|
|
120
|
+
appliedRevision?: string;
|
|
121
|
+
}
|
|
122
|
+
export interface InvestigationKubernetesResource {
|
|
123
|
+
apiVersion: string;
|
|
124
|
+
kind: string;
|
|
125
|
+
metadata: {
|
|
126
|
+
name: string;
|
|
127
|
+
namespace?: string;
|
|
128
|
+
[key: string]: unknown;
|
|
129
|
+
};
|
|
130
|
+
spec?: unknown;
|
|
131
|
+
status?: unknown;
|
|
132
|
+
summaryContext?: unknown;
|
|
133
|
+
[key: string]: unknown;
|
|
134
|
+
}
|
|
135
|
+
/** Current `list_resources` row shape (`ai/context.ResourceSummary`). */
|
|
136
|
+
export interface InvestigationResourceSummary {
|
|
137
|
+
kind: string;
|
|
138
|
+
name: string;
|
|
139
|
+
namespace?: string;
|
|
140
|
+
status?: string;
|
|
141
|
+
ready?: string;
|
|
142
|
+
issue?: string;
|
|
143
|
+
age?: string;
|
|
144
|
+
terminating?: boolean;
|
|
145
|
+
restarts?: number;
|
|
146
|
+
lastTerminatedReason?: string;
|
|
147
|
+
lastRestartedAge?: string;
|
|
148
|
+
summaryContext?: {
|
|
149
|
+
health?: string;
|
|
150
|
+
issueCount?: number;
|
|
151
|
+
managedBy?: {
|
|
152
|
+
kind: string;
|
|
153
|
+
source: string;
|
|
154
|
+
name: string;
|
|
155
|
+
namespace?: string;
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
[key: string]: unknown;
|
|
159
|
+
}
|
|
160
|
+
export interface InvestigationEventEvidence {
|
|
161
|
+
reason: string;
|
|
162
|
+
message: string;
|
|
163
|
+
type: string;
|
|
164
|
+
count: number;
|
|
165
|
+
lastTimestamp: string;
|
|
166
|
+
}
|
|
167
|
+
export interface InvestigationTopologyNode {
|
|
168
|
+
id: string;
|
|
169
|
+
kind: string;
|
|
170
|
+
name: string;
|
|
171
|
+
status?: string;
|
|
172
|
+
data?: Record<string, unknown> | null;
|
|
173
|
+
}
|
|
174
|
+
export interface InvestigationTopologyEdge {
|
|
175
|
+
id?: string;
|
|
176
|
+
source: string;
|
|
177
|
+
target: string;
|
|
178
|
+
type: string;
|
|
179
|
+
label?: string;
|
|
180
|
+
}
|
|
181
|
+
export interface InvestigationNetworkRoute {
|
|
182
|
+
route: string;
|
|
183
|
+
target?: string;
|
|
184
|
+
outcome: string;
|
|
185
|
+
failedLayer?: string;
|
|
186
|
+
confidence?: string;
|
|
187
|
+
evidence?: string;
|
|
188
|
+
benign?: boolean;
|
|
189
|
+
}
|
|
190
|
+
export interface InvestigationNetworkEvidence {
|
|
191
|
+
subject: DiagnosisResourceRef;
|
|
192
|
+
verdict: "healthy" | "degraded" | "broken" | "unknown";
|
|
193
|
+
reason?: string;
|
|
194
|
+
diagnosis?: {
|
|
195
|
+
class?: string;
|
|
196
|
+
severity?: string;
|
|
197
|
+
summary: string;
|
|
198
|
+
route?: string;
|
|
199
|
+
nextAction?: string;
|
|
200
|
+
};
|
|
201
|
+
summary: {
|
|
202
|
+
tested: number;
|
|
203
|
+
passed: number;
|
|
204
|
+
failed: number;
|
|
205
|
+
derived?: number;
|
|
206
|
+
skipped: number;
|
|
207
|
+
headline: string;
|
|
208
|
+
};
|
|
209
|
+
routes: InvestigationNetworkRoute[];
|
|
210
|
+
}
|
|
211
|
+
/** One Prometheus rule as `get_prometheus_rules` flattens it (group stamped on). */
|
|
212
|
+
export interface InvestigationAlertRule {
|
|
213
|
+
group: string;
|
|
214
|
+
name: string;
|
|
215
|
+
type: string;
|
|
216
|
+
state?: string;
|
|
217
|
+
health?: string;
|
|
218
|
+
query?: string;
|
|
219
|
+
labels: Record<string, string>;
|
|
220
|
+
}
|
|
221
|
+
/** One active instance of an alerting rule, with its own label set. */
|
|
222
|
+
export interface InvestigationAlertInstance {
|
|
223
|
+
state: string;
|
|
224
|
+
activeAt?: string;
|
|
225
|
+
value?: string;
|
|
226
|
+
labels: Record<string, string>;
|
|
227
|
+
/** The instance's labels name the investigated resource. */
|
|
228
|
+
namesTarget: boolean;
|
|
229
|
+
}
|
|
230
|
+
export interface InvestigationHelmOperation {
|
|
231
|
+
kind: string;
|
|
232
|
+
status: string;
|
|
233
|
+
message: string;
|
|
234
|
+
revision?: number;
|
|
235
|
+
failedRevision?: number;
|
|
236
|
+
rollbackRevision?: number;
|
|
237
|
+
updated?: string;
|
|
238
|
+
}
|
|
239
|
+
export interface InvestigationHelmOwnedResource {
|
|
240
|
+
kind: string;
|
|
241
|
+
apiVersion?: string;
|
|
242
|
+
name: string;
|
|
243
|
+
namespace: string;
|
|
244
|
+
status?: string;
|
|
245
|
+
ready?: string;
|
|
246
|
+
message?: string;
|
|
247
|
+
summary?: string;
|
|
248
|
+
issue?: string;
|
|
249
|
+
}
|
|
250
|
+
export interface InvestigationHelmRelease {
|
|
251
|
+
name: string;
|
|
252
|
+
namespace: string;
|
|
253
|
+
/** Set only when Helm stores the release metadata elsewhere. */
|
|
254
|
+
storageNamespace?: string;
|
|
255
|
+
chart: string;
|
|
256
|
+
chartVersion: string;
|
|
257
|
+
appVersion?: string;
|
|
258
|
+
status: string;
|
|
259
|
+
revision: number;
|
|
260
|
+
updated: string;
|
|
261
|
+
description?: string;
|
|
262
|
+
resourceHealth?: string;
|
|
263
|
+
healthIssue?: string;
|
|
264
|
+
healthSummary?: string;
|
|
265
|
+
managedByFluxHelmRelease?: string;
|
|
266
|
+
lastOperation?: InvestigationHelmOperation;
|
|
267
|
+
resources: InvestigationHelmOwnedResource[];
|
|
268
|
+
}
|
|
269
|
+
export interface InvestigationPermissionSubject {
|
|
270
|
+
kind: string;
|
|
271
|
+
namespace?: string;
|
|
272
|
+
name: string;
|
|
273
|
+
}
|
|
274
|
+
export interface InvestigationAccessCheck {
|
|
275
|
+
verb: string;
|
|
276
|
+
group?: string;
|
|
277
|
+
resource: string;
|
|
278
|
+
subresource?: string;
|
|
279
|
+
/** Empty means a cluster-scoped resource or cluster-wide request. */
|
|
280
|
+
namespace: string;
|
|
281
|
+
resourceName?: string;
|
|
282
|
+
allowed: boolean;
|
|
283
|
+
denied: boolean;
|
|
284
|
+
reason?: string;
|
|
285
|
+
evaluationError?: string;
|
|
286
|
+
}
|
|
287
|
+
export interface InvestigationPermissionBinding {
|
|
288
|
+
bindingKind: string;
|
|
289
|
+
bindingNamespace?: string;
|
|
290
|
+
bindingName: string;
|
|
291
|
+
roleKind: string;
|
|
292
|
+
roleNamespace?: string;
|
|
293
|
+
roleName: string;
|
|
294
|
+
rulesCount: number;
|
|
295
|
+
inheritedFromGroup?: string;
|
|
296
|
+
}
|
|
297
|
+
export type InvestigationEvidenceData =
|
|
298
|
+
| {
|
|
299
|
+
type: "issue";
|
|
300
|
+
issue: Issue;
|
|
301
|
+
/**
|
|
302
|
+
* A broad `issues` query can return failures from other resources. Keep
|
|
303
|
+
* those factual observations, but do not let agent selection alone imply
|
|
304
|
+
* that they explain the resource under investigation.
|
|
305
|
+
*/
|
|
306
|
+
relevance: "target" | "producer-related" | "broader";
|
|
307
|
+
/** Pods whose startup blocker repeats this issue word for word. */
|
|
308
|
+
pods?: string[];
|
|
309
|
+
}
|
|
310
|
+
| {
|
|
311
|
+
type: "startup";
|
|
312
|
+
blocker: DiagnosisStartupBlocker;
|
|
313
|
+
/** Exact blocker object when the diagnosis producer established it. */
|
|
314
|
+
subject?: DiagnosisResourceRef;
|
|
315
|
+
/**
|
|
316
|
+
* Every pod the producer reported with this exact blocker. A DaemonSet
|
|
317
|
+
* with seven pending pods is one finding, not seven; the card carries the
|
|
318
|
+
* pod list instead of repeating itself.
|
|
319
|
+
*/
|
|
320
|
+
pods?: string[];
|
|
321
|
+
}
|
|
322
|
+
| {
|
|
323
|
+
type: "crash";
|
|
324
|
+
crash: DiagnosisCrashCause;
|
|
325
|
+
/** Namespace of the producing check's subject; pods live there. */
|
|
326
|
+
namespace?: string;
|
|
327
|
+
}
|
|
328
|
+
| {
|
|
329
|
+
type: "resource";
|
|
330
|
+
resource: InvestigationKubernetesResource;
|
|
331
|
+
resourceContext?: InvestigationResourceContext;
|
|
332
|
+
warnings: string[];
|
|
333
|
+
gitOpsDiagnosis?: InvestigationGitOpsDiagnosis;
|
|
334
|
+
}
|
|
335
|
+
| {
|
|
336
|
+
type: "logs";
|
|
337
|
+
pod: string;
|
|
338
|
+
container: string;
|
|
339
|
+
/** Namespace the producing call actually read; absent when unstated. */
|
|
340
|
+
namespace?: string;
|
|
341
|
+
previous: boolean;
|
|
342
|
+
logs?: DiagnosisFilteredLogs;
|
|
343
|
+
warnings: string[];
|
|
344
|
+
error?: string;
|
|
345
|
+
}
|
|
346
|
+
| {
|
|
347
|
+
type: "events";
|
|
348
|
+
events: InvestigationEventEvidence[];
|
|
349
|
+
scope: string;
|
|
350
|
+
}
|
|
351
|
+
| {
|
|
352
|
+
type: "changes";
|
|
353
|
+
changes: IssueRecentChange[];
|
|
354
|
+
scope: string;
|
|
355
|
+
changeContext?: DiagnosisChangeContext;
|
|
356
|
+
/** The resource whose change history the producer read, when it named one. */
|
|
357
|
+
subject?: { kind?: string; namespace?: string; name: string };
|
|
358
|
+
}
|
|
359
|
+
| { type: "dns"; dns: DiagnosisDNSContext }
|
|
360
|
+
| { type: "network"; network: InvestigationNetworkEvidence }
|
|
361
|
+
| {
|
|
362
|
+
type: "relationships";
|
|
363
|
+
root: DiagnosisResourceRef;
|
|
364
|
+
nodes: InvestigationTopologyNode[];
|
|
365
|
+
edges: InvestigationTopologyEdge[];
|
|
366
|
+
truncated: boolean;
|
|
367
|
+
}
|
|
368
|
+
| {
|
|
369
|
+
type: "topology";
|
|
370
|
+
stats: { nodes: number; edges: number };
|
|
371
|
+
namespaces: Array<{ namespace: string; chains: string[] }>;
|
|
372
|
+
problems: string[];
|
|
373
|
+
warnings: string[];
|
|
374
|
+
}
|
|
375
|
+
| {
|
|
376
|
+
type: "inventory";
|
|
377
|
+
resources: InvestigationResourceSummary[];
|
|
378
|
+
scope: string;
|
|
379
|
+
}
|
|
380
|
+
| {
|
|
381
|
+
type: "receipt";
|
|
382
|
+
checked:
|
|
383
|
+
"issues" | "events" | "changes" | "inventory" | "logs" | "alerts";
|
|
384
|
+
scope: string;
|
|
385
|
+
/**
|
|
386
|
+
* Only when there is something to add. The card already shows the title
|
|
387
|
+
* and the scope, so a line that restates either costs the reader a read
|
|
388
|
+
* and returns nothing; this carries the reason the answer is what it is,
|
|
389
|
+
* or the limit of what it proves.
|
|
390
|
+
*/
|
|
391
|
+
message?: string;
|
|
392
|
+
}
|
|
393
|
+
| {
|
|
394
|
+
type: "alerts";
|
|
395
|
+
rule: InvestigationAlertRule;
|
|
396
|
+
instances: InvestigationAlertInstance[];
|
|
397
|
+
annotations: Record<string, string>;
|
|
398
|
+
}
|
|
399
|
+
| { type: "helm"; release: InvestigationHelmRelease }
|
|
400
|
+
| {
|
|
401
|
+
type: "permissions";
|
|
402
|
+
subject: InvestigationPermissionSubject;
|
|
403
|
+
/** Present for the access-check response shape. */
|
|
404
|
+
accessCheck?: InvestigationAccessCheck;
|
|
405
|
+
/** Present for the subject-permissions response shape. */
|
|
406
|
+
bindings?: InvestigationPermissionBinding[];
|
|
407
|
+
flatRulesCount?: number;
|
|
408
|
+
truncated?: boolean;
|
|
409
|
+
usedByPods?: string[];
|
|
410
|
+
podsTotal?: number;
|
|
411
|
+
}
|
|
412
|
+
| InvestigationMetricsEvidence;
|
|
413
|
+
/** One PromQL vector selector as the producer tokenized it. */
|
|
414
|
+
export interface InvestigationMetricsSelector {
|
|
415
|
+
metric: string;
|
|
416
|
+
matchers: Array<{ label: string; op: string; value: string }>;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* A Prometheus result captured during the investigation. `origin` says which
|
|
420
|
+
* producer ran the query; the shape is shared so every metrics card renders
|
|
421
|
+
* the same way. `subject` is set only when the query's selectors are all
|
|
422
|
+
* scoped to the investigation target.
|
|
423
|
+
*/
|
|
424
|
+
export interface InvestigationMetricsEvidence {
|
|
425
|
+
type: "metrics";
|
|
426
|
+
origin: "query" | "diagnose";
|
|
427
|
+
query: string;
|
|
428
|
+
mode: "range" | "instant";
|
|
429
|
+
start?: string;
|
|
430
|
+
end?: string;
|
|
431
|
+
step?: string;
|
|
432
|
+
unit?: string;
|
|
433
|
+
label?: string;
|
|
434
|
+
series: TimeSeries[];
|
|
435
|
+
truncated: boolean;
|
|
436
|
+
summary?: unknown;
|
|
437
|
+
note?: string;
|
|
438
|
+
selectors?: InvestigationMetricsSelector[];
|
|
439
|
+
selectorsUnknown?: boolean;
|
|
440
|
+
subject?: DiagnosisResourceRef;
|
|
441
|
+
pods?: number;
|
|
442
|
+
partial?: boolean;
|
|
443
|
+
}
|
|
444
|
+
export interface InvestigationEvidenceObservation {
|
|
445
|
+
source: InvestigationEvidenceSource;
|
|
446
|
+
revision: number;
|
|
447
|
+
/** This exact observation predates a later successful verification of its proof scope. */
|
|
448
|
+
historical: boolean;
|
|
449
|
+
/** Whether this semantic item differs from its immediately previous observation. */
|
|
450
|
+
changedFromPrevious: boolean;
|
|
451
|
+
/**
|
|
452
|
+
* How this producer-backed observation relates to the resource being
|
|
453
|
+
* investigated. Broader observations remain useful context, but agent
|
|
454
|
+
* selection alone must never promote them as support for this target.
|
|
455
|
+
*/
|
|
456
|
+
relevance: InvestigationEvidenceRelevance;
|
|
457
|
+
tier: InvestigationEvidenceTier;
|
|
458
|
+
tone: DiagnosisEvidenceTone;
|
|
459
|
+
title: string;
|
|
460
|
+
summary?: string;
|
|
461
|
+
data: InvestigationEvidenceData;
|
|
462
|
+
}
|
|
463
|
+
export interface InvestigationEvidenceGroup {
|
|
464
|
+
/** Stable DOM-safe identity for this semantic evidence item. */
|
|
465
|
+
id: string;
|
|
466
|
+
/** Raw deterministic identity used to merge repeated observations. */
|
|
467
|
+
identity: string;
|
|
468
|
+
kind: InvestigationEvidenceKind;
|
|
469
|
+
/** Latest observation predates the most recent completed verification turn. */
|
|
470
|
+
historical: boolean;
|
|
471
|
+
firstOrder: number;
|
|
472
|
+
observations: InvestigationEvidenceObservation[];
|
|
473
|
+
/** Strongest-provenance observation, newest when provenance is equal. */
|
|
474
|
+
latest: InvestigationEvidenceObservation;
|
|
475
|
+
/** Newest observation regardless of proof strength; used for chronology. */
|
|
476
|
+
chronologicalLatest: InvestigationEvidenceObservation;
|
|
477
|
+
}
|
|
478
|
+
export interface InvestigationEvidenceLimitation extends DiagnosisEvidenceLimitationBase {
|
|
479
|
+
/** A qualified history result, not a failed collection. */
|
|
480
|
+
presentation?: "history";
|
|
481
|
+
firstOrder: number;
|
|
482
|
+
sources: InvestigationEvidenceSource[];
|
|
483
|
+
}
|
|
484
|
+
export interface InvestigationEvidenceCoverage {
|
|
485
|
+
/** Completed calls to a tool with a typed evidence adapter. */
|
|
486
|
+
attempted: number;
|
|
487
|
+
/** Adapted calls that contributed at least one evidence group. */
|
|
488
|
+
projected: number;
|
|
489
|
+
/** Adapted calls with a producer-declared or transport limitation. */
|
|
490
|
+
limited: number;
|
|
491
|
+
/** Calls that produced a strict, successful zero-result receipt. */
|
|
492
|
+
checked: number;
|
|
493
|
+
}
|
|
494
|
+
export interface InvestigationEvidenceProjection {
|
|
495
|
+
groups: InvestigationEvidenceGroup[];
|
|
496
|
+
limitations: InvestigationEvidenceLimitation[];
|
|
497
|
+
sources: InvestigationEvidenceSource[];
|
|
498
|
+
/** Every retained tool item carrying a server-issued ref, eligible or not. */
|
|
499
|
+
evidenceRefSources: InvestigationEvidenceSource[];
|
|
500
|
+
/** Complete confirmed-success sources eligible for server-authored links. */
|
|
501
|
+
citableSources: InvestigationEvidenceSource[];
|
|
502
|
+
coverage: InvestigationEvidenceCoverage;
|
|
503
|
+
}
|
|
504
|
+
export interface InvestigationRootCauseEvidenceLink {
|
|
505
|
+
source: InvestigationEvidenceSource;
|
|
506
|
+
/** Canonical semantic group containing this source’s primary observation. */
|
|
507
|
+
originalGroupId?: string;
|
|
508
|
+
}
|
|
509
|
+
export interface InvestigationRootCauseEvidenceResolution {
|
|
510
|
+
status: "linked" | "missing" | "invalid";
|
|
511
|
+
links: InvestigationRootCauseEvidenceLink[];
|
|
512
|
+
}
|
|
@@ -26,6 +26,25 @@ describe("investigation target identity", () => {
|
|
|
26
26
|
).toBe("Rollout.argoproj.io prod/checkout");
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
+
it("formats saved plural targets as Kubernetes Kinds", () => {
|
|
30
|
+
expect(
|
|
31
|
+
formatInvestigationTarget({
|
|
32
|
+
kind: "deployments",
|
|
33
|
+
group: "apps",
|
|
34
|
+
namespace: "prod",
|
|
35
|
+
name: "api",
|
|
36
|
+
}),
|
|
37
|
+
).toBe("Deployment.apps prod/api");
|
|
38
|
+
expect(
|
|
39
|
+
formatInvestigationTarget({
|
|
40
|
+
kind: "pods",
|
|
41
|
+
group: "metrics.k8s.io",
|
|
42
|
+
namespace: "prod",
|
|
43
|
+
name: "api",
|
|
44
|
+
}),
|
|
45
|
+
).toBe("PodMetrics.metrics.k8s.io prod/api");
|
|
46
|
+
});
|
|
47
|
+
|
|
29
48
|
it("keeps the core target label compact", () => {
|
|
30
49
|
expect(
|
|
31
50
|
formatInvestigationTarget({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resourceKey } from "@skyhook-io/k8s-ui";
|
|
2
2
|
|
|
3
|
-
import { kindToPluralWithGroup } from "../../utils/navigation";
|
|
3
|
+
import { kindToPluralWithGroup, knownKindForPluralWithGroup } from "../../utils/navigation";
|
|
4
4
|
|
|
5
5
|
export interface InvestigationTargetIdentity {
|
|
6
6
|
kind: string;
|
|
@@ -31,6 +31,7 @@ export function runTargetKey(
|
|
|
31
31
|
export function formatInvestigationTarget(
|
|
32
32
|
target: InvestigationTargetIdentity,
|
|
33
33
|
): string {
|
|
34
|
-
const
|
|
34
|
+
const canonicalKind = knownKindForPluralWithGroup(target.kind, target.group) ?? target.kind;
|
|
35
|
+
const kind = target.group ? `${canonicalKind}.${target.group}` : canonicalKind;
|
|
35
36
|
return `${kind} ${target.namespace ? `${target.namespace}/` : ""}${target.name}`;
|
|
36
37
|
}
|
|
@@ -72,6 +72,9 @@ import { useRegisterShortcut } from '../../hooks/useKeyboardShortcuts'
|
|
|
72
72
|
import { CodeViewer } from '../ui/CodeViewer'
|
|
73
73
|
import { ArgoResourceDiffLoader } from './ArgoResourceDiffLoader'
|
|
74
74
|
import { RevisionMetaChip } from './RevisionMetaChip'
|
|
75
|
+
import { RemoteDestinationCloudHint } from './RemoteDestinationCloudHint'
|
|
76
|
+
|
|
77
|
+
const GITOPS_HEALTH_DOCS_URL = 'https://radarhq.io/docs/features/gitops#per-resource-health'
|
|
75
78
|
import type { GitOpsHistoryItem } from '@skyhook-io/k8s-ui'
|
|
76
79
|
|
|
77
80
|
const GITOPS_KINDS: APIResource[] = [
|
|
@@ -634,6 +637,9 @@ function GitOpsDetailView({ namespaces, onOpenResource, onOpenSettings }: GitOps
|
|
|
634
637
|
detail={detail}
|
|
635
638
|
insight={insightsQ.data ?? null}
|
|
636
639
|
insightLoading={insightsQ.isLoading}
|
|
640
|
+
healthDocsUrl={GITOPS_HEALTH_DOCS_URL}
|
|
641
|
+
remoteDestinationHint={<RemoteDestinationCloudHint />}
|
|
642
|
+
onOpenSettings={onOpenSettings}
|
|
637
643
|
renderRevisionMeta={
|
|
638
644
|
isArgoApp && insightsQ.data?.capabilities?.revisionMetadataAvailable
|
|
639
645
|
? (revision) => (
|
|
@@ -808,6 +814,7 @@ function GitOpsDetailView({ namespaces, onOpenResource, onOpenSettings }: GitOps
|
|
|
808
814
|
onQueryChange={setGraphSearch}
|
|
809
815
|
filters={graphFilters}
|
|
810
816
|
showToolbar={false}
|
|
817
|
+
issues={insightsQ.data?.issues}
|
|
811
818
|
/>
|
|
812
819
|
</div>
|
|
813
820
|
</div>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useNavCustomization } from '../../context/NavCustomization'
|
|
2
|
+
import { useCapabilities } from '../../api/client'
|
|
3
|
+
import { openCloudFunnel } from '../CloudFunnelButton'
|
|
4
|
+
|
|
5
|
+
// The one sentence a standalone Radar adds after "this application deploys
|
|
6
|
+
// to another cluster": the thing the user just ran into is what Radar Cloud
|
|
7
|
+
// does. "Radar Cloud" opens the same dialog as the top-right button, so
|
|
8
|
+
// there is one pitch and one connect flow. That dialog connects THIS
|
|
9
|
+
// cluster; the destination is a second connect from Cloud, which is why the
|
|
10
|
+
// copy says "both clusters" and promises the view in Cloud, not here. Rendered only when that button
|
|
11
|
+
// is: the server decides whether there is anything to pitch (cloudConnect
|
|
12
|
+
// capability), and embedded hosts (Radar Cloud itself) mount neither.
|
|
13
|
+
export function RemoteDestinationCloudHint() {
|
|
14
|
+
const { embedded } = useNavCustomization()
|
|
15
|
+
const capabilities = useCapabilities()
|
|
16
|
+
if (embedded || !capabilities.data?.cloudConnect) return null
|
|
17
|
+
return (
|
|
18
|
+
<>
|
|
19
|
+
Connect both clusters to{' '}
|
|
20
|
+
<button type="button" onClick={openCloudFunnel} className="underline decoration-theme-border underline-offset-2 hover:text-theme-text-primary">
|
|
21
|
+
Radar Cloud
|
|
22
|
+
</button>{' '}
|
|
23
|
+
to see this app's resources together.
|
|
24
|
+
</>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { computeRequestLimitLines } from './PrometheusCharts'
|
|
3
|
+
|
|
4
|
+
describe('Pod request and limit overlays', () => {
|
|
5
|
+
it('does not draw a Pod limit when one runtime container is unlimited', () => {
|
|
6
|
+
const resource = { spec: { containers: [
|
|
7
|
+
{ resources: { requests: { cpu: '100m' }, limits: { cpu: '1' } } },
|
|
8
|
+
{ resources: { requests: { cpu: '200m' } } },
|
|
9
|
+
] } }
|
|
10
|
+
const lines = computeRequestLimitLines(resource, 'Pod', 'cpu')!
|
|
11
|
+
expect(lines).toHaveLength(1)
|
|
12
|
+
expect(lines[0].kind).toBe('request')
|
|
13
|
+
expect(lines[0].value).toBeCloseTo(0.3)
|
|
14
|
+
})
|
|
15
|
+
it('sums fully limited runtime containers at per-Pod scale', () => {
|
|
16
|
+
const resource = { spec: { replicas: 5, template: { spec: {
|
|
17
|
+
containers: [{ resources: { limits: { cpu: '1' } } }],
|
|
18
|
+
initContainers: [{ restartPolicy: 'Always', resources: { limits: { cpu: '200m' } } }],
|
|
19
|
+
} } } }
|
|
20
|
+
expect(computeRequestLimitLines(resource, 'Deployment', 'cpu')![0].value).toBeCloseTo(1.2)
|
|
21
|
+
})
|
|
22
|
+
})
|
|
@@ -121,6 +121,7 @@ export function PrometheusCharts({ kind, namespace, name, showEmptyState = false
|
|
|
121
121
|
statusError={status?.error}
|
|
122
122
|
onConnect={() => connectMutation.mutate()}
|
|
123
123
|
connecting={connectMutation.isPending}
|
|
124
|
+
discovering={status?.discovering === true}
|
|
124
125
|
category={activeCategory}
|
|
125
126
|
onCategoryChange={setActiveCategory}
|
|
126
127
|
range={timeRange}
|
|
@@ -161,12 +162,12 @@ export function computeRequestLimitLines(
|
|
|
161
162
|
if (runtimeContainers.length === 0) return undefined
|
|
162
163
|
|
|
163
164
|
let reqSum = 0, reqAny = false
|
|
164
|
-
let limSum = 0,
|
|
165
|
+
let limSum = 0, limAll = true
|
|
165
166
|
for (const c of runtimeContainers) {
|
|
166
167
|
const req = readQuantity(c.resources?.requests?.[category], category)
|
|
167
168
|
const lim = readQuantity(c.resources?.limits?.[category], category)
|
|
168
169
|
if (req != null) { reqSum += req; reqAny = true }
|
|
169
|
-
if (lim != null) { limSum += lim
|
|
170
|
+
if (lim != null && lim > 0) { limSum += lim } else { limAll = false }
|
|
170
171
|
}
|
|
171
172
|
|
|
172
173
|
const lines: ReferenceLine[] = []
|
|
@@ -177,7 +178,7 @@ export function computeRequestLimitLines(
|
|
|
177
178
|
kind: 'request',
|
|
178
179
|
})
|
|
179
180
|
}
|
|
180
|
-
if (
|
|
181
|
+
if (limAll) {
|
|
181
182
|
lines.push({
|
|
182
183
|
value: limSum,
|
|
183
184
|
label: `limit ${formatRequestLimitLabel(limSum, category)}`,
|