@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.
Files changed (230) hide show
  1. package/package.json +8 -8
  2. package/src/App.tsx +60 -24
  3. package/src/RadarApp.tsx +5 -0
  4. package/src/api/client.authRedirect.test.ts +12 -1
  5. package/src/api/client.prometheusStatus.test.ts +24 -0
  6. package/src/api/client.ts +325 -16
  7. package/src/api/diagnose.ts +62 -15
  8. package/src/api/drain-plan.test.ts +86 -0
  9. package/src/api/quotas.test.ts +26 -0
  10. package/src/api/quotas.ts +20 -0
  11. package/src/api/workloadMetrics.test.ts +40 -0
  12. package/src/api/workloadMetrics.ts +68 -0
  13. package/src/components/CloudConnectFlow.tsx +179 -42
  14. package/src/components/CloudFunnelButton.tsx +107 -36
  15. package/src/components/ConnectionErrorView.test.tsx +30 -0
  16. package/src/components/ConnectionErrorView.tsx +31 -19
  17. package/src/components/SyncProgressPanel.tsx +73 -0
  18. package/src/components/audit/AuditView.tsx +2 -0
  19. package/src/components/cloudConnectHandoff.test.ts +140 -0
  20. package/src/components/cloudConnectHandoff.ts +124 -0
  21. package/src/components/diagnose/AgentCase.tsx +131 -0
  22. package/src/components/diagnose/DiagnoseContext.tsx +2 -1
  23. package/src/components/diagnose/DiagnoseSurface.test.tsx +0 -20
  24. package/src/components/diagnose/DiagnoseSurface.tsx +32 -195
  25. package/src/components/diagnose/InvestigationEvidencePane.test.tsx +783 -7
  26. package/src/components/diagnose/InvestigationEvidencePane.tsx +774 -133
  27. package/src/components/diagnose/InvestigationView.tsx +222 -5
  28. package/src/components/diagnose/diagnoseEvidenceTypes.ts +22 -1
  29. package/src/components/diagnose/investigationCase.test.tsx +1568 -0
  30. package/src/components/diagnose/investigationCase.ts +439 -0
  31. package/src/components/diagnose/investigationEvidence/adapters/changes.ts +60 -0
  32. package/src/components/diagnose/investigationEvidence/adapters/diagnose.test.ts +573 -0
  33. package/src/components/diagnose/investigationEvidence/adapters/diagnose.ts +935 -0
  34. package/src/components/diagnose/investigationEvidence/adapters/events.ts +96 -0
  35. package/src/components/diagnose/investigationEvidence/adapters/helm.test.ts +242 -0
  36. package/src/components/diagnose/investigationEvidence/adapters/helm.ts +208 -0
  37. package/src/components/diagnose/investigationEvidence/adapters/issues.ts +172 -0
  38. package/src/components/diagnose/investigationEvidence/adapters/logs.test.ts +283 -0
  39. package/src/components/diagnose/investigationEvidence/adapters/logs.ts +183 -0
  40. package/src/components/diagnose/investigationEvidence/adapters/permissions.test.ts +528 -0
  41. package/src/components/diagnose/investigationEvidence/adapters/permissions.ts +292 -0
  42. package/src/components/diagnose/investigationEvidence/adapters/prometheus.test.ts +1641 -0
  43. package/src/components/diagnose/investigationEvidence/adapters/prometheus.ts +769 -0
  44. package/src/components/diagnose/investigationEvidence/adapters/resource.test.ts +54 -0
  45. package/src/components/diagnose/investigationEvidence/adapters/resource.ts +257 -0
  46. package/src/components/diagnose/investigationEvidence/adapters/topology.ts +207 -0
  47. package/src/components/diagnose/investigationEvidence/builder.ts +418 -0
  48. package/src/components/diagnose/investigationEvidence/evidenceFixtures.ts +179 -0
  49. package/src/components/diagnose/investigationEvidence/identity.test.ts +614 -0
  50. package/src/components/diagnose/investigationEvidence/identity.ts +261 -0
  51. package/src/components/diagnose/investigationEvidence/index.ts +55 -0
  52. package/src/components/diagnose/investigationEvidence/observations.ts +954 -0
  53. package/src/components/diagnose/investigationEvidence/parse.ts +467 -0
  54. package/src/components/diagnose/investigationEvidence/projection.test.ts +2703 -0
  55. package/src/components/diagnose/investigationEvidence/types.ts +512 -0
  56. package/src/components/diagnose/investigationEvidenceKinds.ts +218 -0
  57. package/src/components/diagnose/investigationEvidencePresentation.test.ts +31 -0
  58. package/src/components/diagnose/investigationEvidencePresentation.ts +1 -0
  59. package/src/components/diagnose/investigationMetrics.test.ts +712 -0
  60. package/src/components/diagnose/investigationMetrics.ts +393 -0
  61. package/src/components/diagnose/investigationSourceFocus.ts +2 -0
  62. package/src/components/diagnose/investigationState.test.ts +322 -0
  63. package/src/components/diagnose/investigationState.ts +147 -25
  64. package/src/components/diagnose/parts.test.tsx +482 -0
  65. package/src/components/diagnose/parts.tsx +418 -41
  66. package/src/components/diagnose/target.test.ts +19 -0
  67. package/src/components/diagnose/target.ts +3 -2
  68. package/src/components/gitops/GitOpsView.tsx +7 -0
  69. package/src/components/gitops/RemoteDestinationCloudHint.tsx +26 -0
  70. package/src/components/resource/PrometheusCharts.overlays.test.ts +22 -0
  71. package/src/components/resource/PrometheusCharts.tsx +4 -3
  72. package/src/components/resource/PrometheusChartsGrid.render.test.tsx +99 -0
  73. package/src/components/resource/PrometheusChartsGrid.tsx +245 -103
  74. package/src/components/resource/RightsizingStrip.test.ts +38 -0
  75. package/src/components/resource/RightsizingStrip.tsx +15 -3
  76. package/src/components/resource/WorkloadMetricsHelpDialog.test.tsx +79 -0
  77. package/src/components/resource/WorkloadMetricsHelpDialog.tsx +145 -0
  78. package/src/components/resource/WorkloadMetricsSection.render.test.tsx +351 -0
  79. package/src/components/resource/WorkloadMetricsSection.tsx +486 -0
  80. package/src/components/resource/workloadMetricValues.test.ts +65 -0
  81. package/src/components/resource/workloadMetricValues.ts +30 -0
  82. package/src/components/resources/PodFilePreview.test.tsx +131 -0
  83. package/src/components/resources/PodFilePreview.tsx +394 -0
  84. package/src/components/resources/PodFilesystemModal.tsx +157 -67
  85. package/src/components/resources/ResourcesView.tsx +44 -6
  86. package/src/components/resources/renderers/NamespaceRenderer.tsx +7 -1
  87. package/src/components/resources/renderers/PodRenderer.tsx +4 -0
  88. package/src/components/resources/renderers/RolloutRenderer.tsx +15 -1
  89. package/src/components/resources/renderers/WorkloadRenderer.tsx +3 -0
  90. package/src/components/rightsizing/RightsizingScanView.tsx +21 -0
  91. package/src/components/settings/SettingsDialog.tsx +94 -14
  92. package/src/components/traffic/TrafficFlowList.tsx +229 -70
  93. package/src/components/traffic/TrafficGraph.tsx +6 -6
  94. package/src/components/traffic/TrafficView.tsx +10 -9
  95. package/src/components/traffic/trafficFilters.test.ts +28 -1
  96. package/src/components/traffic/trafficFilters.ts +31 -0
  97. package/src/components/workload/WorkloadView.tsx +19 -8
  98. package/src/context/ConnectionContext.tsx +48 -3
  99. package/src/context/DiagnoseCustomization.test.tsx +26 -0
  100. package/src/context/DiagnoseCustomization.tsx +15 -2
  101. package/src/index.css +17 -0
  102. package/src/index.ts +1 -0
  103. package/src/utils/navigation.ts +1 -1
  104. package/src/utils/shell-safe.test.ts +25 -1
  105. package/src/utils/shell-safe.ts +16 -0
  106. package/src/utils/topology-namespace.test.ts +64 -0
  107. package/src/utils/topology-namespace.ts +18 -0
  108. package/src/components/diagnose/investigationEvidence.test.ts +0 -5202
  109. package/src/components/diagnose/investigationEvidence.ts +0 -4784
  110. package/src/components/gitops/GitOpsActions.tsx +0 -1
  111. package/src/components/gitops/GitOpsStatusBadge.tsx +0 -1
  112. package/src/components/gitops/ManagedResourcesList.tsx +0 -1
  113. package/src/components/gitops/SyncCountdown.tsx +0 -1
  114. package/src/components/gitops/index.ts +0 -4
  115. package/src/components/helm/ManifestDiffViewer.tsx +0 -69
  116. package/src/components/logs/JsonLogLine.tsx +0 -1
  117. package/src/components/logs/LogCore.tsx +0 -2
  118. package/src/components/logs/useLogBuffer.ts +0 -2
  119. package/src/components/logs/useLogSearch.ts +0 -1
  120. package/src/components/resource-drawer/ResourceDrawer.tsx +0 -216
  121. package/src/components/resources/drawer-components.tsx +0 -1
  122. package/src/components/resources/renderers/AlertRenderer.tsx +0 -1
  123. package/src/components/resources/renderers/CNPGBackupRenderer.tsx +0 -1
  124. package/src/components/resources/renderers/CNPGPoolerRenderer.tsx +0 -1
  125. package/src/components/resources/renderers/CNPGScheduledBackupRenderer.tsx +0 -1
  126. package/src/components/resources/renderers/CertificateRenderer.tsx +0 -1
  127. package/src/components/resources/renderers/CertificateRequestRenderer.tsx +0 -1
  128. package/src/components/resources/renderers/ChallengeRenderer.tsx +0 -1
  129. package/src/components/resources/renderers/ClusterComplianceReportRenderer.tsx +0 -1
  130. package/src/components/resources/renderers/ClusterExternalSecretRenderer.tsx +0 -1
  131. package/src/components/resources/renderers/ClusterIssuerRenderer.tsx +0 -1
  132. package/src/components/resources/renderers/ConfigAuditReportRenderer.tsx +0 -1
  133. package/src/components/resources/renderers/ConfigMapRenderer.tsx +0 -1
  134. package/src/components/resources/renderers/CronJobRenderer.tsx +0 -1
  135. package/src/components/resources/renderers/CronWorkflowRenderer.tsx +0 -1
  136. package/src/components/resources/renderers/EventRenderer.tsx +0 -1
  137. package/src/components/resources/renderers/ExposedSecretReportRenderer.tsx +0 -1
  138. package/src/components/resources/renderers/ExternalSecretRenderer.tsx +0 -1
  139. package/src/components/resources/renderers/FluxHelmReleaseRenderer.tsx +0 -1
  140. package/src/components/resources/renderers/GRPCRouteRenderer.tsx +0 -1
  141. package/src/components/resources/renderers/GatewayClassRenderer.tsx +0 -1
  142. package/src/components/resources/renderers/GatewayRenderer.tsx +0 -1
  143. package/src/components/resources/renderers/GenericRenderer.tsx +0 -1
  144. package/src/components/resources/renderers/GitRepositoryRenderer.tsx +0 -1
  145. package/src/components/resources/renderers/HTTPRouteRenderer.tsx +0 -1
  146. package/src/components/resources/renderers/HelmRepositoryRenderer.tsx +0 -1
  147. package/src/components/resources/renderers/IngressClassRenderer.tsx +0 -1
  148. package/src/components/resources/renderers/IngressRenderer.tsx +0 -1
  149. package/src/components/resources/renderers/IstioAuthorizationPolicyRenderer.tsx +0 -1
  150. package/src/components/resources/renderers/IstioDestinationRuleRenderer.tsx +0 -1
  151. package/src/components/resources/renderers/IstioGatewayRenderer.tsx +0 -1
  152. package/src/components/resources/renderers/IstioPeerAuthenticationRenderer.tsx +0 -1
  153. package/src/components/resources/renderers/IstioServiceEntryRenderer.tsx +0 -1
  154. package/src/components/resources/renderers/IstioVirtualServiceRenderer.tsx +0 -1
  155. package/src/components/resources/renderers/JobRenderer.tsx +0 -1
  156. package/src/components/resources/renderers/KarpenterEC2NodeClassRenderer.tsx +0 -1
  157. package/src/components/resources/renderers/KarpenterNodeClaimRenderer.tsx +0 -1
  158. package/src/components/resources/renderers/KedaScaledJobRenderer.tsx +0 -1
  159. package/src/components/resources/renderers/KedaScaledObjectRenderer.tsx +0 -1
  160. package/src/components/resources/renderers/KedaTriggerAuthRenderer.tsx +0 -1
  161. package/src/components/resources/renderers/KnativeConfigurationRenderer.tsx +0 -1
  162. package/src/components/resources/renderers/KnativeEventingRenderer.tsx +0 -1
  163. package/src/components/resources/renderers/KnativeFlowRenderer.tsx +0 -1
  164. package/src/components/resources/renderers/KnativeNetworkingRenderer.tsx +0 -1
  165. package/src/components/resources/renderers/KnativeRevisionRenderer.tsx +0 -1
  166. package/src/components/resources/renderers/KnativeRouteRenderer.tsx +0 -1
  167. package/src/components/resources/renderers/KnativeServiceRenderer.tsx +0 -1
  168. package/src/components/resources/renderers/KnativeSourceRenderer.tsx +0 -1
  169. package/src/components/resources/renderers/KustomizationRenderer.tsx +0 -1
  170. package/src/components/resources/renderers/KyvernoPolicyReportRenderer.tsx +0 -1
  171. package/src/components/resources/renderers/LeaseRenderer.tsx +0 -1
  172. package/src/components/resources/renderers/NetworkPolicyRenderer.tsx +0 -1
  173. package/src/components/resources/renderers/OCIRepositoryRenderer.tsx +0 -1
  174. package/src/components/resources/renderers/OrderRenderer.tsx +0 -1
  175. package/src/components/resources/renderers/PersistentVolumeRenderer.tsx +0 -1
  176. package/src/components/resources/renderers/PodDisruptionBudgetRenderer.tsx +0 -1
  177. package/src/components/resources/renderers/PodMonitorRenderer.tsx +0 -1
  178. package/src/components/resources/renderers/PriorityClassRenderer.tsx +0 -1
  179. package/src/components/resources/renderers/PrometheusRuleRenderer.tsx +0 -1
  180. package/src/components/resources/renderers/ReplicaSetRenderer.tsx +0 -1
  181. package/src/components/resources/renderers/RuntimeClassRenderer.tsx +0 -1
  182. package/src/components/resources/renderers/SbomReportRenderer.tsx +0 -1
  183. package/src/components/resources/renderers/SealedSecretRenderer.tsx +0 -1
  184. package/src/components/resources/renderers/SecretRenderer.tsx +0 -1
  185. package/src/components/resources/renderers/SecretStoreRenderer.tsx +0 -1
  186. package/src/components/resources/renderers/ServiceMonitorRenderer.tsx +0 -1
  187. package/src/components/resources/renderers/SimpleRouteRenderer.tsx +0 -1
  188. package/src/components/resources/renderers/StorageClassRenderer.tsx +0 -1
  189. package/src/components/resources/renderers/TraefikIngressRouteRenderer.tsx +0 -1
  190. package/src/components/resources/renderers/VPARenderer.tsx +0 -1
  191. package/src/components/resources/renderers/VeleroScheduleRenderer.tsx +0 -1
  192. package/src/components/resources/renderers/VeleroVSLRenderer.tsx +0 -1
  193. package/src/components/resources/renderers/VulnerabilityReportRenderer.tsx +0 -1
  194. package/src/components/resources/renderers/WebhookConfigRenderer.tsx +0 -1
  195. package/src/components/resources/renderers/WorkflowRenderer.tsx +0 -1
  196. package/src/components/resources/renderers/WorkflowTemplateRenderer.tsx +0 -1
  197. package/src/components/resources/renderers/argo-cells.tsx +0 -1
  198. package/src/components/resources/renderers/certmanager-cells.tsx +0 -1
  199. package/src/components/resources/renderers/cnpg-cells.tsx +0 -1
  200. package/src/components/resources/renderers/eso-cells.tsx +0 -1
  201. package/src/components/resources/renderers/flux-cells.tsx +0 -1
  202. package/src/components/resources/renderers/index.ts +0 -94
  203. package/src/components/resources/renderers/istio-cells.tsx +0 -1
  204. package/src/components/resources/renderers/karpenter-cells.tsx +0 -1
  205. package/src/components/resources/renderers/keda-cells.tsx +0 -1
  206. package/src/components/resources/renderers/knative-cells.tsx +0 -1
  207. package/src/components/resources/renderers/kyverno-cells.tsx +0 -1
  208. package/src/components/resources/renderers/prometheus-cells.tsx +0 -1
  209. package/src/components/resources/renderers/traefik-cells.tsx +0 -1
  210. package/src/components/resources/renderers/trivy-cells.tsx +0 -1
  211. package/src/components/resources/renderers/trivy-shared.tsx +0 -1
  212. package/src/components/resources/renderers/velero-cells.tsx +0 -1
  213. package/src/components/resources/resource-utils-argo.ts +0 -2
  214. package/src/components/resources/resource-utils-certmanager.ts +0 -2
  215. package/src/components/resources/resource-utils-eso.ts +0 -2
  216. package/src/components/resources/resource-utils-flux.ts +0 -2
  217. package/src/components/resources/resource-utils-istio.ts +0 -2
  218. package/src/components/resources/resource-utils-karpenter.ts +0 -2
  219. package/src/components/resources/resource-utils-knative.ts +0 -2
  220. package/src/components/resources/resource-utils-kyverno.ts +0 -2
  221. package/src/components/resources/resource-utils-prometheus.ts +0 -2
  222. package/src/components/resources/resource-utils-traefik.ts +0 -1
  223. package/src/components/resources/resource-utils-trivy.ts +0 -2
  224. package/src/components/resources/resource-utils-velero.ts +0 -2
  225. package/src/components/shared/EditableYamlView.tsx +0 -24
  226. package/src/components/timeline/DiffViewer.tsx +0 -1
  227. package/src/components/traffic/index.ts +0 -3
  228. package/src/components/ui/ForceDeleteConfirmDialog.tsx +0 -1
  229. package/src/components/ui/MetricsChart.tsx +0 -1
  230. package/src/components/ui/ResourceBar.tsx +0 -1
