export type CheckCategory = 'lint' | 'specs' | 'e2e' | 'other'; export type CategoryState = 'fail' | 'running' | 'pending' | 'pass' | 'skipped' | 'none'; export interface CheckInfo { name: string; state: CategoryState; url: string | null; } export interface CategoryStatus { category: CheckCategory; state: CategoryState; passed: number; /** Non-skipped check count (drives the "7/9" chip summary). */ total: number; checks: CheckInfo[]; } export type ReviewState = 'no_review' | 'outstanding' | 'addressed'; export interface ReviewerVerdict { reviewer: string; state: 'APPROVED' | 'CHANGES_REQUESTED'; url: string; submittedAt: string; } export interface PrSnapshot { id: string; repo: string; number: number; title: string; url: string; author: string; isDraft: boolean; /** GitHub's merge-conflict state; UNKNOWN while GitHub is still computing it. */ mergeable: 'MERGEABLE' | 'CONFLICTING' | 'UNKNOWN'; branch: string; updatedAt: string; labels: string[]; /** Per-PR review environment, when the repo configures one and the label matches. */ previewUrl: string | null; reviewState: ReviewState; unresolvedThreads: number; totalThreads: number; verdicts: ReviewerVerdict[]; categories: CategoryStatus[]; } export type TimelineKind = 'issue_comment' | 'review_comment' | 'review'; export interface TimelineEvent { id: string; prId: string; repo: string; prNumber: number; prTitle: string; kind: TimelineKind; actor: string; createdAt: string; bodyExcerpt: string; url: string; reviewState: string | null; path: string | null; read: boolean; /** Trailing lines of the diff hunk a review comment is anchored to. */ diffHunk: string | null; /** Set when this is a reply within a review thread: the thread's root comment. */ inReplyTo: { actor: string; bodyExcerpt: string } | null; } export interface SpecFailure { path: string; line: number | null; name: string; message: string; } export interface FailureReportSummary { key: string; label: string; failed: number; truncated: boolean; } export interface FailureReport extends FailureReportSummary { fetchedAt: string; failures: SpecFailure[]; } export interface StatePayload { /** The configured GitHub login this dashboard belongs to. */ user: string; prs: PrSnapshot[]; lastSyncAt: string | null; lastSyncError: string | null; unreadCountsByPr: Record; unreadTotal: number; failuresByPr: Record; } export interface TimelinePage { events: TimelineEvent[]; nextCursor: string | null; } export interface SyncEventPayload { lastSyncAt: string | null; error: string | null; changedPrIds: string[]; newEventCount: number; unreadCount: number; }