From e659cc2734958b7bd1dcf375f917167b767cab56 Mon Sep 17 00:00:00 2001 From: Jason <6457032+solidblu@users.noreply.github.com> Date: Tue, 12 May 2026 22:20:47 -0400 Subject: [PATCH 1/3] feat: add edit button for connected providers --- .../components/dialog-connect-provider.tsx | 3 +- .../components/dialog-custom-provider-form.ts | 3 +- .../src/components/dialog-custom-provider.tsx | 16 ++++--- .../src/components/dialog-select-server.tsx | 3 ++ .../app/src/components/settings-providers.tsx | 43 +++++++++++++++++++ 5 files changed, 60 insertions(+), 8 deletions(-) diff --git a/packages/app/src/components/dialog-connect-provider.tsx b/packages/app/src/components/dialog-connect-provider.tsx index a0ccc161f25f..472f3bec5270 100644 --- a/packages/app/src/components/dialog-connect-provider.tsx +++ b/packages/app/src/components/dialog-connect-provider.tsx @@ -17,7 +17,7 @@ import { useServerSync } from "@/context/server-sync" import { useLanguage } from "@/context/language" import { useProviders } from "@/hooks/use-providers" -export function DialogConnectProvider(props: { provider: string }) { +export function DialogConnectProvider(props: { provider: string; onComplete?: () => void }) { const dialog = useDialog() const serverSync = useServerSync() const serverSDK = useServerSDK() @@ -332,6 +332,7 @@ export function DialogConnectProvider(props: { provider: string }) { async function complete() { await serverSDK.client.global.dispose() dialog.close() + props.onComplete?.() showToast({ variant: "success", icon: "circle-check", diff --git a/packages/app/src/components/dialog-custom-provider-form.ts b/packages/app/src/components/dialog-custom-provider-form.ts index e26dcb09710d..1a9697d0a0f2 100644 --- a/packages/app/src/components/dialog-custom-provider-form.ts +++ b/packages/app/src/components/dialog-custom-provider-form.ts @@ -46,6 +46,7 @@ type ValidateArgs = { t: Translator disabledProviders: string[] existingProviderIDs: Set + editingProviderID?: string } export function validateCustomProvider(input: ValidateArgs) { @@ -73,7 +74,7 @@ export function validateCustomProvider(input: ValidateArgs) { const disabled = input.disabledProviders.includes(providerID) const existsError = idError ? undefined - : input.existingProviderIDs.has(providerID) && !disabled + : input.existingProviderIDs.has(providerID) && !disabled && providerID !== input.editingProviderID ? input.t("provider.custom.error.providerID.exists") : undefined diff --git a/packages/app/src/components/dialog-custom-provider.tsx b/packages/app/src/components/dialog-custom-provider.tsx index ad30236b0410..65c9f362efdf 100644 --- a/packages/app/src/components/dialog-custom-provider.tsx +++ b/packages/app/src/components/dialog-custom-provider.tsx @@ -17,6 +17,8 @@ import { DialogSelectProvider } from "./dialog-select-provider" type Props = { back?: "providers" | "close" + initialConfig?: Partial + originalProviderID?: string } export function DialogCustomProvider(props: Props) { @@ -26,12 +28,12 @@ export function DialogCustomProvider(props: Props) { const language = useLanguage() const [form, setForm] = createStore({ - providerID: "", - name: "", - baseURL: "", - apiKey: "", - models: [modelRow()], - headers: [headerRow()], + providerID: props.initialConfig?.providerID ?? "", + name: props.initialConfig?.name ?? "", + baseURL: props.initialConfig?.baseURL ?? "", + apiKey: props.initialConfig?.apiKey ?? "", + models: props.initialConfig?.models ?? [modelRow()], + headers: props.initialConfig?.headers ?? [headerRow()], err: {}, }) @@ -107,6 +109,7 @@ export function DialogCustomProvider(props: Props) { t: language.t, disabledProviders: serverSync.data.config.disabled_providers ?? [], existingProviderIDs: new Set(serverSync.data.provider.all.keys()), + editingProviderID: props.originalProviderID, }) batch(() => { setForm("err", output.err) @@ -199,6 +202,7 @@ export function DialogCustomProvider(props: Props) { onChange={(v) => setField("providerID", v)} validationState={form.err.providerID ? "invalid" : undefined} error={form.err.providerID} + disabled={!!props.originalProviderID} /> { if (editMutation.isPending) return setStore("editServer", { name: value, error: "" }) + void previewStatus(store.editServer.value, value, store.editServer.password, (next) => + setStore("editServer", { status: next }), + ) } const handleEditUsernameChange = (value: string) => { diff --git a/packages/app/src/components/settings-providers.tsx b/packages/app/src/components/settings-providers.tsx index ffd85f97dce1..f0cd68c3054a 100644 --- a/packages/app/src/components/settings-providers.tsx +++ b/packages/app/src/components/settings-providers.tsx @@ -11,6 +11,7 @@ import { useServerSync } from "@/context/server-sync" import { DialogConnectProvider } from "./dialog-connect-provider" import { DialogSelectProvider } from "./dialog-select-provider" import { DialogCustomProvider } from "./dialog-custom-provider" +import { headerRow, modelRow, type FormState } from "./dialog-custom-provider-form" import { SettingsList } from "./settings-list" type ProviderSource = "env" | "api" | "config" | "custom" @@ -81,6 +82,28 @@ export const SettingsProviders: Component = () => { return true } + const customProviderFormState = (providerID: string): Partial => { + const config = serverSync.data.config.provider?.[providerID] + if (!config) return { providerID } + const rawHeaders = config.options?.headers as Record | undefined + return { + providerID, + name: config.name ?? "", + baseURL: config.options?.baseURL ?? "", + apiKey: config.env?.[0] ? `{env:${config.env[0]}}` : "", + models: Object.entries(config.models ?? {}).map(([id, m]) => ({ + ...modelRow(), + id, + name: (m as { name?: string }).name ?? "", + })), + headers: Object.entries(rawHeaders ?? {}).map(([key, value]) => ({ + ...headerRow(), + key, + value, + })), + } + } + const disableProvider = async (providerID: string, name: string) => { const before = serverSync.data.config.disabled_providers ?? [] const next = before.includes(providerID) ? before : [...before, providerID] @@ -165,6 +188,26 @@ export const SettingsProviders: Component = () => { + )} From c99bd3f2431063dced4c170eee0d3b4aa7ae2353 Mon Sep 17 00:00:00 2001 From: Jason <6457032+solidblu@users.noreply.github.com> Date: Mon, 18 May 2026 21:37:13 -0400 Subject: [PATCH 2/3] fix: Disconnect and Edit in same div --- .../app/src/components/settings-providers.tsx | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/packages/app/src/components/settings-providers.tsx b/packages/app/src/components/settings-providers.tsx index f0cd68c3054a..80cec1d9d858 100644 --- a/packages/app/src/components/settings-providers.tsx +++ b/packages/app/src/components/settings-providers.tsx @@ -185,29 +185,31 @@ export const SettingsProviders: Component = () => { } > - - +
+ + +
)} From 2ca9378ebc1bd1678c5de5ec7e6e6d0270726236 Mon Sep 17 00:00:00 2001 From: Jason <6457032+solidblu@users.noreply.github.com> Date: Sat, 23 May 2026 00:59:46 -0400 Subject: [PATCH 3/3] add circle-x to Disconnect for better look --- packages/app/src/components/settings-providers.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app/src/components/settings-providers.tsx b/packages/app/src/components/settings-providers.tsx index 80cec1d9d858..bb593408104c 100644 --- a/packages/app/src/components/settings-providers.tsx +++ b/packages/app/src/components/settings-providers.tsx @@ -186,7 +186,7 @@ export const SettingsProviders: Component = () => { } >
-