From 121f72942e67a54b0539b60de526137769479f2e Mon Sep 17 00:00:00 2001 From: rmorshea Date: Wed, 18 Aug 2021 21:32:51 -0700 Subject: [PATCH 01/38] add MANIFEST to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1a06cffb..3b6e5455 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,7 @@ wheels/ *.egg *.manifest *.spec +MANIFEST # Installer logs pip-log.txt From 25e36ff440b9605d32c081c0af591d57c391621e Mon Sep 17 00:00:00 2001 From: rmorshea Date: Thu, 19 Aug 2021 01:45:59 -0700 Subject: [PATCH 02/38] add bug report issue form --- .github/ISSUE_TEMPLATE/bug-report.yml | 59 +++++++++++++++++++++++++++ README.md | 28 +++++++------ 2 files changed, 74 insertions(+), 13 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug-report.yml diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 00000000..32f09795 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,59 @@ +name: Bug Report +description: A detailed description of a problem you are experiencing +title: "..." +labels: [bug, triage] +body: +- type: checkboxes + attributes: + label: Is there an existing issue for this? + description: Please search to see if an issue already exists for the bug you encountered. + options: + - label: I have searched the existing issues + required: true +- type: textarea + attributes: + label: Current Behavior + description: A concise description of what you're experiencing. + validations: + required: false +- type: textarea + attributes: + label: Expected Behavior + description: A concise description of what you expected to happen. + validations: + required: false +- type: textarea + attributes: + label: Steps To Reproduce + description: Steps to reproduce the behavior. + placeholder: | + 1. In this environment... + 2. With this config... + 3. Run '...' + 4. See error... + validations: + required: false +- type: textarea + attributes: + label: Environment + description: | + examples: + - **OS**: Ubuntu 20.04 + - **Python**: 3.10 + - **Browser**: Chrome 92 + value: | + - OS: + - Python: + - Browser: + render: markdown + validations: + required: false +- type: textarea + attributes: + label: Anything else? + description: | + Links? References? Anything that will give us more context about the issue you are encountering! + + Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. + validations: + required: false diff --git a/README.md b/README.md index 08c80f6d..77e8dee4 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,20 @@ # Django IDOM - - Tests - - - Version Info - - - License: MIT - - -`django-idom` allows you to integrate [IDOM](https://github.com/idom-team/idom) into -Django applications. IDOM is a pure Python library inspired by -[ReactJS](https://reactjs.org/) for creating responsive web interfaces. +

+ + Tests + + + Version Info + + + License: MIT + +

