import React, { useState, useEffect } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { LogsModal } from '@/components/ui/logs-modal'; import { YamlEditor } from '@/components/ui/yaml-editor'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from '@/components/ui/tooltip'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { useDaemonSetDetails, useKubectl } from '@/hooks/useKubectl'; import { useToast } from '@/hooks/useToast'; import { ArrowLeft, Shield, RefreshCw, AlertCircle, CheckCircle, XCircle, Clock, Play, Pause, Loader2, MoreVertical, Edit, Trash2, FileText, Activity, Container, Zap, Calendar, Tag, Server, AlertTriangle, Eye, Download, Copy, ExternalLink, Info, Database, Network, HardDrive, Cpu, MemoryStick, List, GitBranch, Settings, Terminal, ChevronDown, RotateCcw, Trash, Key, } from 'lucide-react'; export function DaemonSetDetailsPage() { const { namespaceName, daemonSetName } = useParams<{ namespaceName: string; daemonSetName: string; }>(); const navigate = useNavigate(); const { showToast } = useToast(); const { executeCommand } = useKubectl(); const { daemonSetInfo, pods, events, configMaps, secrets, services, loading, error, isRefreshing, refetch, backgroundRefetch, } = useDaemonSetDetails(daemonSetName || '', namespaceName || ''); const [logsModalOpen, setLogsModalOpen] = useState(false); const [selectedPod, setSelectedPod] = useState(null); const [selectedContainer, setSelectedContainer] = useState(''); const [autoRefresh, setAutoRefresh] = useState(true); const [restarting, setRestarting] = useState(false); const [yamlDrawerOpen, setYamlDrawerOpen] = useState(false); const [deleteModalOpen, setDeleteModalOpen] = useState(false); const [deleting, setDeleting] = useState(false); const [activeTab, setActiveTab] = useState('configuracoes'); // Estados para modais de Environment const [configMapKeysModalOpen, setConfigMapKeysModalOpen] = useState(false); const [selectedConfigMapData, setSelectedConfigMapData] = useState(null); const [secretKeysModalOpen, setSecretKeysModalOpen] = useState(false); const [selectedSecretData, setSelectedSecretData] = useState(null); // Auto-refresh effect useEffect(() => { if (!autoRefresh) return; const interval = setInterval(() => { backgroundRefetch(); }, 5000); return () => clearInterval(interval); }, [autoRefresh, backgroundRefetch]); const handleViewLogs = (pod: any, container: string) => { setSelectedPod(pod); setSelectedContainer(container); setLogsModalOpen(true); }; const handleRestart = async () => { if (!daemonSetInfo) return; setRestarting(true); try { const command = `kubectl rollout restart daemonset ${daemonSetInfo.metadata.name} -n ${daemonSetInfo.metadata.namespace}`; const result = await executeCommand(command); if (result.success) { showToast({ title: 'DaemonSet Reiniciado', description: `DaemonSet "${daemonSetInfo.metadata.name}" foi reiniciado com sucesso`, variant: 'success', }); // Refresh after restart await refetch(); } else { showToast({ title: 'Erro ao Reiniciar DaemonSet', description: result.error || 'Falha ao reiniciar o DaemonSet', variant: 'destructive', }); } } catch (err) { const errorMsg = err instanceof Error ? err.message : 'Erro inesperado'; showToast({ title: 'Erro', description: errorMsg, variant: 'destructive', }); } finally { setRestarting(false); } }; const handleYamlView = () => { if (!daemonSetName || !namespaceName) return; setYamlDrawerOpen(true); }; const handleTabChange = (value: string) => { setActiveTab(value); }; // Function to handle ConfigMap keys view const handleConfigMapKeysView = async (configMapName: string) => { try { const command = `kubectl get configmap ${configMapName} -n ${namespaceName} -o json`; const result = await executeCommand(command); if (result && result.success && result.data) { const configMapData = JSON.parse(result.data); setSelectedConfigMapData(configMapData); setConfigMapKeysModalOpen(true); } else { showToast({ title: 'Erro ao Carregar ConfigMap', description: result.error || 'Falha ao carregar dados do ConfigMap', variant: 'destructive', }); } } catch (err) { showToast({ title: 'Erro', description: 'Erro inesperado ao carregar ConfigMap', variant: 'destructive', }); } }; // Function to handle Secret keys view const handleSecretKeysView = async (secretName: string) => { try { const command = `kubectl get secret ${secretName} -n ${namespaceName} -o json`; const result = await executeCommand(command); if (result && result.success && result.data) { const secretData = JSON.parse(result.data); setSelectedSecretData(secretData); setSecretKeysModalOpen(true); } else { showToast({ title: 'Erro ao Carregar Secret', description: result.error || 'Falha ao carregar dados do Secret', variant: 'destructive', }); } } catch (err) { showToast({ title: 'Erro', description: 'Erro inesperado ao carregar Secret', variant: 'destructive', }); } }; // Function to get ConfigMap info const getConfigMapInfo = (configMap: any) => { const dataKeys = Object.keys(configMap.data || {}); return { keysCount: dataKeys.length, keys: dataKeys, size: JSON.stringify(configMap.data || {}).length, }; }; // Function to get Secret info const getSecretInfo = (secret: any) => { const secretType = secret.type || 'Opaque'; const dataKeys = Object.keys(secret.data || {}); let variant = 'secondary'; let icon = Shield; if (secretType === 'kubernetes.io/dockerconfigjson') { variant = 'outline'; icon = Container; } else if (secretType === 'kubernetes.io/tls') { variant = 'destructive'; icon = Shield; } return { type: secretType, variant, icon, keysCount: dataKeys.length, keys: dataKeys, }; }; // Function to get Secret usage info const getSecretUsageInfo = (secret: any) => { const secretType = secret.type || 'Opaque'; const secretInfo = getSecretInfo(secret); // For specific types, use standardized descriptions switch (secretType) { case 'kubernetes.io/dockerconfigjson': return { type: 'special', badge: 'Registry Config', tooltip: 'Credenciais de registry Docker', color: 'bg-purple-50 text-purple-700', }; case 'kubernetes.io/tls': return { type: 'special', badge: 'Certificado SSL', tooltip: 'Certificado TLS (tls.crt, tls.key)', color: 'bg-red-50 text-red-700', }; case 'kubernetes.io/service-account-token': return { type: 'special', badge: 'Service Account Token', tooltip: 'Token de autenticação da service account', color: 'bg-blue-50 text-blue-700', }; default: const { usageEntry } = secret; if (usageEntry?.isFullSecret) { return { type: 'all-keys', badge: 'Todas as Chaves', tooltip: 'Todas as chaves do secret são usadas', color: 'bg-green-50 text-green-700', }; } if (usageEntry?.keys.length > 0) { return { type: 'specific-keys', badge: `${usageEntry.keys.length} Chave${usageEntry.keys.length > 1 ? 's' : ''}`, tooltip: `Chaves específicas: ${usageEntry.keys.join(', ')}`, color: 'bg-blue-50 text-blue-700', }; } return { type: 'unspecified', badge: 'Não especificado', tooltip: 'Uso não especificado', color: 'bg-gray-50 text-gray-700', }; } }; // Function to get ConfigMap usage info const getConfigMapUsageInfo = (configMap: any) => { const { usageEntry } = configMap; const configMapInfo = getConfigMapInfo(configMap); if (usageEntry?.isFullConfigMap) { return { type: 'all-keys', keys: configMapInfo.keys, color: 'bg-green-50 text-green-700', clickable: true, }; } if (usageEntry?.keys.length > 0) { return { type: 'specific-keys', keys: usageEntry.keys, color: 'bg-blue-50 text-blue-700', clickable: true, }; } return { type: 'unspecified', color: '', clickable: false, }; }; const handleDeleteDaemonSetClick = () => { setDeleteModalOpen(true); }; const handleDeleteDaemonSet = async () => { if (!daemonSetInfo) return; setDeleting(true); try { const command = `kubectl delete daemonset ${daemonSetInfo.metadata.name} -n ${daemonSetInfo.metadata.namespace}`; const result = await executeCommand(command); if (result.success) { showToast({ title: 'DaemonSet Excluído', description: `DaemonSet "${daemonSetInfo.metadata.name}" foi excluído com sucesso`, variant: 'success', }); // Navigate back to daemonsets list navigate('/workloads/daemonsets'); } else { showToast({ title: 'Erro ao Excluir DaemonSet', description: result.error || 'Falha ao excluir o DaemonSet', variant: 'destructive', }); } } catch (err) { const errorMsg = err instanceof Error ? err.message : 'Erro inesperado'; showToast({ title: 'Erro', description: errorMsg, variant: 'destructive', }); } finally { setDeleting(false); setDeleteModalOpen(false); } }; const getAge = (creationTimestamp: string) => { const now = new Date(); const created = new Date(creationTimestamp); const diffMs = now.getTime() - created.getTime(); const diffSeconds = Math.floor(diffMs / 1000); const diffMinutes = Math.floor(diffSeconds / 60); const diffHours = Math.floor(diffMinutes / 60); const diffDays = Math.floor(diffHours / 24); if (diffDays > 0) return `${diffDays}d`; if (diffHours > 0) return `${diffHours}h`; if (diffMinutes > 0) return `${diffMinutes}m`; return `${diffSeconds}s`; }; const getDaemonSetStatus = () => { if (!daemonSetInfo) return { label: 'Unknown', color: 'text-gray-600', bgColor: 'bg-gray-100', icon: Clock, }; const status = daemonSetInfo.status || {}; const desired = status.desiredNumberScheduled || 0; const current = status.currentNumberScheduled || 0; const ready = status.numberReady || 0; const misscheduled = status.numberMisscheduled || 0; if (ready === desired && misscheduled === 0) { return { label: 'Ready', color: 'text-green-600', bgColor: 'bg-green-100', icon: CheckCircle, }; } if (current === 0) { return { label: 'Stopped', color: 'text-red-600', bgColor: 'bg-red-100', icon: XCircle, }; } return { label: 'Not Ready', color: 'text-yellow-600', bgColor: 'bg-yellow-100', icon: Clock, }; }; const getPodStatus = (pod: any) => { const phase = pod.status?.phase || 'Unknown'; const conditions = pod.status?.conditions || []; const readyCondition = conditions.find((c: any) => c.type === 'Ready'); const isReady = readyCondition?.status === 'True'; if (phase === 'Running' && isReady) { return { label: 'Running', color: 'text-green-600', bgColor: 'bg-green-100', icon: CheckCircle, }; } if (phase === 'Pending') { return { label: 'Pending', color: 'text-yellow-600', bgColor: 'bg-yellow-100', icon: Clock, }; } if (phase === 'Failed') { return { label: 'Failed', color: 'text-red-600', bgColor: 'bg-red-100', icon: XCircle, }; } if (phase === 'Succeeded') { return { label: 'Succeeded', color: 'text-green-600', bgColor: 'bg-green-100', icon: CheckCircle, }; } return { label: phase, color: 'text-gray-600', bgColor: 'bg-gray-100', icon: Clock, }; }; const getEventType = (event: any) => { if (event.type === 'Warning') { return { color: 'text-orange-600', bgColor: 'bg-orange-100', icon: AlertTriangle, }; } if (event.type === 'Normal') { return { color: 'text-blue-600', bgColor: 'bg-blue-100', icon: Info }; } return { color: 'text-gray-600', bgColor: 'bg-gray-100', icon: Info }; }; if (loading) { return (

Carregando detalhes do DaemonSet...

); } if (error) { return (

{error}

); } if (!daemonSetInfo) { return (

DaemonSet não encontrado

); } const status = getDaemonSetStatus(); const StatusIcon = status.icon; return (
{/* Header */}

{daemonSetInfo.metadata.name}

DaemonSet no namespace{' '} {daemonSetInfo.metadata.namespace}
{/* Split button - Live/Manual com dropdown de tempo */}
{/* Botão principal - Play/Pause */} {/* Dropdown para configurar tempo */} Atualização automática setAutoRefresh(true)}> Ativar (5s) setAutoRefresh(false)}> Pausar refetch()}> Atualizar agora
{/* Overview Cards */}
Status {status.label}

