Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions apps/web/src/components/ChatView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1562,6 +1562,7 @@ export default function ChatView(props: ChatViewProps) {
};
}, [routeKind, routeThreadRef, routeThreadState]);
const markThreadVisited = useUiStateStore((store) => store.markThreadVisited);
const markThreadUnread = useUiStateStore((store) => store.markThreadUnread);
const settings = useEnvironmentSettings(environmentId);
const setStickyComposerModelSelection = useComposerDraftStore(
(store) => store.setStickyModelSelection,
Expand Down Expand Up @@ -6656,6 +6657,14 @@ export default function ChatView(props: ChatViewProps) {
return;
}

if (command === "thread.markUnread") {
event.preventDefault();
event.stopPropagation();
if (!isServerThread || !activeThreadKey) return;
markThreadUnread(activeThreadKey, activeLatestTurn?.completedAt);
return;
}

if (command === "terminal.toggle") {
event.preventDefault();
event.stopPropagation();
Expand Down Expand Up @@ -6820,6 +6829,8 @@ export default function ChatView(props: ChatViewProps) {
activeThreadRef,
activeThreadPinned,
activeThreadSettled,
activeLatestTurn?.completedAt,
markThreadUnread,
canInterruptRunningThread,
activeThreadKey,
terminalUiState.terminalOpen,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,12 +235,16 @@ describe("KeybindingsSettings.logic", () => {
"chat.new",
"rightPanel.toggleMaximized",
"thread.stop",
"thread.markUnread",
"script.setup-db.run",
]),
);
expect(DEFAULT_RESOLVED_KEYBINDINGS.some((binding) => binding.command === "thread.stop")).toBe(
false,
);
expect(
DEFAULT_RESOLVED_KEYBINDINGS.some((binding) => binding.command === "thread.markUnread"),
).toBe(false);
});

it("reports unknown when variables without rejecting parseable expressions", () => {
Expand Down
21 changes: 12 additions & 9 deletions apps/web/src/keybindings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -743,16 +743,19 @@ describe("cross-command precedence", () => {
});

describe("resolveShortcutCommand", () => {
it("resolves a custom stop-thread shortcut", () => {
const keybindings = compile([{ shortcut: modShortcut("escape"), command: "thread.stop" }]);
it.each(["thread.stop", "thread.markUnread"] as const)(
"resolves a custom %s shortcut",
(command) => {
const keybindings = compile([{ shortcut: modShortcut("escape"), command }]);

assert.strictEqual(
resolveShortcutCommand(event({ key: "Escape", metaKey: true }), keybindings, {
platform: "MacIntel",
}),
"thread.stop",
);
});
assert.strictEqual(
resolveShortcutCommand(event({ key: "Escape", metaKey: true }), keybindings, {
platform: "MacIntel",
}),
command,
);
},
);

it("honors preview conditions for a stop-thread shortcut", () => {
const keybindings = compile([
Expand Down
7 changes: 7 additions & 0 deletions docs/user/keybindings.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ to copy its URL and `mod+shift+k` to copy its number with a `#` prefix.
Both shortcuts can be changed in Settings. Search for “Copy Link or Thread ID”
or “Copy Number”. They copy the selected PR and leave terminal input alone.

## Mark a thread unread

`thread.markUnread` marks the active thread unread after a completed turn. It has
no default shortcut; assign one in **Settings → Keybindings** on web and desktop.
Add `!terminalFocus` as its condition to leave terminal input alone.
The thread stays unread until you reopen it or a new turn completes.

## iPad

With a hardware keyboard, use `Cmd+1` through `Cmd+9` to open the first nine
Expand Down
4 changes: 4 additions & 0 deletions docs/user/thread-sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ The linked pull request participates in automatic settlement.

## Find and reference work

Choose **Mark unread** from a thread's menu to revisit a completed response later.
On web and desktop, assign a shortcut to `thread.markUnread` in **Settings → Keybindings**
to mark the open thread unread. Reopening the thread marks it read again.

On web and desktop, open the command palette with `Cmd/Ctrl+K` to search threads
across connected environments. Message search starts after two characters and
includes your messages and final agent responses.
Expand Down
1 change: 1 addition & 0 deletions packages/contracts/src/keybindings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const THREAD_KEYBINDING_COMMANDS = [
"thread.copyReference",
"thread.settle",
"thread.pin",
"thread.markUnread",
...THREAD_JUMP_KEYBINDING_COMMANDS,
] as const;
export type ThreadKeybindingCommand = (typeof THREAD_KEYBINDING_COMMANDS)[number];
Expand Down
Loading