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