Skip to content
Open
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
3 changes: 2 additions & 1 deletion apps/web/src/components/chat/ChatComposer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ import {
} from "../../lib/attachmentUploadState";
import { isCommandPaletteOpen } from "../../commandPaletteBus";
import { getTerminalFocusOwner } from "../../lib/terminalFocus";
import { resolveShortcutCommand } from "../../keybindings";
import { resolveShortcutCommand, shortcutLabelForCommand } from "../../keybindings";
import {
type TerminalContextDraft,
type TerminalContextSelection,
Expand Down Expand Up @@ -3193,6 +3193,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
<ComposerCommandMenuLayer anchor={composerMenuAnchor}>
<ComposerStashMenu
entries={stashQueue}
stashShortcutLabel={shortcutLabelForCommand(keybindings, "composer.stash")}
onRestore={restoreStashEntry}
onDelete={deleteStashEntry}
onClose={() => setIsStashMenuOpen(false)}
Expand Down
18 changes: 18 additions & 0 deletions apps/web/src/components/chat/ComposerStashMenu.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe("ComposerStashMenu", () => {
const markup = renderToStaticMarkup(
<ComposerStashMenu
entries={[]}
stashShortcutLabel="Ctrl+S"
onRestore={() => {}}
onDelete={() => {}}
onClose={() => {}}
Expand All @@ -20,6 +21,22 @@ describe("ComposerStashMenu", () => {
expect(markup).toContain('aria-label="Close stash"');
expect(markup).not.toContain("dropdown-glass");
expect(markup).not.toContain("Stashed prompts");
expect(markup).toContain("Press Ctrl+S with a prompt in the composer to stash it.");
});

it("does not advertise a shortcut when stash is unbound", () => {
const markup = renderToStaticMarkup(
<ComposerStashMenu
entries={[]}
stashShortcutLabel={null}
onRestore={() => {}}
onDelete={() => {}}
onClose={() => {}}
/>,
);

expect(markup).toContain("Nothing stashed yet.");
expect(markup).not.toContain("Press");
});

it("shows saved image thumbnails and incomplete image states", () => {
Expand Down Expand Up @@ -53,6 +70,7 @@ describe("ComposerStashMenu", () => {
pendingImageCount: 1,
},
]}
stashShortcutLabel="Ctrl+S"
onRestore={() => {}}
onDelete={() => {}}
onClose={() => {}}
Expand Down
8 changes: 6 additions & 2 deletions apps/web/src/components/chat/ComposerStashMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,12 @@ function stashEntrySnippet(entry: PromptStashEntry): string {
*/
export const ComposerStashMenu = memo(function ComposerStashMenu(props: {
entries: ReadonlyArray<PromptStashEntry>;
stashShortcutLabel: string | null;
onRestore: (entry: PromptStashEntry) => void;
onDelete: (entry: PromptStashEntry) => void;
onClose: () => void;
}) {
const { entries, onRestore, onDelete, onClose } = props;
const { entries, stashShortcutLabel, onRestore, onDelete, onClose } = props;
const drawerRef = useRef<HTMLDivElement>(null);
const [highlightedId, setHighlightedId] = useState<string | null>(entries[0]?.id ?? null);

Expand Down Expand Up @@ -128,7 +129,10 @@ export const ComposerStashMenu = memo(function ComposerStashMenu(props: {
<CommandGroup>
{entries.length === 0 ? (
<p className="px-3 py-1.5 text-secondary-label text-xs">
Nothing stashed yet. Press ⌘S with a prompt in the composer to stash it.
Nothing stashed yet.
{stashShortcutLabel
? ` Press ${stashShortcutLabel} with a prompt in the composer to stash it.`
: null}
</p>
) : (
entries.map((entry) => (
Expand Down
Loading