Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion packages/app/e2e/regression/remote-session-settings.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,41 @@ test("auto-accept responds for an unfocused server session", async ({ page }) =>
])
})

test("auto-accept toggle stays enabled on a new-session draft", async ({ page }) => {
const permissionRequests: string[] = []
await mockServers(page, permissionRequests)
await configureServers(page, [{ type: "draft", server: serverB, draftID: "draft-1", directory: directoryB }])

await page.goto("/new-session?draftId=draft-1")
// Wait for server-backed controls: the page command registrations
// (including settings.open) mount with this tree, so the keypress below
// must not race them.
await expect(page.getByRole("button", { name: "Server B Model" })).toBeVisible()
await page.keyboard.press("Control+,")

const dialog = page.locator(".settings-v2-dialog")
const autoAccept = dialog.locator('[data-action="settings-auto-accept-permissions"]')
await expect(autoAccept).toBeVisible()
await expect(autoAccept.getByRole("switch")).toBeEnabled()
await autoAccept.locator('[data-slot="switch-control"]').click()
await expect(autoAccept.getByRole("switch")).toBeChecked()
})

test("auto-accept toggle stays disabled on home with no project selected", async ({ page }) => {
const permissionRequests: string[] = []
await mockServers(page, permissionRequests)
await configureServers(page)

await page.goto("/")
await page.keyboard.press("Control+,")

const dialog = page.locator(".settings-v2-dialog")
const autoAccept = dialog.locator('[data-action="settings-auto-accept-permissions"]')
await expect(autoAccept).toBeVisible()
// No directory context on bare home: nothing to scope the flag to.
await expect(autoAccept.getByRole("switch")).toBeDisabled()
})

type PermissionResponse = {
origin: string
directory?: string
Expand All @@ -150,7 +185,10 @@ type PermissionResponse = {
body: unknown
}

async function configureServers(page: Page, tabs: { type: "session"; server: string; sessionId: string }[] = []) {
async function configureServers(
page: Page,
tabs: ({ type: "session"; server: string; sessionId: string } | { type: "draft"; server: string; draftID: string; directory: string })[] = [],
) {
await page.addInitScript(
({ serverB, tabs }) => {
localStorage.setItem("settings.v3", JSON.stringify({ general: { newLayoutDesigns: true } }))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ export const DialogSettings: Component<{
return draft?.type === "draft" ? draft.directory : undefined
}
if (route.type === "session") return serverSync().session.get(route.sessionId)?.directory
// AUTO_ACCEPT_DIRECTORY_FALLBACK_002: on home, scope to the selected
// project when the user picked one; bare home has nothing to scope to.
if (route.type === "home") return layout.home.selection().directory
return undefined
})

Expand Down Expand Up @@ -94,7 +97,7 @@ export const DialogSettings: Component<{
</div>
</TabsV2.List>
<TabsV2.Content value="general" class="settings-v2-panel">
<SettingsGeneralV2 sessionID={props.sessionID} />
<SettingsGeneralV2 sessionID={props.sessionID} directory={directory()} />
</TabsV2.Content>
<TabsV2.Content value="shortcuts" class="settings-v2-panel">
<SettingsKeybinds v2 />
Expand Down
29 changes: 22 additions & 7 deletions packages/app/src/components/settings-v2/general-controllers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,42 @@ import { createSoundPreviewController, type ShellOption } from "./general-contro
export { createShellOptions, createSoundPreviewController } from "./general-controller-behavior"
export type { ShellOption, ShellSelectOption } from "./general-controller-behavior"

export function createPermissionScopeController(sessionID: Accessor<string | undefined>) {
export function createPermissionScopeController(
sessionID: Accessor<string | undefined>,
fallbackDirectory?: Accessor<string | undefined>,
) {
const permission = usePermission()
const serverSync = useServerSync()
// AUTO_ACCEPT_DIRECTORY_FALLBACK_002: resolve the scope directory from the
// session lineage when a session exists, otherwise fall back to the active
// route directory (new-session/draft views) so the toggle stays usable.
const directory = createMemo(() => {
const id = sessionID()
if (!id) return undefined
return serverSync().session.lineage.peek(id)?.session.directory
if (id) {
const dir = serverSync().session.lineage.peek(id)?.session.directory
if (dir) return dir
}
return fallbackDirectory?.()
})

return {
accepting: createMemo(() => {
const id = sessionID()
const dir = directory()
if (!id || !dir) return false
if (!dir) return false
const id = sessionID()
if (!id) return permission.isAutoAcceptingDirectory(dir)
return permission.isAutoAccepting(id, dir)
}),
enabled: createMemo(() => !!directory()),
set: (checked: boolean) => {
const id = sessionID()
const dir = directory()
if (!id || !dir) return
if (!dir) return
const id = sessionID()
if (!id) {
if (permission.isAutoAcceptingDirectory(dir) === checked) return
permission.toggleAutoAcceptDirectory(dir)
return
}
if (checked) return permission.enableAutoAccept(id, dir)
permission.disableAutoAccept(id, dir)
},
Expand Down
3 changes: 2 additions & 1 deletion packages/app/src/components/settings-v2/general.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -273,14 +273,15 @@ const LanguageSetting = () => {

export const SettingsGeneralV2: Component<{
sessionID?: string
directory?: string
}> = (props) => {
const language = useLanguage()
const platform = usePlatform()
const dialog = useDialog()
const settings = useSettings()
const mobile = createMediaQuery("(max-width: 767px)")
const updater = useUpdaterAction()
const permissionScope = createPermissionScopeController(() => props.sessionID)
const permissionScope = createPermissionScopeController(() => props.sessionID, () => props.directory)
const shell = createShellSettingsController()
const appearance = createAppearanceSettingsController()
const sounds = createSoundSettingsController()
Expand Down
Loading