+ +`django-idom` allows Django to integrate with [IDOM](https://github.com/idom-team/idom), +a package inspired by [ReactJS](https://reactjs.org/) for creating responsive web +interfaces in pure Python. **You can try IDOM now in a Jupyter Notebook:** Date: Thu, 19 Aug 2021 01:53:48 -0700 Subject: [PATCH 03/38] strip down bug form --- .github/ISSUE_TEMPLATE/bug-report.yml | 28 +-------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 32f09795..43726da6 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -1,6 +1,6 @@ name: Bug Report description: A detailed description of a problem you are experiencing -title: "..." +title: "[BUG] " labels: [bug, triage] body: - type: checkboxes @@ -22,32 +22,6 @@ body: description: A concise description of what you expected to happen. validations: required: false -- type: textarea - attributes: - label: Steps To Reproduce - description: Steps to reproduce the behavior. - placeholder: | - 1. In this environment... - 2. With this config... - 3. Run '...' - 4. See error... - validations: - required: false -- type: textarea - attributes: - label: Environment - description: | - examples: - - **OS**: Ubuntu 20.04 - - **Python**: 3.10 - - **Browser**: Chrome 92 - value: | - - OS: - - Python: - - Browser: - render: markdown - validations: - required: false - type: textarea attributes: label: Anything else? From 5d611285c8e628ca2511139ef9b1b750e7a54c38 Mon Sep 17 00:00:00 2001 From: rmorshea <ryan.morshead@gmail.com> Date: Fri, 20 Aug 2021 01:50:35 -0700 Subject: [PATCH 04/38] update issue form --- .github/ISSUE_TEMPLATE/bug-report.yml | 33 --------------------------- .github/ISSUE_TEMPLATE/config.yml | 9 +++----- .github/ISSUE_TEMPLATE/issue-form.yml | 29 +++++++++++++++++++++++ 3 files changed, 32 insertions(+), 39 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug-report.yml create mode 100644 .github/ISSUE_TEMPLATE/issue-form.yml diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml deleted file mode 100644 index 43726da6..00000000 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Bug Report -description: A detailed description of a problem you are experiencing -title: "[BUG] <title>" -labels: [bug, triage] -body: -- type: checkboxes - attributes: - label: Is there an existing issue for this? - description: Please search to see if an issue already exists for the bug you encountered. - options: - - label: I have searched the existing issues - required: true -- type: textarea - attributes: - label: Current Behavior - description: A concise description of what you're experiencing. - validations: - required: false -- type: textarea - attributes: - label: Expected Behavior - description: A concise description of what you expected to happen. - validations: - required: false -- type: textarea - attributes: - label: Anything else? - description: | - Links? References? Anything that will give us more context about the issue you are encountering! - - Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. - validations: - required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 037e3c2f..6c803e3e 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1,5 @@ blank_issues_enabled: false contact_links: - - name: Documentation - url: https://idom-docs.herokuapp.com/ - about: Refer to the documentation before starting a discussion - - name: Community Support - url: https://github.com/idom-team/idom/discussions - about: Report issues, request features, and ask questions + - name: Start a Discussion + url: https://github.com/idom-team/django-idom/discussions + about: Report issues, request features, ask questions, and share ideas diff --git a/.github/ISSUE_TEMPLATE/issue-form.yml b/.github/ISSUE_TEMPLATE/issue-form.yml new file mode 100644 index 00000000..a860ee3a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/issue-form.yml @@ -0,0 +1,29 @@ +name: Draft a Change +description: Create a detailed plan for enhancement (ONLY START AFTER DISCUSSION PLEASE 🙏) +labels: [triage] +body: +- type: textarea + attributes: + label: Old Behavior + description: Describe how things currently work. + validations: + required: false +- type: textarea + attributes: + label: New Behavior + description: Describe how things ought to work. + validations: + required: false +- type: textarea + attributes: + label: Implementation Details + description: | + A thorough explanation for how the new behavior will be implemented and the old behavior will be deprecated. + validations: + required: false +- type: checkboxes + attributes: + label: Code of Conduct + options: + - label: I agree to follow the [Code of Conduct](https://github.com/idom-team/django-idom/blob/main/CODE_OF_CONDUCT.md). + required: true From 964df5545237f70e0b908d5da98ebbae0dc57dde Mon Sep 17 00:00:00 2001 From: rmorshea <ryan.morshead@gmail.com> Date: Wed, 8 Sep 2021 22:43:33 -0700 Subject: [PATCH 05/38] synchronize JS and Py version requirements for IDOM --- requirements/pkg-deps.txt | 2 +- src/js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements/pkg-deps.txt b/requirements/pkg-deps.txt index b823d656..dbbaf6b6 100644 --- a/requirements/pkg-deps.txt +++ b/requirements/pkg-deps.txt @@ -1,2 +1,2 @@ channels<4.0.0 # Django websocket features -idom<1.0.0 # Python React +idom >=0.33.0, <0.34.0 diff --git a/src/js/package.json b/src/js/package.json index 087045c9..43319d86 100644 --- a/src/js/package.json +++ b/src/js/package.json @@ -18,6 +18,6 @@ "rollup-plugin-replace": "^2.2.0" }, "dependencies": { - "idom-client-react": "^0.8.5" + "idom-client-react": "^0.33.0" } } From 24deb2c7dae90e21d349f4ac1fad133b76405b2b Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Wed, 8 Sep 2021 23:51:27 -0700 Subject: [PATCH 06/38] Allow adding class to a template tag div (#10) * rename view.html -> component.html * remove pinned twisted version * add class as a component param * pin idom to 0.31 --- requirements/test-env.txt | 5 +---- .../templates/idom/{view.html => component.html} | 2 +- src/django_idom/templatetags/idom.py | 4 +++- tests/test_app/templates/base.html | 8 ++++---- 4 files changed, 9 insertions(+), 10 deletions(-) rename src/django_idom/templates/idom/{view.html => component.html} (87%) diff --git a/requirements/test-env.txt b/requirements/test-env.txt index c100c316..6f2e151e 100644 --- a/requirements/test-env.txt +++ b/requirements/test-env.txt @@ -1,6 +1,3 @@ django selenium - -# required due issue with channels: -# https://github.com/django/channels/issues/1639#issuecomment-817994671 -twisted<21 +twisted diff --git a/src/django_idom/templates/idom/view.html b/src/django_idom/templates/idom/component.html similarity index 87% rename from src/django_idom/templates/idom/view.html rename to src/django_idom/templates/idom/component.html index adfc3a6d..84ec6963 100644 --- a/src/django_idom/templates/idom/view.html +++ b/src/django_idom/templates/idom/component.html @@ -1,5 +1,5 @@ {% load static %} -<div id="{{ idom_mount_uuid }}"></div> +<div id="{{ idom_mount_uuid }}" class="{{ class }}"></div> <script type="module" crossorigin="anonymous"> import { mountViewToElement } from "{% static 'js/django-idom-client.js' %}"; const mountPoint = document.getElementById("{{ idom_mount_uuid }}"); diff --git a/src/django_idom/templatetags/idom.py b/src/django_idom/templatetags/idom.py index d294d2da..ba44878c 100644 --- a/src/django_idom/templatetags/idom.py +++ b/src/django_idom/templatetags/idom.py @@ -16,13 +16,15 @@ register = template.Library() -@register.inclusion_tag("idom/view.html") +@register.inclusion_tag("idom/component.html") def idom_component(_component_id_, **kwargs): _register_component(_component_id_) + class_ = kwargs.pop("class", "") json_kwargs = json.dumps(kwargs, separators=(",", ":")) return { + "class": class_, "idom_websocket_url": IDOM_WEBSOCKET_URL, "idom_web_modules_url": IDOM_WEB_MODULES_URL, "idom_mount_uuid": uuid4().hex, diff --git a/tests/test_app/templates/base.html b/tests/test_app/templates/base.html index 6677c1b5..1ad73c4a 100644 --- a/tests/test_app/templates/base.html +++ b/tests/test_app/templates/base.html @@ -15,9 +15,9 @@ <body> <h1>IDOM Test Page</h1> - <div>{% idom_component "test_app.components.HelloWorld" %}</div> - <div>{% idom_component "test_app.components.Button" %}</div> - <div>{% idom_component "test_app.components.ParametrizedComponent" x=123 y=456 %}</div> - <div>{% idom_component "test_app.components.SimpleBarChart" %}</div> + <div>{% idom_component "test_app.components.HelloWorld" class="hello-world" %}</div> + <div>{% idom_component "test_app.components.Button" class="button" %}</div> + <div>{% idom_component "test_app.components.ParametrizedComponent" class="parametarized-component" x=123 y=456 %}</div> + <div>{% idom_component "test_app.components.SimpleBarChart" class="simple-bar-chart" %}</div> </body> </html> From bc40e4ee0bc958737cc4cd1e106b0f2138f37ead Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Thu, 9 Sep 2021 01:36:31 -0700 Subject: [PATCH 07/38] add todo --- src/js/rollup.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/js/rollup.config.js b/src/js/rollup.config.js index 9eb08a1c..270a43b5 100644 --- a/src/js/rollup.config.js +++ b/src/js/rollup.config.js @@ -4,6 +4,7 @@ import replace from "rollup-plugin-replace"; const { PRODUCTION } = process.env; +// TODO: Look at this and see why it's borked export default { input: "src/index.js", output: { From 7eed382ee68f8044687564625a5213155f8f0815 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Thu, 9 Sep 2021 21:26:44 -0700 Subject: [PATCH 08/38] fix manifest.in errors --- MANIFEST.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index a43e500c..5b9e5fe2 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,2 @@ -recursive-include src/django_idom/static/ * -recursive-include src/django_idom/templates/ *.html +recursive-include src/django_idom/static * +recursive-include src/django_idom/templates *.html From 27812fc0be845c5523924d640c50b0562ed57153 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Thu, 9 Sep 2021 21:34:49 -0700 Subject: [PATCH 09/38] manually install peer dependencies --- setup.py | 7 +++++++ src/js/package.json | 6 ++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index adeb5937..d2432fe9 100644 --- a/setup.py +++ b/setup.py @@ -119,6 +119,13 @@ def run(self): npm = shutil.which("npm") # this is required on windows if npm is None: raise RuntimeError("NPM is not installed.") + + # Required on when using NPM >3 + log.info(f"> Installing rollup, react, and react-dom") + subprocess.run(f"{npm} install rollup".split(), cwd=js_dir, check=True) + subprocess.run(f"{npm} install react".split(), cwd=js_dir, check=True) + subprocess.run(f"{npm} install react-dom".split(), cwd=js_dir, check=True) + for args in (f"{npm} install", f"{npm} run build"): args_list = args.split() log.info(f"> {list2cmdline(args_list)}") diff --git a/src/js/package.json b/src/js/package.json index 43319d86..bea68d7a 100644 --- a/src/js/package.json +++ b/src/js/package.json @@ -12,12 +12,14 @@ }, "devDependencies": { "prettier": "^2.2.1", - "rollup": "^2.35.1", + "rollup": "^2.56.3", "rollup-plugin-commonjs": "^10.1.0", "rollup-plugin-node-resolve": "^5.2.0", "rollup-plugin-replace": "^2.2.0" }, "dependencies": { - "idom-client-react": "^0.33.0" + "idom-client-react": "^0.33.0", + "react": "^17.0.2", + "react-dom": "^17.0.2" } } From 37fa012c41061ef06380c5b4446da4062af50e96 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Thu, 9 Sep 2021 21:35:05 -0700 Subject: [PATCH 10/38] i don't know if I need to commit this --- src/js/package-lock.json | 414 +++------------------------------------ 1 file changed, 27 insertions(+), 387 deletions(-) diff --git a/src/js/package-lock.json b/src/js/package-lock.json index 6ff0f5ee..ba26a073 100644 --- a/src/js/package-lock.json +++ b/src/js/package-lock.json @@ -1,343 +1,8 @@ { "name": "django-idom-client", "version": "0.0.1", - "lockfileVersion": 2, + "lockfileVersion": 1, "requires": true, - "packages": { - "": { - "name": "django-idom-client", - "version": "0.0.1", - "dependencies": { - "idom-client-react": "^0.8.5" - }, - "devDependencies": { - "prettier": "^2.2.1", - "rollup": "^2.35.1", - "rollup-plugin-commonjs": "^10.1.0", - "rollup-plugin-node-resolve": "^5.2.0", - "rollup-plugin-replace": "^2.2.0" - } - }, - "node_modules/@types/estree": { - "version": "0.0.48", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.48.tgz", - "integrity": "sha512-LfZwXoGUDo0C3me81HXgkBg5CTQYb6xzEl+fNmbO4JdRiSKQ8A0GD1OBBvKAIsbCUgoyAty7m99GqqMQe784ew==", - "dev": true - }, - "node_modules/@types/node": { - "version": "15.12.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz", - "integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==", - "dev": true - }, - "node_modules/@types/resolve": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", - "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/builtin-modules": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", - "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", - "dev": true - }, - "node_modules/fast-json-patch": { - "version": "3.0.0-1", - "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.0.0-1.tgz", - "integrity": "sha512-6pdFb07cknxvPzCeLsFHStEy+MysPJPgZQ9LbQ/2O67unQF93SNqfdSqnPPl71YMHX+AD8gbl7iuoGFzHEdDuw==" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/htm": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/htm/-/htm-3.0.4.tgz", - "integrity": "sha512-VRdvxX3tmrXuT/Ovt59NMp/ORMFi4bceFMDjos1PV4E0mV+5votuID8R60egR9A4U8nLt238R/snlJGz3UYiTQ==" - }, - "node_modules/idom-client-react": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/idom-client-react/-/idom-client-react-0.8.5.tgz", - "integrity": "sha512-/S/J+BPGnQ4YrXWBD0mT0IqigDHrXglTX91qDyIjg6aoQwcprJ8ms9WFwdXcx0/QY85s08+/FP4FnF8lcqwx9w==", - "dependencies": { - "fast-json-patch": "^3.0.0-1", - "htm": "^3.0.3" - }, - "peerDependencies": { - "react": ">=16", - "react-dom": ">=16" - } - }, - "node_modules/is-core-module": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", - "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", - "dev": true - }, - "node_modules/is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dev": true, - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "peer": true - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "peer": true, - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "dev": true, - "dependencies": { - "sourcemap-codec": "^1.4.4" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/prettier": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.1.tgz", - "integrity": "sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "peer": true, - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, - "node_modules/react": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", - "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", - "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.19.1" - }, - "peerDependencies": { - "react": "^16.14.0" - } - }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "peer": true - }, - "node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/rollup": { - "version": "2.51.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.51.2.tgz", - "integrity": "sha512-ReV2eGEadA7hmXSzjxdDKs10neqH2QURf2RxJ6ayAlq93ugy6qIvXMmbc5cWMGCDh1h5T4thuWO1e2VNbMq8FA==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.1" - } - }, - "node_modules/rollup-plugin-commonjs": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz", - "integrity": "sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q==", - "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-commonjs.", - "dev": true, - "dependencies": { - "estree-walker": "^0.6.1", - "is-reference": "^1.1.2", - "magic-string": "^0.25.2", - "resolve": "^1.11.0", - "rollup-pluginutils": "^2.8.1" - }, - "peerDependencies": { - "rollup": ">=1.12.0" - } - }, - "node_modules/rollup-plugin-node-resolve": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz", - "integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==", - "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-node-resolve.", - "dev": true, - "dependencies": { - "@types/resolve": "0.0.8", - "builtin-modules": "^3.1.0", - "is-module": "^1.0.0", - "resolve": "^1.11.1", - "rollup-pluginutils": "^2.8.1" - }, - "peerDependencies": { - "rollup": ">=1.11.0" - } - }, - "node_modules/rollup-plugin-replace": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-replace/-/rollup-plugin-replace-2.2.0.tgz", - "integrity": "sha512-/5bxtUPkDHyBJAKketb4NfaeZjL5yLZdeUihSfbF2PQMz+rSTEb8ARKoOl3UBT4m7/X+QOXJo3sLTcq+yMMYTA==", - "deprecated": "This module has moved and is now available at @rollup/plugin-replace. Please update your dependencies. This version is no longer maintained.", - "dev": true, - "dependencies": { - "magic-string": "^0.25.2", - "rollup-pluginutils": "^2.6.0" - } - }, - "node_modules/rollup-pluginutils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", - "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", - "dev": true, - "dependencies": { - "estree-walker": "^0.6.1" - } - }, - "node_modules/scheduler": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", - "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - } - }, "dependencies": { "@types/estree": { "version": "0.0.48", @@ -373,9 +38,9 @@ "dev": true }, "fast-json-patch": { - "version": "3.0.0-1", - "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.0.0-1.tgz", - "integrity": "sha512-6pdFb07cknxvPzCeLsFHStEy+MysPJPgZQ9LbQ/2O67unQF93SNqfdSqnPPl71YMHX+AD8gbl7iuoGFzHEdDuw==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.0.tgz", + "integrity": "sha512-IhpytlsVTRndz0hU5t0/MGzS/etxLlfrpG5V5M9mVbuj9TrJLWaMfsox9REM5rkuGX0T+5qjpe8XA1o0gZ42nA==" }, "fsevents": { "version": "2.3.2", @@ -400,14 +65,14 @@ } }, "htm": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/htm/-/htm-3.0.4.tgz", - "integrity": "sha512-VRdvxX3tmrXuT/Ovt59NMp/ORMFi4bceFMDjos1PV4E0mV+5votuID8R60egR9A4U8nLt238R/snlJGz3UYiTQ==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/htm/-/htm-3.1.0.tgz", + "integrity": "sha512-L0s3Sid5r6YwrEvkig14SK3Emmc+kIjlfLhEGn2Vy3bk21JyDEes4MoDsbJk6luaPp8bugErnxPz86ZuAw6e5Q==" }, "idom-client-react": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/idom-client-react/-/idom-client-react-0.8.5.tgz", - "integrity": "sha512-/S/J+BPGnQ4YrXWBD0mT0IqigDHrXglTX91qDyIjg6aoQwcprJ8ms9WFwdXcx0/QY85s08+/FP4FnF8lcqwx9w==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/idom-client-react/-/idom-client-react-0.33.2.tgz", + "integrity": "sha512-B0dIWTYtmSwWUkA7g9/8Stz0Otar/pSaARdxxaPVL8QGvjxaCEnP0M1jklep2SXlbO1U/mXRYIYWgGE2sSlTLg==", "requires": { "fast-json-patch": "^3.0.0-1", "htm": "^3.0.3" @@ -440,14 +105,12 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "peer": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "peer": true, "requires": { "js-tokens": "^3.0.0 || ^4.0.0" } @@ -464,8 +127,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "peer": true + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "path-parse": { "version": "1.0.7", @@ -479,46 +141,25 @@ "integrity": "sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA==", "dev": true }, - "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "peer": true, - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, "react": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", - "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", - "peer": true, + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", "requires": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" + "object-assign": "^4.1.1" } }, "react-dom": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", - "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", - "peer": true, + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.19.1" + "scheduler": "^0.20.2" } }, - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "peer": true - }, "resolve": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", @@ -530,12 +171,12 @@ } }, "rollup": { - "version": "2.51.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.51.2.tgz", - "integrity": "sha512-ReV2eGEadA7hmXSzjxdDKs10neqH2QURf2RxJ6ayAlq93ugy6qIvXMmbc5cWMGCDh1h5T4thuWO1e2VNbMq8FA==", + "version": "2.56.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.56.3.tgz", + "integrity": "sha512-Au92NuznFklgQCUcV96iXlxUbHuB1vQMaH76DHl5M11TotjOHwqk9CwcrT78+Tnv4FN9uTBxq6p4EJoYkpyekg==", "dev": true, "requires": { - "fsevents": "~2.3.1" + "fsevents": "~2.3.2" } }, "rollup-plugin-commonjs": { @@ -584,10 +225,9 @@ } }, "scheduler": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", - "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", - "peer": true, + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" From bf8a9bf0d5d6a06a5ed61db9555e269dea41c9ac Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Thu, 9 Sep 2021 21:37:14 -0700 Subject: [PATCH 11/38] fix formatting --- setup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d2432fe9..1d129dcf 100644 --- a/setup.py +++ b/setup.py @@ -124,7 +124,9 @@ def run(self): log.info(f"> Installing rollup, react, and react-dom") subprocess.run(f"{npm} install rollup".split(), cwd=js_dir, check=True) subprocess.run(f"{npm} install react".split(), cwd=js_dir, check=True) - subprocess.run(f"{npm} install react-dom".split(), cwd=js_dir, check=True) + subprocess.run( + f"{npm} install react-dom".split(), cwd=js_dir, check=True + ) for args in (f"{npm} install", f"{npm} run build"): args_list = args.split() From c3ee55eb8b7b360c5bbc0ac88a8bb0431c6b666b Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Thu, 9 Sep 2021 21:37:35 -0700 Subject: [PATCH 12/38] fix ugly comment --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 1d129dcf..45325ddb 100644 --- a/setup.py +++ b/setup.py @@ -120,7 +120,7 @@ def run(self): if npm is None: raise RuntimeError("NPM is not installed.") - # Required on when using NPM >3 + # Required when using NPM >3 log.info(f"> Installing rollup, react, and react-dom") subprocess.run(f"{npm} install rollup".split(), cwd=js_dir, check=True) subprocess.run(f"{npm} install react".split(), cwd=js_dir, check=True) From 28445109363db4b96d9f2c5e0a0b7946543fd248 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Thu, 9 Sep 2021 21:42:45 -0700 Subject: [PATCH 13/38] remove todo --- src/js/rollup.config.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/js/rollup.config.js b/src/js/rollup.config.js index 270a43b5..9eb08a1c 100644 --- a/src/js/rollup.config.js +++ b/src/js/rollup.config.js @@ -4,7 +4,6 @@ import replace from "rollup-plugin-replace"; const { PRODUCTION } = process.env; -// TODO: Look at this and see why it's borked export default { input: "src/index.js", output: { From 722c1d39dc6c04130dbbade6932a697f920bffec Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sat, 11 Sep 2021 01:08:19 -0700 Subject: [PATCH 14/38] remove unneeded lines from setup.py --- setup.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/setup.py b/setup.py index 45325ddb..709083bb 100644 --- a/setup.py +++ b/setup.py @@ -120,14 +120,6 @@ def run(self): if npm is None: raise RuntimeError("NPM is not installed.") - # Required when using NPM >3 - log.info(f"> Installing rollup, react, and react-dom") - subprocess.run(f"{npm} install rollup".split(), cwd=js_dir, check=True) - subprocess.run(f"{npm} install react".split(), cwd=js_dir, check=True) - subprocess.run( - f"{npm} install react-dom".split(), cwd=js_dir, check=True - ) - for args in (f"{npm} install", f"{npm} run build"): args_list = args.split() log.info(f"> {list2cmdline(args_list)}") From 3cd92a1090860bb98d0804092184aabb4acad933 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sat, 11 Sep 2021 01:09:08 -0700 Subject: [PATCH 15/38] fix manifest warning --- MANIFEST.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index 5b9e5fe2..27473a8d 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,2 @@ -recursive-include src/django_idom/static * +recursive-include src/django_idom/static *.js recursive-include src/django_idom/templates *.html From 8774ad829db4afec037ab38681aa0fd795f4821b Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sat, 11 Sep 2021 01:10:57 -0700 Subject: [PATCH 16/38] remove unneeded delta --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index 709083bb..adeb5937 100644 --- a/setup.py +++ b/setup.py @@ -119,7 +119,6 @@ def run(self): npm = shutil.which("npm") # this is required on windows if npm is None: raise RuntimeError("NPM is not installed.") - for args in (f"{npm} install", f"{npm} run build"): args_list = args.split() log.info(f"> {list2cmdline(args_list)}") From 28ba23cf4501933a7161f323ae5bf8ba8772f225 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sat, 11 Sep 2021 01:16:51 -0700 Subject: [PATCH 17/38] Revert "fix manifest warning" This reverts commit 3cd92a1090860bb98d0804092184aabb4acad933. --- MANIFEST.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index 27473a8d..5b9e5fe2 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,2 @@ -recursive-include src/django_idom/static *.js +recursive-include src/django_idom/static * recursive-include src/django_idom/templates *.html From 3e4916bf6ab308105fec6215f6796eeb25ee0698 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 12 Sep 2021 21:38:07 -0700 Subject: [PATCH 18/38] increase test timeout (#15) --- tests/test_app/tests.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_app/tests.py b/tests/test_app/tests.py index 5520e7f4..1b94fe47 100644 --- a/tests/test_app/tests.py +++ b/tests/test_app/tests.py @@ -15,10 +15,10 @@ def setUp(self): def tearDown(self) -> None: self.driver.quit() - def wait(self, timeout=5): + def wait(self, timeout=10): return WebDriverWait(self.driver, timeout) - def wait_until(self, condition, timeout=5): + def wait_until(self, condition, timeout=10): return self.wait(timeout).until(lambda driver: condition()) def test_hello_world(self): @@ -37,7 +37,7 @@ def test_parametrized_component(self): self.assertEqual(element.get_attribute("data-value"), "579") def test_component_from_web_module(self): - self.wait(10).until( + self.wait(20).until( expected_conditions.visibility_of_element_located( (By.CLASS_NAME, "VictoryContainer") ) From 71968eef50b3f456bdf3bf6427b999a7883352d3 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 12 Sep 2021 21:38:44 -0700 Subject: [PATCH 19/38] fix websocket example in readme (#16) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 77e8dee4..aa57be42 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ import os from django.core.asgi import get_asgi_application -from django_idom import IDOM_WEB_MODULES_PATH +from django_idom import IDOM_WEBSOCKET_PATH os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_app.settings") @@ -82,7 +82,7 @@ application = ProtocolTypeRouter( "http": http_asgi_app, "websocket": URLRouter( # add a path for IDOM's websocket - [IDOM_WEB_MODULES_PATH] + [IDOM_WEBSOCKET_PATH] ), } ) From 9336098f17374ce50f24e05c06b53169fe878e84 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 1 Nov 2021 12:22:27 -0700 Subject: [PATCH 20/38] Advanced Websocket Features (#17) * propogate websocket down * update tests * add websocket login * add admin view to test app * fix styling error * more styling * last styling error i swear * fix spelling error * remove unneeded sys import check * reconnecting WS (broken) * prevent duplicate component registration fix #5 * allow any host to access this test app * cache -> lru_cache * py 3.7 compartibility * memory efficient way of preventing reregistration * Limit developer control the websocket * fix readme filename (idom.py -> components,py) * format readme * simplify render example * fix settings anchor link * add IDOM_WS_RECONNECT to readme * add session middleware * change disconnect to close * add view ID to WebSocketConnection * change tab width to 2 * prettier format * IDOM_WS_RECONNECT -> IDOM_WS_RECONNECT_TIMEOUT * format base.html * WebSocket -> Websocket * Awaitable[None] * add disconnect within websocketconnection * bump idom version * revert component registration check * use django-idom version for svg * add EOF newlines * cleanup WebsocketConnection * remove useless init from websocket consumer * IDOM_WS_MAX_RECONNECT_DELAY * self.view_id -> view_id --- README.md | 33 ++++++++--------- src/django_idom/config.py | 1 + src/django_idom/paths.py | 6 ++-- src/django_idom/templates/idom/component.html | 1 + src/django_idom/templatetags/idom.py | 2 ++ src/django_idom/websocket_consumer.py | 36 +++++++++++++++---- src/js/package-lock.json | 6 ++-- src/js/package.json | 2 +- src/js/src/index.js | 10 ++++-- tests/test_app/asgi.py | 6 +++- tests/test_app/components.py | 8 ++--- tests/test_app/settings.py | 2 +- tests/test_app/templates/base.html | 35 +++++++++--------- tests/test_app/urls.py | 7 +++- tests/test_app/views.py | 5 ++- 15 files changed, 98 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index aa57be42..928c33a9 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ <img alt="Tests" src="https://github.com/idom-team/django-idom/workflows/Test/badge.svg?event=push" /> </a> <a href="https://pypi.python.org/pypi/django-idom"> - <img alt="Version Info" src="https://img.shields.io/pypi/v/idom.svg"/> + <img alt="Version Info" src="https://img.shields.io/pypi/v/django-idom.svg"/> </a> <a href="https://github.com/idom-team/django-idom/blob/main/LICENSE"> <img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-purple.svg"> @@ -20,14 +20,13 @@ interfaces in pure Python. <a target="_blank" href="https://mybinder.org/v2/gh/idom-team/idom-jupyter/main?filepath=notebooks%2Fintroduction.ipynb"> - <img +<img alt="Binder" valign="bottom" height="21px" src="https://mybinder.org/badge_logo.svg"/> </a> - # Install Django IDOM ```bash @@ -46,7 +45,7 @@ your_project/ ├── urls.py └── example_app/ ├── __init__.py - ├── idom.py + ├── components.py ├── templates/ │ └── your-template.html └── urls.py @@ -60,7 +59,7 @@ order to create ASGI websockets within Django. Then, we will add a path for IDOM websocket consumer using `IDOM_WEBSOCKET_PATH`. _Note: If you wish to change the route where this websocket is served from, see the -available [settings](#settings.py)._ +available [settings](#settingspy)._ ```python @@ -75,14 +74,14 @@ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_app.settings") # Fetch ASGI application before importing dependencies that require ORM models. http_asgi_app = get_asgi_application() +from channels.auth import AuthMiddlewareStack from channels.routing import ProtocolTypeRouter, URLRouter application = ProtocolTypeRouter( { "http": http_asgi_app, - "websocket": URLRouter( - # add a path for IDOM's websocket - [IDOM_WEBSOCKET_PATH] + "websocket": SessionMiddlewareStack( + AuthMiddlewareStack(URLRouter([IDOM_WEBSOCKET_PATH])) ), } ) @@ -111,6 +110,10 @@ IDOM_BASE_URL: str = "_idom/" # Only applies when not using Django's caching framework (see below). IDOM_WEB_MODULE_LRU_CACHE_SIZE: int | None = None +# Maximum seconds between two reconnection attempts that would cause the client give up. +# 0 will disable reconnection. +IDOM_WS_MAX_RECONNECT_DELAY: int = 604800 + # Configure a cache for loading JS files CACHES = { # Configure a cache for loading JS files for IDOM @@ -147,8 +150,8 @@ ultimately be referenced by name in `your-template.html`. `your-template.html`. import idom @idom.component -def Hello(greeting_recipient): # component names are camelcase by convention - return Header(f"Hello {greeting_recipient}!") +def Hello(websocket, greeting_recipient): # component names are camelcase by convention + return idom.html.header(f"Hello {greeting_recipient}!") ``` ## `example_app/templates/your-template.html` @@ -165,8 +168,6 @@ idom_component module_name.ComponentName param_1="something" param_2="something- In context this will look a bit like the following... ```jinja -<!-- don't forget your load statements --> -{% load static %} {% load idom %} <!DOCTYPE html> @@ -184,15 +185,11 @@ You can then serve `your-template.html` from a view just [like any other](https://docs.djangoproject.com/en/3.2/intro/tutorial03/#write-views-that-actually-do-something). ```python -from django.http import HttpResponse -from django.template import loader - +from django.shortcuts import render def your_view(request): context = {} - return HttpResponse( - loader.get_template("your-template.html").render(context, request) - ) + return render(request, "your-template.html", context) ``` ## `example_app/urls.py` diff --git a/src/django_idom/config.py b/src/django_idom/config.py index 9b2d9f0a..1d527a9e 100644 --- a/src/django_idom/config.py +++ b/src/django_idom/config.py @@ -10,6 +10,7 @@ IDOM_BASE_URL = getattr(settings, "IDOM_BASE_URL", "_idom/") IDOM_WEBSOCKET_URL = IDOM_BASE_URL + "websocket/" IDOM_WEB_MODULES_URL = IDOM_BASE_URL + "web_module/" +IDOM_WS_MAX_RECONNECT_DELAY = getattr(settings, "IDOM_WS_MAX_RECONNECT_DELAY", 604800) _CACHES = getattr(settings, "CACHES", {}) if _CACHES: diff --git a/src/django_idom/paths.py b/src/django_idom/paths.py index 62a346e1..98170740 100644 --- a/src/django_idom/paths.py +++ b/src/django_idom/paths.py @@ -2,13 +2,13 @@ from . import views from .config import IDOM_WEB_MODULES_URL, IDOM_WEBSOCKET_URL -from .websocket_consumer import IdomAsyncWebSocketConsumer +from .websocket_consumer import IdomAsyncWebsocketConsumer IDOM_WEBSOCKET_PATH = path( - IDOM_WEBSOCKET_URL + "<view_id>/", IdomAsyncWebSocketConsumer.as_asgi() + IDOM_WEBSOCKET_URL + "<view_id>/", IdomAsyncWebsocketConsumer.as_asgi() ) -"""A URL resolver for :class:`IdomAsyncWebSocketConsumer` +"""A URL resolver for :class:`IdomAsyncWebsocketConsumer` While this is relatively uncommon in most Django apps, because the URL of the websocket must be defined by the setting ``IDOM_WEBSOCKET_URL``. There's no need diff --git a/src/django_idom/templates/idom/component.html b/src/django_idom/templates/idom/component.html index 84ec6963..65ad0c45 100644 --- a/src/django_idom/templates/idom/component.html +++ b/src/django_idom/templates/idom/component.html @@ -7,6 +7,7 @@ mountPoint, "{{ idom_websocket_url }}", "{{ idom_web_modules_url }}", + "{{ idom_ws_max_reconnect_delay }}", "{{ idom_component_id }}", "{{ idom_component_params }}" ); diff --git a/src/django_idom/templatetags/idom.py b/src/django_idom/templatetags/idom.py index ba44878c..cd83ebec 100644 --- a/src/django_idom/templatetags/idom.py +++ b/src/django_idom/templatetags/idom.py @@ -10,6 +10,7 @@ IDOM_REGISTERED_COMPONENTS, IDOM_WEB_MODULES_URL, IDOM_WEBSOCKET_URL, + IDOM_WS_MAX_RECONNECT_DELAY, ) @@ -27,6 +28,7 @@ def idom_component(_component_id_, **kwargs): "class": class_, "idom_websocket_url": IDOM_WEBSOCKET_URL, "idom_web_modules_url": IDOM_WEB_MODULES_URL, + "idom_ws_max_reconnect_delay": IDOM_WS_MAX_RECONNECT_DELAY, "idom_mount_uuid": uuid4().hex, "idom_component_id": _component_id_, "idom_component_params": urlencode({"kwargs": json_kwargs}), diff --git a/src/django_idom/websocket_consumer.py b/src/django_idom/websocket_consumer.py index 31f1aa38..349a8366 100644 --- a/src/django_idom/websocket_consumer.py +++ b/src/django_idom/websocket_consumer.py @@ -2,9 +2,12 @@ import asyncio import json import logging -from typing import Any +from dataclasses import dataclass +from typing import Any, Awaitable, Callable, Optional from urllib.parse import parse_qsl +from channels.auth import login +from channels.db import database_sync_to_async as convert_to_async from channels.generic.websocket import AsyncJsonWebsocketConsumer from idom.core.dispatcher import dispatch_single_view from idom.core.layout import Layout, LayoutEvent @@ -15,14 +18,30 @@ _logger = logging.getLogger(__name__) -class IdomAsyncWebSocketConsumer(AsyncJsonWebsocketConsumer): - """Communicates with the browser to perform actions on-demand.""" +@dataclass +class WebsocketConnection: + scope: dict + close: Callable[[Optional[int]], Awaitable[None]] + disconnect: Callable[[int], Awaitable[None]] + view_id: str + - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) +class IdomAsyncWebsocketConsumer(AsyncJsonWebsocketConsumer): + """Communicates with the browser to perform actions on-demand.""" async def connect(self) -> None: await super().connect() + + user = self.scope.get("user") + if user and user.is_authenticated: + try: + await login(self.scope, user) + await convert_to_async(self.scope["session"].save)() + except Exception: + _logger.exception("IDOM websocket authentication has failed!") + elif user is None: + _logger.warning("IDOM websocket is missing AuthMiddlewareStack!") + self._idom_dispatcher_future = asyncio.ensure_future(self._run_dispatch_loop()) async def disconnect(self, code: int) -> None: @@ -41,14 +60,17 @@ async def _run_dispatch_loop(self): try: component_constructor = IDOM_REGISTERED_COMPONENTS[view_id] except KeyError: - _logger.warning(f"Uknown IDOM view ID {view_id!r}") + _logger.warning(f"Unknown IDOM view ID {view_id!r}") return query_dict = dict(parse_qsl(self.scope["query_string"].decode())) component_kwargs = json.loads(query_dict.get("kwargs", "{}")) + # Provide developer access to parts of this websocket + socket = WebsocketConnection(self.scope, self.close, self.disconnect, view_id) + try: - component_instance = component_constructor(**component_kwargs) + component_instance = component_constructor(socket, **component_kwargs) except Exception: _logger.exception( f"Failed to construct component {component_constructor} " diff --git a/src/js/package-lock.json b/src/js/package-lock.json index ba26a073..6869fe24 100644 --- a/src/js/package-lock.json +++ b/src/js/package-lock.json @@ -70,9 +70,9 @@ "integrity": "sha512-L0s3Sid5r6YwrEvkig14SK3Emmc+kIjlfLhEGn2Vy3bk21JyDEes4MoDsbJk6luaPp8bugErnxPz86ZuAw6e5Q==" }, "idom-client-react": { - "version": "0.33.2", - "resolved": "https://registry.npmjs.org/idom-client-react/-/idom-client-react-0.33.2.tgz", - "integrity": "sha512-B0dIWTYtmSwWUkA7g9/8Stz0Otar/pSaARdxxaPVL8QGvjxaCEnP0M1jklep2SXlbO1U/mXRYIYWgGE2sSlTLg==", + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/idom-client-react/-/idom-client-react-0.33.3.tgz", + "integrity": "sha512-CTqnSzhAVz20IHDexECtCdLuvE2diUIi63kog45sNiJdu5ig+cUKjT4zuA1YHGchf4jJVgsQKPsd1BB3Bx6cew==", "requires": { "fast-json-patch": "^3.0.0-1", "htm": "^3.0.3" diff --git a/src/js/package.json b/src/js/package.json index bea68d7a..ea04bf2d 100644 --- a/src/js/package.json +++ b/src/js/package.json @@ -18,7 +18,7 @@ "rollup-plugin-replace": "^2.2.0" }, "dependencies": { - "idom-client-react": "^0.33.0", + "idom-client-react": "^0.33.3", "react": "^17.0.2", "react-dom": "^17.0.2" } diff --git a/src/js/src/index.js b/src/js/src/index.js index bddf2a55..8f17c0d4 100644 --- a/src/js/src/index.js +++ b/src/js/src/index.js @@ -14,18 +14,24 @@ export function mountViewToElement( mountPoint, idomWebsocketUrl, idomWebModulesUrl, + maxReconnectTimeout, viewId, queryParams ) { const fullWebsocketUrl = WS_ENDPOINT_URL + idomWebsocketUrl + viewId + "/?" + queryParams; - const fullWebModulesUrl = LOCATION.origin + "/" + idomWebModulesUrl + const fullWebModulesUrl = LOCATION.origin + "/" + idomWebModulesUrl; const loadImportSource = (source, sourceType) => { return import( sourceType == "NAME" ? `${fullWebModulesUrl}${source}` : source ); }; - mountLayoutWithWebSocket(mountPoint, fullWebsocketUrl, loadImportSource); + mountLayoutWithWebSocket( + mountPoint, + fullWebsocketUrl, + loadImportSource, + maxReconnectTimeout + ); } diff --git a/tests/test_app/asgi.py b/tests/test_app/asgi.py index dcb8112c..2b711cc1 100644 --- a/tests/test_app/asgi.py +++ b/tests/test_app/asgi.py @@ -19,12 +19,16 @@ # Fetch ASGI application before importing dependencies that require ORM models. http_asgi_app = get_asgi_application() +from channels.auth import AuthMiddlewareStack # noqa: E402 from channels.routing import ProtocolTypeRouter, URLRouter # noqa: E402 +from channels.sessions import SessionMiddlewareStack # noqa: E402 application = ProtocolTypeRouter( { "http": http_asgi_app, - "websocket": URLRouter([IDOM_WEBSOCKET_PATH]), + "websocket": SessionMiddlewareStack( + AuthMiddlewareStack(URLRouter([IDOM_WEBSOCKET_PATH])) + ), } ) diff --git a/tests/test_app/components.py b/tests/test_app/components.py index f242b9f1..d3452efb 100644 --- a/tests/test_app/components.py +++ b/tests/test_app/components.py @@ -2,12 +2,12 @@ @idom.component -def HelloWorld(): +def HelloWorld(websocket): return idom.html.h1({"id": "hello-world"}, "Hello World!") @idom.component -def Button(): +def Button(websocket): count, set_count = idom.hooks.use_state(0) return idom.html.div( idom.html.button( @@ -22,7 +22,7 @@ def Button(): @idom.component -def ParametrizedComponent(x, y): +def ParametrizedComponent(websocket, x, y): total = x + y return idom.html.h1({"id": "parametrized-component", "data-value": total}, total) @@ -32,5 +32,5 @@ def ParametrizedComponent(x, y): @idom.component -def SimpleBarChart(): +def SimpleBarChart(websocket): return VictoryBar() diff --git a/tests/test_app/settings.py b/tests/test_app/settings.py index ac7d6ab9..29eadffa 100644 --- a/tests/test_app/settings.py +++ b/tests/test_app/settings.py @@ -26,7 +26,7 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ["*"] # Application definition INSTALLED_APPS = [ diff --git a/tests/test_app/templates/base.html b/tests/test_app/templates/base.html index 1ad73c4a..5b2311d2 100644 --- a/tests/test_app/templates/base.html +++ b/tests/test_app/templates/base.html @@ -1,23 +1,22 @@ {% load static %} {% load idom %} <!DOCTYPE html> <html lang="en"> - <head> - <meta charset="UTF-8" /> - <meta http-equiv="X-UA-Compatible" content="IE=edge" /> - <meta name="viewport" content="width=device-width, initial-scale=1.0" /> - <link - rel="shortcut icon" - type="image/png" - href="{% static 'favicon.ico' %}" - /> - <title>IDOM - - -

IDOM Test Page

-
{% idom_component "test_app.components.HelloWorld" class="hello-world" %}
-
{% idom_component "test_app.components.Button" class="button" %}
-
{% idom_component "test_app.components.ParametrizedComponent" class="parametarized-component" x=123 y=456 %}
-
{% idom_component "test_app.components.SimpleBarChart" class="simple-bar-chart" %}
- + + + + + + IDOM + + + +

IDOM Test Page

+
{% idom_component "test_app.components.HelloWorld" class="hello-world" %}
+
{% idom_component "test_app.components.Button" class="button" %}
+
{% idom_component "test_app.components.ParametrizedComponent" class="parametarized-component" x=123 y=456 %} +
+
{% idom_component "test_app.components.SimpleBarChart" class="simple-bar-chart" %}
+ + diff --git a/tests/test_app/urls.py b/tests/test_app/urls.py index cd4f3da0..1ea0c99b 100644 --- a/tests/test_app/urls.py +++ b/tests/test_app/urls.py @@ -17,6 +17,7 @@ 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ +from django.contrib import admin from django.urls import path from django_idom import IDOM_WEB_MODULES_PATH @@ -24,4 +25,8 @@ from .views import base_template -urlpatterns = [path("", base_template), IDOM_WEB_MODULES_PATH] +urlpatterns = [ + path("", base_template), + IDOM_WEB_MODULES_PATH, + path("admin/", admin.site.urls), +] diff --git a/tests/test_app/views.py b/tests/test_app/views.py index 248235a7..11874908 100644 --- a/tests/test_app/views.py +++ b/tests/test_app/views.py @@ -1,7 +1,6 @@ -from django.http import HttpResponse -from django.template import loader +from django.shortcuts import render def base_template(request): context = {} - return HttpResponse(loader.get_template("base.html").render(context, request)) + return render(request, "base.html", context) From 0cd049ea33de815f2ae1f0b36bd91ae0f7ee59a6 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Tue, 2 Nov 2021 00:46:19 -0700 Subject: [PATCH 21/38] Auto populate IDOM component registry (#24) * Auto populate IDOM registered components * avoid multiple component registrations * add component regex tests --- src/django_idom/apps.py | 11 +++ src/django_idom/templatetags/idom.py | 27 +----- src/django_idom/utils.py | 123 ++++++++++++++++++++++++ tests/test_app/tests.py | 53 ---------- tests/test_app/tests/__init__.py | 1 + tests/test_app/tests/test_components.py | 57 +++++++++++ tests/test_app/tests/test_regex.py | 29 ++++++ 7 files changed, 222 insertions(+), 79 deletions(-) create mode 100644 src/django_idom/apps.py create mode 100644 src/django_idom/utils.py delete mode 100644 tests/test_app/tests.py create mode 100644 tests/test_app/tests/__init__.py create mode 100644 tests/test_app/tests/test_components.py create mode 100644 tests/test_app/tests/test_regex.py diff --git a/src/django_idom/apps.py b/src/django_idom/apps.py new file mode 100644 index 00000000..6a963664 --- /dev/null +++ b/src/django_idom/apps.py @@ -0,0 +1,11 @@ +from django.apps import AppConfig + +from django_idom.utils import ComponentPreloader + + +class DjangoIdomConfig(AppConfig): + name = "django_idom" + + def ready(self): + # Populate the IDOM component registry when Django is ready + ComponentPreloader().register_all() diff --git a/src/django_idom/templatetags/idom.py b/src/django_idom/templatetags/idom.py index cd83ebec..d6692b5b 100644 --- a/src/django_idom/templatetags/idom.py +++ b/src/django_idom/templatetags/idom.py @@ -1,17 +1,15 @@ import json -import sys -from importlib import import_module from urllib.parse import urlencode from uuid import uuid4 from django import template from django_idom.config import ( - IDOM_REGISTERED_COMPONENTS, IDOM_WEB_MODULES_URL, IDOM_WEBSOCKET_URL, IDOM_WS_MAX_RECONNECT_DELAY, ) +from django_idom.utils import _register_component register = template.Library() @@ -33,26 +31,3 @@ def idom_component(_component_id_, **kwargs): "idom_component_id": _component_id_, "idom_component_params": urlencode({"kwargs": json_kwargs}), } - - -def _register_component(full_component_name: str) -> None: - module_name, component_name = full_component_name.rsplit(".", 1) - - if module_name in sys.modules: - module = sys.modules[module_name] - else: - try: - module = import_module(module_name) - except ImportError as error: - raise RuntimeError( - f"Failed to import {module_name!r} while loading {component_name!r}" - ) from error - - try: - component = getattr(module, component_name) - except AttributeError as error: - raise RuntimeError( - f"Module {module_name!r} has no component named {component_name!r}" - ) from error - - IDOM_REGISTERED_COMPONENTS[full_component_name] = component diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py new file mode 100644 index 00000000..178995c9 --- /dev/null +++ b/src/django_idom/utils.py @@ -0,0 +1,123 @@ +import logging +import os +import re +from fnmatch import fnmatch +from importlib import import_module +from typing import Set + +from django.template import engines +from django.utils.encoding import smart_str + +from django_idom.config import IDOM_REGISTERED_COMPONENTS + + +COMPONENT_REGEX = re.compile(r"{% *idom_component ((\"[^\"']*\")|('[^\"']*')).*?%}") +_logger = logging.getLogger(__name__) + + +def _register_component(full_component_name: str) -> None: + if full_component_name in IDOM_REGISTERED_COMPONENTS: + return + + module_name, component_name = full_component_name.rsplit(".", 1) + + try: + module = import_module(module_name) + except ImportError as error: + raise RuntimeError( + f"Failed to import {module_name!r} while loading {component_name!r}" + ) from error + + try: + component = getattr(module, component_name) + except AttributeError as error: + raise RuntimeError( + f"Module {module_name!r} has no component named {component_name!r}" + ) from error + + IDOM_REGISTERED_COMPONENTS[full_component_name] = component + + +class ComponentPreloader: + def register_all(self): + """Registers all IDOM components found within Django templates.""" + # Get all template folder paths + paths = self._get_paths() + # Get all HTML template files + templates = self._get_templates(paths) + # Get all components + components = self._get_components(templates) + # Register all components + self._register_components(components) + + def _get_loaders(self): + """Obtains currently configured template loaders.""" + template_source_loaders = [] + for e in engines.all(): + if hasattr(e, "engine"): + template_source_loaders.extend( + e.engine.get_template_loaders(e.engine.loaders) + ) + loaders = [] + for loader in template_source_loaders: + if hasattr(loader, "loaders"): + loaders.extend(loader.loaders) + else: + loaders.append(loader) + return loaders + + def _get_paths(self) -> Set: + """Obtains a set of all template directories.""" + paths = set() + for loader in self._get_loaders(): + try: + module = import_module(loader.__module__) + get_template_sources = getattr(module, "get_template_sources", None) + if get_template_sources is None: + get_template_sources = loader.get_template_sources + paths.update(smart_str(origin) for origin in get_template_sources("")) + except (ImportError, AttributeError, TypeError): + pass + + return paths + + def _get_templates(self, paths: Set) -> Set: + """Obtains a set of all HTML template paths.""" + extensions = [".html"] + templates = set() + for path in paths: + for root, dirs, files in os.walk(path, followlinks=False): + templates.update( + os.path.join(root, name) + for name in files + if not name.startswith(".") + and any(fnmatch(name, "*%s" % glob) for glob in extensions) + ) + + return templates + + def _get_components(self, templates: Set) -> Set: + """Obtains a set of all IDOM components by parsing HTML templates.""" + components = set() + for template in templates: + try: + with open(template, "r", encoding="utf-8") as template_file: + match = COMPONENT_REGEX.findall(template_file.read()) + if not match: + continue + components.update( + [group[0].replace('"', "").replace("'", "") for group in match] + ) + except Exception: + pass + + return components + + def _register_components(self, components: Set) -> None: + """Registers all IDOM components in an iterable.""" + for component in components: + try: + _register_component(component) + _logger.info("IDOM has registered component %s", component) + except Exception: + _logger.warning("IDOM failed to register component %s", component) diff --git a/tests/test_app/tests.py b/tests/test_app/tests.py deleted file mode 100644 index 1b94fe47..00000000 --- a/tests/test_app/tests.py +++ /dev/null @@ -1,53 +0,0 @@ -import os - -from channels.testing import ChannelsLiveServerTestCase -from selenium import webdriver -from selenium.webdriver.common.by import By -from selenium.webdriver.support import expected_conditions -from selenium.webdriver.support.ui import WebDriverWait - - -class TestIdomCapabilities(ChannelsLiveServerTestCase): - def setUp(self): - self.driver = make_driver(5, 5) - self.driver.get(self.live_server_url) - - def tearDown(self) -> None: - self.driver.quit() - - def wait(self, timeout=10): - return WebDriverWait(self.driver, timeout) - - def wait_until(self, condition, timeout=10): - return self.wait(timeout).until(lambda driver: condition()) - - def test_hello_world(self): - self.driver.find_element_by_id("hello-world") - - def test_counter(self): - button = self.driver.find_element_by_id("counter-inc") - count = self.driver.find_element_by_id("counter-num") - - for i in range(5): - self.wait_until(lambda: count.get_attribute("data-count") == str(i)) - button.click() - - def test_parametrized_component(self): - element = self.driver.find_element_by_id("parametrized-component") - self.assertEqual(element.get_attribute("data-value"), "579") - - def test_component_from_web_module(self): - self.wait(20).until( - expected_conditions.visibility_of_element_located( - (By.CLASS_NAME, "VictoryContainer") - ) - ) - - -def make_driver(page_load_timeout, implicit_wait_timeout): - options = webdriver.ChromeOptions() - options.headless = bool(int(os.environ.get("SELENIUM_HEADLESS", 0))) - driver = webdriver.Chrome(options=options) - driver.set_page_load_timeout(page_load_timeout) - driver.implicitly_wait(implicit_wait_timeout) - return driver diff --git a/tests/test_app/tests/__init__.py b/tests/test_app/tests/__init__.py new file mode 100644 index 00000000..fff5a11e --- /dev/null +++ b/tests/test_app/tests/__init__.py @@ -0,0 +1 @@ +from . import * # noqa: F401, F403 diff --git a/tests/test_app/tests/test_components.py b/tests/test_app/tests/test_components.py new file mode 100644 index 00000000..cb10cca9 --- /dev/null +++ b/tests/test_app/tests/test_components.py @@ -0,0 +1,57 @@ +import os +import sys + +from channels.testing import ChannelsLiveServerTestCase +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.support import expected_conditions +from selenium.webdriver.support.ui import WebDriverWait + + +# These tests are broken on Windows due to Selenium +if sys.platform != "win32": + + class TestIdomCapabilities(ChannelsLiveServerTestCase): + def setUp(self): + self.driver = make_driver(5, 5) + self.driver.get(self.live_server_url) + + def tearDown(self) -> None: + self.driver.quit() + + def wait(self, timeout=10): + return WebDriverWait(self.driver, timeout) + + def wait_until(self, condition, timeout=10): + return self.wait(timeout).until(lambda driver: condition()) + + def test_hello_world(self): + self.driver.find_element_by_id("hello-world") + + def test_counter(self): + button = self.driver.find_element_by_id("counter-inc") + count = self.driver.find_element_by_id("counter-num") + + for i in range(5): + self.wait_until(lambda: count.get_attribute("data-count") == str(i)) + button.click() + + def test_parametrized_component(self): + element = self.driver.find_element_by_id("parametrized-component") + self.assertEqual(element.get_attribute("data-value"), "579") + + def test_component_from_web_module(self): + self.wait(20).until( + expected_conditions.visibility_of_element_located( + (By.CLASS_NAME, "VictoryContainer") + ) + ) + + +def make_driver(page_load_timeout, implicit_wait_timeout): + options = webdriver.ChromeOptions() + options.headless = bool(int(os.environ.get("SELENIUM_HEADLESS", 0))) + driver = webdriver.Chrome(options=options) + driver.set_page_load_timeout(page_load_timeout) + driver.implicitly_wait(implicit_wait_timeout) + return driver diff --git a/tests/test_app/tests/test_regex.py b/tests/test_app/tests/test_regex.py new file mode 100644 index 00000000..3e418f1d --- /dev/null +++ b/tests/test_app/tests/test_regex.py @@ -0,0 +1,29 @@ +from django.test import TestCase + +from django_idom.utils import COMPONENT_REGEX + + +class RegexTests(TestCase): + def test_component_regex(self): + for component in { + r'{%idom_component "my.component"%}', + r"{%idom_component 'my.component'%}", + r'{% idom_component "my.component" %}', + r"{% idom_component 'my.component' %}", + r'{% idom_component "my.component" class="my_thing" %}', + r'{% idom_component "my.component" class="my_thing" attr="attribute" %}', + }: + self.assertRegex(component, COMPONENT_REGEX) + + for fake_component in { + r'{% not_a_real_thing "my.component" %}', + r"{% idom_component my.component %}", + r"""{% idom_component 'my.component" %}""", + r'{ idom_component "my.component" }', + r'{{ idom_component "my.component" }}', + r"idom_component", + r"{%%}", + r" ", + r"", + }: + self.assertNotRegex(fake_component, COMPONENT_REGEX) From 6a9ecb12d2134d339f66790efe64f99f4a8da6b4 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Wed, 15 Dec 2021 13:19:38 -0800 Subject: [PATCH 22/38] Add "name" to WS and Web Module paths (#30) * Add "name" to WS and Web Module paths * fix styling error --- src/django_idom/paths.py | 8 ++++++-- src/django_idom/views.py | 1 - 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/django_idom/paths.py b/src/django_idom/paths.py index 98170740..184182c3 100644 --- a/src/django_idom/paths.py +++ b/src/django_idom/paths.py @@ -6,7 +6,9 @@ IDOM_WEBSOCKET_PATH = path( - IDOM_WEBSOCKET_URL + "/", IdomAsyncWebsocketConsumer.as_asgi() + IDOM_WEBSOCKET_URL + "/", + IdomAsyncWebsocketConsumer.as_asgi(), + name="idom_websocket", ) """A URL resolver for :class:`IdomAsyncWebsocketConsumer` @@ -17,7 +19,9 @@ IDOM_WEB_MODULES_PATH = path( - IDOM_WEB_MODULES_URL + "", views.web_modules_file + IDOM_WEB_MODULES_URL + "", + views.web_modules_file, + name="idom_web_modules", ) """A URL resolver for static web modules required by IDOM diff --git a/src/django_idom/views.py b/src/django_idom/views.py index 6ee19851..7dd9578a 100644 --- a/src/django_idom/views.py +++ b/src/django_idom/views.py @@ -27,7 +27,6 @@ async def web_modules_file(request: HttpRequest, file: str) -> HttpResponse: file_path = IDOM_WED_MODULES_DIR.current.joinpath(*file.split("/")) return HttpResponse(file_path.read_text(), content_type="text/javascript") - else: _web_module_cache = caches[IDOM_WEB_MODULE_CACHE] From ad5f38ce76f2ba9e684a5fe5aa7ffad73b398af9 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Wed, 12 Jan 2022 01:18:06 -0800 Subject: [PATCH 23/38] Bump idom to v34 --- requirements/pkg-deps.txt | 4 +- src/js/package-lock.json | 320 +++++++++++++++++++++++++++++++++++++- src/js/package.json | 2 +- 3 files changed, 319 insertions(+), 7 deletions(-) diff --git a/requirements/pkg-deps.txt b/requirements/pkg-deps.txt index dbbaf6b6..45cf27bc 100644 --- a/requirements/pkg-deps.txt +++ b/requirements/pkg-deps.txt @@ -1,2 +1,2 @@ -channels<4.0.0 # Django websocket features -idom >=0.33.0, <0.34.0 +channels <4.0.0 +idom >=0.34.0, <0.35.0 diff --git a/src/js/package-lock.json b/src/js/package-lock.json index 6869fe24..7e1364b4 100644 --- a/src/js/package-lock.json +++ b/src/js/package-lock.json @@ -1,8 +1,320 @@ { "name": "django-idom-client", "version": "0.0.1", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "django-idom-client", + "version": "0.0.1", + "dependencies": { + "idom-client-react": "^0.34.0", + "react": "^17.0.2", + "react-dom": "^17.0.2" + }, + "devDependencies": { + "prettier": "^2.2.1", + "rollup": "^2.56.3", + "rollup-plugin-commonjs": "^10.1.0", + "rollup-plugin-node-resolve": "^5.2.0", + "rollup-plugin-replace": "^2.2.0" + } + }, + "node_modules/@types/estree": { + "version": "0.0.48", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.48.tgz", + "integrity": "sha512-LfZwXoGUDo0C3me81HXgkBg5CTQYb6xzEl+fNmbO4JdRiSKQ8A0GD1OBBvKAIsbCUgoyAty7m99GqqMQe784ew==", + "dev": true + }, + "node_modules/@types/node": { + "version": "15.12.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz", + "integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==", + "dev": true + }, + "node_modules/@types/resolve": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", + "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/builtin-modules": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", + "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + }, + "node_modules/fast-json-patch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.0.tgz", + "integrity": "sha512-IhpytlsVTRndz0hU5t0/MGzS/etxLlfrpG5V5M9mVbuj9TrJLWaMfsox9REM5rkuGX0T+5qjpe8XA1o0gZ42nA==" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/htm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/htm/-/htm-3.1.0.tgz", + "integrity": "sha512-L0s3Sid5r6YwrEvkig14SK3Emmc+kIjlfLhEGn2Vy3bk21JyDEes4MoDsbJk6luaPp8bugErnxPz86ZuAw6e5Q==" + }, + "node_modules/idom-client-react": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/idom-client-react/-/idom-client-react-0.34.0.tgz", + "integrity": "sha512-pIK5eNwFSHKXg7ClpASWFVKyZDYxz59MSFpVaX/OqJFkrJaAxBuhKGXNTMXmuyWOL5Iyvb/ErwwDRxQRzMNkfQ==", + "dependencies": { + "fast-json-patch": "^3.0.0-1", + "htm": "^3.0.3" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, + "node_modules/is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, + "node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/magic-string": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", + "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "dev": true, + "dependencies": { + "sourcemap-codec": "^1.4.4" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/prettier": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.1.tgz", + "integrity": "sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/react": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + }, + "peerDependencies": { + "react": "17.0.2" + } + }, + "node_modules/resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "dependencies": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rollup": { + "version": "2.56.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.56.3.tgz", + "integrity": "sha512-Au92NuznFklgQCUcV96iXlxUbHuB1vQMaH76DHl5M11TotjOHwqk9CwcrT78+Tnv4FN9uTBxq6p4EJoYkpyekg==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-commonjs": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz", + "integrity": "sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q==", + "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-commonjs.", + "dev": true, + "dependencies": { + "estree-walker": "^0.6.1", + "is-reference": "^1.1.2", + "magic-string": "^0.25.2", + "resolve": "^1.11.0", + "rollup-pluginutils": "^2.8.1" + }, + "peerDependencies": { + "rollup": ">=1.12.0" + } + }, + "node_modules/rollup-plugin-node-resolve": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz", + "integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==", + "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-node-resolve.", + "dev": true, + "dependencies": { + "@types/resolve": "0.0.8", + "builtin-modules": "^3.1.0", + "is-module": "^1.0.0", + "resolve": "^1.11.1", + "rollup-pluginutils": "^2.8.1" + }, + "peerDependencies": { + "rollup": ">=1.11.0" + } + }, + "node_modules/rollup-plugin-replace": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-replace/-/rollup-plugin-replace-2.2.0.tgz", + "integrity": "sha512-/5bxtUPkDHyBJAKketb4NfaeZjL5yLZdeUihSfbF2PQMz+rSTEb8ARKoOl3UBT4m7/X+QOXJo3sLTcq+yMMYTA==", + "deprecated": "This module has moved and is now available at @rollup/plugin-replace. Please update your dependencies. This version is no longer maintained.", + "dev": true, + "dependencies": { + "magic-string": "^0.25.2", + "rollup-pluginutils": "^2.6.0" + } + }, + "node_modules/rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "dependencies": { + "estree-walker": "^0.6.1" + } + }, + "node_modules/scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + } + }, "dependencies": { "@types/estree": { "version": "0.0.48", @@ -70,9 +382,9 @@ "integrity": "sha512-L0s3Sid5r6YwrEvkig14SK3Emmc+kIjlfLhEGn2Vy3bk21JyDEes4MoDsbJk6luaPp8bugErnxPz86ZuAw6e5Q==" }, "idom-client-react": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/idom-client-react/-/idom-client-react-0.33.3.tgz", - "integrity": "sha512-CTqnSzhAVz20IHDexECtCdLuvE2diUIi63kog45sNiJdu5ig+cUKjT4zuA1YHGchf4jJVgsQKPsd1BB3Bx6cew==", + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/idom-client-react/-/idom-client-react-0.34.0.tgz", + "integrity": "sha512-pIK5eNwFSHKXg7ClpASWFVKyZDYxz59MSFpVaX/OqJFkrJaAxBuhKGXNTMXmuyWOL5Iyvb/ErwwDRxQRzMNkfQ==", "requires": { "fast-json-patch": "^3.0.0-1", "htm": "^3.0.3" diff --git a/src/js/package.json b/src/js/package.json index ea04bf2d..44e71680 100644 --- a/src/js/package.json +++ b/src/js/package.json @@ -18,7 +18,7 @@ "rollup-plugin-replace": "^2.2.0" }, "dependencies": { - "idom-client-react": "^0.33.3", + "idom-client-react": "^0.34.0", "react": "^17.0.2", "react-dom": "^17.0.2" } From 940fbe21a2a5492f69fd0ba822917e4f4625c582 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Wed, 12 Jan 2022 13:26:02 -0800 Subject: [PATCH 24/38] Fix antipattern with static folder name (#44) * Fix antipattern with static folder name --- .gitignore | 2 +- src/django_idom/templates/idom/component.html | 2 +- src/js/rollup.config.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 3b6e5455..2477a484 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # Django IDOM Build Artifacts -src/django_idom/static/js +src/django_idom/static/ # Django # logs diff --git a/src/django_idom/templates/idom/component.html b/src/django_idom/templates/idom/component.html index 65ad0c45..e471c6a9 100644 --- a/src/django_idom/templates/idom/component.html +++ b/src/django_idom/templates/idom/component.html @@ -1,7 +1,7 @@ {% load static %}