From 94d32c524a0f7f132efd7c6dfd7f5cfb44fa3329 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Sun, 14 Jun 2026 10:50:41 -0400 Subject: [PATCH] =?UTF-8?q?feat(issues):=20S4b=20frontend=20=E2=80=94=20op?= =?UTF-8?q?en-issues=20lists=20+=20issue=20plumbing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - types/note.ts: Note gains systems? + arose_from_id?; TaskKind includes 'issue'. - stores/tasks.ts: create/update accept IssueFields (kind/system_ids/arose_from_id). - api/systems.ts: getProjectIssues + TaskLike. - DashboardView.vue: 'Open issues' rail section from dashboard.open_issues (links to /tasks/, project + status). - SystemsSection.vue (project Systems tab): 'Open issues' list via getProjectIssues, with system chips, links to /tasks/. Both reuse existing CSS tokens. Issue-editor controls (kind selector / system multi-select / arose-from picker in WorkspaceTaskPanel) are the remaining S4b piece. NEEDS operator browser verification (CI typechecks only). Refs plan 825 (S4b frontend — lists). Co-Authored-By: Claude Opus 4.8 (1M context) --- frontend/src/api/systems.ts | 20 ++++++++++++ frontend/src/components/SystemsSection.vue | 37 +++++++++++++++++++++- frontend/src/stores/tasks.ts | 14 ++++++-- frontend/src/types/note.ts | 7 +++- frontend/src/views/DashboardView.vue | 28 +++++++++++++++- 5 files changed, 101 insertions(+), 5 deletions(-) diff --git a/frontend/src/api/systems.ts b/frontend/src/api/systems.ts index 5206f58..1fa194d 100644 --- a/frontend/src/api/systems.ts +++ b/frontend/src/api/systems.ts @@ -42,3 +42,23 @@ export async function updateSystem( export async function deleteSystem(projectId: number, systemId: number): Promise { return apiDelete(`/api/projects/${projectId}/systems/${systemId}`); } + +// Lightweight issue shape returned by the project-issues list endpoint. +export interface TaskLike { + id: number; + title: string; + status: string; + priority: string; + systems?: System[]; + updated_at?: string | null; +} + +export async function getProjectIssues( + projectId: number, + openOnly = true, +): Promise { + const data = await apiGet<{ issues: TaskLike[] }>( + `/api/projects/${projectId}/issues?open_only=${openOnly}`, + ); + return data.issues; +} diff --git a/frontend/src/components/SystemsSection.vue b/frontend/src/components/SystemsSection.vue index 75ce89e..46ebb2a 100644 --- a/frontend/src/components/SystemsSection.vue +++ b/frontend/src/components/SystemsSection.vue @@ -2,7 +2,8 @@ import { ref, computed, onMounted, watch } from "vue"; import { useSystemsStore } from "@/stores/systems"; import { useToastStore } from "@/stores/toast"; -import type { System } from "@/api/systems"; +import { getProjectIssues } from "@/api/systems"; +import type { System, TaskLike } from "@/api/systems"; import { Pencil, Trash2, Archive, ArchiveRestore } from "lucide-vue-next"; const props = defineProps<{ projectId: number }>(); @@ -12,6 +13,7 @@ const toast = useToastStore(); const error = ref(null); const showArchived = ref(false); +const issues = ref([]); // Create state const showCreate = ref(false); @@ -42,6 +44,11 @@ async function load() { } catch { error.value = "Failed to load systems."; } + try { + issues.value = await getProjectIssues(props.projectId); + } catch { + issues.value = []; + } } onMounted(load); @@ -138,6 +145,22 @@ async function confirmDelete() {