Estado atual

Desired
{daemonSetInfo.status?.desiredNumberScheduled || 0}

Pods desejados

Ready
{daemonSetInfo.status?.numberReady || 0}

Pods prontos

Idade
{getAge(daemonSetInfo.metadata.creationTimestamp)}

{new Date( daemonSetInfo.metadata.creationTimestamp, ).toLocaleDateString('pt-BR')}

Misscheduled
{daemonSetInfo.status?.numberMisscheduled || 0}

Pods mal agendados

{/* DaemonSet Configuration */}
Configuração do DaemonSet
Configurações Environment Secret Service
{/* Coluna 1: Informações Básicas */}
Nome: {daemonSetInfo.metadata.name}
Update Strategy: {daemonSetInfo.spec?.updateStrategy?.type || 'RollingUpdate'}
Min Ready Seconds: {daemonSetInfo.spec?.minReadySeconds || 0}
{/* Coluna 2: Configurações de Serviço */}
Service Account: {daemonSetInfo.spec?.template?.spec?.serviceAccountName || 'default'}
Pull Secret: {daemonSetInfo.spec?.template?.spec?.imagePullSecrets ?.length > 0 ? daemonSetInfo.spec.template.spec.imagePullSecrets .map((s: any) => s.name) .join(', ') : 'Nenhum'}
Node Selector: {daemonSetInfo.spec?.template?.spec?.nodeSelector ? Object.entries( daemonSetInfo.spec.template.spec.nodeSelector, ) .map(([k, v]) => `${k}=${v}`) .join(', ') : 'Nenhum'}
{/* Coluna 3: Políticas */}
Restart Policy: {daemonSetInfo.spec?.template?.spec?.restartPolicy || 'Always'}
Revision History Limit: {daemonSetInfo.spec?.revisionHistoryLimit || 10}
Tolerations: {daemonSetInfo.spec?.template?.spec?.tolerations ?.length || 0}
{/* Labels Section */}

