import { useEffect, useMemo, useState } from 'react'; import { Badge } from '@renderer/components/ui/badge'; import { Button } from '@renderer/components/ui/button'; import { Checkbox } from '@renderer/components/ui/checkbox'; import { Input } from '@renderer/components/ui/input'; import { Label } from '@renderer/components/ui/label'; import { compareOpenCodeTeamModelRecommendations, getOpenCodeTeamModelRecommendation, isOpenCodeTeamModelRecommended, } from '@renderer/utils/openCodeModelRecommendations'; import { AlertTriangle, ArrowLeft, CheckCircle2, KeyRound, Loader2, RefreshCcw, Search, Star, Trash2, } from 'lucide-react'; import { formatProviderState, formatRuntimeState, getProviderAction, getProviderModelsLabel, } from '../../core/domain'; import { ProviderBrandIcon } from './providerBrandIcons'; import type { RuntimeProviderManagementActions, RuntimeProviderManagementState, } from '../hooks/useRuntimeProviderManagement'; import type { RuntimeProviderConnectionDto, RuntimeProviderDirectoryEntryDto, RuntimeProviderDirectoryFilterDto, RuntimeProviderModelDto, RuntimeProviderModelTestResultDto, } from '@features/runtime-provider-management/contracts'; import type { CSSProperties, JSX, KeyboardEvent } from 'react'; interface RuntimeProviderManagementPanelViewProps { readonly state: RuntimeProviderManagementState; readonly actions: RuntimeProviderManagementActions; readonly disabled: boolean; readonly projectPath?: string | null; } interface ProviderActionsProps { readonly provider: RuntimeProviderConnectionDto; readonly busy: boolean; readonly disabled: boolean; readonly onStartConnect: () => void; readonly onForget: () => void; } interface ProviderRowProps { readonly provider: RuntimeProviderConnectionDto; readonly state: RuntimeProviderManagementState; readonly active: boolean; readonly formOpen: boolean; readonly apiKeyValue: string; readonly busy: boolean; readonly disabled: boolean; readonly actions: RuntimeProviderManagementActions; } const DIRECTORY_FILTERS: Array<{ id: RuntimeProviderDirectoryFilterDto; label: string }> = [ { id: 'all', label: 'All' }, { id: 'connectable', label: 'Connectable' }, { id: 'connected', label: 'Connected' }, { id: 'configured', label: 'Configured' }, { id: 'manual', label: 'Manual setup' }, { id: 'has-models', label: 'Has models' }, ]; function getDirectoryAction( provider: RuntimeProviderDirectoryEntryDto, actionId: RuntimeProviderConnectionDto['actions'][number]['id'] ) { return provider.actions.find((action) => action.id === actionId) ?? null; } function formatDirectorySetupKind(provider: RuntimeProviderDirectoryEntryDto): string { switch (provider.setupKind) { case 'connected': return 'Connected'; case 'connect-api-key': return 'Connect'; case 'configure-manually': return 'Configure manually'; case 'requires-environment': return 'Requires environment'; case 'available-readonly': return 'Available'; case 'unsupported': return 'Unsupported'; } } function getDirectoryModelsLabel(provider: RuntimeProviderDirectoryEntryDto): string { if (provider.modelCount === null) { return 'models unknown'; } if (provider.modelCount <= 0) { return 'models not reported'; } return `${provider.modelCount} model${provider.modelCount === 1 ? '' : 's'}`; } function directoryEntryMatchesQuery( provider: RuntimeProviderDirectoryEntryDto, query: string ): boolean { if (!query) { return true; } return [ provider.providerId, provider.displayName, provider.detail ?? '', provider.defaultModelId ?? '', provider.sourceLabel ?? '', provider.providerSource ?? '', getDirectoryModelsLabel(provider), formatDirectorySetupKind(provider), ...provider.authMethods, ] .join(' ') .toLowerCase() .includes(query); } function directorySetupKindClassName(provider: RuntimeProviderDirectoryEntryDto): string { switch (provider.setupKind) { case 'connected': return 'border-emerald-400/35 bg-emerald-400/10 text-emerald-200'; case 'connect-api-key': case 'available-readonly': return 'border-sky-400/30 bg-sky-400/10 text-sky-200'; case 'configure-manually': case 'requires-environment': return 'border-white/10 bg-white/[0.04] text-[var(--color-text-muted)]'; case 'unsupported': return 'border-red-400/25 bg-red-400/10 text-red-200'; } } function directoryEntryToProviderConnection( provider: RuntimeProviderDirectoryEntryDto ): RuntimeProviderConnectionDto { return { providerId: provider.providerId, displayName: provider.displayName, state: provider.state, ownership: provider.ownership, recommended: provider.recommended, modelCount: provider.modelCount ?? 1, defaultModelId: provider.defaultModelId, authMethods: provider.authMethods, actions: provider.actions, detail: provider.detail, }; } function stateClassName(provider: RuntimeProviderConnectionDto): string { switch (provider.state) { case 'connected': return 'border-emerald-400/35 bg-emerald-400/10'; case 'available': return 'border-sky-400/25 bg-sky-400/10 text-sky-200'; case 'error': return 'border-red-400/25 bg-red-400/10 text-red-200'; case 'ignored': return 'border-zinc-400/25 bg-zinc-400/10 text-zinc-300'; case 'not-connected': return 'border-white/10 bg-white/[0.04] text-[var(--color-text-muted)]'; } } function stateStyle(provider: RuntimeProviderConnectionDto): CSSProperties | undefined { if (provider.state !== 'connected') { return undefined; } return { color: '#86efac', borderColor: 'rgba(74, 222, 128, 0.38)', backgroundColor: 'rgba(74, 222, 128, 0.11)', }; } function RuntimeSummary({ state, onRefresh, disabled, projectPath, }: Pick & { onRefresh: () => void; }): JSX.Element { const runtime = state.view?.runtime; const loadingWithoutRuntime = state.loading && !runtime; return (
OpenCode runtime
{runtime ? formatRuntimeState(runtime) : state.loading ? 'Checking runtime' : 'Unavailable'} {runtime?.version ? ( v{runtime.version} ) : null} {state.view?.defaultModel ? ( OpenCode default: {state.view.defaultModel} ) : null}
{projectPath ? `Managing selected project profile: ${projectPath}` : 'Managing fallback OpenCode profile. Select a project to manage launch credentials for that project.'}
{state.loading ? (
Loading managed OpenCode runtime, connected providers, and model defaults...
) : null} {state.view?.diagnostics.length ? (
{state.view.diagnostics.slice(0, 3).map((diagnostic) => (
{diagnostic}
))}
) : null}
); } function RuntimeProviderLoadingPlaceholder(): JSX.Element { return (
Loading OpenCode providers