diff --git a/ui/src/components/SwipeToArchive.test.tsx b/ui/src/components/SwipeToArchive.test.tsx index 06867336..8995793c 100644 --- a/ui/src/components/SwipeToArchive.test.tsx +++ b/ui/src/components/SwipeToArchive.test.tsx @@ -83,7 +83,7 @@ describe("SwipeToArchive", () => { expect(onClick).not.toHaveBeenCalled(); act(() => { - vi.advanceTimersByTime(210); + vi.advanceTimersByTime(140); }); expect(onArchive).toHaveBeenCalledTimes(1); diff --git a/ui/src/components/SwipeToArchive.tsx b/ui/src/components/SwipeToArchive.tsx index 141d439c..9a07ca96 100644 --- a/ui/src/components/SwipeToArchive.tsx +++ b/ui/src/components/SwipeToArchive.tsx @@ -9,9 +9,9 @@ interface SwipeToArchiveProps { className?: string; } -const COMMIT_THRESHOLD = 0.4; -const MAX_SWIPE = 0.92; -const COMMIT_DELAY_MS = 210; +const COMMIT_THRESHOLD = 0.32; +const MAX_SWIPE = 0.88; +const COMMIT_DELAY_MS = 140; export function SwipeToArchive({ children, diff --git a/ui/src/lib/inbox.test.ts b/ui/src/lib/inbox.test.ts index af7c1d35..317249c9 100644 --- a/ui/src/lib/inbox.test.ts +++ b/ui/src/lib/inbox.test.ts @@ -8,6 +8,7 @@ import { getInboxWorkItems, getRecentTouchedIssues, getUnreadTouchedIssues, + isMineInboxTab, loadLastInboxTab, RECENT_ISSUES_LIMIT, saveLastInboxTab, @@ -400,4 +401,11 @@ describe("inbox helpers", () => { localStorage.setItem("paperclip:inbox:last-tab", "new"); expect(loadLastInboxTab()).toBe("mine"); }); + + it("enables swipe archive only on the mine tab", () => { + expect(isMineInboxTab("mine")).toBe(true); + expect(isMineInboxTab("recent")).toBe(false); + expect(isMineInboxTab("unread")).toBe(false); + expect(isMineInboxTab("all")).toBe(false); + }); }); diff --git a/ui/src/lib/inbox.ts b/ui/src/lib/inbox.ts index 3b4297b8..997993c7 100644 --- a/ui/src/lib/inbox.ts +++ b/ui/src/lib/inbox.ts @@ -98,6 +98,10 @@ export function saveLastInboxTab(tab: InboxTab) { } } +export function isMineInboxTab(tab: InboxTab): boolean { + return tab === "mine"; +} + export function getLatestFailedRunsByAgent(runs: HeartbeatRun[]): HeartbeatRun[] { const sorted = [...runs].sort( (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), diff --git a/ui/src/pages/Inbox.tsx b/ui/src/pages/Inbox.tsx index 389c79e0..4840e10d 100644 --- a/ui/src/pages/Inbox.tsx +++ b/ui/src/pages/Inbox.tsx @@ -48,6 +48,7 @@ import { getInboxWorkItems, getLatestFailedRunsByAgent, getRecentTouchedIssues, + isMineInboxTab, InboxApprovalFilter, saveLastInboxTab, shouldShowInboxSection, @@ -520,6 +521,7 @@ export function Inbox() { pathSegment === "mine" || pathSegment === "recent" || pathSegment === "all" || pathSegment === "unread" ? pathSegment : "mine"; + const canArchiveFromTab = isMineInboxTab(tab); const issueLinkState = useMemo( () => createIssueDetailLocationState( @@ -911,7 +913,7 @@ export function Inbox() { }, [dismiss]); const nonIssueUnreadState = (key: string): NonIssueUnreadState => { - if (tab !== "mine") return null; + if (!canArchiveFromTab) return null; const isRead = readItems.has(key); const isFading = fadingNonIssueItems.has(key); if (isFading) return "fading"; @@ -951,7 +953,7 @@ export function Inbox() { } // Keyboard shortcuts are only active on the "mine" tab - if (tab !== "mine") return; + if (!canArchiveFromTab) return; const itemCount = workItemsToRender.length; if (itemCount === 0) return; @@ -1033,7 +1035,7 @@ export function Inbox() { window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); }, [ - workItemsToRender, selectedIndex, tab, navigate, issueLinkState, + workItemsToRender, selectedIndex, canArchiveFromTab, navigate, issueLinkState, getWorkItemKey, archivingIssueIds, archivingNonIssueIds, fadingOutIssues, readItems, archiveIssueMutation, markReadMutation, markUnreadMutation, @@ -1219,7 +1221,6 @@ export function Inbox() { , ); } - const isMineTab = tab === "mine"; const isSelected = selectedIndex === index; if (item.kind === "approval") { @@ -1235,7 +1236,7 @@ export function Inbox() { isPending={approveMutation.isPending || rejectMutation.isPending} unreadState={nonIssueUnreadState(approvalKey)} onMarkRead={() => handleMarkNonIssueRead(approvalKey)} - onArchive={isMineTab ? () => handleArchiveNonIssue(approvalKey) : undefined} + onArchive={canArchiveFromTab ? () => handleArchiveNonIssue(approvalKey) : undefined} archiveDisabled={isArchiving} className={ isArchiving @@ -1244,7 +1245,7 @@ export function Inbox() { } /> ); - elements.push(wrapItem(approvalKey, isSelected, isMineTab ? ( + elements.push(wrapItem(approvalKey, isSelected, canArchiveFromTab ? ( handleMarkNonIssueRead(runKey)} - onArchive={isMineTab ? () => handleArchiveNonIssue(runKey) : undefined} + onArchive={canArchiveFromTab ? () => handleArchiveNonIssue(runKey) : undefined} archiveDisabled={isArchiving} className={ isArchiving @@ -1280,7 +1281,7 @@ export function Inbox() { } /> ); - elements.push(wrapItem(runKey, isSelected, isMineTab ? ( + elements.push(wrapItem(runKey, isSelected, canArchiveFromTab ? ( handleMarkNonIssueRead(joinKey)} - onArchive={isMineTab ? () => handleArchiveNonIssue(joinKey) : undefined} + onArchive={canArchiveFromTab ? () => handleArchiveNonIssue(joinKey) : undefined} archiveDisabled={isArchiving} className={ isArchiving @@ -1313,7 +1314,7 @@ export function Inbox() { } /> ); - elements.push(wrapItem(joinKey, isSelected, isMineTab ? ( + elements.push(wrapItem(joinKey, isSelected, canArchiveFromTab ? ( markReadMutation.mutate(issue.id)} onArchive={ - isMineTab + canArchiveFromTab ? () => archiveIssueMutation.mutate(issue.id) : undefined } @@ -1383,7 +1384,7 @@ export function Inbox() { /> ); - elements.push(wrapItem(`issue:${issue.id}`, isSelected, isMineTab ? ( + elements.push(wrapItem(`issue:${issue.id}`, isSelected, canArchiveFromTab ? (