Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ export const AISettingsPage: FC = () => {

const [isNewDialogOpen, setIsNewDialogOpen] = useState(false)
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false)
const [isCloningAction, setIsCloningAction] = useState(false)
const [templateValues, setTemplateValues] = useState<
Partial<LlmProviderConfig> | undefined
>()
Expand Down Expand Up @@ -210,9 +211,14 @@ export const AISettingsPage: FC = () => {
},
}

const setIsNewDialogOpenAndCloning = (_isNew: boolean, _isCloning: boolean) => {
setIsCloningAction(_isCloning)
setIsNewDialogOpen(_isNew)
}

const handleAddProvider = () => {
setTemplateValues(undefined)
setIsNewDialogOpen(true)
setIsNewDialogOpenAndCloning(true, false)
}

const handleUseTemplate = (template: ProviderTemplate) => {
Expand All @@ -232,10 +238,25 @@ export const AISettingsPage: FC = () => {
contextWindow: template.contextWindow,
temperature: 0.2,
})
setIsNewDialogOpen(true)
setIsNewDialogOpenAndCloning(true, false)
}

const handleEditProvider = (provider: LlmProviderConfig) => {
const handleEditProvider = (
provider: LlmProviderConfig,
isCloning = false,
) => {
if (isCloning) {
setTemplateValues({
...provider,
name: `${provider.name.replace(/\s+Copy$/g, '')} Copy`,
id: undefined,
createdAt: undefined,
updatedAt: undefined,
})
setIsNewDialogOpenAndCloning(true, true)
return
}

setEditingProvider(provider)
setIsEditDialogOpen(true)
}
Expand Down Expand Up @@ -275,7 +296,7 @@ export const AISettingsPage: FC = () => {
createdAt: timestamp,
updatedAt: timestamp,
})
setIsNewDialogOpen(true)
setIsNewDialogOpenAndCloning(true, false)
}

const handleDeleteIncompleteProvider = (provider: IncompleteProvider) => {
Expand Down Expand Up @@ -381,9 +402,13 @@ export const AISettingsPage: FC = () => {

<NewProviderDialog
open={isNewDialogOpen}
onOpenChange={setIsNewDialogOpen}
onOpenChange={(open) => {
setIsCloningAction(false)
setIsNewDialogOpen(open)
}}
initialValues={templateValues}
onSave={handleSaveProvider}
isCloningAction={isCloningAction}
/>

<NewProviderDialog
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface ConfiguredProvidersListProps {
testingProviderId: string | null
onSelectProvider: (providerId: string) => void
onTestProvider: (provider: LlmProviderConfig) => void
onEditProvider: (provider: LlmProviderConfig) => void
onEditProvider: (provider: LlmProviderConfig, isCloning?: boolean) => void
onDeleteProvider: (provider: LlmProviderConfig) => void
}

Expand Down Expand Up @@ -38,7 +38,7 @@ export const ConfiguredProvidersList: FC<ConfiguredProvidersListProps> = ({
isTesting={testingProviderId === provider.id}
onSelect={() => onSelectProvider(provider.id)}
onTest={() => onTestProvider(provider)}
onEdit={() => onEditProvider(provider)}
onEdit={(isCloning) => onEditProvider(provider, isCloning)}
onDelete={() => onDeleteProvider(provider)}
/>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import { useCapabilities } from '@/lib/browseros/useCapabilities'
import {
AI_PROVIDER_ADDED_EVENT,
AI_PROVIDER_UPDATED_EVENT,
AI_PROVIDER_CLONED_EVENT,
KIMI_API_KEY_CONFIGURED_EVENT,
KIMI_API_KEY_GUIDE_CLICKED_EVENT,
MODEL_SELECTED_EVENT,
Expand Down Expand Up @@ -207,6 +208,8 @@ export interface NewProviderDialogProps {
initialValues?: Partial<LlmProviderConfig>
/** Callback when provider is saved */
onSave: (provider: LlmProviderConfig) => Promise<void>
/** Whether the dialog is for cloning an existing provider */
isCloningAction?: boolean
}

/**
Expand All @@ -218,6 +221,7 @@ export const NewProviderDialog: FC<NewProviderDialogProps> = ({
onOpenChange,
initialValues,
onSave,
isCloningAction,
}) => {
const [isTesting, setIsTesting] = useState(false)
const [testResult, setTestResult] = useState<TestResult | null>(null)
Expand Down Expand Up @@ -400,7 +404,7 @@ export const NewProviderDialog: FC<NewProviderDialogProps> = ({

await onSave(provider)
if (isNewProvider) {
track(AI_PROVIDER_ADDED_EVENT, {
track(isCloningAction ? AI_PROVIDER_CLONED_EVENT : AI_PROVIDER_ADDED_EVENT, {
provider_type: values.type,
model: values.modelId,
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface ProviderCardProps {
isBuiltIn: boolean
onSelect: () => void
onTest?: () => void
onEdit?: () => void
onEdit?: (isCloning?: boolean) => void
onDelete?: () => void
isTesting?: boolean
}
Expand Down Expand Up @@ -112,6 +112,9 @@ export const ProviderCard: FC<ProviderCardProps> = ({
</div>
{!isBuiltIn && (
<div className="flex shrink-0 items-center gap-2">
<Button variant="outline" size="sm" onClick={() => onEdit?.(true)}>
Clone
</Button>
<Button
variant="outline"
size="sm"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ export const AI_PROVIDER_ADDED_EVENT = 'settings.ai_provider.added'
/** @public */
export const AI_PROVIDER_UPDATED_EVENT = 'settings.ai_provider.updated'

/** @public */
export const AI_PROVIDER_CLONED_EVENT = 'settings.ai_provider.cloned'

/** @public */
export const MODEL_SELECTED_EVENT = 'settings.model.selected'

Expand Down
Loading