From cdece342cd16d24f34ec7f6858d980c56e187c9c Mon Sep 17 00:00:00 2001 From: Michael Ramos Date: Fri, 26 Jun 2026 12:54:36 -0700 Subject: [PATCH] fix(annotate): make Ask AI announcement provider cards clickable (#972) The PlanAIAnnouncementDialog rendered provider cards as plain
s with selection styling but no onClick, so clicking a card did nothing despite the UI implying it switched the active AI provider. Cards now render as buttons for actually-detected providers and call the existing AI config change handler (same path as the Settings provider selector). Providers that aren't installed are shown greyed out as "not installed" rather than appearing selectable. The dialog is fed the raw detected provider list (aiProviders) instead of visibleAIProviders, so the agent-terminal substitution doesn't make every card read "not installed". --- packages/editor/App.tsx | 2 + .../components/PlanAIAnnouncementDialog.tsx | 64 +++++++++++++++---- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/packages/editor/App.tsx b/packages/editor/App.tsx index 119715010..3d9ca4c2e 100644 --- a/packages/editor/App.tsx +++ b/packages/editor/App.tsx @@ -4655,6 +4655,8 @@ const App: React.FC = () => { isOpen={shouldShowPlanAIAnnouncement} origin={origin} providerName={selectedAIProvider?.name ?? null} + providers={aiProviders} + onSelectProvider={(providerId) => handleAIConfigChange({ providerId })} onOpenAI={handleOpenAIAnnouncement} onDismiss={dismissPlanAIAnnouncement} /> diff --git a/packages/ui/components/PlanAIAnnouncementDialog.tsx b/packages/ui/components/PlanAIAnnouncementDialog.tsx index f27a8dcbd..59c945ee3 100644 --- a/packages/ui/components/PlanAIAnnouncementDialog.tsx +++ b/packages/ui/components/PlanAIAnnouncementDialog.tsx @@ -5,10 +5,18 @@ import { AGENT_CONFIG, getAgentAIProviderTypes, getAgentName } from '@plannotato import { SparklesIcon } from './SparklesIcon'; import { getProviderMeta } from './ProviderIcons'; +interface PlanAIAnnouncementProvider { + id: string; + name: string; +} + interface PlanAIAnnouncementDialogProps { isOpen: boolean; origin?: Origin | null; providerName?: string | null; + /** Actually-detected providers (installed + authenticated). Cards matching one of these are selectable. */ + providers?: PlanAIAnnouncementProvider[]; + onSelectProvider?: (providerId: string) => void; onOpenAI: () => void; onDismiss: () => void; } @@ -27,6 +35,8 @@ export const PlanAIAnnouncementDialog: React.FC = isOpen, origin, providerName, + providers = [], + onSelectProvider, onOpenAI, onDismiss, }) => { @@ -67,25 +77,55 @@ export const PlanAIAnnouncementDialog: React.FC = const meta = getProviderMeta(providerType); const Icon = meta.icon; const isSelected = providerType === providerName; - return ( -
+ // A card is selectable only if the provider is actually detected on this machine. + const detected = providers.find(p => p.name === providerType) ?? null; + const isSelectable = Boolean(detected && onSelectProvider); + + const inner = ( + <>
{meta.label}
- {isSelected && ( + {isSelected ? (
selected
- )} + ) : !detected ? ( +
not installed
+ ) : null}
-
+ + ); + + if (!isSelectable) { + return ( +
+ {inner} +
+ ); + } + + return ( + ); })}