Labels

{Object.entries(daemonSetInfo.metadata.labels || {}).length > 0 ? ( Object.entries(daemonSetInfo.metadata.labels || {}).map( ([key, value]) => ( {key}: {String(value)} ), ) ) : ( Nenhum label definido )}
{/* Annotations Section */}

Annotations

{Object.entries(daemonSetInfo.metadata.annotations || {}) .length > 0 ? ( Object.entries( daemonSetInfo.metadata.annotations || {}, ).map(([key, value]) => ( {key}:{' '} {typeof value === 'string' && value.length > 50 ? `${value.substring(0, 50)}...` : String(value)} )) ) : ( Nenhuma annotation definida )}
{/* Containers Section */}

Containers

Nome Imagem Portas Tipo {/* Init Containers */} {daemonSetInfo.spec?.template?.spec?.initContainers?.map( (container: any, index: number) => (
{container.name}
{container.image}
{container.ports?.length > 0 ? ( container.ports.map( (port: any, portIndex: number) => ( {port.containerPort} ), ) ) : ( Nenhuma )}
Init
), )} {/* Regular Containers */} {daemonSetInfo.spec?.template?.spec?.containers?.map( (container: any, index: number) => (
{container.name}
{container.image}
{container.ports?.length > 0 ? ( container.ports.map( (port: any, portIndex: number) => ( {port.containerPort} ), ) ) : ( Nenhuma )}
Container
), )}
{(() => { // Create usage entries exactly like deployment details const configMapUsageEntries: Array<{ configMapName: string; usageType: string; keys: string[]; isFullConfigMap: boolean; }> = []; const secretUsageEntries: Array<{ secretName: string; usageType: string; keys: string[]; isFullSecret: boolean; }> = []; const containers = daemonSetInfo?.spec?.template?.spec?.containers || []; const initContainers = daemonSetInfo?.spec?.template?.spec?.initContainers || []; const allContainers = [...containers, ...initContainers]; // Track hardcoded environment variables const hardcodedVarsEntries: Array<{ varName: string; value: string; containerName: string; }> = []; // Process all containers following deployment pattern allContainers.forEach((container: any) => { // ConfigMaps via env (specific keys) container.env?.forEach((env: any) => { if ( env.valueFrom?.configMapKeyRef?.name && env.valueFrom?.configMapKeyRef?.key ) { const configMapName = env.valueFrom.configMapKeyRef.name; const keyName = env.valueFrom.configMapKeyRef.key; configMapUsageEntries.push({ configMapName, usageType: 'Env', keys: [keyName], isFullConfigMap: false, }); } else if ( env.valueFrom?.secretKeyRef?.name && env.valueFrom?.secretKeyRef?.key ) { const secretName = env.valueFrom.secretKeyRef.name; const keyName = env.valueFrom.secretKeyRef.key; secretUsageEntries.push({ secretName, usageType: 'Env', keys: [keyName], isFullSecret: false, }); } else if (env.value !== undefined) { // Hardcoded environment variable hardcodedVarsEntries.push({ varName: env.name, value: env.value, containerName: container.name, }); } }); // ConfigMaps via envFrom (full configmap) container.envFrom?.forEach((envFrom: any) => { if (envFrom.configMapRef?.name) { const configMapName = envFrom.configMapRef.name; configMapUsageEntries.push({ configMapName, usageType: 'EnvFrom', keys: [], isFullConfigMap: true, }); } if (envFrom.secretRef?.name) { const secretName = envFrom.secretRef.name; secretUsageEntries.push({ secretName, usageType: 'EnvFrom', keys: [], isFullSecret: true, }); } }); }); // Create expanded lists like deployment const expandedConfigMaps = configMapUsageEntries .map((entry) => { const configMap = configMaps.find( (cm: any) => cm.metadata?.name === entry.configMapName, ); return { ...configMap, usageEntry: entry, }; }) .filter((item) => item.metadata); const expandedSecrets = secretUsageEntries .map((entry) => { const secret = secrets.find( (s: any) => s.metadata?.name === entry.secretName, ); return { ...secret, usageEntry: entry, }; }) .filter((item) => item.metadata); // Create hardcoded variable entries (preserve YAML order) const expandedHardcodedVars = hardcodedVarsEntries.map( (entry) => ({ metadata: { name: entry.varName, creationTimestamp: daemonSetInfo?.metadata?.creationTimestamp, }, data: { [entry.varName]: entry.value, }, usageEntry: { varName: entry.varName, usageType: 'Hardcoded', keys: [entry.varName], isHardcoded: true, }, isHardcodedVar: true, containerName: entry.containerName, value: entry.value, }), ); // Order resources to match YAML order: hardcoded vars first, then references, then envFrom const envRefResources = [ ...expandedConfigMaps, ...expandedSecrets, ].filter((r) => r.usageEntry?.usageType === 'Env'); const envFromResources = [ ...expandedConfigMaps, ...expandedSecrets, ].filter((r) => r.usageEntry?.usageType === 'EnvFrom'); const allEnvResources = [ ...expandedHardcodedVars, ...envRefResources, ...envFromResources, ]; const getConfigMapInfo = (configMap: any) => { const dataKeys = Object.keys(configMap.data || {}); return { keysCount: dataKeys.length, keys: dataKeys, size: JSON.stringify(configMap.data || {}).length, }; }; const getSecretInfo = (secret: any) => { const dataKeys = Object.keys(secret.data || {}); return { keysCount: dataKeys.length, keys: dataKeys, size: JSON.stringify(secret.data || {}).length, }; }; return allEnvResources.length === 0 ? (

Nenhum ConfigMap/Secret Relacionado

Este DaemonSet não possui ConfigMaps ou Secrets associados às variáveis de ambiente.

Nenhum recurso encontrado
) : (

Recursos de Ambiente ({allEnvResources.length})

Type Chaves Uso Tamanho Idade Ações {allEnvResources.map((envResource, index) => { const isConfigMap = envResource.usageEntry?.configMapName; const isSecret = envResource.usageEntry?.secretName; const isHardcoded = envResource.isHardcodedVar; const { usageEntry } = envResource; const IconComponent = isConfigMap ? Database : isSecret ? Key : Settings; const iconColor = isConfigMap ? 'text-blue-600' : isSecret ? 'text-orange-600' : 'text-green-600'; const resourceInfo = isHardcoded ? { size: envResource.metadata?.name?.length + envResource.value?.length || 0, } : isConfigMap ? getConfigMapInfo(envResource) : getSecretInfo(envResource); const getTypeDisplay = () => { if (isHardcoded) return 'Environment Variable'; if (isConfigMap) return 'ConfigMap'; if (isSecret) return 'Secret'; return 'Unknown'; }; return ( {/* Type Column */}
{getTypeDisplay()} { navigator.clipboard.writeText( getTypeDisplay(), ); showToast({ title: 'Type Copiado', description: `Type "${getTypeDisplay()}" copiado para a área de transferência`, variant: 'success', }); }} />
{/* Chaves Column */}
{usageEntry.isFullConfigMap || usageEntry.isFullSecret ? ( isConfigMap ? handleConfigMapKeysView(envResource) : handleSecretKeysView(envResource) } > (Todas as Chaves) ) : isHardcoded ? ( { const envVarData = { metadata: { name: usageEntry.varName, }, data: { [usageEntry.varName || '']: envResource.value, }, }; setSelectedConfigMapData(envVarData); setConfigMapKeysModalOpen(true); }} > {usageEntry.varName} ) : usageEntry.keys && usageEntry.keys.length > 0 ? (
{usageEntry.keys.map((key: string) => ( { if (isConfigMap) { handleConfigMapKeysView( envResource, ); } else { handleSecretKeysView(envResource); } }} > {key} ))}
) : ( (Não especificado) )}
{/* Uso Column */} {usageEntry.usageType} {/* Tamanho Column */} {(resourceInfo.size / 1024).toFixed(1)} KB {/* Idade Column */} {getAge( envResource.metadata?.creationTimestamp || '', )} {/* Ações Column */} Ações { if (isHardcoded) { const envVarData = { metadata: { name: envResource.metadata?.name, }, data: { [envResource.metadata?.name || '']: envResource.value, }, }; setSelectedConfigMapData(envVarData); setConfigMapKeysModalOpen(true); } else if (isConfigMap) { handleConfigMapKeysView(envResource); } else { handleSecretKeysView(envResource); } }} > Ver {isHardcoded ? 'Valor' : 'Chaves'} { showToast({ title: 'Em Desenvolvimento', description: 'Visualização YAML será implementada em breve', variant: 'default', }); }} > Ver YAML
); })}
); })()}
{secrets.length === 0 ? (

Nenhum Secret Relacionado

Este DaemonSet não possui Secrets associados.

Nenhum secret encontrado
) : (

Secrets Relacionados ({secrets.length})

Nome Tipo Chaves Uso Idade {secrets.map((secret: any, index: number) => { const secretInfo = getSecretInfo(secret); const SecretIcon = secretInfo.icon; const { usageEntry } = secret; return (
{secret.metadata?.name} { navigator.clipboard.writeText( secret.metadata?.name || '', ); showToast({ title: 'Nome Copiado', description: `Nome "${secret.metadata?.name}" copiado para a área de transferência`, variant: 'success', }); }} />
{secretInfo.type}
{usageEntry.isFullSecret ? ( (Todas as Chaves) ) : usageEntry.keys.length > 0 ? (
{usageEntry.keys.map((key: string) => ( {key} ))}
) : ( (Não especificado) )}
{usageEntry.usageType} {getAge(secret.metadata?.creationTimestamp)}
); })}
)}
{services.length === 0 ? (

Nenhum Service Relacionado

Este DaemonSet não possui Services associados.

Nenhum service encontrado
) : (

Services Relacionados ({services.length})

Nome Tipo Cluster IP Portas Seletores Idade {services.map((service: any, index: number) => { const serviceType = service.spec?.type || 'ClusterIP'; const ports = service.spec?.ports || []; const selectors = service.spec?.selector || {}; return (
{service.metadata?.name} { navigator.clipboard.writeText( service.metadata?.name || '', ); showToast({ title: 'Nome Copiado', description: `Nome "${service.metadata?.name}" copiado para a área de transferência`, variant: 'success', }); }} />
{serviceType} {service.spec?.clusterIP || 'None'}
{ports.length > 0 ? ( ports.map((port: any, portIndex: number) => ( {port.port} {port.targetPort && port.targetPort !== port.port && ( <>:{port.targetPort} )} /{port.protocol || 'TCP'} )) ) : ( Nenhuma )}
{Object.entries(selectors).length > 0 ? ( Object.entries(selectors).map( ([key, value]) => ( {key}={String(value)} ), ) ) : ( Nenhum )}
{getAge(service.metadata?.creationTimestamp)}
); })}
)}
{/* Tabs */} Pods ({pods.length}) Eventos ({events.length}) YAML Pods do DaemonSet Pods criados e gerenciados por este DaemonSet Nome Node Status Restarts Idade Ações {pods.map((pod) => { const podStatus = getPodStatus(pod); const PodStatusIcon = podStatus.icon; return ( {pod.spec.nodeName || 'N/A'}
{podStatus.label}
{pod.status.containerStatuses?.reduce( (total: number, container: any) => total + (container.restartCount || 0), 0, ) || 0} {getAge(pod.metadata.creationTimestamp)} Ações do Pod navigate( `/workloads/pods/${pod.metadata.name}/${pod.metadata.namespace}`, ) } > Visualizar handleViewLogs( pod, pod.spec.containers[0]?.name || '', ) } > Ver Logs
); })} {pods.length === 0 && (

Nenhum pod encontrado

)}
Eventos do DaemonSet Eventos relacionados a este DaemonSet Tipo Motivo Mensagem Primeira Ocorrência Última Ocorrência Contagem {events.map((event, index) => { const eventType = getEventType(event); const EventIcon = eventType.icon; return (
{event.type}
{event.reason} {event.message} {event.firstTimestamp ? new Date(event.firstTimestamp).toLocaleString() : 'N/A'} {event.lastTimestamp ? new Date(event.lastTimestamp).toLocaleString() : 'N/A'} {event.count || 1}
); })} {events.length === 0 && (

Nenhum evento encontrado

)}
YAML do DaemonSet Configuração completa do DaemonSet em formato YAML
                {JSON.stringify(daemonSetInfo, null, 2)}
              
