From a1f12b6dc713916a1afd815e03c6ecc420861eac Mon Sep 17 00:00:00 2001 From: Oleksandr Pryimak Date: Sat, 21 Nov 2020 18:09:13 -0800 Subject: [PATCH 1/7] Add nbdiff-web-export to export a diff inside a rendered HTML nbdiff-web-export --ouput-dir output ./nbdime/webapp/testnotebooks/remote.ipynb ./nbdime/webapp/testnotebooks/base.ipynb or nbdiff-web-export --output-dir output HEAD~1 HEAD These would generate inside output directory diff1.html diff2.html .... diffN.html depending how many files has been changed it would also drop nbdime.js in the output directory Alternatively one can use --nbdime_url optional parameter to specify where to get nbdime.js --- nbdime/args.py | 2 +- nbdime/nbdiffapp.py | 59 +++++++------ nbdime/webapp/nbdiffwebexport.py | 102 ++++++++++++++++++++++ nbdime/webapp/nbdimeserver.py | 1 + nbdime/webapp/templates/diffembedded.html | 38 ++++++++ packages/webapp/src/app/diff.ts | 5 ++ packages/webapp/src/index.ts | 13 ++- setup.py | 1 + 8 files changed, 192 insertions(+), 29 deletions(-) create mode 100644 nbdime/webapp/nbdiffwebexport.py create mode 100644 nbdime/webapp/templates/diffembedded.html diff --git a/nbdime/args.py b/nbdime/args.py index ceaa99b30..d1dc3f377 100644 --- a/nbdime/args.py +++ b/nbdime/args.py @@ -369,7 +369,7 @@ def add_filter_args(diff_parser): def add_git_diff_driver_args(diff_parser): - """Adds a set of 7 stanard git diff driver arguments: + """Adds a set of 7 standard git diff driver arguments: path old-file old-hex old-mode new-file new-hex new-mode [ rename-to rename-metadata ] Note: Only path, base and remote are added to parsed namespace diff --git a/nbdime/nbdiffapp.py b/nbdime/nbdiffapp.py index ece783a14..1d8968348 100644 --- a/nbdime/nbdiffapp.py +++ b/nbdime/nbdiffapp.py @@ -33,38 +33,27 @@ def main_diff(args): process_diff_flags(args) base, remote, paths = resolve_diff_args(args) - # Check if base/remote are gitrefs: + # We are asked to do a diff of git revisions: + status = 0 + for fbase, fremote in list_changed_file_pairs(base, remote, paths): + status = _handle_diff(fbase, fremote, output, args) + if status != 0: + # Short-circuit on error in diff handling + return status + return status + + +def list_changed_file_pairs(base, remote, paths): if is_gitref(base) and is_gitref(remote): - # We are asked to do a diff of git revisions: - status = 0 for fbase, fremote in changed_notebooks(base, remote, paths): - status = _handle_diff(fbase, fremote, output, args) - if status != 0: - # Short-circuit on error in diff handling - return status - return status + yield fbase, fremote else: # Not gitrefs: - return _handle_diff(base, remote, output, args) + yield base, remote def _handle_diff(base, remote, output, args): """Handles diffs of files, either as filenames or file-like objects""" - # Check that if args are filenames they either exist, or are - # explicitly marked as missing (added/removed): - for fn in (base, remote): - if (isinstance(fn, string_types) and not os.path.exists(fn) and - fn != EXPLICIT_MISSING_FILE): - print("Missing file {}".format(fn)) - return 1 - # Both files cannot be missing - assert not (base == EXPLICIT_MISSING_FILE and remote == EXPLICIT_MISSING_FILE), ( - 'cannot diff %r against %r' % (base, remote)) - - # Perform actual work: - a = read_notebook(base, on_null='empty') - b = read_notebook(remote, on_null='empty') - - d = diff_notebooks(a, b) + a, b, d = _build_diff(base, remote, on_null="empty") # Output as JSON to file, or print to stdout: if output: @@ -90,6 +79,26 @@ def write(self, text): return 0 +def _build_diff(base, remote, on_null): + """Builds diffs of files, either as filenames or file-like objects""" + # Check that if args are filenames they either exist, or are + # explicitly marked as missing (added/removed): + for fn in (base, remote): + if (isinstance(fn, string_types) and not os.path.exists(fn) and + fn != EXPLICIT_MISSING_FILE): + print("Missing file {}".format(fn)) + return 1 + # Both files cannot be missing + assert not (base == EXPLICIT_MISSING_FILE and remote == EXPLICIT_MISSING_FILE), ( + 'cannot diff %r against %r' % (base, remote)) + + # Perform actual work: + base_notebook = read_notebook(base, on_null=on_null) + remote_notebook = read_notebook(remote, on_null=on_null) + + d = diff_notebooks(base_notebook, remote_notebook) + return base_notebook, remote_notebook, d + def _build_arg_parser(prog=None): """Creates an argument parser for the nbdiff command.""" parser = ConfigBackedParser( diff --git a/nbdime/webapp/nbdiffwebexport.py b/nbdime/webapp/nbdiffwebexport.py new file mode 100644 index 000000000..1d81f9d5a --- /dev/null +++ b/nbdime/webapp/nbdiffwebexport.py @@ -0,0 +1,102 @@ +import sys +import os +import json + +from jinja2 import FileSystemLoader, Environment + +from ..args import ( + Path, + ConfigBackedParser, + add_generic_args) + +from ..nbdiffapp import ( + list_changed_file_pairs, + resolve_diff_args, + _build_diff) + + +here = os.path.abspath(os.path.dirname(__file__)) +static_path = os.path.join(here, 'static') +template_path = os.path.join(here, 'templates') + + +def build_arg_parser(): + """ + Creates an argument parser for the diff tool, that also lets the + user specify a port and displays a help message. + """ + description = 'Difftool for Nbdime.' + parser = ConfigBackedParser( + description=description, + add_help=True + ) + add_generic_args(parser) + parser.add_argument( + "base", help="the base notebook filename OR base git-revision.", + type=Path, + nargs='?', default='HEAD', + ) + parser.add_argument( + "remote", help="the remote modified notebook filename OR remote git-revision.", + type=Path, + nargs='?', default=None, + ) + parser.add_argument( + "paths", help="filter diffs for git-revisions based on path", + type=Path, + nargs='*', default=None, + ) + parser.add_argument( + "--nbdime_url", + type=Path, + default="", + help="URL to nbdime.js" + ) + parser.add_argument( + "--output-dir", + type=Path, + default="output/", + help="a path to an output dir" + ) + return parser + + +def main_export(opts): + env = Environment(loader=FileSystemLoader([template_path]), autoescape=False) + outputdir = opts.output_dir + nbdime_url = opts.nbdime_url + if not nbdime_url: + nbdime_url = "nbdime.js" + import shutil + shutil.copy(os.path.join(static_path, "nbdime.js"), os.path.join(outputdir, nbdime_url)) + + base, remote, paths = resolve_diff_args(opts) + index = 1 + for fbase, fremote in list_changed_file_pairs(base, remote, paths): + # on_null="minimal" is crucial cause web renderer expects + # base_notebook to be a valid notebook even if it is missing + base_notebook, remote_notebook, diff = _build_diff(fbase, fremote, on_null="minimal") + data = json.dumps(dict( + base=base_notebook, + diff=diff + )) + + template = env.get_template("diffembedded.html") + rendered = template.render( + data=data, + nbdime_url=nbdime_url) + outputfilename = os.path.join(outputdir, "diff" + str(index) + ".html") + with open(outputfilename, "w") as f: + f.write(rendered) + index += 1 + + +def main(args=None): + if args is None: + args = sys.argv[1:] + opts = build_arg_parser().parse_args(args) + return main_export(opts) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/nbdime/webapp/nbdimeserver.py b/nbdime/webapp/nbdimeserver.py index 90fd5891f..1883dc4ad 100644 --- a/nbdime/webapp/nbdimeserver.py +++ b/nbdime/webapp/nbdimeserver.py @@ -402,6 +402,7 @@ def make_app(**params): app.exit_code = 0 return app + def init_app(on_port=None, closable=False, **params): asyncio_patch() _logger.debug('Using params: %s', params) diff --git a/nbdime/webapp/templates/diffembedded.html b/nbdime/webapp/templates/diffembedded.html new file mode 100644 index 000000000..f8bd9aeae --- /dev/null +++ b/nbdime/webapp/templates/diffembedded.html @@ -0,0 +1,38 @@ + + + + + + + + nbdime - diff and merge your Jupyter notebooks + + + + + + + + +
+

