diff --git a/CHANGELOG.md b/CHANGELOG.md index f95f81f8..3731aaed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,13 +14,14 @@ #### @deathbeds/ipydrawio 1.2.0 +- adds support for data URI-encoded shape libraries (incompatible with `stealth`) [#80] - fixes selection in widget diagrams with more than 10 shapes [#85] #### @deathbeds/ipydrawio-notebook 1.2.0 -#### @deathbeds/ipydrawio-webpack 16.4.0 +#### @deathbeds/ipydrawio-webpack 16.4.500 -- updates to drawio v16.4.0 +- updates to drawio v16.4.5 #### @deathbeds/ipydrawio-jupyter-templates 1.2.0 @@ -31,6 +32,7 @@ #### @deathbeds/ipydrawio-pdf 1.2.0 [#63]: https://github.com/deathbeds/ipydrawio/issues/63 +[#80]: https://github.com/deathbeds/ipydrawio/issues/80 [#85]: https://github.com/deathbeds/ipydrawio/issues/85 [#88]: https://github.com/deathbeds/ipydrawio/issues/88 diff --git a/atest/_Variables.robot b/atest/_Variables.robot index 8338fdab..0dfdb1be 100644 --- a/atest/_Variables.robot +++ b/atest/_Variables.robot @@ -97,3 +97,6 @@ ${XP DIO PAGE SIZE} //div[contains(@class, "geFormatSection")][contains(., "P ${MIME STDERR} application/vnd.jupyter.stderr # retro ${CSS RETRO TREE DIO BTN} css:button[title='${CREATE A BLANK}'] +# docs +${TUTORIALS} ${ROOT}${/}docs${/}tutorials +${CLIB TUTORIAL} ${TUTORIALS}${/}working-with-custom-libraries${/}index.ipynb diff --git a/atest/lab/Tutorials.robot b/atest/lab/Tutorials.robot new file mode 100644 index 00000000..85855884 --- /dev/null +++ b/atest/lab/Tutorials.robot @@ -0,0 +1,51 @@ +# Copyright 2022 ipydrawio contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +*** Settings *** +Documentation Do the tutorials work? +Resource ../_Keywords.robot +Library OperatingSystem +Force Tags component:tutorials +Suite Setup Set Screenshot Directory ${OUTPUT DIR}${/}screenshots${/}tutorials + +*** Variables *** +${XP MY LIBRARY TITLE} xpath://a[starts-with(@title, 'my+library')] +${XP MY LIBRARY SHAPES} ${XP MY LIBRARY TITLE}/following-sibling::div[1]//a[contains(@class, 'geItem')] +${XP SHAPE TOOLTIP} xpath://*[contains(@class, 'geSidebarTooltip')] +@{SHAPE TITLES} Exit Machine Queue Source + +*** Test Cases *** +Custom Library URL Hack + [Documentation] Does using a custom library work? + [Tags] component:widget + Copy File ${CLIB TUTORIAL} ${HOME}${/}clib.ipynb + Wait Until Keyword Succeeds 5x 5s Open clib.ipynb in ${MENU NOTEBOOK} + Lab Command Restart Kernel and Run All Cells + Accept Default Dialog Option + Click Element css:.jp-Cell:last-child + Wait Until Keyword Succeeds 5x 5s Wait for a Diagram to be Ready + Wait Until Page Contains Element ${XP MY LIBRARY TITLE} + ${shapes} = Get WebElements ${XP MY LIBRARY SHAPES} + Should be Equal as Integers ${shapes.__len__()} 4 + FOR ${idx} ${shape} IN ENUMERATE ${shapes} + Mouse Over ${shape} + Wait Until Page Contains Element + ... ${XP SHAPE TOOLTIP}\[contains(., '${SHAPE TITLES[${idx}]}')] + END + [Teardown] Tear Down Custom Library Tutorial + +*** Keywords *** +Tear Down Custom Library Tutorial + Unselect Frame + Remove File ${HOME}${/}clib.ipynb diff --git a/docs/tutorials/index.md b/docs/tutorials/index.md index f51355f1..e51062ef 100644 --- a/docs/tutorials/index.md +++ b/docs/tutorials/index.md @@ -3,6 +3,7 @@ ```{toctree} :maxdepth: 2 designing-jupyter-extensions/index +working-with-custom-libraries/index ``` \"\"\"\n", + "library_xml" + ] + }, + { + "cell_type": "markdown", + "id": "76502de9-f2cb-4485-a438-acb6a06a8ca5", + "metadata": {}, + "source": [ + "This, in turn, must be transformed into a [Data URI](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs). The whole thing can't be `base64` encoded, because drawio expects a semicolon-separated list of ids. \n", + "\n", + "> **GOTCHA**: Use of data URIs relies on a **NASTY PATCH** applied when packaging `@deathbeds/jupyterlab-drawio-webpack`: by default, the upstream would rewrite this into a proxied request, which `ipydrawio` don't support. Usually, the name of the library will be derived from the filename, which is usually the last path component after the `/` ... in this case, the _whole document_ is the path, so we make do with some hacks." + ] + }, + { + "cell_type": "markdown", + "id": "bcd588f0-100e-4dd9-96a7-ea0b16bc6a0f", + "metadata": {}, + "source": [ + "## URL Encoding" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3f062362-8691-42d9-b9d7-f4a29cf6c405", + "metadata": {}, + "outputs": [], + "source": [ + "library_data_uri = f\"data:application/xml,{library_xml}\"" + ] + }, + { + "cell_type": "markdown", + "id": "c59eeed7-8599-429e-a869-3964b4709964", + "metadata": {}, + "source": [] + }, + { + "cell_type": "markdown", + "id": "ca0d0acc-7186-4f81-83cf-fd93da83f59c", + "metadata": {}, + "source": [ + "## URL Params\n", + "Finally, the most reliable means of communicating with drawio is via its [URL parameters](https://www.diagrams.net/doc/faq/supported-url-parameters), exposed on the widget as `url_params`\n", + "\n", + "> **GOTCHA** `url_params` should be set before the widget is displayed to avoid extra dialogs. \n", + "\n", + "The `clibs` parameters accepts a list of \"library keys,\" each with different formats. We are interest in `U` (for `URL`) library.\n", + "\n", + "> Some others that might be worth exploring some time include `L` for `Local`, which works with an `IndexedDB` instance... but is not guaranteed to be configured by the time a document loads.\n", + "\n", + "Note, we also override the `stealth` default... `stealth` isn't _strictly_ going to worsen the privacy posture, as all of the other providers are still disabled." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5a89ad37-caf4-4174-90f0-ba51f7c98c3b", + "metadata": {}, + "outputs": [], + "source": [ + "url_params = dict(ipydrawio.Diagram._default_url_params(None))\n", + "url_params.update(clibs=f\"U{library_data_uri}\", stealth=\"0\",)\n", + "url_params" + ] + }, + { + "cell_type": "markdown", + "id": "40668d7d-0d2d-4727-add8-ef8d494f0b23", + "metadata": {}, + "source": [ + "### More URL Params\n", + "\n", + "A number of other parameters can be useful for custom embedding purposes, such as using a `min`imal `ui`, hiding the default `libs`, disabling additional `p`lugins." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "938af1fe-a2b5-42a0-beee-c93d910b7dfd", + "metadata": {}, + "outputs": [], + "source": [ + "url_params.update(ui=\"min\", libs=\"0\", p=\"\")" + ] + }, + { + "cell_type": "markdown", + "id": "7b7169ce-668f-426c-8146-1c27aa4ef66d", + "metadata": {}, + "source": [ + "## The Widget" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "91835331-2f68-48af-9ca1-c2512f25ded3", + "metadata": {}, + "outputs": [], + "source": [ + "d = ipydrawio.Diagram(url_params=url_params, layout=dict(height=\"800px\"))\n", + "d" + ] + }, + { + "cell_type": "markdown", + "id": "bbb0e474-649d-4e33-96c3-5f4f3bad56bd", + "metadata": {}, + "source": [ + "## Use The Source\n", + "\n", + "We should now be able to use the desired shapes in the diagram. Unlike `url_params`, the `value` of the diagram's `source` can be updated immediately." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5daa299b-08d8-4ad2-b35e-d599157612e4", + "metadata": {}, + "outputs": [], + "source": [ + "d.source.value = '''\n", + " \n", + " \n", + " \n", + " \n", + "'''" + ] + } + ], + "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.10.1" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/packages/ipydrawio-webpack/drawio b/packages/ipydrawio-webpack/drawio index bbf17d5f..bdfb2a39 160000 --- a/packages/ipydrawio-webpack/drawio +++ b/packages/ipydrawio-webpack/drawio @@ -1 +1 @@ -Subproject commit bbf17d5f5a1d73cb6c955b579cd3691fc55ebae7 +Subproject commit bdfb2a3944aaef1a9f95097a6c30d98fbefce1c4 diff --git a/packages/ipydrawio-webpack/package.json b/packages/ipydrawio-webpack/package.json index 96680b34..a0940e4d 100644 --- a/packages/ipydrawio-webpack/package.json +++ b/packages/ipydrawio-webpack/package.json @@ -43,5 +43,5 @@ "build:pre": "python scripts/patch.py && python scripts/static.py" }, "types": "lib/index.d.ts", - "version": "16.4.0" + "version": "16.4.500" } diff --git a/packages/ipydrawio-webpack/scripts/patch.py b/packages/ipydrawio-webpack/scripts/patch.py index 9677bbec..261fe065 100644 --- a/packages/ipydrawio-webpack/scripts/patch.py +++ b/packages/ipydrawio-webpack/scripts/patch.py @@ -29,7 +29,12 @@ "name": "global ref so we can get at the App at runtime", "before": "new App(new Editor", "after": "window.IPYDRAWIO_APP = new App(new Editor", - } + }, + { + "name": "patch cors check for data URI", + "before": "this.editor.isCorsEnabledForUrl(n)||(n=", + "after": "(n.match(/^data:/) || this.editor.isCorsEnabledForUrl(n))||(n=", + }, ] } diff --git a/packages/ipydrawio/package.json b/packages/ipydrawio/package.json index 9dc8d053..a0fa7350 100644 --- a/packages/ipydrawio/package.json +++ b/packages/ipydrawio/package.json @@ -8,7 +8,7 @@ "@jupyterlab/application": "^3.1.0", "@jupyterlab/launcher": "^3.1.0", "@jupyterlab/mainmenu": "^3.1.0", - "@deathbeds/ipydrawio-webpack": "^16.4.0" + "@deathbeds/ipydrawio-webpack": "^16.4.500" }, "description": "A JupyterLab extension for embedding interactive drawio / mxgraph diagrams.", "devDependencies": { diff --git a/yarn.lock b/yarn.lock index 37e77c09..6dfbeca8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -106,14 +106,14 @@ "@jupyterlab/application" "^3.1.0" "@deathbeds/ipydrawio-webpack@file:packages/ipydrawio-webpack": - version "16.4.0" + version "16.4.500" dependencies: "@jupyterlab/application" "^3.1.0" "@deathbeds/ipydrawio@file:packages/ipydrawio": version "1.2.0" dependencies: - "@deathbeds/ipydrawio-webpack" "^16.4.0" + "@deathbeds/ipydrawio-webpack" "^16.4.500" "@jupyterlab/application" "^3.1.0" "@jupyterlab/launcher" "^3.1.0" "@jupyterlab/mainmenu" "^3.1.0"