From 444612fc555a661683d104daa5b71a962bcdef89 Mon Sep 17 00:00:00 2001 From: Dave Date: Wed, 16 Sep 2026 13:24:57 +0200 Subject: [PATCH] feat(linking): unassigned commit tray with manual attachment --- src/app/p/[clientSlug]/[projectSlug]/page.tsx | 8 ++ .../[projectSlug]/unassigned/page.tsx | 70 +++++++++++ src/components/linking/unassigned-list.tsx | 117 ++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 src/app/p/[clientSlug]/[projectSlug]/unassigned/page.tsx create mode 100644 src/components/linking/unassigned-list.tsx diff --git a/src/app/p/[clientSlug]/[projectSlug]/page.tsx b/src/app/p/[clientSlug]/[projectSlug]/page.tsx index ca8f23f..2464120 100644 --- a/src/app/p/[clientSlug]/[projectSlug]/page.tsx +++ b/src/app/p/[clientSlug]/[projectSlug]/page.tsx @@ -35,6 +35,14 @@ export default async function BoardPage({ > Archive + {session.role === "owner" && ( + + Unassigned + + )} ; +}) { + const session = await getSession(); + if (!session) redirect("/login"); + if (session.role !== "owner") notFound(); + + const { clientSlug, projectSlug } = await params; + const board = await loadBoard(clientSlug, projectSlug); + if (!board) notFound(); + + const pb = await getServerPb(); + + const commits = await pb.collection("commits").getFullList({ + filter: `project = "${board.project.id}" && card = "" && is_merge = false`, + sort: "-authored_at", + }); + + const cards: CardOption[] = board.cards + .filter((card) => !card.archived) + .sort((a, b) => a.number - b.number) + .map((card) => ({ id: card.id, number: card.number, title: card.title })); + + const boardHref = `/p/${clientSlug}/${projectSlug}`; + + return ( + + + +
+ + + Back to board + + + +
+
+ ); +} \ No newline at end of file diff --git a/src/components/linking/unassigned-list.tsx b/src/components/linking/unassigned-list.tsx new file mode 100644 index 0000000..3f53a6e --- /dev/null +++ b/src/components/linking/unassigned-list.tsx @@ -0,0 +1,117 @@ +"use client"; + +import { useState, useTransition } from "react"; +import { RefreshCw } from "lucide-react"; + +import { linkCommitAction, relinkProjectAction } from "@/app/actions/linking"; +import { relativeTime } from "@/lib/time/relative"; +import { Pill } from "@/components/ui/pill"; +import type { CommitRecord } from "@/lib/pb/types"; + +export interface CardOption { + id: string; + number: number; + title: string; +} + +export function UnassignedList({ + projectId, + commits, + cards, + clientSlug, + projectSlug, +}: { + projectId: string; + commits: CommitRecord[]; + cards: CardOption[]; + clientSlug: string; + projectSlug: string; +}) { + const [pending, startTransition] = useTransition(); + const [status, setStatus] = useState(null); + + return ( +
+
+ + {status && {status}} +
+ + {commits.length === 0 ? ( +

+ Every commit is attached to a card. +

+ ) : ( +
    + {commits.map((commit) => ( +
  • +
    +

    + {commit.subject || commit.short_sha} +

    +

    + {commit.short_sha} + {relativeTime(commit.authored_at)} + {commit.type && commit.type !== "other" && ( + {commit.type} + )} + {commit.scope && {commit.scope}} +

    +
    + + +
  • + ))} +
+ )} +
+ ); +} \ No newline at end of file