mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-21 10:16:03 +00:00
fix(app): persist home project selection (#33935)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { createStore, produce } from "solid-js/store"
|
||||
import { createStore, produce, reconcile } from "solid-js/store"
|
||||
import { batch, createEffect, createMemo, onCleanup, onMount, type Accessor } from "solid-js"
|
||||
import { useLocation } from "@solidjs/router"
|
||||
import { createSimpleContext } from "@opencode-ai/ui/context"
|
||||
@@ -73,6 +73,7 @@ type TabHandoff = {
|
||||
}
|
||||
|
||||
export type LocalProject = Partial<Project> & { worktree: string; expanded: boolean }
|
||||
export type HomeProjectSelection = { server: ServerConnection.Key; directory?: string }
|
||||
|
||||
export type ReviewDiffStyle = "unified" | "split"
|
||||
|
||||
@@ -290,6 +291,9 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
|
||||
handoff: {
|
||||
tabs: undefined as TabHandoff | undefined,
|
||||
},
|
||||
home: {
|
||||
selection: { server: server.key } as HomeProjectSelection,
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -579,6 +583,12 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
|
||||
return {
|
||||
route,
|
||||
ready,
|
||||
home: {
|
||||
selection: createMemo(() => store.home.selection),
|
||||
setSelection(selection: HomeProjectSelection) {
|
||||
setStore("home", "selection", reconcile(selection))
|
||||
},
|
||||
},
|
||||
handoff: {
|
||||
tabs: createMemo(() => store.handoff?.tabs),
|
||||
setTabs(dir: string, id: string) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { Session } from "@opencode-ai/sdk/v2/client"
|
||||
import {
|
||||
batch,
|
||||
createEffect,
|
||||
createMemo,
|
||||
createRoot,
|
||||
@@ -26,7 +25,12 @@ import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon"
|
||||
import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2"
|
||||
import { MenuV2 } from "@opencode-ai/ui/v2/menu-v2"
|
||||
import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2"
|
||||
import { getProjectAvatarVariant, useLayout, type LocalProject } from "@/context/layout"
|
||||
import {
|
||||
getProjectAvatarVariant,
|
||||
useLayout,
|
||||
type HomeProjectSelection,
|
||||
type LocalProject,
|
||||
} from "@/context/layout"
|
||||
import { useNavigate } from "@solidjs/router"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { Icon } from "@opencode-ai/ui/icon"
|
||||
@@ -47,7 +51,6 @@ import {
|
||||
errorMessage,
|
||||
getProjectAvatarSource,
|
||||
homeProjectDirectories,
|
||||
type HomeProjectSelection,
|
||||
projectForSession,
|
||||
sortedRootSessions,
|
||||
toggleHomeProjectSelection,
|
||||
@@ -149,12 +152,12 @@ export function NewHome() {
|
||||
let focusSessionSearch: (() => void) | undefined
|
||||
const [state, setState] = createStore({
|
||||
search: "",
|
||||
selection: { server: server.key } as HomeProjectSelection,
|
||||
searchFocused: false,
|
||||
})
|
||||
const selection = layout.home.selection
|
||||
|
||||
const focusedServer = createMemo(
|
||||
() => global.servers.list().find((conn) => ServerConnection.key(conn) === state.selection.server) ?? server.current,
|
||||
() => global.servers.list().find((conn) => ServerConnection.key(conn) === selection().server) ?? server.current,
|
||||
)
|
||||
const focusedServerCtx = createMemo(() => {
|
||||
const conn = focusedServer()
|
||||
@@ -163,7 +166,7 @@ export function NewHome() {
|
||||
})
|
||||
const focusedSync = () => focusedServerCtx()?.sync ?? sync()
|
||||
const projects = createMemo(() => focusedServerCtx()?.projects.list() ?? layout.projects.list())
|
||||
const selectedProject = createMemo(() => projects().find((project) => project.worktree === state.selection.directory))
|
||||
const selectedProject = createMemo(() => projects().find((project) => project.worktree === selection().directory))
|
||||
const newSessionProject = createMemo(
|
||||
() =>
|
||||
selectedProject() ??
|
||||
@@ -191,7 +194,7 @@ export function NewHome() {
|
||||
return language.t("home.sessions.search.placeholder")
|
||||
})
|
||||
const sessionLoad = useQuery(() => ({
|
||||
queryKey: ["home", "sessions", state.selection.server, ...projectDirectories()] as const,
|
||||
queryKey: ["home", "sessions", selection().server, ...projectDirectories()] as const,
|
||||
queryFn: async () => {
|
||||
await Promise.all(
|
||||
projectDirectories().map((directory) =>
|
||||
@@ -257,10 +260,7 @@ export function NewHome() {
|
||||
})
|
||||
|
||||
function setSelection(next: HomeProjectSelection) {
|
||||
batch(() => {
|
||||
if (state.selection.server !== next.server) setState("selection", "server", next.server)
|
||||
if (state.selection.directory !== next.directory) setState("selection", "directory", next.directory)
|
||||
})
|
||||
layout.home.setSelection(next)
|
||||
}
|
||||
|
||||
function closeSearch() {
|
||||
@@ -285,7 +285,7 @@ export function NewHome() {
|
||||
|
||||
createEffect(() => {
|
||||
const list = global.servers.list()
|
||||
if (list.some((conn) => ServerConnection.key(conn) === state.selection.server)) return
|
||||
if (list.some((conn) => ServerConnection.key(conn) === selection().server)) return
|
||||
const conn = list.find((conn) => ServerConnection.key(conn) === server.key) ?? list[0]
|
||||
if (conn) setSelection({ server: ServerConnection.key(conn) })
|
||||
})
|
||||
@@ -310,7 +310,7 @@ export function NewHome() {
|
||||
.some((project) => project.worktree === directory)
|
||||
)
|
||||
return
|
||||
setSelection(toggleHomeProjectSelection(state.selection, key, directory))
|
||||
setSelection(toggleHomeProjectSelection(selection(), key, directory))
|
||||
}
|
||||
|
||||
function addProjects(conn: ServerConnection.Any, directories: string[]) {
|
||||
@@ -418,7 +418,7 @@ export function NewHome() {
|
||||
<div class="mx-auto grid h-full w-full max-w-[1080px] grid-rows-[auto_minmax(0,1fr)_auto] gap-4 px-3 pb-3 lg:grid-cols-[280px_minmax(0,720px)] lg:grid-rows-1 lg:gap-8 lg:px-6 lg:pb-16">
|
||||
<HomeProjectColumn
|
||||
projects={projects()}
|
||||
selected={state.selection}
|
||||
selected={selection()}
|
||||
focusServer={focusServer}
|
||||
selectProject={selectProject}
|
||||
openNewSession={openProjectNewSession}
|
||||
@@ -426,7 +426,7 @@ export function NewHome() {
|
||||
editProject={editProject}
|
||||
closeProject={(conn, directory) => {
|
||||
const next = closeHomeProject(
|
||||
state.selection,
|
||||
selection(),
|
||||
ServerConnection.key(conn),
|
||||
global.ensureServerCtx(conn).projects,
|
||||
directory,
|
||||
@@ -451,8 +451,8 @@ export function NewHome() {
|
||||
loading={sessionLoad.isLoading}
|
||||
results={searchResults()}
|
||||
showProjectName={!selectedProject()}
|
||||
server={state.selection.server}
|
||||
activeServer={state.selection.server === server.key}
|
||||
server={selection().server}
|
||||
activeServer={selection().server === server.key}
|
||||
noResultsLabel={language.t("home.sessions.search.noResults", { query: search() })}
|
||||
bindFocus={(focus) => {
|
||||
focusSessionSearch = focus
|
||||
@@ -489,8 +489,8 @@ export function NewHome() {
|
||||
<HomeSessionRow
|
||||
record={record}
|
||||
showProjectName={!selectedProject()}
|
||||
server={state.selection.server}
|
||||
activeServer={state.selection.server === server.key}
|
||||
server={selection().server}
|
||||
activeServer={selection().server === server.key}
|
||||
openSession={openSession}
|
||||
archiveSession={archiveSession}
|
||||
/>
|
||||
|
||||
@@ -2,6 +2,7 @@ import { getFilename } from "@opencode-ai/core/util/path"
|
||||
import { type Session } from "@opencode-ai/sdk/v2/client"
|
||||
import { pathKey } from "@/utils/path-key"
|
||||
import type { ServerConnection } from "@/context/server"
|
||||
import type { HomeProjectSelection } from "@/context/layout"
|
||||
|
||||
type SessionStore = {
|
||||
session?: Session[]
|
||||
@@ -56,8 +57,6 @@ export const childSessionOnPath = (sessions: Session[] | undefined, rootID: stri
|
||||
export const displayName = (project: { name?: string; worktree: string }) =>
|
||||
project.name || getFilename(project.worktree) || project.worktree
|
||||
|
||||
export type HomeProjectSelection = { server: ServerConnection.Key; directory?: string }
|
||||
|
||||
export function toggleHomeProjectSelection(
|
||||
current: HomeProjectSelection | undefined,
|
||||
server: ServerConnection.Key,
|
||||
|
||||
Reference in New Issue
Block a user