Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update notebook window size on panel resize #75

Closed
wants to merge 5 commits into from
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
185 changes: 185 additions & 0 deletions galata/test/jupyterlab/notebooks/20_empty_cells.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "27ad8e86-a071-4008-9473-21336849d03d",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "ecaeb4fd-1324-46bf-a56d-36c14c0c5c27",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "7c661b5f-04d7-4f7f-a403-802bc31e6a9e",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "73b35147-27a8-41e1-b8c2-3b40bb70a7d8",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "5eefb0c1-f1d6-44bf-86e0-44443d4fa2ca",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "951ac539-dea8-421f-8b0e-2363d0e347c8",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "d563933e-80a5-4d87-8b67-9a11e95902cb",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "bc8f61ab-31c1-458d-b0fe-af6e2056be9f",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "bc647bd0-783a-40df-b334-ae07c50c8b94",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "aff20e91-87cd-4337-93b6-71a396c387b0",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "92690a64-7054-46f1-9b56-82fc3c6c174f",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "63b23bf4-11a6-4990-a0ea-15734626b039",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "34476483-41a0-44de-a405-5dfdc64b76e2",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "c1ead4e1-1977-44cc-8e90-6c8da478f892",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "cc28bbde-b459-4260-8567-b133172a1d04",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "9976c3c6-48c7-4565-9f5f-5a4f6050c4a8",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "641f61d8-b4c3-44e3-991d-47bc13171f33",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "ca17251f-e34d-4133-870e-698648005c69",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "25bf4039-280b-45da-b310-b8f0ba1432ab",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "60ee0f13-2387-454e-bab4-52300607a1dc",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.4"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
75 changes: 61 additions & 14 deletions galata/test/jupyterlab/windowed-notebook.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
import { expect, galata, test } from '@jupyterlab/galata';
import { ElementHandle } from '@playwright/test';
import * as path from 'path';

const fileName = 'windowed_notebook.ipynb';
Expand All @@ -27,32 +28,78 @@ test.beforeEach(async ({ page, tmpPath }) => {
);
});

async function getInnerHeight(panel: ElementHandle<Element>) {
return parseInt(
await panel.$eval(
'.jp-WindowedPanel-inner',
node => (node as HTMLElement).style.height
),
10
);
}
async function getWindowHeight(panel: ElementHandle<Element>) {
return parseInt(
await panel.$eval(
'.jp-WindowedPanel-window',
node => (node as HTMLElement).style.minHeight
),
10
);
}

test('should update window height on resize', async ({ page, tmpPath }) => {
// Note: this needs many small cells so that they get added during resize changing height.
const notebookName = '20_empty_cells.ipynb';
await page.contents.uploadFile(
path.resolve(__dirname, `notebooks/${notebookName}`),
`${tmpPath}/${notebookName}`
);
await page.notebook.openByPath(`${tmpPath}/${notebookName}`);

const notebook = await page.notebook.getNotebookInPanel();

// Measure height when the notebook is open but launcher closed
const fullHeight = await getWindowHeight(notebook);

// Add a new launcher below the notebook
await page.evaluate(async () => {
const widget = await window.jupyterapp.commands.execute('launcher:create');
window.jupyterapp.shell.add(widget, 'main', { mode: 'split-bottom' });
});
// Measure height after splitting the dock area
const heightAfterSplit = await getWindowHeight(notebook);

expect(heightAfterSplit).toBeLessThan(fullHeight);

// Resize the dock panel, increasing the notebook height/decreasing the launcher height.
const resizeHandle = page.locator(
'.lm-DockPanel-handle[data-orientation="vertical"]:visible'
);
await resizeHandle.dragTo(page.locator('#jp-main-statusbar'));

// Measure height after resizing
const heightAfterResize = await getWindowHeight(notebook);

expect(heightAfterResize).toBeGreaterThan(heightAfterSplit);
});

test('should not update height when hiding', async ({ page, tmpPath }) => {
await page.notebook.openByPath(`${tmpPath}/${fileName}`);

// Wait to ensure the rendering logic is stable.
await page.waitForTimeout(200);

const h = await page.notebook.getNotebookInPanel();
const initialHeight = parseInt(
(await h?.$$eval(
'.jp-WindowedPanel-inner',
nodes => nodes[0].style.height
)) ?? '0',
10
);
const notebook = await page.notebook.getNotebookInPanel();
const initialHeight = await getInnerHeight(notebook);

expect(initialHeight).toBeGreaterThan(0);

// Add a new launcher covering the notebook.
await page.menu.clickMenuItem('File>New Launcher');

const innerHeight =
(await h?.$$eval(
'.jp-WindowedPanel-inner',
nodes => nodes[0].style.height
)) ?? '-1';
const innerHeight = await getInnerHeight(notebook);

expect(parseInt(innerHeight, 10)).toEqual(initialHeight);
expect(innerHeight).toEqual(initialHeight);
});

test('should hide first inactive code cell when scrolling down', async ({
Expand Down
15 changes: 15 additions & 0 deletions packages/ui-components/src/components/windowedlist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { ArrayExt } from '@lumino/algorithm';
import { PromiseDelegate } from '@lumino/coreutils';
import { IDisposable } from '@lumino/disposable';
import { Message, MessageLoop } from '@lumino/messaging';
import { Throttler } from '@lumino/polling';
import { ISignal, Signal } from '@lumino/signaling';
import { PanelLayout, Widget } from '@lumino/widgets';

Expand Down Expand Up @@ -688,6 +689,7 @@ export class WindowedList<
this._scrollToItem = null;
this._scrollRepaint = null;
this._scrollUpdateWasRequested = false;
this._updater = new Throttler(() => this.update(), 50);
this._resizeObserver = null;

this._viewModel.stateChanged.connect(this.onStateChanged, this);
Expand Down Expand Up @@ -727,6 +729,14 @@ export class WindowedList<
return this._viewModel;
}

/**
* Dispose the windowed list.
*/
dispose(): void {
this._updater.dispose();
super.dispose();
}

/**
* Callback on event.
*
Expand Down Expand Up @@ -880,8 +890,12 @@ export class WindowedList<
* A message handler invoked on an `'resize-request'` message.
*/
protected onResize(msg: Widget.ResizeMessage): void {
const previousHeight = this.viewModel.height;
this.viewModel.height =
msg.height >= 0 ? msg.height : this.node.getBoundingClientRect().height;
if (this.viewModel.height !== previousHeight) {
void this._updater.invoke();
}
super.onResize(msg);
}

Expand Down Expand Up @@ -1114,6 +1128,7 @@ export class WindowedList<
private _scrollRepaint: number | null;
private _scrollToItem: [number, WindowedList.ScrollToAlign] | null;
private _scrollUpdateWasRequested: boolean;
private _updater: Throttler;
}

/**
Expand Down
Loading