Files
mission-control/src/lib/types.ts
teernisse d4b8a4baea feat(bd-318): implement QueueView container with filtering and batch support
QueueView now supports:
- Filtering items via CommandPalette (Cmd+K)
- Hide snoozed items by default (showSnoozed prop)
- Show snooze count indicator when items are hidden
- Support batch mode entry for sections with 2+ items
- Filter by type prop for programmatic filtering

Added snoozedUntil field to FocusItem type and updated fixtures.

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

138 lines
3.8 KiB
TypeScript

/**
* TypeScript types for Mission Control.
*
* IPC types are auto-generated by tauri-specta and re-exported from bindings.
* Frontend-only types are defined here.
*/
// -- Re-export IPC types from generated bindings --
export type {
BridgeStatus,
CaptureResult,
JsonValue,
LoreStatus,
LoreSummaryStatus,
McError,
McErrorCode,
SyncResult,
Result,
} from "./bindings";
// -- Type guards for IPC types --
import type { McError } from "./bindings";
/** Type guard to check if an error is a structured McError */
export function isMcError(err: unknown): err is McError {
if (typeof err !== "object" || err === null) return false;
const obj = err as Record<string, unknown>;
return (
typeof obj.code === "string" &&
typeof obj.message === "string" &&
typeof obj.recoverable === "boolean"
);
}
// -- 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;
/** ISO timestamp when snooze expires (item hidden until then) */
snoozedUntil: string | null;
}
/** Action the user takes on a focused item */
export type FocusAction =
| "start"
| "defer_1h"
| "defer_3h"
| "defer_tomorrow"
| "defer_next_week"
| "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;
/** Whether this item has been archived */
archived?: boolean;
/** ISO timestamp when snooze expires (item hidden until then) */
snoozedUntil?: 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();
// Guard against invalid date strings (NaN propagates through arithmetic)
if (Number.isNaN(ageMs)) return "normal";
const ageDays = ageMs / (1000 * 60 * 60 * 24);
if (ageDays < 1) return "fresh";
if (ageDays < 3) return "normal";
if (ageDays < 7) return "amber";
return "urgent";
}