import { useCallback, useEffect, useState } from 'react' import { Cpu, ExternalLink, Loader2, Pause, Play, RefreshCw, RotateCcw, Zap, } from 'lucide-react' import type { StreamingStatus } from '../../types' import { fetchStreamingStatus, restartKafkaConnector, pauseKafkaConnector, resumeKafkaConnector, triggerStreamingJob, } from '../../lib/api' import { cn } from '../../lib/utils' type Tab = 'spark' | 'kafka' | 'jobs' export function SparkKafkaPanel({ embedded, selectedNodeId, streaming: initialStreaming, onRefreshGraph, }: { embedded?: boolean selectedNodeId?: string | null streaming?: StreamingStatus | null onRefreshGraph?: () => void }) { const [tab, setTab] = useState('spark') const [streaming, setStreaming] = useState(initialStreaming ?? null) const [loading, setLoading] = useState(!initialStreaming) const [busy, setBusy] = useState(null) const [jobConf, setJobConf] = useState>({}) const [selectedJob, setSelectedJob] = useState('spark_to_curated') const [showSparkUi, setShowSparkUi] = useState(false) const load = useCallback(async (refresh = false) => { setLoading(true) const s = await fetchStreamingStatus(refresh) if (s) setStreaming(s) setLoading(false) }, []) useEffect(() => { if (initialStreaming) setStreaming(initialStreaming) }, [initialStreaming]) useEffect(() => { if (selectedNodeId === 'spark') setTab('spark') if (selectedNodeId === 'kafka') setTab('kafka') }, [selectedNodeId]) useEffect(() => { const iv = setInterval(() => load(), 8000) return () => clearInterval(iv) }, [load]) const spark = streaming?.spark const kafka = streaming?.kafka const jobs = streaming?.jobs ?? [] const onJob = async (jobId: string) => { setBusy(`job:${jobId}`) try { let conf: Record = {} const raw = jobConf[jobId] if (raw?.trim()) { conf = JSON.parse(raw) } await triggerStreamingJob(jobId, conf) onRefreshGraph?.() await load(true) } catch { /* ignore */ } finally { setBusy(null) } } const onConnector = async (name: string, action: 'restart' | 'pause' | 'resume') => { setBusy(`conn:${name}:${action}`) try { if (action === 'restart') await restartKafkaConnector(name) else if (action === 'pause') await pauseKafkaConnector(name) else await resumeKafkaConnector(name) await load(true) onRefreshGraph?.() } finally { setBusy(null) } } return (
{(['spark', 'kafka', 'jobs'] as Tab[]).map((t) => ( ))}
{spark?.ui_ok && ( Spark {spark.alive_workers}w · {spark.cores_used}/{spark.cores} cores )} {kafka?.connect_ok && ( {kafka.connectors?.length ?? 0} connectors )}
{tab === 'spark' && (
Open full Spark UI
{showSparkUi && (