Skip to content
Merged
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
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,4 @@ Never:
- Commit secrets or credentials.
- Edit generated output folders unless explicitly requested.
- Modify node_modules or lockfiles unless explicitly requested.
- Reintroduce cross-workspace overwrite/delete behavior with any changes.
85 changes: 85 additions & 0 deletions playwright/github-pr-drawer/open-pr-create.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1116,6 +1116,91 @@ test('Local New workspace always creates a new stored workspace snapshot', async
await expect.poll(async () => countLocalRecords()).toBe(initialLocalRecordCount + 1)
})

test('Local New workspace shows forked head immediately when source workspace has prTitle', async ({
page,
}) => {
const seededWorkspaceId = 'local_seed_title_carryover_guard'
const seededWorkspaceTitle = 'Seed local context title'

await waitForAppReady(page, `${appEntryPath}`)

await seedLocalWorkspaceContexts(page, [
{
id: seededWorkspaceId,
repo: '',
base: 'main',
head: 'feat/component-seeded-title-guard',
prTitle: seededWorkspaceTitle,
prNumber: null,
prContextState: 'inactive',
},
])

await page.reload()
await waitForAppReady(page, `${appEntryPath}`)
await connectByotWithSingleRepo(page)
await selectWorkspacesRepositoryFilter(page, '__local__')

await page.getByRole('button', { name: 'New workspace', exact: true }).click()
await expect(page.getByRole('complementary', { name: 'Workspaces' })).toBeHidden()

let createdWorkspaceId = ''
await expect
.poll(async () => {
const records = await getAllWorkspaceRecords(page)
const createdRecord = records.find(record => {
const id = String(record?.id ?? '').trim()
const repo = String(record?.repo ?? '').trim()
const prTitle = String(record?.prTitle ?? '').trim()
return id !== seededWorkspaceId && !repo && !prTitle
})

createdWorkspaceId = String(createdRecord?.id ?? '').trim()
return createdWorkspaceId
})
.not.toBe('')

const createdRecords = await getAllWorkspaceRecords(page)
const createdRecord = createdRecords.find(record => {
const id = String(record?.id ?? '').trim()
return id === createdWorkspaceId
})

const createdHead = String(createdRecord?.head ?? '').trim()
expect(createdHead).toBeTruthy()

await page.getByRole('button', { name: 'Workspaces' }).click()
await selectWorkspacesRepositoryFilter(page, '__local__')

const storedWorkspaceSelect = page.getByRole('combobox', {
name: 'Stored workspace',
})
const selectedWorkspaceId = String(
await storedWorkspaceSelect.evaluate(element => (element as HTMLSelectElement).value),
).trim()
expect(selectedWorkspaceId).not.toBe(seededWorkspaceId)

const selectedLabelText = await storedWorkspaceSelect.evaluate(element => {
const select = element as HTMLSelectElement
return select.selectedOptions.item(0)?.textContent ?? ''
})
const selectedLabel = String(selectedLabelText ?? '').trim()

const selectedRecord = createdRecords.find(record => {
const id = String(record?.id ?? '').trim()
return id === selectedWorkspaceId
})
const selectedHead = String(selectedRecord?.head ?? '').trim()
const selectedPrTitle = String(selectedRecord?.prTitle ?? '').trim()

expect(selectedPrTitle).toBe('')
expect(selectedHead).toBeTruthy()
expect(selectedLabel).toBe(selectedHead)
expect(selectedLabel).not.toBe(seededWorkspaceTitle)
await expect(page.locator('#workspace-context-status')).toContainText(selectedHead)
await expect(page.locator('#workspace-context-status')).toContainText('local')
})

test('Non-Local New workspace forks a new repository-scoped workspace when entries exist', async ({
page,
}) => {
Expand Down
4 changes: 4 additions & 0 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -950,6 +950,10 @@ const { syncActiveWorkspaceRepositoryScope, forkWorkspaceFromCurrentState } =
githubPrTitle.value = value
}
},
setActiveWorkspacePersistedMetadata: ({ prTitle, head } = {}) => {
activeWorkspacePersistedPrTitle = toNonEmptyWorkspaceText(prTitle)
activeWorkspacePersistedHeadBranch = toNonEmptyWorkspaceText(head)
},
})

editedIndicatorVisibilityController.setRefreshHandlers({
Expand Down
9 changes: 9 additions & 0 deletions src/modules/app-core/workspace-scope-fork-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const createWorkspaceScopeForkActions = ({
setWorkspaceScopeMarker,
setHeadBranchValue,
setPrTitleValue,
setActiveWorkspacePersistedMetadata,
}) => {
const syncActiveWorkspaceRepositoryScope = async (
repositoryFullName,
Expand Down Expand Up @@ -172,6 +173,14 @@ export const createWorkspaceScopeForkActions = ({
typeof saved?.createdAt === 'number' && Number.isFinite(saved.createdAt)
? saved.createdAt
: now

if (typeof setActiveWorkspacePersistedMetadata === 'function') {
setActiveWorkspacePersistedMetadata({
prTitle: '',
head: forkedHeadBranch,
})
}

setActiveWorkspaceRecordId(savedId)
setActiveWorkspaceCreatedAt(savedCreatedAt)

Expand Down
Loading