{/* YAML Editor */} { setTimeout(() => { backgroundRefetch(); }, 1000); }} /> {/* Delete Confirmation Modal */} Excluir DaemonSet Tem certeza que deseja excluir o DaemonSet{' '} {daemonSetInfo?.metadata.name} do namespace{' '} {daemonSetInfo?.metadata.namespace}?

Esta ação não pode ser desfeita e todos os pods associados serão removidos de todos os nós.
{/* Logs Modal */} {selectedPod && ( )} {/* Modal para visualizar chaves e valores do ConfigMap */} Chaves do ConfigMap: {selectedConfigMapData?.metadata?.name} Visualização das chaves e valores do ConfigMap {selectedConfigMapData ? (
Chave Valor Ações {Object.entries(selectedConfigMapData.data || {}).map( ([key, value]) => ( {key}
{typeof value === 'string' && value.length > 100 ? `${value.substring(0, 100)}...` : String(value)}
{ navigator.clipboard.writeText(String(value)); showToast({ title: 'Valor Copiado', description: `Valor da chave "${key}" copiado para a área de transferência`, variant: 'success', }); }} />
), )}
) : (

Nenhum dado encontrado para este ConfigMap

)}
{/* Modal para visualizar chaves e valores do Secret */} Chaves do Secret: {selectedSecretData?.metadata?.name} Visualização das chaves e valores do Secret (valores são mostrados decodificados) {selectedSecretData ? (
Chave Valor Ações {Object.entries(selectedSecretData.data || {}).map( ([key, encodedValue]) => { // Decodificar valor base64 let decodedValue = ''; try { decodedValue = atob(encodedValue as string); } catch (e) { decodedValue = '(Erro ao decodificar)'; } return ( {key}
{decodedValue.length > 100 ? `${decodedValue.substring(0, 100)}...` : decodedValue}
); }, )}
) : (

Nenhum dado encontrado para este Secret

)}
); }