kanban-dev-webapp/src/app/actions/linking.ts
Dave d7e0b97ff4 feat(linking): re-link on ingest and on card rule changes
- ingestProject now calls relinkProject after every store
- updateCard relinks when scopeScope rule is in the patch
- acceptCard, archiveCard, unlinkCommitArchiveCard relink after their change
- three owner Server Actions for the tray: relinkProjectAction, linkCommitAction, unlinkCommitAction
2026-09-16 13:24:17 +02:00

54 lines
No EOL
1.4 KiB
TypeScript

"use server";
import { revalidatePath } from "next/cache";
import { requireSession } from "@/lib/auth/session";
import {
linkCommitManually,
relinkProject,
unlinkCommit,
} from "@/lib/linking/engine";
/** See the security note at the top of src/app/actions/cards.ts. */
async function requireOwner() {
const session = await requireSession();
if (session.role !== "owner") throw new Error("Not found");
return session;
}
export async function relinkProjectAction(input: {
projectId: string;
clientSlug: string;
projectSlug: string;
}): Promise<{ linked: number; unlinked: number; preserved: number }> {
await requireOwner();
const result = await relinkProject(input.projectId);
revalidatePath(`/p/${input.clientSlug}/${input.projectSlug}/unassigned`);
return {
linked: result.linked,
unlinked: result.unlinked,
preserved: result.preserved,
};
}
export async function linkCommitAction(input: {
commitId: string;
cardId: string;
clientSlug: string;
projectSlug: string;
}): Promise<void> {
await requireOwner();
await linkCommitManually(input.commitId, input.cardId);
revalidatePath(`/p/${input.clientSlug}/${input.projectSlug}/unassigned`);
}
export async function unlinkCommitAction(input: {
commitId: string;
clientSlug: string;
projectSlug: string;
}): Promise<void> {
await requireOwner();
await unlinkCommit(input.commitId);
revalidatePath(`/p/${input.clientSlug}/${input.projectSlug}/unassigned`);
}