diff --git a/site/src/pages/AgentsPage/components/ChatsSidebar/dialogs/ChatSearchDialog.stories.tsx b/site/src/pages/AgentsPage/components/ChatsSidebar/dialogs/ChatSearchDialog.stories.tsx index 5e430d222e..3bf3b96c37 100644 --- a/site/src/pages/AgentsPage/components/ChatsSidebar/dialogs/ChatSearchDialog.stories.tsx +++ b/site/src/pages/AgentsPage/components/ChatsSidebar/dialogs/ChatSearchDialog.stories.tsx @@ -85,6 +85,8 @@ const cappedMockChats: Chat[] = Array.from( diff_status: undefined, }), ); +const longDiffURL = + "github.com/coder/coder/pull/26016/files/1234567890abcdef1234567890abcdef1234567890abcdef"; const meta: Meta = { title: "pages/AgentsPage/ChatSearchDialog", @@ -123,6 +125,42 @@ type Story = StoryObj; export const EmptyState: Story = {}; +export const IconInputAlignment: Story = { + play: async () => { + const body = within(document.body); + const searchInput = await body.findByRole("combobox", { + name: "Search chats", + }); + const toggleButton = await body.findByRole("button", { + name: "Toggle filters", + }); + + const container = toggleButton.parentElement; + if (!container) { + throw new Error("Expected the toggle button to have a parent container"); + } + const searchIcon = container.querySelector("svg"); + const filterIcon = toggleButton.querySelector("svg"); + if (!searchIcon || !filterIcon) { + throw new Error("Expected the search and filter icons to render"); + } + + const verticalCenter = (element: Element) => { + const rect = element.getBoundingClientRect(); + return rect.top + rect.height / 2; + }; + await waitFor(() => { + const inputCenter = verticalCenter(searchInput); + expect( + Math.abs(verticalCenter(searchIcon) - inputCenter), + ).toBeLessThanOrEqual(1); + expect( + Math.abs(verticalCenter(filterIcon) - inputCenter), + ).toBeLessThanOrEqual(1); + }); + }, +}; + export const LoadingState: Story = { beforeEach: () => { spyOn(API.experimental, "getChats").mockImplementation( @@ -461,6 +499,63 @@ export const ParameterizedFilterPill: Story = { }, }; +export const DiffURLFilterPill: Story = { + beforeEach: () => { + spyOn(API.experimental, "getChats").mockResolvedValue(mockChats); + }, + play: async () => { + const body = within(document.body); + const searchInput = body.getByRole("combobox", { name: "Search chats" }); + const toggleButton = body.getByRole("button", { name: "Toggle filters" }); + + await userEvent.click(toggleButton); + await userEvent.click(await body.findByText("Diff URL")); + + await expect(await body.findByText("diff_url:")).toBeInTheDocument(); + + await userEvent.click(searchInput); + await userEvent.type(searchInput, `${longDiffURL} `); + + const diffURLPill = await body.findByText(`diff_url:${longDiffURL}`); + await expect(diffURLPill).toBeInTheDocument(); + await expect(diffURLPill).toHaveAttribute( + "title", + `diff_url:${longDiffURL}`, + ); + await expect(searchInput).toBeVisible(); + + const searchContainer = searchInput.parentElement; + const searchWrapper = searchContainer?.parentElement; + if (!searchContainer || !searchWrapper) { + throw new Error( + "Expected search input to render inside nested containers", + ); + } + + const dialog = searchWrapper.closest('[role="dialog"]'); + if (!dialog) { + throw new Error("Expected the search input to render inside a dialog"); + } + + await waitFor(() => { + const dialogRight = Math.ceil(dialog.getBoundingClientRect().right); + expect( + Math.ceil(searchWrapper.getBoundingClientRect().right), + ).toBeLessThanOrEqual(dialogRight); + expect( + Math.ceil(diffURLPill.getBoundingClientRect().right), + ).toBeLessThanOrEqual(dialogRight); + }); + + await waitFor(() => { + expect(API.experimental.getChats).toHaveBeenCalledWith({ + limit: CHAT_SEARCH_LIMIT, + q: `diff_url:"https://${longDiffURL}"`, + }); + }); + }, +}; + export const ParameterizedFilterPillEnterCommit: Story = { beforeEach: () => { spyOn(API.experimental, "getChats").mockResolvedValue(mockChats); diff --git a/site/src/pages/AgentsPage/components/ChatsSidebar/dialogs/ChatSearchDialog.tsx b/site/src/pages/AgentsPage/components/ChatsSidebar/dialogs/ChatSearchDialog.tsx index 25aa41dca7..963da2e9f5 100644 --- a/site/src/pages/AgentsPage/components/ChatsSidebar/dialogs/ChatSearchDialog.tsx +++ b/site/src/pages/AgentsPage/components/ChatsSidebar/dialogs/ChatSearchDialog.tsx @@ -400,7 +400,7 @@ const ChatSearchDialogContent: FC = ({ the dropdown, but clicks within the dropdown (which is inside the same container) don't trigger blur. */}
{ if (!e.currentTarget.contains(e.relatedTarget)) { setIsDropdownOpen(false); diff --git a/site/src/pages/AgentsPage/components/ChatsSidebar/dialogs/ChatSearchInput.tsx b/site/src/pages/AgentsPage/components/ChatsSidebar/dialogs/ChatSearchInput.tsx index b134f8854b..f4722c5933 100644 --- a/site/src/pages/AgentsPage/components/ChatsSidebar/dialogs/ChatSearchInput.tsx +++ b/site/src/pages/AgentsPage/components/ChatsSidebar/dialogs/ChatSearchInput.tsx @@ -45,56 +45,63 @@ export const ChatSearchInput: FC = ({ return (
- - {completedFilters.map((f) => ( - - - {f.key}:{f.value} - - - - ))} - {incompleteFilter && ( - - {incompleteFilter.key}: - - )} - 0 ? "" : "Search chats..."} - className="min-w-[60px] flex-1 border-none bg-transparent py-2 text-sm text-content-primary outline-none placeholder:text-content-disabled" - aria-label="Search chats" - role="combobox" - aria-controls={hasResults ? listboxId : undefined} - aria-expanded={hasResults} - aria-haspopup="listbox" - aria-activedescendant={activeResultId} - /> + + {f.key}:{f.value} + + + + ))} + {incompleteFilter && ( + + {incompleteFilter.key}: + + )} + 0 ? "" : "Search chats..."} + className="min-w-[60px] flex-1 basis-[60px] border-none bg-transparent py-0.5 text-sm text-content-primary outline-none placeholder:text-content-disabled" + aria-label="Search chats" + role="combobox" + aria-controls={hasResults ? listboxId : undefined} + aria-expanded={hasResults} + aria-haspopup="listbox" + aria-activedescendant={activeResultId} + /> +