Compare commits

...
2 changed files with 56 additions and 5 deletions
@@ -26,10 +26,13 @@ test("session settings use the remote server context", async ({ page }) => {
await page.goto(`/server/${base64Encode(serverB)}/session/${sessionB.id}`)
const sessionHeading = page.getByRole("heading", { name: sessionB.title, exact: true, includeHidden: true })
await expect(sessionHeading).toBeVisible()
const activeTabs = page.locator('[data-titlebar-tab-slot][data-active="true"]')
await expect(activeTabs).toHaveCount(1)
await page.keyboard.press("Control+,")
const settings = page.getByTestId("settings-screen")
await expect(settings).toBeVisible()
await expect(activeTabs).toHaveCount(0)
await expect(page.getByRole("dialog")).toHaveCount(0)
await expect(settings.getByRole("tablist")).toHaveCSS("width", "328px")
await expect(sessionHeading).toBeAttached()
@@ -67,6 +70,49 @@ test("session settings use the remote server context", async ({ page }) => {
await settings.getByRole("button", { name: "Back to app" }).click()
await expect(settings).toBeHidden()
await expect(sessionHeading).toBeVisible()
await expect(activeTabs).toHaveCount(1)
await page.keyboard.press("Control+,")
await expect(settings).toBeVisible()
await page.locator(`[data-titlebar-tab-slot]:has(a[href$="/session/${sessionB.id}"])`).click()
await expect(settings).toBeHidden()
await expect(sessionHeading).toBeVisible()
await expect(activeTabs).toHaveCount(1)
})
test("new session works while draft settings are open", async ({ page }) => {
await installSseTransport(page, { server: serverA })
await installSseTransport(page, { server: serverB })
await mockServers(page, [])
await configureServers(page)
await page.goto(`/server/${base64Encode(serverB)}/session/${sessionB.id}`)
await expect(page.getByRole("heading", { name: sessionB.title, exact: true })).toBeVisible()
const newSession = page.locator('[data-slot="titlebar-v2"]').getByRole("button", { name: "New session", exact: true })
await newSession.click()
await expect(page).toHaveURL((url) => url.pathname === "/new-session" && !!url.searchParams.get("draftId"))
const draftURL = page.url()
const editor = page.locator('[data-component="composer-editor"][contenteditable="true"]')
await expect(editor).toBeEditable()
await editor.fill("Keep the original draft")
const tabs = page.locator("[data-titlebar-tab-slot]")
const activeTabs = page.locator('[data-titlebar-tab-slot][data-active="true"]')
await expect(tabs).toHaveCount(2)
await expect(activeTabs).toHaveCount(1)
await page.keyboard.press("Control+,")
const settings = page.getByTestId("settings-screen")
await expect(settings).toBeVisible()
await expect(activeTabs).toHaveCount(0)
await newSession.click()
await expect(page).toHaveURL(
(url) => url.pathname === "/new-session" && !!url.searchParams.get("draftId") && url.href !== draftURL,
)
await expect(settings).toBeHidden()
await expect(tabs).toHaveCount(3)
await expect(activeTabs).toHaveCount(1)
await expect(activeTabs.locator("a")).toHaveAttribute("href", `/new-session${new URL(page.url()).search}`)
await expect(editor).toBeEditable()
await expect(editor).toBeEmpty()
})
test("auto-accept responds for an unfocused server session", async ({ page }) => {
@@ -385,9 +431,10 @@ async function mockServers(
return json(route, { data: [], cursor: {} })
if (sessions.some((session) => url.pathname === `/api/session/${session.id}/inbox`))
return json(route, { data: [] })
if (url.pathname === "/api/location") return json(route, { directory })
if (url.pathname === "/api/location")
return json(route, { directory, project: { id: remote ? sessionB.projectID : "project-server-a" } })
if (url.pathname === "/api/vcs")
return json(route, { location: { directory }, data: { branch: "main", defaultBranch: "main" } })
return json(route, { location: { directory }, data: { branch: { current: "main", default: "main" } } })
if (url.pathname === "/api/pty/shells") return json(route, { location: { directory }, data: [] })
return json(route, {})
})
+7 -3
View File
@@ -12,6 +12,7 @@ import { usePlatform } from "@/runtime/platform/platform"
import { useCommand } from "@/shell/commands/command"
import { useLanguage } from "@/runtime/i18n/language"
import { useSettings } from "@/settings/model"
import { useSettingsSurface } from "@/settings/surface"
import { WindowsAppMenu } from "./windows-menu"
import { applyPath, backPath, forwardPath } from "./history"
import { TitlebarTabStrip } from "@/shell/titlebar/tab-strip"
@@ -46,6 +47,7 @@ export function Titlebar(props: {
const command = useCommand()
const language = useLanguage()
const settings = useSettings()
const surface = useSettingsSurface()
const navigate = useNavigate()
const location = useLocation()
const mobile = createMediaQuery("(max-width: 767px)")
@@ -199,11 +201,11 @@ export function Titlebar(props: {
}
}
const currentTab = () => matchRoute(layout.route())
const currentTab = () => (surface.store.open ? undefined : matchRoute(layout.route()))
createEffect(() => {
const route = layout.route()
if (!tabs.ready()) return
if (!tabs.ready() || surface.store.open) return
const tab = currentTab()
if (tab) {
const current = session()
@@ -254,7 +256,7 @@ export function Titlebar(props: {
return
}
case "draft": {
const activeTab = currentTab()
const activeTab = matchRoute(route)
if (activeTab?.type !== "draft") return
const model = tabs.stateValue<ComposerState>(activeTab, "prompt")?.model.current()
@@ -372,6 +374,7 @@ export function Titlebar(props: {
forceTruncate={tabsAreOverflowing()}
onOverflowChange={setTabsAreOverflowing}
onNavigate={(tab, el) => {
surface.close()
tabs.select(tab)
el?.scrollIntoView({ behavior: "instant" })
}}
@@ -414,6 +417,7 @@ export function Titlebar(props: {
forceTruncate={false}
onOverflowChange={setTabsAreOverflowing}
onNavigate={(tab, el) => {
surface.close()
tabs.select(tab)
el?.scrollIntoView({ behavior: "instant", block: "nearest" })
}}