Replace state blob with resource-oriented API endpoints

Split /api/v1/state into dedicated resource endpoints:
- /api/v1/operator, /api/v1/central-domain
- /api/v1/ddns/config, /api/v1/dns/settings
- /api/v1/dhcp/config (moved from /dnsmasq/dhcp/)
- /api/v1/nftables/config, /api/v1/haproxy/routes

Each page now talks to its own resource instead of deep-merging
a blob. Removes useConfig hook, CentralState type, and legacy
config methods.
This commit is contained in:
2026-07-10 22:45:36 +00:00
parent 79c0c32b98
commit 79f38d2750
12 changed files with 528 additions and 335 deletions

View File

@@ -12,9 +12,8 @@ import {
import { useCloudflare } from '../hooks/useCloudflare';
import { useDdns } from '../hooks/useDdns';
import { useCentralStatus } from '../hooks/useCentralStatus';
import { useConfig } from '../hooks';
import { useVpn } from '../hooks/useVpn';
import { secretsApi } from '../services/api';
import { secretsApi, dnsSettingsApi, nftablesConfigApi } from '../services/api';
import { usePageHelp } from '../hooks/usePageHelp';
import type { DdnsRecordStatus } from '../services/api/networking';
@@ -22,8 +21,9 @@ export function DashboardComponent() {
const { data: centralStatus, isLoading: statusLoading, restart: restartDaemon, isRestarting } = useCentralStatus();
const { verification, isLoading: cfLoading } = useCloudflare();
const { status: ddnsStatus, isLoadingStatus: ddnsLoading, trigger: triggerDdns, isTriggering } = useDdns();
const { config: globalConfig } = useConfig();
const { config: vpnConfig } = useVpn();
const { data: dnsSettings } = useQuery({ queryKey: ['dns', 'settings'], queryFn: () => dnsSettingsApi.get() });
const { data: nftConfig } = useQuery({ queryKey: ['nftables', 'config'], queryFn: () => nftablesConfigApi.get() });
const queryClient = useQueryClient();
const { data: globalSecrets } = useQuery({
@@ -379,9 +379,9 @@ export function DashboardComponent() {
<ul className="list-disc list-inside space-y-1 text-xs">
<li>
Set the router's DNS server to Wild Central
{globalConfig?.cloud?.dnsmasq?.ip && (
{dnsSettings?.ip && (
<span className="font-mono bg-muted px-1.5 py-0.5 rounded ml-1">
{globalConfig.cloud.dnsmasq.ip}
{dnsSettings.ip}
</span>
)}
</li>
@@ -391,7 +391,7 @@ export function DashboardComponent() {
{ port: 443, proto: 'TCP', label: 'HTTPS' },
{ port: 80, proto: 'TCP', label: 'HTTP' },
...(vpnConfig?.enabled ? [{ port: vpnConfig.listenPort || 51820, proto: 'UDP', label: 'VPN' }] : []),
...((globalConfig?.cloud?.nftables?.extraPorts ?? []) as { port: number; protocol?: string; label?: string }[])
...((nftConfig?.extraPorts ?? []) as { port: number; protocol?: string; label?: string }[])
.map(ep => ({ port: ep.port, proto: (ep.protocol || 'tcp').toUpperCase(), label: ep.label || '' })),
].map((p, i) => (
<span key={i}>