Fix issue detail inbox archive shortcut

This commit is contained in:
dotta 2026-04-08 08:56:07 -05:00
parent 296033620f
commit e21e442033
3 changed files with 11 additions and 50 deletions

View file

@ -55,7 +55,7 @@ describe("keyboardShortcuts helpers", () => {
})).toBe("archive"); })).toBe("archive");
}); });
it("disarms on the first non-y keypress", () => { it("ignores non-y keypresses", () => {
const button = document.createElement("button"); const button = document.createElement("button");
expect(resolveInboxQuickArchiveKeyAction({ expect(resolveInboxQuickArchiveKeyAction({
@ -67,7 +67,7 @@ describe("keyboardShortcuts helpers", () => {
altKey: false, altKey: false,
target: button, target: button,
hasOpenDialog: false, hasOpenDialog: false,
})).toBe("disarm"); })).toBe("ignore");
}); });
it("stays inert for modifier combos before a real keypress", () => { it("stays inert for modifier combos before a real keypress", () => {
@ -96,7 +96,7 @@ describe("keyboardShortcuts helpers", () => {
})).toBe("ignore"); })).toBe("ignore");
}); });
it("disarms instead of archiving when typing into an editor", () => { it("ignores input typing instead of archiving", () => {
const input = document.createElement("input"); const input = document.createElement("input");
expect(resolveInboxQuickArchiveKeyAction({ expect(resolveInboxQuickArchiveKeyAction({
@ -108,7 +108,7 @@ describe("keyboardShortcuts helpers", () => {
altKey: false, altKey: false,
target: input, target: input,
hasOpenDialog: false, hasOpenDialog: false,
})).toBe("disarm"); })).toBe("ignore");
}); });
it("arms go-to-inbox on a clean g press", () => { it("arms go-to-inbox on a clean g press", () => {

View file

@ -47,11 +47,11 @@ export function resolveInboxQuickArchiveKeyAction({
hasOpenDialog: boolean; hasOpenDialog: boolean;
}): InboxQuickArchiveKeyAction { }): InboxQuickArchiveKeyAction {
if (!armed) return "ignore"; if (!armed) return "ignore";
if (defaultPrevented) return "disarm"; if (defaultPrevented) return "ignore";
if (metaKey || ctrlKey || altKey || isModifierOnlyKey(key)) return "ignore"; if (metaKey || ctrlKey || altKey || isModifierOnlyKey(key)) return "ignore";
if (hasOpenDialog || isKeyboardShortcutTextInputTarget(target)) return "disarm"; if (hasOpenDialog || isKeyboardShortcutTextInputTarget(target)) return "ignore";
if (key === "y") return "archive"; if (key.toLowerCase() === "y") return "archive";
return "disarm"; return "ignore";
} }
export function resolveGoToInboxKeyAction({ export function resolveGoToInboxKeyAction({

View file

@ -24,7 +24,6 @@ import {
readIssueDetailLocationState, readIssueDetailLocationState,
readIssueDetailBreadcrumb, readIssueDetailBreadcrumb,
rememberIssueDetailLocationState, rememberIssueDetailLocationState,
shouldArmIssueDetailInboxQuickArchive,
} from "../lib/issueDetailBreadcrumb"; } from "../lib/issueDetailBreadcrumb";
import { import {
hasBlockingShortcutDialog, hasBlockingShortcutDialog,
@ -1235,46 +1234,17 @@ export function IssueDetail() {
return () => closePanel(); return () => closePanel();
}, [closePanel, handleIssuePropertiesUpdate, issuePanelKey, openNewSubIssue, openPanel]); }, [closePanel, handleIssuePropertiesUpdate, issuePanelKey, openNewSubIssue, openPanel]);
const inboxQuickArchiveArmedRef = useRef(false);
const goToInboxShortcutArmedRef = useRef(false); const goToInboxShortcutArmedRef = useRef(false);
const goToInboxShortcutTimeoutRef = useRef<number | null>(null); const goToInboxShortcutTimeoutRef = useRef<number | null>(null);
const canQuickArchiveFromInbox = const canQuickArchiveFromInbox =
keyboardShortcutsEnabled && keyboardShortcutsEnabled &&
!issue?.hiddenAt && !issue?.hiddenAt;
sourceBreadcrumb.href.startsWith("/inbox") &&
shouldArmIssueDetailInboxQuickArchive(location.state);
useEffect(() => { useEffect(() => {
if (!issue?.id || !canQuickArchiveFromInbox) { if (!issue?.id || !canQuickArchiveFromInbox) return;
inboxQuickArchiveArmedRef.current = false;
return;
}
inboxQuickArchiveArmedRef.current = true;
const disarm = () => {
inboxQuickArchiveArmedRef.current = false;
};
const handlePointerDown = () => {
disarm();
};
const handleFocusIn = (event: FocusEvent) => {
if (event.target instanceof HTMLElement && event.target !== document.body) {
disarm();
}
};
const handleSelectionChange = () => {
const selection = window.getSelection();
if (!selection || selection.isCollapsed || selection.toString().trim().length === 0) return;
disarm();
};
const handleKeyDown = (event: KeyboardEvent) => { const handleKeyDown = (event: KeyboardEvent) => {
const action = resolveInboxQuickArchiveKeyAction({ const action = resolveInboxQuickArchiveKeyAction({
armed: inboxQuickArchiveArmedRef.current, armed: canQuickArchiveFromInbox,
defaultPrevented: event.defaultPrevented, defaultPrevented: event.defaultPrevented,
key: event.key, key: event.key,
metaKey: event.metaKey, metaKey: event.metaKey,
@ -1284,9 +1254,6 @@ export function IssueDetail() {
hasOpenDialog: hasBlockingShortcutDialog(document), hasOpenDialog: hasBlockingShortcutDialog(document),
}); });
if (action === "ignore") return;
disarm();
if (action !== "archive") return; if (action !== "archive") return;
event.preventDefault(); event.preventDefault();
@ -1295,14 +1262,8 @@ export function IssueDetail() {
} }
}; };
document.addEventListener("pointerdown", handlePointerDown, true);
document.addEventListener("focusin", handleFocusIn, true);
document.addEventListener("selectionchange", handleSelectionChange);
document.addEventListener("keydown", handleKeyDown, true); document.addEventListener("keydown", handleKeyDown, true);
return () => { return () => {
document.removeEventListener("pointerdown", handlePointerDown, true);
document.removeEventListener("focusin", handleFocusIn, true);
document.removeEventListener("selectionchange", handleSelectionChange);
document.removeEventListener("keydown", handleKeyDown, true); document.removeEventListener("keydown", handleKeyDown, true);
}; };
}, [archiveFromInbox, canQuickArchiveFromInbox, issue?.id]); }, [archiveFromInbox, canQuickArchiveFromInbox, issue?.id]);