SPB Git
10.7 KB · 30 lines tsx
1import { taxonomy } from "@/lib/admin/queries";2import { requireUserPage } from "@/lib/auth/guard";3import { csrfToken } from "@/lib/auth/session";4import { taxonomyAction } from "@/lib/admin/actions";5import { Check, Csrf, Field, Notice, PageTitle, Select } from "@/components/admin-ui";6export default async function Taxonomy({ searchParams }: { searchParams: Promise<Record<string, string | undefined>> }) {7  const sp = await searchParams; const u = await requireUserPage(); const csrf = csrfToken(u); const tax = await taxonomy();8  const Del = ({ kind, id }: { kind: string; id: number }) => <form action={taxonomyAction} className="inline"><Csrf token={csrf} /><input type="hidden" name="kind" value={kind} /><input type="hidden" name="op" value="delete" /><input type="hidden" name="id" value={id} /><button className="text-bad text-xs">delete</button></form>;9  return (<div><PageTitle title="Taxonomy" /><Notice sp={sp} /><p className="meta mb-6">Authors, research domains and topics, methods, datasets and series. Editing a name updates every paper that uses it. Deleting a topic/method/dataset removes its assignments; authors with papers cannot be deleted.</p>10    <div className="grid xl:grid-cols-2 gap-6">11      <section className="card p-4"><h2 className="text-lg mb-2">Authors ({tax.authors.length})</h2>12        {tax.authors.map((a) => <details key={a.id} className="border-b border-line py-2"><summary className="text-sm flex justify-between"><span>{a.display_name}{a.is_primary ? <span className="chip chip-navy ml-2">primary</span> : null}</span><Del kind="author" id={a.id} /></summary>13          <form action={taxonomyAction} className="grid sm:grid-cols-2 gap-2 mt-2 text-sm"><Csrf token={csrf} /><input type="hidden" name="kind" value="author" /><input type="hidden" name="id" value={a.id} /><Field label="Given name" name="given_name" value={a.given_name} required /><Field label="Family name" name="family_name" value={a.family_name} required /><Field label="Display name" name="display_name" value={a.display_name} /><Field label="Slug" name="slug" value={a.slug} /><Field label="ORCID" name="orcid" value={a.orcid} /><Field label="E-mail" name="email" value={a.email} /><Field label="Website" name="website" value={a.website} /><Field label="Google Scholar" name="google_scholar" value={a.google_scholar} /><Field label="SSRN author URL" name="ssrn_url" value={a.ssrn_url} /><Field label="GitHub" name="github" value={a.github} /><Field label="Affiliation (EN)" name="affiliation_en" value={a.affiliation_en} /><Field label="Affiliation (FR)" name="affiliation_fr" value={a.affiliation_fr} /><Field label="Department (EN)" name="department_en" value={a.department_en} /><Field label="Department (FR)" name="department_fr" value={a.department_fr} /><Field label="Bio (EN)" name="bio_en" value={a.bio_en} rows={3} /><Field label="Bio (FR)" name="bio_fr" value={a.bio_fr} rows={3} /><Check label="Primary author of the observatory (excluded from co-author links)" name="is_primary" checked={a.is_primary} /><Field label="Sort" name="sort" type="number" value={a.sort} /><button className="btn btn-sm justify-self-start">Save</button></form></details>)}14        <details className="py-2"><summary className="text-sm text-navy">+ New author</summary><form action={taxonomyAction} className="grid sm:grid-cols-2 gap-2 mt-2 text-sm"><Csrf token={csrf} /><input type="hidden" name="kind" value="author" /><Field label="Given name" name="given_name" required /><Field label="Family name" name="family_name" required /><Field label="ORCID" name="orcid" /><Field label="Affiliation (EN)" name="affiliation_en" /><Field label="Affiliation (FR)" name="affiliation_fr" /><Field label="Website" name="website" /><button className="btn btn-sm justify-self-start">Create</button></form></details></section>15      <section className="card p-4"><h2 className="text-lg mb-2">Domains and topics ({tax.topics.length})</h2>16        {tax.topics.map((t) => <details key={t.id} className="border-b border-line py-2"><summary className="text-sm flex justify-between"><span>{t.kind === "domain" ? "◆ " : ""}{t.name_en} <span className="text-fg-3">· {t.n}</span></span><Del kind="topic" id={t.id} /></summary>17          <form action={taxonomyAction} className="grid sm:grid-cols-2 gap-2 mt-2 text-sm"><Csrf token={csrf} /><input type="hidden" name="kind" value="topic" /><input type="hidden" name="id" value={t.id} /><Field label="Name (EN)" name="name_en" value={t.name_en} required /><Field label="Name (FR)" name="name_fr" value={t.name_fr} /><Field label="Slug" name="slug" value={t.slug} /><Select label="Kind" name="topic_kind" value={t.kind} options={[{ v: "domain", label: "Research domain" }, { v: "topic", label: "Topic" }]} /><Field label="Description (EN)" name="description_en" value={t.description_en} rows={2} /><Field label="Description (FR)" name="description_fr" value={t.description_fr} rows={2} /><Field label="Accent colour" name="accent" value={t.accent} /><Field label="Sort" name="sort" type="number" value={t.sort} /><button className="btn btn-sm justify-self-start">Save</button></form></details>)}18        <details className="py-2"><summary className="text-sm text-navy">+ New domain or topic</summary><form action={taxonomyAction} className="grid sm:grid-cols-2 gap-2 mt-2 text-sm"><Csrf token={csrf} /><input type="hidden" name="kind" value="topic" /><Field label="Name (EN)" name="name_en" required /><Field label="Name (FR)" name="name_fr" /><Select label="Kind" name="topic_kind" value="topic" options={[{ v: "domain", label: "Research domain" }, { v: "topic", label: "Topic" }]} /><Field label="Accent colour" name="accent" /><button className="btn btn-sm justify-self-start">Create</button></form></details></section>19      <section className="card p-4"><h2 className="text-lg mb-2">Methods ({tax.methods.length})</h2>20        {tax.methods.map((m) => <details key={m.id} className="border-b border-line py-2"><summary className="text-sm flex justify-between"><span>{m.name_en} <span className="text-fg-3">· {m.category} · {m.n}</span></span><Del kind="method" id={m.id} /></summary><form action={taxonomyAction} className="grid sm:grid-cols-2 gap-2 mt-2 text-sm"><Csrf token={csrf} /><input type="hidden" name="kind" value="method" /><input type="hidden" name="id" value={m.id} /><Field label="Name (EN)" name="name_en" value={m.name_en} required /><Field label="Name (FR)" name="name_fr" value={m.name_fr} /><Field label="Slug" name="slug" value={m.slug} /><Field label="Category" name="category" value={m.category} /><Field label="Description (EN)" name="description_en" value={m.description_en} rows={2} /><Field label="Description (FR)" name="description_fr" value={m.description_fr} rows={2} /><button className="btn btn-sm justify-self-start">Save</button></form></details>)}21        <details className="py-2"><summary className="text-sm text-navy">+ New method</summary><form action={taxonomyAction} className="grid sm:grid-cols-2 gap-2 mt-2 text-sm"><Csrf token={csrf} /><input type="hidden" name="kind" value="method" /><Field label="Name (EN)" name="name_en" required /><Field label="Name (FR)" name="name_fr" /><Field label="Category" name="category" value="general" /><button className="btn btn-sm justify-self-start">Create</button></form></details></section>22      <section className="card p-4"><h2 className="text-lg mb-2">Datasets ({tax.datasets.length})</h2>23        {tax.datasets.map((d) => <details key={d.id} className="border-b border-line py-2"><summary className="text-sm flex justify-between"><span>{d.name_en} <span className="text-fg-3">· {d.n}</span></span><Del kind="dataset" id={d.id} /></summary><form action={taxonomyAction} className="grid sm:grid-cols-2 gap-2 mt-2 text-sm"><Csrf token={csrf} /><input type="hidden" name="kind" value="dataset" /><input type="hidden" name="id" value={d.id} /><Field label="Name (EN)" name="name_en" value={d.name_en} required /><Field label="Name (FR)" name="name_fr" value={d.name_fr} /><Field label="Slug" name="slug" value={d.slug} /><Field label="Provider" name="provider" value={d.provider} /><Field label="Coverage" name="coverage" value={d.coverage} /><Field label="Frequency" name="frequency" value={d.frequency} /><Field label="Access conditions" name="access_conditions" value={d.access_conditions} /><Field label="License" name="license" value={d.license} /><Field label="URL" name="url" value={d.url} /><Check label="Publicly available" name="is_public" checked={d.is_public} /><Field label="Description (EN)" name="description_en" value={d.description_en} rows={2} /><Field label="Description (FR)" name="description_fr" value={d.description_fr} rows={2} /><button className="btn btn-sm justify-self-start">Save</button></form></details>)}24        <details className="py-2"><summary className="text-sm text-navy">+ New dataset</summary><form action={taxonomyAction} className="grid sm:grid-cols-2 gap-2 mt-2 text-sm"><Csrf token={csrf} /><input type="hidden" name="kind" value="dataset" /><Field label="Name (EN)" name="name_en" required /><Field label="Name (FR)" name="name_fr" /><Field label="Provider" name="provider" /><Field label="Access conditions" name="access_conditions" /><Check label="Publicly available" name="is_public" /><button className="btn btn-sm justify-self-start">Create</button></form></details></section>25      <section className="card p-4 xl:col-span-2"><h2 className="text-lg mb-2">Series ({tax.series.length})</h2>26        {tax.series.map((s) => <details key={s.id} className="border-b border-line py-2"><summary className="text-sm">{s.code} — {s.name_en}</summary><form action={taxonomyAction} className="grid sm:grid-cols-3 gap-2 mt-2 text-sm"><Csrf token={csrf} /><input type="hidden" name="kind" value="series" /><input type="hidden" name="id" value={s.id} /><Field label="Code" name="code" value={s.code} required /><Field label="Name (EN)" name="name_en" value={s.name_en} required /><Field label="Name (FR)" name="name_fr" value={s.name_fr} /><Field label="Slug" name="slug" value={s.slug} /><Field label="ISSN" name="issn" value={s.issn} /><Field label="Sort" name="sort" type="number" value={s.sort} /><Field label="Description (EN)" name="description_en" value={s.description_en} rows={2} className="sm:col-span-3" /><Field label="Description (FR)" name="description_fr" value={s.description_fr} rows={2} className="sm:col-span-3" /><button className="btn btn-sm justify-self-start">Save</button></form></details>)}27        <details className="py-2"><summary className="text-sm text-navy">+ New series</summary><form action={taxonomyAction} className="grid sm:grid-cols-3 gap-2 mt-2 text-sm"><Csrf token={csrf} /><input type="hidden" name="kind" value="series" /><Field label="Code (e.g. TN)" name="code" required /><Field label="Name (EN)" name="name_en" required /><Field label="Name (FR)" name="name_fr" /><button className="btn btn-sm justify-self-start">Create</button></form></details></section>28    </div></div>);29}30
Files · main
Menu

Theme