diff --git a/news/2 Fixes/7638.md b/news/2 Fixes/7638.md new file mode 100644 index 000000000000..dea499b65438 --- /dev/null +++ b/news/2 Fixes/7638.md @@ -0,0 +1 @@ +Fix a hang in the Interactive window when connecting guest to host after the host has already started the interactive window. \ No newline at end of file diff --git a/src/client/datascience/jupyter/jupyterServer.ts b/src/client/datascience/jupyter/jupyterServer.ts index afef002f8bec..6830b2497e37 100644 --- a/src/client/datascience/jupyter/jupyterServer.ts +++ b/src/client/datascience/jupyter/jupyterServer.ts @@ -169,6 +169,10 @@ export class JupyterServerBase implements INotebookServer { return this.notebooks.get(resource.toString()); } + protected getNotebooks(): INotebook[] { + return [...this.notebooks.values()]; + } + protected setNotebook(resource: Uri, notebook: INotebook) { const oldDispose = notebook.dispose; notebook.dispose = () => { diff --git a/src/client/datascience/jupyter/liveshare/guestJupyterServer.ts b/src/client/datascience/jupyter/liveshare/guestJupyterServer.ts index 4acea881452c..64924bce0a3b 100644 --- a/src/client/datascience/jupyter/liveshare/guestJupyterServer.ts +++ b/src/client/datascience/jupyter/liveshare/guestJupyterServer.ts @@ -72,6 +72,17 @@ export class GuestJupyterServer return result; } + public async onSessionChange(api: vsls.LiveShare | null): Promise { + await super.onSessionChange(api); + + this.notebooks.forEach(async notebook => { + const guestNotebook = notebook as GuestJupyterNotebook; + if (guestNotebook) { + await guestNotebook.onSessionChange(api); + } + }); + } + public async getNotebook(resource: Uri): Promise { return this.notebooks.get(resource.toString()); } diff --git a/src/client/datascience/jupyter/liveshare/hostJupyterServer.ts b/src/client/datascience/jupyter/liveshare/hostJupyterServer.ts index 64ea465df7a1..4f099e945a19 100644 --- a/src/client/datascience/jupyter/liveshare/hostJupyterServer.ts +++ b/src/client/datascience/jupyter/liveshare/hostJupyterServer.ts @@ -95,6 +95,17 @@ export class HostJupyterServer } } + public async onSessionChange(api: vsls.LiveShare | null): Promise { + await super.onSessionChange(api); + + this.getNotebooks().forEach(async notebook => { + const hostNotebook = notebook as HostJupyterNotebook; + if (hostNotebook) { + await hostNotebook.onSessionChange(api); + } + }); + } + public async onDetach(api: vsls.LiveShare | null): Promise { await super.onDetach(api); diff --git a/src/test/datascience/liveshare.functional.test.tsx b/src/test/datascience/liveshare.functional.test.tsx index 27ea390bac19..1ff19cafed39 100644 --- a/src/test/datascience/liveshare.functional.test.tsx +++ b/src/test/datascience/liveshare.functional.test.tsx @@ -202,6 +202,23 @@ suite('DataScience LiveShare tests', () => { verifyHtmlOnCell(guestContainer.wrapper!, 'InteractiveCell', '1', CellPosition.Last); }); + test('Host starts LiveShare after starting Jupyter', async() => { + addMockData(hostContainer!, 'a=1\na', 1); + addMockData(hostContainer!, 'b=2\nb', 2); + await getOrCreateInteractiveWindow(vsls.Role.Host); + let wrapper = await addCodeToRole(vsls.Role.Host, 'a=1\na'); + verifyHtmlOnCell(wrapper, 'InteractiveCell', '1', CellPosition.Last); + + await startSession(vsls.Role.Host); + await getOrCreateInteractiveWindow(vsls.Role.Guest); + await startSession(vsls.Role.Guest); + + wrapper = await addCodeToRole(vsls.Role.Host, 'b=2\nb'); + + assert.ok(guestContainer.wrapper, 'Guest wrapper not created'); + verifyHtmlOnCell(guestContainer.wrapper!, 'InteractiveCell', '2', CellPosition.Last); + }); + test('Host Shutdown and Run', async () => { // Should only need mock data in host addMockData(hostContainer!, 'a=1\na', 1);