feat: add dnsmasq DNS record admin UI

- store records in SQLite via built-in node:sqlite, no native deps
- wrap DB reads in await io() so they stay out of the static shell
- add CRUD pages backed by Server Actions with per-request data
- generate managed config and restart container via Docker socket
- add /resolve page to query dnsmasq for A and CNAME records
- add Dockerfile and compose setup with shared config volume
This commit is contained in:
siujamo committed 2026-10-09 16:47:31 +08:00
1 parent c5585f2b13
commit 97ad09ad8a
27 files changed
+1344 -130

No files matched your search

+41
View File
@@ -0,0 +1,41 @@
import { notFound } from "next/navigation"
import { Suspense } from "react"
import { getRecord } from "@/lib/records"
import { RecordForm } from "../../_components/RecordForm"
import { updateRecordAction } from "../../actions"
export const metadata = { title: "编辑记录" }
export default function EditRecordPage({ params }: PageProps<"/records/[id]">) {
return (
<section className="space-y-6">
<h1 className="text-xl font-semibold text-zinc-900 dark:text-zinc-100">编辑记录</h1>
{/* params are awaited inside Suspense so the shell can still be prerendered */}
<Suspense fallback={<p className="text-sm text-zinc-500 dark:text-zinc-400">加载中…</p>}>
<EditRecordForm params={params} />
</Suspense>
</section>
)
}
async function EditRecordForm({ params }: Pick<PageProps<"/records/[id]">, "params">) {
const { id } = await params
const numericId = Number(id)
// Guard against /records/abc: Number() would hand NaN to SQLite.
if (!Number.isInteger(numericId) || numericId <= 0) notFound()
const record = await getRecord(numericId)
if (!record) notFound()
return (
<RecordForm
action={updateRecordAction}
record={record}
submitLabel="保存修改"
cancelHref="/records"
/>
)
}