feat(libs): create library by name only; root_path derived server-side as BOOKS_DIR/SafeName(name), validated at creation; drop root_path input from admin UI; align changelogs to bilingual template; trim AGENTS.md to rules not derivable from repo layout

This commit is contained in:
2026-09-07 21:56:59 +08:00
parent ca64bc0d73
commit 45eefd6741
9 changed files with 80 additions and 146 deletions
+5 -8
View File
@@ -9,15 +9,13 @@ export default function AdminLibraries() {
const qc = useQueryClient();
const libsQ = useQuery({ queryKey: ["libraries"], queryFn: api.listLibraries });
const [name, setName] = useState("");
const [root, setRoot] = useState("");
const fileRefs = useRef<Record<number, HTMLInputElement | null>>({});
const create = useMutation({
mutationFn: () => api.createLibrary(name.trim(), root.trim()),
mutationFn: () => api.createLibrary(name.trim()),
onSuccess: (lib) => {
toast("ok", `库「${lib.name}」已创建`);
setName("");
setRoot("");
void qc.invalidateQueries({ queryKey: ["libraries"] });
},
onError: (e) => toast("err", e instanceof Error ? e.message : "建库失败"),
@@ -54,14 +52,13 @@ export default function AdminLibraries() {
<div className="flex-1 overflow-y-auto p-4">
<h1 className="mb-4 text-lg font-semibold">库管理</h1>
<form onSubmit={submit} className={`${card} mb-6 flex max-w-2xl flex-wrap items-center gap-3 p-4`}>
<input className={input} placeholder="库名(如 comics)" value={name} onChange={(e) => setName(e.target.value)} />
<input
className={input + " flex-1"}
placeholder="root_path(服务端绝对路径,须位于 BOOKS_DIR 下,如 /data/books/comics)"
value={root}
onChange={(e) => setRoot(e.target.value)}
placeholder="库名(如 comics,服务端目录自动落在 BOOKS_DIR/<库名> 下)"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<button className={btnPrimary} disabled={create.isPending || !name.trim() || !root.startsWith("/")}>
<button className={btnPrimary} disabled={create.isPending || !name.trim()}>
{create.isPending ? "创建中…" : "建库"}
</button>
</form>