From caba62f7ad3f7d16ba17bcc7b3316b9b549d45aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Collonval?= Date: Mon, 5 Apr 2021 19:19:02 +0200 Subject: [PATCH] Refactor diff using new @jupyterlab/git version (#39) * Use jlab/git endpoint for nb diff * Refactor diff logic with new jlab-git version * Clean style * Homogeneous diff tab title with jlab-git --- jupyterlab_pullrequests/handlers.py | 28 --- jupyterlab_pullrequests/managers/manager.py | 27 --- .../sample_responses/github/ipynb_base.json | 61 ------ .../sample_responses/github/ipynb_nbdiff.json | 110 ----------- .../sample_responses/github/ipynb_remote.json | 65 ------ .../tests/test_handlers_integration.py | 36 ---- jupyterlab_pullrequests/tests/test_manager.py | 18 -- package.json | 2 +- setup.cfg | 2 +- src/components/diff/NotebookDiff.ts | 187 ++++-------------- src/components/diff/plaintext.ts | 146 ++++++-------- src/components/tab/FileDiffWidget.ts | 8 +- src/index.ts | 11 +- style/index.css | 29 +-- yarn.lock | 29 +-- 15 files changed, 132 insertions(+), 627 deletions(-) delete mode 100644 jupyterlab_pullrequests/tests/sample_responses/github/ipynb_base.json delete mode 100644 jupyterlab_pullrequests/tests/sample_responses/github/ipynb_nbdiff.json delete mode 100644 jupyterlab_pullrequests/tests/sample_responses/github/ipynb_remote.json diff --git a/jupyterlab_pullrequests/handlers.py b/jupyterlab_pullrequests/handlers.py index f838737..fb0da05 100644 --- a/jupyterlab_pullrequests/handlers.py +++ b/jupyterlab_pullrequests/handlers.py @@ -152,33 +152,6 @@ async def post(self): self.finish(json.dumps(result)) -class PullRequestsFileNBDiffHandler(PullRequestsAPIHandler): - """ - Returns nbdime diff of given notebook base content and remote content - """ - - @tornado.web.authenticated - async def post(self): - data = get_body_value(self) - try: - prev_content = data["previousContent"] - curr_content = data["currentContent"] - except KeyError as e: - self._jp_log.error(f"Missing key in POST request.", exc_info=e) - raise tornado.web.HTTPError( - status_code=HTTPStatus.BAD_REQUEST, reason=f"Missing POST key: {e}" - ) - try: - content = await self._manager.get_file_nbdiff(prev_content, curr_content) - except Exception as e: - self._jp_log.error(f"Error computing notebook diff.", exc_info=e) - raise tornado.web.HTTPError( - status_code=HTTPStatus.INTERNAL_SERVER_ERROR, - reason=f"Error diffing content: {e}.", - ) from e - self.finish(json.dumps(content)) - - # ----------------------------------------------------------------------------- # Handler utilities # ----------------------------------------------------------------------------- @@ -222,7 +195,6 @@ def get_body_value(handler): ("prs/files", ListPullRequestsFilesHandler), ("files/content", PullRequestsFileContentHandler), ("files/comments", PullRequestsFileCommentsHandler), - ("files/nbdiff", PullRequestsFileNBDiffHandler), ] diff --git a/jupyterlab_pullrequests/managers/manager.py b/jupyterlab_pullrequests/managers/manager.py index 16aff96..24e8894 100644 --- a/jupyterlab_pullrequests/managers/manager.py +++ b/jupyterlab_pullrequests/managers/manager.py @@ -6,7 +6,6 @@ import nbformat import tornado -from nbdime import diff_notebooks from notebook.utils import url_path_join from .._version import __version__ @@ -62,32 +61,6 @@ async def get_file_diff(self, pr_id: str, filename: str) -> dict: """ raise NotImplementedError() - async def get_file_nbdiff( - self, prev_content: str, curr_content: str - ) -> Dict[str, str]: - """Compute the diff between two notebooks. - - Args: - prev_content: Notebook previous content - curr_content: Notebook current content - Returns: - {"base": Dict, "diff": Dict} - """ - - def read_notebook(content): - if not content: - return nbformat.v4.new_notebook() - return nbformat.reads(content, as_version=4) - - current_loop = tornado.ioloop.IOLoop.current() - prev_nb = await current_loop.run_in_executor(None, read_notebook, prev_content) - curr_nb = await current_loop.run_in_executor(None, read_notebook, curr_content) - thediff = await current_loop.run_in_executor( - None, diff_notebooks, prev_nb, curr_nb - ) - - return {"base": prev_nb, "diff": thediff} - @abc.abstractmethod async def get_threads( self, pr_id: str, filename: Optional[str] = None diff --git a/jupyterlab_pullrequests/tests/sample_responses/github/ipynb_base.json b/jupyterlab_pullrequests/tests/sample_responses/github/ipynb_base.json deleted file mode 100644 index f761235..0000000 --- a/jupyterlab_pullrequests/tests/sample_responses/github/ipynb_base.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cool Header" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Some information\n", - "* Item 1\n", - "* Item 2\n", - "* Item 3" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "hi\n", - "2\n" - ] - } - ], - "source": [ - "print('hi')\n", - "print(1+1)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 - } \ No newline at end of file diff --git a/jupyterlab_pullrequests/tests/sample_responses/github/ipynb_nbdiff.json b/jupyterlab_pullrequests/tests/sample_responses/github/ipynb_nbdiff.json deleted file mode 100644 index ed484b8..0000000 --- a/jupyterlab_pullrequests/tests/sample_responses/github/ipynb_nbdiff.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "base":{ - "cells":[ - { - "cell_type":"markdown", - "metadata":{ - - }, - "source":"## Cool Header" - }, - { - "cell_type":"markdown", - "metadata":{ - - }, - "source":"## Some information\n* Item 1\n* Item 2\n* Item 3" - }, - { - "cell_type":"code", - "execution_count":1, - "metadata":{ - - }, - "outputs":[ - { - "name":"stdout", - "output_type":"stream", - "text":"hi\n2\n" - } - ], - "source":"print('hi')\nprint(1+1)" - } - ], - "metadata":{ - "kernelspec":{ - "display_name":"Python 3", - "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.7.3" - } - }, - "nbformat":4, - "nbformat_minor":2 - }, - "diff":[ - { - "op":"patch", - "key":"cells", - "diff":[ - { - "op":"addrange", - "key":0, - "valuelist":[ - { - "cell_type":"code", - "execution_count":1, - "metadata":{ - - }, - "outputs":[ - - ], - "source":"def hello():\n print(\"hello!\")" - } - ] - }, - { - "op":"removerange", - "key":0, - "length":1 - }, - { - "op":"patch", - "key":1, - "diff":[ - { - "op":"patch", - "key":"source", - "diff":[ - { - "op":"addrange", - "key":3, - "valuelist":[ - "* Item 2.5\n" - ] - } - ] - } - ] - } - ] - }, - { - "op":"replace", - "key":"nbformat_minor", - "value":4 - } - ] -} \ No newline at end of file diff --git a/jupyterlab_pullrequests/tests/sample_responses/github/ipynb_remote.json b/jupyterlab_pullrequests/tests/sample_responses/github/ipynb_remote.json deleted file mode 100644 index 7579808..0000000 --- a/jupyterlab_pullrequests/tests/sample_responses/github/ipynb_remote.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "def hello():\n", - " print(\"hello!\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Some information\n", - "* Item 1\n", - "* Item 2\n", - "* Item 2.5\n", - "* Item 3" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "hi\n", - "2\n" - ] - } - ], - "source": [ - "print('hi')\n", - "print(1+1)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 - } \ No newline at end of file diff --git a/jupyterlab_pullrequests/tests/test_handlers_integration.py b/jupyterlab_pullrequests/tests/test_handlers_integration.py index 73e6897..b3d4eee 100644 --- a/jupyterlab_pullrequests/tests/test_handlers_integration.py +++ b/jupyterlab_pullrequests/tests/test_handlers_integration.py @@ -248,39 +248,3 @@ def test_id_invalid(self): ) self.assertEqual(response.code, 400) self.assertIn("Invalid response", response.reason) - - -# Test get PR comments -class TestPostPullRequestsNBDiffHandler(TestPullRequest): - - # Test empty body - def test_body_empty(self): - response = self.fetch("/pullrequests/files/nbdiff", method="POST", body="") - self.assertEqual(response.code, 400) - self.assertIn("Invalid POST body", response.reason) - - # Test invalid body JSON - def test_body_invalid(self): - response = self.fetch("/pullrequests/files/nbdiff", method="POST", body="{)") - self.assertEqual(response.code, 400) - self.assertIn("Invalid POST body", response.reason) - - # Test invalid body JSON - def test_body_missingkey(self): - response = self.fetch( - "/pullrequests/files/nbdiff", - method="POST", - body='{"body": 123, "currentContent": "test"}', - ) - self.assertEqual(response.code, 400) - self.assertIn("Missing POST key", response.reason) - - # Test invalid body JSON - def test_body_invalid_(self): - response = self.fetch( - "/pullrequests/files/nbdiff", - method="POST", - body='{"previousContent": "bad", "currentContent": "bad"}', - ) - self.assertEqual(response.code, 500) - self.assertIn("Error diffing content", response.reason) diff --git a/jupyterlab_pullrequests/tests/test_manager.py b/jupyterlab_pullrequests/tests/test_manager.py index 782fcc5..5fb8d5c 100644 --- a/jupyterlab_pullrequests/tests/test_manager.py +++ b/jupyterlab_pullrequests/tests/test_manager.py @@ -18,24 +18,6 @@ def read_sample_response(filename): ) -@pytest.mark.asyncio -async def test_GitHubManager_get_file_nbdiff(): - manager = GitHubManager(access_token="valid") - prev_content = ( - HERE / "sample_responses" / "github" / "ipynb_base.json" - ).read_text() - curr_content = ( - HERE / "sample_responses" / "github" / "ipynb_remote.json" - ).read_text() - - result = await manager.get_file_nbdiff(prev_content, curr_content) - - expected_result = json.loads( - (HERE / "sample_responses" / "github" / "ipynb_nbdiff.json").read_text() - ) - assert result == expected_result - - @pytest.mark.asyncio @patch("tornado.httpclient.AsyncHTTPClient.fetch", new_callable=AsyncMock) async def test_GitHubManager_call_provider_bad_gitresponse(mock_fetch): diff --git a/package.json b/package.json index e4e31cc..a63612b 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "@jupyterlab/coreutils": "^4.0.0", "@jupyterlab/docregistry": "^2.0.0", "@jupyterlab/filebrowser": "^2.0.0", - "@jupyterlab/git": "0.21.0 - 0.30.0", + "@jupyterlab/git": "0.24.0 - 0.30.0", "@jupyterlab/mainmenu": "^2.0.0", "@jupyterlab/nbformat": "^2.0.0", "@jupyterlab/rendermime": "^2.0.0", diff --git a/setup.cfg b/setup.cfg index 2f78c1b..cecc833 100644 --- a/setup.cfg +++ b/setup.cfg @@ -43,7 +43,7 @@ setup_requires = wheel install_requires = jupyterlab ~=2.0 - nbdime + jupyterlab-git >=0.24.0,<0.30.0a0 packages = find: include_package_data = True zip_safe = False diff --git a/src/components/diff/NotebookDiff.ts b/src/components/diff/NotebookDiff.ts index dc1691d..68d2d0e 100644 --- a/src/components/diff/NotebookDiff.ts +++ b/src/components/diff/NotebookDiff.ts @@ -5,89 +5,41 @@ /* eslint-disable no-inner-declarations */ -import { INotebookContent } from '@jupyterlab/nbformat'; +import { NotebookDiff } from '@jupyterlab/git'; +import { DiffModel } from '@jupyterlab/git/lib/components/diff/model'; import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; -import { ServerConnection } from '@jupyterlab/services'; -import { JSONObject } from '@lumino/coreutils'; -import { Message } from '@lumino/messaging'; -import { Panel, Widget } from '@lumino/widgets'; import jsonMap from 'json-source-map'; -import { IDiffEntry } from 'nbdime/lib/diff/diffentries'; import { CellDiffModel, NotebookDiffModel } from 'nbdime/lib/diff/model'; +import { NotebookDiffWidget } from 'nbdime/lib/diff/widget'; import { IDiffOptions, INotebookMapping, IThread, IThreadCell } from '../../tokens'; -import { generateNode, requestAPI } from '../../utils'; import { NotebookCellsDiff } from './NotebookCellsDiff'; -/** - * Class of the outermost widget, the draggable tab - */ -const NBDIME_CLASS = 'nbdime-Widget'; - -/** - * Class of the root of the actual diff, the scroller element - */ -const ROOT_CLASS = 'nbdime-root'; - -export class NotebookDiff extends Panel { +export class NotebookPRDiff extends NotebookDiff { constructor(props: IDiffOptions) { - super(); - this.addClass(NBDIME_CLASS); - this.scroller = new Panel(); - this.scroller.addClass(ROOT_CLASS); - this.scroller.node.tabIndex = -1; - - const header = Private.diffHeader( - props.diff.base.label, - props.diff.head.label - ); - this.scroller.addWidget(header); - - this.addWidget(this.scroller); - - this.computeDiff(props.diff.base.content, props.diff.head.content) - .then(data => { - this.onData( - props.pullRequestId, - props.filename, - data, - props.renderMime, - props.threads - ); - }) - .catch(error => { - this.onError(error); - }); - } - - protected async computeDiff( - previousContent: string, - currentContent: string - ): Promise { - const data = await requestAPI( - 'pullrequests/files/nbdiff', - 'POST', - { - previousContent, - currentContent - } + super( + new DiffModel({ + challenger: { + content: (): Promise => + Promise.resolve(props.diff.head.content), + label: props.diff.head.label, + source: props.diff.head.sha + }, + filename: props.filename, + reference: { + content: (): Promise => + Promise.resolve(props.diff.base.content), + label: props.diff.base.label, + source: props.diff.base.sha + } + }), + props.renderMime ); - data['baseMapping'] = Private.computeNotebookMapping( - previousContent || '{}' - ) as any; - data['headMapping'] = Private.computeNotebookMapping( - currentContent || '{}' - ) as any; - return data; - } - - dispose(): void { - this.scroller.dispose(); - super.dispose(); + this._props = props; } protected static mapThreadsOnChunks( @@ -208,73 +160,31 @@ export class NotebookDiff extends Panel { return threadsByChunk; } - /** - * Handle `'activate-request'` messages. - */ - protected onActivateRequest(msg: Message): void { - this.scroller.node.focus(); - } - - /** - * Callback on diff and discussions requests - * - * @param pullRequestId Pull request ID - * @param filename Notebook filename - * @param data Notebook diff raw data - * @param renderMime Rendermime registry - * @param threads List of discussion on the file - */ - protected onData( - pullRequestId: string, - filename: string, - data: JSONObject, - renderMime: IRenderMimeRegistry, - threads: IThread[] - ): void { - if (this.isDisposed) { - return; - } - const base = data['base'] as INotebookContent; - const diff = (data['diff'] as any) as IDiffEntry[]; - const model = new NotebookDiffModel(base, diff); - const comments = NotebookDiff.mapThreadsOnChunks( - data.baseMapping as any, - data.headMapping as any, - NotebookDiff.reChunkCells(model.chunkedCells), - threads + protected createDiffView( + model: NotebookDiffModel, + renderMime: IRenderMimeRegistry + ): NotebookDiffWidget { + // return new NotebookDiffWidget(model, renderMime); + const baseMapping = Private.computeNotebookMapping( + this._props.diff.base.content || '{}' + ); + const headMapping = Private.computeNotebookMapping( + this._props.diff.head.content || '{}' ); - const nbdWidget = new NotebookCellsDiff({ - pullRequestId, - filename, + const comments = NotebookPRDiff.mapThreadsOnChunks( + baseMapping, + headMapping, + NotebookPRDiff.reChunkCells(model.chunkedCells), + this._props.threads + ); + + return new NotebookCellsDiff({ + pullRequestId: this._props.pullRequestId, + filename: this._props.filename, model, comments, renderMime }); - - this.scroller.addWidget(nbdWidget); - nbdWidget.init().catch(error => { - console.error('Failed to mark unchanged ranges', error); - }); - } - - /** - * Callback on error when requesting the diff or the discussions - * - * @param error Error - */ - protected onError( - error: ServerConnection.NetworkError | ServerConnection.ResponseError - ): void { - if (this.isDisposed) { - return; - } - console.error(error); - const widget = new Widget(); - widget.node.innerHTML = ``; - this.scroller.addWidget(widget); } /** @@ -323,7 +233,7 @@ export class NotebookDiff extends Panel { return newChunks; } - protected scroller: Panel; + protected _props: IDiffOptions; } namespace Private { @@ -353,15 +263,4 @@ namespace Private { ) }; } - /** - * Create a header widget for the diff view. - */ - export function diffHeader(baseLabel: string, remoteLabel: string): Widget { - const node = generateNode('div', { class: 'jp-git-diff-banner' }); - - node.innerHTML = `${baseLabel} - ${remoteLabel}`; - - return new Widget({ node }); - } } diff --git a/src/components/diff/plaintext.ts b/src/components/diff/plaintext.ts index a263524..d2dc851 100644 --- a/src/components/diff/plaintext.ts +++ b/src/components/diff/plaintext.ts @@ -1,8 +1,7 @@ /* eslint-disable @typescript-eslint/ban-ts-ignore */ -import { Mode } from '@jupyterlab/codemirror'; -import { mergeView } from '@jupyterlab/git/lib/components/diff/mergeview'; +import { PlainTextDiff } from '@jupyterlab/git'; +import { DiffModel } from '@jupyterlab/git/lib/components/diff/model'; import { Widget } from '@lumino/widgets'; -import { MergeView } from 'codemirror'; import { IComment, IDiffOptions, IThread } from '../../tokens'; import { generateNode } from '../../utils'; import { Discussion } from '../discussion/Discussion'; @@ -10,14 +9,25 @@ import { Discussion } from '../discussion/Discussion'; /** * Plain Text Diff widget */ -export class PlainTextDiff extends Widget { +export class PlainTextPRDiff extends PlainTextDiff { constructor(props: IDiffOptions) { - super({ - node: PlainTextDiff.createNode( - props.diff.base.label, - props.diff.head.label - ) - }); + super( + new DiffModel({ + challenger: { + content: (): Promise => + Promise.resolve(props.diff.head.content), + label: props.diff.head.label, + source: props.diff.head.sha + }, + filename: props.filename, + reference: { + content: (): Promise => + Promise.resolve(props.diff.base.content), + label: props.diff.base.label, + source: props.diff.base.sha + } + }) + ); this._props = props; } @@ -36,35 +46,6 @@ export class PlainTextDiff extends Widget { super.dispose(); } - /** - * Callback to create the diff widget once the widget - * is attached so CodeMirror get proper size. - */ - onAfterAttach(): void { - this.createDiffView(this._props); - } - - /** - * Create wrapper node - */ - protected static createNode( - baseLabel: string, - remoteLabel: string - ): HTMLElement { - const head = generateNode('div', { class: 'jp-git-diff-root' }); - head.innerHTML = ` - `; - head.appendChild( - generateNode('div', { - class: 'jp-git-PlainText-diff jp-PullRequestTextDiff' - }) - ); - return head; - } - /** * Create comment decoration node */ @@ -87,7 +68,7 @@ export class PlainTextDiff extends Widget { ): void { editor.clearGutter('jp-PullRequestCommentDecoration'); for (let lineIdx = from; lineIdx < to; lineIdx++) { - const div = PlainTextDiff.makeCommentDecoration(); + const div = PlainTextPRDiff.makeCommentDecoration(); div.addEventListener('click', () => { this.createThread(editor, lineIdx, side); }); @@ -100,60 +81,54 @@ export class PlainTextDiff extends Widget { * * @param props Plain Text diff options */ - protected createDiffView(props: IDiffOptions): void { - const mode = - Mode.findByFileName(props.filename) || Mode.findBest(props.filename); + protected async createDiffView(): Promise { + await super.createDiffView(); - this._mergeView = mergeView( - this.node.getElementsByClassName( - 'jp-git-PlainText-diff' - )[0] as HTMLElement, + if (this._mergeView) { { - value: props.diff.head.content, - orig: props.diff.base.content, - gutters: [ + this._mergeView.leftOriginal().setOption('gutters', [ 'CodeMirror-linenumbers', // FIXME without this - the comment decoration does not show up // But it add a single comment decoration on the first line of each editors 'jp-PullRequestCommentDecoration', 'CodeMirror-patchgutter' - ], - lineNumbers: true, - mode: mode.mime, - theme: 'jupyter', - connect: 'align', - collapseIdentical: true, - readOnly: true, - revertButtons: false, - lineWrapping: true + ]); + const { from, to } = this._mergeView.leftOriginal().getViewport(); + this.updateView( + this._mergeView.leftOriginal(), + from, + to, + 'originalLine' + ); + this._mergeView + .leftOriginal() + .on( + 'viewportChange', + (editor: CodeMirror.Editor, from: number, to: number) => { + this.updateView(editor, from, to, 'originalLine'); + } + ); } - ) as MergeView.MergeViewEditor; - { - // @ts-ignore - const { from, to } = this._mergeView.left.orig.getViewport(); - // @ts-ignore - this.updateView(this._mergeView.left.orig, from, to, 'originalLine'); - // @ts-ignore - this._mergeView.left.orig.on( - 'viewportChange', - (editor: CodeMirror.Editor, from: number, to: number) => { - this.updateView(editor, from, to, 'originalLine'); - } - ); - } - - { - const { from, to } = this._mergeView.editor().getViewport(); - this.updateView(this._mergeView.editor(), from, to, 'line'); - this._mergeView - .editor() - .on( - 'viewportChange', - (editor: CodeMirror.Editor, from: number, to: number) => { - this.updateView(editor, from, to, 'line'); - } - ); + { + this._mergeView.editor().setOption('gutters', [ + 'CodeMirror-linenumbers', + // FIXME without this - the comment decoration does not show up + // But it add a single comment decoration on the first line of each editors + 'jp-PullRequestCommentDecoration', + 'CodeMirror-patchgutter' + ]); + const { from, to } = this._mergeView.editor().getViewport(); + this.updateView(this._mergeView.editor(), from, to, 'line'); + this._mergeView + .editor() + .on( + 'viewportChange', + (editor: CodeMirror.Editor, from: number, to: number) => { + this.updateView(editor, from, to, 'line'); + } + ); + } } } @@ -246,7 +221,6 @@ export class PlainTextDiff extends Widget { .dispose(); } - protected _mergeView: MergeView.MergeViewEditor; protected _props: IDiffOptions; // Keep track of discussion widgets to dispose them with this widget private _threadWidgets: Widget[] = []; diff --git a/src/components/tab/FileDiffWidget.ts b/src/components/tab/FileDiffWidget.ts index cd40175..bde9d4d 100644 --- a/src/components/tab/FileDiffWidget.ts +++ b/src/components/tab/FileDiffWidget.ts @@ -6,8 +6,8 @@ import { PromiseDelegate } from '@lumino/coreutils'; import { Panel } from '@lumino/widgets'; import { IDiffOptions, IFileDiff, IThread } from '../../tokens'; import { requestAPI } from '../../utils'; -import { NotebookDiff } from '../diff/NotebookDiff'; -import { PlainTextDiff } from '../diff/plaintext'; +import { NotebookPRDiff } from '../diff/NotebookDiff'; +import { PlainTextPRDiff } from '../diff/plaintext'; /** * FileDiffWidget properties @@ -98,10 +98,10 @@ export class FileDiffWidget extends MainAreaWidget { protected showDiff(diffProps: IDiffOptions): void { const fileExtension = PathExt.extname(diffProps.filename).toLowerCase(); if (fileExtension === '.ipynb') { - this.content.addWidget(new NotebookDiff(diffProps)); + this.content.addWidget(new NotebookPRDiff(diffProps)); } else { try { - this.content.addWidget(new PlainTextDiff(diffProps)); + this.content.addWidget(new PlainTextPRDiff(diffProps)); } catch (reason) { this.showError(reason.message || reason); } diff --git a/src/index.ts b/src/index.ts index e832473..a6a8e4c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,11 +3,15 @@ import { JupyterFrontEnd, JupyterFrontEndPlugin } from '@jupyterlab/application'; +import { PathExt } from '@jupyterlab/coreutils'; +import { diffIcon } from '@jupyterlab/git/lib/style/icons'; import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; -import { diffIcon } from '@jupyterlab/git/lib/style/icons'; import { Widget } from '@lumino/widgets'; import { PullRequestPanelWrapper } from './components/PullRequestPanel'; +import { DescriptionWidget } from './components/tab/DescriptionWidget'; +import { FileDiffWidget } from './components/tab/FileDiffWidget'; +import { pullRequestsIcon } from './style/icons'; import { CommandIDs, IFile, @@ -15,9 +19,6 @@ import { NAMESPACE, PLUGIN_ID } from './tokens'; -import { DescriptionWidget } from './components/tab/DescriptionWidget'; -import { FileDiffWidget } from './components/tab/FileDiffWidget'; -import { pullRequestsIcon } from './style/icons'; // JupyterLab plugin props const pullRequestPlugin: JupyterFrontEndPlugin = { @@ -111,7 +112,7 @@ function activate( settingsRegistry }); mainAreaItem.id = id; - mainAreaItem.title.label = file.name; + mainAreaItem.title.label = PathExt.basename(file.name); mainAreaItem.title.caption = file.name; mainAreaItem.title.icon = diffIcon; mainAreaItem.title.closable = true; diff --git a/style/index.css b/style/index.css index 81c990f..1820f0d 100644 --- a/style/index.css +++ b/style/index.css @@ -349,11 +349,6 @@ p.jp-PullRequestCommentItemContentTitle { } /* Notebook diff styles */ -.nbdime-Widget .jp-git-diff-banner { - width: calc(100% - 52px); - margin: 0px 8px; -} - .jp-PullRequestCellDiff { overflow: visible; margin: 5px 0px; @@ -425,7 +420,7 @@ p.jp-PullRequestCommentItemContentTitle { } /* Plain text diff */ -.jp-git-PlainText-diff.jp-PullRequestTextDiff { +.jp-PullRequestTab .jp-git-diff-root { height: auto; } @@ -451,7 +446,7 @@ p.jp-PullRequestCommentItemContentTitle { transition: all 0.2s ease-in-out; } -.jp-PullRequestTextDiff .cm-s-jupyter .CodeMirror-gutters { +.jp-PullRequestTab .jp-git-diff-root .cm-s-jupyter .CodeMirror-gutters { background-color: var(--jp-layout-color2); } @@ -459,23 +454,3 @@ p.jp-PullRequestCommentItemContentTitle { .jp-PullRequestCommentDecoration:hover { transform: scale(1.2); } - -.jp-git-diff-banner { - display: flex; - margin-bottom: 5px; -} - -.jp-git-diff-banner span { - margin: 0px 4px; - padding: 0px 4px; - width: 50%; - font-weight: bold; -} - -.jp-git-diff-banner span:first-of-type { - background-color: var(--jp-git-diff-deleted-color); -} - -.jp-git-diff-banner span:last-of-type { - background-color: var(--jp-git-diff-added-color); -} diff --git a/yarn.lock b/yarn.lock index 4449355..243da93 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1392,10 +1392,10 @@ "@lumino/widgets" "^1.11.1" react "~16.9.0" -"@jupyterlab/git@0.21.0 - 0.30.0": - version "0.23.3" - resolved "https://registry.yarnpkg.com/@jupyterlab/git/-/git-0.23.3.tgz#a7081ec2e85db62cccc7557304c62908d5f7469e" - integrity sha512-ayGAKS0XXwysZnjfp6Nr4fZ90+d0ap4bq/JvVpu/5nB3ZJzhBHjkotkajlCzlOfmOVRg3Bhu2TPSH8XXfJOuAQ== +"@jupyterlab/git@0.24.0 - 0.30.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@jupyterlab/git/-/git-0.24.0.tgz#3af0901790d89bc566d37d08f09ff5462afb00d4" + integrity sha512-V7J2j/NU1Wk1hujvyPL/06ulve8+hztTA/6lo/Coxz2M03ByIapVdgWNHQI2bM3emJbVdgV+0W1Kd1nwO8hEQg== dependencies: "@jupyterlab/application" "^2.0.0" "@jupyterlab/apputils" "^2.0.0" @@ -1410,11 +1410,12 @@ "@jupyterlab/terminal" "^2.0.0" "@jupyterlab/ui-components" "^2.0.0" "@lumino/collections" "^1.2.3" - "@lumino/commands" "^1.11.0" - "@lumino/coreutils" "^1.5.0" - "@lumino/polling" "^1.0.4" - "@lumino/signaling" "^1.4.0" - "@lumino/widgets" "^1.11.1" + "@lumino/commands" "^1.12.0" + "@lumino/coreutils" "^1.5.3" + "@lumino/disposable" "^1.4.3" + "@lumino/polling" "^1.3.3" + "@lumino/signaling" "^1.4.3" + "@lumino/widgets" "^1.17.0" "@material-ui/core" "^4.8.2" "@material-ui/icons" "^4.5.1" "@material-ui/lab" "^4.0.0-alpha.54" @@ -1680,7 +1681,7 @@ dependencies: "@lumino/algorithm" "^1.3.3" -"@lumino/commands@^1.10.1", "@lumino/commands@^1.11.0", "@lumino/commands@^1.12.0": +"@lumino/commands@^1.10.1", "@lumino/commands@^1.12.0": version "1.12.0" resolved "https://registry.yarnpkg.com/@lumino/commands/-/commands-1.12.0.tgz#63a744d034d8bc524455e47f06c0ac5f2eb6ec38" integrity sha512-5TFlhDzZk1X8rCBjhh0HH3j6CcJ03mx2Pd/1rGa7MB5R+3+yYYk+gTlfHRqsxdehNRmiISaHRSrMnW8bynW7ZQ== @@ -1693,7 +1694,7 @@ "@lumino/signaling" "^1.4.3" "@lumino/virtualdom" "^1.8.0" -"@lumino/coreutils@^1.3.0", "@lumino/coreutils@^1.4.2", "@lumino/coreutils@^1.5.0", "@lumino/coreutils@^1.5.3": +"@lumino/coreutils@^1.3.0", "@lumino/coreutils@^1.4.2", "@lumino/coreutils@^1.5.3": version "1.5.3" resolved "https://registry.yarnpkg.com/@lumino/coreutils/-/coreutils-1.5.3.tgz#89dd7b7f381642a1bf568910c5b62c7bde705d71" integrity sha512-G72jJ6sgOwAUuilz+cri7LpHIJxllK+qz+YZUC3fyyWHK7oRlZemcc43jZAVE+tagTdMxKYSQWNIVzM5lI8sWw== @@ -1732,7 +1733,7 @@ "@lumino/algorithm" "^1.3.3" "@lumino/collections" "^1.3.3" -"@lumino/polling@^1.0.4", "@lumino/polling@^1.1.1": +"@lumino/polling@^1.1.1", "@lumino/polling@^1.3.3": version "1.3.3" resolved "https://registry.yarnpkg.com/@lumino/polling/-/polling-1.3.3.tgz#6336638cb9ba2f4f4c3ef2529c7f260abbd25148" integrity sha512-uMRi6sPRnKW8m38WUY3qox1jxwzpvceafUbDJATCwyrZ48+YoY5Fxfmd9dqwioHS1aq9np5c6L35a9ZGuS0Maw== @@ -1746,7 +1747,7 @@ resolved "https://registry.yarnpkg.com/@lumino/properties/-/properties-1.2.3.tgz#10675e554e4a9dcc4022de01875fd51f33e2c785" integrity sha512-dbS9V/L+RpQoRjxHMAGh1JYoXaLA6F7xkVbg/vmYXqdXZ7DguO5C3Qteu9tNp7Z7Q31TqFWUCrniTI9UJiJCoQ== -"@lumino/signaling@^1.2.2", "@lumino/signaling@^1.3.5", "@lumino/signaling@^1.4.0", "@lumino/signaling@^1.4.3": +"@lumino/signaling@^1.2.2", "@lumino/signaling@^1.3.5", "@lumino/signaling@^1.4.3": version "1.4.3" resolved "https://registry.yarnpkg.com/@lumino/signaling/-/signaling-1.4.3.tgz#d29f7f542fdcd70b91ca275d3ca793ae21cebf6a" integrity sha512-6clc8SMcH0tyKXIX31xw6sxjxJl5hj4YRd1DTHTS62cegQ0FkO8JjJeuv+Nc1pgTg6nEAf65aSOHpUdsFHDAvQ== @@ -1760,7 +1761,7 @@ dependencies: "@lumino/algorithm" "^1.3.3" -"@lumino/widgets@^1.11.1", "@lumino/widgets@^1.16.0", "@lumino/widgets@^1.19.0", "@lumino/widgets@^1.6.0": +"@lumino/widgets@^1.11.1", "@lumino/widgets@^1.16.0", "@lumino/widgets@^1.17.0", "@lumino/widgets@^1.19.0", "@lumino/widgets@^1.6.0": version "1.19.0" resolved "https://registry.yarnpkg.com/@lumino/widgets/-/widgets-1.19.0.tgz#5275aaa9c30d23d78a40004fe1c33582cb5dd5fc" integrity sha512-LR1mwbbTS0K58K3SzC7TtapjSDBwL75Udrif9vBygyIpYNTT9VfRFvl+PT2+KSwhefClNI4n5pZ2s+RO908rsg==