Add publisher dashboard routes
All checks were successful
buildbot/nix-eval Build done.
buildbot/nix-build Build done.
buildbot/nix-effects Build done.

This commit is contained in:
Abel Luck 2026-06-02 10:18:59 +02:00
parent 96551c2788
commit e4a5246ab3
31 changed files with 1603 additions and 516 deletions

View file

@ -98,27 +98,27 @@ def admin_sidebar(
h.nav(class_="mt-8 space-y-2")[
nav_link(
label="Dashboard",
href="/",
active=current_path == "/",
href="/admin",
active=current_path == "/admin",
badge="Live",
),
nav_link(
label="Sources",
href="/sources",
active=current_path.startswith("/sources"),
href="/admin/sources",
active=current_path.startswith("/admin/sources"),
badge=str(source_count),
),
nav_link(
label="Runs",
href="/runs",
active=current_path.startswith("/runs")
or current_path.startswith("/job/"),
href="/admin/runs",
active=current_path.startswith("/admin/runs")
or current_path.startswith("/admin/job/"),
badge=str(running_count),
),
nav_link(
label="Settings",
href="/settings",
active=current_path.startswith("/settings"),
href="/admin/settings",
active=current_path.startswith("/admin/settings"),
badge="App",
),
],
@ -148,11 +148,18 @@ def header_secondary_link(*, href: str, label: str) -> Renderable:
)[label]
def muted_action_link(*, href: str, label: str) -> Renderable:
return h.a(
href=href,
class_=_button_classes(tone="muted", emphasis="soft"),
)[label]
def muted_action_link(
*, href: str, label: str, target: str | None = None, rel: str | None = None
) -> Renderable:
attributes = {
"href": href,
"class": _button_classes(tone="muted", emphasis="soft"),
}
if target is not None:
attributes["target"] = target
if rel is not None:
attributes["rel"] = rel
return h.a(attributes)[label]
def inline_link(*, href: str, label: str, tone: str = "default") -> Renderable:
@ -225,6 +232,15 @@ def app_shell(
]
def publisher_shell(*, current_path: str, content: Node) -> Renderable:
del current_path
return h.main(id="morph", class_="min-h-screen")[
h.div(class_="px-4 py-4 sm:px-4 lg:px-5 lg:py-4")[
h.div(class_="mx-auto max-w-7xl space-y-4")[content]
],
]
def page_shell(
*,
current_path: str,
@ -269,7 +285,7 @@ def section_card(*, content: Node) -> Renderable:
def table_section(
*,
eyebrow: str | None = None,
title: str,
title: str | None,
subtitle: str | None = None,
empty_message: str,
headers: tuple[str, ...],
@ -315,8 +331,16 @@ def table_section(
)[empty_message]
]
has_heading = (
eyebrow is not None
or title is not None
or subtitle is not None
or actions is not None
)
return h.section[
h.div(
has_heading
and h.div(
class_="flex flex-col gap-2.5 sm:flex-row sm:items-end sm:justify-between"
)[
h.div[
@ -324,13 +348,18 @@ def table_section(
and h.p(
class_="text-xs font-semibold uppercase tracking-[0.22em] text-amber-600"
)[eyebrow],
h.h2(class_="mt-1 text-xl font-semibold text-slate-950")[title],
title
and h.h2(class_="mt-1 text-xl font-semibold text-slate-950")[title],
subtitle and h.p(class_="mt-1 text-sm text-slate-600")[subtitle],
],
actions,
],
h.div(
class_="mt-3 overflow-hidden rounded-2xl bg-white shadow-sm ring-1 ring-slate-200"
class_=(
"overflow-hidden rounded-2xl bg-white shadow-sm ring-1 ring-slate-200"
if not has_heading
else "mt-3 overflow-hidden rounded-2xl bg-white shadow-sm ring-1 ring-slate-200"
)
)[
h.div(class_="overflow-x-auto")[
h.table(