Files
mission-control/src/lib/types.ts
teernisse 175c1994fc feat: implement Inbox view with triage actions
- Add InboxItem types and TriageAction/DeferDuration types
- Create Inbox component with:
  - Accept/Defer/Archive actions for each item
  - Keyboard shortcuts (A/D/X) for fast triage
  - Defer duration picker popup
  - Inbox Zero celebration state
  - Type-specific badges with colors
- Add comprehensive tests for all functionality

Closes bd-qvc

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-26 10:08:54 -05:00

166 lines
4.3 KiB
TypeScript

/**
* TypeScript types mirroring the Rust backend data structures.
*
* These are used by the IPC layer and components to maintain
* type safety across the Tauri boundary.
*/
// -- Backend response types (match Rust structs in commands/mod.rs) --
export interface LoreStatus {
last_sync: string | null;
is_healthy: boolean;
message: string;
summary: LoreSummaryStatus | null;
}
export interface LoreSummaryStatus {
open_issues: number;
authored_mrs: number;
reviewing_mrs: number;
}
export interface BridgeStatus {
mapping_count: number;
pending_count: number;
suspect_count: number;
last_sync: string | null;
last_reconciliation: string | null;
}
export interface SyncResult {
created: number;
closed: number;
skipped: number;
/** Number of suspect_orphan flags cleared (item reappeared) */
healed: number;
/** Error messages from non-fatal errors during sync */
errors: string[];
}
// -- Structured error types (match Rust error.rs) --
/** Error codes for programmatic handling */
export type McErrorCode =
| "LORE_UNAVAILABLE"
| "LORE_UNHEALTHY"
| "LORE_FETCH_FAILED"
| "BRIDGE_LOCKED"
| "BRIDGE_MAP_CORRUPTED"
| "BRIDGE_SYNC_FAILED"
| "BEADS_UNAVAILABLE"
| "BEADS_CREATE_FAILED"
| "BEADS_CLOSE_FAILED"
| "IO_ERROR"
| "INTERNAL_ERROR";
/** Structured error from Tauri IPC commands */
export interface McError {
code: McErrorCode;
message: string;
recoverable: boolean;
}
/** Type guard to check if an error is a structured McError */
export function isMcError(err: unknown): err is McError {
return (
typeof err === "object" &&
err !== null &&
"code" in err &&
"message" in err &&
"recoverable" in err
);
}
/** Result from the quick_capture command */
export interface CaptureResult {
bead_id: string;
}
// -- Frontend-only types --
/** The type of work item surfaced in the Focus View */
export type FocusItemType = "mr_review" | "issue" | "mr_authored" | "manual";
/** A single work item that can be THE ONE THING */
export interface FocusItem {
/** Unique key matching bridge mapping (e.g., "mr_review:g/p:847") */
id: string;
/** Human-readable title */
title: string;
/** Type badge to display */
type: FocusItemType;
/** Project path (e.g., "platform/core") */
project: string;
/** URL to open in browser (GitLab link) */
url: string;
/** Entity IID (e.g., MR !847, Issue #42) */
iid: number;
/** ISO timestamp of last update */
updatedAt: string | null;
/** Optional context quote (e.g., reviewer comment) */
contextQuote: string | null;
/** Who is requesting attention */
requestedBy: string | null;
}
/** Action the user takes on a focused item */
export type FocusAction = "start" | "defer_1h" | "defer_tomorrow" | "skip";
/** An entry in the decision log */
export interface DecisionEntry {
timestamp: string;
action: FocusAction;
itemId: string;
reason: string | null;
}
/** Staleness level derived from item age */
export type Staleness = "fresh" | "normal" | "amber" | "urgent";
// -- Inbox types --
/** Type of work item in the inbox */
export type InboxItemType = "mention" | "mr_feedback" | "review_request" | "assignment" | "manual";
/** A work item awaiting triage in the inbox */
export interface InboxItem {
/** Unique identifier */
id: string;
/** Human-readable title */
title: string;
/** Type of inbox item */
type: InboxItemType;
/** Whether this item has been triaged */
triaged: boolean;
/** When the item was created/arrived */
createdAt: string;
/** Optional snippet/preview */
snippet?: string;
/** Source project */
project?: string;
/** Web URL for opening in browser */
url?: string;
/** Who triggered this item (e.g., commenter name) */
actor?: string;
}
/** Triage action the user can take on an inbox item */
export type TriageAction = "accept" | "defer" | "archive";
/** Duration options for deferring an item */
export type DeferDuration = "1h" | "3h" | "tomorrow" | "next_week";
/** Compute staleness from an ISO timestamp */
export function computeStaleness(updatedAt: string | null): Staleness {
if (!updatedAt) return "normal";
const ageMs = Date.now() - new Date(updatedAt).getTime();
const ageDays = ageMs / (1000 * 60 * 60 * 24);
if (ageDays < 1) return "fresh";
if (ageDays < 3) return "normal";
if (ageDays < 7) return "amber";
return "urgent";
}