From 03d884797c19e7cbe92d7ef237c4b28d51b58f18 Mon Sep 17 00:00:00 2001 From: adamelmore <2363879+adamdottv@users.noreply.github.com> Date: Sun, 25 Jan 2026 15:59:56 -0600 Subject: wip(app): provider settings --- packages/app/src/components/dialog-settings.tsx | 68 ++++------ packages/app/src/components/settings-providers.tsx | 149 ++++++++++++++++++++- packages/app/src/i18n/en.ts | 10 ++ 3 files changed, 181 insertions(+), 46 deletions(-) (limited to 'packages/app/src') diff --git a/packages/app/src/components/dialog-settings.tsx b/packages/app/src/components/dialog-settings.tsx index dbbc8fa7a..0b8d108d0 100644 --- a/packages/app/src/components/dialog-settings.tsx +++ b/packages/app/src/components/dialog-settings.tsx @@ -39,16 +39,30 @@ export const DialogSettings: Component = () => { "padding-top": "12px", }} > - {language.t("settings.section.desktop")} -
- - - {language.t("settings.tab.general")} - - - - {language.t("settings.tab.shortcuts")} - +
+
+ {language.t("settings.section.desktop")} +
+ + + {language.t("settings.tab.general")} + + + + {language.t("settings.tab.shortcuts")} + +
+
+ +
+ {language.t("settings.section.server")} +
+ + + {language.t("settings.providers.title")} + +
+
@@ -56,31 +70,6 @@ export const DialogSettings: Component = () => { v{platform.version}
- {/* Server */} - {/* */} - {/* */} - {/* Permissions */} - {/* */} - {/* */} - {/* */} - {/* Providers */} - {/* */} - {/* */} - {/* */} - {/* Models */} - {/* */} - {/* */} - {/* */} - {/* Agents */} - {/* */} - {/* */} - {/* */} - {/* Commands */} - {/* */} - {/* */} - {/* */} - {/* MCP */} - {/* */} @@ -88,12 +77,9 @@ export const DialogSettings: Component = () => { - {/* */} - {/* */} - {/* */} - {/* */} - {/* */} - {/* */} + + + {/* */} {/* */} {/* */} diff --git a/packages/app/src/components/settings-providers.tsx b/packages/app/src/components/settings-providers.tsx index 7b6ca1939..b175a570b 100644 --- a/packages/app/src/components/settings-providers.tsx +++ b/packages/app/src/components/settings-providers.tsx @@ -1,14 +1,153 @@ -import { Component } from "solid-js" +import { Button } from "@opencode-ai/ui/button" +import { useDialog } from "@opencode-ai/ui/context/dialog" +import { ProviderIcon } from "@opencode-ai/ui/provider-icon" +import { Tag } from "@opencode-ai/ui/tag" +import { showToast } from "@opencode-ai/ui/toast" +import type { IconName } from "@opencode-ai/ui/icons/provider" +import { popularProviders, useProviders } from "@/hooks/use-providers" +import { createMemo, type Component, For, Show } from "solid-js" import { useLanguage } from "@/context/language" +import { useGlobalSDK } from "@/context/global-sdk" +import { DialogConnectProvider } from "./dialog-connect-provider" +import { DialogSelectProvider } from "./dialog-select-provider" + +type ProviderSource = "env" | "api" | "config" | "custom" +type ProviderMeta = { source?: ProviderSource } export const SettingsProviders: Component = () => { + const dialog = useDialog() const language = useLanguage() + const globalSDK = useGlobalSDK() + const providers = useProviders() + + const connected = createMemo(() => providers.connected()) + const popular = createMemo(() => { + const items = providers.popular().slice() + items.sort((a, b) => popularProviders.indexOf(a.id) - popularProviders.indexOf(b.id)) + return items + }) + + const source = (item: unknown) => (item as ProviderMeta).source + + const disconnect = async (providerID: string, name: string) => { + await globalSDK.client.auth + .remove({ providerID }) + .then(async () => { + await globalSDK.client.global.dispose() + showToast({ + variant: "success", + icon: "circle-check", + title: language.t("provider.disconnect.toast.disconnected.title", { provider: name }), + description: language.t("provider.disconnect.toast.disconnected.description", { provider: name }), + }) + }) + .catch((err: unknown) => { + const message = err instanceof Error ? err.message : String(err) + showToast({ title: language.t("common.requestFailed"), description: message }) + }) + } return ( -
-
-

{language.t("settings.providers.title")}

-

{language.t("settings.providers.description")}

+
+
+
+
+

{language.t("settings.providers.title")}

+
+
+
+ +
+
+

{language.t("settings.providers.section.connected")}

+
+ 0} + fallback={ +
+ {language.t("settings.providers.connected.empty")} +
+ } + > + + {(item) => ( +
+
+ + {item.name} + + {language.t("settings.providers.tag.environment")} + + + {language.t("provider.connect.method.apiKey")} + +
+ + + +
+ )} +
+
+
+
+ +
+

{language.t("settings.providers.section.popular")}

+
+ + {(item) => ( +
+
+ + {item.name} + + {language.t("dialog.provider.tag.recommended")} + + +
{language.t("dialog.provider.anthropic.note")}
+
+ +
{language.t("dialog.provider.openai.note")}
+
+ +
{language.t("dialog.provider.copilot.note")}
+
+
+ +
+ )} +
+
+ + +
) diff --git a/packages/app/src/i18n/en.ts b/packages/app/src/i18n/en.ts index b32f03485..a34c8ef21 100644 --- a/packages/app/src/i18n/en.ts +++ b/packages/app/src/i18n/en.ts @@ -137,6 +137,9 @@ export const dict = { "provider.connect.toast.connected.title": "{{provider}} connected", "provider.connect.toast.connected.description": "{{provider}} models are now available to use.", + "provider.disconnect.toast.disconnected.title": "{{provider}} disconnected", + "provider.disconnect.toast.disconnected.description": "{{provider}} models are no longer available.", + "model.tag.free": "Free", "model.tag.latest": "Latest", "model.provider.anthropic": "Anthropic", @@ -159,6 +162,8 @@ export const dict = { "common.loading": "Loading", "common.loading.ellipsis": "...", "common.cancel": "Cancel", + "common.connect": "Connect", + "common.disconnect": "Disconnect", "common.submit": "Submit", "common.save": "Save", "common.saving": "Saving...", @@ -491,6 +496,7 @@ export const dict = { "sidebar.project.viewAllSessions": "View all sessions", "settings.section.desktop": "Desktop", + "settings.section.server": "Server", "settings.tab.general": "General", "settings.tab.shortcuts": "Shortcuts", @@ -599,6 +605,10 @@ export const dict = { "settings.providers.title": "Providers", "settings.providers.description": "Provider settings will be configurable here.", + "settings.providers.section.connected": "Connected providers", + "settings.providers.connected.empty": "No connected providers", + "settings.providers.section.popular": "Popular providers", + "settings.providers.tag.environment": "Environment", "settings.models.title": "Models", "settings.models.description": "Model settings will be configurable here.", "settings.agents.title": "Agents", -- cgit v1.2.3