Skip to content

Commit 4ddd256

Browse files
authored
feat(ui): add instance-scoped provider manager from model selector (NeuralNomadsAI#476)
## Summary - move provider authentication management out of global settings and into the model selector so it always runs against a live OpenCode instance - add an instance-scoped provider manager modal with API-key and OAuth flows, cancellable OAuth waiting, and provider discovery/configuration details - handle configured provider sources differently so config- and env-backed providers are explained in the UI while auth-backed providers can be disconnected safely ## Validation - npm run typecheck --workspace @codenomad/ui - npm run build --workspace @codenomad/ui
1 parent 02c2622 commit 4ddd256

14 files changed

Lines changed: 1548 additions & 6 deletions

File tree

packages/ui/src/components/model-selector.tsx

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { Combobox } from "@kobalte/core/combobox"
22
import { createEffect, createMemo, createSignal } from "solid-js"
33
import { providers, fetchProviders } from "../stores/sessions"
4-
import { ChevronDown, Star } from "lucide-solid"
4+
import { ChevronDown, PlugZap, Star } from "lucide-solid"
55
import type { Model } from "../types/session"
66
import { useI18n } from "../lib/i18n"
77
import { getLogger } from "../lib/logger"
88
import { uiState, toggleFavoriteModelPreference } from "../stores/preferences"
9+
import { ProviderManagerModal } from "./provider-auth/provider-manager-modal"
910
const log = getLogger("session")
1011

1112
interface ModelSelectorProps {
@@ -52,6 +53,7 @@ export default function ModelSelector(props: ModelSelectorProps) {
5253
const [initialQuery, setInitialQuery] = createSignal("")
5354
const [initialQueryReady, setInitialQueryReady] = createSignal(false)
5455
const [inputValue, setInputValue] = createSignal("")
56+
const [providersModalOpen, setProvidersModalOpen] = createSignal(false)
5557
let triggerRef!: HTMLButtonElement
5658
let searchInputRef!: HTMLInputElement
5759
let listboxRef!: HTMLUListElement
@@ -404,6 +406,27 @@ export default function ModelSelector(props: ModelSelectorProps) {
404406
</div>
405407
<Combobox.Listbox ref={listboxRef} class="selector-listbox" />
406408
<div class="selector-footer">
409+
<button
410+
type="button"
411+
class="selector-option selector-option-action w-full"
412+
onMouseDown={(event) => {
413+
event.preventDefault()
414+
event.stopPropagation()
415+
}}
416+
onPointerDown={(event) => {
417+
event.preventDefault()
418+
event.stopPropagation()
419+
}}
420+
onClick={(event) => {
421+
event.preventDefault()
422+
event.stopPropagation()
423+
setIsOpen(false)
424+
setProvidersModalOpen(true)
425+
}}
426+
>
427+
<PlugZap class="w-4 h-4" />
428+
<span class="selector-option-label">{t("modelSelector.manageProviders")}</span>
429+
</button>
407430
<button
408431
type="button"
409432
class="selector-option selector-option-action w-full"
@@ -428,6 +451,7 @@ export default function ModelSelector(props: ModelSelectorProps) {
428451
</Combobox.Content>
429452
</Combobox.Portal>
430453
</Combobox>
454+
<ProviderManagerModal instanceId={props.instanceId} open={providersModalOpen()} onOpenChange={setProvidersModalOpen} />
431455
</div>
432456
)
433457
}

0 commit comments

Comments
 (0)