Notebook Diff

+ +
+ + + + +
+
+ Base + Remote +
+
+ +
+
+ + + + + diff --git a/packages/webapp/src/app/diff.ts b/packages/webapp/src/app/diff.ts index edc6a2dc6..43a15c85e 100644 --- a/packages/webapp/src/app/diff.ts +++ b/packages/webapp/src/app/diff.ts @@ -161,6 +161,11 @@ function getDiff(base: string, remote: string | undefined) { requestDiff(base, remote, baseUrl, onDiffRequestCompleted, onDiffRequestFailed); } +export +function renderDiff(diff: any) { + onDiffRequestCompleted(JSON.parse(diff)); +} + /** * Callback for a successfull diff request */ diff --git a/packages/webapp/src/index.ts b/packages/webapp/src/index.ts index 5630756b6..c00a037c3 100644 --- a/packages/webapp/src/index.ts +++ b/packages/webapp/src/index.ts @@ -3,7 +3,7 @@ 'use strict'; import { - initializeDiff + initializeDiff, renderDiff } from './app/diff'; import { @@ -44,8 +44,15 @@ import './app/merge.css'; /** */ function initialize() { let closable = getConfigOption('closable'); - let type: 'diff' | 'merge' | 'compare'; - if (document.getElementById('compare-local')) { + let type: 'diff' | 'merge' | 'compare' | 'diff-and-base'; + if (document.getElementById('diff-and-base')) { + type = 'diff-and-base' + closable = false + let el = document.getElementById('diff-and-base'); + if (el && el.textContent) { + renderDiff(JSON.parse(el.textContent)) + } + } else if (document.getElementById('compare-local')) { initializeCompare(); type = 'compare'; } else if (getConfigOption('local') || document.getElementById('merge-local')) { diff --git a/setup.py b/setup.py index 73a73b749..def7ea8be 100644 --- a/setup.py +++ b/setup.py @@ -145,6 +145,7 @@ 'nbshow = nbdime.nbshowapp:main', 'nbdiff = nbdime.nbdiffapp:main', 'nbdiff-web = nbdime.webapp.nbdiffweb:main', + 'nbdiff-web-export = nbdime.webapp.nbdiffwebexport:main', 'nbmerge = nbdime.nbmergeapp:main', 'nbmerge-web = nbdime.webapp.nbmergeweb:main', 'git-nbdiffdriver = nbdime.vcs.git.diffdriver:main', From f38f36c5160e5c4ad22a67528fabc6d60d8cb810 Mon Sep 17 00:00:00 2001 From: Oleksandr Pryimak Date: Mon, 23 Nov 2020 23:22:44 -0800 Subject: [PATCH 2/7] Fix missing file bug --- nbdime/nbdiffapp.py | 10 ++++++---- nbdime/webapp/nbdiffwebexport.py | 7 ++++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/nbdime/nbdiffapp.py b/nbdime/nbdiffapp.py index 1d8968348..13e98cbba 100644 --- a/nbdime/nbdiffapp.py +++ b/nbdime/nbdiffapp.py @@ -53,8 +53,11 @@ def list_changed_file_pairs(base, remote, paths): def _handle_diff(base, remote, output, args): """Handles diffs of files, either as filenames or file-like objects""" - a, b, d = _build_diff(base, remote, on_null="empty") - + try: + a, b, d = _build_diff(base, remote, on_null="empty") + except ValueError as e: + print(e, file=sys.stderr) + return 1 # Output as JSON to file, or print to stdout: if output: with open(output, "w") as df: @@ -86,8 +89,7 @@ def _build_diff(base, remote, on_null): for fn in (base, remote): if (isinstance(fn, string_types) and not os.path.exists(fn) and fn != EXPLICIT_MISSING_FILE): - print("Missing file {}".format(fn)) - return 1 + raise ValueError("Missing file {}".format(fn)) # Both files cannot be missing assert not (base == EXPLICIT_MISSING_FILE and remote == EXPLICIT_MISSING_FILE), ( 'cannot diff %r against %r' % (base, remote)) diff --git a/nbdime/webapp/nbdiffwebexport.py b/nbdime/webapp/nbdiffwebexport.py index 1d81f9d5a..c2fe7c51c 100644 --- a/nbdime/webapp/nbdiffwebexport.py +++ b/nbdime/webapp/nbdiffwebexport.py @@ -75,7 +75,11 @@ def main_export(opts): for fbase, fremote in list_changed_file_pairs(base, remote, paths): # on_null="minimal" is crucial cause web renderer expects # base_notebook to be a valid notebook even if it is missing - base_notebook, remote_notebook, diff = _build_diff(fbase, fremote, on_null="minimal") + try: + base_notebook, remote_notebook, diff = _build_diff(fbase, fremote, on_null="minimal") + except ValueError as e: + print(e, file=sys.stderr) + return 1 data = json.dumps(dict( base=base_notebook, diff=diff @@ -89,6 +93,7 @@ def main_export(opts): with open(outputfilename, "w") as f: f.write(rendered) index += 1 + return 0 def main(args=None): From 1dea3580751256b758c910ccd2fa1048196aa6f9 Mon Sep 17 00:00:00 2001 From: Oleksandr Pryimak Date: Mon, 23 Nov 2020 23:30:49 -0800 Subject: [PATCH 3/7] Add the basic test nbdiff can handle missing files --- nbdime/tests/test_cli_apps.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/nbdime/tests/test_cli_apps.py b/nbdime/tests/test_cli_apps.py index 7cbe36c0c..d5437c506 100644 --- a/nbdime/tests/test_cli_apps.py +++ b/nbdime/tests/test_cli_apps.py @@ -286,6 +286,16 @@ def test_nbdiff_app_no_colors(filespath, capsys): assert 0 == main_diff(args) +def test_nbdiff_app_fail_if_file_is_missing(filespath): + # Simply check that the --color-words argument is accepted, not behavior + # Behavior is covered elsewhere + afn = os.path.join(filespath, "missing-file.ipynb") + bfn = os.path.join(filespath, "multilevel-test-local.ipynb") + + args = nbdiffapp._build_arg_parser().parse_args([afn, bfn]) + assert 1 == main_diff(args) + + def test_nbmerge_app(tempfiles, capsys, reset_log): bfn = os.path.join(tempfiles, "multilevel-test-base.ipynb") lfn = os.path.join(tempfiles, "multilevel-test-local.ipynb") From 39c73ee493b69dfcee223ed37c37f77c27d00e1b Mon Sep 17 00:00:00 2001 From: Oleksandr Pryimak Date: Tue, 24 Nov 2020 21:28:41 -0800 Subject: [PATCH 4/7] Remove unrelated comment --- nbdime/tests/test_cli_apps.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/nbdime/tests/test_cli_apps.py b/nbdime/tests/test_cli_apps.py index d5437c506..a3305b5e4 100644 --- a/nbdime/tests/test_cli_apps.py +++ b/nbdime/tests/test_cli_apps.py @@ -287,8 +287,6 @@ def test_nbdiff_app_no_colors(filespath, capsys): def test_nbdiff_app_fail_if_file_is_missing(filespath): - # Simply check that the --color-words argument is accepted, not behavior - # Behavior is covered elsewhere afn = os.path.join(filespath, "missing-file.ipynb") bfn = os.path.join(filespath, "multilevel-test-local.ipynb") From 97855715c53c013d19d80d9dd4895b517e3d9541 Mon Sep 17 00:00:00 2001 From: Oleksandr Pryimak Date: Tue, 24 Nov 2020 23:04:32 -0800 Subject: [PATCH 5/7] nbdiff-web-export will embed the script if --nbdime-url is missing --- nbdime/webapp/nbdiffwebexport.py | 12 +++++++----- nbdime/webapp/templates/diffembedded.html | 4 ++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/nbdime/webapp/nbdiffwebexport.py b/nbdime/webapp/nbdiffwebexport.py index c2fe7c51c..7e874dc77 100644 --- a/nbdime/webapp/nbdiffwebexport.py +++ b/nbdime/webapp/nbdiffwebexport.py @@ -50,7 +50,7 @@ def build_arg_parser(): "--nbdime_url", type=Path, default="", - help="URL to nbdime.js" + help="URL to nbdime.js. If missing output html will contain the script embedded" ) parser.add_argument( "--output-dir", @@ -64,11 +64,12 @@ def build_arg_parser(): def main_export(opts): env = Environment(loader=FileSystemLoader([template_path]), autoescape=False) outputdir = opts.output_dir + nbdime_content = "" nbdime_url = opts.nbdime_url if not nbdime_url: - nbdime_url = "nbdime.js" - import shutil - shutil.copy(os.path.join(static_path, "nbdime.js"), os.path.join(outputdir, nbdime_url)) + # if nbdime_url is empty then we would embed the script + with open(os.path.join(static_path, "nbdime.js"), "r") as f: + nbdime_content = f.read() base, remote, paths = resolve_diff_args(opts) index = 1 @@ -88,7 +89,8 @@ def main_export(opts): template = env.get_template("diffembedded.html") rendered = template.render( data=data, - nbdime_url=nbdime_url) + nbdime_url=nbdime_url, + nbdime_content=nbdime_content) outputfilename = os.path.join(outputdir, "diff" + str(index) + ".html") with open(outputfilename, "w") as f: f.write(rendered) diff --git a/nbdime/webapp/templates/diffembedded.html b/nbdime/webapp/templates/diffembedded.html index f8bd9aeae..cef34db9a 100644 --- a/nbdime/webapp/templates/diffembedded.html +++ b/nbdime/webapp/templates/diffembedded.html @@ -32,7 +32,11 @@

Notebook Diff

+ {% if ndime_url == "" %} + {% else %} + + {% endif %} From 067c83e582a7b7dca669d9be373d269431d07392 Mon Sep 17 00:00:00 2001 From: Vidar Tonaas Fauske Date: Fri, 18 Dec 2020 14:06:03 +0100 Subject: [PATCH 6/7] fix broken checkbox label link --- nbdime/webapp/templates/diff.html | 2 +- nbdime/webapp/templates/difftool.html | 2 +- nbdime/webapp/templates/merge.html | 2 +- nbdime/webapp/templates/mergetool.html | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/nbdime/webapp/templates/diff.html b/nbdime/webapp/templates/diff.html index d077b67e9..4c3088c14 100644 --- a/nbdime/webapp/templates/diff.html +++ b/nbdime/webapp/templates/diff.html @@ -17,7 +17,7 @@

Notebook Diff

- + diff --git a/nbdime/webapp/templates/difftool.html b/nbdime/webapp/templates/difftool.html index 8064884e9..299fbf27d 100644 --- a/nbdime/webapp/templates/difftool.html +++ b/nbdime/webapp/templates/difftool.html @@ -5,7 +5,7 @@

Notebook Diff

- + diff --git a/nbdime/webapp/templates/merge.html b/nbdime/webapp/templates/merge.html index 9de509773..6b80a34cb 100644 --- a/nbdime/webapp/templates/merge.html +++ b/nbdime/webapp/templates/merge.html @@ -20,7 +20,7 @@

Notebook Merge

- + diff --git a/nbdime/webapp/templates/mergetool.html b/nbdime/webapp/templates/mergetool.html index 7820add4a..f6e2d2634 100644 --- a/nbdime/webapp/templates/mergetool.html +++ b/nbdime/webapp/templates/mergetool.html @@ -5,7 +5,7 @@

Notebook Merge

- + From 5b9e1ff7a25719731b1f41ddcd39b0186bb3d22a Mon Sep 17 00:00:00 2001 From: Vidar Tonaas Fauske Date: Fri, 18 Dec 2020 14:35:48 +0100 Subject: [PATCH 7/7] Align some of the changes with existign conventions Important points: - Allow for configuration of mathjax and hide unchanged defaults - Fix read/write encodings so it works on Windows - Add some error handling code if we end up with broken json for the diff view Remaining TODO: - Ensure we build and use a single bundle. Existing nbdime.js does not bundle all the things (fonts, and some chunked JS). - Find and check a decent default for MathJax: Use CDN as default, or switch to using jupyter-renderer's mathjax3 bundled ? --- nbdime/webapp/nbdiffwebexport.py | 69 +++++++++++++++++------ nbdime/webapp/templates/diffembedded.html | 37 ++++-------- nbdime/webapp/templates/nbdimepage.html | 6 +- packages/webapp/src/app/diff.ts | 44 +++++++++------ packages/webapp/src/index.ts | 13 +---- 5 files changed, 95 insertions(+), 74 deletions(-) diff --git a/nbdime/webapp/nbdiffwebexport.py b/nbdime/webapp/nbdiffwebexport.py index 7e874dc77..2510637b5 100644 --- a/nbdime/webapp/nbdiffwebexport.py +++ b/nbdime/webapp/nbdiffwebexport.py @@ -7,7 +7,8 @@ from ..args import ( Path, ConfigBackedParser, - add_generic_args) + add_generic_args, + add_diff_args) from ..nbdiffapp import ( list_changed_file_pairs, @@ -22,15 +23,15 @@ def build_arg_parser(): """ - Creates an argument parser for the diff tool, that also lets the - user specify a port and displays a help message. + Creates an argument parser for the web diff exporter. """ - description = 'Difftool for Nbdime.' + description = 'Export Nbdime diff.' parser = ConfigBackedParser( description=description, add_help=True ) add_generic_args(parser) + add_diff_args(parser) parser.add_argument( "base", help="the base notebook filename OR base git-revision.", type=Path, @@ -42,36 +43,56 @@ def build_arg_parser(): nargs='?', default=None, ) parser.add_argument( - "paths", help="filter diffs for git-revisions based on path", + "paths", help="filter diffs for git-revisions based on path.", type=Path, nargs='*', default=None, ) parser.add_argument( - "--nbdime_url", - type=Path, + "--nbdime-url", default="", - help="URL to nbdime.js. If missing output html will contain the script embedded" + help="URL to nbdime.js. If missing the script will be embedded in the HTML page." + ) + parser.add_argument( + "--mathjax-url", + default="", + help="URL to MathJax JS. If blank, typsetting of LaTeX won't be available in the diff view." + ) + parser.add_argument( + "--mathjax-config", + default="TeX-AMS_HTML-full,Safe", + help="config string for MathJax." + ) + parser.add_argument( + '--show-unchanged', + dest='hide_unchanged', + action="store_false", + default=True, + help="show unchanged cells by default" ) parser.add_argument( "--output-dir", type=Path, - default="output/", - help="a path to an output dir" + default=".", + help="path to output directory." ) return parser def main_export(opts): - env = Environment(loader=FileSystemLoader([template_path]), autoescape=False) + outputdir = opts.output_dir + os.makedirs(outputdir, exist_ok=True) + nbdime_content = "" nbdime_url = opts.nbdime_url if not nbdime_url: # if nbdime_url is empty then we would embed the script - with open(os.path.join(static_path, "nbdime.js"), "r") as f: + with open(os.path.join(static_path, "nbdime.js"), "r", encoding='utf8') as f: nbdime_content = f.read() base, remote, paths = resolve_diff_args(opts) + + env = Environment(loader=FileSystemLoader([template_path]), autoescape=False) index = 1 for fbase, fremote in list_changed_file_pairs(base, remote, paths): # on_null="minimal" is crucial cause web renderer expects @@ -81,20 +102,32 @@ def main_export(opts): except ValueError as e: print(e, file=sys.stderr) return 1 - data = json.dumps(dict( + data = dict( base=base_notebook, diff=diff - )) + ) + + config = dict( + hideUnchange=opts.hide_unchanged, + mathjaxUrl=opts.mathjax_url, + mathjaxConfig=opts.mathjax_config, + ) + # TODO: Create labels for use in template + filenames (instead of index) template = env.get_template("diffembedded.html") rendered = template.render( data=data, - nbdime_url=nbdime_url, - nbdime_content=nbdime_content) - outputfilename = os.path.join(outputdir, "diff" + str(index) + ".html") - with open(outputfilename, "w") as f: + nbdime_js_url=nbdime_url, + nbdime_js_content=nbdime_content, + base_label='Base', + remote_label='Remote', + config_data=config, + ) + outputfilename = os.path.join(outputdir, "nbdiff-" + str(index) + ".html") + with open(outputfilename, "w", encoding="utf8") as f: f.write(rendered) index += 1 + print('Wrote %d diffs to %s' % (index - 1, outputdir)) return 0 diff --git a/nbdime/webapp/templates/diffembedded.html b/nbdime/webapp/templates/diffembedded.html index cef34db9a..551fdde05 100644 --- a/nbdime/webapp/templates/diffembedded.html +++ b/nbdime/webapp/templates/diffembedded.html @@ -1,42 +1,29 @@ - - +{% extends "nbdimepage.html" %} - - - - - nbdime - diff and merge your Jupyter notebooks - - - - - - - + {% block nbdimeheader %}

Notebook Diff

- + -
- Base - Remote + {{ base_label }} + {{ remote_label }}
-
-
+ {% endblock %} - {% if ndime_url == "" %} - + {% block nbdimescripts %} + + {% if nbdime_js_url == "" %} + {% else %} - + {% endif %} - - + {% endblock %} diff --git a/nbdime/webapp/templates/nbdimepage.html b/nbdime/webapp/templates/nbdimepage.html index c209fd165..435ad0348 100644 --- a/nbdime/webapp/templates/nbdimepage.html +++ b/nbdime/webapp/templates/nbdimepage.html @@ -10,9 +10,7 @@ - - - + {% block nbdimeheader %} {% endblock %} @@ -20,8 +18,10 @@
+ {% block nbdimescripts %} + {% endblock %} diff --git a/packages/webapp/src/app/diff.ts b/packages/webapp/src/app/diff.ts index 43a15c85e..6c09fe55f 100644 --- a/packages/webapp/src/app/diff.ts +++ b/packages/webapp/src/app/diff.ts @@ -17,10 +17,6 @@ import { defaultSanitizer } from '@jupyterlab/apputils'; -import { - PageConfig -} from '@jupyterlab/coreutils'; - import { MathJaxTypesetter } from '@jupyterlab/mathjax2'; @@ -158,18 +154,14 @@ function editHistory(pushHistory: boolean | 'replace', statedata: any, title: st export function getDiff(base: string, remote: string | undefined) { let baseUrl = getBaseUrl(); - requestDiff(base, remote, baseUrl, onDiffRequestCompleted, onDiffRequestFailed); + requestDiff(base, remote, baseUrl, renderDiff, renderError); } -export -function renderDiff(diff: any) { - onDiffRequestCompleted(JSON.parse(diff)); -} /** * Callback for a successfull diff request */ -function onDiffRequestCompleted(data: any) { +function renderDiff(data: {base: nbformat.INotebookContent, diff: IDiffEntry[]}) { let layoutWork = showDiff(data); layoutWork.then(() => { @@ -183,13 +175,13 @@ function onDiffRequestCompleted(data: any) { /** * Callback for a failed diff request */ -function onDiffRequestFailed(response: string) { +function renderError(message: string) { console.log('Diff request failed.'); let root = document.getElementById('nbdime-root'); if (!root) { throw new Error('Missing root element "nbidme-root"'); } - root.innerHTML = '
' + response + '
'; + root.innerHTML = '
' + message + '
'; diffWidget = null; toggleSpinner(false); } @@ -247,12 +239,28 @@ function attachToForm() { */ export function initializeDiff() { - attachToForm(); - // If arguments supplied in config, run diff directly: - let base = getConfigOption('base'); - let remote = getConfigOption('remote'); - if (base && (remote || hasPrefix(base))) { - compare(base, remote, 'replace'); + // Check to see if we already have the diff data embedded + if (document.getElementById('diff-and-base')) { + let el = document.getElementById('diff-and-base'); + if (el && el.textContent) { + let data; + try { + data = JSON.parse(el.textContent); + } catch { + renderError('Failed to parse diff data'); + } + renderDiff(data); + } else { + renderError('Missing diff data'); + } + } else { + attachToForm(); + // If arguments supplied in config, run diff directly: + let base = getConfigOption('base'); + let remote = getConfigOption('remote'); + if (base && (remote || hasPrefix(base))) { + compare(base, remote, 'replace'); + } } let exportBtn = document.getElementById('nbdime-export') as HTMLButtonElement; diff --git a/packages/webapp/src/index.ts b/packages/webapp/src/index.ts index c00a037c3..5630756b6 100644 --- a/packages/webapp/src/index.ts +++ b/packages/webapp/src/index.ts @@ -3,7 +3,7 @@ 'use strict'; import { - initializeDiff, renderDiff + initializeDiff } from './app/diff'; import { @@ -44,15 +44,8 @@ import './app/merge.css'; /** */ function initialize() { let closable = getConfigOption('closable'); - let type: 'diff' | 'merge' | 'compare' | 'diff-and-base'; - if (document.getElementById('diff-and-base')) { - type = 'diff-and-base' - closable = false - let el = document.getElementById('diff-and-base'); - if (el && el.textContent) { - renderDiff(JSON.parse(el.textContent)) - } - } else if (document.getElementById('compare-local')) { + let type: 'diff' | 'merge' | 'compare'; + if (document.getElementById('compare-local')) { initializeCompare(); type = 'compare'; } else if (getConfigOption('local') || document.getElementById('merge-local')) {