From 7d703832ab33cfa12a5d8854aed4146f430bbab6 Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Thu, 9 Jul 2026 22:45:17 +0000 Subject: [PATCH] fix: Add token editing, DDNS record management, wildcard display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dashboard: - Cloudflare token can be changed when already configured (was only editable when missing/invalid) - DDNS records can be added and removed inline (was read-only) Services: - Wildcard services display as *.domain instead of domain with a separate subdomains badge — clearer at a glance Co-Authored-By: Claude Opus 4.6 (1M context) --- web/src/components/DashboardComponent.tsx | 82 +++++++++++++++++++++-- web/src/components/ServicesComponent.tsx | 5 +- 2 files changed, 77 insertions(+), 10 deletions(-) diff --git a/web/src/components/DashboardComponent.tsx b/web/src/components/DashboardComponent.tsx index 6270d65..6d3d446 100644 --- a/web/src/components/DashboardComponent.tsx +++ b/web/src/components/DashboardComponent.tsx @@ -7,7 +7,7 @@ import { Alert, AlertDescription } from './ui/alert'; import { Badge } from './ui/badge'; import { LayoutDashboard, Cloud, CheckCircle, XCircle, AlertCircle, Loader2, - RefreshCw, BookOpen, Globe, Shield, Router, Server, RotateCw, Key, + RefreshCw, BookOpen, Globe, Shield, Router, Server, RotateCw, Key, Plus, X, } from 'lucide-react'; import { useCloudflare } from '../hooks/useCloudflare'; import { useDdns } from '../hooks/useDdns'; @@ -23,7 +23,7 @@ export function DashboardComponent() { const { verification, isLoading: cfLoading } = useCloudflare(); const { status: ddnsStatus, isLoadingStatus: ddnsLoading, trigger: triggerDdns, isTriggering } = useDdns(); const { status: certStatus } = useCert(); - const { config: globalConfig } = useConfig(); + const { config: globalConfig, updateConfig } = useConfig(); const queryClient = useQueryClient(); const { data: globalSecrets } = useQuery({ @@ -36,6 +36,8 @@ export function DashboardComponent() { const [editingToken, setEditingToken] = useState(false); const [tokenValue, setTokenValue] = useState(''); + const [addingDdnsRecord, setAddingDdnsRecord] = useState(false); + const [newDdnsRecord, setNewDdnsRecord] = useState(''); const updateSecretsMutation = useMutation({ mutationFn: (values: Record) => secretsApi.update(values), @@ -168,6 +170,29 @@ export function DashboardComponent() { )} + {!editingToken ? ( + + ) : ( +
+ setTokenValue(e.target.value)} + /> +
+ + +
+
+ )} ) : (
@@ -249,13 +274,13 @@ export function DashboardComponent() {
- {/* Record list */} + {/* Record list with remove buttons */} {globalConfig?.cloud?.ddns?.records?.length ? (
- {globalConfig.cloud.ddns.records.map((r) => { - const rs: DdnsRecordStatus | undefined = ddnsStatus.records?.find(s => s.name === r); + {globalConfig.cloud.ddns.records.map((r: string) => { + const rs: DdnsRecordStatus | undefined = ddnsStatus.records?.find((s: DdnsRecordStatus) => s.name === r); return ( -
+
{rs?.ok ? ( ) : rs && !rs.ok ? ( @@ -270,12 +295,57 @@ export function DashboardComponent() { {rs && !rs.ok && rs.error && ( {rs.error} )} +
); })}
) : null} + {/* Add DDNS record */} + {!addingDdnsRecord ? ( + + ) : ( +
+ setNewDdnsRecord(e.target.value)} + placeholder="dev.payne.io" + className="h-8 text-xs font-mono flex-1" + /> + + +
+ )} +