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
This commit is contained in:
parent
25b504c901
commit
d7e0b97ff4
3 changed files with 71 additions and 0 deletions
|
|
@ -7,6 +7,7 @@ import { requireSession } from "@/lib/auth/session";
|
|||
import { logActivity } from "@/app/actions/activity";
|
||||
import { positionBetween } from "@/lib/ordering/fractional";
|
||||
import { nextCardNumber } from "@/lib/cards/number";
|
||||
import { relinkProject } from "@/lib/linking/engine";
|
||||
import type { CardRecord, ColumnRecord } from "@/lib/pb/types";
|
||||
|
||||
/**
|
||||
|
|
@ -109,6 +110,10 @@ export async function updateCard(input: {
|
|||
|
||||
await pb.collection("cards").update(input.cardId, patch);
|
||||
|
||||
if (input.scopeRule !== undefined) {
|
||||
await relinkProject(card.project);
|
||||
}
|
||||
|
||||
// One row per field, matching how client edits are logged, so the timeline
|
||||
// reads consistently regardless of who made the change.
|
||||
for (const field of Object.keys(patch)) {
|
||||
|
|
@ -172,6 +177,8 @@ export async function acceptCard(input: {
|
|||
position: positionBetween(last ? last.position : null, null),
|
||||
});
|
||||
|
||||
await relinkProject(card.project);
|
||||
|
||||
await logActivity({
|
||||
project: card.project,
|
||||
card: card.id,
|
||||
|
|
@ -195,6 +202,8 @@ export async function archiveCard(input: {
|
|||
|
||||
await pb.collection("cards").update(input.cardId, { archived: true });
|
||||
|
||||
await relinkProject(card.project);
|
||||
|
||||
await logActivity({
|
||||
project: card.project,
|
||||
card: card.id,
|
||||
|
|
@ -217,6 +226,8 @@ export async function unarchiveCard(input: {
|
|||
|
||||
await pb.collection("cards").update(input.cardId, { archived: false });
|
||||
|
||||
await relinkProject(card.project);
|
||||
|
||||
await logActivity({
|
||||
project: card.project,
|
||||
card: card.id,
|
||||
|
|
|
|||
54
src/app/actions/linking.ts
Normal file
54
src/app/actions/linking.ts
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
"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`);
|
||||
}
|
||||
|
|
@ -168,6 +168,12 @@ export async function ingestProject(
|
|||
.collection("projects")
|
||||
.update(project.id, { last_ingest_at: new Date().toISOString() });
|
||||
|
||||
// New commits mean new links. Doing this here rather than in each caller
|
||||
// means the webhook, the poll and the backfill all get it, and none of them
|
||||
// has to remember.
|
||||
const { relinkProject } = await import("@/lib/linking/engine");
|
||||
await relinkProject(project.id);
|
||||
|
||||
return { created, skipped, pagesRead: page };
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue