diff --git a/ui/desktop/image.d.ts b/ui/desktop/image.d.ts new file mode 100644 index 00000000..bde75ecc --- /dev/null +++ b/ui/desktop/image.d.ts @@ -0,0 +1,5 @@ +declare module '*.png'; +declare module '*.jpg'; +declare module '*.jpeg'; +declare module '*.svg'; +declare module '*.gif'; \ No newline at end of file diff --git a/ui/desktop/openapi.json b/ui/desktop/openapi.json index fae01de5..0cd35edb 100644 --- a/ui/desktop/openapi.json +++ b/ui/desktop/openapi.json @@ -10,7 +10,7 @@ "license": { "name": "Apache-2.0" }, - "version": "1.0.9" + "version": "1.0.10" }, "paths": { "/config": { diff --git a/ui/desktop/src/App.tsx b/ui/desktop/src/App.tsx index bef7f792..634263c4 100644 --- a/ui/desktop/src/App.tsx +++ b/ui/desktop/src/App.tsx @@ -17,7 +17,7 @@ import SettingsView, { type SettingsViewOptions } from './components/settings/Se import SettingsViewV2 from './components/settings_v2/SettingsView'; import MoreModelsView from './components/settings/models/MoreModelsView'; import ConfigureProvidersView from './components/settings/providers/ConfigureProvidersView'; -import ProviderSettings from './components/settings/providers/providers/NewProviderSettingsPage'; +import ProviderSettings from './components/settings_v2/providers/ProviderSettingsPage'; import 'react-toastify/dist/ReactToastify.css'; diff --git a/ui/desktop/src/components/settings/providers/providers/ProviderGrid.tsx b/ui/desktop/src/components/settings/providers/providers/ProviderGrid.tsx deleted file mode 100644 index 3f9cdd85..00000000 --- a/ui/desktop/src/components/settings/providers/providers/ProviderGrid.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import React from 'react'; -import { ProviderCard } from './subcomponents/ProviderCard'; -import ProviderState from './interfaces/ProviderState'; -import OnShowModal from './callbacks/ShowModal'; -import OnAdd from './callbacks/AddProviderParameters'; -import OnDelete from './callbacks/DeleteProviderParameters'; -import OnShowSettings from './callbacks/UpdateProviderParameters'; -import OnRefresh from './callbacks/RefreshActiveProviders'; -import DefaultProviderActions from './subcomponents/actions/DefaultProviderActions'; - -function GridLayout({ children }: { children: React.ReactNode }) { - return ( -
- {children} -
- ); -} - -function ProviderCards({ providers }: { providers: ProviderState[] }) { - const providerCallbacks = { - onShowModal: OnShowModal, - onAdd: OnAdd, - onDelete: OnDelete, - onShowSettings: OnShowSettings, - onRefresh: OnRefresh, - }; - return ( - <> - {providers.map((provider) => ( - - ))} - - ); -} - -export default function ProviderGrid({ providers }: { providers: ProviderState[] }) { - console.log('got these providers', providers); - return ( - - - - ); -} diff --git a/ui/desktop/src/components/settings/providers/providers/ProviderRegistry.tsx b/ui/desktop/src/components/settings/providers/providers/ProviderRegistry.tsx deleted file mode 100644 index 3a0f7a57..00000000 --- a/ui/desktop/src/components/settings/providers/providers/ProviderRegistry.tsx +++ /dev/null @@ -1,242 +0,0 @@ -import React from 'react'; -import ProviderDetails from './interfaces/ProviderDetails'; -import DefaultProviderActions from './subcomponents/actions/DefaultProviderActions'; -import OllamaActions from './subcomponents/actions/OllamaActions'; - -export interface ProviderRegistry { - name: string; - details: ProviderDetails; -} - -export const PROVIDER_REGISTRY: ProviderRegistry[] = [ - { - name: 'OpenAI', - details: { - id: 'openai', - name: 'OpenAI', - description: 'Access GPT-4, GPT-3.5 Turbo, and other OpenAI models', - parameters: [ - { - name: 'OPENAI_API_KEY', - is_secret: true, - }, - ], - getActions: (provider, callbacks) => { - const { onAdd, onDelete, onShowSettings } = callbacks || {}; - return [ - { - id: 'default-provider-actions', - renderButton: () => ( - - ), - }, - ]; - }, - }, - }, - { - name: 'Anthropic', - details: { - id: 'anthropic', - name: 'Anthropic', - description: 'Access Claude and other Anthropic models', - parameters: [ - { - name: 'ANTHROPIC_API_KEY', - is_secret: true, - }, - ], - getActions: (provider, callbacks) => { - const { onAdd, onDelete, onShowSettings } = callbacks || {}; - return [ - { - id: 'default-provider-actions', - renderButton: () => ( - - ), - }, - ]; - }, - }, - }, - { - name: 'Google', - details: { - id: 'google', - name: 'Google', - description: 'Access Gemini and other Google AI models', - parameters: [ - { - name: 'GOOGLE_API_KEY', - is_secret: true, - }, - ], - getActions: (provider, callbacks) => { - const { onAdd, onDelete, onShowSettings } = callbacks || {}; - return [ - { - id: 'default-provider-actions', - renderButton: () => ( - - ), - }, - ]; - }, - }, - }, - { - name: 'Groq', - details: { - id: 'groq', - name: 'Groq', - description: 'Access Mixtral and other Groq-hosted models', - parameters: [ - { - name: 'GROQ_API_KEY', - is_secret: true, - }, - ], - getActions: (provider, callbacks) => { - const { onAdd, onDelete, onShowSettings } = callbacks || {}; - return [ - { - id: 'default-provider-actions', - renderButton: () => ( - - ), - }, - ]; - }, - }, - }, - { - name: 'Databricks', - details: { - id: 'databricks', - name: 'Databricks', - description: 'Access models hosted on your Databricks instance', - parameters: [ - { - name: 'DATABRICKS_HOST', - is_secret: false, - }, - ], - getActions: (provider, callbacks) => { - const { onAdd, onDelete, onShowSettings } = callbacks || {}; - return [ - { - id: 'default-provider-actions', - renderButton: () => ( - - ), - }, - ]; - }, - }, - }, - { - name: 'OpenRouter', - details: { - id: 'openrouter', - name: 'OpenRouter', - description: 'Access a variety of AI models through OpenRouter', - parameters: [ - { - name: 'OPENROUTER_API_KEY', - is_secret: true, - }, - ], - getActions: (provider, callbacks) => { - const { onAdd, onDelete, onShowSettings } = callbacks || {}; - return [ - { - id: 'default-provider-actions', - renderButton: () => ( - - ), - }, - ]; - }, - }, - }, - { - name: 'Ollama', - details: { - id: 'ollama', - name: 'Ollama', - description: 'Run and use open-source models locally', - parameters: [ - { - name: 'OLLAMA_HOST', - is_secret: false, - }, - ], - getActions: (provider, callbacks) => { - const { onAdd, onDelete, onRefresh, onShowSettings } = callbacks || {}; - return [ - { - id: 'ollama-actions', - renderButton: () => ( - - ), - }, - ]; - }, - }, - }, -]; - -// const ACTION_IMPLEMENTATIONS = { -// 'default': (provider, callbacks) => [{ -// id: 'default-provider-actions', -// renderButton: () => -// }], -// -// 'ollama': (provider, callbacks) => [{ -// id: 'ollama-actions', -// renderButton: () => -// }] -// }; diff --git a/ui/desktop/src/components/settings/providers/providers/interfaces/ConfigurationCallbacks.tsx b/ui/desktop/src/components/settings/providers/providers/interfaces/ConfigurationCallbacks.tsx deleted file mode 100644 index 145cf0d3..00000000 --- a/ui/desktop/src/components/settings/providers/providers/interfaces/ConfigurationCallbacks.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export default interface ProviderCallbacks { - onShowModal?: () => void; - onAdd?: () => void; - onDelete?: () => void; - onShowSettings?: () => void; - onRefresh?: () => void; -} diff --git a/ui/desktop/src/components/settings/providers/providers/modals/ProviderConfiguationModal.tsx b/ui/desktop/src/components/settings/providers/providers/modals/ProviderConfiguationModal.tsx deleted file mode 100644 index 87134e32..00000000 --- a/ui/desktop/src/components/settings/providers/providers/modals/ProviderConfiguationModal.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React from 'react'; -import { Card } from '../../../../ui/card'; -import ProviderSetupOverlay from './configuration_modal_subcomponents/ProviderSetupOverlay'; -import ProviderSetupHeader from './configuration_modal_subcomponents/ProviderSetupHeader'; -import ProviderSetupForm from './configuration_modal_subcomponents/ProviderSetupForm'; -import ProviderSetupActions from './configuration_modal_subcomponents/ProviderSetupActions'; -import ProviderConfiguationModalProps from './interfaces/ProviderConfigurationModalProps'; - -export default function ProviderConfigurationModal({ - provider, - title, - onSubmit, - onCancel, -}: ProviderConfiguationModalProps) { - const [configValues, setConfigValues] = React.useState<{ [key: string]: string }>({}); - const headerText = title || `Setup ${provider}`; - - const handleSubmitForm = (e: React.FormEvent) => { - e.preventDefault(); - onSubmit(configValues); - }; - - return ( - - -
- - - - - -
-
-
- ); -} diff --git a/ui/desktop/src/components/settings/providers/providers/modals/configuration_modal_subcomponents/ProviderSetupForm.tsx b/ui/desktop/src/components/settings/providers/providers/modals/configuration_modal_subcomponents/ProviderSetupForm.tsx deleted file mode 100644 index d9ffa384..00000000 --- a/ui/desktop/src/components/settings/providers/providers/modals/configuration_modal_subcomponents/ProviderSetupForm.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import React from 'react'; -import { Input } from '../../../../../ui/input'; -import { Lock } from 'lucide-react'; -import { isSecretKey } from '../../../../api_keys/utils'; -import ProviderSetupFormProps from '../interfaces/ProviderSetupFormProps'; -import ParameterSchema from '../../interfaces/ParameterSchema'; - -/** - * Renders the form with required input fields and the "lock" info row. - * The submit/cancel buttons are in a separate ProviderSetupActions component. - */ -export default function ProviderSetupForm({ - configValues, - setConfigValues, - onSubmit, - provider, -}: ProviderSetupFormProps) { - const parameters: ParameterSchema[] = provider.parameters; - return ( -
-
- {parameters.map((parameter) => ( -
- - setConfigValues((prev) => ({ - ...prev, - [parameter.name]: e.target.value, - })) - } - placeholder={parameter.name} - className="w-full h-14 px-4 font-regular rounded-lg border shadow-none border-gray-300 bg-white text-lg placeholder:text-gray-400 font-regular text-gray-900" - required - /> -
- ))} -
- - - Your configuration values will be stored securely in the keychain and used only for - making requests to {provider.name}. - -
-
- {/* The action buttons are not in this form; they're in ProviderSetupActions. */} -
- ); -} diff --git a/ui/desktop/src/components/settings/providers/providers/modals/configuration_modal_subcomponents/ProviderSetupHeader.tsx b/ui/desktop/src/components/settings/providers/providers/modals/configuration_modal_subcomponents/ProviderSetupHeader.tsx deleted file mode 100644 index 21bd1a70..00000000 --- a/ui/desktop/src/components/settings/providers/providers/modals/configuration_modal_subcomponents/ProviderSetupHeader.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; - -interface ProviderSetupHeaderProps { - headerText: string; -} - -/** - * Renders the header (title) for the modal. - */ -export default function ProviderSetupHeader({ headerText }: ProviderSetupHeaderProps) { - return ( -
-

{headerText}

-
- ); -} diff --git a/ui/desktop/src/components/settings/providers/providers/subcomponents/actions/DefaultProviderActions.tsx b/ui/desktop/src/components/settings/providers/providers/subcomponents/actions/DefaultProviderActions.tsx deleted file mode 100644 index dff612ca..00000000 --- a/ui/desktop/src/components/settings/providers/providers/subcomponents/actions/DefaultProviderActions.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import React from 'react'; -import { AddButton, DeleteButton, GearSettingsButton } from './ActionButtons'; - -interface ProviderActionsProps { - name: string; - isConfigured: boolean; - onAdd?: () => void; - onConfigure?: () => void; - onDelete?: () => void; - onShowSettings?: () => void; -} - -function getDefaultTooltipMessages(name: string, actionType: string) { - switch (actionType) { - case 'add': - return `Configure ${name} settings`; - case 'edit': - return `Edit ${name} settings`; - case 'delete': - return `Delete ${name} settings`; - default: - return null; - } -} - -export default function DefaultProviderActions({ - name, - isConfigured, - onAdd, - onDelete, - onShowSettings, -}: ProviderActionsProps) { - return ( - <> - {/*Set up an unconfigured provider */} - {!isConfigured && ( - { - e.stopPropagation(); - onAdd?.(); - }} - /> - )} - {/*Edit settings of configured provider*/} - {isConfigured && ( - { - e.stopPropagation(); - onShowSettings?.(); - }} - /> - )} - {/*Delete configuration*/} - {isConfigured && ( - { - e.stopPropagation(); - onDelete?.(); - }} - /> - )} - - ); -} diff --git a/ui/desktop/src/components/settings/providers/providers/subcomponents/actions/OllamaActions.tsx b/ui/desktop/src/components/settings/providers/providers/subcomponents/actions/OllamaActions.tsx deleted file mode 100644 index 876620b2..00000000 --- a/ui/desktop/src/components/settings/providers/providers/subcomponents/actions/OllamaActions.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import React from 'react'; -import { AddButton, DeleteButton, GearSettingsButton, RefreshButton } from './ActionButtons'; -import OllamaMetadata from '../../interfaces/OllamaMetadata'; - -interface OllamaActionsProps { - isConfigured: boolean; - ollamaMetadata: OllamaMetadata; - onRefresh?: (e: React.MouseEvent) => void; - onAdd?: () => void; - onDelete?: () => void; - onShowSettings?: () => void; -} - -export default function OllamaActions({ - isConfigured, - ollamaMetadata, - onRefresh, - onAdd, - onDelete, - onShowSettings, -}: OllamaActionsProps) { - const showHostDeleteButton = isConfigured && ollamaMetadata.location === 'host' && !onDelete; - - const showRefreshButton = !isConfigured && onRefresh; - - // add host url to overwrite the app url OR if not configured at all yet - const showAddHostUrlButton = - (isConfigured && ollamaMetadata.location === 'app' && onAdd) || (!isConfigured && onAdd); - - const showHostUrlSettingsButton = - isConfigured && ollamaMetadata.location === 'host' && onShowSettings; - - // We’ll figure out which buttons to render: - - // 1) Refresh button if not configured - // 2) If configured via app => show "plus" to switch to host config - // 3) If configured via host => show "X" to remove the host and "gear" to edit - - return ( - // TODO: is this the right class name? -
- {/* (1) Refresh button if not configured */} - {showRefreshButton && ( - { - e.stopPropagation(); - onRefresh?.(e); - }} - > - )} - - {/* (2) If configured location = 'app', show a plus button to switch / set host */} - {showAddHostUrlButton && ( - { - e.stopPropagation(); - onAdd?.(); - }} - > - )} - - {/* (3) If configured location = 'host', show an X to delete or revert config */} - {showHostDeleteButton && ( - { - e.stopPropagation(); - onDelete?.(); - }} - > - )} - - {/* (4) If configured location = 'host', show a gear to view and edit config */} - {showHostUrlSettingsButton && ( - { - e.stopPropagation(); - onShowSettings?.(); - }} - > - )} -
- ); -} diff --git a/ui/desktop/src/components/settings_v2/providers/ProviderGrid.tsx b/ui/desktop/src/components/settings_v2/providers/ProviderGrid.tsx new file mode 100644 index 00000000..25424bda --- /dev/null +++ b/ui/desktop/src/components/settings_v2/providers/ProviderGrid.tsx @@ -0,0 +1,74 @@ +import React from 'react'; +import { ProviderCard } from './subcomponents/ProviderCard'; +import ProviderState from './interfaces/ProviderState'; +import OnRefresh from './callbacks/RefreshActiveProviders'; +import { ProviderModalProvider, useProviderModal } from './modal/ProviderModalProvider'; +import ProviderConfigurationModal from './modal/ProviderConfiguationModal'; + +function GridLayout({ children }: { children: React.ReactNode }) { + return ( +
+ {children} +
+ ); +} + +function ProviderCards({ + providers, + isOnboarding, +}: { + providers: ProviderState[]; + isOnboarding: boolean; +}) { + const { openModal } = useProviderModal(); + + // Define the callbacks for provider actions + const providerCallbacks = { + // Replace your OnShowSettings with the modal opener + onConfigure: (provider: ProviderState) => { + console.log('Configure button clicked for:', provider.name); + openModal(provider, { + onSubmit: (values: any) => { + console.log(`Configuring ${provider.name}:`, values); + // Your logic to save the configuration + }, + formProps: {}, + }); + console.log('openModal called'); // Check if this executes + }, + onLaunch: (provider: ProviderState) => { + OnRefresh(); + }, + }; + + return ( + <> + {providers.map((provider) => ( + + ))} + + ); +} + +export default function ProviderGrid({ + providers, + isOnboarding, +}: { + providers: ProviderState[]; + isOnboarding: boolean; +}) { + console.log('(1) Provider Grid -- is this the onboarding page?', isOnboarding); + return ( + + + + {/* This is missing! */} + + + ); +} diff --git a/ui/desktop/src/components/settings_v2/providers/ProviderRegistry.tsx b/ui/desktop/src/components/settings_v2/providers/ProviderRegistry.tsx new file mode 100644 index 00000000..2cb4c1a8 --- /dev/null +++ b/ui/desktop/src/components/settings_v2/providers/ProviderRegistry.tsx @@ -0,0 +1,199 @@ +import React from 'react'; +import ProviderDetails from './interfaces/ProviderDetails'; +import DefaultCardButtons from './subcomponents/buttons/DefaultCardButtons'; +import ButtonCallbacks from '@/src/components/settings_v2/providers/interfaces/ButtonCallbacks'; +import ProviderState from '@/src/components/settings_v2/providers/interfaces/ProviderState'; + +// Helper function to generate default actions for most providers +const getDefaultButtons = ( + provider: ProviderState, + callbacks: ButtonCallbacks, + isOnboardingPage +) => { + return [ + { + id: 'default-buttons', + renderButton: () => ( + + ), + }, + ]; +}; + +export interface ProviderRegistry { + name: string; + details: ProviderDetails; +} + +/** + * Provider Registry System + * ======================== + * + * This registry defines all available providers and how they behave in the UI. + * It works with a dynamic modal system to create a flexible, extensible architecture + * for managing provider configurations. + * + * How the System Works: + * -------------------- + * + * 1. Provider Definition: + * Each provider entry in the registry defines its core properties: + * - Basic info (id, name, description) + * - Parameters needed for configuration + * - Optional custom form component + * - Action buttons that appear on provider cards + * + * 2. Two-Level Configuration: + * a) Provider Card UI - What buttons appear on each provider card + * - Controlled by the provider's getActions() function + * - Most providers use default buttons (configure/launch) + * - Can be customized for special providers + * + * b) Modal Content - What form appears in the configuration modal + * - A single modal component exists in the app + * - Content changes dynamically based on the provider being configured + * - If provider has CustomForm property, that component is rendered + * - Otherwise, DefaultProviderForm renders based on parameters array + * + * 3. Modal Flow: + * - User clicks Configure button on a provider card + * - Button handler calls openModal() with the provider object + * - Modal context stores the current provider and opens the modal + * - ProviderConfigModal checks for CustomForm on the current provider + * - Appropriate form is rendered with provider data passed as props + * + * Adding a New Provider: + * --------------------- + * + * For a standard provider with simple configuration: + * - Define parameters array with all required fields + * - Use the default getActions function + * - No need to specify a CustomForm + * + * For a provider needing custom configuration: + * - Define parameters array (even if just for documentation) + * - Create a custom form component and assign to CustomForm property + * - Use the default or custom getActions function + * + * This architecture centralizes provider definitions while allowing + * flexibility for special cases, keeping the codebase maintainable. + */ + +export const PROVIDER_REGISTRY: ProviderRegistry[] = [ + { + name: 'OpenAI', + details: { + id: 'openai', + name: 'OpenAI', + description: 'Access GPT-4, GPT-3.5 Turbo, and other OpenAI models', + parameters: [ + { + name: 'OPENAI_API_KEY', + is_secret: true, + }, + ], + getActions: (provider, callbacks, isOnboardingPage) => + getDefaultButtons(provider, callbacks, isOnboardingPage), + }, + }, + { + name: 'Anthropic', + details: { + id: 'anthropic', + name: 'Anthropic', + description: 'Access Claude and other Anthropic models', + parameters: [ + { + name: 'ANTHROPIC_API_KEY', + is_secret: true, + }, + ], + getActions: (provider, callbacks, isOnboardingPage) => + getDefaultButtons(provider, callbacks, isOnboardingPage), + }, + }, + { + name: 'Google', + details: { + id: 'google', + name: 'Google', + description: 'Access Gemini and other Google AI models', + parameters: [ + { + name: 'GOOGLE_API_KEY', + is_secret: true, + }, + ], + getActions: (provider, callbacks, isOnboardingPage) => + getDefaultButtons(provider, callbacks, isOnboardingPage), + }, + }, + { + name: 'Groq', + details: { + id: 'groq', + name: 'Groq', + description: 'Access Mixtral and other Groq-hosted models', + parameters: [ + { + name: 'GROQ_API_KEY', + is_secret: true, + }, + ], + getActions: (provider, callbacks, isOnboardingPage) => + getDefaultButtons(provider, callbacks, isOnboardingPage), + }, + }, + { + name: 'Databricks', + details: { + id: 'databricks', + name: 'Databricks', + description: 'Access models hosted on your Databricks instance', + parameters: [ + { + name: 'DATABRICKS_HOST', + is_secret: false, + }, + ], + getActions: (provider, callbacks, isOnboardingPage) => + getDefaultButtons(provider, callbacks, isOnboardingPage), + }, + }, + { + name: 'OpenRouter', + details: { + id: 'openrouter', + name: 'OpenRouter', + description: 'Access a variety of AI models through OpenRouter', + parameters: [ + { + name: 'OPENROUTER_API_KEY', + is_secret: true, + }, + ], + getActions: (provider, callbacks, isOnboardingPage) => + getDefaultButtons(provider, callbacks, isOnboardingPage), + }, + }, + { + name: 'Ollama', + details: { + id: 'ollama', + name: 'Ollama', + description: 'Run and use open-source models locally', + parameters: [ + { + name: 'OLLAMA_HOST', + is_secret: false, + }, + ], + getActions: (provider, callbacks, isOnboardingPage) => + getDefaultButtons(provider, callbacks, isOnboardingPage), + }, + }, +]; diff --git a/ui/desktop/src/components/settings/providers/providers/NewProviderSettingsPage.tsx b/ui/desktop/src/components/settings_v2/providers/ProviderSettingsPage.tsx similarity index 90% rename from ui/desktop/src/components/settings/providers/providers/NewProviderSettingsPage.tsx rename to ui/desktop/src/components/settings_v2/providers/ProviderSettingsPage.tsx index 8cd41870..cabf5753 100644 --- a/ui/desktop/src/components/settings/providers/providers/NewProviderSettingsPage.tsx +++ b/ui/desktop/src/components/settings_v2/providers/ProviderSettingsPage.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { ScrollArea } from '../../../ui/scroll-area'; -import BackButton from '../../../ui/BackButton'; +import { ScrollArea } from '../../ui/scroll-area'; +import BackButton from '../../ui/BackButton'; import ProviderGrid from './ProviderGrid'; import ProviderState from './interfaces/ProviderState'; @@ -68,7 +68,7 @@ export default function ProviderSettings({ onClose }: { onClose: () => void }) { {/* Content Area */}
- +
diff --git a/ui/desktop/src/components/settings/providers/providers/callbacks/AddProviderParameters.tsx b/ui/desktop/src/components/settings_v2/providers/callbacks/AddProviderParameters.tsx similarity index 100% rename from ui/desktop/src/components/settings/providers/providers/callbacks/AddProviderParameters.tsx rename to ui/desktop/src/components/settings_v2/providers/callbacks/AddProviderParameters.tsx diff --git a/ui/desktop/src/components/settings/providers/providers/callbacks/CallbackRegistry.tsx b/ui/desktop/src/components/settings_v2/providers/callbacks/CallbackRegistry.tsx similarity index 100% rename from ui/desktop/src/components/settings/providers/providers/callbacks/CallbackRegistry.tsx rename to ui/desktop/src/components/settings_v2/providers/callbacks/CallbackRegistry.tsx diff --git a/ui/desktop/src/components/settings/providers/providers/callbacks/DeleteProviderParameters.tsx b/ui/desktop/src/components/settings_v2/providers/callbacks/DeleteProviderParameters.tsx similarity index 100% rename from ui/desktop/src/components/settings/providers/providers/callbacks/DeleteProviderParameters.tsx rename to ui/desktop/src/components/settings_v2/providers/callbacks/DeleteProviderParameters.tsx diff --git a/ui/desktop/src/components/settings/providers/providers/callbacks/RefreshActiveProviders.tsx b/ui/desktop/src/components/settings_v2/providers/callbacks/RefreshActiveProviders.tsx similarity index 100% rename from ui/desktop/src/components/settings/providers/providers/callbacks/RefreshActiveProviders.tsx rename to ui/desktop/src/components/settings_v2/providers/callbacks/RefreshActiveProviders.tsx diff --git a/ui/desktop/src/components/settings/providers/providers/callbacks/ShowModal.tsx b/ui/desktop/src/components/settings_v2/providers/callbacks/ShowModal.tsx similarity index 100% rename from ui/desktop/src/components/settings/providers/providers/callbacks/ShowModal.tsx rename to ui/desktop/src/components/settings_v2/providers/callbacks/ShowModal.tsx diff --git a/ui/desktop/src/components/settings/providers/providers/callbacks/UpdateProviderParameters.tsx b/ui/desktop/src/components/settings_v2/providers/callbacks/UpdateProviderParameters.tsx similarity index 100% rename from ui/desktop/src/components/settings/providers/providers/callbacks/UpdateProviderParameters.tsx rename to ui/desktop/src/components/settings_v2/providers/callbacks/UpdateProviderParameters.tsx diff --git a/ui/desktop/src/components/settings_v2/providers/interfaces/ButtonCallbacks.tsx b/ui/desktop/src/components/settings_v2/providers/interfaces/ButtonCallbacks.tsx new file mode 100644 index 00000000..74ef05e6 --- /dev/null +++ b/ui/desktop/src/components/settings_v2/providers/interfaces/ButtonCallbacks.tsx @@ -0,0 +1,6 @@ +import ProviderState from '../interfaces/ProviderState'; + +export default interface ButtonCallbacks { + onConfigure?: (provider: ProviderState) => void; + onLaunch?: (provider: ProviderState) => void; +} diff --git a/ui/desktop/src/components/settings/providers/providers/interfaces/ConfigurationAction.tsx b/ui/desktop/src/components/settings_v2/providers/interfaces/ConfigurationAction.tsx similarity index 100% rename from ui/desktop/src/components/settings/providers/providers/interfaces/ConfigurationAction.tsx rename to ui/desktop/src/components/settings_v2/providers/interfaces/ConfigurationAction.tsx diff --git a/ui/desktop/src/components/settings/providers/providers/interfaces/OllamaMetadata.tsx b/ui/desktop/src/components/settings_v2/providers/interfaces/OllamaMetadata.tsx similarity index 100% rename from ui/desktop/src/components/settings/providers/providers/interfaces/OllamaMetadata.tsx rename to ui/desktop/src/components/settings_v2/providers/interfaces/OllamaMetadata.tsx diff --git a/ui/desktop/src/components/settings/providers/providers/interfaces/ParameterSchema.ts b/ui/desktop/src/components/settings_v2/providers/interfaces/ParameterSchema.ts similarity index 100% rename from ui/desktop/src/components/settings/providers/providers/interfaces/ParameterSchema.ts rename to ui/desktop/src/components/settings_v2/providers/interfaces/ParameterSchema.ts diff --git a/ui/desktop/src/components/settings/providers/providers/interfaces/ProviderDetails.tsx b/ui/desktop/src/components/settings_v2/providers/interfaces/ProviderDetails.tsx similarity index 55% rename from ui/desktop/src/components/settings/providers/providers/interfaces/ProviderDetails.tsx rename to ui/desktop/src/components/settings_v2/providers/interfaces/ProviderDetails.tsx index 7b0f088c..6523b74c 100644 --- a/ui/desktop/src/components/settings/providers/providers/interfaces/ProviderDetails.tsx +++ b/ui/desktop/src/components/settings_v2/providers/interfaces/ProviderDetails.tsx @@ -1,8 +1,8 @@ // metadata and action builder import ProviderState from './ProviderState'; import ConfigurationAction from './ConfigurationAction'; -import ParameterSchema from '../parameters/interfaces/ParameterSchema'; -import ProviderCallbacks from './ConfigurationCallbacks'; +import ParameterSchema from '../interfaces/ParameterSchema'; +import ButtonCallbacks from './ButtonCallbacks'; export default interface ProviderDetails { id: string; @@ -10,5 +10,9 @@ export default interface ProviderDetails { description: string; parameters: ParameterSchema[]; getTags?: (name: string) => string[]; - getActions?: (provider: ProviderState, callbacks: ProviderCallbacks) => ConfigurationAction[]; + getActions?: ( + provider: ProviderState, + callbacks: ButtonCallbacks, + isOnboardingPage: boolean + ) => ConfigurationAction[]; } diff --git a/ui/desktop/src/components/settings/providers/providers/interfaces/ProviderState.tsx b/ui/desktop/src/components/settings_v2/providers/interfaces/ProviderState.tsx similarity index 100% rename from ui/desktop/src/components/settings/providers/providers/interfaces/ProviderState.tsx rename to ui/desktop/src/components/settings_v2/providers/interfaces/ProviderState.tsx diff --git a/ui/desktop/src/components/settings_v2/providers/modal/ProviderConfiguationModal.tsx b/ui/desktop/src/components/settings_v2/providers/modal/ProviderConfiguationModal.tsx new file mode 100644 index 00000000..693a0cb1 --- /dev/null +++ b/ui/desktop/src/components/settings_v2/providers/modal/ProviderConfiguationModal.tsx @@ -0,0 +1,84 @@ +import React, { useEffect, useState } from 'react'; +import ProviderSetupOverlay from './subcomponents/ProviderSetupOverlay'; +import ProviderSetupHeader from './subcomponents/ProviderSetupHeader'; +import DefaultProviderSetupForm from './subcomponents/forms/DefaultProviderSetupForm'; +import ProviderSetupActions from './subcomponents/ProviderSetupActions'; +import ProviderLogo from './subcomponents/ProviderLogo'; +import ProviderConfiguationModalProps from './interfaces/ProviderConfigurationModalProps'; +import { useProviderModal } from './ProviderModalProvider'; +import { toast } from 'react-toastify'; + +export default function ProviderConfigurationModal() { + const { isOpen, currentProvider, modalProps, closeModal } = useProviderModal(); + console.log('currentProvider', currentProvider); + const [configValues, setConfigValues] = useState({}); + + // Reset form values when provider changes + useEffect(() => { + if (currentProvider) { + // Initialize form with default values + const initialValues = {}; + if (currentProvider.parameters) { + currentProvider.parameters.forEach((param) => { + initialValues[param.name] = param.defaultValue || ''; + }); + } + setConfigValues(initialValues); + } else { + setConfigValues({}); + } + }, [currentProvider]); + + if (!isOpen || !currentProvider) return null; + + const headerText = `Configure ${currentProvider.name}`; + const descriptionText = `Add your generated api keys for this provider to integrate into Goose`; + + // Use custom form component if provider specifies one, otherwise use default + const FormComponent = currentProvider.CustomForm || DefaultProviderSetupForm; + + const handleSubmitForm = (e) => { + e.preventDefault(); + + // Use custom submit handler if provided in modalProps + if (modalProps.onSubmit) { + modalProps.onSubmit(configValues); + } else { + // Default submit behavior + toast('Submitted configuration!'); + } + + closeModal(); + }; + + const handleCancel = () => { + // Use custom cancel handler if provided + if (modalProps.onCancel) { + modalProps.onCancel(); + } + + closeModal(); + }; + + return ( + +
+ {/* Logo area - centered above title */} + + {/* Title and some information - centered */} + +
+ + {/* Contains information used to set up each provider */} + + + +
+ ); +} diff --git a/ui/desktop/src/components/settings_v2/providers/modal/ProviderModalProvider.tsx b/ui/desktop/src/components/settings_v2/providers/modal/ProviderModalProvider.tsx new file mode 100644 index 00000000..bbff2449 --- /dev/null +++ b/ui/desktop/src/components/settings_v2/providers/modal/ProviderModalProvider.tsx @@ -0,0 +1,46 @@ +import React, { createContext, useContext, useState } from 'react'; + +const ProviderModalContext = createContext({ + isOpen: false, + currentProvider: null, + modalProps: {}, + openModal: (provider, additionalProps) => {}, + closeModal: () => {}, +}); + +export const useProviderModal = () => useContext(ProviderModalContext); + +export const ProviderModalProvider = ({ children }) => { + const [isOpen, setIsOpen] = useState(false); + const [currentProvider, setCurrentProvider] = useState(null); + const [modalProps, setModalProps] = useState({}); + + const openModal = (provider, additionalProps = {}) => { + setCurrentProvider(provider); + setModalProps(additionalProps); + setIsOpen(true); + }; + + const closeModal = () => { + setIsOpen(false); + // Use a small timeout to prevent UI flicker + setTimeout(() => { + setCurrentProvider(null); + setModalProps({}); + }, 200); + }; + + return ( + + {children} + + ); +}; diff --git a/ui/desktop/src/components/settings_v2/providers/modal/constants.tsx b/ui/desktop/src/components/settings_v2/providers/modal/constants.tsx new file mode 100644 index 00000000..09315b72 --- /dev/null +++ b/ui/desktop/src/components/settings_v2/providers/modal/constants.tsx @@ -0,0 +1 @@ +export const QUICKSTART_GUIDE_URL = 'https://block.github.io/goose/docs/quickstart'; diff --git a/ui/desktop/src/components/settings/providers/providers/modals/interfaces/ProviderConfigurationModalProps.tsx b/ui/desktop/src/components/settings_v2/providers/modal/interfaces/ProviderConfigurationModalProps.tsx similarity index 100% rename from ui/desktop/src/components/settings/providers/providers/modals/interfaces/ProviderConfigurationModalProps.tsx rename to ui/desktop/src/components/settings_v2/providers/modal/interfaces/ProviderConfigurationModalProps.tsx diff --git a/ui/desktop/src/components/settings/providers/providers/modals/interfaces/ProviderSetupFormProps.tsx b/ui/desktop/src/components/settings_v2/providers/modal/interfaces/ProviderSetupFormProps.tsx similarity index 72% rename from ui/desktop/src/components/settings/providers/providers/modals/interfaces/ProviderSetupFormProps.tsx rename to ui/desktop/src/components/settings_v2/providers/modal/interfaces/ProviderSetupFormProps.tsx index a2b16fa1..c2b3c79d 100644 --- a/ui/desktop/src/components/settings/providers/providers/modals/interfaces/ProviderSetupFormProps.tsx +++ b/ui/desktop/src/components/settings_v2/providers/modal/interfaces/ProviderSetupFormProps.tsx @@ -1,9 +1,9 @@ import React from 'react'; -import ProviderDetails from '../../interfaces/ProviderDetails'; +import ProviderState from '../../interfaces/ProviderState'; export default interface ProviderSetupFormProps { configValues: { [key: string]: string }; setConfigValues: React.Dispatch>; onSubmit: (e: React.FormEvent) => void; - provider: ProviderDetails; + provider: ProviderState; } diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/ProviderLogo.tsx b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/ProviderLogo.tsx new file mode 100644 index 00000000..df947e26 --- /dev/null +++ b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/ProviderLogo.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import OpenAILogo from './icons/openai@3x.png'; +import AnthropicLogo from './icons/anthropic@3x.png'; +import GoogleLogo from './icons/google@3x.png'; +import GroqLogo from './icons/groq@3x.png'; +import OllamaLogo from './icons/ollama@3x.png'; +import DatabricksLogo from './icons/databricks@3x.png'; +import OpenRouterLogo from './icons/openrouter@3x.png'; + +// Map provider names to their logos +const providerLogos = { + openai: OpenAILogo, + anthropic: AnthropicLogo, + google: GoogleLogo, + groq: GroqLogo, + ollama: OllamaLogo, + databricks: DatabricksLogo, + openrouter: OpenRouterLogo, +}; + +export default function ProviderLogo({ providerName }) { + // Convert provider name to lowercase and fetch the logo + const logoKey = providerName.toLowerCase(); + const logo = providerLogos[logoKey] || OpenAILogo; // TODO: need default icon + + return ( +
+
+ {`${providerName} +
+
+ ); +} diff --git a/ui/desktop/src/components/settings/providers/providers/modals/configuration_modal_subcomponents/ProviderSetupActions.tsx b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/ProviderSetupActions.tsx similarity index 75% rename from ui/desktop/src/components/settings/providers/providers/modals/configuration_modal_subcomponents/ProviderSetupActions.tsx rename to ui/desktop/src/components/settings_v2/providers/modal/subcomponents/ProviderSetupActions.tsx index 94de8f75..e8cbef78 100644 --- a/ui/desktop/src/components/settings/providers/providers/modals/configuration_modal_subcomponents/ProviderSetupActions.tsx +++ b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/ProviderSetupActions.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Button } from '../../../../../ui/button'; +import { Button } from '../../../../ui/button'; interface ProviderSetupActionsProps { onCancel: () => void; @@ -7,16 +7,16 @@ interface ProviderSetupActionsProps { /** * Renders the "Submit" and "Cancel" buttons at the bottom. - * Notice we rely on the parent's `onSubmit` in the form, so we only handle Cancel here. + * Updated to match the design from screenshots. */ export default function ProviderSetupActions({ onCancel }: ProviderSetupActionsProps) { return ( -
+
{/* We rely on the
"onSubmit" for the actual Submit logic */} diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/ProviderSetupHeader.tsx b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/ProviderSetupHeader.tsx new file mode 100644 index 00000000..9c2b9a9a --- /dev/null +++ b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/ProviderSetupHeader.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { ExternalLink } from 'lucide-react'; +import { QUICKSTART_GUIDE_URL } from '../constants'; + +interface ProviderSetupHeaderProps { + title: string; + body: string; +} + +/** + * Renders the header (title + description + link to guide) for the modal. + */ +export default function ProviderSetupHeader({ title, body }: ProviderSetupHeaderProps) { + return ( +
+

{title}

+
{body}
+ + + View quick start guide + +
+ ); +} diff --git a/ui/desktop/src/components/settings/providers/providers/modals/configuration_modal_subcomponents/ProviderSetupOverlay.tsx b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/ProviderSetupOverlay.tsx similarity index 60% rename from ui/desktop/src/components/settings/providers/providers/modals/configuration_modal_subcomponents/ProviderSetupOverlay.tsx rename to ui/desktop/src/components/settings_v2/providers/modal/subcomponents/ProviderSetupOverlay.tsx index ff127d97..a2c74f5f 100644 --- a/ui/desktop/src/components/settings/providers/providers/modals/configuration_modal_subcomponents/ProviderSetupOverlay.tsx +++ b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/ProviderSetupOverlay.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { Card } from '../../../../ui/card'; interface ProviderSetupOverlayProps { children: React.ReactNode; @@ -10,7 +11,9 @@ interface ProviderSetupOverlayProps { export default function ProviderSetupOverlay({ children }: ProviderSetupOverlayProps) { return (
- {children} + +
{children}
+
); } diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/forms/DefaultProviderSetupForm.tsx b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/forms/DefaultProviderSetupForm.tsx new file mode 100644 index 00000000..bd0212f9 --- /dev/null +++ b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/forms/DefaultProviderSetupForm.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { Input } from '../../../../../ui/input'; +import { Lock } from 'lucide-react'; +import ProviderSetupFormProps from '../../interfaces/ProviderSetupFormProps'; +import ParameterSchema from '../../../interfaces/ParameterSchema'; +import { PROVIDER_REGISTRY } from '../../../ProviderRegistry'; + +export default function DefaultProviderSetupForm({ + configValues, + setConfigValues, + onSubmit, + provider, +}: ProviderSetupFormProps) { + const providerEntry = PROVIDER_REGISTRY.find((p) => p.name === provider.name); + const parameters: ParameterSchema[] = providerEntry.details.parameters; + + return ( + +
+ {parameters.map((parameter) => ( +
+ + setConfigValues((prev) => ({ + ...prev, + [parameter.name]: e.target.value, + })) + } + placeholder={parameter.name.replace(/_/g, ' ')} + className="w-full h-14 px-4 font-regular rounded-lg border shadow-none border-gray-300 bg-white text-lg placeholder:text-gray-400 font-regular text-gray-900" + required + /> +
+ ))} + +
+ + Keys are stored in a secure .env file +
+
+
+ ); +} diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/anthropic.png b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/anthropic.png new file mode 100644 index 00000000..28e3ec5a Binary files /dev/null and b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/anthropic.png differ diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/anthropic@2x.png b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/anthropic@2x.png new file mode 100644 index 00000000..fb0af21a Binary files /dev/null and b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/anthropic@2x.png differ diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/anthropic@3x.png b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/anthropic@3x.png new file mode 100644 index 00000000..cb5f2fd8 Binary files /dev/null and b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/anthropic@3x.png differ diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/databricks.png b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/databricks.png new file mode 100644 index 00000000..7c1e5439 Binary files /dev/null and b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/databricks.png differ diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/databricks@2x.png b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/databricks@2x.png new file mode 100644 index 00000000..03bc9a11 Binary files /dev/null and b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/databricks@2x.png differ diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/databricks@3x.png b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/databricks@3x.png new file mode 100644 index 00000000..5fd8039f Binary files /dev/null and b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/databricks@3x.png differ diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/google.png b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/google.png new file mode 100644 index 00000000..1469fb1b Binary files /dev/null and b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/google.png differ diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/google@2x.png b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/google@2x.png new file mode 100644 index 00000000..9aeffe07 Binary files /dev/null and b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/google@2x.png differ diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/google@3x.png b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/google@3x.png new file mode 100644 index 00000000..0b218240 Binary files /dev/null and b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/google@3x.png differ diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/groq.png b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/groq.png new file mode 100644 index 00000000..6f91335b Binary files /dev/null and b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/groq.png differ diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/groq@2x.png b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/groq@2x.png new file mode 100644 index 00000000..8e1560b0 Binary files /dev/null and b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/groq@2x.png differ diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/groq@3x.png b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/groq@3x.png new file mode 100644 index 00000000..da191305 Binary files /dev/null and b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/groq@3x.png differ diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/ollama.png b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/ollama.png new file mode 100644 index 00000000..3dca6cae Binary files /dev/null and b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/ollama.png differ diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/ollama@2x.png b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/ollama@2x.png new file mode 100644 index 00000000..68827c2e Binary files /dev/null and b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/ollama@2x.png differ diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/ollama@3x.png b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/ollama@3x.png new file mode 100644 index 00000000..7195cccc Binary files /dev/null and b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/ollama@3x.png differ diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/openai.png b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/openai.png new file mode 100644 index 00000000..a42ae9e4 Binary files /dev/null and b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/openai.png differ diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/openai.svg b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/openai.svg new file mode 100644 index 00000000..621638b9 --- /dev/null +++ b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/openai.svg @@ -0,0 +1,3 @@ + + + diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/openai@2x.png b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/openai@2x.png new file mode 100644 index 00000000..69306a71 Binary files /dev/null and b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/openai@2x.png differ diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/openai@3x.png b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/openai@3x.png new file mode 100644 index 00000000..bca9a867 Binary files /dev/null and b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/openai@3x.png differ diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/openrouter.png b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/openrouter.png new file mode 100644 index 00000000..8a124299 Binary files /dev/null and b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/openrouter.png differ diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/openrouter@2x.png b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/openrouter@2x.png new file mode 100644 index 00000000..9e4ab432 Binary files /dev/null and b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/openrouter@2x.png differ diff --git a/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/openrouter@3x.png b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/openrouter@3x.png new file mode 100644 index 00000000..a76a6bc3 Binary files /dev/null and b/ui/desktop/src/components/settings_v2/providers/modal/subcomponents/icons/openrouter@3x.png differ diff --git a/ui/desktop/src/components/settings/providers/providers/parameters/UpdateSecrets.tsx b/ui/desktop/src/components/settings_v2/providers/parameters/UpdateSecrets.tsx similarity index 100% rename from ui/desktop/src/components/settings/providers/providers/parameters/UpdateSecrets.tsx rename to ui/desktop/src/components/settings_v2/providers/parameters/UpdateSecrets.tsx diff --git a/ui/desktop/src/components/settings/providers/providers/state/ActiveKeysContext.tsx b/ui/desktop/src/components/settings_v2/providers/state/ActiveKeysContext.tsx similarity index 100% rename from ui/desktop/src/components/settings/providers/providers/state/ActiveKeysContext.tsx rename to ui/desktop/src/components/settings_v2/providers/state/ActiveKeysContext.tsx diff --git a/ui/desktop/src/components/settings/providers/providers/state/types.ts b/ui/desktop/src/components/settings_v2/providers/state/types.ts similarity index 100% rename from ui/desktop/src/components/settings/providers/providers/state/types.ts rename to ui/desktop/src/components/settings_v2/providers/state/types.ts diff --git a/ui/desktop/src/components/settings/providers/providers/state/utils.tsx b/ui/desktop/src/components/settings_v2/providers/state/utils.tsx similarity index 100% rename from ui/desktop/src/components/settings/providers/providers/state/utils.tsx rename to ui/desktop/src/components/settings_v2/providers/state/utils.tsx diff --git a/ui/desktop/src/components/settings/providers/providers/subcomponents/CardActions.tsx b/ui/desktop/src/components/settings_v2/providers/subcomponents/CardActions.tsx similarity index 100% rename from ui/desktop/src/components/settings/providers/providers/subcomponents/CardActions.tsx rename to ui/desktop/src/components/settings_v2/providers/subcomponents/CardActions.tsx diff --git a/ui/desktop/src/components/settings/providers/providers/subcomponents/CardBody.tsx b/ui/desktop/src/components/settings_v2/providers/subcomponents/CardBody.tsx similarity index 75% rename from ui/desktop/src/components/settings/providers/providers/subcomponents/CardBody.tsx rename to ui/desktop/src/components/settings_v2/providers/subcomponents/CardBody.tsx index 343b4d19..38437e8e 100644 --- a/ui/desktop/src/components/settings/providers/providers/subcomponents/CardBody.tsx +++ b/ui/desktop/src/components/settings_v2/providers/subcomponents/CardBody.tsx @@ -7,9 +7,8 @@ interface CardBodyProps { } export default function CardBody({ actions }: CardBodyProps) { - console.log('in card body'); return ( -
+
); diff --git a/ui/desktop/src/components/settings/providers/providers/subcomponents/CardContainer.tsx b/ui/desktop/src/components/settings_v2/providers/subcomponents/CardContainer.tsx similarity index 100% rename from ui/desktop/src/components/settings/providers/providers/subcomponents/CardContainer.tsx rename to ui/desktop/src/components/settings_v2/providers/subcomponents/CardContainer.tsx diff --git a/ui/desktop/src/components/settings/providers/providers/subcomponents/CardHeader.tsx b/ui/desktop/src/components/settings_v2/providers/subcomponents/CardHeader.tsx similarity index 91% rename from ui/desktop/src/components/settings/providers/providers/subcomponents/CardHeader.tsx rename to ui/desktop/src/components/settings_v2/providers/subcomponents/CardHeader.tsx index 82d347a7..852eeaa5 100644 --- a/ui/desktop/src/components/settings/providers/providers/subcomponents/CardHeader.tsx +++ b/ui/desktop/src/components/settings_v2/providers/subcomponents/CardHeader.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { ExclamationButton, GreenCheckButton } from './actions/ActionButtons'; +import { ExclamationButton, GreenCheckButton } from './buttons/CardButtons'; import { ConfiguredProviderTooltipMessage, OllamaNotConfiguredTooltipMessage, @@ -28,7 +28,7 @@ function ProviderNameAndStatus({ name, isConfigured }: ProviderNameAndStatusProp const ollamaNotConfigured = !isConfigured && name === 'Ollama'; return ( -
+
{/* Configured state: Green check */} diff --git a/ui/desktop/src/components/settings/providers/providers/subcomponents/ProviderCard.tsx b/ui/desktop/src/components/settings_v2/providers/subcomponents/ProviderCard.tsx similarity index 79% rename from ui/desktop/src/components/settings/providers/providers/subcomponents/ProviderCard.tsx rename to ui/desktop/src/components/settings_v2/providers/subcomponents/ProviderCard.tsx index fb1a8c3b..e89ebca8 100644 --- a/ui/desktop/src/components/settings/providers/providers/subcomponents/ProviderCard.tsx +++ b/ui/desktop/src/components/settings_v2/providers/subcomponents/ProviderCard.tsx @@ -3,15 +3,16 @@ import CardContainer from './CardContainer'; import CardHeader from './CardHeader'; import ProviderState from '../interfaces/ProviderState'; import CardBody from './CardBody'; -import ProviderCallbacks from '../interfaces/ConfigurationCallbacks'; +import ButtonCallbacks from '../interfaces/ButtonCallbacks'; import { PROVIDER_REGISTRY } from '../ProviderRegistry'; interface ProviderCardProps { provider: ProviderState; - providerCallbacks: ProviderCallbacks; + buttonCallbacks: ButtonCallbacks; + isOnboarding: boolean; } -export function ProviderCard({ provider, providerCallbacks }: ProviderCardProps) { +export function ProviderCard({ provider, buttonCallbacks, isOnboarding }: ProviderCardProps) { const providerEntry = PROVIDER_REGISTRY.find((p) => p.name === provider.name); // Add safety check @@ -29,7 +30,7 @@ export function ProviderCard({ provider, providerCallbacks }: ProviderCardProps) console.log('provider details', providerDetails); try { - const actions = providerDetails.getActions(provider, providerCallbacks); + const actions = providerDetails.getActions(provider, buttonCallbacks, isOnboarding); return ( { /** Icon component to render, e.g. `RefreshCw` from lucide-react */ @@ -11,11 +11,15 @@ interface ActionButtonProps extends React.ComponentProps { tooltip?: React.ReactNode; /** Additional classes for styling. */ className?: string; + /** Text to display next to the icon */ + text?: string; + /** Additional class for the icon specifically */ + iconClassName?: string; } -// className is the styling for the ); @@ -62,17 +79,14 @@ export function GreenCheckButton({ icon={Check} tooltip={tooltip} className={` - bg-green-100 - dark:bg-green-900/30 text-green-600 dark:text-green-500 - hover:bg-green-100 hover:text-green-600 border-none shadow-none w-5 h-5 cursor-default - ${className} // Removed the nullish coalescing operator as default is provided + ${className} `} onClick={() => {}} {...props} @@ -84,8 +98,17 @@ export function ExclamationButton({ tooltip, className, ...props }: ActionButton return {}} {...props} />; } -export function GearSettingsButton({ tooltip, className, ...props }: ActionButtonProps) { - return ; +export function ConfigureSettingsButton({ tooltip, className, ...props }: ActionButtonProps) { + return ( + + ); } export function AddButton({ tooltip, className, ...props }: ActionButtonProps) { @@ -101,5 +124,13 @@ export function RefreshButton({ tooltip, className, ...props }: ActionButtonProp } export function RocketButton({ tooltip, className, ...props }: ActionButtonProps) { - return ; + return ( + + ); } diff --git a/ui/desktop/src/components/settings_v2/providers/subcomponents/buttons/DefaultCardButtons.tsx b/ui/desktop/src/components/settings_v2/providers/subcomponents/buttons/DefaultCardButtons.tsx new file mode 100644 index 00000000..2f5ace8d --- /dev/null +++ b/ui/desktop/src/components/settings_v2/providers/subcomponents/buttons/DefaultCardButtons.tsx @@ -0,0 +1,77 @@ +import React from 'react'; +import { ConfigureSettingsButton, RocketButton } from './CardButtons'; +import ButtonCallbacks from '../../interfaces/ButtonCallbacks'; +import ProviderState from '@/src/components/settings_v2/providers/interfaces/ProviderState'; + +// can define other optional callbacks as needed +interface CardButtonsProps { + provider: ProviderState; + isOnboardingPage?: boolean; + callbacks: ButtonCallbacks; // things like onConfigure, onDelete +} + +function getDefaultTooltipMessages(name: string, actionType: string) { + switch (actionType) { + case 'add': + return `Configure ${name} settings`; + case 'edit': + return `Edit ${name} settings`; + case 'delete': + return `Delete ${name} settings`; + default: + return null; + } +} + +/// This defines a group of buttons that will appear on the card +/// Controlled by if a provider is configured and which version of the grid page we're on (onboarding vs settings page) +/// This is the default button group +/// +/// Settings page: +/// - show configure button +/// Onboarding page: +/// - show configure button if NOT configured +/// - show rocket launch button if configured +/// +/// We inject what will happen if we click on a button via on +/// - onConfigure: pop open a modal -- modal is configured dynamically +/// - onLaunch: continue to chat window +export default function DefaultCardButtons({ + provider, + isOnboardingPage, + callbacks, +}: CardButtonsProps) { + return ( + <> + {/*Set up an unconfigured provider */} + {!provider.isConfigured && ( + { + e.stopPropagation(); + callbacks.onConfigure(provider); + }} + /> + )} + {/*show edit tooltip instead when hovering over button for configured providers*/} + {provider.isConfigured && !isOnboardingPage && ( + { + e.stopPropagation(); + callbacks.onConfigure(provider); + }} + /> + )} + {/*show Launch button for configured providers on onboarding page*/} + {provider.isConfigured && isOnboardingPage && ( + { + e.stopPropagation(); + callbacks.onLaunch(provider); + }} + /> + )} + + ); +} diff --git a/ui/desktop/src/components/settings/providers/providers/subcomponents/actions/TooltipWrapper.tsx b/ui/desktop/src/components/settings_v2/providers/subcomponents/buttons/TooltipWrapper.tsx similarity index 88% rename from ui/desktop/src/components/settings/providers/providers/subcomponents/actions/TooltipWrapper.tsx rename to ui/desktop/src/components/settings_v2/providers/subcomponents/buttons/TooltipWrapper.tsx index ca291ad9..0986fd7d 100644 --- a/ui/desktop/src/components/settings/providers/providers/subcomponents/actions/TooltipWrapper.tsx +++ b/ui/desktop/src/components/settings_v2/providers/subcomponents/buttons/TooltipWrapper.tsx @@ -1,11 +1,6 @@ // TooltipWrapper.tsx import React from 'react'; -import { - Tooltip, - TooltipTrigger, - TooltipContent, - TooltipProvider, -} from '../../../../../ui/Tooltip'; +import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '../../../../ui/Tooltip'; import { Portal } from '@radix-ui/react-portal'; interface TooltipWrapperProps { diff --git a/ui/desktop/src/components/settings/providers/providers/subcomponents/utils/StringUtils.tsx b/ui/desktop/src/components/settings_v2/providers/subcomponents/utils/StringUtils.tsx similarity index 100% rename from ui/desktop/src/components/settings/providers/providers/subcomponents/utils/StringUtils.tsx rename to ui/desktop/src/components/settings_v2/providers/subcomponents/utils/StringUtils.tsx