From 3bb546c94d6bb295bfeafdafbb9d34b7cc462560 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Wed, 10 Dec 2025 21:16:50 -0600 Subject: wip(desktop): progress --- packages/desktop/src/pages/layout.tsx | 213 +++++++++++++++++++++++++++++++++- 1 file changed, 210 insertions(+), 3 deletions(-) (limited to 'packages/desktop/src/pages') diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index 10d4cbfda..0ba6c0a2d 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -17,7 +17,7 @@ import { DiffChanges } from "@opencode-ai/ui/diff-changes" import { getFilename } from "@opencode-ai/util/path" import { Select } from "@opencode-ai/ui/select" import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu" -import { Session, Project } from "@opencode-ai/sdk/v2/client" +import { Session, Project, ProviderAuthMethod } from "@opencode-ai/sdk/v2/client" import { usePlatform } from "@/context/platform" import { createStore } from "solid-js/store" import { @@ -34,6 +34,11 @@ import { SelectDialog } from "@opencode-ai/ui/select-dialog" import { Tag } from "@opencode-ai/ui/tag" import { IconName } from "@opencode-ai/ui/icons/provider" import { popularProviders, useProviders } from "@/hooks/use-providers" +import { Dialog } from "@opencode-ai/ui/dialog" +import { iife } from "@opencode-ai/util/iife" +import { List, ListRef } from "@opencode-ai/ui/list" +import { Input } from "@opencode-ai/ui/input" +import { useGlobalSDK } from "@/context/global-sdk" export default function Layout(props: ParentProps) { const [store, setStore] = createStore({ @@ -42,6 +47,7 @@ export default function Layout(props: ParentProps) { }) const params = useParams() + const globalSDK = useGlobalSDK() const globalSync = useGlobalSync() const layout = useLayout() const platform = usePlatform() @@ -562,7 +568,6 @@ export default function Layout(props: ParentProps) { activeIcon="plus-small" key={(x) => x?.id} items={providers().all} - // current={local.model.current()} filterKeys={["id", "name"]} groupBy={(x) => (popularProviders.includes(x.id) ? "Popular" : "Other")} sortBy={(a, b) => { @@ -575,7 +580,10 @@ export default function Layout(props: ParentProps) { if (b.category === "Popular" && a.category !== "Popular") return 1 return 0 }} - // onSelect={(x) => } + onSelect={(x) => { + if (!x) return + layout.dialog.connect(x.id) + }} onOpenChange={(open) => { if (open) { layout.dialog.open("provider") @@ -607,6 +615,205 @@ export default function Layout(props: ParentProps) { )} + + {iife(() => { + const [store, setStore] = createStore({ + method: undefined as undefined | ProviderAuthMethod, + }) + const providerID = layout.connect.provider()! + const provider = globalSync.data.provider.all.find((x) => x.id === providerID)! + const methods = globalSync.data.provider_auth[providerID] ?? [ + { + type: "api", + label: "API key", + }, + ] + if (methods.length === 1) { + setStore("method", methods[0]) + } + + let listRef: ListRef | undefined + const handleKey = (e: KeyboardEvent) => { + if (e.key === "Escape") return + listRef?.onKeyDown(e) + } + + return ( + { + if (open) { + layout.dialog.open("connect") + } else { + layout.dialog.close("connect") + } + }} + > + + + { + if (store.method && methods.length > 1) { + setStore("method", undefined) + return + } + layout.dialog.open("provider") + }} + /> + + + + +
+
+ +
Connect {provider.name}
+
+ +
Select login method for {provider.name}.
+
+ + (listRef = ref)} + items={methods} + key={(m) => m?.label} + onSelect={(method) => { + if (!method) return + setStore("method", method) + + if (method.type === "oauth") { + // const result = await sdk.client.provider.oauth.authorize({ + // providerID: provider.id, + // method: index, + // }) + // if (result.data?.method === "code") { + // dialog.replace(() => ( + // + // )) + // } + // if (result.data?.method === "auto") { + // dialog.replace(() => ( + // + // )) + // } + } + if (method.type === "api") { + // return dialog.replace(() => ) + } + }} + > + {(i) => ( +
+ {/* TODO: add checkmark thing */} + {i.label} +
+ )} +
+
+
+ + {iife(() => { + const [formStore, setFormStore] = createStore({ + value: "", + error: undefined as string | undefined, + }) + + async function handleSubmit(e: SubmitEvent) { + e.preventDefault() + + const form = e.currentTarget as HTMLFormElement + const formData = new FormData(form) + const apiKey = formData.get("apiKey") as string + + if (!apiKey?.trim()) { + setFormStore("error", "API key is required") + return + } + + setFormStore("error", undefined) + globalSDK.client.auth.set({ + providerID, + auth: { + type: "api", + key: apiKey, + }, + }) + await globalSDK.client.instance.dispose() + } + + return ( +
+ + +
+
+ OpenCode Zen gives you access to a curated set of reliable optimized models for + coding agents. +
+
+ With a single API key you’ll get access to models such as Claude, GPT, Gemini, GLM + and more. +
+
+ Visit{" "} + {" "} + to collect your API key. +
+
+
+ +
+ Enter your {provider.name} API key to connect your account and use {provider.name}{" "} + models in OpenCode. +
+
+
+
+ + +
+
+ ) + })} +
+
+
+
+ ) + })} +
) -- cgit v1.2.3