mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-14 12:10:45 +03:00
feat(app): add an Add project button to the location search
This commit is contained in:
@@ -224,11 +224,11 @@ test("Home lists the used server projects by recent activity, hides them, and li
|
||||
await newSessionLocation(page).click()
|
||||
const options = page.getByRole("dialog").getByRole("option")
|
||||
await expect(options.locator(".command-palette-title")).toHaveText([
|
||||
"Add project",
|
||||
"oldest",
|
||||
"fresh",
|
||||
"unused",
|
||||
"recent",
|
||||
"Add project",
|
||||
])
|
||||
await options.filter({ hasText: "C:/OpenCode/recent" }).click()
|
||||
await expect(newSessionLocation(page)).toContainText("recent")
|
||||
|
||||
@@ -590,6 +590,7 @@ test("the location dialog lists every ready server's projects in one list and ta
|
||||
const paths = options.locator(".command-palette-description")
|
||||
const chip = dialog.getByRole("button", { name: "Back to projects", exact: true })
|
||||
const heading = dialog.getByText("Projects", { exact: true })
|
||||
const addButton = dialog.getByRole("button", { name: "Add project", exact: true })
|
||||
// Used projects first, then the rest, each by recent activity across servers; only remote ones carry a tag.
|
||||
await expect(names).toHaveText(["opencodeapollo", "opencode", "console", "sstapollo"])
|
||||
await expect(paths).toHaveText(["/home/dax/opencode", "C:/work/opencode", "C:/work/console", "/home/dax/sst"])
|
||||
@@ -606,6 +607,10 @@ test("the location dialog lists every ready server's projects in one list and ta
|
||||
})
|
||||
.toBe(true)
|
||||
await expect(rows.nth(0)).toHaveAttribute("aria-selected", "true")
|
||||
// The search field also ends with an "Add project" button, next in the Tab order.
|
||||
await page.keyboard.press("Tab")
|
||||
await expect(addButton).toBeFocused()
|
||||
await search.focus()
|
||||
|
||||
// The picker shares the palette's full-width search, compact rows, and single-line titles.
|
||||
await expect(rows.nth(0)).toHaveCSS("height", "36px")
|
||||
@@ -644,6 +649,7 @@ test("the location dialog lists every ready server's projects in one list and ta
|
||||
await page.keyboard.press("ArrowRight")
|
||||
// The worktree step has no "Add project".
|
||||
await expect(add).toHaveCount(0)
|
||||
await expect(addButton).toHaveCount(0)
|
||||
await expect(chip).toContainText("opencode")
|
||||
await expect(chip.locator('[data-component="tag"]')).toHaveText("apollo")
|
||||
await expect(options.locator(".command-palette-title")).toHaveText(["opencode", "New worktree", "opencode-beta"])
|
||||
@@ -672,6 +678,13 @@ test("the location dialog lists every ready server's projects in one list and ta
|
||||
await page.keyboard.press("ArrowUp")
|
||||
await page.keyboard.press("ArrowRight")
|
||||
await expect(chip).toHaveText("Add project")
|
||||
await expect(addButton).toHaveCount(0)
|
||||
// The search field's button starts the same flow.
|
||||
await page.keyboard.press("Backspace")
|
||||
await expect(addButton).toBeVisible()
|
||||
await page.keyboard.press("Tab")
|
||||
await page.keyboard.press("Enter")
|
||||
await expect(chip).toHaveText("Add project")
|
||||
// The server the app runs beside shows its hostname and "This computer" instead of its address.
|
||||
await expect(options).toHaveText(["hailmaryThis computer", "apollo"])
|
||||
await options.filter({ hasText: "apollo" }).click()
|
||||
|
||||
@@ -66,3 +66,41 @@
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.new-session-location-add {
|
||||
display: flex;
|
||||
height: 24px;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 0 8px 0 6px;
|
||||
border-radius: 4px;
|
||||
color: var(--v2-text-text-muted);
|
||||
font-size: 13px;
|
||||
font-weight: 440;
|
||||
line-height: 16px;
|
||||
white-space: nowrap;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.new-session-location-add:is(:hover, :focus-visible) {
|
||||
background: var(--v2-overlay-simple-overlay-hover);
|
||||
color: var(--v2-text-text-base);
|
||||
}
|
||||
|
||||
.new-session-location-add:focus-visible {
|
||||
outline: 2px solid var(--v2-border-border-focus);
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
/* Narrow screens keep only the icon; the tooltip names it. */
|
||||
@media (max-width: 480px) {
|
||||
.new-session-location-add {
|
||||
width: 24px;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.new-session-location-add > span {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
ProjectAvatar,
|
||||
} from "@opencode/ui/project-avatar"
|
||||
import { TextInput } from "@opencode/ui/text-input"
|
||||
import { Tooltip } from "@opencode/ui/tooltip"
|
||||
import { createTypeahead } from "@opencode/ui/typeahead"
|
||||
import { getFilename } from "@opencode/util/path"
|
||||
import { createEffect, createMemo, createResource, For, type JSX, Match, onCleanup, Show, Switch } from "solid-js"
|
||||
@@ -418,6 +419,21 @@ function NewSessionLocationDialog(props: {
|
||||
aria-activedescendant={typeahead.activeID()}
|
||||
onInput={(event) => setStore("query", event.currentTarget.value)}
|
||||
onKeyDown={handleKeyDown}
|
||||
trailing={
|
||||
<Show when={!props.projectsOnly && !store.drilled && !store.picking}>
|
||||
<Tooltip placement="top" value={language.t("session.new.project.add")}>
|
||||
<button
|
||||
type="button"
|
||||
class="new-session-location-add"
|
||||
aria-label={language.t("session.new.project.add")}
|
||||
onClick={() => choose(addEntry)}
|
||||
>
|
||||
<Icon name="plus" size="small" />
|
||||
<span>{language.t("session.new.project.add")}</span>
|
||||
</button>
|
||||
</Tooltip>
|
||||
</Show>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div class="command-palette-scroll" data-scrollable ref={(el) => (resultsRef = el)}>
|
||||
|
||||
Reference in New Issue
Block a user