@@ -22,13 +22,8 @@ import {
22
22
  Check,
23
23
  RotateCcw,
24
24
  PanelLeftOpen,
25
- Link,
26
- Lock,
27
- Users,
28
25
  } from "lucide-react";
29
26
  import { Tooltip } from "../ui/Tooltip";
30
- import { ConfirmDialog } from "../ui/ConfirmDialog";
31
- import { Badge } from "@skyhook-io/k8s-ui/components/ui/Badge";
32
27
  import { useAnimatedUnmount } from "../../hooks/useAnimatedUnmount";
33
28
  import { TRANSITION_BACKDROP, TRANSITION_DRAWER } from "../../utils/animation";
34
29
  import {
@@ -52,7 +47,6 @@ import { AgentSetupNotice } from "./AgentSetupNotice";
52
47
  import { ConsentCard } from "./parts";
53
48
  import { buildLaunchCommand, launchAgentLabel, openInTerminal } from "./launch";
54
49
  import {
55
- updateRunVisibility,
56
50
  type RunSummary,
57
51
  type ExecutionProfile,
58
52
  } from "../../api/diagnose";
@@ -190,153 +184,6 @@ function InvestigationMenu({ run }: { run: RunSummary }) {
190
184
  );
191
185
  }
192
186
 
193
- export function canCopyRunLink(
194
- run: RunSummary | null | undefined,
195
- ): run is RunSummary & { radarUrl: string } {
196
- return typeof run?.radarUrl === "string" && run.radarUrl.length > 0;
197
- }
198
-
199
- function CopyRunLink({
200
- radarUrl,
201
- visibility,
202
- }: {
203
- radarUrl: string;
204
- visibility: RunSummary["visibility"];
205
- }) {
206
- const label =
207
- visibility === "private"
208
- ? "Copy private link (only you can open it)"
209
- : "Copy investigation link";
210
- const [copyState, setCopyState] = useState<"idle" | "copied" | "error">(
211
- "idle",
212
- );
213
- const copy = async () => {
214
- try {
215
- if (!navigator.clipboard) throw new Error("clipboard unavailable");
216
- await navigator.clipboard.writeText(
217
- new URL(radarUrl, window.location.origin).href,
218
- );
219
- setCopyState("copied");
220
- } catch {
221
- setCopyState("error");
222
- }
223
- setTimeout(() => setCopyState("idle"), 1500);
224
- };
225
- return (
226
- <Tooltip
227
- content={
228
- copyState === "copied"
229
- ? "Link copied"
230
- : copyState === "error"
231
- ? "Couldn’t copy link"
232
- : label
233
- }
234
- position="bottom"
235
- >
236
- <button
237
- onClick={copy}
238
- className="rounded-md p-1 text-theme-text-tertiary hover:bg-theme-hover hover:text-theme-text-primary"
239
- aria-label={label}
240
- >
241
- {copyState === "copied" ? (
242
- <Check className="h-4 w-4 text-emerald-500" />
243
- ) : (
244
- <Link className="h-4 w-4" />
245
- )}
246
- </button>
247
- </Tooltip>
248
- );
249
- }
250
-
251
- function VisibilityControl({
252
- run,
253
- onChanged,
254
- }: {
255
- run: RunSummary;
256
- onChanged: (run: RunSummary) => void;
257
- }) {
258
- const [busy, setBusy] = useState(false);
259
- const [error, setError] = useState(false);
260
- const [confirmShare, setConfirmShare] = useState(false);
261
- if (!run.canManageVisibility) {
262
- return run.visibility === "organization" ? (
263
- <Tooltip content="Shared with your organization" position="bottom">
264
- <Badge severity="neutral" size="sm" className="shrink-0">
265
- <Users className="h-3 w-3" />
266
- Organization
267
- </Badge>
268
- </Tooltip>
269
- ) : run.visibility === "private" ? (
270
- <Tooltip
271
- content="Only you can view this investigation. Other organization members don’t have access."
272
- position="bottom"
273
- >
274
- <Badge severity="neutral" size="sm" className="shrink-0">
275
- <Lock className="h-3 w-3" />
276
- Private
277
- </Badge>
278
- </Tooltip>
279
- ) : null;
280
- }
281
- const shared = run.visibility === "organization";
282
- const update = () => {
283
- if (busy) return;
284
- setBusy(true);
285
- setError(false);
286
- updateRunVisibility(run.id, shared ? "private" : "organization")
287
- .then((updated) => {
288
- onChanged(updated);
289
- setConfirmShare(false);
290
- })
291
- .catch(() => setError(true))
292
- .finally(() => setBusy(false));
293
- };
294
- const label = shared ? "Organization" : "Private";
295
- return (
296
- <>
297
- <Tooltip
298
- content={
299
- error
300
- ? "Couldn't change sharing"
301
- : shared
302
- ? "Shared with your organization — make private"
303
- : "Private — click to let organization members access this investigation"
304
- }
305
- position="bottom"
306
- >
307
- <button
308
- onClick={() => (shared ? update() : setConfirmShare(true))}
309
- disabled={busy}
310
- className="flex items-center gap-1 rounded-md border border-theme-border/70 px-1.5 py-1 text-[11px] font-medium text-theme-text-secondary hover:bg-theme-hover hover:text-theme-text-primary disabled:opacity-50"
311
- aria-label={
312
- shared
313
- ? "Shared with your organization — make private"
314
- : "Private — click to let organization members access this investigation"
315
- }
316
- >
317
- {shared ? (
318
- <Users className="h-3.5 w-3.5" />
319
- ) : (
320
- <Lock className="h-3.5 w-3.5" />
321
- )}
322
- {label}
323
- </button>
324
- </Tooltip>
325
- <ConfirmDialog
326
- open={confirmShare}
327
- onClose={() => !busy && setConfirmShare(false)}
328
- onConfirm={update}
329
- title="Share this investigation?"
330
- message="Everyone in your organization can read this entire investigation—including your questions and the logs and manifests Radar read—and can continue or stop it."
331
- confirmLabel="Share with organization"
332
- showWarning={false}
333
- variant="warning"
334
- isLoading={busy}
335
- />
336
- </>
337
- );
338
- }
339
-
340
187
  // The panel is an ABSOLUTE slot inside the app's body frame (the column under the
