From 086fc8fc49439de147d96d5feb58e09f2a20733a Mon Sep 17 00:00:00 2001
From: null
Date: Sun, 24 May 2026 19:52:50 -0500
Subject: [PATCH] =?UTF-8?q?Assign=20Agent=20no=20longer=20strands=20you=20?=
=?UTF-8?q?at=20=E2=80=9CRepository=20not=20linked=20to=20any=20board.?=
=?UTF-8?q?=E2=80=9D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../components/git/AssignIssueAgentDialog.tsx | 112 ++++++++++++++++--
1 file changed, 104 insertions(+), 8 deletions(-)
diff --git a/frontend/src/components/git/AssignIssueAgentDialog.tsx b/frontend/src/components/git/AssignIssueAgentDialog.tsx
index 7720bbf..5bead7b 100644
--- a/frontend/src/components/git/AssignIssueAgentDialog.tsx
+++ b/frontend/src/components/git/AssignIssueAgentDialog.tsx
@@ -8,6 +8,10 @@ import {
useListAgentsApiV1AgentsGet,
type listAgentsApiV1AgentsGetResponse,
} from "@/api/generated/agents/agents";
+import {
+ useListBoardsApiV1BoardsGet,
+ type listBoardsApiV1BoardsGetResponse,
+} from "@/api/generated/boards/boards";
import { ApiError } from "@/api/mutator";
import {
Dialog,
@@ -20,7 +24,11 @@ import {
import { Button } from "@/components/ui/button";
import { Textarea } from "@/components/ui/textarea";
import type { ForgejoIssue, AssignIssueAgentResponse } from "@/lib/api-forgejo";
-import { assignIssueToAgent, getLinkedBoardsForRepository } from "@/lib/api-forgejo";
+import {
+ assignIssueToAgent,
+ getLinkedBoardsForRepository,
+ linkBoardForgejoRepository,
+} from "@/lib/api-forgejo";
type LinkedBoard = { id: string; name: string };
@@ -74,6 +82,8 @@ export function AssignIssueAgentDialog({
const [linkedBoards, setLinkedBoards] = useState([]);
const [boardsLoading, setBoardsLoading] = useState(false);
const [linkedBoardsLoaded, setLinkedBoardsLoaded] = useState(false);
+ const [linkBoardId, setLinkBoardId] = useState("");
+ const [isLinkingRepository, setIsLinkingRepository] = useState(false);
// Fetch only boards linked to this issue's repository — prevents picking a
// board that the backend will reject with "not linked to any board".
@@ -110,10 +120,31 @@ export function AssignIssueAgentDialog({
{ query: { enabled: open && !!boardId, refetchOnMount: "always" } },
);
+ const boardsQuery = useListBoardsApiV1BoardsGet<
+ listBoardsApiV1BoardsGetResponse,
+ ApiError
+ >(
+ { limit: 200 },
+ {
+ query: {
+ enabled:
+ open &&
+ linkedBoardsLoaded &&
+ !boardsLoading &&
+ linkedBoards.length === 0,
+ refetchOnMount: "always",
+ },
+ },
+ );
+
const agents =
agentsQuery.data?.status === 200
? (agentsQuery.data.data.items ?? [])
: [];
+ const allBoards =
+ boardsQuery.data?.status === 200
+ ? (boardsQuery.data.data.items ?? [])
+ : [];
useEffect(() => {
if (!open) {
@@ -124,6 +155,8 @@ export function AssignIssueAgentDialog({
setStartImmediately(true);
setError(null);
setLinkedBoardsLoaded(false);
+ setLinkBoardId("");
+ setIsLinkingRepository(false);
}
}, [open]);
@@ -164,6 +197,32 @@ export function AssignIssueAgentDialog({
}
};
+ const handleLinkRepositoryToBoard = async () => {
+ if (!issue || !linkBoardId) return;
+ setIsLinkingRepository(true);
+ setError(null);
+
+ try {
+ await linkBoardForgejoRepository(linkBoardId, issue.repository_id);
+ const linkedBoard = allBoards.find((board) => board.id === linkBoardId);
+ const nextBoard = {
+ id: linkBoardId,
+ name: linkedBoard?.name ?? "Selected board",
+ };
+ setLinkedBoards([nextBoard]);
+ setBoardId(nextBoard.id);
+ setLinkBoardId("");
+ } catch (err) {
+ setError(
+ err instanceof Error
+ ? err.message
+ : "Failed to link repository to board",
+ );
+ } finally {
+ setIsLinkingRepository(false);
+ }
+ };
+
const toggleSwitch = (
value: boolean,
setter: (v: boolean) => void,
@@ -227,13 +286,50 @@ export function AssignIssueAgentDialog({
use its Git Project repositories panel, or manage tracked
repositories first.
-
- Manage Git repositories
-
-
+
+
+
+ {boardsQuery.isError ? (
+
+ Unable to load boards. You can still manage repositories
+ from Git Projects.
+
+ ) : null}
+
+
+
+
+ Manage Git repositories
+
+
+
) : (
<>