Skip to content

Commit

Permalink
Make Cells Display Lazily When Diffing Unchanged Cells
Browse files Browse the repository at this point in the history
Motivation:
  During diffing Unchanged cells are displayed, which is not necessary.
  This is a performance issue when there are many unchanged cells.

Related Issues:
  - #635

Open Questions:
  - I am struggling with getting the svg images to build properly.
  - How can this be tested in JupyterLab?

Changes:
  - Alter Notebooks Widget to only display changed cells by using new linked
    list of cells.
  - Add new linked list of cells and lazy version of linked list of cells.
  • Loading branch information
gwincr11 committed Oct 24, 2022
1 parent 4bc7ae2 commit f56db7c
Show file tree
Hide file tree
Showing 10 changed files with 610 additions and 181 deletions.
74 changes: 46 additions & 28 deletions nbdime/webapp/templates/diff.html
Original file line number Diff line number Diff line change
@@ -1,31 +1,49 @@
{% extends "nbdimepage.html" %}
{% extends "nbdimepage.html" %} {% block nbdimeheader %}

{% block nbdimeheader %}
<div id="nbdime-header" class="nbdime-Diff">
<h3>Notebook Diff</h3>
Enter notebook filenames or URLs in the form below to get started.

<div id="nbdime-header" class="nbdime-Diff">
<h3>Notebook Diff</h3>
Enter notebook filenames or URLs in the form below to get started.
<form id="nbdime-diff-form" class="nbdime-forms">
<fieldset>
<legend>Please input filenames/URLs of notebooks to diff:</legend>
<label>Base:</label>
<input
id="diff-base"
type="text"
name="base"
value="{{ config_data['base']|e }}"
/>
<label>Remote:</label>
<input
id="diff-remote"
type="text"
name="remote"
value="{{ config_data['remote']|e }}"
/>
<input
id="nbdime-run-diff"
type="submit"
name="diff"
value="Diff files"
/>
</fieldset>
</form>
<!-- nbdime-forms -->
<div id="nbdime-header-buttonrow">
<button id="nbdime-trust" style="display: none">Trust outputs</button>
<button id="nbdime-close" type="checkbox" style="display: none">
Close tool
</button>
<button id="nbdime-export" type="checkbox" style="display: none">
Export diff
</button>
</div>
<div id="nbdime-header-banner">
<span id="nbdime-header-base">Base</span>
<span id="nbdime-header-remote">Remote</span>
</div>
</div>
<!-- ndime-header -->

<form id="nbdime-diff-form" class="nbdime-forms">
<fieldset>
<legend>Please input filenames/URLs of notebooks to diff:</legend>
<label>Base:</label>
<input id="diff-base" type="text" name="base" value="{{ config_data['base']|e }}" />
<label>Remote:</label>
<input id="diff-remote" type="text" name="remote" value="{{ config_data['remote']|e }}" />
<input id="nbdime-run-diff" type="submit" name="diff" value="Diff files" />
</fieldset>
</form> <!-- nbdime-forms -->
<div id="nbdime-header-buttonrow">
<input id="nbdime-hide-unchanged" type="checkbox"><label for="cbox1">Hide unchanged cells</label></input>
<button id="nbdime-trust" style="display: none">Trust outputs</button>
<button id="nbdime-close" type="checkbox" style="display: none">Close tool</button>
<button id="nbdime-export" type="checkbox" style="display: none">Export diff</button>
</div>
<div id=nbdime-header-banner>
<span id="nbdime-header-base">Base</span>
<span id="nbdime-header-remote">Remote</span>
</div>
</div> <!-- ndime-header -->

{% endblock %}
{% endblock %}
1 change: 1 addition & 0 deletions packages/nbdime/src/diff/widget/fold-down.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/nbdime/src/diff/widget/fold-up.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/nbdime/src/diff/widget/fold.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
202 changes: 202 additions & 0 deletions packages/nbdime/src/diff/widget/linked-cells.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
import { Panel, Widget } from "@lumino/widgets";
import type { CellDiffWidget } from "./";

import foldDown from "./fold-down.svg";
import foldUp from "./fold-up.svg";
import fold from "./fold.svg";

