diff --git a/openflare_server/web/features/proxy-routes/components/domain-list-input.tsx b/openflare_server/web/features/proxy-routes/components/domain-list-input.tsx index dc1ec49e..a4788e0b 100644 --- a/openflare_server/web/features/proxy-routes/components/domain-list-input.tsx +++ b/openflare_server/web/features/proxy-routes/components/domain-list-input.tsx @@ -1,15 +1,23 @@ 'use client'; import { useId, useMemo } from 'react'; +import { Minus, Plus } from 'lucide-react'; +import type { TlsCertificateItem } from '@/features/tls-certificates/types'; import { ResourceInput, + ResourceSelect, SecondaryButton, } from '@/features/shared/components/resource-primitives'; +export type DomainListRow = { + domain: string; + certificateId: string; +}; -function splitDomainRows(value: string) { - const rows = value.split(/\r?\n/); - return rows.length > 0 ? rows : ['']; +const actionButtonClassName = 'h-12 w-[72px] shrink-0 rounded-2xl px-0'; + +function ensureRows(rows: DomainListRow[]) { + return rows.length > 0 ? rows : [{ domain: '', certificateId: '' }]; } function buildSuggestionSources(domains: string[]) { @@ -32,7 +40,11 @@ function buildSuggestionSources(domains: string[]) { return Array.from(values); } -function buildDomainSuggestions(input: string, sources: string[], rows: string[]) { +function buildDomainSuggestions( + input: string, + sources: string[], + rows: DomainListRow[], +) { const normalizedInput = input.trim().toLowerCase(); if (!normalizedInput) { return []; @@ -40,7 +52,7 @@ function buildDomainSuggestions(input: string, sources: string[], rows: string[] const existingDomains = new Set( rows - .map((row) => row.trim().toLowerCase()) + .map((row) => row.domain.trim().toLowerCase()) .filter((row) => row && row !== normalizedInput), ); const suggestions: string[] = []; @@ -72,114 +84,171 @@ function buildDomainSuggestions(input: string, sources: string[], rows: string[] }); } +export function buildDomainRowsFromRoute( + domains: string[], + certIDs: number[], +): DomainListRow[] { + if (domains.length === 0) { + return ensureRows([]); + } + + if (certIDs.length === 0) { + return domains.map((domain) => ({ domain, certificateId: '' })); + } + + if (certIDs.length === 1) { + return domains.map((domain) => ({ + domain, + certificateId: String(certIDs[0]), + })); + } + + return domains.map((domain, index) => ({ + domain, + certificateId: certIDs[index] ? String(certIDs[index]) : '', + })); +} + export function DomainListInput({ - value, + rows, onChange, onBlur, suggestionSources = [], - placeholder = 'app.example.com', + certificates = [], + domainPlaceholder = 'app.example.com', }: { - value: string; - onChange: (value: string) => void; + rows: DomainListRow[]; + onChange: (rows: DomainListRow[]) => void; onBlur?: () => void; suggestionSources?: string[]; - placeholder?: string; + certificates?: TlsCertificateItem[]; + domainPlaceholder?: string; }) { const listId = useId(); - const rows = splitDomainRows(value); + const safeRows = ensureRows(rows); const normalizedSources = useMemo( () => buildSuggestionSources(suggestionSources), [suggestionSources], ); - const updateRows = (nextRows: string[]) => { - onChange(nextRows.join('\n')); + const updateRows = (nextRows: DomainListRow[]) => { + onChange(ensureRows(nextRows)); }; return ( -