mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-13 19:46:16 +03:00
fix(app): keep Search projects to the project list (#58978)
Co-authored-by: vimtor <36263538+vimtor@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
32db0d5dba
commit
507fc19e82
@@ -153,6 +153,12 @@ test("Search projects opens a new session's project picker from a session and fr
|
||||
await dialog.getByRole("option", { name: /^Search projects/ }).click()
|
||||
await expect(page).toHaveURL(/\/new-session\?draftId=.+$/)
|
||||
await expect(picker).toBeFocused()
|
||||
// Just the projects: no "Add project", no worktrees and no key hints.
|
||||
const projects = page.getByRole("dialog").getByRole("option")
|
||||
await expect(projects).toHaveCount(1)
|
||||
await expect(projects).toHaveText(/command-palette/)
|
||||
await expect(projects.getByRole("button", { name: "Worktrees", exact: true })).toHaveCount(0)
|
||||
await expect(page.locator(".new-session-location-hints")).toHaveCount(0)
|
||||
await picker.press("Escape")
|
||||
await expect(picker).toHaveCount(0)
|
||||
await expect(editor).toBeFocused()
|
||||
|
||||
@@ -34,7 +34,8 @@ type LocationEntry =
|
||||
|
||||
/**
|
||||
* Opens the new-session location dialog: one project list across every ready server, → on a Git project lists where
|
||||
* the session can run, and → on "Add project" picks the server when there are several.
|
||||
* the session can run, and → on "Add project" picks the server when there are several. Search projects passes
|
||||
* `projectsOnly` for just the project list: no "Add project", no worktrees and no key hints, like the other palettes.
|
||||
*/
|
||||
export function useNewSessionLocationDialog(input: {
|
||||
project: PromptProjectController
|
||||
@@ -43,13 +44,14 @@ export function useNewSessionLocationDialog(input: {
|
||||
}) {
|
||||
const dialog = useDialog()
|
||||
|
||||
return (options?: { onWorkspace?: (value: string) => void }) => {
|
||||
return (options?: { onWorkspace?: (value: string) => void; projectsOnly?: boolean }) => {
|
||||
void dialog.show(
|
||||
() => (
|
||||
<NewSessionLocationDialog
|
||||
project={input.project}
|
||||
workspace={input.workspace}
|
||||
onWorkspace={options?.onWorkspace}
|
||||
projectsOnly={options?.projectsOnly}
|
||||
/>
|
||||
),
|
||||
input.onDone,
|
||||
@@ -61,6 +63,7 @@ function NewSessionLocationDialog(props: {
|
||||
project: PromptProjectController
|
||||
workspace: NewSessionWorkspaceController
|
||||
onWorkspace?: (value: string) => void
|
||||
projectsOnly?: boolean
|
||||
}) {
|
||||
const dialog = useDialog()
|
||||
const language = useLanguage()
|
||||
@@ -127,7 +130,7 @@ function NewSessionLocationDialog(props: {
|
||||
.projects()
|
||||
.filter((project) => matches(displayName(project), project.worktree, tagged(project.server)?.name))
|
||||
.map((project) => ({ id: projectEntryID(project), type: "project" as const, project })),
|
||||
addEntry,
|
||||
...(props.projectsOnly ? [] : [addEntry]),
|
||||
])
|
||||
|
||||
const serverEntries = createMemo<LocationEntry[]>(() =>
|
||||
@@ -163,7 +166,9 @@ function NewSessionLocationDialog(props: {
|
||||
return projectEntries()
|
||||
}
|
||||
|
||||
const pinned = () => !store.drilled && !store.picking
|
||||
const pinned = () => !props.projectsOnly && !store.drilled && !store.picking
|
||||
|
||||
const drillable = (project: PromptProject) => !props.projectsOnly && !!project.id && project.vcs === "git"
|
||||
|
||||
const listEntries = () => entries().filter((entry) => entry.type !== "add")
|
||||
|
||||
@@ -439,28 +444,30 @@ function NewSessionLocationDialog(props: {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="new-session-location-hints">
|
||||
<span>
|
||||
<Keybind keys={["↵"]} variant="neutral" />
|
||||
{language.t("session.new.location.select")}
|
||||
</span>
|
||||
<Show
|
||||
when={store.drilled || store.picking}
|
||||
fallback={
|
||||
<span>
|
||||
<Keybind keys={["→"]} variant="neutral" />
|
||||
{activeEntry()?.type === "add" && choosesServer()
|
||||
? language.t("session.new.location.servers")
|
||||
: language.t("session.new.location.worktrees")}
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<Show when={!props.projectsOnly}>
|
||||
<div class="new-session-location-hints">
|
||||
<span>
|
||||
<Keybind keys={["←"]} variant="neutral" />
|
||||
{language.t("session.new.location.back")}
|
||||
<Keybind keys={["↵"]} variant="neutral" />
|
||||
{language.t("session.new.location.select")}
|
||||
</span>
|
||||
</Show>
|
||||
</div>
|
||||
<Show
|
||||
when={store.drilled || store.picking}
|
||||
fallback={
|
||||
<span>
|
||||
<Keybind keys={["→"]} variant="neutral" />
|
||||
{activeEntry()?.type === "add" && choosesServer()
|
||||
? language.t("session.new.location.servers")
|
||||
: language.t("session.new.location.worktrees")}
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<span>
|
||||
<Keybind keys={["←"]} variant="neutral" />
|
||||
{language.t("session.new.location.back")}
|
||||
</span>
|
||||
</Show>
|
||||
</div>
|
||||
</Show>
|
||||
</DialogBody>
|
||||
</Dialog>
|
||||
)
|
||||
@@ -558,10 +565,6 @@ function WorkspaceRow(props: { title: string; value: string; description: string
|
||||
)
|
||||
}
|
||||
|
||||
function drillable(project: PromptProject) {
|
||||
return !!project.id && project.vcs === "git"
|
||||
}
|
||||
|
||||
function projectEntryID(project: PromptProject) {
|
||||
return `project:${project.server?.key ?? ""}:${project.worktree}`
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ export default function NewSessionPage(props: { draftId: string }) {
|
||||
restoreFocus: model.restoreFocus,
|
||||
project: {
|
||||
empty: project.empty,
|
||||
open: () => location(),
|
||||
open: () => location({ projectsOnly: true }),
|
||||
},
|
||||
workspace: {
|
||||
enabled: workspace.bar.visible,
|
||||
@@ -67,7 +67,7 @@ export default function NewSessionPage(props: { draftId: string }) {
|
||||
if (!ready) return
|
||||
|
||||
// Search projects opened this draft; the picker returns focus to the composer when it closes.
|
||||
if (layout.draft.projectSearch.take()) location()
|
||||
if (layout.draft.projectSearch.take()) location({ projectsOnly: true })
|
||||
else model.restoreFocus()
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -37,7 +37,7 @@ import { TitlebarItems, useTitlebarItems } from "@/runtime/extension/titlebar-it
|
||||
|
||||
export const newTabCommand = { id: "tab.new", keybind: "mod+t,mod+n" }
|
||||
|
||||
/** A draft registers its own Search projects; everywhere else it opens a new draft with the project picker open. */
|
||||
/** Search projects: a draft searches in place; everywhere else it opens a new draft with the project picker open. */
|
||||
export const projectSearchCommand = { id: "project.select", keybind: "mod+shift+o" }
|
||||
|
||||
export const goBackCommand = { id: "common.goBack", keybind: "mod+[" }
|
||||
@@ -556,16 +556,19 @@ export function Titlebar(props: { verticalTabs?: { mount?: HTMLElement } }) {
|
||||
tabsStoreActions.closeTab(tabsStore.findIndex((tab) => current === tab))
|
||||
},
|
||||
},
|
||||
{
|
||||
...projectSearchCommand,
|
||||
title: language.t("session.new.project.search"),
|
||||
category: language.t("command.category.project"),
|
||||
onSelect: () => {
|
||||
layout.draft.projectSearch.request()
|
||||
// A draft registers its own, which searches projects in place.
|
||||
layout.route().type === "draft"
|
||||
? undefined
|
||||
: {
|
||||
...projectSearchCommand,
|
||||
title: language.t("session.new.project.search"),
|
||||
category: language.t("command.category.project"),
|
||||
onSelect: () => {
|
||||
layout.draft.projectSearch.request()
|
||||
|
||||
if (!openNewTab()) layout.draft.projectSearch.take()
|
||||
},
|
||||
},
|
||||
if (!openNewTab()) layout.draft.projectSearch.take()
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "tab.reopenClosed",
|
||||
category: language.t("command.category.file"),
|
||||
|
||||
Reference in New Issue
Block a user