feat(issues): S4b frontend — open-issues lists + issue plumbing
- 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/<id>, project + status). - SystemsSection.vue (project Systems tab): 'Open issues' list via getProjectIssues, with system chips, links to /tasks/<id>. 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) <noreply@anthropic.com>
This commit is contained in:
@@ -13,10 +13,12 @@ interface ActiveProject {
|
||||
interface DoneItem { id: number; title: string; project_title: string | null; completed_at: string }
|
||||
interface UpcomingEvent { id: number; title: string; start_dt: string | null; all_day: boolean }
|
||||
interface WeekStats { completed_this_week: number; open_total: number; in_progress: number; active_plans: number }
|
||||
interface IssueRow { id: number; title: string; status: string; priority: string; project_id: number | null; project_title: string | null }
|
||||
interface DashboardData {
|
||||
active_projects: ActiveProject[];
|
||||
recently_completed: DoneItem[];
|
||||
upcoming_events: UpcomingEvent[];
|
||||
open_issues: IssueRow[];
|
||||
week_stats: WeekStats;
|
||||
}
|
||||
|
||||
@@ -29,7 +31,7 @@ onMounted(async () => {
|
||||
try {
|
||||
data.value = await apiGet<DashboardData>("/api/dashboard");
|
||||
} catch {
|
||||
data.value = { active_projects: [], recently_completed: [], upcoming_events: [], week_stats: { completed_this_week: 0, open_total: 0, in_progress: 0, active_plans: 0 } };
|
||||
data.value = { active_projects: [], recently_completed: [], upcoming_events: [], open_issues: [], week_stats: { completed_this_week: 0, open_total: 0, in_progress: 0, active_plans: 0 } };
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
@@ -132,6 +134,22 @@ function fmtEvent(e: UpcomingEvent): string {
|
||||
|
||||
<!-- Right rail -->
|
||||
<aside class="dash-rail">
|
||||
<template v-if="data.open_issues.length">
|
||||
<div class="dash-label">⚠ Open issues</div>
|
||||
<div class="rail-card issues-card">
|
||||
<router-link
|
||||
v-for="i in data.open_issues"
|
||||
:key="i.id"
|
||||
:to="`/tasks/${i.id}`"
|
||||
class="issue-row"
|
||||
>
|
||||
<span class="issue-mark" :class="`imk-${i.status}`">{{ i.status === 'in_progress' ? '▸' : '○' }}</span>
|
||||
<span class="issue-title">{{ i.title }}</span>
|
||||
<span class="issue-meta">{{ i.project_title || '—' }}</span>
|
||||
</router-link>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="dash-label">Upcoming · 7 days</div>
|
||||
<div class="rail-card">
|
||||
<template v-if="data.upcoming_events.length">
|
||||
@@ -240,5 +258,13 @@ function fmtEvent(e: UpcomingEvent): string {
|
||||
.qa-btn { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: 8px; padding: 6px 12px; font-size: 0.82rem; color: var(--color-text); text-decoration: none; }
|
||||
.qa-btn:hover { border-color: var(--color-primary); color: var(--color-primary); }
|
||||
|
||||
.issues-card { display: flex; flex-direction: column; gap: 0.1rem; padding: 0.4rem 0.45rem; }
|
||||
.issue-row { display: flex; align-items: center; gap: 0.5rem; padding: 0.35rem 0.4rem; border-radius: 7px; text-decoration: none; color: var(--color-text); font-size: 0.85rem; }
|
||||
.issue-row:hover { background: var(--color-hover); }
|
||||
.issue-mark { color: var(--color-muted); flex-shrink: 0; }
|
||||
.issue-mark.imk-in_progress { color: var(--color-primary); }
|
||||
.issue-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.issue-meta { font-size: 0.72rem; color: var(--color-muted); white-space: nowrap; flex-shrink: 0; }
|
||||
|
||||
@media (max-width: 760px) { .dash-cols { flex-direction: column; } }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user