Skip to content
Merged
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
27 changes: 27 additions & 0 deletions packages/ui/src/app/drafts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,11 @@ test('a draft names its project in the heading and the dropdown moves it to anot
typeQuery('zzz');
expect(shownValues()).toEqual([]);
expect(query('[data-testid=draft-project-empty]').textContent).toContain('zzz');
// Enter on a query nothing answers takes nothing: the folder row is not its fallback.
search.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
flushSync();
expect(store.projectPickerOpen).toBe(false);
expect(document.querySelector('[data-testid=draft-project-menu]')).not.toBeNull();
typeQuery('BOI');
expect(shownValues().map((value) => JSON.parse(value!)[1])).toEqual(['p-boite']);

Expand All @@ -210,6 +215,28 @@ test('a draft names its project in the heading and the dropdown moves it to anot
expect(query('[data-testid=project][data-project-id=p-notes]').querySelector('[data-testid=draft-row]')).toBeNull();
await waitFor(() => document.activeElement === document.querySelector('[data-testid=composer-input]'));

// The find chord opens the list from the composer, one word per field
// finds the row, and Escape twice gives the keyboard back to the composer.
const composer = query<HTMLTextAreaElement>('[data-testid=composer-input]');
composer.dispatchEvent(new KeyboardEvent('keydown', { key: 'f', code: 'KeyF', ctrlKey: true, bubbles: true, cancelable: true }));
await waitFor(() => document.activeElement === document.querySelector('[data-testid=draft-project-search]'));
const again = query<HTMLInputElement>('[data-testid=draft-project-search]');
// The list is modal: Tab stays in its search instead of reaching the page behind the scrim.
const tab = new KeyboardEvent('keydown', { key: 'Tab', bubbles: true, cancelable: true });
again.dispatchEvent(tab);
expect(tab.defaultPrevented).toBe(true);
expect(document.activeElement).toBe(again);
again.value = 'note src';
again.dispatchEvent(new Event('input', { bubbles: true }));
flushSync();
expect(shownValues().map((value) => JSON.parse(value!)[1])).toEqual(['p-notes']);
again.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
flushSync();
expect(again.value).toBe('');
again.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
await waitFor(() => document.querySelector('[data-testid=draft-project-menu]') === null);
expect(document.activeElement).toBe(composer);

// Focus back on the trigger, Escape still closes the list.
const trigger = query<HTMLButtonElement>('[data-testid=draft-project]');
trigger.click();
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/ChatView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@
<img src="./icons/icon.svg" alt="" width="42" height="42" />
<h1>{strings.mobile.draftTitle}</h1>
<p>{strings.mobile.draftHint}</p>
<span class="project-choice"><ProjectChoice {store} testid="mobile-draft-project">{#if project}<ProjectTile {project} {store} />{:else}<FolderOpen size={15} />{/if}<span class="project-label ui-label">{project ? projectName(project) : strings.drafts.name}</span><ChevronDown size={14} /></ProjectChoice></span>
<span class="project-choice"><ProjectChoice {store} testid="mobile-draft-project" phone>{#if project}<ProjectTile {project} {store} />{:else}<FolderOpen size={15} />{/if}<span class="project-label ui-label">{project ? projectName(project) : strings.drafts.name}</span><ChevronDown size={14} /></ProjectChoice></span>
{#if draftChoice}<small>{modePhrase(draftChoice.permissionMode, draftProvider)}</small>{/if}
{#if store.draft?.worktree}<small>{strings.thread.inWorktree}</small>{/if}
</div>
Expand Down
Loading
Loading