From cd6a51f5555a65dfb168df4d0884088baeb3cd8c Mon Sep 17 00:00:00 2001 From: alphaeusmote <41258468-alphaeusmote@users.noreply.replit.com> Date: Thu, 10 Apr 2025 16:11:40 +0000 Subject: [PATCH] Enhance domain details display and add auto IP address option. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 9111ef36-26c8-4085-84ca-a35dc1fec1b5 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7083d608-d6d3-4a6a-9a27-6286c5109627/047afec0-aed8-488c-9dff-5c38706fcc42.jpg --- .../src/components/domain/domain-details.tsx | 182 ++-- .../components/domain/domain-details.tsx.new | 970 ------------------ 2 files changed, 93 insertions(+), 1059 deletions(-) delete mode 100644 client/src/components/domain/domain-details.tsx.new diff --git a/client/src/components/domain/domain-details.tsx b/client/src/components/domain/domain-details.tsx index 4a53588..eb98c64 100644 --- a/client/src/components/domain/domain-details.tsx +++ b/client/src/components/domain/domain-details.tsx @@ -372,11 +372,11 @@ export function DomainDetails({ domain, onBack }: DomainDetailsProps) { - {record.content} + {record.isAutoIP ? "Auto IP" : record.content} -

{record.content}

+

{record.isAutoIP ? "Auto IP" : record.content}

{record.notes && ( <>
@@ -396,7 +396,7 @@ export function DomainDetails({ domain, onBack }: DomainDetailsProps) { {record.isActive ? ( - Active + Active ) : ( Inactive )} @@ -547,26 +547,51 @@ export function DomainDetails({ domain, onBack }: DomainDetailsProps) { )} /> - ( - - Content - - - - - {form.watch("type") === "A" && "IP address (e.g. 192.168.1.1)"} - {form.watch("type") === "AAAA" && "IPv6 address"} - {form.watch("type") === "CNAME" && "Domain name (e.g. example.com)"} - {form.watch("type") === "MX" && "Mail server (e.g. mail.example.com)"} - {form.watch("type") === "TXT" && "Text content"} - - - - )} - /> + {(form.watch("type") === "A" || form.watch("type") === "AAAA") && ( + ( + +
+ Auto IP Address + + Automatically determine IP address using STUN + +
+ + + +
+ )} + /> + )} + + {(!form.watch("isAutoIP") || (form.watch("type") !== "A" && form.watch("type") !== "AAAA")) && ( + ( + + Content + + + + + {form.watch("type") === "A" && "IP address (e.g. 192.168.1.1)"} + {form.watch("type") === "AAAA" && "IPv6 address"} + {form.watch("type") === "CNAME" && "Domain name (e.g. example.com)"} + {form.watch("type") === "MX" && "Mail server (e.g. mail.example.com)"} + {form.watch("type") === "TXT" && "Text content"} + + + + )} + /> + )} - {(form.watch("type") === "A" || form.watch("type") === "AAAA") && ( - ( - -
- Auto IP Address - - Automatically determine IP address using STUN - -
- - - -
- )} - /> - )} - - ( - - Content - - - - - {form.watch("type") === "A" && "IP address (e.g. 192.168.1.1)"} - {form.watch("type") === "AAAA" && "IPv6 address"} - {form.watch("type") === "CNAME" && "Domain name (e.g. example.com)"} - {form.watch("type") === "MX" && "Mail server (e.g. mail.example.com)"} - {form.watch("type") === "TXT" && "Text content"} - - - - )} - /> + {(form.watch("type") === "A" || form.watch("type") === "AAAA") && ( + ( + +
+ Auto IP Address + + Automatically determine IP address using STUN + +
+ + + +
+ )} + /> + )} + + {(!form.watch("isAutoIP") || (form.watch("type") !== "A" && form.watch("type") !== "AAAA")) && ( + ( + + Content + + + + + {form.watch("type") === "A" && "IP address (e.g. 192.168.1.1)"} + {form.watch("type") === "AAAA" && "IPv6 address"} + {form.watch("type") === "CNAME" && "Domain name (e.g. example.com)"} + {form.watch("type") === "MX" && "Mail server (e.g. mail.example.com)"} + {form.watch("type") === "TXT" && "Text content"} + + + + )} + /> + )} - {(form.watch("type") === "A" || form.watch("type") === "AAAA") && ( - ( - -
- Auto IP Address - - Automatically determine IP address using STUN - -
- - - -
- )} - /> - )} - { - // Content is required if isAutoIP is false - if (!data.isAutoIP && (!data.content || data.content.trim() === '')) { - return false; - } - return true; -}, { - message: "Content is required when Auto IP is disabled", - path: ["content"] -}); - -interface DomainDetailsProps { - domain: Domain; - onBack?: () => void; -} - -export function DomainDetails({ domain, onBack }: DomainDetailsProps) { - const { toast } = useToast(); - - const [isAddRecordDialogOpen, setIsAddRecordDialogOpen] = useState(false); - const [isEditRecordDialogOpen, setIsEditRecordDialogOpen] = useState(false); - const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false); - const [selectedRecord, setSelectedRecord] = useState(null); - const [currentPage, setCurrentPage] = useState(1); - const pageSize = 5; - - // Fetch providers for the form - const { data: providers = [] } = useQuery({ - queryKey: ["/api/providers"], - }); - - // Fetch DNS Records - const { - data: records = [], - isLoading - } = useQuery({ - queryKey: ["/api/dns-records", domain.id], - queryFn: async () => { - const res = await apiRequest("GET", `/api/dns-records?domainId=${domain.id}`); - return await res.json(); - }, - enabled: !!domain?.id, - }); - - // Form for adding/editing a record - const form = useForm>({ - resolver: zodResolver(dnsRecordSchema), - defaultValues: { - name: "", - type: "A", - content: "", - ttl: 3600, - proxied: false, - isActive: true, - isAutoIP: false, - notes: "", - providerId: undefined, - }, - }); - - // Add record mutation - const addRecordMutation = useMutation({ - mutationFn: async (data: z.infer) => { - // Prepare record data - const recordData: InsertDnsRecord = { - ...data, - domainId: domain.id, - }; - - // Handle providerId - convert "none" to null - if (recordData.providerId === "none") { - recordData.providerId = null; - } - - const res = await apiRequest("POST", "/api/dns-records", recordData); - return await res.json(); - }, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ["/api/dns-records", domain.id] }); - setIsAddRecordDialogOpen(false); - form.reset(); - toast({ - title: "Record added", - description: "The DNS record has been successfully added.", - }); - }, - onError: (error) => { - toast({ - title: "Failed to add record", - description: error.message, - variant: "destructive", - }); - }, - }); - - // Update record mutation - const updateRecordMutation = useMutation({ - mutationFn: async (data: z.infer & { id: string }) => { - const { id, ...updateData } = data; - - // Handle providerId - convert "none" to null - if (updateData.providerId === "none") { - updateData.providerId = null; - } - - const res = await apiRequest("PUT", `/api/dns-records/${id}`, updateData); - return await res.json(); - }, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ["/api/dns-records", domain.id] }); - setIsEditRecordDialogOpen(false); - setSelectedRecord(null); - toast({ - title: "Record updated", - description: "The DNS record has been successfully updated.", - }); - }, - onError: (error) => { - toast({ - title: "Failed to update record", - description: error.message, - variant: "destructive", - }); - }, - }); - - // Delete record mutation - const deleteRecordMutation = useMutation({ - mutationFn: async (recordId: string) => { - await apiRequest("DELETE", `/api/dns-records/${recordId}`); - }, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ["/api/dns-records", domain.id] }); - setIsDeleteDialogOpen(false); - setSelectedRecord(null); - toast({ - title: "Record deleted", - description: "The DNS record has been successfully deleted.", - }); - }, - onError: (error) => { - toast({ - title: "Failed to delete record", - description: error.message, - variant: "destructive", - }); - }, - }); - - // Form submission handlers - const onAddSubmit = (data: z.infer) => { - addRecordMutation.mutate(data); - }; - - const onEditSubmit = (data: z.infer) => { - if (selectedRecord) { - updateRecordMutation.mutate({ ...data, id: selectedRecord.id }); - } - }; - - // Handle record editing - const handleEditRecord = (record: DnsRecord) => { - setSelectedRecord(record); - - // Set form values for editing - form.reset({ - name: record.name, - type: record.type, - content: record.content, - ttl: record.ttl, - proxied: record.proxied, - isActive: record.isActive, - isAutoIP: record.isAutoIP, - notes: record.notes || "", - providerId: record.providerId || "none", - }); - - setIsEditRecordDialogOpen(true); - }; - - // Handle record deletion - const handleDeleteRecord = (record: DnsRecord) => { - setSelectedRecord(record); - setIsDeleteDialogOpen(true); - }; - - // Confirm deletion - const confirmDeleteRecord = () => { - if (selectedRecord) { - deleteRecordMutation.mutate(selectedRecord.id); - } - }; - - // Get a human-readable provider name from the provider ID - const getProviderName = (providerId: string | null) => { - if (!providerId) return "None"; - const provider = providers.find(p => p.id === providerId); - return provider ? provider.name : "Unknown Provider"; - }; - - // Calculate pagination - const startIndex = (currentPage - 1) * pageSize; - const endIndex = startIndex + pageSize; - const paginatedRecords = records.slice(startIndex, endIndex); - const totalPages = Math.ceil(records.length / pageSize); - - // Handle adding a new record - const handleAddRecord = () => { - // Reset form with defaults - form.reset({ - name: "", - type: "A", - content: "", - ttl: 3600, - proxied: false, - isActive: true, - isAutoIP: false, - notes: "", - providerId: "none", - }); - setIsAddRecordDialogOpen(true); - }; - - if (isLoading) { - return ( -
- -
- ); - } - - return ( - <> -
-

DNS Records for {domain.name}

- -
- - {records.length === 0 ? ( -
-
- -
-

No DNS records found

-

- Get started by adding your first DNS record. -

-
- -
-
- ) : ( -
-
- - - - Name - Type - Content - TTL - Provider - Last Update - Status - Actions - - - - {paginatedRecords.map(record => ( - - - {record.name === "@" ? ( - - - - {record.name} - - -

Root domain: {domain.name}

-
-
-
- ) : ( - record.name - )} -
- - {record.type} - - - - - - - {record.isAutoIP ? "Auto IP" : record.content} - - - -

{record.isAutoIP ? "Auto IP" : record.content}

- {record.notes && ( - <> -
-

{record.notes}

- - )} -
-
-
-
- {record.ttl}s - {getProviderName(record.providerId)} - - {record.lastUpdated - ? formatDistanceToNow(new Date(record.lastUpdated), { addSuffix: true }) - : "Never"} - - - {record.isActive ? ( - Active - ) : ( - Inactive - )} - - -
- - -
-
-
- ))} -
-
-
- - {records.length > pageSize && ( -
- -
- )} -
- )} - -
- - - Recent Activity - - - - - -
- - {/* Add Record Dialog */} - - - - Add DNS Record - - Add a new DNS record to {domain.name}. - - - -
- - ( - - Name - - - - - Use @ for root domain or enter subdomain name - - - - )} - /> - - ( - - DNS Provider - - - Select the DNS provider to use for this record - - - - )} - /> - - ( - - Record Type - - - - )} - /> - - {(form.watch("type") === "A" || form.watch("type") === "AAAA") && ( - ( - -
- Auto IP Address - - Automatically determine IP address using STUN - -
- - - -
- )} - /> - )} - - {(!form.watch("isAutoIP") || (form.watch("type") !== "A" && form.watch("type") !== "AAAA")) && ( - ( - - Content - - - - - {form.watch("type") === "A" && "IP address (e.g. 192.168.1.1)"} - {form.watch("type") === "AAAA" && "IPv6 address"} - {form.watch("type") === "CNAME" && "Domain name (e.g. example.com)"} - {form.watch("type") === "MX" && "Mail server (e.g. mail.example.com)"} - {form.watch("type") === "TXT" && "Text content"} - - - - )} - /> - )} - - ( - - TTL (seconds) - - field.onChange(parseInt(e.target.value || "3600"))} - /> - - - Time-to-live in seconds. 3600 = 1 hour - - - - )} - /> - - ( - -
- Proxied - - Enable proxying through CDN (Cloudflare only) - -
- - - -
- )} - /> - - ( - -
- Active - - Enable this record to be used - -
- - - -
- )} - /> - - ( - - Notes - - - - - Add any additional information about this record - - - - )} - /> - - - - - - -
-
- - {/* Edit Record Dialog */} - - - - Edit DNS Record - - Update the DNS record for {domain.name}. - - - -
- - ( - - Name - - - - - Use @ for root domain or enter subdomain name - - - - )} - /> - - ( - - DNS Provider - - - Select the DNS provider to use for this record - - - - )} - /> - - ( - - Record Type - - - - )} - /> - - {(form.watch("type") === "A" || form.watch("type") === "AAAA") && ( - ( - -
- Auto IP Address - - Automatically determine IP address using STUN - -
- - - -
- )} - /> - )} - - {(!form.watch("isAutoIP") || (form.watch("type") !== "A" && form.watch("type") !== "AAAA")) && ( - ( - - Content - - - - - {form.watch("type") === "A" && "IP address (e.g. 192.168.1.1)"} - {form.watch("type") === "AAAA" && "IPv6 address"} - {form.watch("type") === "CNAME" && "Domain name (e.g. example.com)"} - {form.watch("type") === "MX" && "Mail server (e.g. mail.example.com)"} - {form.watch("type") === "TXT" && "Text content"} - - - - )} - /> - )} - - ( - - TTL (seconds) - - field.onChange(parseInt(e.target.value || "3600"))} - /> - - - Time-to-live in seconds. 3600 = 1 hour - - - - )} - /> - - ( - -
- Proxied - - Enable proxying through CDN (Cloudflare only) - -
- - - -
- )} - /> - - ( - -
- Active - - Enable this record to be used - -
- - - -
- )} - /> - - ( - - Notes - - - - - Add any additional information about this record - - - - )} - /> - - - - - - -
-
- - {/* Delete Confirmation Dialog */} - - - - Are you sure? - - This will permanently delete the DNS record {selectedRecord?.name} of type {selectedRecord?.type}. - This action cannot be undone. - - - - Cancel - - {deleteRecordMutation.isPending ? ( - <> - - Deleting... - - ) : ( - "Delete" - )} - - - - - - ); -} \ No newline at end of file