@skyhook-io/radar-app 1.9.3 → 1.9.5
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 +1 -1
- package/src/App.tsx +26 -6
- package/src/api/client.ts +251 -0
- package/src/api/config.test.ts +19 -0
- package/src/components/CloudConnectFlow.tsx +605 -0
- package/src/components/CloudFunnelButton.tsx +499 -0
- package/src/components/ConnectionErrorView.tsx +2 -1
- package/src/components/UserMenu.tsx +3 -2
- package/src/components/audit/AuditView.tsx +13 -0
- package/src/components/audit/ChecksViewTabs.test.tsx +20 -0
- package/src/components/audit/ChecksViewTabs.tsx +43 -0
- package/src/components/audit/UpgradeReadinessView.test.ts +130 -0
- package/src/components/audit/UpgradeReadinessView.tsx +699 -0
- package/src/components/capacity/shared.tsx +9 -2
- package/src/components/diagnose/DiagnoseSurface.tsx +2 -1
- package/src/components/home/ClusterHealthCard.tsx +10 -5
- package/src/components/nav/PrimaryNavRail.tsx +4 -1
- package/src/components/resources/ImageFilesystemModal.tsx +4 -1
- package/src/components/settings/SettingsDialog.tsx +15 -6
- package/src/components/traffic/TrafficWizard.tsx +4 -2
- package/src/main.tsx +7 -1
- package/src/vite-env.d.ts +8 -0
|
@@ -1341,7 +1341,7 @@ export function EmptyState({
|
|
|
1341
1341
|
}: {
|
|
1342
1342
|
icon: ComponentType<{ className?: string }>;
|
|
1343
1343
|
title: string;
|
|
1344
|
-
detail:
|
|
1344
|
+
detail: ReactNode;
|
|
1345
1345
|
action?: ReactNode;
|
|
1346
1346
|
}) {
|
|
1347
1347
|
return (
|
|
@@ -1528,7 +1528,14 @@ export function integrationBlock(
|
|
|
1528
1528
|
<EmptyState
|
|
1529
1529
|
icon={Gauge}
|
|
1530
1530
|
title="Capacity needs a newer Radar"
|
|
1531
|
-
detail=
|
|
1531
|
+
detail={
|
|
1532
|
+
<>
|
|
1533
|
+
This cluster’s Radar predates the Capacity view (added in
|
|
1534
|
+
Radar v1.9.0).
|
|
1535
|
+
<br />
|
|
1536
|
+
Upgrade the in-cluster Radar to enable it.
|
|
1537
|
+
</>
|
|
1538
|
+
}
|
|
1532
1539
|
/>
|
|
1533
1540
|
);
|
|
1534
1541
|
return (
|
|
@@ -30,6 +30,7 @@ import { AgentSetupNotice } from "./AgentSetupNotice";
|
|
|
30
30
|
import { ConsentCard } from "./parts";
|
|
31
31
|
import { buildLaunchCommand, launchAgentLabel, openInTerminal } from "./launch";
|
|
32
32
|
import { type RunSummary, type ExecutionProfile } from "../../api/diagnose";
|
|
33
|
+
import { routePath } from "../../api/config";
|
|
33
34
|
|
|
34
35
|
function capWord(s: string): string {
|
|
35
36
|
return s ? s[0].toUpperCase() + s.slice(1) : s;
|
|
@@ -66,7 +67,7 @@ function InvestigationMenu({ run }: { run: RunSummary }) {
|
|
|
66
67
|
const [open, setOpen] = useState(false);
|
|
67
68
|
const [copied, setCopied] = useState(false);
|
|
68
69
|
const label = launchAgentLabel(run);
|
|
69
|
-
const command = buildLaunchCommand(run, `${window.location.origin}/mcp`);
|
|
70
|
+
const command = buildLaunchCommand(run, `${window.location.origin}${routePath('/mcp')}`);
|
|
70
71
|
// No resumable session yet (or stale run) → nothing to hand off.
|
|
71
72
|
if (!command) return null;
|
|
72
73
|
|
|
@@ -10,12 +10,17 @@ import { clsx } from 'clsx'
|
|
|
10
10
|
import { formatCPUMillicores, formatMemoryMiB } from '../../utils/format'
|
|
11
11
|
import { useCapabilitiesContext } from '../../contexts/CapabilitiesContext'
|
|
12
12
|
import { MCPSetupDialog } from './MCPSetupDialog'
|
|
13
|
-
import { pluralize, parseContextName } from '@skyhook-io/k8s-ui'
|
|
13
|
+
import { assetUrl, pluralize, parseContextName } from '@skyhook-io/k8s-ui'
|
|
14
14
|
import { Tooltip } from '../ui/Tooltip'
|
|
15
|
+
import { routePath } from '../../api/config'
|
|
15
16
|
import gkeIcon from '../../assets/platform-icons/google_kubernetes_engine.png'
|
|
16
17
|
import eksIcon from '../../assets/platform-icons/aws_eks.png'
|
|
17
18
|
import aksIcon from '../../assets/platform-icons/azure-aks.svg'
|
|
18
19
|
|
|
20
|
+
const gkeIconUrl = assetUrl(gkeIcon)
|
|
21
|
+
const eksIconUrl = assetUrl(eksIcon)
|
|
22
|
+
const aksIconUrl = assetUrl(aksIcon)
|
|
23
|
+
|
|
19
24
|
interface ClusterHealthCardProps {
|
|
20
25
|
health: DashboardResponse['health']
|
|
21
26
|
counts: DashboardResponse['resourceCounts']
|
|
@@ -74,13 +79,13 @@ function MetricsUnavailableHint({ platform, metricsServerAvailable }: { platform
|
|
|
74
79
|
function getPlatformInfo(platform: string): { name: string; icon: string | null } {
|
|
75
80
|
const platformLower = platform.toLowerCase()
|
|
76
81
|
if (platformLower.includes('gke') || platformLower.includes('google')) {
|
|
77
|
-
return { name: 'Google Kubernetes Engine', icon:
|
|
82
|
+
return { name: 'Google Kubernetes Engine', icon: gkeIconUrl }
|
|
78
83
|
}
|
|
79
84
|
if (platformLower.includes('eks') || platformLower.includes('amazon') || platformLower.includes('aws')) {
|
|
80
|
-
return { name: 'Amazon EKS', icon:
|
|
85
|
+
return { name: 'Amazon EKS', icon: eksIconUrl }
|
|
81
86
|
}
|
|
82
87
|
if (platformLower.includes('aks') || platformLower.includes('azure')) {
|
|
83
|
-
return { name: 'Azure Kubernetes Service', icon:
|
|
88
|
+
return { name: 'Azure Kubernetes Service', icon: aksIconUrl }
|
|
84
89
|
}
|
|
85
90
|
if (platformLower.includes('openshift')) {
|
|
86
91
|
return { name: 'OpenShift', icon: null }
|
|
@@ -138,7 +143,7 @@ export function ClusterHealthCard({
|
|
|
138
143
|
const mcpEnabled = caps.mcpEnabled
|
|
139
144
|
const isCloud = deployment.mode === 'cloud'
|
|
140
145
|
const isInCluster = deployment.mode === 'in-cluster' || deployment.mode === 'cloud'
|
|
141
|
-
const mcpUrl = `${window.location.origin}/mcp`
|
|
146
|
+
const mcpUrl = `${window.location.origin}${routePath('/mcp')}`
|
|
142
147
|
// In Cloud, MCP is org-wide and PAT-authed (api.radarhq.io/mcp). The OSS
|
|
143
148
|
// "this binary is your local MCP server" framing is wrong there — Cloud
|
|
144
149
|
// surfaces MCP from the hub Home dashboard instead.
|
|
@@ -20,6 +20,9 @@ import {
|
|
|
20
20
|
import { clsx } from "clsx";
|
|
21
21
|
import type { MainView } from "../../types";
|
|
22
22
|
import { Tooltip } from "../ui/Tooltip";
|
|
23
|
+
import { assetUrl } from "@skyhook-io/k8s-ui";
|
|
24
|
+
|
|
25
|
+
const radarLogoUrl = assetUrl("/images/radar/radar-icon.svg");
|
|
23
26
|
|
|
24
27
|
// The views the rail can navigate to. Broader than k8s-ui's ExtendedMainView
|
|
25
28
|
// (which omits 'applications') — it mirrors the navigable subset of App.tsx's
|
|
@@ -233,7 +236,7 @@ function BrandRow({
|
|
|
233
236
|
<span className="flex w-14 shrink-0 items-center justify-center">
|
|
234
237
|
<span className="relative w-7 h-7 rounded-lg overflow-hidden bg-emerald-500/10 border border-emerald-500/20">
|
|
235
238
|
<img
|
|
236
|
-
src=
|
|
239
|
+
src={radarLogoUrl}
|
|
237
240
|
alt=""
|
|
238
241
|
aria-hidden
|
|
239
242
|
className="w-full h-full p-0.5"
|
|
@@ -2,6 +2,7 @@ import { useState, useRef, useEffect, useMemo, useCallback } from 'react'
|
|
|
2
2
|
import { createPortal } from 'react-dom'
|
|
3
3
|
import { X, Folder, File, Link2, ChevronRight, ChevronDown, AlertTriangle, Loader2, Search, Download, HardDrive, Shield, ShieldCheck, Terminal, Copy, Check, RefreshCw } from 'lucide-react'
|
|
4
4
|
import radarLoadingIcon from '@skyhook-io/k8s-ui/assets/radar/radar-icon-loading.svg'
|
|
5
|
+
import { assetUrl } from '@skyhook-io/k8s-ui'
|
|
5
6
|
import { clsx } from 'clsx'
|
|
6
7
|
import { useImageMetadata, ApiError } from '../../api/client'
|
|
7
8
|
import type { FileNode, ImageFilesystem } from '../../types'
|
|
@@ -11,6 +12,8 @@ import { Tooltip } from '../ui/Tooltip'
|
|
|
11
12
|
import { apiUrl, getAuthHeaders, getCredentialsMode } from '../../api/config'
|
|
12
13
|
import { Input } from '@skyhook-io/k8s-ui'
|
|
13
14
|
|
|
15
|
+
const radarLoadingIconUrl = assetUrl(radarLoadingIcon)
|
|
16
|
+
|
|
14
17
|
// Manual fetch function for filesystem (not a hook - gives us full control)
|
|
15
18
|
async function fetchImageFilesystem(
|
|
16
19
|
image: string,
|
|
@@ -182,7 +185,7 @@ export function ImageFilesystemModal({
|
|
|
182
185
|
{/* Loading state */}
|
|
183
186
|
{isLoading && (
|
|
184
187
|
<div className="flex flex-col items-center justify-center gap-3 h-64">
|
|
185
|
-
<img src={
|
|
188
|
+
<img src={radarLoadingIconUrl} alt="" aria-hidden className="w-11 h-11" />
|
|
186
189
|
<span className="text-sm text-theme-text-secondary">
|
|
187
190
|
{isLoadingMetadata ? 'Checking image…' : 'Downloading image layers…'}
|
|
188
191
|
</span>
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
import { clsx } from 'clsx'
|
|
10
10
|
import { useAnimatedUnmount } from '../../hooks/useAnimatedUnmount'
|
|
11
11
|
import { TRANSITION_BACKDROP, TRANSITION_PANEL } from '../../utils/animation'
|
|
12
|
-
import { apiUrl, getAuthHeaders, getCredentialsMode } from '../../api/config'
|
|
12
|
+
import { apiUrl, getAuthHeaders, getCredentialsMode, routePath } from '../../api/config'
|
|
13
13
|
import {
|
|
14
14
|
useCloudRole, useVersionCheck, useClusterInfo, usePrometheusStatus, useArgoStatus,
|
|
15
15
|
} from '../../api/client'
|
|
@@ -20,6 +20,14 @@ import { AISettingsSection, type AIDraft } from '../diagnose/AISettings'
|
|
|
20
20
|
import { MyPermissionsContent } from './MyPermissionsDialog'
|
|
21
21
|
import { useDiagnose } from '../diagnose/DiagnoseContext'
|
|
22
22
|
|
|
23
|
+
// The loopback URL an MCP client is told to connect to. Shared by the overview
|
|
24
|
+
// row and the MCP section: both must carry the base path, or the URL they
|
|
25
|
+
// advertise 404s under a subpath deployment.
|
|
26
|
+
function mcpLoopbackUrl(): string {
|
|
27
|
+
const port = Number(window.location.port) || 80
|
|
28
|
+
return `http://localhost:${port}${routePath('/mcp')}`
|
|
29
|
+
}
|
|
30
|
+
|
|
23
31
|
interface Config {
|
|
24
32
|
kubeconfig?: string
|
|
25
33
|
kubeconfigDirs?: string[]
|
|
@@ -842,8 +850,7 @@ function OverviewPanel({ active, onNavigate }: { active: boolean; onNavigate: (s
|
|
|
842
850
|
const agentLabel =
|
|
843
851
|
diag.agents.find((a) => a.name === diag.selectedAgent)?.label ?? diag.agents[0]?.label
|
|
844
852
|
const mcpOn = capabilities.mcpEnabled
|
|
845
|
-
const
|
|
846
|
-
const mcpUrl = `http://localhost:${port}/mcp`
|
|
853
|
+
const mcpUrl = mcpLoopbackUrl()
|
|
847
854
|
|
|
848
855
|
const rows: OverviewRow[] = [
|
|
849
856
|
{
|
|
@@ -964,8 +971,10 @@ function AIUnavailableNotice() {
|
|
|
964
971
|
<div className="rounded-md border border-theme-border bg-theme-elevated/50 p-3">
|
|
965
972
|
<p className="text-sm font-medium text-theme-text-primary">No supported agent CLI found</p>
|
|
966
973
|
<p className="mt-1 text-xs text-theme-text-tertiary">
|
|
967
|
-
Install <span className="text-theme-text-secondary">Claude Code</span
|
|
968
|
-
<span className="text-theme-text-secondary">Codex</span>,
|
|
974
|
+
Install <span className="text-theme-text-secondary">Claude Code</span>,{' '}
|
|
975
|
+
<span className="text-theme-text-secondary">Codex</span>, or{' '}
|
|
976
|
+
<span className="text-theme-text-secondary">Cursor</span> (
|
|
977
|
+
<span className="font-mono">cursor-agent</span>), then restart Radar — this tab
|
|
969
978
|
will show the agent, model, and effort controls.
|
|
970
979
|
</p>
|
|
971
980
|
</div>
|
|
@@ -1117,7 +1126,7 @@ function MCPSection({
|
|
|
1117
1126
|
const [copied, setCopied] = useState(false)
|
|
1118
1127
|
|
|
1119
1128
|
const currentPort = Number(window.location.port) || 80
|
|
1120
|
-
const mcpUrl =
|
|
1129
|
+
const mcpUrl = mcpLoopbackUrl()
|
|
1121
1130
|
|
|
1122
1131
|
const handleCopy = () => {
|
|
1123
1132
|
navigator.clipboard.writeText(mcpUrl)
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { useState, useEffect } from 'react'
|
|
2
2
|
import type { TrafficSourcesResponse, TrafficWizardState } from '../../types'
|
|
3
3
|
import { CheckCircle2, XCircle, AlertTriangle, Copy, ExternalLink, ArrowRight, ArrowLeft, Package } from 'lucide-react'
|
|
4
|
-
import { PaneLoader } from '@skyhook-io/k8s-ui'
|
|
4
|
+
import { assetUrl, PaneLoader } from '@skyhook-io/k8s-ui'
|
|
5
5
|
import radarLoadingIcon from '@skyhook-io/k8s-ui/assets/radar/radar-icon-loading.svg'
|
|
6
6
|
import { InstallWizard } from '../helm/InstallWizard'
|
|
7
7
|
|
|
8
|
+
const radarLoadingIconUrl = assetUrl(radarLoadingIcon)
|
|
9
|
+
|
|
8
10
|
interface TrafficWizardProps {
|
|
9
11
|
state: TrafficWizardState
|
|
10
12
|
setState: (state: TrafficWizardState) => void
|
|
@@ -100,7 +102,7 @@ export function TrafficWizard({
|
|
|
100
102
|
<div className="flex items-center justify-center h-full w-full">
|
|
101
103
|
<div className="max-w-md w-full p-6 space-y-6">
|
|
102
104
|
<div className="flex flex-col items-center gap-3">
|
|
103
|
-
<img src={
|
|
105
|
+
<img src={radarLoadingIconUrl} alt="" aria-hidden className="h-11 w-11" />
|
|
104
106
|
<h2 className="text-lg font-medium text-theme-text-primary">Waiting for traffic source…</h2>
|
|
105
107
|
<p className="text-sm text-theme-text-secondary">
|
|
106
108
|
Checking for availability
|
package/src/main.tsx
CHANGED
|
@@ -153,8 +153,14 @@ window.addEventListener('mouseup', (e: MouseEvent) => {
|
|
|
153
153
|
// tab, so it opts into per-view document.title. Library consumers (e.g.
|
|
154
154
|
// radar-hub-web) render <RadarApp apiBase="..." basename="..." /> WITHOUT this
|
|
155
155
|
// flag, keeping their own tab title.
|
|
156
|
+
const runtimeConfig = window.__RADAR_RUNTIME_CONFIG__
|
|
157
|
+
|
|
156
158
|
ReactDOM.createRoot(document.getElementById('radar')!).render(
|
|
157
159
|
<React.StrictMode>
|
|
158
|
-
<RadarApp
|
|
160
|
+
<RadarApp
|
|
161
|
+
apiBase={runtimeConfig?.apiBase}
|
|
162
|
+
basename={runtimeConfig?.basePath}
|
|
163
|
+
manageDocumentTitle
|
|
164
|
+
/>
|
|
159
165
|
</React.StrictMode>
|
|
160
166
|
)
|