341
188
  // header, right of the nav rail) — App renders it there and passes topInset (the
342
189
  // header height; 0 in chromeless embeds). It shares that frame with the resource/
@@ -443,37 +290,37 @@ function DiagnoseHeaderIdentity({
443
290
  onOpenSettings: (() => void) | null;
444
291
  }) {
445
292
  return (
446
- <div className={`min-w-0 ${className}`}>
447
- <div className="flex min-w-0 items-center gap-2">
448
- <div className="min-w-0 flex-1 truncate text-sm font-medium text-theme-text-primary">
293
+ <div className={`flex min-w-0 items-center gap-3 ${className}`}>
294
+ <div className="min-w-0 flex-1">
295
+ <div className="min-w-0 truncate text-sm font-medium text-theme-text-primary">
449
296
  {title}
450
297
  </div>
451
- {runMeta ? (
452
- <div
453
- className={`${MAXIMIZED_RUN_META_VISIBILITY_CLASS} shrink-0 items-center gap-1 text-[11px] tabular-nums text-theme-text-tertiary`}
454
- >
455
- <span className={`font-medium ${runMeta.labelClass}`}>
456
- {runMeta.label}
457
- </span>
458
- <span aria-hidden>·</span>
459
- <time dateTime={runMeta.dateTime}>{runMeta.time}</time>
460
- </div>
461
- ) : null}
462
- </div>
463
- <div className="flex items-center gap-1 text-xs text-theme-text-tertiary">
464
- <span className="truncate">{configLine}</span>
465
- {onOpenSettings && (
466
- <Tooltip content="AI settings" position="bottom">
467
- <button
468
- onClick={onOpenSettings}
469
- className="shrink-0 rounded p-0.5 text-theme-text-tertiary hover:text-theme-text-primary"
470
- aria-label="AI settings"
471
- >
472
- <Settings2 className="h-3 w-3" />
473
- </button>
474
- </Tooltip>
475
- )}
298
+ <div className="flex items-center gap-1 text-xs text-theme-text-tertiary">
299
+ <span className="truncate">{configLine}</span>
300
+ {onOpenSettings && (
301
+ <Tooltip content="AI settings" position="bottom">
302
+ <button
303
+ onClick={onOpenSettings}
304
+ className="shrink-0 rounded p-0.5 text-theme-text-tertiary hover:text-theme-text-primary"
305
+ aria-label="AI settings"
306
+ >
307
+ <Settings2 className="h-3 w-3" />
308
+ </button>
309
+ </Tooltip>
310
+ )}
311
+ </div>
476
312
  </div>
313
+ {runMeta ? (
314
+ <div
315
+ className={`${MAXIMIZED_RUN_META_VISIBILITY_CLASS} shrink-0 items-center gap-1 whitespace-nowrap text-[11px] tabular-nums text-theme-text-tertiary`}
316
+ >
317
+ <span className={`font-medium ${runMeta.labelClass}`}>
318
+ {runMeta.label}
319
+ </span>
320
+ <span aria-hidden>·</span>
321
+ <time dateTime={runMeta.dateTime}>{runMeta.time}</time>
322
+ </div>
323
+ ) : null}
477
324
  </div>
478
325
  );
479
326
  }