class LinkedListCell extends Panel {
_next: LinkedListCell | LazyDisplayLinkedListCell | null;
_prev: LinkedListCell | LazyDisplayLinkedListCell | null;
renderFunc: () => CellDiffWidget;
_displayed: boolean;
lazy: boolean;

constructor(renderFunc: () => CellDiffWidget) {
super();
this._next = null;
this._prev = null;
this.renderFunc = renderFunc;
this._displayed = true;
this.renderCell();
this.addClass("linked-cell");
this.lazy = false;
}

protected renderCell() {
this.addWidget(this.renderFunc());
this._displayed = true;
}

get next(): LinkedListCell | LazyDisplayLinkedListCell | null {
return this._next;
}

set next(nextCell: LinkedListCell | LazyDisplayLinkedListCell | null) {
this._next = nextCell;
if (nextCell === null) {
return;
}

if (nextCell.lazy) {
console.log("call expandDown");
nextCell.expandDown();
}
}

get prev(): LinkedListCell | LazyDisplayLinkedListCell | null {
return this._prev;
}

set prev(prevCell: LinkedListCell | LazyDisplayLinkedListCell | null) {
this._prev = prevCell;
if (prevCell === null) {
return;
}
prevCell.next = this;
if (prevCell.lazy) {
prevCell.expandUp();
}
}

get displayed(): boolean {
return this._displayed;
}

expandUp(): void {
return;
}

expandDown(): void {
return;
}
}

class LazyDisplayLinkedListCell extends LinkedListCell {
expandButton: HTMLDivElement;
expandButtonDisplayed: boolean;

// Path: packages/nbdime/src/diff/widget/wrapper_cells.ts
constructor(renderFunc: () => CellDiffWidget) {
super(renderFunc);
this.expandButton = document.createElement("div");
this.expandButton.className = "jp-expand-output-wrapper";
this.expandButtonDisplayed = false;
this.addClass("lazy-linked-cell");
this.lazy = true;
}

set prev(prevCell: LinkedListCell | LazyDisplayLinkedListCell) {
this._prev = prevCell;
prevCell.next = this;
}

set next(nextCell: LinkedListCell | LazyDisplayLinkedListCell) {
this._next = nextCell;
}

protected renderCell() {
this._displayed = false;
}

expandUp(): void {
if (this._displayed) {
return;
}
if (this.expandButtonDisplayed) {
this._setupFoldButton();
} else {
this._setupExpandUpButton();
}
}

expandDown(): void {
if (this._displayed) {
return;
}
if (this.expandButtonDisplayed) {
this._setupFoldButton();
} else {
this._setupExpandDownButton();
}
}

_setupFoldButton() {
this.expandButton.innerHTML = "";
const button = this.createButton("Fold");
button.onclick = (e) => {
e.preventDefault();
this.showLazyCellUp();
};
this.expandButton.appendChild(button);
const widget = new Widget({ node: this.expandButton });
this.addWidget(widget);
}

_setupExpandUpButton() {
const button = this.createButton("Up");
button.onclick = (e) => {
e.preventDefault();
this.showLazyCellUp();
};
this.expandButton.appendChild(button);
const widget = new Widget({ node: this.expandButton });
this.addWidget(widget);
}

_setupExpandDownButton() {
const button = this.createButton("Down");
button.onclick = (e) => {
e.preventDefault();
this.showLazyCellDown();
};
this.expandButton.appendChild(button);
const widget = new Widget({ node: this.expandButton });
this.addWidget(widget);
}

createButton(direction: "Up" | "Down" | "Fold"): HTMLAnchorElement {
this.expandButton.innerHTML = "";
const button = document.createElement("a");
button.title = `Expand ${direction}`;
button.setAttribute("aria-label", `Expand ${direction}`);
button.innerHTML = this.buttonSvg(direction);
if (direction === "Up") {
button.innerHTML = foldUp;
} else if (direction === "Down") {
button.innerHTML = foldDown;
} else {
button.innerHTML = fold;
}
this.expandButtonDisplayed = true;
return button;
}

buttonSvg(direction: "Up" | "Down" | "Fold"): string {
if (direction === "Up") {
return foldUp;
} else if (direction === "Down") {
return foldDown;
} else {
return fold;
}
}

showLazyCellUp() {
this.showLazyCell();
this._prev?.expandUp();
}

showLazyCellDown() {
this.showLazyCell();
this._next?.expandDown();
}

showLazyCell() {
this.addWidget(this.renderFunc());
this._displayed = true;
this.expandButton.remove();
}
}

export { LinkedListCell, LazyDisplayLinkedListCell };

0 comments on commit f56db7c

Please sign in to comment.