Backend — GET /api/v1/dashboard (single authenticated request):
Aggregates repos, open PRs, review queue, open issues server-side Per-repo PR and issue counts computed in one pass Review queue pulls PRs where the user is an assigned reviewer (from pr_reviewers table), excluding their own PRs Frontend — complete redesign of DashboardPage.tsx: Section What it shows Stats bar Repo count · My PRs · Reviews awaiting · Open issues — each a clickable nav pill ⌘K Command palette Fuzzy search across repos, PRs, issues with keyboard nav (↑↓ / Enter / Esc), quick-nav shortcuts when empty Needs attention Only appears when review queue is non-empty; badges each PR as "Review requested" My pull requests Open PRs I authored, with source→target branch, repo context, relative timestamp My open issues Issues I filed, linked to the repo issue list Workspaces My repos, prioritising recently visited (from useRecentRepos), with PR/issue count badges CI/CD Honest placeholder until pipeline integration lands Quick actions New repo · Import · Explore · Settings — always one click away Empty state Shows only when user has zero repos
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { z } from 'zod'
|
||||
import { api } from '../client'
|
||||
|
||||
const statsSchema = z.object({
|
||||
repoCount: z.number(),
|
||||
openPRs: z.number(),
|
||||
reviewQueue: z.number(),
|
||||
openIssues: z.number(),
|
||||
})
|
||||
|
||||
const dashPRSchema = z.object({
|
||||
id: z.number(),
|
||||
title: z.string(),
|
||||
sourceBranch: z.string(),
|
||||
targetBranch: z.string(),
|
||||
status: z.string(),
|
||||
createdAt: z.string(),
|
||||
updatedAt: z.string(),
|
||||
repoId: z.number(),
|
||||
repoName: z.string(),
|
||||
ownerName: z.string(),
|
||||
authorId: z.number(),
|
||||
})
|
||||
|
||||
const dashIssueSchema = z.object({
|
||||
id: z.number(),
|
||||
number: z.number(),
|
||||
title: z.string(),
|
||||
state: z.string(),
|
||||
createdAt: z.string(),
|
||||
updatedAt: z.string(),
|
||||
repoId: z.number(),
|
||||
repoName: z.string(),
|
||||
ownerName: z.string(),
|
||||
})
|
||||
|
||||
const dashRepoSchema = z.object({
|
||||
id: z.number(),
|
||||
name: z.string(),
|
||||
description: z.string(),
|
||||
isPrivate: z.boolean(),
|
||||
defaultBranch: z.string(),
|
||||
updatedAt: z.string(),
|
||||
ownerName: z.string(),
|
||||
avatarUrl: z.string(),
|
||||
openPrCount: z.number(),
|
||||
openIssueCount: z.number(),
|
||||
})
|
||||
|
||||
const dashboardSchema = z.object({
|
||||
stats: statsSchema,
|
||||
reviewQueue: z.array(dashPRSchema),
|
||||
myOpenPRs: z.array(dashPRSchema),
|
||||
myOpenIssues: z.array(dashIssueSchema),
|
||||
repos: z.array(dashRepoSchema),
|
||||
})
|
||||
|
||||
export type DashboardData = z.infer<typeof dashboardSchema>
|
||||
export type DashPR = z.infer<typeof dashPRSchema>
|
||||
export type DashIssue = z.infer<typeof dashIssueSchema>
|
||||
export type DashRepo = z.infer<typeof dashRepoSchema>
|
||||
|
||||
export function useDashboard() {
|
||||
return useQuery({
|
||||
queryKey: ['dashboard'],
|
||||
queryFn: () => api.get<DashboardData>('/api/v1/dashboard', dashboardSchema),
|
||||
refetchInterval: 60_000,
|
||||
staleTime: 30_000,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user