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>
138 lines
3.8 KiB
TypeScript
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";
|
|
}
|