From 99c0362b26dfe6a225c15298d7028596d9b952c0 Mon Sep 17 00:00:00 2001 From: TJ Date: Wed, 24 Jun 2026 17:58:14 -0700 Subject: [PATCH] fix(site/src/pages/AISettingsPage/ModelsPage): duplicate Add model dropdown in empty state (#26685) Mirrors the providers page on `/ai/settings/providers`: when the models table is empty on `/ai/settings/models`, the empty state now renders an **Add model** dropdown alongside the description so users have an obvious next step. ## Changes - `AddModelDropdown` accepts an optional `align` prop (defaults to `"end"`), so the existing header instance is unchanged. - The empty state passes a second instance via `TableEmpty`'s `cta` prop with `align="start"`, matching how `ProvidersPageView` duplicates `AddProviderDropdown`. - Updated the `Empty` Storybook story to assert two **Add model** buttons render (header + empty state). ## Verification - `pnpm --dir site exec biome check src/pages/AISettingsPage/ModelsPage/` - `pnpm --dir site exec tsc -p . --noEmit` - `pnpm --dir site exec vitest run --project=storybook src/pages/AISettingsPage/ModelsPage/` (20/20 stories pass, including the updated `Empty` play)
Reference: providers page pattern `ProvidersPageView.tsx` already does this with `AddProviderDropdown`: ```tsx } /> ``` This PR brings the models page in line with that pattern.
--- > [!NOTE] > Opened by Coder Agents on behalf of @tracyjohnsonux. --- .../ModelsPage/ModelsPageView.stories.tsx | 3 +++ .../AISettingsPage/ModelsPage/ModelsPageView.tsx | 15 +++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/site/src/pages/AISettingsPage/ModelsPage/ModelsPageView.stories.tsx b/site/src/pages/AISettingsPage/ModelsPage/ModelsPageView.stories.tsx index 39994900f0..85bf8b6635 100644 --- a/site/src/pages/AISettingsPage/ModelsPage/ModelsPageView.stories.tsx +++ b/site/src/pages/AISettingsPage/ModelsPage/ModelsPageView.stories.tsx @@ -65,6 +65,9 @@ export const Empty: Story = { play: async ({ canvasElement }) => { const canvas = within(canvasElement); await expect(canvas.getByText("No models configured")).toBeInTheDocument(); + await expect( + canvas.getAllByRole("button", { name: /add model/i }).length, + ).toBe(2); }, }; diff --git a/site/src/pages/AISettingsPage/ModelsPage/ModelsPageView.tsx b/site/src/pages/AISettingsPage/ModelsPage/ModelsPageView.tsx index 2cf3f67f24..b4375e7ab3 100644 --- a/site/src/pages/AISettingsPage/ModelsPage/ModelsPageView.tsx +++ b/site/src/pages/AISettingsPage/ModelsPage/ModelsPageView.tsx @@ -35,9 +35,10 @@ import { ModelRow } from "./components/ModelRow"; const MODELS_PAGE_SIZE = 10; -const AddModelDropdown: FC<{ providerStates: readonly ProviderState[] }> = ({ - providerStates, -}) => { +const AddModelDropdown: FC<{ + providerStates: readonly ProviderState[]; + align?: "start" | "end"; +}> = ({ providerStates, align = "end" }) => { const navigate = useNavigate(); const manageableProviderStates = providerStates.filter( canManageProviderModels, @@ -52,7 +53,7 @@ const AddModelDropdown: FC<{ providerStates: readonly ProviderState[] }> = ({ - +
Select a provider
@@ -140,6 +141,12 @@ const ModelsPageView: FC = ({ + } /> ) : ( pagedItems.map((model) => (