import React, { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { useToast } from '@/hooks/useToast'; import { useKubectl, useNamespacesInfo } from '@/hooks/useKubectl'; import { useGlobalNamespace } from '@/hooks/useGlobalNamespace'; import { ArrowLeft, Database, Upload, CheckCircle, Loader2, Settings, AlertCircle, Eye, EyeOff, } from 'lucide-react'; interface ParsedProperty { key: string; value: string; lineNumber: number; isValid: boolean; error?: string; } function ConfigMapImportPropertiesPage() { const navigate = useNavigate(); const { showToast } = useToast(); const { executeCommand } = useKubectl(); const { namespaces } = useNamespacesInfo(); const { selectedNamespace: globalNamespace } = useGlobalNamespace(); const [configMapName, setConfigMapName] = useState(''); const [selectedNamespace, setSelectedNamespace] = useState(() => { return globalNamespace === 'all' ? 'default' : globalNamespace; }); const [propertiesContent, setPropertiesContent] = useState(''); const [parsedProperties, setParsedProperties] = useState([]); const [showPreview, setShowPreview] = useState(false); const [creating, setCreating] = useState(false); const parsePropertiesFile = (content: string): ParsedProperty[] => { const lines = content.split('\n'); const properties: ParsedProperty[] = []; lines.forEach((line, index) => { const trimmedLine = line.trim(); // Skip empty lines and comments if (!trimmedLine || trimmedLine.startsWith('#') || trimmedLine.startsWith('!')) { return; } // Handle line continuation with backslash let processedLine = trimmedLine; if (processedLine.endsWith('\\')) { // For simplicity, we'll remove the backslash and continue on the same line processedLine = processedLine.slice(0, -1); } // Find the separator (= or : or space) let separatorIndex = -1; let separator = ''; // Look for = first separatorIndex = processedLine.indexOf('='); if (separatorIndex !== -1) { separator = '='; } else { // Look for : separatorIndex = processedLine.indexOf(':'); if (separatorIndex !== -1) { separator = ':'; } else { // Look for space separatorIndex = processedLine.indexOf(' '); if (separatorIndex !== -1) { separator = ' '; } } } if (separatorIndex === -1) { properties.push({ key: processedLine, value: '', lineNumber: index + 1, isValid: false, error: `Formato inválido: faltando separador (=, :, ou espaço)`, }); return; } const key = processedLine.substring(0, separatorIndex).trim(); const value = processedLine.substring(separatorIndex + 1).trim(); if (!key) { properties.push({ key: '', value: value, lineNumber: index + 1, isValid: false, error: 'Chave vazia', }); return; } // Process escape sequences in key and value const processedKey = key.replace(/\\(.)/g, '$1'); const processedValue = value.replace(/\\(.)/g, '$1'); // Validate key format (Java properties keys can contain dots, but we'll be more restrictive for ConfigMap) if (!/^[a-zA-Z_][a-zA-Z0-9_.-]*$/.test(processedKey)) { properties.push({ key: processedKey, value: processedValue, lineNumber: index + 1, isValid: false, error: 'Nome de chave inválido para ConfigMap', }); return; } properties.push({ key: processedKey, value: processedValue, lineNumber: index + 1, isValid: true, }); }); return properties; }; const handleContentChange = (content: string) => { setPropertiesContent(content); if (content.trim()) { const parsed = parsePropertiesFile(content); setParsedProperties(parsed); } else { setParsedProperties([]); } }; const handleFileUpload = (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (file) { const reader = new FileReader(); reader.onload = (e) => { const content = e.target?.result as string; handleContentChange(content); }; reader.readAsText(file); } }; const validateForm = () => { if (!configMapName.trim()) { showToast({ title: 'Erro de Validação', description: 'Nome do ConfigMap é obrigatório', variant: 'destructive', }); return false; } if (!selectedNamespace) { showToast({ title: 'Erro de Validação', description: 'Namespace é obrigatório', variant: 'destructive', }); return false; } const validProperties = parsedProperties.filter((p) => p.isValid); if (validProperties.length === 0) { showToast({ title: 'Erro de Validação', description: 'Nenhuma propriedade válida encontrada', variant: 'destructive', }); return false; } return true; }; const handleCreateConfigMap = async () => { if (!validateForm()) return; setCreating(true); try { const validProperties = parsedProperties.filter((p) => p.isValid); let command = `kubectl create configmap "${configMapName}" -n "${selectedNamespace}"`; validProperties.forEach((property) => { command += ` --from-literal="${property.key}"="${property.value}"`; }); const result = await executeCommand(command); if (result.success) { showToast({ title: 'ConfigMap Criado com Sucesso', description: `ConfigMap "${configMapName}" foi criado com ${validProperties.length} propriedades`, variant: 'success', }); navigate('/storage/configmaps'); } else { showToast({ title: 'Erro ao Criar ConfigMap', description: result.error || 'Falha ao criar o ConfigMap', variant: 'destructive', }); } } catch (error) { const errorMsg = error instanceof Error ? error.message : 'Erro inesperado'; showToast({ title: 'Erro', description: errorMsg, variant: 'destructive', }); } finally { setCreating(false); } }; const validProperties = parsedProperties.filter((p) => p.isValid); const invalidProperties = parsedProperties.filter((p) => !p.isValid); return (
{/* Header */}

Importar Arquivo .properties

Importe propriedades Java de um arquivo .properties

{/* Basic Info */} Informações Básicas
setConfigMapName(e.target.value)} />
{/* File Upload */} Arquivo .properties