From ee65f2238deb9880155d627a7caaaf7c3bd12257 Mon Sep 17 00:00:00 2001 From: Dave Date: Wed, 16 Sep 2026 16:25:58 +0200 Subject: [PATCH] feat(admin): manual narrative generation --- src/app/actions/narrative.ts | 31 ++++++++++++++++++++++++++ src/components/admin/summary-panel.tsx | 19 +++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 src/app/actions/narrative.ts diff --git a/src/app/actions/narrative.ts b/src/app/actions/narrative.ts new file mode 100644 index 0000000..d79f6ae --- /dev/null +++ b/src/app/actions/narrative.ts @@ -0,0 +1,31 @@ +"use server"; + +import { revalidatePath } from "next/cache"; + +import { requireSession } from "@/lib/auth/session"; +import { narrateProject } from "@/lib/ai/narrate"; + +/** See the security note at the top of src/app/actions/cards.ts. */ +export async function narrateProjectAction(input: { + projectId: string; +}): Promise<{ written: number; message: string }> { + const session = await requireSession(); + if (session.role !== "owner") throw new Error("Not found"); + + const result = await narrateProject(input.projectId); + revalidatePath(`/admin/projects/${input.projectId}`); + + if (result.skipped) { + return { written: 0, message: result.error ?? "No AI provider is configured." }; + } + if (result.considered === 0) { + return { written: 0, message: "Every narrative is up to date." }; + } + + return { + written: result.written, + message: `${result.written} of ${result.considered} narratives written${ + result.error ? ` · ${result.error}` : "" + }`, + }; +} diff --git a/src/components/admin/summary-panel.tsx b/src/components/admin/summary-panel.tsx index d1a161d..e05cc41 100644 --- a/src/components/admin/summary-panel.tsx +++ b/src/components/admin/summary-panel.tsx @@ -1,12 +1,13 @@ "use client"; import { useState, useTransition } from "react"; -import { Sparkles, RotateCcw } from "lucide-react"; +import { Sparkles, RotateCcw, BookText } from "lucide-react"; import { retryFailedSummariesAction, summariseProjectAction, } from "@/app/actions/summarise"; +import { narrateProjectAction } from "@/app/actions/narrative"; export function SummaryPanel({ projectId, @@ -83,6 +84,22 @@ export function SummaryPanel({ )} + + {message && {message}}