@skyhook-io/radar-app 1.13.4 → 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/RadarApp.tsx +5 -0
- package/src/api/client.authRedirect.test.ts +12 -1
- package/src/api/client.prometheusStatus.test.ts +24 -0
- package/src/api/client.ts +325 -16
- package/src/api/diagnose.ts +62 -15
- 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/ConnectionErrorView.test.tsx +30 -0
- package/src/components/ConnectionErrorView.tsx +31 -19
- 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/AgentCase.tsx +131 -0
- package/src/components/diagnose/DiagnoseContext.tsx +2 -1
- package/src/components/diagnose/DiagnoseSurface.test.tsx +0 -20
- package/src/components/diagnose/DiagnoseSurface.tsx +32 -195
- package/src/components/diagnose/InvestigationEvidencePane.test.tsx +783 -7
- package/src/components/diagnose/InvestigationEvidencePane.tsx +774 -133
- package/src/components/diagnose/InvestigationView.tsx +222 -5
- package/src/components/diagnose/diagnoseEvidenceTypes.ts +22 -1
- package/src/components/diagnose/investigationCase.test.tsx +1568 -0
- package/src/components/diagnose/investigationCase.ts +439 -0
- 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/investigationEvidenceKinds.ts +218 -0
- package/src/components/diagnose/investigationEvidencePresentation.test.ts +31 -0
- package/src/components/diagnose/investigationEvidencePresentation.ts +1 -0
- package/src/components/diagnose/investigationMetrics.test.ts +712 -0
- package/src/components/diagnose/investigationMetrics.ts +393 -0
- package/src/components/diagnose/investigationSourceFocus.ts +2 -0
- package/src/components/diagnose/investigationState.test.ts +322 -0
- package/src/components/diagnose/investigationState.ts +147 -25
- package/src/components/diagnose/parts.test.tsx +482 -0
- package/src/components/diagnose/parts.tsx +418 -41
- 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 +245 -103
- 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/PodFilePreview.test.tsx +131 -0
- package/src/components/resources/PodFilePreview.tsx +394 -0
- package/src/components/resources/PodFilesystemModal.tsx +157 -67
- 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.test.tsx +26 -0
- package/src/context/DiagnoseCustomization.tsx +15 -2
- package/src/index.css +17 -0
- package/src/index.ts +1 -0
- package/src/utils/navigation.ts +1 -1
- package/src/utils/shell-safe.test.ts +25 -1
- package/src/utils/shell-safe.ts +16 -0
- 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 -5202
- package/src/components/diagnose/investigationEvidence.ts +0 -4784
- 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
|
@@ -30,6 +30,8 @@ import {
|
|
|
30
30
|
investigationEvidenceInputsEqual,
|
|
31
31
|
investigationEvidenceCoverageLimited,
|
|
32
32
|
investigationEvidenceConflictsWithHealthy,
|
|
33
|
+
investigationHealthConflictExplainedBy,
|
|
34
|
+
investigationLiveCaseTurnIndex,
|
|
33
35
|
investigationEndedBeforeConclusion,
|
|
34
36
|
type InvestigationHistoryUnavailableState,
|
|
35
37
|
investigationHistoryUnavailablePresentation,
|
|
@@ -78,6 +80,7 @@ import {
|
|
|
78
80
|
AssessmentSources,
|
|
79
81
|
ApplyDialog,
|
|
80
82
|
appendThinking,
|
|
83
|
+
mergeStartupSignal,
|
|
81
84
|
upsertTool,
|
|
82
85
|
type Turn,
|
|
83
86
|
} from "./parts";
|
|
@@ -88,6 +91,12 @@ import {
|
|
|
88
91
|
projectInvestigationEvidence,
|
|
89
92
|
resolveInvestigationRootCauseEvidence,
|
|
90
93
|
} from "./investigationEvidence";
|
|
94
|
+
import {
|
|
95
|
+
resolveInvestigationCase,
|
|
96
|
+
investigationCaseItemsStillRendered,
|
|
97
|
+
mergeInvestigationCases,
|
|
98
|
+
type InvestigationCaseResolution,
|
|
99
|
+
} from "./investigationCase";
|
|
91
100
|
import {
|
|
92
101
|
InvestigationEvidencePane,
|
|
93
102
|
partitionInvestigationEvidence,
|
|
@@ -477,6 +486,14 @@ export function InvestigationView({
|
|
|
477
486
|
},
|
|
478
487
|
]);
|
|
479
488
|
break;
|
|
489
|
+
case "phase":
|
|
490
|
+
// Startup phases only feed the pending status line; a replayed
|
|
491
|
+
// finished turn is not running, so nothing shows for it.
|
|
492
|
+
updateLast((t) => {
|
|
493
|
+
const startup = mergeStartupSignal(t.startup, ev);
|
|
494
|
+
return startup === t.startup ? t : { ...t, startup };
|
|
495
|
+
});
|
|
496
|
+
break;
|
|
480
497
|
case "thinking":
|
|
481
498
|
if (ev.token) {
|
|
482
499
|
if (live) {
|
|
@@ -967,15 +984,114 @@ export function InvestigationView({
|
|
|
967
984
|
: undefined,
|
|
968
985
|
[currentAssessment, currentAssessmentIdx, projection],
|
|
969
986
|
);
|
|
987
|
+
// The agent's case binds for every assessment, healthy and inconclusive
|
|
988
|
+
// included, so it is resolved independently of the root cause.
|
|
989
|
+
const investigationCase = useMemo(
|
|
990
|
+
() =>
|
|
991
|
+
currentAssessment?.diagnosis
|
|
992
|
+
? resolveInvestigationCase(
|
|
993
|
+
projection,
|
|
994
|
+
currentAssessment.diagnosis,
|
|
995
|
+
currentAssessmentIdx,
|
|
996
|
+
)
|
|
997
|
+
: undefined,
|
|
998
|
+
[currentAssessment, currentAssessmentIdx, projection],
|
|
999
|
+
);
|
|
1000
|
+
// A follow-up answer that cites evidence takes over the pane's case; the
|
|
1001
|
+
// assessment's own items are then listed read-only under it.
|
|
1002
|
+
const liveCaseTurnIdx = investigationLiveCaseTurnIndex(
|
|
1003
|
+
turns,
|
|
1004
|
+
currentAssessmentIdx,
|
|
1005
|
+
);
|
|
1006
|
+
const liveCaseIsCurrentAssessment = liveCaseTurnIdx === currentAssessmentIdx;
|
|
1007
|
+
// The qualification banner and the "Used for assessment" markers describe the
|
|
1008
|
+
// assessment on screen, so they always read its own resolution. A later turn's
|
|
1009
|
+
// citations only widen the selection (below): replacing the resolution would
|
|
1010
|
+
// drop the assessment's qualification and push its cited evidence back into
|
|
1011
|
+
// the withheld set.
|
|
1012
|
+
const paneResolution = rootCauseEvidenceResolution;
|
|
1013
|
+
// The live turn's own resolution stays available for the live turn's own
|
|
1014
|
+
// receipt: its sources are its, not the assessment's.
|
|
1015
|
+
const liveTurnResolution = useMemo(() => {
|
|
1016
|
+
if (liveCaseIsCurrentAssessment) return rootCauseEvidenceResolution;
|
|
1017
|
+
const diagnosis = turns[liveCaseTurnIdx]?.diagnosis;
|
|
1018
|
+
return diagnosis?.rootCause
|
|
1019
|
+
? resolveInvestigationRootCauseEvidence(
|
|
1020
|
+
projection,
|
|
1021
|
+
diagnosis.rootCauseEvidence,
|
|
1022
|
+
liveCaseTurnIdx,
|
|
1023
|
+
)
|
|
1024
|
+
: undefined;
|
|
1025
|
+
}, [
|
|
1026
|
+
liveCaseIsCurrentAssessment,
|
|
1027
|
+
rootCauseEvidenceResolution,
|
|
1028
|
+
turns,
|
|
1029
|
+
liveCaseTurnIdx,
|
|
1030
|
+
projection,
|
|
1031
|
+
]);
|
|
1032
|
+
const followUpSelectedGroupIds = useMemo(() => {
|
|
1033
|
+
if (liveCaseIsCurrentAssessment) return undefined;
|
|
1034
|
+
if (liveTurnResolution?.status !== "linked") return undefined;
|
|
1035
|
+
return liveTurnResolution.links.flatMap((link) =>
|
|
1036
|
+
link.originalGroupId
|
|
1037
|
+
? [{ groupId: link.originalGroupId, source: link.source }]
|
|
1038
|
+
: [],
|
|
1039
|
+
);
|
|
1040
|
+
}, [liveCaseIsCurrentAssessment, liveTurnResolution]);
|
|
1041
|
+
// The live turn's own case, before anything is carried onto it. Its source
|
|
1042
|
+
// receipt must list what IT cited, not what the merge brought along.
|
|
1043
|
+
const liveTurnCase = useMemo(
|
|
1044
|
+
() =>
|
|
1045
|
+
liveCaseIsCurrentAssessment
|
|
1046
|
+
? investigationCase
|
|
1047
|
+
: resolveInvestigationCase(
|
|
1048
|
+
projection,
|
|
1049
|
+
turns[liveCaseTurnIdx]?.diagnosis,
|
|
1050
|
+
liveCaseTurnIdx,
|
|
1051
|
+
),
|
|
1052
|
+
[
|
|
1053
|
+
liveCaseIsCurrentAssessment,
|
|
1054
|
+
investigationCase,
|
|
1055
|
+
projection,
|
|
1056
|
+
turns,
|
|
1057
|
+
liveCaseTurnIdx,
|
|
1058
|
+
],
|
|
1059
|
+
);
|
|
1060
|
+
const paneCase = useMemo(() => {
|
|
1061
|
+
const live = liveTurnCase;
|
|
1062
|
+
const earlier: InvestigationCaseResolution[] = [];
|
|
1063
|
+
for (let i = turns.length - 1; i >= 0; i -= 1) {
|
|
1064
|
+
const diagnosis = turns[i]?.diagnosis;
|
|
1065
|
+
if (i === liveCaseTurnIdx || !diagnosis) continue;
|
|
1066
|
+
// Reuse the assessment's own resolution rather than resolving it a
|
|
1067
|
+
// second time: same projection, same result, and it keeps the items the
|
|
1068
|
+
// conflict banner reasons about the ones the merge received.
|
|
1069
|
+
earlier.push(
|
|
1070
|
+
i === currentAssessmentIdx && investigationCase
|
|
1071
|
+
? investigationCase
|
|
1072
|
+
: resolveInvestigationCase(projection, diagnosis, i),
|
|
1073
|
+
);
|
|
1074
|
+
}
|
|
1075
|
+
return mergeInvestigationCases(live, earlier);
|
|
1076
|
+
}, [
|
|
1077
|
+
liveTurnCase,
|
|
1078
|
+
investigationCase,
|
|
1079
|
+
currentAssessmentIdx,
|
|
1080
|
+
projection,
|
|
1081
|
+
turns,
|
|
1082
|
+
liveCaseTurnIdx,
|
|
1083
|
+
]);
|
|
970
1084
|
const visibleEvidenceGroupIds = useMemo(
|
|
971
1085
|
() =>
|
|
972
1086
|
new Set(
|
|
973
1087
|
partitionInvestigationEvidence(
|
|
974
1088
|
projection.groups,
|
|
975
|
-
|
|
1089
|
+
paneResolution,
|
|
1090
|
+
paneCase,
|
|
1091
|
+
followUpSelectedGroupIds,
|
|
976
1092
|
).collectionByGroup.keys(),
|
|
977
1093
|
),
|
|
978
|
-
[projection.groups,
|
|
1094
|
+
[projection.groups, paneResolution, paneCase, followUpSelectedGroupIds],
|
|
979
1095
|
);
|
|
980
1096
|
const evidenceStepIdsByTurn = useMemo(
|
|
981
1097
|
() =>
|
|
@@ -1273,6 +1389,32 @@ export function InvestigationView({
|
|
|
1273
1389
|
const currentAssessmentEvidenceConflict =
|
|
1274
1390
|
currentAssessment?.diagnosis?.healthy === true &&
|
|
1275
1391
|
investigationEvidenceConflictsWithHealthy(projection);
|
|
1392
|
+
// The banner qualifies THIS assessment, so only this assessment's own case
|
|
1393
|
+
// may reframe it. `paneCase` also carries a later answer's items and notes
|
|
1394
|
+
// inherited from superseded assessments; neither of those spoke about this
|
|
1395
|
+
// verdict, and letting them soften it would let an unrelated follow-up
|
|
1396
|
+
// retire a warning the reader still needs.
|
|
1397
|
+
const currentAssessmentEvidenceConflictExplainedBy = useMemo(() => {
|
|
1398
|
+
if (!currentAssessmentEvidenceConflict) return undefined;
|
|
1399
|
+
// Two conditions, and both are required. The note must belong to THIS
|
|
1400
|
+
// assessment — a later answer or a superseded assessment did not speak
|
|
1401
|
+
// about this verdict. And it must survive into the case the pane actually
|
|
1402
|
+
// renders: the merge lets a later turn take over a group, and a banner
|
|
1403
|
+
// that points at a note the reader cannot find is worse than no banner.
|
|
1404
|
+
const qualifying = investigationCaseItemsStillRendered(
|
|
1405
|
+
investigationCase?.items,
|
|
1406
|
+
paneCase?.items,
|
|
1407
|
+
);
|
|
1408
|
+
return (
|
|
1409
|
+
investigationHealthConflictExplainedBy(projection, qualifying) ??
|
|
1410
|
+
undefined
|
|
1411
|
+
);
|
|
1412
|
+
}, [
|
|
1413
|
+
currentAssessmentEvidenceConflict,
|
|
1414
|
+
projection,
|
|
1415
|
+
investigationCase,
|
|
1416
|
+
paneCase,
|
|
1417
|
+
]);
|
|
1276
1418
|
const hasEvidenceCollectedAfterAssessment =
|
|
1277
1419
|
currentAssessmentIdx >= 0 &&
|
|
1278
1420
|
projection.sources.some(
|
|
@@ -1680,6 +1822,7 @@ export function InvestigationView({
|
|
|
1680
1822
|
<Fragment key={index}>
|
|
1681
1823
|
<TurnView
|
|
1682
1824
|
turn={turn}
|
|
1825
|
+
agentLabel={agentLabel}
|
|
1683
1826
|
turnIndex={index}
|
|
1684
1827
|
evidenceStepIds={evidenceStepIdsByTurn.get(index)}
|
|
1685
1828
|
onViewEvidence={viewEvidenceSource}
|
|
@@ -1704,6 +1847,49 @@ export function InvestigationView({
|
|
|
1704
1847
|
: undefined
|
|
1705
1848
|
}
|
|
1706
1849
|
hideConclusion={assessmentIndexes.includes(index)}
|
|
1850
|
+
assessmentSources={(() => {
|
|
1851
|
+
// Answer turns show what they cited; the live
|
|
1852
|
+
// one also drives Findings, earlier ones are
|
|
1853
|
+
// read-only.
|
|
1854
|
+
if (
|
|
1855
|
+
!turn.question ||
|
|
1856
|
+
turn.verify ||
|
|
1857
|
+
turn.apply ||
|
|
1858
|
+
turn.status !== "done" ||
|
|
1859
|
+
!turn.diagnosis
|
|
1860
|
+
)
|
|
1861
|
+
return undefined;
|
|
1862
|
+
const answerCase =
|
|
1863
|
+
index === liveCaseTurnIdx
|
|
1864
|
+
? liveTurnCase
|
|
1865
|
+
: resolveInvestigationCase(
|
|
1866
|
+
projection,
|
|
1867
|
+
turn.diagnosis,
|
|
1868
|
+
index,
|
|
1869
|
+
);
|
|
1870
|
+
const answerResolution =
|
|
1871
|
+
index === liveCaseTurnIdx
|
|
1872
|
+
? liveTurnResolution
|
|
1873
|
+
: undefined;
|
|
1874
|
+
return answerCase?.items.length ||
|
|
1875
|
+
answerResolution?.links.length ||
|
|
1876
|
+
turn.diagnosis?.unlinkedEvidence ||
|
|
1877
|
+
turn.diagnosis?.evidenceMalformed ? (
|
|
1878
|
+
<AssessmentSources
|
|
1879
|
+
renderedGroupIds={visibleEvidenceGroupIds}
|
|
1880
|
+
resolution={answerResolution}
|
|
1881
|
+
investigationCase={answerCase}
|
|
1882
|
+
unlinkedEvidence={
|
|
1883
|
+
turn.diagnosis?.unlinkedEvidence
|
|
1884
|
+
}
|
|
1885
|
+
evidenceMalformed={
|
|
1886
|
+
turn.diagnosis?.evidenceMalformed
|
|
1887
|
+
}
|
|
1888
|
+
readOnly={index !== liveCaseTurnIdx}
|
|
1889
|
+
onViewSource={viewActivitySource}
|
|
1890
|
+
/>
|
|
1891
|
+
) : undefined;
|
|
1892
|
+
})()}
|
|
1707
1893
|
/>
|
|
1708
1894
|
{showSplitWorkspace &&
|
|
1709
1895
|
index === currentAssessmentIdx &&
|
|
@@ -1942,9 +2128,24 @@ export function InvestigationView({
|
|
|
1942
2128
|
}
|
|
1943
2129
|
diagnosis={currentAssessment.diagnosis}
|
|
1944
2130
|
assessmentSources={
|
|
1945
|
-
|
|
2131
|
+
// An assessment whose every note was rejected has no
|
|
2132
|
+
// items and no links, and the loss is the only thing
|
|
2133
|
+
// there is to say about it.
|
|
2134
|
+
rootCauseEvidenceResolution?.links.length ||
|
|
2135
|
+
investigationCase?.items.length ||
|
|
2136
|
+
currentAssessment.diagnosis.unlinkedEvidence ||
|
|
2137
|
+
currentAssessment.diagnosis.evidenceMalformed ? (
|
|
1946
2138
|
<AssessmentSources
|
|
2139
|
+
renderedGroupIds={visibleEvidenceGroupIds}
|
|
1947
2140
|
resolution={rootCauseEvidenceResolution}
|
|
2141
|
+
investigationCase={investigationCase}
|
|
2142
|
+
unlinkedEvidence={
|
|
2143
|
+
currentAssessment.diagnosis?.unlinkedEvidence
|
|
2144
|
+
}
|
|
2145
|
+
evidenceMalformed={
|
|
2146
|
+
currentAssessment.diagnosis?.evidenceMalformed
|
|
2147
|
+
}
|
|
2148
|
+
readOnly={!liveCaseIsCurrentAssessment}
|
|
1948
2149
|
onViewSource={viewActivitySource}
|
|
1949
2150
|
/>
|
|
1950
2151
|
) : undefined
|
|
@@ -1983,6 +2184,9 @@ export function InvestigationView({
|
|
|
1983
2184
|
showDisclaimer={false}
|
|
1984
2185
|
coverageLimited={currentAssessmentCoverageLimited}
|
|
1985
2186
|
evidenceConflict={currentAssessmentEvidenceConflict}
|
|
2187
|
+
evidenceConflictExplainedBy={
|
|
2188
|
+
currentAssessmentEvidenceConflictExplainedBy
|
|
2189
|
+
}
|
|
1986
2190
|
/>
|
|
1987
2191
|
) : (
|
|
1988
2192
|
<div className="mt-2 flex items-center gap-2 rounded-md bg-theme-surface/60 px-2.5 py-2 text-xs text-theme-text-tertiary">
|
|
@@ -2046,15 +2250,26 @@ export function InvestigationView({
|
|
|
2046
2250
|
diagnosis: turns[index].diagnosis!,
|
|
2047
2251
|
explanation: explanationFor(turns[index]),
|
|
2048
2252
|
sources: (() => {
|
|
2253
|
+
// Each earlier assessment owns its own items; they
|
|
2254
|
+
// render read-only here and never annotate cards.
|
|
2049
2255
|
const resolution =
|
|
2050
2256
|
resolveInvestigationRootCauseEvidence(
|
|
2051
2257
|
projection,
|
|
2052
2258
|
turns[index].diagnosis!.rootCauseEvidence,
|
|
2053
2259
|
index,
|
|
2054
2260
|
);
|
|
2055
|
-
|
|
2261
|
+
const earlierCase = resolveInvestigationCase(
|
|
2262
|
+
projection,
|
|
2263
|
+
turns[index].diagnosis,
|
|
2264
|
+
index,
|
|
2265
|
+
);
|
|
2266
|
+
return resolution.links.length ||
|
|
2267
|
+
earlierCase.items.length ? (
|
|
2056
2268
|
<AssessmentSources
|
|
2269
|
+
renderedGroupIds={visibleEvidenceGroupIds}
|
|
2057
2270
|
resolution={resolution}
|
|
2271
|
+
investigationCase={earlierCase}
|
|
2272
|
+
readOnly
|
|
2058
2273
|
onViewSource={viewActivitySource}
|
|
2059
2274
|
/>
|
|
2060
2275
|
) : undefined;
|
|
@@ -2064,7 +2279,9 @@ export function InvestigationView({
|
|
|
2064
2279
|
|
|
2065
2280
|
<InvestigationEvidencePane
|
|
2066
2281
|
projection={projection}
|
|
2067
|
-
rootCauseEvidence={
|
|
2282
|
+
rootCauseEvidence={paneResolution}
|
|
2283
|
+
alsoSelectedGroupIds={followUpSelectedGroupIds}
|
|
2284
|
+
investigationCase={paneCase}
|
|
2068
2285
|
collecting={
|
|
2069
2286
|
explanationRequest?.status !== "running" &&
|
|
2070
2287
|
(requestPending ||
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* investigation projection. These deliberately exclude any presentation or
|
|
4
4
|
* transport envelope so the live Diagnose UI is not coupled to another route.
|
|
5
5
|
*/
|
|
6
|
+
import type { HPADiagnosisView } from "@skyhook-io/k8s-ui";
|
|
7
|
+
|
|
6
8
|
export interface DiagnosisFilteredLogs {
|
|
7
9
|
lines: string[] | null;
|
|
8
10
|
totalLines: number;
|
|
@@ -53,6 +55,25 @@ export interface DiagnosisResourceRef {
|
|
|
53
55
|
name: string;
|
|
54
56
|
}
|
|
55
57
|
|
|
58
|
+
/** The HPA diagnosis Radar computes for the scaler itself, attached to the workload it scales. */
|
|
59
|
+
export interface DiagnosisHPASummary extends HPADiagnosisView {
|
|
60
|
+
target?: DiagnosisResourceRef;
|
|
61
|
+
metrics?: Array<{
|
|
62
|
+
type: string;
|
|
63
|
+
name: string;
|
|
64
|
+
current?: string;
|
|
65
|
+
target?: string;
|
|
66
|
+
status: string;
|
|
67
|
+
}>;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface DiagnosisScalerRef extends DiagnosisResourceRef {
|
|
71
|
+
/** The KEDA ScaledObject that owns this HPA, when KEDA created it. */
|
|
72
|
+
managedBy?: DiagnosisResourceRef;
|
|
73
|
+
/** Present only for an HPA the caller may read; KEDA scalers carry the ref alone. */
|
|
74
|
+
hpaSummary?: DiagnosisHPASummary;
|
|
75
|
+
}
|
|
76
|
+
|
|
56
77
|
export interface DiagnosisResourceContext {
|
|
57
78
|
tier: "basic" | "diagnostic";
|
|
58
79
|
owner?: DiagnosisResourceRef;
|
|
@@ -71,7 +92,7 @@ export interface DiagnosisResourceContext {
|
|
|
71
92
|
pvcs?: DiagnosisResourceRef[];
|
|
72
93
|
};
|
|
73
94
|
runsOn?: DiagnosisResourceRef;
|
|
74
|
-
scaledBy?:
|
|
95
|
+
scaledBy?: DiagnosisScalerRef[];
|
|
75
96
|
statusSummary?: {
|
|
76
97
|
phase?: string;
|
|
77
98
|
conditions?: Array<{
|