From 2613f44961a73bc57db6662bfa1d0407515c497a Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Sun, 14 Dec 2025 06:39:08 -0600 Subject: wip(desktop): progress --- packages/desktop/src/components/dialog-connect.tsx | 74 ++++++++++------------ packages/desktop/src/components/dialog-model.tsx | 32 ++++------ .../desktop/src/components/dialog-provider.tsx | 68 -------------------- .../src/components/dialog-select-provider.tsx | 67 ++++++++++++++++++++ packages/desktop/src/components/prompt-input.tsx | 9 +-- 5 files changed, 119 insertions(+), 131 deletions(-) delete mode 100644 packages/desktop/src/components/dialog-provider.tsx create mode 100644 packages/desktop/src/components/dialog-select-provider.tsx (limited to 'packages/desktop/src/components') diff --git a/packages/desktop/src/components/dialog-connect.tsx b/packages/desktop/src/components/dialog-connect.tsx index a44365069..d482b3f50 100644 --- a/packages/desktop/src/components/dialog-connect.tsx +++ b/packages/desktop/src/components/dialog-connect.tsx @@ -1,6 +1,6 @@ import { Component, createMemo, Match, onCleanup, onMount, Switch } from "solid-js" import { createStore, produce } from "solid-js/store" -import { useLayout } from "@/context/layout" +import { useDialog } from "@/context/dialog" import { useGlobalSync } from "@/context/global-sync" import { useGlobalSDK } from "@/context/global-sdk" import { usePlatform } from "@/context/platform" @@ -17,18 +17,19 @@ import { ProviderIcon } from "@opencode-ai/ui/provider-icon" import { IconName } from "@opencode-ai/ui/icons/provider" import { iife } from "@opencode-ai/util/iife" import { Link } from "@/components/link" +import { DialogSelectProvider } from "./dialog-select-provider" +import { DialogModel } from "./dialog-model" -export const DialogConnect: Component = () => { - const layout = useLayout() +export const DialogConnect: Component<{ provider: string }> = (props) => { + const dialog = useDialog() const globalSync = useGlobalSync() const globalSDK = useGlobalSDK() const platform = usePlatform() - const providerID = createMemo(() => layout.connect.provider()!) - const provider = createMemo(() => globalSync.data.provider.all.find((x) => x.id === providerID())!) + const provider = createMemo(() => globalSync.data.provider.all.find((x) => x.id === props.provider)!) const methods = createMemo( () => - globalSync.data.provider_auth[providerID()] ?? [ + globalSync.data.provider_auth[props.provider] ?? [ { type: "api", label: "API key", @@ -61,7 +62,7 @@ export const DialogConnect: Component = () => { await globalSDK.client.provider.oauth .authorize( { - providerID: providerID(), + providerID: props.provider, method: index, }, { throwOnError: true }, @@ -116,55 +117,50 @@ export const DialogConnect: Component = () => { title: `${provider().name} connected`, description: `${provider().name} models are now available to use.`, }) - layout.connect.complete() + dialog.replace(() => ) }, 500) } + function goBack() { + if (methods().length === 1) { + dialog.replace(() => ) + return + } + if (store.authorization) { + setStore("authorization", undefined) + setStore("method", undefined) + return + } + if (store.method) { + setStore("method", undefined) + return + } + dialog.replace(() => ) + } + return ( { - if (open) { - layout.dialog.open("connect") - } else { - layout.dialog.close("connect") + if (!open) { + dialog.clear() } }} > - { - if (methods().length === 1) { - layout.dialog.open("provider") - return - } - if (store.authorization) { - setStore("authorization", undefined) - setStore("method", undefined) - return - } - if (store.method) { - setStore("method", undefined) - return - } - layout.dialog.open("provider") - }} - /> + - + - + Login with Claude Pro/Max Connect {provider().name} @@ -233,7 +229,7 @@ export const DialogConnect: Component = () => { setFormStore("error", undefined) await globalSDK.client.auth.set({ - providerID: providerID(), + providerID: props.provider, auth: { type: "api", key: apiKey, @@ -320,7 +316,7 @@ export const DialogConnect: Component = () => { setFormStore("error", undefined) const { error } = await globalSDK.client.provider.oauth.callback({ - providerID: providerID(), + providerID: props.provider, method: methodIndex(), code, }) @@ -369,12 +365,12 @@ export const DialogConnect: Component = () => { onMount(async () => { const result = await globalSDK.client.provider.oauth.callback({ - providerID: providerID(), + providerID: props.provider, method: methodIndex(), }) if (result.error) { // TODO: show error - layout.dialog.close("connect") + dialog.clear() return } await complete() diff --git a/packages/desktop/src/components/dialog-model.tsx b/packages/desktop/src/components/dialog-model.tsx index 9d36e0797..7f90e1a78 100644 --- a/packages/desktop/src/components/dialog-model.tsx +++ b/packages/desktop/src/components/dialog-model.tsx @@ -1,6 +1,6 @@ import { Component, createMemo, Match, onCleanup, onMount, Show, Switch } from "solid-js" import { useLocal } from "@/context/local" -import { useLayout } from "@/context/layout" +import { useDialog } from "@/context/dialog" import { popularProviders, useProviders } from "@/hooks/use-providers" import { SelectDialog } from "@opencode-ai/ui/select-dialog" import { Button } from "@opencode-ai/ui/button" @@ -10,10 +10,12 @@ import { List, ListRef } from "@opencode-ai/ui/list" import { iife } from "@opencode-ai/util/iife" import { ProviderIcon } from "@opencode-ai/ui/provider-icon" import { IconName } from "@opencode-ai/ui/icons/provider" +import { DialogSelectProvider } from "./dialog-select-provider" +import { DialogConnect } from "./dialog-connect" -export const DialogModel: Component = () => { +export const DialogModel: Component<{ connectedProvider?: string }> = (props) => { const local = useLocal() - const layout = useLayout() + const dialog = useDialog() const providers = useProviders() return ( @@ -24,18 +26,14 @@ export const DialogModel: Component = () => { local.model .list() .filter((m) => m.visible) - .filter((m) => - layout.connect.state() === "complete" ? m.provider.id === layout.connect.provider() : true, - ), + .filter((m) => (props.connectedProvider ? m.provider.id === props.connectedProvider : true)), ) return ( { - if (open) { - layout.dialog.open("model") - } else { - layout.dialog.close("model") + if (!open) { + dialog.clear() } }} title="Select model" @@ -66,7 +64,7 @@ export const DialogModel: Component = () => { class="h-7 -my-1 text-14-medium" icon="plus-small" tabIndex={-1} - onClick={() => layout.dialog.open("provider")} + onClick={() => dialog.replace(() => )} > Connect provider @@ -107,10 +105,8 @@ export const DialogModel: Component = () => { modal defaultOpen onOpenChange={(open) => { - if (open) { - layout.dialog.open("model") - } else { - layout.dialog.close("model") + if (!open) { + dialog.clear() } }} > @@ -130,7 +126,7 @@ export const DialogModel: Component = () => { local.model.set(x ? { modelID: x.id, providerID: x.provider.id } : undefined, { recent: true, }) - layout.dialog.close("model") + dialog.clear() }} > {(i) => ( @@ -163,7 +159,7 @@ export const DialogModel: Component = () => { }} onSelect={(x) => { if (!x) return - layout.dialog.connect(x.id) + dialog.replace(() => ) }} > {(i) => ( @@ -193,7 +189,7 @@ export const DialogModel: Component = () => { class="w-full justify-start px-[11px] py-3.5 gap-4.5 text-14-medium" icon="dot-grid" onClick={() => { - layout.dialog.open("provider") + dialog.replace(() => ) }} > View all providers diff --git a/packages/desktop/src/components/dialog-provider.tsx b/packages/desktop/src/components/dialog-provider.tsx deleted file mode 100644 index 56c791479..000000000 --- a/packages/desktop/src/components/dialog-provider.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { Component, Show } from "solid-js" -import { useLayout } from "@/context/layout" -import { popularProviders, useProviders } from "@/hooks/use-providers" -import { SelectDialog } from "@opencode-ai/ui/select-dialog" -import { Tag } from "@opencode-ai/ui/tag" -import { ProviderIcon } from "@opencode-ai/ui/provider-icon" -import { IconName } from "@opencode-ai/ui/icons/provider" - -export const DialogProvider: Component = () => { - const layout = useLayout() - const providers = useProviders() - - return ( - x?.id} - items={providers.all} - filterKeys={["id", "name"]} - groupBy={(x) => (popularProviders.includes(x.id) ? "Popular" : "Other")} - sortBy={(a, b) => { - if (popularProviders.includes(a.id) && popularProviders.includes(b.id)) - return popularProviders.indexOf(a.id) - popularProviders.indexOf(b.id) - return a.name.localeCompare(b.name) - }} - sortGroupsBy={(a, b) => { - if (a.category === "Popular" && b.category !== "Popular") return -1 - if (b.category === "Popular" && a.category !== "Popular") return 1 - return 0 - }} - onSelect={(x) => { - if (!x) return - layout.dialog.connect(x.id) - }} - onOpenChange={(open) => { - if (open) { - layout.dialog.open("provider") - } else { - layout.dialog.close("provider") - } - }} - > - {(i) => ( - - - {i.name} - - Recommended - - - Connect with Claude Pro/Max or API key - - - )} - - ) -} diff --git a/packages/desktop/src/components/dialog-select-provider.tsx b/packages/desktop/src/components/dialog-select-provider.tsx new file mode 100644 index 000000000..6dabdb8b4 --- /dev/null +++ b/packages/desktop/src/components/dialog-select-provider.tsx @@ -0,0 +1,67 @@ +import { Component, Show } from "solid-js" +import { useDialog } from "@/context/dialog" +import { popularProviders, useProviders } from "@/hooks/use-providers" +import { SelectDialog } from "@opencode-ai/ui/select-dialog" +import { Tag } from "@opencode-ai/ui/tag" +import { ProviderIcon } from "@opencode-ai/ui/provider-icon" +import { IconName } from "@opencode-ai/ui/icons/provider" +import { DialogConnect } from "./dialog-connect" + +export const DialogSelectProvider: Component = () => { + const dialog = useDialog() + const providers = useProviders() + + return ( + x?.id} + items={providers.all} + filterKeys={["id", "name"]} + groupBy={(x) => (popularProviders.includes(x.id) ? "Popular" : "Other")} + sortBy={(a, b) => { + if (popularProviders.includes(a.id) && popularProviders.includes(b.id)) + return popularProviders.indexOf(a.id) - popularProviders.indexOf(b.id) + return a.name.localeCompare(b.name) + }} + sortGroupsBy={(a, b) => { + if (a.category === "Popular" && b.category !== "Popular") return -1 + if (b.category === "Popular" && a.category !== "Popular") return 1 + return 0 + }} + onSelect={(x) => { + if (!x) return + dialog.replace(() => ) + }} + onOpenChange={(open) => { + if (!open) { + dialog.clear() + } + }} + > + {(i) => ( + + + {i.name} + + Recommended + + + Connect with Claude Pro/Max or API key + + + )} + + ) +} diff --git a/packages/desktop/src/components/prompt-input.tsx b/packages/desktop/src/components/prompt-input.tsx index 7c60a6d01..ca0ccf96a 100644 --- a/packages/desktop/src/components/prompt-input.tsx +++ b/packages/desktop/src/components/prompt-input.tsx @@ -15,7 +15,7 @@ import { Tooltip } from "@opencode-ai/ui/tooltip" import { IconButton } from "@opencode-ai/ui/icon-button" import { Select } from "@opencode-ai/ui/select" import { getDirectory, getFilename } from "@opencode-ai/util/path" -import { useLayout } from "@/context/layout" +import { useDialog } from "@/context/dialog" import { DialogModel } from "@/components/dialog-model" interface PromptInputProps { @@ -57,7 +57,7 @@ export const PromptInput: Component = (props) => { const sync = useSync() const local = useLocal() const session = useSession() - const layout = useLayout() + const dialog = useDialog() let editorRef!: HTMLDivElement const [store, setStore] = createStore<{ @@ -610,14 +610,11 @@ export const PromptInput: Component = (props) => { class="capitalize" variant="ghost" /> - layout.dialog.open("model")}> + dialog.push(() => )}> {local.model.current()?.name ?? "Select model"} {local.model.current()?.provider.name} - - -