From ba51ee8f9881ef6b105eb4e34735dcbfafd1368d Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Thu, 11 Jun 2026 12:43:53 +0100 Subject: [PATCH] refactor(site/src/pages/AgentsPage): centralize setup notice rendering (#26134) --- site/src/pages/AgentsPage/AgentChatPage.tsx | 30 ++------------ .../AgentsPage/AgentChatPageView.stories.tsx | 28 +++++++------ .../pages/AgentsPage/AgentChatPageView.tsx | 13 ++++-- site/src/pages/AgentsPage/AgentCreatePage.tsx | 28 ++----------- .../AgentsPage/components/AgentChatInput.tsx | 40 ++++++++++++++++--- .../components/AgentCreateForm.stories.tsx | 7 ++-- .../AgentsPage/components/AgentCreateForm.tsx | 21 +++++----- .../AgentsPage/components/ChatPageContent.tsx | 12 ++++-- 8 files changed, 87 insertions(+), 92 deletions(-) diff --git a/site/src/pages/AgentsPage/AgentChatPage.tsx b/site/src/pages/AgentsPage/AgentChatPage.tsx index 9fb29e556c..89d55e0816 100644 --- a/site/src/pages/AgentsPage/AgentChatPage.tsx +++ b/site/src/pages/AgentsPage/AgentChatPage.tsx @@ -63,7 +63,6 @@ import { } from "./AgentChatPageView"; import type { AgentsOutletContext } from "./AgentsPage"; import type { ChatMessageInputRef } from "./components/AgentChatInput"; -import { AgentSetupNotice } from "./components/AgentSetupNotice"; import { normalizeChatErrorPayload } from "./components/ChatConversation/chatError"; import { getParentChatID, @@ -1130,31 +1129,6 @@ const AgentChatPage: FC = () => { hasConfiguredModels, hasUserFixableModelProviders, }); - const isAdmin = permissions.editDeploymentConfig; - const agentSetupNotice = (() => { - // Admin: show when providers or models are missing - if ( - isAdmin && - providerCount !== undefined && - modelCount !== undefined && - (providerCount === 0 || modelCount === 0) - ) { - return ( - - ); - } - // Member: show when no models are available - if (!isAdmin && modelCount !== undefined && modelCount === 0) { - return ( - - ); - } - return undefined; - })(); const isSubmissionPending = isSendPending || isEditPending || isInterruptPending; const isChatSettingsPending = @@ -1626,7 +1600,9 @@ const AgentChatPage: FC = () => { modelOptions={modelOptions} modelSelectorPlaceholder={modelSelectorPlaceholder} modelSelectorHelp={modelSelectorHelp} - agentSetupNotice={agentSetupNotice} + canConfigureAgentSetup={permissions.editDeploymentConfig} + providerCount={providerCount} + modelCount={modelCount} hasModelOptions={hasModelOptions} isModelCatalogLoading={isModelCatalogLoading} planModeEnabled={planModeEnabled} diff --git a/site/src/pages/AgentsPage/AgentChatPageView.stories.tsx b/site/src/pages/AgentsPage/AgentChatPageView.stories.tsx index 0d8be1b1b2..6d905b634c 100644 --- a/site/src/pages/AgentsPage/AgentChatPageView.stories.tsx +++ b/site/src/pages/AgentsPage/AgentChatPageView.stories.tsx @@ -25,7 +25,6 @@ import { AgentChatPageNotFoundView, AgentChatPageView, } from "./AgentChatPageView"; -import { AgentSetupNotice } from "./components/AgentSetupNotice"; import { createChatStore, useChatSelector, @@ -190,6 +189,9 @@ const StoryAgentChatPageView: FC = ({ editing, ...overrides }) => { onMCPSelectionChange: fn(), onMCPAuthComplete: fn(), canShareChat: false, + canConfigureAgentSetup: true, + providerCount: 1, + modelCount: 1, ...overrides, store, messageCount: overrides.messageCount ?? messageCount, @@ -528,9 +530,9 @@ export const NoModelOptions: Story = { export const MissingProviderAndModelSetup: Story = { render: () => ( - } + canConfigureAgentSetup + providerCount={0} + modelCount={0} hasModelOptions={false} modelOptions={[]} isInputDisabled @@ -563,9 +565,9 @@ export const MissingProviderAndModelSetup: Story = { export const MissingModelSetup: Story = { render: () => ( - } + canConfigureAgentSetup + providerCount={1} + modelCount={0} hasModelOptions={false} modelOptions={[]} isInputDisabled @@ -594,9 +596,9 @@ export const MissingModelSetup: Story = { export const MissingProviderSetup: Story = { render: () => ( - } + canConfigureAgentSetup + providerCount={0} + modelCount={1} /> ), play: async ({ canvasElement }) => { @@ -622,9 +624,9 @@ export const MissingProviderSetup: Story = { export const MemberNoModelsAvailable: Story = { render: () => ( - } + canConfigureAgentSetup={false} + providerCount={0} + modelCount={0} hasModelOptions={false} modelOptions={[]} isInputDisabled diff --git a/site/src/pages/AgentsPage/AgentChatPageView.tsx b/site/src/pages/AgentsPage/AgentChatPageView.tsx index cd11b23334..a6db3f0d63 100644 --- a/site/src/pages/AgentsPage/AgentChatPageView.tsx +++ b/site/src/pages/AgentsPage/AgentChatPageView.tsx @@ -128,7 +128,9 @@ interface AgentChatPageViewProps { modelOptions: readonly ModelSelectorOption[]; modelSelectorPlaceholder: string; modelSelectorHelp?: ReactNode; - agentSetupNotice?: ReactNode; + canConfigureAgentSetup: boolean; + providerCount?: number; + modelCount?: number; hasModelOptions: boolean; isModelCatalogLoading?: boolean; planModeEnabled?: boolean; @@ -263,7 +265,9 @@ export const AgentChatPageView: FC = ({ modelOptions, modelSelectorPlaceholder, modelSelectorHelp, - agentSetupNotice, + canConfigureAgentSetup, + providerCount, + modelCount, hasModelOptions, isModelCatalogLoading = false, planModeEnabled, @@ -748,12 +752,14 @@ export const AgentChatPageView: FC = ({ isSendPending={isSubmissionPending} isInterruptPending={isInterruptPending} hasModelOptions={hasModelOptions} + canConfigureAgentSetup={canConfigureAgentSetup} + providerCount={providerCount} + modelCount={modelCount} selectedModel={effectiveSelectedModel} onModelChange={setSelectedModel} modelOptions={modelOptions} modelSelectorPlaceholder={modelSelectorPlaceholder} modelSelectorHelp={modelSelectorHelp} - agentSetupNotice={agentSetupNotice} planModeEnabled={planModeEnabled} onPlanModeToggle={onPlanModeToggle} isModelCatalogLoading={isModelCatalogLoading} @@ -911,6 +917,7 @@ export const AgentChatPageLoadingView: FC = ({ onPlanModeToggle={onPlanModeToggle} isModelCatalogLoading={isModelCatalogLoading} hasModelOptions={hasModelOptions} + canConfigureAgentSetup={false} /> {" "} diff --git a/site/src/pages/AgentsPage/AgentCreatePage.tsx b/site/src/pages/AgentsPage/AgentCreatePage.tsx index 4e9076a7ca..5be7071336 100644 --- a/site/src/pages/AgentsPage/AgentCreatePage.tsx +++ b/site/src/pages/AgentsPage/AgentCreatePage.tsx @@ -21,7 +21,6 @@ import { type CreateChatOptions, } from "./components/AgentCreateForm"; import { AgentPageHeader } from "./components/AgentPageHeader"; -import { AgentSetupNotice } from "./components/AgentSetupNotice"; import { ChimeButton } from "./components/ChimeButton"; import { WebPushButton } from "./components/WebPushButton"; import { getAgentChatSendShortcut } from "./utils/agentChatSendShortcut"; @@ -73,29 +72,6 @@ const AgentCreatePage: FC = () => { chatModelConfigsQuery.isSuccess && chatModelsQuery.isSuccess ? catalogModelOptions.length : undefined; - const isAdmin = permissions.editDeploymentConfig; - const agentSetupNotice = (() => { - if ( - isAdmin && - providerCount !== undefined && - modelCount !== undefined && - (providerCount === 0 || modelCount === 0) - ) { - return ( - - ); - } - if (!isAdmin && modelCount !== undefined && modelCount === 0) { - return ( - - ); - } - return undefined; - })(); const handleCreateChat = async ({ message, @@ -181,7 +157,9 @@ const AgentCreatePage: FC = () => { canCreateChat={permissions.createChat} modelCatalog={chatModelsQuery.data} modelOptions={catalogModelOptions} - agentSetupNotice={agentSetupNotice} + canConfigureAgentSetup={permissions.editDeploymentConfig} + providerCount={providerCount} + modelCount={modelCount} modelConfigs={chatModelConfigsQuery.data ?? []} isModelCatalogLoading={chatModelsQuery.isLoading} isModelConfigsLoading={chatModelConfigsQuery.isLoading} diff --git a/site/src/pages/AgentsPage/components/AgentChatInput.tsx b/site/src/pages/AgentsPage/components/AgentChatInput.tsx index b24ce61bd1..ea6f59dc5f 100644 --- a/site/src/pages/AgentsPage/components/AgentChatInput.tsx +++ b/site/src/pages/AgentsPage/components/AgentChatInput.tsx @@ -67,6 +67,7 @@ import { isChatAttachmentFile, } from "../utils/chatAttachments"; import { formatProviderLabel } from "../utils/modelOptions"; +import { AgentSetupNotice } from "./AgentSetupNotice"; import { AttachmentPreview, isUploadInProgress, @@ -183,7 +184,9 @@ interface AgentChatInputProps { sshCommand?: string; attachedWorkspace?: AttachedWorkspaceInfo; folder?: string; - agentSetupNotice?: React.ReactNode; + canConfigureAgentSetup: boolean; + providerCount?: number; + modelCount?: number; } export interface AttachedWorkspaceInfo { @@ -381,9 +384,16 @@ export const AgentChatInput: FC = ({ sshCommand, attachedWorkspace, folder, - agentSetupNotice, + canConfigureAgentSetup, + providerCount, + modelCount, }) => { const [chatFullWidth] = useChatFullWidth(); + const showAgentSetupNotice = canConfigureAgentSetup + ? providerCount !== undefined && + modelCount !== undefined && + (providerCount === 0 || modelCount === 0) + : modelCount !== undefined && modelCount === 0; const internalRef = useRef(null); const [previewImage, setPreviewImage] = useState(null); const [previewText, setPreviewText] = useState(null); @@ -1044,15 +1054,31 @@ export const AgentChatInput: FC = ({ className="mb-2" /> )} - {agentSetupNotice && ( -
{agentSetupNotice}
+ {showAgentSetupNotice && ( +
+ {canConfigureAgentSetup && + providerCount !== undefined && + modelCount !== undefined ? ( + + ) : ( + + )} +
)}
= ({ size="icon" className="size-7 shrink-0 rounded-full [&>svg]:!size-icon-sm [&>svg]:p-0" disabled={ - isDisabled && !agentSetupNotice && !canUseWorkspacePicker + isDisabled && + !showAgentSetupNotice && + !canUseWorkspacePicker } aria-label="More options" > diff --git a/site/src/pages/AgentsPage/components/AgentCreateForm.stories.tsx b/site/src/pages/AgentsPage/components/AgentCreateForm.stories.tsx index 2631a42970..bb9717a161 100644 --- a/site/src/pages/AgentsPage/components/AgentCreateForm.stories.tsx +++ b/site/src/pages/AgentsPage/components/AgentCreateForm.stories.tsx @@ -18,7 +18,6 @@ import { } from "#/testHelpers/entities"; import { withDashboardProvider } from "#/testHelpers/storybook"; import { AgentCreateForm } from "./AgentCreateForm"; -import { AgentSetupNotice } from "./AgentSetupNotice"; // Query key used by permittedOrganizations() in the form. const permittedOrgsKey = [ @@ -471,9 +470,9 @@ export const NoModelsConfigured: Story = { export const MissingProviderAndModelSetup: Story = { args: { ...defaultArgs, - agentSetupNotice: ( - - ), + canConfigureAgentSetup: true, + providerCount: 0, + modelCount: 0, modelCatalog: { providers: [] }, modelOptions: [], isModelCatalogLoading: false, diff --git a/site/src/pages/AgentsPage/components/AgentCreateForm.tsx b/site/src/pages/AgentsPage/components/AgentCreateForm.tsx index d4ec3b5956..8c8c9f291e 100644 --- a/site/src/pages/AgentsPage/components/AgentCreateForm.tsx +++ b/site/src/pages/AgentsPage/components/AgentCreateForm.tsx @@ -1,11 +1,4 @@ -import { - type FC, - type ReactNode, - useEffect, - useEffectEvent, - useRef, - useState, -} from "react"; +import { type FC, useEffect, useEffectEvent, useRef, useState } from "react"; import { useQuery } from "react-query"; import { Link } from "react-router"; import { toast } from "sonner"; @@ -132,7 +125,9 @@ interface AgentCreateFormProps { canCreateChat: boolean; modelCatalog: TypesGen.ChatModelsResponse | null | undefined; modelOptions: readonly ChatModelOption[]; - agentSetupNotice?: ReactNode; + canConfigureAgentSetup: boolean; + providerCount?: number; + modelCount?: number; isModelCatalogLoading: boolean; modelConfigs: readonly TypesGen.ChatModelConfig[]; isModelConfigsLoading: boolean; @@ -154,7 +149,9 @@ export const AgentCreateForm: FC = ({ canCreateChat, modelCatalog, modelOptions, - agentSetupNotice, + canConfigureAgentSetup, + providerCount, + modelCount, modelConfigs, isModelCatalogLoading, isModelConfigsLoading, @@ -548,7 +545,9 @@ export const AgentCreateForm: FC = ({ selectedWorkspaceId={effectiveWorkspaceId} onWorkspaceChange={handleWorkspaceChange} isWorkspaceLoading={isWorkspacesLoading} - agentSetupNotice={agentSetupNotice} + canConfigureAgentSetup={canConfigureAgentSetup} + providerCount={providerCount} + modelCount={modelCount} /> {modelSelectorHelp ? (
diff --git a/site/src/pages/AgentsPage/components/ChatPageContent.tsx b/site/src/pages/AgentsPage/components/ChatPageContent.tsx index 135db09f81..84ca4fe606 100644 --- a/site/src/pages/AgentsPage/components/ChatPageContent.tsx +++ b/site/src/pages/AgentsPage/components/ChatPageContent.tsx @@ -169,7 +169,9 @@ interface ChatPageInputProps { modelOptions: readonly ModelSelectorOption[]; modelSelectorPlaceholder: string; modelSelectorHelp?: ReactNode; - agentSetupNotice?: ReactNode; + canConfigureAgentSetup: boolean; + providerCount?: number; + modelCount?: number; planModeEnabled?: boolean; onPlanModeToggle?: (enabled: boolean) => void; isModelCatalogLoading?: boolean; @@ -234,7 +236,9 @@ export const ChatPageInput: FC = ({ modelOptions, modelSelectorPlaceholder, modelSelectorHelp, - agentSetupNotice, + canConfigureAgentSetup, + providerCount, + modelCount, planModeEnabled, onPlanModeToggle, isModelCatalogLoading = false, @@ -490,7 +494,9 @@ export const ChatPageInput: FC = ({ sshCommand={sshCommand} attachedWorkspace={attachedWorkspace} folder={folder} - agentSetupNotice={agentSetupNotice} + canConfigureAgentSetup={canConfigureAgentSetup} + providerCount={providerCount} + modelCount={modelCount} /> );