import { useState } from 'react' import { CircleHelp } from 'lucide-react' import type { ProxyHost } from '../api/proxyHosts' import { useRemoteServers } from '../hooks/useRemoteServers' import { useDomains } from '../hooks/useDomains' import { useDocker } from '../hooks/useDocker' interface ProxyHostFormProps { host?: ProxyHost onSubmit: (data: Partial) => Promise onCancel: () => void } export default function ProxyHostForm({ host, onSubmit, onCancel }: ProxyHostFormProps) { const [formData, setFormData] = useState({ domain_names: host?.domain_names || '', forward_scheme: host?.forward_scheme || 'http', forward_host: host?.forward_host || '', forward_port: host?.forward_port || 80, ssl_forced: host?.ssl_forced ?? false, http2_support: host?.http2_support ?? false, hsts_enabled: host?.hsts_enabled ?? false, hsts_subdomains: host?.hsts_subdomains ?? false, block_exploits: host?.block_exploits ?? true, websocket_support: host?.websocket_support ?? true, advanced_config: host?.advanced_config || '', enabled: host?.enabled ?? true, }) const { servers: remoteServers } = useRemoteServers() const { domains } = useDomains() const [connectionSource, setConnectionSource] = useState<'local' | 'custom' | string>('custom') const [selectedDomain, setSelectedDomain] = useState('') // Fetch containers based on selected source // If 'local', host is undefined (which defaults to local socket in backend) // If remote UUID, we need to find the server and get its host address? // Actually, the backend ListContainers takes a 'host' query param. // If it's a remote server, we should probably pass the UUID or the host address. // Looking at backend/internal/services/docker_service.go, it takes a 'host' string. // If it's a remote server, we need to pass the TCP address (e.g. tcp://1.2.3.4:2375). const getDockerHostString = () => { if (connectionSource === 'local') return undefined; if (connectionSource === 'custom') return null; const server = remoteServers.find(s => s.uuid === connectionSource); if (!server) return null; // Construct the Docker host string return `tcp://${server.host}:${server.port}`; } const { containers: dockerContainers, isLoading: dockerLoading, error: dockerError } = useDocker(getDockerHostString()) const [loading, setLoading] = useState(false) const [error, setError] = useState(null) const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() setLoading(true) setError(null) try { await onSubmit(formData) } catch (err) { setError(err instanceof Error ? err.message : 'Failed to save proxy host') } finally { setLoading(false) } } const handleContainerSelect = (containerId: string) => { const container = dockerContainers.find(c => c.id === containerId) if (container) { // Prefer internal IP if available, otherwise use container name const host = container.ip || container.names[0] // Use the first exposed port if available, otherwise default to 80 const port = container.ports && container.ports.length > 0 ? container.ports[0].private_port : 80 let newDomainNames = formData.domain_names if (selectedDomain) { const subdomain = container.names[0].replace(/^\//, '') newDomainNames = `${subdomain}.${selectedDomain}` } setFormData({ ...formData, forward_host: host, forward_port: port, forward_scheme: 'http', domain_names: newDomainNames, }) } } return (

{host ? 'Edit Proxy Host' : 'Add Proxy Host'}

{error && (
{error}
)} {/* Domain Names */}
{domains.length > 0 && (
)}
setFormData({ ...formData, domain_names: e.target.value })} placeholder="example.com, www.example.com" className="w-full bg-gray-900 border border-gray-700 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-blue-500" />
{/* Docker Container Quick Select */}
{dockerError && connectionSource !== 'custom' && (

Failed to connect: {(dockerError as Error).message}

)}
{/* Forward Details */}
setFormData({ ...formData, forward_host: e.target.value })} placeholder="192.168.1.100" className="w-full bg-gray-900 border border-gray-700 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-blue-500" />
setFormData({ ...formData, forward_port: parseInt(e.target.value) })} className="w-full bg-gray-900 border border-gray-700 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-blue-500" />
{/* SSL & Security Options */}
{/* Advanced Config */}