diff options
| author | Adam <[email protected]> | 2026-01-02 20:17:02 -0600 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-01-02 20:17:02 -0600 |
| commit | 052de3c556097a983c7c27e9a9a9cbc5d22b13c5 (patch) | |
| tree | 6b2f8d7d74e1027a110f8ee17ab9fd538c25ccfd /packages/app/src/components/session | |
| parent | f6fe709f6ee75427ba64829af25b64d9a3111569 (diff) | |
| download | opencode-052de3c556097a983c7c27e9a9a9cbc5d22b13c5.tar.gz opencode-052de3c556097a983c7c27e9a9a9cbc5d22b13c5.zip | |
feat: add managed git worktrees (#6674)
Diffstat (limited to 'packages/app/src/components/session')
| -rw-r--r-- | packages/app/src/components/session/session-header.tsx | 17 | ||||
| -rw-r--r-- | packages/app/src/components/session/session-new-view.tsx | 48 |
2 files changed, 53 insertions, 12 deletions
diff --git a/packages/app/src/components/session/session-header.tsx b/packages/app/src/components/session/session-header.tsx index 0a0b53607..7e4ade523 100644 --- a/packages/app/src/components/session/session-header.tsx +++ b/packages/app/src/components/session/session-header.tsx @@ -1,4 +1,4 @@ -import { createMemo, createResource, Show } from "solid-js" +import { createEffect, createMemo, createResource, Show } from "solid-js" import { A, useNavigate, useParams } from "@solidjs/router" import { useLayout } from "@/context/layout" import { useCommand } from "@/context/command" @@ -7,7 +7,7 @@ import { useDialog } from "@opencode-ai/ui/context/dialog" import { useSync } from "@/context/sync" import { useGlobalSDK } from "@/context/global-sdk" import { getFilename } from "@opencode-ai/util/path" -import { base64Encode } from "@opencode-ai/util/encode" +import { base64Decode, base64Encode } from "@opencode-ai/util/encode" import { iife } from "@opencode-ai/util/iife" import { Icon } from "@opencode-ai/ui/icon" import { IconButton } from "@opencode-ai/ui/icon-button" @@ -31,10 +31,11 @@ export function SessionHeader() { const dialog = useDialog() const sync = useSync() + const projectDirectory = createMemo(() => base64Decode(params.dir ?? "")) + const sessions = createMemo(() => (sync.data.session ?? []).filter((s) => !s.parentID)) const currentSession = createMemo(() => sessions().find((s) => s.id === params.id)) const shareEnabled = createMemo(() => sync.data.config.share !== "disabled") - const branch = createMemo(() => sync.data.vcs?.branch) function navigateToProject(directory: string) { navigate(`/${base64Encode(directory)}`) @@ -60,12 +61,8 @@ export function SessionHeader() { <div class="hidden xl:flex items-center gap-2"> <Select options={layout.projects.list().map((project) => project.worktree)} - current={sync.directory} - label={(x) => { - const name = getFilename(x) - const b = x === sync.directory ? branch() : undefined - return b ? `${name}:${b}` : name - }} + current={sync.project?.worktree ?? projectDirectory()} + label={(x) => getFilename(x)} onSelect={(x) => (x ? navigateToProject(x) : undefined)} class="text-14-regular text-text-base" variant="ghost" @@ -191,7 +188,7 @@ export function SessionHeader() { let shareURL = session.share?.url if (!shareURL) { shareURL = await globalSDK.client.session - .share({ sessionID: session.id, directory: sync.directory }) + .share({ sessionID: session.id, directory: projectDirectory() }) .then((r) => r.data?.share?.url) .catch((e) => { console.error("Failed to share session", e) diff --git a/packages/app/src/components/session/session-new-view.tsx b/packages/app/src/components/session/session-new-view.tsx index 90a280612..bd8033ae6 100644 --- a/packages/app/src/components/session/session-new-view.tsx +++ b/packages/app/src/components/session/session-new-view.tsx @@ -1,12 +1,41 @@ -import { Show } from "solid-js" +import { Show, createMemo } from "solid-js" import { DateTime } from "luxon" import { useSync } from "@/context/sync" import { Icon } from "@opencode-ai/ui/icon" import { getDirectory, getFilename } from "@opencode-ai/util/path" +import { Select } from "@opencode-ai/ui/select" -export function NewSessionView() { +const MAIN_WORKTREE = "main" +const CREATE_WORKTREE = "create" + +interface NewSessionViewProps { + worktree: string + onWorktreeChange: (value: string) => void +} + +export function NewSessionView(props: NewSessionViewProps) { const sync = useSync() + const sandboxes = createMemo(() => sync.project?.sandboxes ?? []) + const options = createMemo(() => [MAIN_WORKTREE, ...sandboxes(), CREATE_WORKTREE]) + const current = createMemo(() => { + const selection = props.worktree + if (options().includes(selection)) return selection + return MAIN_WORKTREE + }) + + const label = (value: string) => { + if (value === MAIN_WORKTREE) { + const branch = sync.data.vcs?.branch + if (branch) return `Current branch (${branch})` + return "Main branch" + } + + if (value === CREATE_WORKTREE) return "Create new worktree" + + return getFilename(value) + } + return ( <div class="size-full flex flex-col pb-45 justify-end items-start gap-4 flex-[1_0_0] self-stretch max-w-200 mx-auto px-6"> <div class="text-20-medium text-text-weaker">New session</div> @@ -17,6 +46,21 @@ export function NewSessionView() { <span class="text-text-strong">{getFilename(sync.data.path.directory)}</span> </div> </div> + <div class="flex justify-center items-center gap-1"> + <Icon name="branch" size="small" /> + <Select + options={options()} + current={current()} + value={(x) => x} + label={label} + onSelect={(value) => { + props.onWorktreeChange(value ?? MAIN_WORKTREE) + }} + size="normal" + variant="ghost" + class="text-12-medium" + /> + </div> <Show when={sync.project}> {(project) => ( <div class="flex justify-center items-center gap-3"> |
