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
31 changes: 31 additions & 0 deletions packages/web-shell/client/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1848,6 +1848,37 @@ describe('App session callbacks', () => {
);
});

it('creates first sessions in the initial unlocked workspace', async () => {
mockConnection.sessionId = undefined;
mockWorkspace.capabilities = {
workspaces: [
{ id: 'primary', cwd: '/workspace', primary: true, trusted: true },
{
id: 'secondary',
cwd: '/work/secondary',
primary: false,
trusted: true,
},
],
} as typeof mockWorkspace.capabilities;
renderApp({ initialSelectedWorkspaceCwd: '/work/secondary' });
await flush();

expect(testState.latestChatEditorProps?.selectedWorkspaceCwd).toBe(
'/work/secondary',
);

await act(async () => {
testState.latestChatEditorProps?.onSubmit('secondary prompt');
await vi.waitFor(() => {
expect(mockSessionActions.createSession).toHaveBeenCalled();
});
});
expect(mockSessionActions.createSession).toHaveBeenCalledWith(
expect.objectContaining({ workspaceCwd: '/work/secondary' }),
);
});

describe('worktree welcome toggle', () => {
beforeEach(() => {
mockConnection.sessionId = undefined;
Expand Down
4 changes: 3 additions & 1 deletion packages/web-shell/client/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,7 @@ export interface WebShellProps {
}

interface AppProps extends WebShellProps {
initialSelectedWorkspaceCwd?: string;
lockedWorkspaceCwd?: string;
lockedWorkspaceCapability?: DaemonWorkspaceCapability;
restartSseOnPrompt?: boolean;
Expand Down Expand Up @@ -1112,6 +1113,7 @@ export function App({
onSubmitBefore,
restartSseOnPrompt,
historyPageSize,
initialSelectedWorkspaceCwd,
lockedWorkspaceCwd,
lockedWorkspaceCapability,
}: AppProps = {}) {
Expand Down Expand Up @@ -1392,7 +1394,7 @@ export function App({
// so the ensureSessionForPrompt callback must read the latest value.
const [selectedWorkspaceCwd, setSelectedWorkspaceCwd] = useState<
string | undefined
>(undefined);
>(initialSelectedWorkspaceCwd);
const selectedWorkspaceCwdRef = useRef(selectedWorkspaceCwd);
selectedWorkspaceCwdRef.current = selectedWorkspaceCwd;
const [selectedWorkspaceGitStatus, setSelectedWorkspaceGitStatus] = useState<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,9 @@ export function WorkspaceSessionProvider({
{...webShellProps}
historyPageSize={historyPageSize}
restartSseOnPrompt={restartSseOnPrompt}
initialSelectedWorkspaceCwd={
!lockWorkspaceCwd && targetWorkspace ? targetWorkspace.cwd : undefined
}
lockedWorkspaceCwd={lockWorkspaceCwd ? targetWorkspace?.cwd : undefined}
lockedWorkspaceCapability={
lockWorkspaceCwd ? targetWorkspace : undefined
Expand Down
19 changes: 19 additions & 0 deletions packages/web-shell/client/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,25 @@ describe('WebShellWithProviders top-level boundary', () => {
expect(appProps[0]?.lockedWorkspaceCwd).toBeUndefined();
});

it('initializes an unlocked workspace selector from workspace id', () => {
workspaceCapabilities = {
workspaces: [
{ id: 'primary', cwd: '/workspace', primary: true },
{ id: 'secondary', cwd: '/work/secondary', primary: false },
],
};

render(<WebShellWithProviders workspaceId="secondary" />);

expect(sessionProviderProps[0]).toMatchObject({
workspaceCwd: '/work/secondary',
});
expect(appProps[0]).toMatchObject({
initialSelectedWorkspaceCwd: '/work/secondary',
});
expect(appProps[0]?.lockedWorkspaceCwd).toBeUndefined();
});

it('does not register an unknown unlocked workspace path', () => {
const container = render(
<WebShellWithProviders workspaceCwd="/work/missing" />,
Expand Down
Loading