@@ -552,7 +399,7 @@ export function DiagnoseSurface({
552
399
  }, []);
553
400
  // Injected settings action: undefined = Radar's own Settings dialog;
554
401
  // null = hide the gear + links.
555
- const { consentCopy, onOpenSettings: hostOpenSettings } =
402
+ const { consentCopy, onOpenSettings: hostOpenSettings, renderRunActions } =
556
403
  useDiagnoseCustomization();
557
404
  const { embedded } = useNavCustomization();
558
405
  const openSettings =
@@ -838,7 +685,7 @@ export function DiagnoseSurface({
838
685
  )}
839
686
 
840
687
  {/* Header */}
841
- <div className="relative z-30 flex items-center justify-between border-b border-theme-border bg-theme-surface px-4 py-2.5">
688
+ <div className="relative z-30 flex items-center justify-between gap-3 border-b border-theme-border bg-theme-surface px-4 py-2.5">
842
689
  <div className="flex min-w-0 flex-1 items-center gap-2">
843
690
  {showHistory && (d.view !== "home" || !persistentHistory) ? (
844
691
  <Tooltip
@@ -893,7 +740,7 @@ export function DiagnoseSurface({
893
740
  )}
894
741
  </div>
895
742
  </div>
896
- <div className="flex shrink-0 items-center gap-0.5">
743
+ <div className="flex shrink-0 items-center gap-1">
897
744
  {activeRun &&
898
745
  canRerunInvestigation(d.view, activeRun, d.needsConsent) && (
899
746
  <Tooltip
@@ -922,17 +769,7 @@ export function DiagnoseSurface({
922
769
  <div
923
770
  className={`items-center gap-1 ${headerPresentation.runActionsClass || "flex"}`}
924
771
  >
925
- <VisibilityControl
926
- key={visibleRunDetail.id}
927
- run={visibleRunDetail}
928
- onChanged={d.updateRunSummary}
929
- />
930
- {canCopyRunLink(visibleRunDetail) && (
931
- <CopyRunLink
932
- radarUrl={visibleRunDetail.radarUrl}
933
- visibility={visibleRunDetail.visibility}
934
- />
935
- )}
772
+ {renderRunActions?.({ run: visibleRunDetail, onRunUpdated: d.updateRunSummary })}
936
773
  <InvestigationMenu run={visibleRunDetail} />
937
774
  </div>
938
775
  )}