@skyhook-io/radar-app 0.1.1
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/README.md +67 -0
- package/package.json +80 -0
- package/src/App.tsx +1538 -0
- package/src/RadarApp.tsx +145 -0
- package/src/api/apiResources.ts +28 -0
- package/src/api/client.ts +2583 -0
- package/src/api/config.ts +116 -0
- package/src/api/traffic.ts +139 -0
- package/src/components/ConnectionErrorView.tsx +272 -0
- package/src/components/ContextSwitcher.tsx +481 -0
- package/src/components/DebugOverlay.tsx +94 -0
- package/src/components/UserMenu.tsx +87 -0
- package/src/components/audit/AuditSettingsDialog.tsx +162 -0
- package/src/components/audit/AuditView.tsx +123 -0
- package/src/components/cost/CostTrendChart.tsx +388 -0
- package/src/components/cost/CostView.tsx +545 -0
- package/src/components/dock/BottomDock.tsx +96 -0
- package/src/components/dock/DockContext.tsx +11 -0
- package/src/components/dock/LocalTerminalTab.tsx +22 -0
- package/src/components/dock/LogsTab.tsx +26 -0
- package/src/components/dock/NodeTerminalTab.tsx +50 -0
- package/src/components/dock/TerminalTab.tsx +42 -0
- package/src/components/dock/TrafficFlowListTab.tsx +18 -0
- package/src/components/dock/WorkloadLogsTab.tsx +23 -0
- package/src/components/dock/index.ts +2 -0
- package/src/components/gitops/GitOpsActions.tsx +1 -0
- package/src/components/gitops/GitOpsStatusBadge.tsx +1 -0
- package/src/components/gitops/ManagedResourcesList.tsx +1 -0
- package/src/components/gitops/SyncCountdown.tsx +1 -0
- package/src/components/gitops/index.ts +4 -0
- package/src/components/helm/ChartBrowser.tsx +580 -0
- package/src/components/helm/HelmReleaseDrawer.tsx +774 -0
- package/src/components/helm/HelmView.tsx +475 -0
- package/src/components/helm/InstallWizard.tsx +1060 -0
- package/src/components/helm/ManifestDiffViewer.tsx +91 -0
- package/src/components/helm/ManifestViewer.tsx +61 -0
- package/src/components/helm/OwnedResources.tsx +465 -0
- package/src/components/helm/RevisionHistory.tsx +167 -0
- package/src/components/helm/ValuesDiffPreview.tsx +190 -0
- package/src/components/helm/ValuesViewer.tsx +365 -0
- package/src/components/helm/helm-utils.ts +37 -0
- package/src/components/home/ActivitySummary.tsx +262 -0
- package/src/components/home/CertificateHealthCard.tsx +105 -0
- package/src/components/home/ClusterHealthCard.tsx +483 -0
- package/src/components/home/CostCard.tsx +112 -0
- package/src/components/home/HealthRing.tsx +1 -0
- package/src/components/home/HelmSummary.tsx +129 -0
- package/src/components/home/HomeView.tsx +224 -0
- package/src/components/home/MCPSetupDialog.tsx +417 -0
- package/src/components/home/NetworkPolicyCoverageCard.tsx +109 -0
- package/src/components/home/TopologyPreview.tsx +219 -0
- package/src/components/home/TrafficSummary.tsx +154 -0
- package/src/components/logs/JsonLogLine.tsx +1 -0
- package/src/components/logs/LogCore.tsx +2 -0
- package/src/components/logs/LogsViewer.tsx +44 -0
- package/src/components/logs/WorkloadLogsViewer.tsx +40 -0
- package/src/components/logs/useLogBuffer.ts +2 -0
- package/src/components/logs/useLogSearch.ts +1 -0
- package/src/components/portforward/PortForwardButton.tsx +375 -0
- package/src/components/portforward/PortForwardManager.tsx +871 -0
- package/src/components/resource/PrometheusCharts.tsx +687 -0
- package/src/components/resource-drawer/ResourceDrawer.tsx +214 -0
- package/src/components/resources/ImageFilesystemModal.tsx +745 -0
- package/src/components/resources/PodFilesystemModal.tsx +407 -0
- package/src/components/resources/ResourceDetailDrawer.tsx +43 -0
- package/src/components/resources/ResourcesView.tsx +190 -0
- package/src/components/resources/drawer-components.tsx +1 -0
- package/src/components/resources/file-browser-utils.ts +35 -0
- package/src/components/resources/renderers/AlertRenderer.tsx +1 -0
- package/src/components/resources/renderers/ArgoApplicationRenderer.tsx +17 -0
- package/src/components/resources/renderers/CNPGBackupRenderer.tsx +1 -0
- package/src/components/resources/renderers/CNPGClusterRenderer.tsx +1 -0
- package/src/components/resources/renderers/CNPGPoolerRenderer.tsx +1 -0
- package/src/components/resources/renderers/CNPGScheduledBackupRenderer.tsx +1 -0
- package/src/components/resources/renderers/CertificateRenderer.tsx +1 -0
- package/src/components/resources/renderers/CertificateRequestRenderer.tsx +1 -0
- package/src/components/resources/renderers/ChallengeRenderer.tsx +1 -0
- package/src/components/resources/renderers/ClusterComplianceReportRenderer.tsx +1 -0
- package/src/components/resources/renderers/ClusterExternalSecretRenderer.tsx +1 -0
- package/src/components/resources/renderers/ClusterIssuerRenderer.tsx +1 -0
- package/src/components/resources/renderers/ConfigAuditReportRenderer.tsx +1 -0
- package/src/components/resources/renderers/ConfigMapRenderer.tsx +1 -0
- package/src/components/resources/renderers/CronJobRenderer.tsx +1 -0
- package/src/components/resources/renderers/EventRenderer.tsx +1 -0
- package/src/components/resources/renderers/ExposedSecretReportRenderer.tsx +1 -0
- package/src/components/resources/renderers/ExternalSecretRenderer.tsx +1 -0
- package/src/components/resources/renderers/FluxHelmReleaseRenderer.tsx +1 -0
- package/src/components/resources/renderers/GRPCRouteRenderer.tsx +1 -0
- package/src/components/resources/renderers/GatewayClassRenderer.tsx +1 -0
- package/src/components/resources/renderers/GatewayRenderer.tsx +1 -0
- package/src/components/resources/renderers/GenericRenderer.tsx +1 -0
- package/src/components/resources/renderers/GitRepositoryRenderer.tsx +1 -0
- package/src/components/resources/renderers/HPARenderer.tsx +1 -0
- package/src/components/resources/renderers/HTTPRouteRenderer.tsx +1 -0
- package/src/components/resources/renderers/HelmRepositoryRenderer.tsx +1 -0
- package/src/components/resources/renderers/IngressClassRenderer.tsx +1 -0
- package/src/components/resources/renderers/IngressRenderer.tsx +1 -0
- package/src/components/resources/renderers/IstioAuthorizationPolicyRenderer.tsx +1 -0
- package/src/components/resources/renderers/IstioDestinationRuleRenderer.tsx +1 -0
- package/src/components/resources/renderers/IstioGatewayRenderer.tsx +1 -0
- package/src/components/resources/renderers/IstioPeerAuthenticationRenderer.tsx +1 -0
- package/src/components/resources/renderers/IstioServiceEntryRenderer.tsx +1 -0
- package/src/components/resources/renderers/IstioVirtualServiceRenderer.tsx +1 -0
- package/src/components/resources/renderers/JobRenderer.tsx +1 -0
- package/src/components/resources/renderers/KarpenterEC2NodeClassRenderer.tsx +1 -0
- package/src/components/resources/renderers/KarpenterNodeClaimRenderer.tsx +1 -0
- package/src/components/resources/renderers/KarpenterNodePoolRenderer.tsx +1 -0
- package/src/components/resources/renderers/KedaScaledJobRenderer.tsx +1 -0
- package/src/components/resources/renderers/KedaScaledObjectRenderer.tsx +1 -0
- package/src/components/resources/renderers/KedaTriggerAuthRenderer.tsx +1 -0
- package/src/components/resources/renderers/KnativeConfigurationRenderer.tsx +1 -0
- package/src/components/resources/renderers/KnativeEventingRenderer.tsx +1 -0
- package/src/components/resources/renderers/KnativeFlowRenderer.tsx +1 -0
- package/src/components/resources/renderers/KnativeNetworkingRenderer.tsx +1 -0
- package/src/components/resources/renderers/KnativeRevisionRenderer.tsx +1 -0
- package/src/components/resources/renderers/KnativeRouteRenderer.tsx +1 -0
- package/src/components/resources/renderers/KnativeServiceRenderer.tsx +1 -0
- package/src/components/resources/renderers/KnativeSourceRenderer.tsx +1 -0
- package/src/components/resources/renderers/KustomizationRenderer.tsx +1 -0
- package/src/components/resources/renderers/KyvernoPolicyReportRenderer.tsx +1 -0
- package/src/components/resources/renderers/LeaseRenderer.tsx +1 -0
- package/src/components/resources/renderers/NetworkPolicyRenderer.tsx +1 -0
- package/src/components/resources/renderers/NodeRenderer.tsx +44 -0
- package/src/components/resources/renderers/OCIRepositoryRenderer.tsx +1 -0
- package/src/components/resources/renderers/OrderRenderer.tsx +1 -0
- package/src/components/resources/renderers/PVCRenderer.tsx +1 -0
- package/src/components/resources/renderers/PersistentVolumeRenderer.tsx +1 -0
- package/src/components/resources/renderers/PodDisruptionBudgetRenderer.tsx +1 -0
- package/src/components/resources/renderers/PodMonitorRenderer.tsx +1 -0
- package/src/components/resources/renderers/PodRenderer.tsx +94 -0
- package/src/components/resources/renderers/PriorityClassRenderer.tsx +1 -0
- package/src/components/resources/renderers/PrometheusRuleRenderer.tsx +1 -0
- package/src/components/resources/renderers/ReplicaSetRenderer.tsx +1 -0
- package/src/components/resources/renderers/RoleBindingRenderer.tsx +1 -0
- package/src/components/resources/renderers/RoleRenderer.tsx +1 -0
- package/src/components/resources/renderers/RolloutRenderer.tsx +1 -0
- package/src/components/resources/renderers/RuntimeClassRenderer.tsx +1 -0
- package/src/components/resources/renderers/SbomReportRenderer.tsx +1 -0
- package/src/components/resources/renderers/SealedSecretRenderer.tsx +1 -0
- package/src/components/resources/renderers/SecretRenderer.tsx +1 -0
- package/src/components/resources/renderers/SecretStoreRenderer.tsx +1 -0
- package/src/components/resources/renderers/ServiceAccountRenderer.tsx +1 -0
- package/src/components/resources/renderers/ServiceMonitorRenderer.tsx +1 -0
- package/src/components/resources/renderers/ServiceRenderer.tsx +26 -0
- package/src/components/resources/renderers/SimpleRouteRenderer.tsx +1 -0
- package/src/components/resources/renderers/StorageClassRenderer.tsx +1 -0
- package/src/components/resources/renderers/TraefikIngressRouteRenderer.tsx +1 -0
- package/src/components/resources/renderers/VPARenderer.tsx +1 -0
- package/src/components/resources/renderers/VeleroBSLRenderer.tsx +1 -0
- package/src/components/resources/renderers/VeleroBackupRenderer.tsx +1 -0
- package/src/components/resources/renderers/VeleroRestoreRenderer.tsx +1 -0
- package/src/components/resources/renderers/VeleroScheduleRenderer.tsx +1 -0
- package/src/components/resources/renderers/VeleroVSLRenderer.tsx +1 -0
- package/src/components/resources/renderers/VulnerabilityReportRenderer.tsx +1 -0
- package/src/components/resources/renderers/WebhookConfigRenderer.tsx +1 -0
- package/src/components/resources/renderers/WorkflowRenderer.tsx +1 -0
- package/src/components/resources/renderers/WorkflowTemplateRenderer.tsx +1 -0
- package/src/components/resources/renderers/WorkloadRenderer.tsx +52 -0
- package/src/components/resources/renderers/argo-cells.tsx +1 -0
- package/src/components/resources/renderers/certmanager-cells.tsx +1 -0
- package/src/components/resources/renderers/cnpg-cells.tsx +1 -0
- package/src/components/resources/renderers/eso-cells.tsx +1 -0
- package/src/components/resources/renderers/flux-cells.tsx +1 -0
- package/src/components/resources/renderers/index.ts +91 -0
- package/src/components/resources/renderers/istio-cells.tsx +1 -0
- package/src/components/resources/renderers/karpenter-cells.tsx +1 -0
- package/src/components/resources/renderers/keda-cells.tsx +1 -0
- package/src/components/resources/renderers/knative-cells.tsx +1 -0
- package/src/components/resources/renderers/kyverno-cells.tsx +1 -0
- package/src/components/resources/renderers/prometheus-cells.tsx +1 -0
- package/src/components/resources/renderers/traefik-cells.tsx +1 -0
- package/src/components/resources/renderers/trivy-cells.tsx +1 -0
- package/src/components/resources/renderers/trivy-shared.tsx +1 -0
- package/src/components/resources/renderers/velero-cells.tsx +1 -0
- package/src/components/resources/resource-utils-argo.ts +2 -0
- package/src/components/resources/resource-utils-certmanager.ts +2 -0
- package/src/components/resources/resource-utils-cnpg.ts +2 -0
- package/src/components/resources/resource-utils-eso.ts +2 -0
- package/src/components/resources/resource-utils-flux.ts +2 -0
- package/src/components/resources/resource-utils-istio.ts +2 -0
- package/src/components/resources/resource-utils-karpenter.ts +2 -0
- package/src/components/resources/resource-utils-keda.ts +2 -0
- package/src/components/resources/resource-utils-knative.ts +2 -0
- package/src/components/resources/resource-utils-kyverno.ts +2 -0
- package/src/components/resources/resource-utils-prometheus.ts +2 -0
- package/src/components/resources/resource-utils-traefik.ts +1 -0
- package/src/components/resources/resource-utils-trivy.ts +2 -0
- package/src/components/resources/resource-utils-velero.ts +2 -0
- package/src/components/resources/resource-utils.ts +5 -0
- package/src/components/settings/SettingsDialog.tsx +537 -0
- package/src/components/shared/CreateResourceDialog.tsx +17 -0
- package/src/components/shared/EditableYamlView.tsx +24 -0
- package/src/components/shared/LargeClusterNamespacePicker.tsx +70 -0
- package/src/components/shared/ResourceRendererDispatch.tsx +31 -0
- package/src/components/timeline/DiffViewer.tsx +1 -0
- package/src/components/timeline/TimelineList.tsx +69 -0
- package/src/components/timeline/TimelineSwimlanes.tsx +1308 -0
- package/src/components/timeline/TimelineView.tsx +157 -0
- package/src/components/timeline/shared.tsx +1 -0
- package/src/components/traffic/TrafficFilterSidebar.tsx +571 -0
- package/src/components/traffic/TrafficFlowList.tsx +415 -0
- package/src/components/traffic/TrafficFlowListContext.tsx +68 -0
- package/src/components/traffic/TrafficGraph.tsx +1546 -0
- package/src/components/traffic/TrafficView.tsx +1213 -0
- package/src/components/traffic/TrafficWizard.tsx +386 -0
- package/src/components/traffic/index.ts +3 -0
- package/src/components/ui/CodeViewer.tsx +8 -0
- package/src/components/ui/CommandPalette.tsx +460 -0
- package/src/components/ui/ConfirmDialog.tsx +1 -0
- package/src/components/ui/DiagnosticsOverlay.tsx +619 -0
- package/src/components/ui/ErrorBoundary.tsx +46 -0
- package/src/components/ui/ForceDeleteConfirmDialog.tsx +1 -0
- package/src/components/ui/Markdown.tsx +108 -0
- package/src/components/ui/MetricsChart.tsx +1 -0
- package/src/components/ui/NamespaceSelector.tsx +436 -0
- package/src/components/ui/ResourceBar.tsx +1 -0
- package/src/components/ui/ShortcutHelpOverlay.tsx +301 -0
- package/src/components/ui/Toast.tsx +1 -0
- package/src/components/ui/Tooltip.tsx +1 -0
- package/src/components/ui/UpdateNotification.tsx +299 -0
- package/src/components/ui/YamlEditor.tsx +1 -0
- package/src/components/workload/WorkloadView.tsx +532 -0
- package/src/context/ConnectionContext.tsx +173 -0
- package/src/context/ContextSwitchContext.tsx +56 -0
- package/src/context/NavCustomization.tsx +62 -0
- package/src/context/ThemeContext.tsx +97 -0
- package/src/contexts/CapabilitiesContext.tsx +130 -0
- package/src/hooks/useAnimatedUnmount.ts +1 -0
- package/src/hooks/useDesktopDownload.ts +41 -0
- package/src/hooks/useEventSource.ts +262 -0
- package/src/hooks/useFavorites.ts +69 -0
- package/src/hooks/useKeyboardShortcuts.tsx +7 -0
- package/src/hooks/useRefreshAnimation.ts +1 -0
- package/src/index.css +243 -0
- package/src/index.ts +17 -0
- package/src/main.tsx +158 -0
- package/src/types/gitops.ts +2 -0
- package/src/types.ts +3 -0
- package/src/utils/animation.ts +2 -0
- package/src/utils/badge-colors.ts +2 -0
- package/src/utils/context-name.ts +2 -0
- package/src/utils/desktop-download.ts +66 -0
- package/src/utils/desktop-open-folder.ts +21 -0
- package/src/utils/format.ts +2 -0
- package/src/utils/log-format.ts +12 -0
- package/src/utils/navigation.ts +23 -0
- package/src/utils/resource-hierarchy.ts +2 -0
- package/src/utils/resource-icons.ts +2 -0
- package/src/utils/skeleton-yaml.ts +2 -0
- package/src/utils/traffic-colors.ts +54 -0
- package/src/vite-env.d.ts +1 -0
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react'
|
|
2
|
+
import type { TrafficSourcesResponse, TrafficWizardState } from '../../types'
|
|
3
|
+
import { Loader2, CheckCircle2, XCircle, AlertTriangle, Copy, ExternalLink, ArrowRight, ArrowLeft, Package } from 'lucide-react'
|
|
4
|
+
import { InstallWizard } from '../helm/InstallWizard'
|
|
5
|
+
|
|
6
|
+
interface TrafficWizardProps {
|
|
7
|
+
state: TrafficWizardState
|
|
8
|
+
setState: (state: TrafficWizardState) => void
|
|
9
|
+
sourcesData?: TrafficSourcesResponse
|
|
10
|
+
sourcesLoading: boolean
|
|
11
|
+
onRefetch: () => void
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function TrafficWizard({
|
|
15
|
+
state,
|
|
16
|
+
setState,
|
|
17
|
+
sourcesData,
|
|
18
|
+
sourcesLoading,
|
|
19
|
+
onRefetch,
|
|
20
|
+
}: TrafficWizardProps) {
|
|
21
|
+
const [step, setStep] = useState<'choice' | 'install'>('choice')
|
|
22
|
+
const [copied, setCopied] = useState(false)
|
|
23
|
+
const [lastChecked, setLastChecked] = useState<Date | null>(null)
|
|
24
|
+
const [showHelmInstall, setShowHelmInstall] = useState(false)
|
|
25
|
+
|
|
26
|
+
const cluster = sourcesData?.cluster
|
|
27
|
+
const recommendation = sourcesData?.recommended
|
|
28
|
+
const helmChart = recommendation?.helmChart
|
|
29
|
+
|
|
30
|
+
// Auto-check when in 'checking' state
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (state !== 'checking') return
|
|
33
|
+
|
|
34
|
+
// Initial check
|
|
35
|
+
onRefetch()
|
|
36
|
+
setLastChecked(new Date())
|
|
37
|
+
|
|
38
|
+
const interval = setInterval(() => {
|
|
39
|
+
onRefetch()
|
|
40
|
+
setLastChecked(new Date())
|
|
41
|
+
}, 30000) // Check every 30 seconds
|
|
42
|
+
|
|
43
|
+
return () => clearInterval(interval)
|
|
44
|
+
}, [state, onRefetch])
|
|
45
|
+
|
|
46
|
+
// Format relative time
|
|
47
|
+
const formatLastChecked = (date: Date | null): string => {
|
|
48
|
+
if (!date) return 'never'
|
|
49
|
+
const seconds = Math.floor((Date.now() - date.getTime()) / 1000)
|
|
50
|
+
if (seconds < 5) return 'just now'
|
|
51
|
+
if (seconds < 60) return `${seconds}s ago`
|
|
52
|
+
const minutes = Math.floor(seconds / 60)
|
|
53
|
+
return `${minutes}m ${seconds % 60}s ago`
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Update display every second when checking
|
|
57
|
+
const [, setTick] = useState(0)
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (state !== 'checking') return
|
|
60
|
+
const interval = setInterval(() => setTick(t => t + 1), 1000)
|
|
61
|
+
return () => clearInterval(interval)
|
|
62
|
+
}, [state])
|
|
63
|
+
|
|
64
|
+
// Copy command to clipboard
|
|
65
|
+
const copyCommand = (command: string) => {
|
|
66
|
+
navigator.clipboard.writeText(command)
|
|
67
|
+
setCopied(true)
|
|
68
|
+
setTimeout(() => setCopied(false), 2000)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Render Helm InstallWizard as overlay if shown
|
|
72
|
+
const helmInstallOverlay = showHelmInstall && helmChart ? (
|
|
73
|
+
<InstallWizard
|
|
74
|
+
repo={helmChart.repo}
|
|
75
|
+
chartName={helmChart.chartName}
|
|
76
|
+
version={helmChart.version || 'latest'}
|
|
77
|
+
source="artifacthub"
|
|
78
|
+
repoUrl={helmChart.repoUrl} // Pass direct repo URL for non-ArtifactHub charts
|
|
79
|
+
defaultValues={helmChart.defaultValues}
|
|
80
|
+
onClose={() => setShowHelmInstall(false)}
|
|
81
|
+
onSuccess={() => {
|
|
82
|
+
setShowHelmInstall(false)
|
|
83
|
+
setState('checking')
|
|
84
|
+
setLastChecked(null)
|
|
85
|
+
}}
|
|
86
|
+
/>
|
|
87
|
+
) : null
|
|
88
|
+
|
|
89
|
+
// Detecting state
|
|
90
|
+
if (state === 'detecting' || sourcesLoading) {
|
|
91
|
+
return (
|
|
92
|
+
<div className="flex items-center justify-center h-full w-full">
|
|
93
|
+
<div className="text-center space-y-4">
|
|
94
|
+
<Loader2 className="h-8 w-8 animate-spin text-blue-400 mx-auto" />
|
|
95
|
+
<p className="text-theme-text-secondary">Detecting traffic sources...</p>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Checking state (polling for newly enabled source)
|
|
102
|
+
if (state === 'checking') {
|
|
103
|
+
return (
|
|
104
|
+
<>
|
|
105
|
+
<div className="flex items-center justify-center h-full w-full">
|
|
106
|
+
<div className="max-w-md w-full p-6 space-y-6">
|
|
107
|
+
<div className="text-center space-y-2">
|
|
108
|
+
<Loader2 className="h-8 w-8 animate-spin text-blue-400 mx-auto" />
|
|
109
|
+
<h2 className="text-lg font-medium text-theme-text-primary">Waiting for traffic source...</h2>
|
|
110
|
+
<p className="text-sm text-theme-text-secondary">
|
|
111
|
+
Checking for availability
|
|
112
|
+
</p>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<div className="bg-theme-elevated/50 rounded-lg p-4 text-sm">
|
|
116
|
+
<p className="text-theme-text-tertiary">
|
|
117
|
+
Last checked: {formatLastChecked(lastChecked)}
|
|
118
|
+
</p>
|
|
119
|
+
<p className="text-theme-text-tertiary">
|
|
120
|
+
Polls every 30 seconds automatically
|
|
121
|
+
</p>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<div className="flex gap-2 justify-center">
|
|
125
|
+
<button
|
|
126
|
+
onClick={() => {
|
|
127
|
+
setStep('choice')
|
|
128
|
+
setState('wizard')
|
|
129
|
+
}}
|
|
130
|
+
className="flex items-center gap-1 px-3 py-2 text-sm rounded border border-theme-border text-theme-text-primary hover:bg-theme-hover transition-colors"
|
|
131
|
+
>
|
|
132
|
+
<ArrowLeft className="h-4 w-4" />
|
|
133
|
+
Back
|
|
134
|
+
</button>
|
|
135
|
+
<button
|
|
136
|
+
onClick={() => {
|
|
137
|
+
onRefetch()
|
|
138
|
+
setLastChecked(new Date())
|
|
139
|
+
}}
|
|
140
|
+
className="px-3 py-2 text-sm rounded border border-theme-border text-theme-text-primary hover:bg-theme-hover transition-colors"
|
|
141
|
+
>
|
|
142
|
+
Check Now
|
|
143
|
+
</button>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
{helmInstallOverlay}
|
|
148
|
+
</>
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Step 1: Choice screen
|
|
153
|
+
if (step === 'choice') {
|
|
154
|
+
return (
|
|
155
|
+
<>
|
|
156
|
+
<div className="flex items-center justify-center h-full w-full">
|
|
157
|
+
<div className="max-w-lg w-full p-6 space-y-6">
|
|
158
|
+
<div className="space-y-2">
|
|
159
|
+
<h2 className="text-lg font-medium text-theme-text-primary">Traffic Visibility</h2>
|
|
160
|
+
<p className="text-sm text-theme-text-secondary">
|
|
161
|
+
View service-to-service network flows in your cluster
|
|
162
|
+
</p>
|
|
163
|
+
</div>
|
|
164
|
+
|
|
165
|
+
{/* Cluster detection results */}
|
|
166
|
+
<div className="bg-theme-elevated/50 rounded-lg p-4 space-y-3">
|
|
167
|
+
<h3 className="text-sm font-medium text-theme-text-primary">Cluster Detection</h3>
|
|
168
|
+
<div className="grid grid-cols-2 gap-2 text-sm">
|
|
169
|
+
<div className="flex items-center gap-2 text-theme-text-secondary">
|
|
170
|
+
<CheckCircle2 className="h-4 w-4 text-green-500" />
|
|
171
|
+
<span>Platform: {cluster?.platform || 'generic'}</span>
|
|
172
|
+
</div>
|
|
173
|
+
<div className="flex items-center gap-2 text-theme-text-secondary">
|
|
174
|
+
{cluster?.cni && cluster.cni !== 'unknown' ? (
|
|
175
|
+
<CheckCircle2 className="h-4 w-4 text-green-500" />
|
|
176
|
+
) : (
|
|
177
|
+
<XCircle className="h-4 w-4 text-yellow-500" />
|
|
178
|
+
)}
|
|
179
|
+
<span>CNI: {cluster?.cni || 'unknown'}</span>
|
|
180
|
+
</div>
|
|
181
|
+
{cluster?.cni === 'cilium' && (
|
|
182
|
+
<div className="flex items-center gap-2 col-span-2 text-theme-text-secondary">
|
|
183
|
+
{cluster.dataplaneV2 ? (
|
|
184
|
+
<CheckCircle2 className="h-4 w-4 text-green-500" />
|
|
185
|
+
) : (
|
|
186
|
+
<XCircle className="h-4 w-4 text-yellow-500" />
|
|
187
|
+
)}
|
|
188
|
+
<span>
|
|
189
|
+
Hubble: {cluster.dataplaneV2 ? 'Enabled' : 'Not enabled'}
|
|
190
|
+
</span>
|
|
191
|
+
</div>
|
|
192
|
+
)}
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
{/* Detection errors */}
|
|
197
|
+
{sourcesData?.detected.filter(s => s.status === 'error').map(source => (
|
|
198
|
+
<div key={source.name} className="bg-red-500/10 border border-red-500/30 rounded-lg p-3">
|
|
199
|
+
<div className="flex items-start gap-2">
|
|
200
|
+
<AlertTriangle className="h-4 w-4 text-red-400 mt-0.5 shrink-0" />
|
|
201
|
+
<div className="text-sm">
|
|
202
|
+
<span className="font-medium text-red-400 capitalize">{source.name}</span>
|
|
203
|
+
<span className="text-theme-text-secondary"> detection failed: </span>
|
|
204
|
+
<span className="text-theme-text-tertiary">{source.message}</span>
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
</div>
|
|
208
|
+
))}
|
|
209
|
+
|
|
210
|
+
{/* Recommendation */}
|
|
211
|
+
{recommendation && (
|
|
212
|
+
<div className="space-y-4">
|
|
213
|
+
{/* Primary option */}
|
|
214
|
+
<div className="border border-skyhook-500/30 bg-skyhook-500/5 rounded-lg p-4 space-y-3">
|
|
215
|
+
<div className="flex items-start gap-2">
|
|
216
|
+
<span className="badge btn-brand">
|
|
217
|
+
Recommended
|
|
218
|
+
</span>
|
|
219
|
+
<span className="font-medium capitalize text-theme-text-primary">{recommendation.name}</span>
|
|
220
|
+
</div>
|
|
221
|
+
<p className="text-sm text-theme-text-secondary">{recommendation.reason}</p>
|
|
222
|
+
|
|
223
|
+
{/* Helm install button if chart info available */}
|
|
224
|
+
{recommendation.helmChart ? (
|
|
225
|
+
<button
|
|
226
|
+
onClick={() => setShowHelmInstall(true)}
|
|
227
|
+
className="w-full flex items-center justify-center gap-2 px-4 py-2 text-sm font-medium rounded btn-brand"
|
|
228
|
+
>
|
|
229
|
+
<Package className="h-4 w-4" />
|
|
230
|
+
Install {recommendation.name} with Helm
|
|
231
|
+
</button>
|
|
232
|
+
) : (
|
|
233
|
+
<button
|
|
234
|
+
onClick={() => setStep('install')}
|
|
235
|
+
className="w-full flex items-center justify-center gap-1 px-4 py-2 text-sm font-medium rounded btn-brand"
|
|
236
|
+
>
|
|
237
|
+
View install instructions
|
|
238
|
+
<ArrowRight className="h-4 w-4" />
|
|
239
|
+
</button>
|
|
240
|
+
)}
|
|
241
|
+
|
|
242
|
+
{/* Documentation link */}
|
|
243
|
+
{recommendation.docsUrl && (
|
|
244
|
+
<a
|
|
245
|
+
href={recommendation.docsUrl}
|
|
246
|
+
target="_blank"
|
|
247
|
+
rel="noopener noreferrer"
|
|
248
|
+
className="inline-flex items-center gap-1 text-sm text-blue-400 hover:underline"
|
|
249
|
+
>
|
|
250
|
+
View documentation
|
|
251
|
+
<ExternalLink className="h-4 w-4" />
|
|
252
|
+
</a>
|
|
253
|
+
)}
|
|
254
|
+
</div>
|
|
255
|
+
|
|
256
|
+
{/* Alternative option (if available) */}
|
|
257
|
+
{recommendation.alternativeName && (
|
|
258
|
+
<div className="border border-theme-border rounded-lg p-4 space-y-3">
|
|
259
|
+
<div className="flex items-start gap-2">
|
|
260
|
+
<span className="badge bg-theme-elevated text-theme-text-secondary">
|
|
261
|
+
Alternative
|
|
262
|
+
</span>
|
|
263
|
+
<span className="font-medium capitalize text-theme-text-primary">{recommendation.alternativeName}</span>
|
|
264
|
+
</div>
|
|
265
|
+
<p className="text-sm text-theme-text-secondary">{recommendation.alternativeReason}</p>
|
|
266
|
+
{recommendation.alternativeDocsUrl && (
|
|
267
|
+
<a
|
|
268
|
+
href={recommendation.alternativeDocsUrl}
|
|
269
|
+
target="_blank"
|
|
270
|
+
rel="noopener noreferrer"
|
|
271
|
+
className="inline-flex items-center gap-1 text-sm text-blue-400 hover:underline"
|
|
272
|
+
>
|
|
273
|
+
Learn more about {recommendation.alternativeName}
|
|
274
|
+
<ExternalLink className="h-4 w-4" />
|
|
275
|
+
</a>
|
|
276
|
+
)}
|
|
277
|
+
</div>
|
|
278
|
+
)}
|
|
279
|
+
</div>
|
|
280
|
+
)}
|
|
281
|
+
|
|
282
|
+
{/* No recommendation */}
|
|
283
|
+
{!recommendation && (
|
|
284
|
+
<div className="border border-theme-border rounded-lg p-4 space-y-3">
|
|
285
|
+
<p className="text-sm text-theme-text-secondary">
|
|
286
|
+
No traffic source detected. Install Cilium with Hubble for traffic visibility.
|
|
287
|
+
</p>
|
|
288
|
+
<a
|
|
289
|
+
href="https://docs.cilium.io/en/stable/gettingstarted/hubble/"
|
|
290
|
+
target="_blank"
|
|
291
|
+
rel="noopener noreferrer"
|
|
292
|
+
className="inline-flex items-center gap-1 px-3 py-2 text-sm rounded border border-theme-border text-theme-text-primary hover:bg-theme-hover transition-colors"
|
|
293
|
+
>
|
|
294
|
+
View Hubble Documentation
|
|
295
|
+
<ExternalLink className="h-4 w-4" />
|
|
296
|
+
</a>
|
|
297
|
+
</div>
|
|
298
|
+
)}
|
|
299
|
+
</div>
|
|
300
|
+
</div>
|
|
301
|
+
{helmInstallOverlay}
|
|
302
|
+
</>
|
|
303
|
+
)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Step 2: Install instructions (for non-Helm installs like gcloud commands)
|
|
307
|
+
return (
|
|
308
|
+
<>
|
|
309
|
+
<div className="flex items-center justify-center h-full w-full">
|
|
310
|
+
<div className="max-w-lg w-full p-6 space-y-6">
|
|
311
|
+
<div className="space-y-2">
|
|
312
|
+
<h2 className="text-lg font-medium text-theme-text-primary">Enable {recommendation?.name || 'Hubble'}</h2>
|
|
313
|
+
<p className="text-sm text-theme-text-secondary">
|
|
314
|
+
Run the following command to enable traffic observability
|
|
315
|
+
</p>
|
|
316
|
+
</div>
|
|
317
|
+
|
|
318
|
+
{/* Install command */}
|
|
319
|
+
<div className="bg-theme-elevated rounded-lg p-4 space-y-3">
|
|
320
|
+
<div className="flex items-center justify-between">
|
|
321
|
+
<span className="text-xs font-medium text-theme-text-tertiary">Command</span>
|
|
322
|
+
<button
|
|
323
|
+
onClick={() => copyCommand(recommendation?.installCommand || '')}
|
|
324
|
+
className="p-1 rounded text-theme-text-secondary hover:text-theme-text-primary hover:bg-theme-hover transition-colors"
|
|
325
|
+
>
|
|
326
|
+
{copied ? (
|
|
327
|
+
<CheckCircle2 className="h-4 w-4 text-green-500" />
|
|
328
|
+
) : (
|
|
329
|
+
<Copy className="h-4 w-4" />
|
|
330
|
+
)}
|
|
331
|
+
</button>
|
|
332
|
+
</div>
|
|
333
|
+
<pre className="text-sm font-mono whitespace-pre-wrap break-all bg-theme-surface rounded p-3 overflow-x-auto text-theme-text-primary">
|
|
334
|
+
{recommendation?.installCommand || 'No command available'}
|
|
335
|
+
</pre>
|
|
336
|
+
</div>
|
|
337
|
+
|
|
338
|
+
{/* Platform-specific notes */}
|
|
339
|
+
{cluster?.platform === 'gke' && cluster?.cni === 'cilium' && (
|
|
340
|
+
<div className="bg-skyhook-500/10 border border-skyhook-500/20 rounded-lg p-4 text-sm">
|
|
341
|
+
<p className="text-blue-400 font-medium">GKE Dataplane V2</p>
|
|
342
|
+
<p className="text-theme-text-secondary mt-1">
|
|
343
|
+
Your cluster uses Cilium natively. The command above enables the Hubble
|
|
344
|
+
observability layer which provides traffic visibility without any performance impact.
|
|
345
|
+
</p>
|
|
346
|
+
</div>
|
|
347
|
+
)}
|
|
348
|
+
|
|
349
|
+
{/* Documentation link */}
|
|
350
|
+
{recommendation?.docsUrl && (
|
|
351
|
+
<a
|
|
352
|
+
href={recommendation.docsUrl}
|
|
353
|
+
target="_blank"
|
|
354
|
+
rel="noopener noreferrer"
|
|
355
|
+
className="flex items-center gap-2 text-sm text-blue-400 hover:underline"
|
|
356
|
+
>
|
|
357
|
+
View full documentation
|
|
358
|
+
<ExternalLink className="h-4 w-4" />
|
|
359
|
+
</a>
|
|
360
|
+
)}
|
|
361
|
+
|
|
362
|
+
{/* Action buttons */}
|
|
363
|
+
<div className="flex gap-2">
|
|
364
|
+
<button
|
|
365
|
+
onClick={() => setStep('choice')}
|
|
366
|
+
className="flex items-center gap-1 px-3 py-2 text-sm rounded border border-theme-border text-theme-text-primary hover:bg-theme-hover transition-colors"
|
|
367
|
+
>
|
|
368
|
+
<ArrowLeft className="h-4 w-4" />
|
|
369
|
+
Back
|
|
370
|
+
</button>
|
|
371
|
+
<button
|
|
372
|
+
onClick={() => {
|
|
373
|
+
setState('checking')
|
|
374
|
+
setLastChecked(null)
|
|
375
|
+
}}
|
|
376
|
+
className="flex-1 px-4 py-2 text-sm font-medium rounded btn-brand"
|
|
377
|
+
>
|
|
378
|
+
I've run the command
|
|
379
|
+
</button>
|
|
380
|
+
</div>
|
|
381
|
+
</div>
|
|
382
|
+
</div>
|
|
383
|
+
{helmInstallOverlay}
|
|
384
|
+
</>
|
|
385
|
+
)
|
|
386
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ComponentProps } from 'react'
|
|
2
|
+
import { CodeViewer as BaseCodeViewer } from '@skyhook-io/k8s-ui'
|
|
3
|
+
import { useTheme } from '../../context/ThemeContext'
|
|
4
|
+
|
|
5
|
+
export function CodeViewer(props: Omit<ComponentProps<typeof BaseCodeViewer>, 'theme'>) {
|
|
6
|
+
const { theme } = useTheme()
|
|
7
|
+
return <BaseCodeViewer {...props} theme={theme} />
|
|
8
|
+
}
|