From 4d272fc767fb60370ea7bed276112cb1ace1097b Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sat, 16 Apr 2022 20:47:32 -0700 Subject: [PATCH 01/53] change required versions --- requirements/pkg-deps.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements/pkg-deps.txt b/requirements/pkg-deps.txt index 98683e1a..7b9f9420 100644 --- a/requirements/pkg-deps.txt +++ b/requirements/pkg-deps.txt @@ -1,3 +1,3 @@ -channels <4.0.0 -idom >=0.37.2, <0.38.0 -aiofile >=3.0, <4.0 +channels >=3.0.0 +idom >=0.38.0, <0.39.0 +aiofile >=3.0 From 2f4bc419e5aac7c73d54eb535b87bf2edd650350 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sat, 16 Apr 2022 20:49:45 -0700 Subject: [PATCH 02/53] bump version number --- src/django_idom/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/django_idom/__init__.py b/src/django_idom/__init__.py index eb1e19d8..cb2412c5 100644 --- a/src/django_idom/__init__.py +++ b/src/django_idom/__init__.py @@ -2,5 +2,5 @@ from .websocket.paths import IDOM_WEBSOCKET_PATH -__version__ = "0.0.5" +__version__ = "0.0.6" __all__ = ["IDOM_WEBSOCKET_PATH", "IdomWebsocket"] From fcb1f8c0441357f9fc3feb56b78967a4a0b8b04e Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sat, 16 Apr 2022 20:49:56 -0700 Subject: [PATCH 03/53] add changelog entry --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0eeb2f49..2acaa209 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,12 @@ Types of changes are to be listed in this order - Nothing (yet) +## [0.0.6] - 2022-04-16 + +### Changed + +- Bumped the minimum IDOM version to 0.38.0 + ## [0.0.5] - 2022-04-04 ### Changed @@ -81,6 +87,7 @@ Types of changes are to be listed in this order - Support for IDOM within the Django [unreleased]: https://github.com/idom-team/django-idom/compare/0.0.2...HEAD +[0.0.5]: https://github.com/idom-team/django-idom/compare/0.0.5...0.0.6 [0.0.5]: https://github.com/idom-team/django-idom/compare/0.0.4...0.0.5 [0.0.4]: https://github.com/idom-team/django-idom/compare/0.0.3...0.0.4 [0.0.3]: https://github.com/idom-team/django-idom/compare/0.0.2...0.0.3 From 98b795a3c38b767da799656b95f730a19f9aa1f3 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sat, 16 Apr 2022 20:55:54 -0700 Subject: [PATCH 04/53] use contextlib suppress --- src/django_idom/utils.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py index 178995c9..5ec13c11 100644 --- a/src/django_idom/utils.py +++ b/src/django_idom/utils.py @@ -70,15 +70,12 @@ def _get_paths(self) -> Set: """Obtains a set of all template directories.""" paths = set() for loader in self._get_loaders(): - try: + with contextlib.suppress(ImportError, AttributeError, TypeError): 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: @@ -100,7 +97,7 @@ 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 contextlib.suppress(Exception): with open(template, "r", encoding="utf-8") as template_file: match = COMPONENT_REGEX.findall(template_file.read()) if not match: @@ -108,9 +105,6 @@ def _get_components(self, templates: Set) -> Set: components.update( [group[0].replace('"', "").replace("'", "") for group in match] ) - except Exception: - pass - return components def _register_components(self, components: Set) -> None: From f03b0cb726da8414118e4eee8ac23fa35638f04e Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sat, 16 Apr 2022 20:56:12 -0700 Subject: [PATCH 05/53] use f-strings --- src/django_idom/utils.py | 3 ++- src/django_idom/websocket/paths.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py index 5ec13c11..faf5109c 100644 --- a/src/django_idom/utils.py +++ b/src/django_idom/utils.py @@ -1,3 +1,4 @@ +import contextlib import logging import os import re @@ -88,7 +89,7 @@ def _get_templates(self, paths: Set) -> Set: os.path.join(root, name) for name in files if not name.startswith(".") - and any(fnmatch(name, "*%s" % glob) for glob in extensions) + and any(fnmatch(name, f"*{glob}") for glob in extensions) ) return templates diff --git a/src/django_idom/websocket/paths.py b/src/django_idom/websocket/paths.py index 0d2920e0..f337c83e 100644 --- a/src/django_idom/websocket/paths.py +++ b/src/django_idom/websocket/paths.py @@ -6,8 +6,9 @@ IDOM_WEBSOCKET_PATH = path( - IDOM_WEBSOCKET_URL + "/", IdomAsyncWebsocketConsumer.as_asgi() + f"{IDOM_WEBSOCKET_URL}/", IdomAsyncWebsocketConsumer.as_asgi() ) + """A URL path for :class:`IdomAsyncWebsocketConsumer`. Required in order for IDOM to know the websocket path. From 0d1acbad099722b6359f36e6442620a06cefd48a Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sat, 16 Apr 2022 22:15:58 -0700 Subject: [PATCH 06/53] dispatch_single_view -> serve_json_patch --- src/django_idom/websocket/consumer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/django_idom/websocket/consumer.py b/src/django_idom/websocket/consumer.py index 8f773a38..da8153f2 100644 --- a/src/django_idom/websocket/consumer.py +++ b/src/django_idom/websocket/consumer.py @@ -9,7 +9,7 @@ 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.serve import serve_json_patch from idom.core.layout import Layout, LayoutEvent from django_idom.config import IDOM_REGISTERED_COMPONENTS @@ -80,7 +80,7 @@ async def _run_dispatch_loop(self): self._idom_recv_queue = recv_queue = asyncio.Queue() try: - await dispatch_single_view( + await serve_json_patch( Layout(component_instance), self.send_json, recv_queue.get, From 9b13b6a4871a7325778bb336d3af93a123caa9fd Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sat, 16 Apr 2022 22:19:12 -0700 Subject: [PATCH 07/53] sort imports --- src/django_idom/websocket/consumer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/django_idom/websocket/consumer.py b/src/django_idom/websocket/consumer.py index da8153f2..eae11736 100644 --- a/src/django_idom/websocket/consumer.py +++ b/src/django_idom/websocket/consumer.py @@ -9,8 +9,8 @@ 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.serve import serve_json_patch from idom.core.layout import Layout, LayoutEvent +from idom.core.serve import serve_json_patch from django_idom.config import IDOM_REGISTERED_COMPONENTS From 036c4adb6d83cbe9a641207e0da85317e13da456 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 17 Apr 2022 01:59:32 -0700 Subject: [PATCH 08/53] new hooks --- README.md | 7 ++-- src/django_idom/__init__.py | 3 +- src/django_idom/hooks.py | 41 ++++++++++++++++++++++ src/django_idom/websocket/consumer.py | 16 +++------ tests/test_app/components.py | 45 ++++++++++++++++++++++--- tests/test_app/templates/base.html | 8 +++-- tests/test_app/tests/test_components.py | 14 +++++++- 7 files changed, 109 insertions(+), 25 deletions(-) create mode 100644 src/django_idom/hooks.py diff --git a/README.md b/README.md index e24d5a07..682eddaf 100644 --- a/README.md +++ b/README.md @@ -23,12 +23,11 @@ by Python dotted path in `your-template.html`. ```python from idom import component, html -from django_idom import IdomWebsocket # Components are CamelCase by ReactJS convention @component -def Hello(websocket: IdomWebsocket, greeting_recipient: str): - return html.h1(f"Hello {greeting_recipient}!") +def Hello(recipient: str): + return html.h1(f"Hello {recipient}!") ``` ## [`example_app/templates/your-template.html`](https://docs.djangoproject.com/en/dev/topics/templates/) @@ -50,7 +49,7 @@ In context this will look a bit like the following... - {% idom_component "my_django_project.example_app.components.Hello" greeting_recipient="World" %} + {% idom_component "my_django_project.example_app.components.Hello" recipient="World" %} ``` diff --git a/src/django_idom/__init__.py b/src/django_idom/__init__.py index cb2412c5..365655a7 100644 --- a/src/django_idom/__init__.py +++ b/src/django_idom/__init__.py @@ -1,6 +1,7 @@ +from . import hooks from .websocket.consumer import IdomWebsocket from .websocket.paths import IDOM_WEBSOCKET_PATH __version__ = "0.0.6" -__all__ = ["IDOM_WEBSOCKET_PATH", "IdomWebsocket"] +__all__ = ["IDOM_WEBSOCKET_PATH", "IdomWebsocket", "hooks"] diff --git a/src/django_idom/hooks.py b/src/django_idom/hooks.py new file mode 100644 index 00000000..c3d33bcc --- /dev/null +++ b/src/django_idom/hooks.py @@ -0,0 +1,41 @@ +from dataclasses import dataclass +from typing import Awaitable, Callable, Dict, Optional + +from idom.backend.types import Location +from idom.core.hooks import Context, create_context, use_context + + +@dataclass +class IdomWebsocket: + scope: dict + close: Callable[[Optional[int]], Awaitable[None]] + disconnect: Callable[[int], Awaitable[None]] + view_id: str + + +WebsocketContext: type[Context[IdomWebsocket | None]] = create_context( + None, "WebSocketContext" +) + + +def use_location() -> Location: + """Get the current route as a string""" + # TODO: Use the browser's current page, rather than the WS route + scope = use_scope() + search = scope["query_string"].decode() + return Location(scope["path"], f"?{search}" if search else "") + + +def use_scope() -> Dict: + """Get the current ASGI scope dictionary""" + return use_websocket().scope + + +def use_websocket() -> IdomWebsocket: + """Get the current IdomWebsocket object""" + websocket = use_context(WebsocketContext) + if websocket is None: + raise RuntimeError( + "No websocket. Are you running with a Django server?" + ) + return websocket diff --git a/src/django_idom/websocket/consumer.py b/src/django_idom/websocket/consumer.py index eae11736..aa988afa 100644 --- a/src/django_idom/websocket/consumer.py +++ b/src/django_idom/websocket/consumer.py @@ -2,8 +2,7 @@ import asyncio import json import logging -from dataclasses import dataclass -from typing import Any, Awaitable, Callable, Optional +from typing import Any from urllib.parse import parse_qsl from channels.auth import login @@ -13,19 +12,12 @@ from idom.core.serve import serve_json_patch from django_idom.config import IDOM_REGISTERED_COMPONENTS +from django_idom.hooks import IdomWebsocket, WebsocketContext _logger = logging.getLogger(__name__) -@dataclass -class IdomWebsocket: - scope: dict - close: Callable[[Optional[int]], Awaitable[None]] - disconnect: Callable[[int], Awaitable[None]] - view_id: str - - class IdomAsyncWebsocketConsumer(AsyncJsonWebsocketConsumer): """Communicates with the browser to perform actions on-demand.""" @@ -70,7 +62,7 @@ async def _run_dispatch_loop(self): socket = IdomWebsocket(self.scope, self.close, self.disconnect, view_id) try: - component_instance = component_constructor(socket, **component_kwargs) + component_instance = component_constructor(**component_kwargs) except Exception: _logger.exception( f"Failed to construct component {component_constructor} " @@ -81,7 +73,7 @@ async def _run_dispatch_loop(self): self._idom_recv_queue = recv_queue = asyncio.Queue() try: await serve_json_patch( - Layout(component_instance), + Layout(WebsocketContext(component_instance, value=socket)), self.send_json, recv_queue.get, ) diff --git a/tests/test_app/components.py b/tests/test_app/components.py index d3452efb..2efd878c 100644 --- a/tests/test_app/components.py +++ b/tests/test_app/components.py @@ -1,13 +1,15 @@ import idom +import django_idom + @idom.component -def HelloWorld(websocket): +def HelloWorld(): return idom.html.h1({"id": "hello-world"}, "Hello World!") @idom.component -def Button(websocket): +def Button(): count, set_count = idom.hooks.use_state(0) return idom.html.div( idom.html.button( @@ -22,7 +24,7 @@ def Button(websocket): @idom.component -def ParametrizedComponent(websocket, x, y): +def ParametrizedComponent(x, y): total = x + y return idom.html.h1({"id": "parametrized-component", "data-value": total}, total) @@ -32,5 +34,40 @@ def ParametrizedComponent(websocket, x, y): @idom.component -def SimpleBarChart(websocket): +def SimpleBarChart(): return VictoryBar() + + +@idom.component +def UseWebsocket(): + ws = django_idom.hooks.use_websocket() + ws.scope = "..." + success = bool(ws.scope and ws.close and ws.disconnect and ws.view_id) + return idom.html.div( + {"id": "use-websocket", "data-success": success}, + idom.html.hr(), + f"UseWebsocket: {ws}", + idom.html.hr(), + ) + + +@idom.component +def UseScope(): + scope = django_idom.hooks.use_scope() + success = len(scope) >= 10 and scope["type"] == "websocket" + return idom.html.div( + {"id": "use-scope", "data-success": success}, + f"UseScope: {scope}", + idom.html.hr(), + ) + + +@idom.component +def UseLocation(): + location = django_idom.hooks.use_location() + success = bool(location) + return idom.html.div( + {"id": "use-location", "data-success": success}, + f"UseLocation: {location}", + idom.html.hr(), + ) diff --git a/tests/test_app/templates/base.html b/tests/test_app/templates/base.html index 5b2311d2..28f0c12a 100644 --- a/tests/test_app/templates/base.html +++ b/tests/test_app/templates/base.html @@ -14,9 +14,11 @@

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_component "test_app.components.ParametrizedComponent" class="parametarized-component" x=123 y=456 %}
+
{% idom_component "test_app.components.SimpleBarChart" %}
+
{% idom_component "test_app.components.UseWebsocket" %}
+
{% idom_component "test_app.components.UseScope" %}
+
{% idom_component "test_app.components.UseLocation" %}
diff --git a/tests/test_app/tests/test_components.py b/tests/test_app/tests/test_components.py index cb10cca9..fbfda829 100644 --- a/tests/test_app/tests/test_components.py +++ b/tests/test_app/tests/test_components.py @@ -5,7 +5,7 @@ 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 +from selenium.webdriver.support.wait import WebDriverWait # These tests are broken on Windows due to Selenium @@ -47,6 +47,18 @@ def test_component_from_web_module(self): ) ) + def test_use_websocket(self): + element = self.driver.find_element_by_id("use-websocket") + self.assertEqual(element.get_attribute("data-success"), "true") + + def test_use_scope(self): + element = self.driver.find_element_by_id("use-scope") + self.assertEqual(element.get_attribute("data-success"), "true") + + def test_use_location(self): + element = self.driver.find_element_by_id("use-location") + self.assertEqual(element.get_attribute("data-success"), "true") + def make_driver(page_load_timeout, implicit_wait_timeout): options = webdriver.ChromeOptions() From 2db9b1dd89111f261cf8c79e7563121b11c2e008 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 17 Apr 2022 02:04:39 -0700 Subject: [PATCH 09/53] formatting --- src/django_idom/hooks.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/django_idom/hooks.py b/src/django_idom/hooks.py index c3d33bcc..589ae89c 100644 --- a/src/django_idom/hooks.py +++ b/src/django_idom/hooks.py @@ -35,7 +35,5 @@ def use_websocket() -> IdomWebsocket: """Get the current IdomWebsocket object""" websocket = use_context(WebsocketContext) if websocket is None: - raise RuntimeError( - "No websocket. Are you running with a Django server?" - ) + raise RuntimeError("No websocket. Are you running with a Django server?") return websocket From c4e8b4aa0d4fec45a308ca865a7b2c231ecd1337 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 17 Apr 2022 02:04:55 -0700 Subject: [PATCH 10/53] update changelog to add hooks --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2acaa209..8d786b9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,9 +21,14 @@ Types of changes are to be listed in this order ## [0.0.6] - 2022-04-16 +### Added + +- Django-specific hooks! `use_websocket`, `use_scope`, and `use_location` are now available within the `django_idom.hooks` module. + ### Changed - Bumped the minimum IDOM version to 0.38.0 +- `websocket` positional parameter within component functions has been removed. Functionally, it is replaced with `django_idom.hooks.use_websocket`. ## [0.0.5] - 2022-04-04 From 9de275a6ace80769c9b319e2c52c01c00169f815 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 17 Apr 2022 02:06:58 -0700 Subject: [PATCH 11/53] Python 3.8 fixes --- src/django_idom/hooks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/django_idom/hooks.py b/src/django_idom/hooks.py index 589ae89c..b1b7a34e 100644 --- a/src/django_idom/hooks.py +++ b/src/django_idom/hooks.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Awaitable, Callable, Dict, Optional +from typing import Awaitable, Callable, Dict, Optional, Union from idom.backend.types import Location from idom.core.hooks import Context, create_context, use_context @@ -13,7 +13,7 @@ class IdomWebsocket: view_id: str -WebsocketContext: type[Context[IdomWebsocket | None]] = create_context( +WebsocketContext: type[Context[Union[IdomWebsocket, None]]] = create_context( None, "WebSocketContext" ) From 2fe120892000c69de3ec5ac30d334d1509ed1850 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 17 Apr 2022 02:10:33 -0700 Subject: [PATCH 12/53] more python 3.8 fixes --- src/django_idom/hooks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/django_idom/hooks.py b/src/django_idom/hooks.py index b1b7a34e..5d088223 100644 --- a/src/django_idom/hooks.py +++ b/src/django_idom/hooks.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Awaitable, Callable, Dict, Optional, Union +from typing import Awaitable, Callable, Dict, Optional, Type, Union from idom.backend.types import Location from idom.core.hooks import Context, create_context, use_context @@ -13,7 +13,7 @@ class IdomWebsocket: view_id: str -WebsocketContext: type[Context[Union[IdomWebsocket, None]]] = create_context( +WebsocketContext: Type[Context[Union[IdomWebsocket, None]]] = create_context( None, "WebSocketContext" ) From eda71b9b87892d0f20d6451ece3dfef05f72a6e0 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 24 Apr 2022 00:06:03 -0700 Subject: [PATCH 13/53] new docs source --- CHANGELOG.md | 1 + README.md | 185 ++++++----------------------- docs/contribute/development-env.md | 25 ++++ docs/contribute/running-tests.md | 11 ++ docs/django/index.md | 45 +++++++ docs/how-to-use/index.md | 61 ++++++++++ docs/index.md | 25 ++++ docs/installation/install.md | 89 ++++++++++++++ mkdocs.yml | 59 +++++++++ requirements/build-docs.txt | 4 + 10 files changed, 357 insertions(+), 148 deletions(-) create mode 100644 docs/contribute/development-env.md create mode 100644 docs/contribute/running-tests.md create mode 100644 docs/django/index.md create mode 100644 docs/how-to-use/index.md create mode 100644 docs/index.md create mode 100644 docs/installation/install.md create mode 100644 mkdocs.yml create mode 100644 requirements/build-docs.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d786b9b..5982215c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ Types of changes are to be listed in this order ### Added - Django-specific hooks! `use_websocket`, `use_scope`, and `use_location` are now available within the `django_idom.hooks` module. +- A real docs page to show off these new features. ### Changed diff --git a/README.md b/README.md index 682eddaf..bbb86de0 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,46 @@ + # Django IDOM · [![Tests](https://github.com/idom-team/django-idom/workflows/Test/badge.svg?event=push)](https://github.com/idom-team/django-idom/actions?query=workflow%3ATest) [![PyPI Version](https://img.shields.io/pypi/v/django-idom.svg)](https://pypi.python.org/pypi/django-idom) [![License](https://img.shields.io/badge/License-MIT-purple.svg)](https://github.com/idom-team/django-idom/blob/main/LICENSE) + -`django-idom` allows Django to integrate with [IDOM](https://github.com/idom-team/idom), a reactive Python web framework for building **interactive websites without needing a single line of Javascript**. + +IDOM is a Python micro-framework that links your web framework of choice to a ReactJS frontend, allowing you to create **interactive websites without needing JavaScript!** -**You can try IDOM now in a Jupyter Notebook:** - -Binder - +Following ReactJS styling, web elements are combined into [reusable "components"](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/your-first-components/index.html#parametrizing-components). These components can utilize [hooks](https://idom-docs.herokuapp.com/docs/reference/hooks-api.html) and [events](https://idom-docs.herokuapp.com/docs/guides/adding-interactivity/responding-to-events/index.html#async-event-handlers) to create infinitely complex web pages. -# Quick Example +When needed, IDOM can [use JavaScript components](https://idom-docs.herokuapp.com/docs/guides/escape-hatches/javascript-components.html#dynamically-loaded-components) directly from NPM. Components can also be [developed in JavaScript](https://idom-docs.herokuapp.com/docs/guides/escape-hatches/javascript-components.html#custom-javascript-components) for additional flexibility. + +IDOM's ecosystem independent design allows components to be reused across a variety of web frameworks. Pre-existing support is included for many popular Python frameworks, however, any framework with WebSocket support can be adapted to utilize IDOM. + +| Supported Frameworks | Supported Frameworks (External) | +| --- | --- | +| [`Flask`, `FastAPI`, `Sanic`, `Tornado`](https://idom-docs.herokuapp.com/docs/guides/getting-started/installing-idom.html#officially-supported-servers) | [`Django`](https://github.com/idom-team/django-idom), [`Plotly-Dash`](https://github.com/idom-team/idom-dash), [`Jupyter`](https://github.com/idom-team/idom-jupyter) | + + +--- + +# At a Glance ## `example_app/components.py` -This is where you'll define your [IDOM](https://github.com/idom-team/idom) components. Ultimately though, you should -feel free to organize your component modules as you wish. Any components created will ultimately be referenced -by Python dotted path in `your-template.html`. + +Define your [IDOM](https://github.com/idom-team/idom) components within any Python module. To start out, we recommend creating a `components.py` file within your chosen **Django app**. + +_Note: You are free to name and place this file anywhere. Ultimately, components are referenced by Python dotted path in `my-template.html`._ ```python from idom import component, html # Components are CamelCase by ReactJS convention @component -def Hello(recipient: str): +def HelloComponent(recipient: str): return html.h1(f"Hello {recipient}!") ``` + -## [`example_app/templates/your-template.html`](https://docs.djangoproject.com/en/dev/topics/templates/) +## [`example_app/templates/my-template.html`](https://docs.djangoproject.com/en/dev/topics/templates/) -In your templates, you may add IDOM components into your HTML by using the `idom_component` -template tag. This tag requires the dotted path to the component function. + +In your **Django app**'s `templates` folder, you can now add your IDOM component into your HTML using the `idom_component` template tag using dotted path to the component function. Additonally, you can pass in keyworded arguments into your component function. @@ -41,143 +48,25 @@ In context this will look a bit like the following... ```jinja {% load idom %} - - - Example Project - - - {% idom_component "my_django_project.example_app.components.Hello" recipient="World" %} + {% idom_component "django_project.example_app.components.HelloComponent" recipient="World" %} ``` -# Installation - -Install `django-idom` via pip. - -```bash -pip install django-idom -``` - -You'll also need to modify a few files in your Django project. - -## [`settings.py`](https://docs.djangoproject.com/en/dev/topics/settings/) - -In your settings you'll need to add `channels` and `django_idom` to [`INSTALLED_APPS`](https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-INSTALLED_APPS). - -```python -INSTALLED_APPS = [ - ..., - "channels", - "django_idom", -] - -# Ensure ASGI_APPLICATION is set properly based on your project name! -ASGI_APPLICATION = "my_django_project.asgi.application" -``` - -**Optional:** You can also configure IDOM settings. - -```python -# If "idom" cache is not configured, then we'll use "default" instead -CACHES = { - "idom": {"BACKEND": ...}, -} - -# Maximum seconds between two reconnection attempts that would cause the client give up. -# 0 will disable reconnection. -IDOM_WS_MAX_RECONNECT_TIMEOUT: int = 604800 - -# The URL for IDOM to serve websockets -IDOM_WEBSOCKET_URL: str = "idom/" -``` - -## [`urls.py`](https://docs.djangoproject.com/en/dev/topics/http/urls/) - -Add IDOM HTTP paths to your `urlpatterns`. - -```python -from django.urls import include, path - -urlpatterns = [ - path("idom/", include("django_idom.http.urls")), - ... -] -``` - -## [`asgi.py`](https://docs.djangoproject.com/en/dev/howto/deployment/asgi/) - -Register IDOM's websocket using `IDOM_WEBSOCKET_PATH`. - -_Note: If you do not have an `asgi.py`, follow the [`channels` installation guide](https://channels.readthedocs.io/en/stable/installation.html)._ - -```python - -import os -from django.core.asgi import get_asgi_application - -# Ensure DJANGO_SETTINGS_MODULE is set properly based on your project name! -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "my_django_project.settings") -django_asgi_app = get_asgi_application() - -from channels.auth import AuthMiddlewareStack -from channels.routing import ProtocolTypeRouter, URLRouter -from channels.sessions import SessionMiddlewareStack -from django_idom import IDOM_WEBSOCKET_PATH - -application = ProtocolTypeRouter( - { - "http": django_asgi_app, - "websocket": SessionMiddlewareStack( - AuthMiddlewareStack(URLRouter([IDOM_WEBSOCKET_PATH])) - ), - } -) -``` - -# Developer Guide - -If you plan to make code changes to this repository, you'll need to install the -following dependencies first: - -- [NPM](https://docs.npmjs.com/try-the-latest-stable-version-of-npm) for - installing and managing Javascript -- [ChromeDriver](https://chromedriver.chromium.org/downloads) for testing with - [Selenium](https://www.seleniumhq.org/) - -Once done, you should clone this repository: - -```bash -git clone https://github.com/idom-team/django-idom.git -cd django-idom -``` - -Then, by running the command below you can: - -- Install an editable version of the Python code - -- Download, build, and install Javascript dependencies - -```bash -pip install -e . -r requirements.txt -``` +_Note: If you do not have a `templates` folder in your **Django app**, simply create one! Also, your `templates` folder will not be detected unless you [add the corresponding **Django App** to `settings.py:INSTALLED_APPS`](https://docs.djangoproject.com/en/dev/ref/applications/#configuring-applications)._ + -Finally, to verify that everything is working properly, you'll want to run the test suite. +--- -## Running The Tests +# Resources -This repo uses [Nox](https://nox.thea.codes/en/stable/) to run scripts which can -be found in `noxfile.py`. For a full test of available scripts run `nox -l`. To run the full test suite simple execute: + +Follow the links below to find out more about this project. -``` -nox -s test -``` - -To run the tests using a headless browser: - -``` -nox -s test -- --headless -``` +- [Try it Now](https://mybinder.org/v2/gh/idom-team/idom-jupyter/main?urlpath=lab/tree/notebooks/introduction.ipynb) - Check out IDOM in a Jupyter Notebook. +- [Documentation](https://idom-team.github.io/django-idom) - Learn how to install, run, and use IDOM. +- [Community Forum](https://github.com/idom-team/idom/discussions) - Ask questions, share ideas, and show off projects. + \ No newline at end of file diff --git a/docs/contribute/development-env.md b/docs/contribute/development-env.md new file mode 100644 index 00000000..11cd9e5e --- /dev/null +++ b/docs/contribute/development-env.md @@ -0,0 +1,25 @@ +If you plan to make code changes to this repository, you'll need to install the following dependencies first: + +- [NPM](https://docs.npmjs.com/try-the-latest-stable-version-of-npm) for + installing and managing Javascript +- [ChromeDriver](https://chromedriver.chromium.org/downloads) for testing with + [Selenium](https://www.seleniumhq.org/) + +Once done, you should clone this repository: + +```bash +git clone https://github.com/idom-team/django-idom.git +cd django-idom +``` + +Then, by running the command below you can: + +- Install an editable version of the Python code + +- Download, build, and install Javascript dependencies + +```bash +pip install -e . -r requirements.txt +``` + +Finally, to verify that everything is working properly, you'll want to run the test suite in the next step. \ No newline at end of file diff --git a/docs/contribute/running-tests.md b/docs/contribute/running-tests.md new file mode 100644 index 00000000..1f054e54 --- /dev/null +++ b/docs/contribute/running-tests.md @@ -0,0 +1,11 @@ +This repo uses [Nox](https://nox.thea.codes/en/stable/) to run scripts which can be found in `noxfile.py`. For a full test of available scripts run `nox -l`. To run the full test suite simple execute: + +``` +nox -s test +``` + +To run the tests using a headless browser: + +``` +nox -s test -- --headless +``` diff --git a/docs/django/index.md b/docs/django/index.md new file mode 100644 index 00000000..7483dd54 --- /dev/null +++ b/docs/django/index.md @@ -0,0 +1,45 @@ +# Django Hooks + +## Use Websocket + +You can fetch the Django Channels websocket at any time by using `use_websocket`. + +```python +from idom import component, html +from django_idom.hooks import use_websocket + +@component +def MyComponent(): + my_websocket = use_websocket() + return html.div(my_websocket) +``` + +## Use Scope + +This is a shortcut that returns the websocket's `scope`. + +```python +from idom import component, html +from django_idom.hooks import use_scope + +@component +def MyComponent(): + my_scope = use_scope() + return html.div(my_scope) +``` + +## Use Location + +Returns the URL that the websocket was opened from. + +_Note: This will [eventually be updated](https://github.com/idom-team/idom/issues/569) to return the client's current webpage URL. This will come in conjunction with Single Page Application (SPA) support._ + +```python +from idom import component, html +from django_idom.hooks import use_location + +@component +def MyComponent(): + my_location = use_location() + return html.div(my_location) +``` \ No newline at end of file diff --git a/docs/how-to-use/index.md b/docs/how-to-use/index.md new file mode 100644 index 00000000..e18faacb --- /dev/null +++ b/docs/how-to-use/index.md @@ -0,0 +1,61 @@ +## Create a Django Project and App + +We are going to assume you've [created a basic **Django project**](https://docs.djangoproject.com/en/dev/intro/tutorial01/) before, which also involves creating/installing at least one **Django app**. If not, check out this [9 minute video tutorial](https://www.youtube.com/watch?v=ZsJRXS_vrw0) created by _IDG TECHtalk_. + +Django provides you the flexibility to place your apps anywhere you wish. In the examples below, we are going to assume you've placed your apps directly into your **Django project** folder. This is a common folder structure for small projects. + +--- + +## Create a component + +### `components.py` + +{% + include-markdown "../../README.md" + start="" + end="" +%} + +--- + +## Reference your component + +### `templates/my-template.html` + +{% + include-markdown "../../README.md" + start="" + end="" +%} + +--- + +## Render your component + +We will also assume you've [created a Django View](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view) before, but we'll give a simple example below. + +### `views.py` + +This is your **Django app**'s [view file](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view). This function will render your HTML template, which includes your IDOM component. + +```python +from django.shortcuts import render + +def index(request): + return render(request, "my-template.html") +``` + +### `urls.py` + +To simplify things for this example, we are adding this view directly to your [**Django project**'s `urls.py`](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view) rather than adding to a **Django app*. + +```python +from django.urls import path +from . import views + +urlpatterns = [ + path("example/", views.index), +] +``` + +Now, navigate to `http://127.0.0.1:8000/example/` to see your component print out "Hello World". \ No newline at end of file diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..75d5e581 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,25 @@ +--- +hide: + - navigation + - toc +--- + +{% + include-markdown "../README.md" + start="" + end="" +%} + +{% + include-markdown "../README.md" + start="" + end="" +%} + +## Resources + +{% + include-markdown "../README.md" + start="" + end="" +%} \ No newline at end of file diff --git a/docs/installation/install.md b/docs/installation/install.md new file mode 100644 index 00000000..d37f3640 --- /dev/null +++ b/docs/installation/install.md @@ -0,0 +1,89 @@ + + +## Install `django-idom` from PyPI + +```bash +pip install django-idom +``` + +You'll also need to modify a few files in your Django project... + +--- + +## Configure [`settings.py`](https://docs.djangoproject.com/en/dev/topics/settings/) + +In your settings you'll need to add `channels` and `django_idom` to [`INSTALLED_APPS`](https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-INSTALLED_APPS). + +```python +INSTALLED_APPS = [ + ..., + "channels", + "django_idom", +] + +# Ensure ASGI_APPLICATION is set properly based on your project name! +ASGI_APPLICATION = "my_django_project.asgi.application" +``` + +**Optional:** You can also configure IDOM settings. + +```python +# If "idom" cache is not configured, then we'll use "default" instead +CACHES = { + "idom": {"BACKEND": ...}, +} + +# Maximum seconds between two reconnection attempts that would cause the client give up. +# 0 will disable reconnection. +IDOM_WS_MAX_RECONNECT_TIMEOUT: int = 604800 + +# The URL for IDOM to serve websockets +IDOM_WEBSOCKET_URL: str = "idom/" +``` + +--- + +## Configure [`urls.py`](https://docs.djangoproject.com/en/dev/topics/http/urls/) + +Add IDOM HTTP paths to your `urlpatterns`. + +```python +from django.urls import include, path + +urlpatterns = [ + path("idom/", include("django_idom.http.urls")), + ... +] +``` + +--- + +## Configure [`asgi.py`](https://docs.djangoproject.com/en/dev/howto/deployment/asgi/) + +Register IDOM's websocket using `IDOM_WEBSOCKET_PATH`. + +_Note: If you do not have an `asgi.py`, follow the [`channels` installation guide](https://channels.readthedocs.io/en/stable/installation.html)._ + +```python + +import os +from django.core.asgi import get_asgi_application + +# Ensure DJANGO_SETTINGS_MODULE is set properly based on your project name! +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "my_django_project.settings") +django_asgi_app = get_asgi_application() + +from channels.auth import AuthMiddlewareStack +from channels.routing import ProtocolTypeRouter, URLRouter +from channels.sessions import SessionMiddlewareStack +from django_idom import IDOM_WEBSOCKET_PATH + +application = ProtocolTypeRouter( + { + "http": django_asgi_app, + "websocket": SessionMiddlewareStack( + AuthMiddlewareStack(URLRouter([IDOM_WEBSOCKET_PATH])) + ), + } +) +``` \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 00000000..8c8465ec --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,59 @@ +--- +nav: + - Home: index.md + - Installation: installation/install.md + - How to Use: how-to-use/index.md + - Django-Only Features: django/index.md + - Contribute: + - Setup Development Enviroment: contribute/development-env.md + - Running Tests: contribute/running-tests.md + +theme: + name: material + palette: + - scheme: slate + toggle: + icon: material/toggle-switch + name: Switch to light mode + primary: deep-orange + accent: deep-orange + - scheme: default + toggle: + icon: material/toggle-switch-off-outline + name: Switch to dark mode + primary: deep-orange + accent: deep-orange + features: + - navigation.instant + - navigation.tracking + - navigation.tabs + - navigation.sections + - toc.integrate + - navigation.top + + icon: + repo: fontawesome/brands/github + +markdown_extensions: + - toc: + permalink: true + - pymdownx.emoji: + emoji_index: !!python/name:materialx.emoji.twemoji + emoji_generator: !!python/name:materialx.emoji.to_svg + - pymdownx.highlight + - pymdownx.superfences + - attr_list + +plugins: + - search + - include-markdown + - git-revision-date-localized: + fallback_to_build_date: true + +site_name: Django IDOM Docs +site_author: Archmonger +site_description: React for Django developers. +repo_url: https://github.com/idom-team/django-idom +site_url: https://idom-team.github.io/django-idom +repo_name: idom-team/django-idom +edit_uri: edit/docs diff --git a/requirements/build-docs.txt b/requirements/build-docs.txt new file mode 100644 index 00000000..48cd4d03 --- /dev/null +++ b/requirements/build-docs.txt @@ -0,0 +1,4 @@ +mkdocs==1.2.3 +mkdocs-git-revision-date-localized-plugin==1.0.0 +mkdocs-material==8.2.5 +mkdocs-include-markdown-plugin==3.3.0 \ No newline at end of file From 2965ceb71cb5d0de64117a763c24373fc5fdd6c8 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 24 Apr 2022 00:11:40 -0700 Subject: [PATCH 14/53] publish docs workflow --- .github/workflows/publish-docs.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .github/workflows/publish-docs.yml diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml new file mode 100644 index 00000000..af8abe99 --- /dev/null +++ b/.github/workflows/publish-docs.yml @@ -0,0 +1,15 @@ +name: Publish Docs +on: + push: + branches: + - main +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: 3.x + - run: pip install requirements/build-docs.txt + - run: mkdocs gh-deploy --force \ No newline at end of file From dedaf7eca5b5e3b48e347a6cbe610393921ba42b Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 24 Apr 2022 00:19:34 -0700 Subject: [PATCH 15/53] rename idom_component to component --- CHANGELOG.md | 1 + README.md | 4 ++-- src/django_idom/templatetags/idom.py | 2 +- src/django_idom/utils.py | 2 +- tests/test_app/templates/base.html | 14 +++++++------- tests/test_app/tests/test_regex.py | 22 +++++++++++----------- 6 files changed, 23 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5982215c..4f2e7065 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ Types of changes are to be listed in this order - Bumped the minimum IDOM version to 0.38.0 - `websocket` positional parameter within component functions has been removed. Functionally, it is replaced with `django_idom.hooks.use_websocket`. +- `idom_component` template tag has been renamed to `component` ## [0.0.5] - 2022-04-04 diff --git a/README.md b/README.md index bbb86de0..a0f7c0bc 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ def HelloComponent(recipient: str): ## [`example_app/templates/my-template.html`](https://docs.djangoproject.com/en/dev/topics/templates/) -In your **Django app**'s `templates` folder, you can now add your IDOM component into your HTML using the `idom_component` template tag using dotted path to the component function. +In your **Django app**'s `templates` folder, you can now add your IDOM component into your HTML using the `component` template tag using your dotted path to the component function. Additonally, you can pass in keyworded arguments into your component function. @@ -51,7 +51,7 @@ In context this will look a bit like the following... - {% idom_component "django_project.example_app.components.HelloComponent" recipient="World" %} + {% component "django_project.example_app.components.HelloComponent" recipient="World" %} ``` diff --git a/src/django_idom/templatetags/idom.py b/src/django_idom/templatetags/idom.py index 28def13e..5707733d 100644 --- a/src/django_idom/templatetags/idom.py +++ b/src/django_idom/templatetags/idom.py @@ -14,7 +14,7 @@ @register.inclusion_tag("idom/component.html") -def idom_component(_component_id_, **kwargs): +def component(_component_id_, **kwargs): _register_component(_component_id_) class_ = kwargs.pop("class", "") diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py index faf5109c..1a31b0bb 100644 --- a/src/django_idom/utils.py +++ b/src/django_idom/utils.py @@ -12,7 +12,7 @@ from django_idom.config import IDOM_REGISTERED_COMPONENTS -COMPONENT_REGEX = re.compile(r"{% *idom_component ((\"[^\"']*\")|('[^\"']*')).*?%}") +COMPONENT_REGEX = re.compile(r"{% *component ((\"[^\"']*\")|('[^\"']*')).*?%}") _logger = logging.getLogger(__name__) diff --git a/tests/test_app/templates/base.html b/tests/test_app/templates/base.html index 28f0c12a..0c52a8cc 100644 --- a/tests/test_app/templates/base.html +++ b/tests/test_app/templates/base.html @@ -12,13 +12,13 @@

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" %}
-
{% idom_component "test_app.components.UseWebsocket" %}
-
{% idom_component "test_app.components.UseScope" %}
-
{% idom_component "test_app.components.UseLocation" %}
+
{% component "test_app.components.HelloWorld" class="hello-world" %}
+
{% component "test_app.components.Button" class="button" %}
+
{% component "test_app.components.ParametrizedComponent" class="parametarized-component" x=123 y=456 %}
+
{% component "test_app.components.SimpleBarChart" %}
+
{% component "test_app.components.UseWebsocket" %}
+
{% component "test_app.components.UseScope" %}
+
{% component "test_app.components.UseLocation" %}
diff --git a/tests/test_app/tests/test_regex.py b/tests/test_app/tests/test_regex.py index 3e418f1d..690b0f3a 100644 --- a/tests/test_app/tests/test_regex.py +++ b/tests/test_app/tests/test_regex.py @@ -6,22 +6,22 @@ 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" %}', + r'{%component "my.component"%}', + r"{%component 'my.component'%}", + r'{% component "my.component" %}', + r"{% component 'my.component' %}", + r'{% component "my.component" class="my_thing" %}', + r'{% 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"{% component my.component %}", + r"""{% component 'my.component" %}""", + r'{ component "my.component" }', + r'{{ component "my.component" }}', + r"component", r"{%%}", r" ", r"", From 465092df3496408904db4351c25ba6bcdf80deaf Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 24 Apr 2022 00:31:49 -0700 Subject: [PATCH 16/53] better docs statement in changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f2e7065..b6c2584a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,7 @@ Types of changes are to be listed in this order ### Added - Django-specific hooks! `use_websocket`, `use_scope`, and `use_location` are now available within the `django_idom.hooks` module. -- A real docs page to show off these new features. +- Documentation has been placed into a formal docs webpage. ### Changed From d1c4637b9f952b635f4b75a0078577f6fe2779d0 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 24 Apr 2022 00:35:39 -0700 Subject: [PATCH 17/53] formatting and cleanup --- README.md | 27 ++++++++++++++++++--------- docs/contribute/development-env.md | 14 +++++++------- docs/django/index.md | 2 +- docs/how-to-use/index.md | 10 +++++----- docs/index.md | 14 ++++++++------ docs/installation/install.md | 4 +--- 6 files changed, 40 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index a0f7c0bc..12c9dd83 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,23 @@ + # Django IDOM · [![Tests](https://github.com/idom-team/django-idom/workflows/Test/badge.svg?event=push)](https://github.com/idom-team/django-idom/actions?query=workflow%3ATest) [![PyPI Version](https://img.shields.io/pypi/v/django-idom.svg)](https://pypi.python.org/pypi/django-idom) [![License](https://img.shields.io/badge/License-MIT-purple.svg)](https://github.com/idom-team/django-idom/blob/main/LICENSE) + + IDOM is a Python micro-framework that links your web framework of choice to a ReactJS frontend, allowing you to create **interactive websites without needing JavaScript!** Following ReactJS styling, web elements are combined into [reusable "components"](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/your-first-components/index.html#parametrizing-components). These components can utilize [hooks](https://idom-docs.herokuapp.com/docs/reference/hooks-api.html) and [events](https://idom-docs.herokuapp.com/docs/guides/adding-interactivity/responding-to-events/index.html#async-event-handlers) to create infinitely complex web pages. When needed, IDOM can [use JavaScript components](https://idom-docs.herokuapp.com/docs/guides/escape-hatches/javascript-components.html#dynamically-loaded-components) directly from NPM. Components can also be [developed in JavaScript](https://idom-docs.herokuapp.com/docs/guides/escape-hatches/javascript-components.html#custom-javascript-components) for additional flexibility. -IDOM's ecosystem independent design allows components to be reused across a variety of web frameworks. Pre-existing support is included for many popular Python frameworks, however, any framework with WebSocket support can be adapted to utilize IDOM. +IDOM's ecosystem independent design allows components to be reused across a variety of web frameworks. Pre-existing support is included for many popular Python frameworks, however, any framework with WebSocket support can be adapted to utilize IDOM. + +| Supported Frameworks | Supported Frameworks (External) | +| ------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [`Flask`, `FastAPI`, `Sanic`, `Tornado`](https://idom-docs.herokuapp.com/docs/guides/getting-started/installing-idom.html#officially-supported-servers) | [`Django`](https://github.com/idom-team/django-idom), [`Plotly-Dash`](https://github.com/idom-team/idom-dash), [`Jupyter`](https://github.com/idom-team/idom-jupyter) | -| Supported Frameworks | Supported Frameworks (External) | -| --- | --- | -| [`Flask`, `FastAPI`, `Sanic`, `Tornado`](https://idom-docs.herokuapp.com/docs/guides/getting-started/installing-idom.html#officially-supported-servers) | [`Django`](https://github.com/idom-team/django-idom), [`Plotly-Dash`](https://github.com/idom-team/idom-dash), [`Jupyter`](https://github.com/idom-team/idom-jupyter) | --- @@ -23,6 +27,7 @@ IDOM's ecosystem independent design allows components to be reused across a vari ## `example_app/components.py` + Define your [IDOM](https://github.com/idom-team/idom) components within any Python module. To start out, we recommend creating a `components.py` file within your chosen **Django app**. _Note: You are free to name and place this file anywhere. Ultimately, components are referenced by Python dotted path in `my-template.html`._ @@ -35,11 +40,13 @@ from idom import component, html def HelloComponent(recipient: str): return html.h1(f"Hello {recipient}!") ``` + ## [`example_app/templates/my-template.html`](https://docs.djangoproject.com/en/dev/topics/templates/) + In your **Django app**'s `templates` folder, you can now add your IDOM component into your HTML using the `component` template tag using your dotted path to the component function. Additonally, you can pass in keyworded arguments into your component function. @@ -56,7 +63,8 @@ In context this will look a bit like the following... ``` -_Note: If you do not have a `templates` folder in your **Django app**, simply create one! Also, your `templates` folder will not be detected unless you [add the corresponding **Django App** to `settings.py:INSTALLED_APPS`](https://docs.djangoproject.com/en/dev/ref/applications/#configuring-applications)._ +_Note: If you do not have a `templates` folder in your **Django app**, simply create one! Also, your `templates` folder will not be detected unless you [add the corresponding **Django app** to `settings.py:INSTALLED_APPS`](https://docs.djangoproject.com/en/dev/ref/applications/#configuring-applications)._ + --- @@ -64,9 +72,10 @@ _Note: If you do not have a `templates` folder in your **Django app**, simply cr # Resources + Follow the links below to find out more about this project. -- [Try it Now](https://mybinder.org/v2/gh/idom-team/idom-jupyter/main?urlpath=lab/tree/notebooks/introduction.ipynb) - Check out IDOM in a Jupyter Notebook. -- [Documentation](https://idom-team.github.io/django-idom) - Learn how to install, run, and use IDOM. -- [Community Forum](https://github.com/idom-team/idom/discussions) - Ask questions, share ideas, and show off projects. - \ No newline at end of file +- [Try it Now](https://mybinder.org/v2/gh/idom-team/idom-jupyter/main?urlpath=lab/tree/notebooks/introduction.ipynb) - Check out IDOM in a Jupyter Notebook. +- [Documentation](https://idom-team.github.io/django-idom) - Learn how to install, run, and use IDOM. +- [Community Forum](https://github.com/idom-team/idom/discussions) - Ask questions, share ideas, and show off projects. + diff --git a/docs/contribute/development-env.md b/docs/contribute/development-env.md index 11cd9e5e..a28b6fd6 100644 --- a/docs/contribute/development-env.md +++ b/docs/contribute/development-env.md @@ -1,9 +1,9 @@ If you plan to make code changes to this repository, you'll need to install the following dependencies first: -- [NPM](https://docs.npmjs.com/try-the-latest-stable-version-of-npm) for - installing and managing Javascript -- [ChromeDriver](https://chromedriver.chromium.org/downloads) for testing with - [Selenium](https://www.seleniumhq.org/) +- [NPM](https://docs.npmjs.com/try-the-latest-stable-version-of-npm) for + installing and managing Javascript +- [ChromeDriver](https://chromedriver.chromium.org/downloads) for testing with + [Selenium](https://www.seleniumhq.org/) Once done, you should clone this repository: @@ -14,12 +14,12 @@ cd django-idom Then, by running the command below you can: -- Install an editable version of the Python code +- Install an editable version of the Python code -- Download, build, and install Javascript dependencies +- Download, build, and install Javascript dependencies ```bash pip install -e . -r requirements.txt ``` -Finally, to verify that everything is working properly, you'll want to run the test suite in the next step. \ No newline at end of file +Finally, to verify that everything is working properly, you'll want to run the test suite in the next step. diff --git a/docs/django/index.md b/docs/django/index.md index 7483dd54..dcd778e2 100644 --- a/docs/django/index.md +++ b/docs/django/index.md @@ -42,4 +42,4 @@ from django_idom.hooks import use_location def MyComponent(): my_location = use_location() return html.div(my_location) -``` \ No newline at end of file +``` diff --git a/docs/how-to-use/index.md b/docs/how-to-use/index.md index e18faacb..2697a869 100644 --- a/docs/how-to-use/index.md +++ b/docs/how-to-use/index.md @@ -1,4 +1,4 @@ -## Create a Django Project and App +## Create a Django project and app We are going to assume you've [created a basic **Django project**](https://docs.djangoproject.com/en/dev/intro/tutorial01/) before, which also involves creating/installing at least one **Django app**. If not, check out this [9 minute video tutorial](https://www.youtube.com/watch?v=ZsJRXS_vrw0) created by _IDG TECHtalk_. @@ -10,7 +10,7 @@ Django provides you the flexibility to place your apps anywhere you wish. In the ### `components.py` -{% +{% include-markdown "../../README.md" start="" end="" @@ -22,7 +22,7 @@ Django provides you the flexibility to place your apps anywhere you wish. In the ### `templates/my-template.html` -{% +{% include-markdown "../../README.md" start="" end="" @@ -47,7 +47,7 @@ def index(request): ### `urls.py` -To simplify things for this example, we are adding this view directly to your [**Django project**'s `urls.py`](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view) rather than adding to a **Django app*. +To simplify things for this example, we are adding this view directly to your [**Django project**'s `urls.py`](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view) rather than adding to a **Django app**. ```python from django.urls import path @@ -58,4 +58,4 @@ urlpatterns = [ ] ``` -Now, navigate to `http://127.0.0.1:8000/example/` to see your component print out "Hello World". \ No newline at end of file +Now, navigate to `http://127.0.0.1:8000/example/` to see your component print out "Hello World". diff --git a/docs/index.md b/docs/index.md index 75d5e581..f13eaa00 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,25 +1,27 @@ --- hide: - - navigation - - toc + - navigation + - toc --- -{% +{% include-markdown "../README.md" start="" end="" %} -{% +{% include-markdown "../README.md" start="" end="" %} +--- + ## Resources -{% +{% include-markdown "../README.md" start="" end="" -%} \ No newline at end of file +%} diff --git a/docs/installation/install.md b/docs/installation/install.md index d37f3640..bcc698e5 100644 --- a/docs/installation/install.md +++ b/docs/installation/install.md @@ -1,5 +1,3 @@ - - ## Install `django-idom` from PyPI ```bash @@ -86,4 +84,4 @@ application = ProtocolTypeRouter( ), } ) -``` \ No newline at end of file +``` From d31cad0b90c9298412c13393d937353f9c3e9889 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 24 Apr 2022 02:42:49 -0700 Subject: [PATCH 18/53] more everything --- CHANGELOG.md | 63 ++++++++++--------- README.md | 12 ++-- docs/changelog/index.md | 14 +++++ docs/contribute/docs-env.md | 28 +++++++++ .../{development-env.md => idom-env.md} | 12 +++- docs/django/{index.md => hooks.md} | 12 +++- docs/django/templatetags.md | 26 ++++++++ docs/how-to-use/initial-steps.md | 21 +++++++ .../{index.md => render-component.md} | 22 +------ docs/index.md | 2 - docs/installation/install.md | 4 +- mkdocs.yml | 38 ++++++----- requirements/build-docs.txt | 8 +-- 13 files changed, 179 insertions(+), 83 deletions(-) create mode 100644 docs/changelog/index.md create mode 100644 docs/contribute/docs-env.md rename docs/contribute/{development-env.md => idom-env.md} (67%) rename docs/django/{index.md => hooks.md} (67%) create mode 100644 docs/django/templatetags.md create mode 100644 docs/how-to-use/initial-steps.md rename docs/how-to-use/{index.md => render-component.md} (58%) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6c2584a..635a4ad5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,7 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + ## [Unreleased] -- Nothing (yet) +- Nothing (yet) -## [0.0.6] - 2022-04-16 +## [0.0.6] - 2022-04-30 ### Added -- Django-specific hooks! `use_websocket`, `use_scope`, and `use_location` are now available within the `django_idom.hooks` module. -- Documentation has been placed into a formal docs webpage. +- Django-specific hooks! `use_websocket`, `use_scope`, and `use_location` are now available within the `django_idom.hooks` module. +- Documentation has been placed into a formal docs webpage. ### Changed -- Bumped the minimum IDOM version to 0.38.0 -- `websocket` positional parameter within component functions has been removed. Functionally, it is replaced with `django_idom.hooks.use_websocket`. -- `idom_component` template tag has been renamed to `component` +- Bumped the minimum IDOM version to 0.38.0 +- `websocket` positional parameter within component functions has been removed. Functionally, it is replaced with `django_idom.hooks.use_websocket`. +- `idom_component` template tag has been renamed to `component` ## [0.0.5] - 2022-04-04 ### Changed -- Bumped the minimum IDOM version to 0.37.2 +- Bumped the minimum IDOM version to 0.37.2 ### Fixed -- ModuleNotFoundError: No module named `idom.core.proto` caused by IDOM 0.37.2 +- ModuleNotFoundError: No module named `idom.core.proto` caused by IDOM 0.37.2 ## [0.0.4] - 2022-03-05 ### Changed -- Bumped the minimum IDOM version to 0.37.1 +- Bumped the minimum IDOM version to 0.37.1 ## [0.0.3] - 2022-02-19 ### Changed -- Bumped the minimum IDOM version to 0.36.3 +- Bumped the minimum IDOM version to 0.36.3 ## [0.0.2] - 2022-01-30 ### Added -- Ability to declare the HTML class of the top-level component `div` -- `name = ...` parameter to IDOM HTTP paths for use with `django.urls.reverse()` -- Cache versioning to automatically invalidate old web module files from the cache backend -- Automatic pre-population of the IDOM component registry -- Type hinting for `IdomWebsocket` +- Ability to declare the HTML class of the top-level component `div` +- `name = ...` parameter to IDOM HTTP paths for use with `django.urls.reverse()` +- Cache versioning to automatically invalidate old web module files from the cache backend +- Automatic pre-population of the IDOM component registry +- Type hinting for `IdomWebsocket` ### Changed -- Fetching web modules from disk and/or cache is now fully async -- Static files are now contained within a `django_idom/` parent folder -- Upgraded IDOM to version `0.36.0` -- Minimum Django version required is now `4.0` -- Minimum Python version required is now `3.8` +- Fetching web modules from disk and/or cache is now fully async +- Static files are now contained within a `django_idom/` parent folder +- Upgraded IDOM to version `0.36.0` +- Minimum Django version required is now `4.0` +- Minimum Python version required is now `3.8` ### Removed -- `IDOM_WEB_MODULES_PATH` has been replaced with Django `include(...)` -- `IDOM_WS_MAX_RECONNECT_DELAY` has been renamed to `IDOM_WS_MAX_RECONNECT_TIMEOUT` -- `idom_web_modules` cache backend has been renamed to `idom` +- `IDOM_WEB_MODULES_PATH` has been replaced with Django `include(...)` +- `IDOM_WS_MAX_RECONNECT_DELAY` has been renamed to `IDOM_WS_MAX_RECONNECT_TIMEOUT` +- `idom_web_modules` cache backend has been renamed to `idom` ### Fixed -- Increase test timeout values to prevent false positives -- Windows compatibility for building Django-IDOM +- Increase test timeout values to prevent false positives +- Windows compatibility for building Django-IDOM ### Security -- Fixed potential directory travesal attack on the IDOM web modules URL +- Fixed potential directory travesal attack on the IDOM web modules URL ## [0.0.1] - 2021-08-18 ### Added -- Support for IDOM within the Django +- Support for IDOM within the Django [unreleased]: https://github.com/idom-team/django-idom/compare/0.0.2...HEAD -[0.0.5]: https://github.com/idom-team/django-idom/compare/0.0.5...0.0.6 +[0.0.6]: https://github.com/idom-team/django-idom/compare/0.0.5...0.0.6 [0.0.5]: https://github.com/idom-team/django-idom/compare/0.0.4...0.0.5 [0.0.4]: https://github.com/idom-team/django-idom/compare/0.0.3...0.0.4 [0.0.3]: https://github.com/idom-team/django-idom/compare/0.0.2...0.0.3 diff --git a/README.md b/README.md index 12c9dd83..ba0c19da 100644 --- a/README.md +++ b/README.md @@ -28,9 +28,11 @@ IDOM's ecosystem independent design allows components to be reused across a vari -Define your [IDOM](https://github.com/idom-team/idom) components within any Python module. To start out, we recommend creating a `components.py` file within your chosen **Django app**. +You'll need a file to define your [IDOM](https://github.com/idom-team/idom) components. This can be within any Python module, however, we recommend creating a `components.py` file within your chosen **Django app** to start out. -_Note: You are free to name and place this file anywhere. Ultimately, components are referenced by Python dotted path in `my-template.html`._ +!!! note + + You can name `components.py` anything you wish, and place it within any Python module. Ultimately, components are referenced by Python dotted path in `my-template.html`. So, at minimum this path needs to be valid to Python's `importlib`. ```python from idom import component, html @@ -53,6 +55,10 @@ Additonally, you can pass in keyworded arguments into your component function. In context this will look a bit like the following... +!!! note + + If you do not have a `templates` folder in your **Django app**, simply create one! Keep in mind, templates within this folder will not be detected unless you [add the corresponding **Django app** to `settings.py:INSTALLED_APPS`](https://docs.djangoproject.com/en/dev/ref/applications/#configuring-applications). + ```jinja {% load idom %} @@ -63,8 +69,6 @@ In context this will look a bit like the following... ``` -_Note: If you do not have a `templates` folder in your **Django app**, simply create one! Also, your `templates` folder will not be detected unless you [add the corresponding **Django app** to `settings.py:INSTALLED_APPS`](https://docs.djangoproject.com/en/dev/ref/applications/#configuring-applications)._ - --- diff --git a/docs/changelog/index.md b/docs/changelog/index.md new file mode 100644 index 00000000..f650d0c1 --- /dev/null +++ b/docs/changelog/index.md @@ -0,0 +1,14 @@ +--- +hide: + - navigation + - toc +--- + +!!! note + + The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +{% + include-markdown "../../CHANGELOG.md" + start="" +%} diff --git a/docs/contribute/docs-env.md b/docs/contribute/docs-env.md new file mode 100644 index 00000000..00ade941 --- /dev/null +++ b/docs/contribute/docs-env.md @@ -0,0 +1,28 @@ +If you plan to make documentation changes to this repository, you'll need to install the following dependencies first: + +- [Python 3.8+](https://www.python.org/downloads/) +- [Git](https://git-scm.com/downloads) + +Once done, you should clone this repository: + +```bash +git clone https://github.com/idom-team/django-idom.git +cd django-idom +``` + +Then, by running the command below you can: + +- Install an editable version of the documentation +- Self-host a test server for the documentation + +```bash +pip install -r ./requirements/build-docs.txt --upgrade +``` + +Finally, to verify that everything is working properly, you can manually run the docs preview webserver. + +```bash +mkdocs serve +``` + +Navigate to `http://127.0.0.1:8000` to view a preview of the documentation. diff --git a/docs/contribute/development-env.md b/docs/contribute/idom-env.md similarity index 67% rename from docs/contribute/development-env.md rename to docs/contribute/idom-env.md index a28b6fd6..2046a6c1 100644 --- a/docs/contribute/development-env.md +++ b/docs/contribute/idom-env.md @@ -1,5 +1,7 @@ If you plan to make code changes to this repository, you'll need to install the following dependencies first: +- [Python 3.8+](https://www.python.org/downloads/) +- [Git](https://git-scm.com/downloads) - [NPM](https://docs.npmjs.com/try-the-latest-stable-version-of-npm) for installing and managing Javascript - [ChromeDriver](https://chromedriver.chromium.org/downloads) for testing with @@ -15,11 +17,17 @@ cd django-idom Then, by running the command below you can: - Install an editable version of the Python code - - Download, build, and install Javascript dependencies ```bash pip install -e . -r requirements.txt ``` -Finally, to verify that everything is working properly, you'll want to run the test suite in the next step. +Finally, to verify that everything is working properly, you can manually run the development webserver. + +```bash +cd tests +python manage.py runserver +``` + +Navigate to `http://127.0.0.1:8000` to see if the tests are rendering correctly. diff --git a/docs/django/index.md b/docs/django/hooks.md similarity index 67% rename from docs/django/index.md rename to docs/django/hooks.md index dcd778e2..b330d2ed 100644 --- a/docs/django/index.md +++ b/docs/django/hooks.md @@ -14,9 +14,11 @@ def MyComponent(): return html.div(my_websocket) ``` +--- + ## Use Scope -This is a shortcut that returns the websocket's `scope`. +This is a shortcut that returns the Websocket's `scope`. ```python from idom import component, html @@ -28,11 +30,15 @@ def MyComponent(): return html.div(my_scope) ``` +--- + ## Use Location -Returns the URL that the websocket was opened from. +This is a shortcut that returns the Websocket's `path`. + +!!! note -_Note: This will [eventually be updated](https://github.com/idom-team/idom/issues/569) to return the client's current webpage URL. This will come in conjunction with Single Page Application (SPA) support._ + This hook will [eventually be updated](https://github.com/idom-team/idom/issues/569) to return the client's current webpage URL. This will come in conjunction with Single Page Application (SPA) support. ```python from idom import component, html diff --git a/docs/django/templatetags.md b/docs/django/templatetags.md new file mode 100644 index 00000000..200a7899 --- /dev/null +++ b/docs/django/templatetags.md @@ -0,0 +1,26 @@ +Integrated within Django IDOM, we bundle a template tag. Within this tag, you can pass in keyworded parameters. + +!!! note + + You can add as many components to a webpage as needed. Retrofitting legacy sites to use reactive components will typically involve many components. + + But keep in mind, in scenarios where you are trying to create a Single Page Application (SPA) within Django, you will only have one central component within your body tag as shown below. + +```jinja +{% load idom %} + + + + {% component "example.components.HelloComponent" recipient="World" %} + + +``` + +There are only two reserved parameters: `class` and `key` + +- `class` allows you to apply a HTML class to the top-level component div. This is useful for styling purposes. +- `key` allows you to force the component to use a [specific key value](https://idom-docs.herokuapp.com/docs/guides/understanding-idom/why-idom-needs-keys.html?highlight=key) within the front-end client. You typically won't need to change this. + +```jinja +{% component "example.components.HelloComponent" class="my-html-class" key=123 %} +``` diff --git a/docs/how-to-use/initial-steps.md b/docs/how-to-use/initial-steps.md new file mode 100644 index 00000000..672a8e0a --- /dev/null +++ b/docs/how-to-use/initial-steps.md @@ -0,0 +1,21 @@ +## Create a Django project and app + +We are going to assume you've [created a basic **Django project**](https://docs.djangoproject.com/en/dev/intro/tutorial01/) before, which also involves creating/installing at least one **Django app**. If not, check out this [9 minute video tutorial](https://www.youtube.com/watch?v=ZsJRXS_vrw0) created by _IDG TECHtalk_. + +Django provides you high flexibility on file structure for your apps. For the examples within this section, we will assume you've placed the files [generated by `startapp`](https://docs.djangoproject.com/en/dev/intro/tutorial01/#creating-the-polls-app) directly into your **Django project** folder. This is a common folder structure for small projects. + +!!! note + + Django-IDOM has no requirements on file structure. Organize everything as you wish. + +--- + +## Create a component + +### `components.py` + +{% + include-markdown "../../README.md" + start="" + end="" +%} diff --git a/docs/how-to-use/index.md b/docs/how-to-use/render-component.md similarity index 58% rename from docs/how-to-use/index.md rename to docs/how-to-use/render-component.md index 2697a869..2a834f87 100644 --- a/docs/how-to-use/index.md +++ b/docs/how-to-use/render-component.md @@ -1,23 +1,3 @@ -## Create a Django project and app - -We are going to assume you've [created a basic **Django project**](https://docs.djangoproject.com/en/dev/intro/tutorial01/) before, which also involves creating/installing at least one **Django app**. If not, check out this [9 minute video tutorial](https://www.youtube.com/watch?v=ZsJRXS_vrw0) created by _IDG TECHtalk_. - -Django provides you the flexibility to place your apps anywhere you wish. In the examples below, we are going to assume you've placed your apps directly into your **Django project** folder. This is a common folder structure for small projects. - ---- - -## Create a component - -### `components.py` - -{% - include-markdown "../../README.md" - start="" - end="" -%} - ---- - ## Reference your component ### `templates/my-template.html` @@ -47,7 +27,7 @@ def index(request): ### `urls.py` -To simplify things for this example, we are adding this view directly to your [**Django project**'s `urls.py`](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view) rather than adding to a **Django app**. +To simplify things for this example, we are adding this view directly to your [**Django project**'s `urls.py`](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view) rather than adding to a **Django app**'s `urls.py`. ```python from django.urls import path diff --git a/docs/index.md b/docs/index.md index f13eaa00..adf108eb 100644 --- a/docs/index.md +++ b/docs/index.md @@ -16,8 +16,6 @@ hide: end="" %} ---- - ## Resources {% diff --git a/docs/installation/install.md b/docs/installation/install.md index bcc698e5..3e37d8f7 100644 --- a/docs/installation/install.md +++ b/docs/installation/install.md @@ -60,7 +60,9 @@ urlpatterns = [ Register IDOM's websocket using `IDOM_WEBSOCKET_PATH`. -_Note: If you do not have an `asgi.py`, follow the [`channels` installation guide](https://channels.readthedocs.io/en/stable/installation.html)._ +!!! note + + If you do not have an `asgi.py`, follow the [`channels` installation guide](https://channels.readthedocs.io/en/stable/installation.html). ```python diff --git a/mkdocs.yml b/mkdocs.yml index 8c8465ec..22112d9c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -2,27 +2,33 @@ nav: - Home: index.md - Installation: installation/install.md - - How to Use: how-to-use/index.md - - Django-Only Features: django/index.md + - How to Use: + - Initial Steps: how-to-use/initial-steps.md + - Render your component: how-to-use/render-component.md + - Django-Only Features: + - Hooks: django/hooks.md + - Template Tags: django/templatetags.md - Contribute: - - Setup Development Enviroment: contribute/development-env.md + - Django-IDOM Environment: contribute/idom-env.md + - Documentation Environment: contribute/docs-env.md - Running Tests: contribute/running-tests.md + - Changelog: changelog/index.md theme: name: material palette: - - scheme: slate - toggle: - icon: material/toggle-switch - name: Switch to light mode - primary: deep-orange - accent: deep-orange - - scheme: default - toggle: - icon: material/toggle-switch-off-outline - name: Switch to dark mode - primary: deep-orange - accent: deep-orange + - scheme: slate + toggle: + icon: material/toggle-switch + name: Switch to light mode + primary: deep-orange + accent: deep-orange + - scheme: default + toggle: + icon: material/toggle-switch-off-outline + name: Switch to dark mode + primary: deep-orange + accent: deep-orange features: - navigation.instant - navigation.tracking @@ -42,6 +48,8 @@ markdown_extensions: emoji_generator: !!python/name:materialx.emoji.to_svg - pymdownx.highlight - pymdownx.superfences + - pymdownx.details + - admonition - attr_list plugins: diff --git a/requirements/build-docs.txt b/requirements/build-docs.txt index 48cd4d03..ce3fba84 100644 --- a/requirements/build-docs.txt +++ b/requirements/build-docs.txt @@ -1,4 +1,4 @@ -mkdocs==1.2.3 -mkdocs-git-revision-date-localized-plugin==1.0.0 -mkdocs-material==8.2.5 -mkdocs-include-markdown-plugin==3.3.0 \ No newline at end of file +mkdocs +mkdocs-git-revision-date-localized-plugin +mkdocs-material +mkdocs-include-markdown-plugin \ No newline at end of file From 96a16059b4e6e10dfc234ddb754e4d9478f1a83c Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 24 Apr 2022 17:03:24 -0700 Subject: [PATCH 19/53] cleanup --- CHANGELOG.md | 2 ++ README.md | 22 ++++++++++------------ docs/changelog/index.md | 9 +++------ docs/django/hooks.md | 6 +++--- docs/django/templatetags.md | 22 ++++++++++++---------- docs/how-to-use/initial-steps.md | 14 ++++++++------ docs/how-to-use/render-component.md | 16 +++++++++++----- docs/index.md | 18 +++--------------- docs/installation/install.md | 13 ++++++------- mkdocs.yml | 2 +- 10 files changed, 59 insertions(+), 65 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 635a4ad5..ce16f502 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,9 @@ All notable changes to this project will be documented in this file. + The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + You'll need a file to define your [IDOM](https://github.com/idom-team/idom) components. This can be within any Python module, however, we recommend creating a `components.py` file within your chosen **Django app** to start out. -!!! note - - You can name `components.py` anything you wish, and place it within any Python module. Ultimately, components are referenced by Python dotted path in `my-template.html`. So, at minimum this path needs to be valid to Python's `importlib`. + + ```python from idom import component, html @@ -43,21 +42,20 @@ def HelloComponent(recipient: str): return html.h1(f"Hello {recipient}!") ``` - + ## [`example_app/templates/my-template.html`](https://docs.djangoproject.com/en/dev/topics/templates/) - + -In your **Django app**'s `templates` folder, you can now add your IDOM component into your HTML using the `component` template tag using your dotted path to the component function. +In your **Django app**'s HTML located within your `templates` folder, you can now embed your IDOM component using the `component` template tag. Within this tag, you will need to type in your dotted path to the component function as the first argument. Additonally, you can pass in keyworded arguments into your component function. In context this will look a bit like the following... -!!! note - - If you do not have a `templates` folder in your **Django app**, simply create one! Keep in mind, templates within this folder will not be detected unless you [add the corresponding **Django app** to `settings.py:INSTALLED_APPS`](https://docs.djangoproject.com/en/dev/ref/applications/#configuring-applications). + + ```jinja {% load idom %} @@ -69,7 +67,7 @@ In context this will look a bit like the following... ``` - + --- diff --git a/docs/changelog/index.md b/docs/changelog/index.md index f650d0c1..a6e2f878 100644 --- a/docs/changelog/index.md +++ b/docs/changelog/index.md @@ -4,11 +4,8 @@ hide: - toc --- -!!! note +!!! note "Attribution" - The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + {% include-markdown "../../CHANGELOG.md" start="" end="" %} -{% - include-markdown "../../CHANGELOG.md" - start="" -%} +{% include-markdown "../../CHANGELOG.md" start="" %} diff --git a/docs/django/hooks.md b/docs/django/hooks.md index b330d2ed..820e562e 100644 --- a/docs/django/hooks.md +++ b/docs/django/hooks.md @@ -34,12 +34,12 @@ def MyComponent(): ## Use Location -This is a shortcut that returns the Websocket's `path`. - -!!! note +!!! note "Note: Use Location Behavior" This hook will [eventually be updated](https://github.com/idom-team/idom/issues/569) to return the client's current webpage URL. This will come in conjunction with Single Page Application (SPA) support. +This is a shortcut that returns the Websocket's `path`. + ```python from idom import component, html from django_idom.hooks import use_location diff --git a/docs/django/templatetags.md b/docs/django/templatetags.md index 200a7899..26fe5ff7 100644 --- a/docs/django/templatetags.md +++ b/docs/django/templatetags.md @@ -1,10 +1,4 @@ -Integrated within Django IDOM, we bundle a template tag. Within this tag, you can pass in keyworded parameters. - -!!! note - - You can add as many components to a webpage as needed. Retrofitting legacy sites to use reactive components will typically involve many components. - - But keep in mind, in scenarios where you are trying to create a Single Page Application (SPA) within Django, you will only have one central component within your body tag as shown below. +Integrated within Django IDOM, we bundle a template tag. Within this tag, you can pass in keyworded parameters directly into your component. ```jinja {% load idom %} @@ -16,11 +10,19 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca ``` -There are only two reserved parameters: `class` and `key` +!!! note "Note: Multiple Components on One Page" + + You can add as many components to a webpage as needed by using the template tag multiple times. Retrofitting legacy sites to use reactive components will typically involve many components on one page. + + But keep in mind, in scenarios where you are trying to create a Single Page Application (SPA) within Django, you will only have one central component within your body tag as shown below. + +--- + +For this template tag, there are only two reserved parameters: `class` and `key` - `class` allows you to apply a HTML class to the top-level component div. This is useful for styling purposes. -- `key` allows you to force the component to use a [specific key value](https://idom-docs.herokuapp.com/docs/guides/understanding-idom/why-idom-needs-keys.html?highlight=key) within the front-end client. You typically won't need to change this. +- `key` allows you to force the component to use a [specific key value](https://idom-docs.herokuapp.com/docs/guides/understanding-idom/why-idom-needs-keys.html?highlight=key). You typically won't need to set this. ```jinja -{% component "example.components.HelloComponent" class="my-html-class" key=123 %} +{% component "example.components.MyComponent" class="my-html-class" key=123 %} ``` diff --git a/docs/how-to-use/initial-steps.md b/docs/how-to-use/initial-steps.md index 672a8e0a..ab4305a4 100644 --- a/docs/how-to-use/initial-steps.md +++ b/docs/how-to-use/initial-steps.md @@ -4,7 +4,7 @@ We are going to assume you've [created a basic **Django project**](https://docs. Django provides you high flexibility on file structure for your apps. For the examples within this section, we will assume you've placed the files [generated by `startapp`](https://docs.djangoproject.com/en/dev/intro/tutorial01/#creating-the-polls-app) directly into your **Django project** folder. This is a common folder structure for small projects. -!!! note +!!! note "Note: Django Project Structure" Django-IDOM has no requirements on file structure. Organize everything as you wish. @@ -14,8 +14,10 @@ Django provides you high flexibility on file structure for your apps. For the ex ### `components.py` -{% - include-markdown "../../README.md" - start="" - end="" -%} +{% include-markdown "../../README.md" start="" end="" %} + +{% include-markdown "../../README.md" start="" end="" %} + +!!! note "Note: File Naming" + + You can name `components.py` anything you wish, and place it within any Python module. Ultimately, components are referenced by Python dotted path in `my-template.html`. So, at minimum this path needs to be valid to Python's `importlib`. diff --git a/docs/how-to-use/render-component.md b/docs/how-to-use/render-component.md index 2a834f87..cc9eb3ac 100644 --- a/docs/how-to-use/render-component.md +++ b/docs/how-to-use/render-component.md @@ -2,11 +2,17 @@ ### `templates/my-template.html` -{% - include-markdown "../../README.md" - start="" - end="" -%} +{% include-markdown "../../README.md" start="" end="" %} + +{% include-markdown "../../README.md" start="" end="" %} + +!!! note "Note: Django HTML Templates" + + If you do not have a `templates` folder in your **Django app**, simply create one! Keep in mind, templates within this folder will not be detected unless you [add the corresponding **Django app** to `settings.py:INSTALLED_APPS`](https://docs.djangoproject.com/en/dev/ref/applications/#configuring-applications). + +!!! note "Note: `recipient` Argument" + + Pay attention to how the function definition for HelloComponent (_in the previous example_) accepts a 'recipient' arguement. --- diff --git a/docs/index.md b/docs/index.md index adf108eb..83838442 100644 --- a/docs/index.md +++ b/docs/index.md @@ -4,22 +4,10 @@ hide: - toc --- -{% - include-markdown "../README.md" - start="" - end="" -%} +{% include-markdown "../README.md" start="" end="" %} -{% - include-markdown "../README.md" - start="" - end="" -%} +{% include-markdown "../README.md" start="" end="" %} ## Resources -{% - include-markdown "../README.md" - start="" - end="" -%} +{% include-markdown "../README.md" start="" end="" %} diff --git a/docs/installation/install.md b/docs/installation/install.md index 3e37d8f7..fb5cd5b7 100644 --- a/docs/installation/install.md +++ b/docs/installation/install.md @@ -33,10 +33,10 @@ CACHES = { # Maximum seconds between two reconnection attempts that would cause the client give up. # 0 will disable reconnection. -IDOM_WS_MAX_RECONNECT_TIMEOUT: int = 604800 +IDOM_WS_MAX_RECONNECT_TIMEOUT = 604800 # The URL for IDOM to serve websockets -IDOM_WEBSOCKET_URL: str = "idom/" +IDOM_WEBSOCKET_URL = "idom/" ``` --- @@ -60,12 +60,7 @@ urlpatterns = [ Register IDOM's websocket using `IDOM_WEBSOCKET_PATH`. -!!! note - - If you do not have an `asgi.py`, follow the [`channels` installation guide](https://channels.readthedocs.io/en/stable/installation.html). - ```python - import os from django.core.asgi import get_asgi_application @@ -87,3 +82,7 @@ application = ProtocolTypeRouter( } ) ``` + +!!! note "Note: Locating `asgi.py`" + + If you do not have an `asgi.py`, follow the [`channels` installation guide](https://channels.readthedocs.io/en/stable/installation.html). diff --git a/mkdocs.yml b/mkdocs.yml index 22112d9c..6197bee3 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -4,7 +4,7 @@ nav: - Installation: installation/install.md - How to Use: - Initial Steps: how-to-use/initial-steps.md - - Render your component: how-to-use/render-component.md + - Use Component with Django: how-to-use/render-component.md - Django-Only Features: - Hooks: django/hooks.md - Template Tags: django/templatetags.md From c937fcfa9afb4e8c13d124a74e7eb04c1491ab70 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 24 Apr 2022 18:59:08 -0700 Subject: [PATCH 20/53] cleanup gen2 --- CHANGELOG.md | 3 ++ README.md | 10 ++--- docs/contribute/running-tests.md | 2 +- docs/django/hooks.md | 8 ++-- docs/django/templatetags.md | 6 ++- docs/how-to-use/create-component.md | 11 +++++ docs/how-to-use/initial-steps.md | 23 ---------- docs/how-to-use/learn-more.md | 7 +++ docs/how-to-use/reference-component.md | 13 ++++++ docs/how-to-use/render-component.md | 36 +++------------ docs/how-to-use/start-project.md | 11 +++++ docs/installation/{install.md => index.md} | 52 ++++++++++++---------- mkdocs.yml | 10 +++-- src/django_idom/utils.py | 6 ++- 14 files changed, 103 insertions(+), 95 deletions(-) create mode 100644 docs/how-to-use/create-component.md delete mode 100644 docs/how-to-use/initial-steps.md create mode 100644 docs/how-to-use/learn-more.md create mode 100644 docs/how-to-use/reference-component.md create mode 100644 docs/how-to-use/start-project.md rename docs/installation/{install.md => index.md} (54%) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce16f502..704c43e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,9 @@ All notable changes to this project will be documented in this file. + The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + -You'll need a file to define your [IDOM](https://github.com/idom-team/idom) components. This can be within any Python module, however, we recommend creating a `components.py` file within your chosen **Django app** to start out. +You'll need a file to define your [IDOM](https://github.com/idom-team/idom) components. We recommend creating a `components.py` file within your chosen **Django app** to start out. -```python +```python title="components.py" from idom import component, html # Components are CamelCase by ReactJS convention @@ -50,14 +50,12 @@ def HelloComponent(recipient: str): In your **Django app**'s HTML located within your `templates` folder, you can now embed your IDOM component using the `component` template tag. Within this tag, you will need to type in your dotted path to the component function as the first argument. -Additonally, you can pass in keyworded arguments into your component function. - -In context this will look a bit like the following... +Additonally, you can pass in keyworded arguments into your component function. For example, pay attention to how the function definition for HelloComponent (_in the previous example_) accepts a 'recipient' argument. -```jinja +```jinja title="my-template.html" {% load idom %} diff --git a/docs/contribute/running-tests.md b/docs/contribute/running-tests.md index 1f054e54..287b9301 100644 --- a/docs/contribute/running-tests.md +++ b/docs/contribute/running-tests.md @@ -4,7 +4,7 @@ This repo uses [Nox](https://nox.thea.codes/en/stable/) to run scripts which can nox -s test ``` -To run the tests using a headless browser: +If you want to run the tests in the background (headless): ``` nox -s test -- --headless diff --git a/docs/django/hooks.md b/docs/django/hooks.md index 820e562e..e9ea1edb 100644 --- a/docs/django/hooks.md +++ b/docs/django/hooks.md @@ -4,7 +4,7 @@ You can fetch the Django Channels websocket at any time by using `use_websocket`. -```python +```python title="components.py" from idom import component, html from django_idom.hooks import use_websocket @@ -20,7 +20,7 @@ def MyComponent(): This is a shortcut that returns the Websocket's `scope`. -```python +```python title="components.py" from idom import component, html from django_idom.hooks import use_scope @@ -36,11 +36,11 @@ def MyComponent(): !!! note "Note: Use Location Behavior" - This hook will [eventually be updated](https://github.com/idom-team/idom/issues/569) to return the client's current webpage URL. This will come in conjunction with Single Page Application (SPA) support. + This hook will [eventually be updated](https://github.com/idom-team/idom/issues/569) to return the client's current webpage URL. This will come in alongside our built-in Single Page Application (SPA) support. This is a shortcut that returns the Websocket's `path`. -```python +```python title="components.py" from idom import component, html from django_idom.hooks import use_location diff --git a/docs/django/templatetags.md b/docs/django/templatetags.md index 26fe5ff7..67704511 100644 --- a/docs/django/templatetags.md +++ b/docs/django/templatetags.md @@ -1,6 +1,6 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you can pass in keyworded parameters directly into your component. -```jinja +```jinja title="my-template.html" {% load idom %} @@ -23,6 +23,8 @@ For this template tag, there are only two reserved parameters: `class` and `key` - `class` allows you to apply a HTML class to the top-level component div. This is useful for styling purposes. - `key` allows you to force the component to use a [specific key value](https://idom-docs.herokuapp.com/docs/guides/understanding-idom/why-idom-needs-keys.html?highlight=key). You typically won't need to set this. -```jinja +```jinja title="my-template.html" +... {% component "example.components.MyComponent" class="my-html-class" key=123 %} +... ``` diff --git a/docs/how-to-use/create-component.md b/docs/how-to-use/create-component.md new file mode 100644 index 00000000..abb702db --- /dev/null +++ b/docs/how-to-use/create-component.md @@ -0,0 +1,11 @@ +{% include-markdown "../../README.md" start="" end="" %} + +{% include-markdown "../../README.md" start="" end="" %} + +!!! note "Note: File Naming" + + You can name `components.py` anything you wish, and place it within any Python module. + + You should determine the best way to sort your Python modules and component functions to fit your needs. + + Ultimately, components are referenced by Python dotted path in `my-template.html`. So, at minimum this path needs to be valid to Python's `importlib`. diff --git a/docs/how-to-use/initial-steps.md b/docs/how-to-use/initial-steps.md deleted file mode 100644 index ab4305a4..00000000 --- a/docs/how-to-use/initial-steps.md +++ /dev/null @@ -1,23 +0,0 @@ -## Create a Django project and app - -We are going to assume you've [created a basic **Django project**](https://docs.djangoproject.com/en/dev/intro/tutorial01/) before, which also involves creating/installing at least one **Django app**. If not, check out this [9 minute video tutorial](https://www.youtube.com/watch?v=ZsJRXS_vrw0) created by _IDG TECHtalk_. - -Django provides you high flexibility on file structure for your apps. For the examples within this section, we will assume you've placed the files [generated by `startapp`](https://docs.djangoproject.com/en/dev/intro/tutorial01/#creating-the-polls-app) directly into your **Django project** folder. This is a common folder structure for small projects. - -!!! note "Note: Django Project Structure" - - Django-IDOM has no requirements on file structure. Organize everything as you wish. - ---- - -## Create a component - -### `components.py` - -{% include-markdown "../../README.md" start="" end="" %} - -{% include-markdown "../../README.md" start="" end="" %} - -!!! note "Note: File Naming" - - You can name `components.py` anything you wish, and place it within any Python module. Ultimately, components are referenced by Python dotted path in `my-template.html`. So, at minimum this path needs to be valid to Python's `importlib`. diff --git a/docs/how-to-use/learn-more.md b/docs/how-to-use/learn-more.md new file mode 100644 index 00000000..2c750d59 --- /dev/null +++ b/docs/how-to-use/learn-more.md @@ -0,0 +1,7 @@ +# :confetti_ball: Congratulations :confetti_ball: + +If you followed the previous steps, you've now created a basic "Hello World" component. + +The docs you are reading only cover topics specific to Django integration, combined with basic examples. + +However, **IDOM** contains advanced features to add interactivity to your components through events and hooks. Check out the [IDOM Core Documentation](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/index.html) to learn more about what features IDOM has to offer! diff --git a/docs/how-to-use/reference-component.md b/docs/how-to-use/reference-component.md new file mode 100644 index 00000000..f4f5d2f7 --- /dev/null +++ b/docs/how-to-use/reference-component.md @@ -0,0 +1,13 @@ +{% include-markdown "../../README.md" start="" end="" %} + +{% include-markdown "../../README.md" start="" end="" %} + +!!! note "Note: Keyworded Arguments" + + You can only pass in **keyworded arguments** within the template tag. Due to technical limitations, **positional arguments** are not supported at this time. + + Also, be mindful of [reserved keywords](../django/templatetags.md). + +!!! note "Note: Django HTML Templates" + + If you do not have a `templates` folder in your **Django app**, you can simply create one! Keep in mind, templates within this folder will not be detected by Django unless you [add the corresponding **Django app** to `settings.py:INSTALLED_APPS`](https://docs.djangoproject.com/en/dev/ref/applications/#configuring-applications). diff --git a/docs/how-to-use/render-component.md b/docs/how-to-use/render-component.md index cc9eb3ac..0022c474 100644 --- a/docs/how-to-use/render-component.md +++ b/docs/how-to-use/render-component.md @@ -1,41 +1,17 @@ -## Reference your component +We will assume you've [created a Django View](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view) before, but we'll give a simple example below. -### `templates/my-template.html` +Within your **Django app**'s [`views.py` file](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view), you'll need to create a function to render the HTML template that has some IDOM components within it. -{% include-markdown "../../README.md" start="" end="" %} - -{% include-markdown "../../README.md" start="" end="" %} - -!!! note "Note: Django HTML Templates" - - If you do not have a `templates` folder in your **Django app**, simply create one! Keep in mind, templates within this folder will not be detected unless you [add the corresponding **Django app** to `settings.py:INSTALLED_APPS`](https://docs.djangoproject.com/en/dev/ref/applications/#configuring-applications). - -!!! note "Note: `recipient` Argument" - - Pay attention to how the function definition for HelloComponent (_in the previous example_) accepts a 'recipient' arguement. - ---- - -## Render your component - -We will also assume you've [created a Django View](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view) before, but we'll give a simple example below. - -### `views.py` - -This is your **Django app**'s [view file](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view). This function will render your HTML template, which includes your IDOM component. - -```python +```python title="views.py" from django.shortcuts import render def index(request): return render(request, "my-template.html") ``` -### `urls.py` - -To simplify things for this example, we are adding this view directly to your [**Django project**'s `urls.py`](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view) rather than adding to a **Django app**'s `urls.py`. +To simplify things for this example, we will add this view directly to your [**Django project**'s `urls.py`](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view) rather than adding to a **Django app**'s `urls.py`. -```python +```python title="urls.py" from django.urls import path from . import views @@ -44,4 +20,4 @@ urlpatterns = [ ] ``` -Now, navigate to `http://127.0.0.1:8000/example/` to see your component print out "Hello World". +Now, navigate to `http://127.0.0.1:8000/example/`. If you copy-pasted the component from the previous example, you will now see your component display "Hello World". diff --git a/docs/how-to-use/start-project.md b/docs/how-to-use/start-project.md new file mode 100644 index 00000000..62d601b7 --- /dev/null +++ b/docs/how-to-use/start-project.md @@ -0,0 +1,11 @@ +If you've reached this point, you should have already [installed Django-IDOM](../installation/index.md) through the previous steps. + +Now, we are going to assume you have at least [a basic **Django project**](https://docs.djangoproject.com/en/dev/intro/tutorial01/) configured, which also involves creating/installing at least one **Django app**. If not, check out this [9 minute video tutorial](https://www.youtube.com/watch?v=ZsJRXS_vrw0) created by _IDG TECHtalk_. + +Django provides you high flexibility on file structure for your apps. For the examples within this section, we will assume you've placed the files [generated by `startapp`](https://docs.djangoproject.com/en/dev/intro/tutorial01/#creating-the-polls-app) directly into your **Django project** folder. + +This is a common folder structure for small projects. + +!!! note "Note: Django Project Structure" + + Django-IDOM has no requirements on file structure. Organize everything as you wish. diff --git a/docs/installation/install.md b/docs/installation/index.md similarity index 54% rename from docs/installation/install.md rename to docs/installation/index.md index fb5cd5b7..defe3677 100644 --- a/docs/installation/install.md +++ b/docs/installation/index.md @@ -1,4 +1,4 @@ -## Install `django-idom` from PyPI +## Install from PyPI ```bash pip install django-idom @@ -10,34 +10,38 @@ You'll also need to modify a few files in your Django project... ## Configure [`settings.py`](https://docs.djangoproject.com/en/dev/topics/settings/) -In your settings you'll need to add `channels` and `django_idom` to [`INSTALLED_APPS`](https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-INSTALLED_APPS). +In your settings you'll need to add `django_idom` to [`INSTALLED_APPS`](https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-INSTALLED_APPS). -```python +```python title="settings.py" INSTALLED_APPS = [ - ..., - "channels", - "django_idom", + "django_idom", + ... ] - -# Ensure ASGI_APPLICATION is set properly based on your project name! -ASGI_APPLICATION = "my_django_project.asgi.application" ``` -**Optional:** You can also configure IDOM settings. +!!! note "Optional: Configure IDOM settings" -```python -# If "idom" cache is not configured, then we'll use "default" instead -CACHES = { - "idom": {"BACKEND": ...}, -} + ```python title="settings.py" + # If "idom" cache is not configured, then we'll use "default" instead + CACHES = { + "idom": {"BACKEND": ...}, + } -# Maximum seconds between two reconnection attempts that would cause the client give up. -# 0 will disable reconnection. -IDOM_WS_MAX_RECONNECT_TIMEOUT = 604800 + # Maximum seconds between two reconnection attempts that would cause the client give up. + # 0 will disable reconnection. + IDOM_WS_MAX_RECONNECT_TIMEOUT = 604800 -# The URL for IDOM to serve websockets -IDOM_WEBSOCKET_URL = "idom/" -``` + # The URL for IDOM to serve websockets + IDOM_WEBSOCKET_URL = "idom/" + ``` + +!!! note "Note: Configuring New Django Projects" + + If you haven't enabled ASGI on your Django project yet, don't forget to add `channels` to `INSTALLED_APPS` and set your `ASGI_APPLICATION`. + ```python title="settings.py" + INSTALLED_APPS = [..., "channels", ...] + ASGI_APPLICATION = "my_django_project.asgi.application" + ``` --- @@ -45,7 +49,7 @@ IDOM_WEBSOCKET_URL = "idom/" Add IDOM HTTP paths to your `urlpatterns`. -```python +```python title="urls.py" from django.urls import include, path urlpatterns = [ @@ -58,9 +62,9 @@ urlpatterns = [ ## Configure [`asgi.py`](https://docs.djangoproject.com/en/dev/howto/deployment/asgi/) -Register IDOM's websocket using `IDOM_WEBSOCKET_PATH`. +Register IDOM's Websocket using `IDOM_WEBSOCKET_PATH`. -```python +```python title="asgi.py" import os from django.core.asgi import get_asgi_application diff --git a/mkdocs.yml b/mkdocs.yml index 6197bee3..1bb16763 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,10 +1,13 @@ --- nav: - Home: index.md - - Installation: installation/install.md + - Installation: installation/index.md - How to Use: - - Initial Steps: how-to-use/initial-steps.md - - Use Component with Django: how-to-use/render-component.md + - 1. Create a Django project: how-to-use/start-project.md + - 2. Create a Component: how-to-use/create-component.md + - 3. Reference your Component: how-to-use/reference-component.md + - 4. Render your Component: how-to-use/render-component.md + - 5. Learn More: how-to-use/learn-more.md - Django-Only Features: - Hooks: django/hooks.md - Template Tags: django/templatetags.md @@ -33,7 +36,6 @@ theme: - navigation.instant - navigation.tracking - navigation.tabs - - navigation.sections - toc.integrate - navigation.top diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py index 1a31b0bb..3ec504b6 100644 --- a/src/django_idom/utils.py +++ b/src/django_idom/utils.py @@ -100,6 +100,7 @@ def _get_components(self, templates: Set) -> Set: for template in templates: with contextlib.suppress(Exception): with open(template, "r", encoding="utf-8") as template_file: + # TODO: Only match if the template also contains {% load idom %} match = COMPONENT_REGEX.findall(template_file.read()) if not match: continue @@ -115,4 +116,7 @@ def _register_components(self, components: Set) -> None: _register_component(component) _logger.info("IDOM has registered component %s", component) except Exception: - _logger.warning("IDOM failed to register component %s", component) + _logger.exception( + "IDOM failed to register component %s! This component path may not be valid, or an error may have occurred while importing.", + component, + ) From 9d83b00681b5f16507f6bb0706f64dd10e675bdd Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 24 Apr 2022 19:00:37 -0700 Subject: [PATCH 21/53] templatetags -> templatetag --- docs/django/{templatetags.md => templatetag.md} | 0 docs/how-to-use/reference-component.md | 2 +- mkdocs.yml | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename docs/django/{templatetags.md => templatetag.md} (100%) diff --git a/docs/django/templatetags.md b/docs/django/templatetag.md similarity index 100% rename from docs/django/templatetags.md rename to docs/django/templatetag.md diff --git a/docs/how-to-use/reference-component.md b/docs/how-to-use/reference-component.md index f4f5d2f7..078f6478 100644 --- a/docs/how-to-use/reference-component.md +++ b/docs/how-to-use/reference-component.md @@ -6,7 +6,7 @@ You can only pass in **keyworded arguments** within the template tag. Due to technical limitations, **positional arguments** are not supported at this time. - Also, be mindful of [reserved keywords](../django/templatetags.md). + Also, be mindful of [reserved keywords](../django/templatetag.md). !!! note "Note: Django HTML Templates" diff --git a/mkdocs.yml b/mkdocs.yml index 1bb16763..1a7909ae 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -10,7 +10,7 @@ nav: - 5. Learn More: how-to-use/learn-more.md - Django-Only Features: - Hooks: django/hooks.md - - Template Tags: django/templatetags.md + - Template Tag: django/templatetag.md - Contribute: - Django-IDOM Environment: contribute/idom-env.md - Documentation Environment: contribute/docs-env.md From 9fcc082f61cced5e5a43bfccc950685059d37855 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 24 Apr 2022 19:01:56 -0700 Subject: [PATCH 22/53] quick start -> at a glance --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2145bee8..044c4aea 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ IDOM's ecosystem independent design allows components to be reused across a vari --- -# Quick Start +# At a Glance ## `example_app/components.py` From 87a900a2f41f0ff58e144de8efc37b70a4fe241a Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 25 Apr 2022 11:25:19 -0700 Subject: [PATCH 23/53] collapsible everything! --- README.md | 6 +-- docs/django/hooks.md | 4 +- docs/django/templatetag.md | 6 ++- docs/how-to-use/create-component.md | 10 ++++- docs/how-to-use/initial-steps.md | 21 ++++++++++ docs/how-to-use/learn-more.md | 8 ++-- docs/how-to-use/reference-component.md | 18 ++++++--- docs/how-to-use/render-component.md | 12 ++++-- docs/how-to-use/start-project.md | 11 ------ docs/installation/index.md | 53 ++++++++++++++++---------- mkdocs.yml | 6 +-- 11 files changed, 102 insertions(+), 53 deletions(-) create mode 100644 docs/how-to-use/initial-steps.md delete mode 100644 docs/how-to-use/start-project.md diff --git a/README.md b/README.md index 044c4aea..902e5a48 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ IDOM's ecosystem independent design allows components to be reused across a vari # At a Glance -## `example_app/components.py` +## `my_app/components.py` @@ -44,7 +44,7 @@ def HelloComponent(recipient: str): -## [`example_app/templates/my-template.html`](https://docs.djangoproject.com/en/dev/topics/templates/) +## [`my_app/templates/my-template.html`](https://docs.djangoproject.com/en/dev/topics/templates/) @@ -60,7 +60,7 @@ Additonally, you can pass in keyworded arguments into your component function. F - {% component "django_project.example_app.components.HelloComponent" recipient="World" %} + {% component "example_project.my_app.components.HelloComponent" recipient="World" %} ``` diff --git a/docs/django/hooks.md b/docs/django/hooks.md index e9ea1edb..d3ea39aa 100644 --- a/docs/django/hooks.md +++ b/docs/django/hooks.md @@ -34,9 +34,9 @@ def MyComponent(): ## Use Location -!!! note "Note: Use Location Behavior" +??? info "This hook's behavior will be changed in a future update" - This hook will [eventually be updated](https://github.com/idom-team/idom/issues/569) to return the client's current webpage URL. This will come in alongside our built-in Single Page Application (SPA) support. + This hook will [eventually be updated](https://github.com/idom-team/idom/issues/569) to return the client's current webpage URL. This will come in alongside our built-in Single Page Application (SPA) support. This is a shortcut that returns the Websocket's `path`. diff --git a/docs/django/templatetag.md b/docs/django/templatetag.md index 67704511..9dc98ad7 100644 --- a/docs/django/templatetag.md +++ b/docs/django/templatetag.md @@ -10,12 +10,16 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca ``` -!!! note "Note: Multiple Components on One Page" + + +??? question "Can I use multiple components on one page?" You can add as many components to a webpage as needed by using the template tag multiple times. Retrofitting legacy sites to use reactive components will typically involve many components on one page. But keep in mind, in scenarios where you are trying to create a Single Page Application (SPA) within Django, you will only have one central component within your body tag as shown below. + + --- For this template tag, there are only two reserved parameters: `class` and `key` diff --git a/docs/how-to-use/create-component.md b/docs/how-to-use/create-component.md index abb702db..dfdca830 100644 --- a/docs/how-to-use/create-component.md +++ b/docs/how-to-use/create-component.md @@ -1,10 +1,16 @@ +???+ summary + + Create a component function using our decorator. + +--- + {% include-markdown "../../README.md" start="" end="" %} {% include-markdown "../../README.md" start="" end="" %} -!!! note "Note: File Naming" +??? question "What do I name my component files and functions?" - You can name `components.py` anything you wish, and place it within any Python module. + You can have full freedom in where you name or place your files/functions within IDOM. You should determine the best way to sort your Python modules and component functions to fit your needs. diff --git a/docs/how-to-use/initial-steps.md b/docs/how-to-use/initial-steps.md new file mode 100644 index 00000000..ea8011fa --- /dev/null +++ b/docs/how-to-use/initial-steps.md @@ -0,0 +1,21 @@ +???+ summary + + Set up a Django Project with at least one app. + +--- + +If you've reached this point, you should have already [installed Django-IDOM](../installation/index.md) through the previous steps. + +Django provides you high flexibility on where your apps can reside. + +However, for the examples within this section we will assume you've placed the files [generated by `startapp`](https://docs.djangoproject.com/en/dev/intro/tutorial01/#creating-the-polls-app) directly into your **Django project** folder. This is common for small projects. + +??? Info "Starting from scratch" + + {% include-markdown "../installation/index.md" start="" end="" %} + + Afterwards, make sure to follow the [Django-IDOM installation instructions](../installation/index.md). + +??? question "How do I organize my Django project for IDOM?" + + Django-IDOM has no requirements on file structure. Organize everything as you wish, just like any other Django project. diff --git a/docs/how-to-use/learn-more.md b/docs/how-to-use/learn-more.md index 2c750d59..1b2286f9 100644 --- a/docs/how-to-use/learn-more.md +++ b/docs/how-to-use/learn-more.md @@ -1,7 +1,9 @@ # :confetti_ball: Congratulations :confetti_ball: -If you followed the previous steps, you've now created a basic "Hello World" component. +If you followed the previous steps, you've now created a "Hello World" component! -The docs you are reading only cover topics specific to Django integration, combined with basic examples. +The docs you are reading only covers our Django integration. -However, **IDOM** contains advanced features to add interactivity to your components through events and hooks. Check out the [IDOM Core Documentation](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/index.html) to learn more about what features IDOM has to offer! +Check out the [IDOM Core Documentation](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/index.html) to learn more about our advanced features, such as adding interactivity through events and hooks! + +[Learn More](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/index.html){ .md-button .md-button--primary} diff --git a/docs/how-to-use/reference-component.md b/docs/how-to-use/reference-component.md index 078f6478..df653c88 100644 --- a/docs/how-to-use/reference-component.md +++ b/docs/how-to-use/reference-component.md @@ -1,13 +1,21 @@ +???+ summary + + Use our template tag in your HTML. + +--- + {% include-markdown "../../README.md" start="" end="" %} {% include-markdown "../../README.md" start="" end="" %} -!!! note "Note: Keyworded Arguments" +{% include-markdown "../django/templatetag.md" start="" end="" %} + +??? question "Can I use positional arguments instead of keyworded arguments?" - You can only pass in **keyworded arguments** within the template tag. Due to technical limitations, **positional arguments** are not supported at this time. + You can only pass in **keyworded arguments** within the template tag. Due to technical limitations, **positional arguments** are not supported at this time. - Also, be mindful of [reserved keywords](../django/templatetag.md). + Also, be mindful of [reserved keywords](../django/templatetag.md). -!!! note "Note: Django HTML Templates" +??? question "Where is my templates folder?" - If you do not have a `templates` folder in your **Django app**, you can simply create one! Keep in mind, templates within this folder will not be detected by Django unless you [add the corresponding **Django app** to `settings.py:INSTALLED_APPS`](https://docs.djangoproject.com/en/dev/ref/applications/#configuring-applications). + If you do not have a `templates` folder in your **Django app**, you can simply create one! Keep in mind, templates within this folder will not be detected by Django unless you [add the corresponding **Django app** to `settings.py:INSTALLED_APPS`](https://docs.djangoproject.com/en/dev/ref/applications/#configuring-applications). diff --git a/docs/how-to-use/render-component.md b/docs/how-to-use/render-component.md index 0022c474..c7a45a11 100644 --- a/docs/how-to-use/render-component.md +++ b/docs/how-to-use/render-component.md @@ -1,6 +1,12 @@ +???+ summary + + Render the template with a view. + +--- + We will assume you've [created a Django View](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view) before, but we'll give a simple example below. -Within your **Django app**'s [`views.py` file](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view), you'll need to create a function to render the HTML template that has some IDOM components within it. +Within your **Django app**'s [`views.py` file](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view), you'll need to create a function to render the HTML template containing your IDOM components. ```python title="views.py" from django.shortcuts import render @@ -9,11 +15,11 @@ def index(request): return render(request, "my-template.html") ``` -To simplify things for this example, we will add this view directly to your [**Django project**'s `urls.py`](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view) rather than adding to a **Django app**'s `urls.py`. +To simplify things for this example, we will add this new view directly to your [**Django project**'s `urls.py`](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view) rather than adding to a **Django app**'s `urls.py`. ```python title="urls.py" from django.urls import path -from . import views +from example_project.my_app import views urlpatterns = [ path("example/", views.index), diff --git a/docs/how-to-use/start-project.md b/docs/how-to-use/start-project.md deleted file mode 100644 index 62d601b7..00000000 --- a/docs/how-to-use/start-project.md +++ /dev/null @@ -1,11 +0,0 @@ -If you've reached this point, you should have already [installed Django-IDOM](../installation/index.md) through the previous steps. - -Now, we are going to assume you have at least [a basic **Django project**](https://docs.djangoproject.com/en/dev/intro/tutorial01/) configured, which also involves creating/installing at least one **Django app**. If not, check out this [9 minute video tutorial](https://www.youtube.com/watch?v=ZsJRXS_vrw0) created by _IDG TECHtalk_. - -Django provides you high flexibility on file structure for your apps. For the examples within this section, we will assume you've placed the files [generated by `startapp`](https://docs.djangoproject.com/en/dev/intro/tutorial01/#creating-the-polls-app) directly into your **Django project** folder. - -This is a common folder structure for small projects. - -!!! note "Note: Django Project Structure" - - Django-IDOM has no requirements on file structure. Organize everything as you wish. diff --git a/docs/installation/index.md b/docs/installation/index.md index defe3677..5766ea78 100644 --- a/docs/installation/index.md +++ b/docs/installation/index.md @@ -1,3 +1,9 @@ + + +We are going to assume you have created [a basic **Django project**](https://docs.djangoproject.com/en/dev/intro/tutorial01/), which also involves generating/installing at least one **Django app**. If not, check out this [9 minute video tutorial](https://www.youtube.com/watch?v=ZsJRXS_vrw0) created by _IDG TECHtalk_. + + + ## Install from PyPI ```bash @@ -19,29 +25,36 @@ INSTALLED_APPS = [ ] ``` -!!! note "Optional: Configure IDOM settings" +??? note "Configure IDOM settings (Optional)" + + Below are a handful of values you can change within `settings.py` to modify the behavior of IDOM. + + ```python title="settings.py" + # If "idom" cache is not configured, then we'll use "default" instead + CACHES = { + "idom": {"BACKEND": ...}, + } - ```python title="settings.py" - # If "idom" cache is not configured, then we'll use "default" instead - CACHES = { - "idom": {"BACKEND": ...}, - } + # Maximum seconds between two reconnection attempts that would cause the client give up. + # 0 will disable reconnection. + IDOM_WS_MAX_RECONNECT_TIMEOUT = 604800 - # Maximum seconds between two reconnection attempts that would cause the client give up. - # 0 will disable reconnection. - IDOM_WS_MAX_RECONNECT_TIMEOUT = 604800 + # The URL for IDOM to serve websockets + IDOM_WEBSOCKET_URL = "idom/" + ``` - # The URL for IDOM to serve websockets - IDOM_WEBSOCKET_URL = "idom/" - ``` +??? warning "Enabling ASGI on Django (Required)" -!!! note "Note: Configuring New Django Projects" + Django-IDOM requires ASGI in order to use Websockets. - If you haven't enabled ASGI on your Django project yet, don't forget to add `channels` to `INSTALLED_APPS` and set your `ASGI_APPLICATION`. - ```python title="settings.py" - INSTALLED_APPS = [..., "channels", ...] - ASGI_APPLICATION = "my_django_project.asgi.application" - ``` + If you haven't [enabled ASGI](https://channels.readthedocs.io/en/stable/installation.html) on your Django project yet, you'll need to add `channels` to `INSTALLED_APPS` and set your `ASGI_APPLICATION` variable. + ```python title="settings.py" + INSTALLED_APPS = [ + "channels", + ... + ] + ASGI_APPLICATION = "example_project.asgi.application" + ``` --- @@ -69,7 +82,7 @@ import os from django.core.asgi import get_asgi_application # Ensure DJANGO_SETTINGS_MODULE is set properly based on your project name! -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "my_django_project.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example_project.settings") django_asgi_app = get_asgi_application() from channels.auth import AuthMiddlewareStack @@ -87,6 +100,6 @@ application = ProtocolTypeRouter( ) ``` -!!! note "Note: Locating `asgi.py`" +??? question "Where is my asgi.py?" If you do not have an `asgi.py`, follow the [`channels` installation guide](https://channels.readthedocs.io/en/stable/installation.html). diff --git a/mkdocs.yml b/mkdocs.yml index 1a7909ae..860427cd 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -3,10 +3,10 @@ nav: - Home: index.md - Installation: installation/index.md - How to Use: - - 1. Create a Django project: how-to-use/start-project.md + - 1. Initial Steps: how-to-use/initial-steps.md - 2. Create a Component: how-to-use/create-component.md - - 3. Reference your Component: how-to-use/reference-component.md - - 4. Render your Component: how-to-use/render-component.md + - 3. Reference Your Component: how-to-use/reference-component.md + - 4. Render Your Component: how-to-use/render-component.md - 5. Learn More: how-to-use/learn-more.md - Django-Only Features: - Hooks: django/hooks.md From 30b8f5ca62e9a90c3daba236121db684e6e08bdc Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 25 Apr 2022 12:02:30 -0700 Subject: [PATCH 24/53] 0.0.6 -> 1.0.0 --- CHANGELOG.md | 11 +++++++---- src/django_idom/__init__.py | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 704c43e3..5343a3eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,7 @@ Types of changes are to be listed in this order - Nothing (yet) -## [0.0.6] - 2022-04-30 +## [1.0.0] - 2022-05-22 ### Added @@ -34,9 +34,12 @@ Types of changes are to be listed in this order ### Changed -- Bumped the minimum IDOM version to 0.38.0 -- `websocket` positional parameter within component functions has been removed. Functionally, it is replaced with `django_idom.hooks.use_websocket`. - `idom_component` template tag has been renamed to `component` +- Bumped the minimum IDOM version to 0.38.0 + +### Removed + +- `websocket` parameter for components has been removed. Functionally, it is replaced with `django_idom.hooks.use_websocket`. ## [0.0.5] - 2022-04-04 @@ -100,7 +103,7 @@ Types of changes are to be listed in this order - Support for IDOM within the Django [unreleased]: https://github.com/idom-team/django-idom/compare/0.0.2...HEAD -[0.0.6]: https://github.com/idom-team/django-idom/compare/0.0.5...0.0.6 +[1.0.0]: https://github.com/idom-team/django-idom/compare/0.0.5...1.0.0 [0.0.5]: https://github.com/idom-team/django-idom/compare/0.0.4...0.0.5 [0.0.4]: https://github.com/idom-team/django-idom/compare/0.0.3...0.0.4 [0.0.3]: https://github.com/idom-team/django-idom/compare/0.0.2...0.0.3 diff --git a/src/django_idom/__init__.py b/src/django_idom/__init__.py index 365655a7..af2dec38 100644 --- a/src/django_idom/__init__.py +++ b/src/django_idom/__init__.py @@ -3,5 +3,5 @@ from .websocket.paths import IDOM_WEBSOCKET_PATH -__version__ = "0.0.6" +__version__ = "1.0.0" __all__ = ["IDOM_WEBSOCKET_PATH", "IdomWebsocket", "hooks"] From ad9b6722296c674b3d61aa3fe2b8e115f2897d51 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 25 Apr 2022 12:14:00 -0700 Subject: [PATCH 25/53] note cleanup --- docs/django/hooks.md | 2 +- docs/django/templatetag.md | 9 +++++++++ docs/how-to-use/reference-component.md | 6 +----- docs/installation/index.md | 26 +++++++++++++------------- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/docs/django/hooks.md b/docs/django/hooks.md index d3ea39aa..a024e816 100644 --- a/docs/django/hooks.md +++ b/docs/django/hooks.md @@ -36,7 +36,7 @@ def MyComponent(): ??? info "This hook's behavior will be changed in a future update" - This hook will [eventually be updated](https://github.com/idom-team/idom/issues/569) to return the client's current webpage URL. This will come in alongside our built-in Single Page Application (SPA) support. + This hook will eventually be updated to return the client's current webpage URL. This will come in alongside our built-in [Single Page Application (SPA) support](https://github.com/idom-team/idom/issues/569). This is a shortcut that returns the Websocket's `path`. diff --git a/docs/django/templatetag.md b/docs/django/templatetag.md index 9dc98ad7..97fc834f 100644 --- a/docs/django/templatetag.md +++ b/docs/django/templatetag.md @@ -19,6 +19,15 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca But keep in mind, in scenarios where you are trying to create a Single Page Application (SPA) within Django, you will only have one central component within your body tag as shown below. + + +??? question "Can I use positional arguments instead of keyworded arguments?" + + You can only pass in **keyworded arguments** within the template tag. Due to technical limitations, **positional arguments** are not supported at this time. + + Also, be mindful of [reserved keywords](../django/templatetag.md). + + --- diff --git a/docs/how-to-use/reference-component.md b/docs/how-to-use/reference-component.md index df653c88..393c8b80 100644 --- a/docs/how-to-use/reference-component.md +++ b/docs/how-to-use/reference-component.md @@ -10,11 +10,7 @@ {% include-markdown "../django/templatetag.md" start="" end="" %} -??? question "Can I use positional arguments instead of keyworded arguments?" - - You can only pass in **keyworded arguments** within the template tag. Due to technical limitations, **positional arguments** are not supported at this time. - - Also, be mindful of [reserved keywords](../django/templatetag.md). +{% include-markdown "../django/templatetag.md" start="" end="" %} ??? question "Where is my templates folder?" diff --git a/docs/installation/index.md b/docs/installation/index.md index 5766ea78..442150e6 100644 --- a/docs/installation/index.md +++ b/docs/installation/index.md @@ -25,6 +25,19 @@ INSTALLED_APPS = [ ] ``` +??? warning "Enabling ASGI on Django (Required)" + + Django-IDOM requires ASGI in order to use Websockets. + + If you haven't [enabled ASGI](https://channels.readthedocs.io/en/stable/installation.html) on your Django project yet, you'll need to add `channels` to `INSTALLED_APPS` and set your `ASGI_APPLICATION` variable. + ```python title="settings.py" + INSTALLED_APPS = [ + "channels", + ... + ] + ASGI_APPLICATION = "example_project.asgi.application" + ``` + ??? note "Configure IDOM settings (Optional)" Below are a handful of values you can change within `settings.py` to modify the behavior of IDOM. @@ -43,19 +56,6 @@ INSTALLED_APPS = [ IDOM_WEBSOCKET_URL = "idom/" ``` -??? warning "Enabling ASGI on Django (Required)" - - Django-IDOM requires ASGI in order to use Websockets. - - If you haven't [enabled ASGI](https://channels.readthedocs.io/en/stable/installation.html) on your Django project yet, you'll need to add `channels` to `INSTALLED_APPS` and set your `ASGI_APPLICATION` variable. - ```python title="settings.py" - INSTALLED_APPS = [ - "channels", - ... - ] - ASGI_APPLICATION = "example_project.asgi.application" - ``` - --- ## Configure [`urls.py`](https://docs.djangoproject.com/en/dev/topics/http/urls/) From f931f9b3db1c72838d1b7c1eb81116ff1d46c98c Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 25 Apr 2022 14:10:31 -0700 Subject: [PATCH 26/53] better component regex --- src/django_idom/utils.py | 11 ++++++++--- tests/test_app/tests/test_regex.py | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py index 3ec504b6..0741f740 100644 --- a/src/django_idom/utils.py +++ b/src/django_idom/utils.py @@ -12,7 +12,7 @@ from django_idom.config import IDOM_REGISTERED_COMPONENTS -COMPONENT_REGEX = re.compile(r"{% *component ((\"[^\"']*\")|('[^\"']*')).*?%}") +COMPONENT_REGEX = re.compile(r"{% *component +((\"[^\"']*\")|('[^\"']*'))(.*?)%}") _logger = logging.getLogger(__name__) @@ -32,7 +32,7 @@ def _register_component(full_component_name: str) -> None: try: component = getattr(module, component_name) except AttributeError as error: - raise RuntimeError( + raise RuntimeError( f"Module {module_name!r} has no component named {component_name!r}" ) from error @@ -100,7 +100,6 @@ def _get_components(self, templates: Set) -> Set: for template in templates: with contextlib.suppress(Exception): with open(template, "r", encoding="utf-8") as template_file: - # TODO: Only match if the template also contains {% load idom %} match = COMPONENT_REGEX.findall(template_file.read()) if not match: continue @@ -111,6 +110,12 @@ def _get_components(self, templates: Set) -> Set: def _register_components(self, components: Set) -> None: """Registers all IDOM components in an iterable.""" + if not components: + _logger.warning( + "No IDOM components were found. Are you sure you are using the template tag correctly?" + ) + return + for component in components: try: _register_component(component) diff --git a/tests/test_app/tests/test_regex.py b/tests/test_app/tests/test_regex.py index 690b0f3a..c0942dba 100644 --- a/tests/test_app/tests/test_regex.py +++ b/tests/test_app/tests/test_regex.py @@ -7,6 +7,7 @@ class RegexTests(TestCase): def test_component_regex(self): for component in { r'{%component "my.component"%}', + r'{%component "my.component"%}', r"{%component 'my.component'%}", r'{% component "my.component" %}', r"{% component 'my.component' %}", From a4abe01b90da896208207bb5ef0efe3467846077 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 25 Apr 2022 14:11:57 -0700 Subject: [PATCH 27/53] add logging to test app --- tests/test_app/settings.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/test_app/settings.py b/tests/test_app/settings.py index 29eadffa..fbacac81 100644 --- a/tests/test_app/settings.py +++ b/tests/test_app/settings.py @@ -121,3 +121,20 @@ "django.contrib.staticfiles.finders.FileSystemFinder", "django.contrib.staticfiles.finders.AppDirectoriesFinder", ] + +# Logging +LOGGING = { + "version": 1, + "disable_existing_loggers": False, + "handlers": { + "console": { + "class": "logging.StreamHandler", + }, + }, + "loggers": { + "django_idom": { + "handlers": ["console"], + "level": "DEBUG", + }, + }, +} From ddbf68cc1339642951d2a7ae3a8b9d1a27968b62 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 25 Apr 2022 14:25:34 -0700 Subject: [PATCH 28/53] fix spacing --- src/django_idom/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py index 0741f740..08ab5c29 100644 --- a/src/django_idom/utils.py +++ b/src/django_idom/utils.py @@ -32,7 +32,7 @@ def _register_component(full_component_name: str) -> None: try: component = getattr(module, component_name) except AttributeError as error: - raise RuntimeError( + raise RuntimeError( f"Module {module_name!r} has no component named {component_name!r}" ) from error From 5d924d38dd7f631f784e4111132df0c00eee678b Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 25 Apr 2022 15:59:11 -0700 Subject: [PATCH 29/53] more smithing --- README.md | 3 +- docs/django/templatetag.md | 75 ++++++++++++------- docs/how-to-use/create-component.md | 7 +- docs/how-to-use/initial-steps.md | 8 +- docs/how-to-use/learn-more.md | 2 +- docs/how-to-use/reference-component.md | 11 ++- .../{render-component.md => render-view.md} | 2 +- docs/index.md | 4 + docs/installation/index.md | 2 +- mkdocs.yml | 4 +- src/django_idom/utils.py | 3 +- 11 files changed, 69 insertions(+), 52 deletions(-) rename docs/how-to-use/{render-component.md => render-view.md} (92%) diff --git a/README.md b/README.md index 902e5a48..6edfb525 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ # Django IDOM · [![Tests](https://github.com/idom-team/django-idom/workflows/Test/badge.svg?event=push)](https://github.com/idom-team/django-idom/actions?query=workflow%3ATest) [![PyPI Version](https://img.shields.io/pypi/v/django-idom.svg)](https://pypi.python.org/pypi/django-idom) [![License](https://img.shields.io/badge/License-MIT-purple.svg)](https://github.com/idom-team/django-idom/blob/main/LICENSE) - IDOM is a Python micro-framework that links your web framework of choice to a ReactJS frontend, allowing you to create **interactive websites without needing JavaScript!** @@ -50,7 +49,7 @@ def HelloComponent(recipient: str): In your **Django app**'s HTML located within your `templates` folder, you can now embed your IDOM component using the `component` template tag. Within this tag, you will need to type in your dotted path to the component function as the first argument. -Additonally, you can pass in keyworded arguments into your component function. For example, pay attention to how the function definition for HelloComponent (_in the previous example_) accepts a 'recipient' argument. +Additonally, you can pass in keyword arguments into your component function. For example, pay attention to how the function definition for HelloComponent (_in the previous example_) accepts a 'recipient' argument. diff --git a/docs/django/templatetag.md b/docs/django/templatetag.md index 97fc834f..b75cf89d 100644 --- a/docs/django/templatetag.md +++ b/docs/django/templatetag.md @@ -1,43 +1,60 @@ -Integrated within Django IDOM, we bundle a template tag. Within this tag, you can pass in keyworded parameters directly into your component. +Integrated within Django IDOM, we bundle a template tag. Within this tag, you can pass in keyword arguments directly into your component. -```jinja title="my-template.html" -{% load idom %} - - - - {% component "example.components.HelloComponent" recipient="World" %} - - -``` +{% include-markdown "../../README.md" start="" end="" %} - + -??? question "Can I use multiple components on one page?" +??? warning "Do not use context variables for the IDOM component name" - You can add as many components to a webpage as needed by using the template tag multiple times. Retrofitting legacy sites to use reactive components will typically involve many components on one page. + Our pre-processor relies on the template tag containing a string. - But keep in mind, in scenarios where you are trying to create a Single Page Application (SPA) within Django, you will only have one central component within your body tag as shown below. + **Do not** use Django context variables for the component path. For example, **do not** do the following: + + ```python title="views.py" + def example_view(): + context = {"MyVariable": "example_project.my_app.components.HelloComponent"} + return render(request, "my-template.html", context) + ``` + + ```jinja title="my-template.html" + ... + {% component MyVariable recipient="World" %} + ... + ``` + + Failure to follow this warning will result in a performance penalty and jankiness when using the Django autoreloader. + + + - - +??? info "Reserved keyword arguments: `class` and `key`" -??? question "Can I use positional arguments instead of keyworded arguments?" + For this template tag, there are two reserved keyword arguments: `class` and `key` - You can only pass in **keyworded arguments** within the template tag. Due to technical limitations, **positional arguments** are not supported at this time. + - `class` allows you to apply a HTML class to the top-level component div. This is useful for styling purposes. + - `key` allows you to force the component to use a [specific key value](https://idom-docs.herokuapp.com/docs/guides/understanding-idom/why-idom-needs-keys.html?highlight=key). You typically won't need to set this. - Also, be mindful of [reserved keywords](../django/templatetag.md). + ```jinja title="my-template.html" + ... + {% component "example.components.MyComponent" class="my-html-class" key=123 %} + ... + ``` + + + + +??? question "Can I use multiple components on one page?" + + You can add as many components to a webpage as needed by using the template tag multiple times. Retrofitting legacy sites to use reactive components will typically involve many components on one page. + + But keep in mind, in scenarios where you are trying to create a Single Page Application (SPA) within Django, you will only have one central component within your body tag as shown below. - + + ---- +??? question "Can I use positional arguments instead of keyword arguments?" -For this template tag, there are only two reserved parameters: `class` and `key` + You can only pass in **keyword arguments** within the template tag. Due to technical limitations, **positional arguments** are not supported at this time. -- `class` allows you to apply a HTML class to the top-level component div. This is useful for styling purposes. -- `key` allows you to force the component to use a [specific key value](https://idom-docs.herokuapp.com/docs/guides/understanding-idom/why-idom-needs-keys.html?highlight=key). You typically won't need to set this. -```jinja title="my-template.html" -... -{% component "example.components.MyComponent" class="my-html-class" key=123 %} -... -``` + diff --git a/docs/how-to-use/create-component.md b/docs/how-to-use/create-component.md index dfdca830..333b7b92 100644 --- a/docs/how-to-use/create-component.md +++ b/docs/how-to-use/create-component.md @@ -5,13 +5,12 @@ --- {% include-markdown "../../README.md" start="" end="" %} - {% include-markdown "../../README.md" start="" end="" %} -??? question "What do I name my component files and functions?" +??? question "What do I name my IDOM files and functions?" - You can have full freedom in where you name or place your files/functions within IDOM. + You have full freedom in naming/placement of your files and functions. You should determine the best way to sort your Python modules and component functions to fit your needs. - Ultimately, components are referenced by Python dotted path in `my-template.html`. So, at minimum this path needs to be valid to Python's `importlib`. + Ultimately, components are referenced by Python dotted path in `my-template.html` (_see next step_). So, at minimum this path needs to be valid to Python's `importlib`. diff --git a/docs/how-to-use/initial-steps.md b/docs/how-to-use/initial-steps.md index ea8011fa..e5136ac9 100644 --- a/docs/how-to-use/initial-steps.md +++ b/docs/how-to-use/initial-steps.md @@ -6,11 +6,9 @@ If you've reached this point, you should have already [installed Django-IDOM](../installation/index.md) through the previous steps. -Django provides you high flexibility on where your apps can reside. +For the examples within this section, we will assume you've placed the files [generated by `startapp`](https://docs.djangoproject.com/en/dev/intro/tutorial01/#creating-the-polls-app) directly into your **Django project** folder. This is common for small projects. -However, for the examples within this section we will assume you've placed the files [generated by `startapp`](https://docs.djangoproject.com/en/dev/intro/tutorial01/#creating-the-polls-app) directly into your **Django project** folder. This is common for small projects. - -??? Info "Starting from scratch" +??? question "I've never used Django, what do I do now?" {% include-markdown "../installation/index.md" start="" end="" %} @@ -18,4 +16,4 @@ However, for the examples within this section we will assume you've placed the f ??? question "How do I organize my Django project for IDOM?" - Django-IDOM has no requirements on file structure. Organize everything as you wish, just like any other Django project. + Django-IDOM has no project structure requirements. Organize everything as you wish, just like any Django project. diff --git a/docs/how-to-use/learn-more.md b/docs/how-to-use/learn-more.md index 1b2286f9..abe21cfa 100644 --- a/docs/how-to-use/learn-more.md +++ b/docs/how-to-use/learn-more.md @@ -4,6 +4,6 @@ If you followed the previous steps, you've now created a "Hello World" component The docs you are reading only covers our Django integration. -Check out the [IDOM Core Documentation](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/index.html) to learn more about our advanced features, such as adding interactivity through events and hooks! +To learn more about our advanced features, such as interactive events and hooks, check out the [IDOM Core Documentation](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/index.html)! [Learn More](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/index.html){ .md-button .md-button--primary} diff --git a/docs/how-to-use/reference-component.md b/docs/how-to-use/reference-component.md index 393c8b80..e098982c 100644 --- a/docs/how-to-use/reference-component.md +++ b/docs/how-to-use/reference-component.md @@ -1,16 +1,15 @@ ???+ summary - Use our template tag in your HTML. + Decide where the component will be displayed by using our template tag. --- {% include-markdown "../../README.md" start="" end="" %} - {% include-markdown "../../README.md" start="" end="" %} - -{% include-markdown "../django/templatetag.md" start="" end="" %} - -{% include-markdown "../django/templatetag.md" start="" end="" %} +{% include-markdown "../django/templatetag.md" start="" end="" %} +{% include-markdown "../django/templatetag.md" start="" end="" %} +{% include-markdown "../django/templatetag.md" start="" end="" %} +{% include-markdown "../django/templatetag.md" start="" end="" %} ??? question "Where is my templates folder?" diff --git a/docs/how-to-use/render-component.md b/docs/how-to-use/render-view.md similarity index 92% rename from docs/how-to-use/render-component.md rename to docs/how-to-use/render-view.md index c7a45a11..792301df 100644 --- a/docs/how-to-use/render-component.md +++ b/docs/how-to-use/render-view.md @@ -1,6 +1,6 @@ ???+ summary - Render the template with a view. + Select your template containing an IDOM component, and render it using a Django view. --- diff --git a/docs/index.md b/docs/index.md index 83838442..39874a5f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,6 +6,10 @@ hide: {% include-markdown "../README.md" start="" end="" %} +## It's React for Django Developers. + +--- + {% include-markdown "../README.md" start="" end="" %} ## Resources diff --git a/docs/installation/index.md b/docs/installation/index.md index 442150e6..cdf9820b 100644 --- a/docs/installation/index.md +++ b/docs/installation/index.md @@ -1,6 +1,6 @@ -We are going to assume you have created [a basic **Django project**](https://docs.djangoproject.com/en/dev/intro/tutorial01/), which also involves generating/installing at least one **Django app**. If not, check out this [9 minute video tutorial](https://www.youtube.com/watch?v=ZsJRXS_vrw0) created by _IDG TECHtalk_. +These docs assumes you have created [a basic **Django project**](https://docs.djangoproject.com/en/dev/intro/tutorial01/), which also involves generating/installing at least one **Django app**. If not, check out this [9 minute YouTube tutorial](https://www.youtube.com/watch?v=ZsJRXS_vrw0) created by _IDG TECHtalk_. diff --git a/mkdocs.yml b/mkdocs.yml index 860427cd..81cb4622 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -5,8 +5,8 @@ nav: - How to Use: - 1. Initial Steps: how-to-use/initial-steps.md - 2. Create a Component: how-to-use/create-component.md - - 3. Reference Your Component: how-to-use/reference-component.md - - 4. Render Your Component: how-to-use/render-component.md + - 3. Use the Template Tag: how-to-use/reference-component.md + - 4. Render Your View: how-to-use/render-view.md - 5. Learn More: how-to-use/learn-more.md - Django-Only Features: - Hooks: django/hooks.md diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py index 08ab5c29..2212e83b 100644 --- a/src/django_idom/utils.py +++ b/src/django_idom/utils.py @@ -37,6 +37,7 @@ def _register_component(full_component_name: str) -> None: ) from error IDOM_REGISTERED_COMPONENTS[full_component_name] = component + _logger.debug("IDOM has registered component %s", full_component_name) class ComponentPreloader: @@ -118,8 +119,8 @@ def _register_components(self, components: Set) -> None: for component in components: try: + _logger.info("IDOM preloader has detected component %s", component) _register_component(component) - _logger.info("IDOM has registered component %s", component) except Exception: _logger.exception( "IDOM failed to register component %s! This component path may not be valid, or an error may have occurred while importing.", From a772359034d8c7e104a6d5ac2ea12bb6494b113e Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 25 Apr 2022 17:46:38 -0700 Subject: [PATCH 30/53] ELI5 --- docs/django/templatetag.md | 42 ++++++++++++++++++++------ docs/how-to-use/reference-component.md | 1 + docs/how-to-use/render-view.md | 14 +++++++-- mkdocs.yml | 1 + 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/docs/django/templatetag.md b/docs/django/templatetag.md index b75cf89d..18827d38 100644 --- a/docs/django/templatetag.md +++ b/docs/django/templatetag.md @@ -8,21 +8,23 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca Our pre-processor relies on the template tag containing a string. - **Do not** use Django context variables for the component path. For example, **do not** do the following: + **Do not** use a Django context variable for the path string. For example, **do not** do the following: ```python title="views.py" def example_view(): - context = {"MyVariable": "example_project.my_app.components.HelloComponent"} - return render(request, "my-template.html", context) + context_vars = {"DontDoThis": "example_project.my_app.components.HelloComponent"} + return render(request, "my-template.html", context_vars) ``` ```jinja title="my-template.html" - ... - {% component MyVariable recipient="World" %} - ... + + {% component DontDoThis recipient="World" %} + + + {% component "example_project.my_app.components.HelloComponent" recipient="World" %} ``` - Failure to follow this warning will result in a performance penalty and jankiness when using the Django autoreloader. + Failure to follow this warning will result in a performance penalty and also jankiness when using the Django autoreloader. @@ -47,7 +49,19 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca You can add as many components to a webpage as needed by using the template tag multiple times. Retrofitting legacy sites to use reactive components will typically involve many components on one page. - But keep in mind, in scenarios where you are trying to create a Single Page Application (SPA) within Django, you will only have one central component within your body tag as shown below. + ```jinja + {% load idom %} + + + + {% component "example.my_app_1.components.MyFirstComponent" %} + {% component "example.my_app_2.components.MySecondComponent" %} +
{% component "example.my_app_3.components.MyThirdComponent" %}
+ + + ``` + + But keep in mind, in scenarios where you are trying to create a Single Page Application (SPA) within Django, you will only have one central component within your body tag. @@ -56,5 +70,15 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca You can only pass in **keyword arguments** within the template tag. Due to technical limitations, **positional arguments** are not supported at this time. - + + +??? question "What is a "template tag"?" + + Template tags are Django's way of allowing you to run Python code within your HTML. Django IDOM uses a `#!jinja {% component ... %}` template tag to perform it's magic. + + Keep in mind, in order to use the `#!jinja {% component ... %}` tag, you'll need to first call `#!jinja {% load idom %}` to gain access to it. + + {% include-markdown "../../README.md" start="" end="" %} + + diff --git a/docs/how-to-use/reference-component.md b/docs/how-to-use/reference-component.md index e098982c..b8eee98e 100644 --- a/docs/how-to-use/reference-component.md +++ b/docs/how-to-use/reference-component.md @@ -10,6 +10,7 @@ {% include-markdown "../django/templatetag.md" start="" end="" %} {% include-markdown "../django/templatetag.md" start="" end="" %} {% include-markdown "../django/templatetag.md" start="" end="" %} +{% include-markdown "../django/templatetag.md" start="" end="" %} ??? question "Where is my templates folder?" diff --git a/docs/how-to-use/render-view.md b/docs/how-to-use/render-view.md index 792301df..cc963872 100644 --- a/docs/how-to-use/render-view.md +++ b/docs/how-to-use/render-view.md @@ -6,7 +6,9 @@ We will assume you've [created a Django View](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view) before, but we'll give a simple example below. -Within your **Django app**'s [`views.py` file](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view), you'll need to create a function to render the HTML template containing your IDOM components. +Within your **Django app**'s `views.py` file, you'll need to create a function to render the HTML template containing your IDOM components. + +In this example, we will render the `my-template.html` from the previous step. ```python title="views.py" from django.shortcuts import render @@ -15,7 +17,7 @@ def index(request): return render(request, "my-template.html") ``` -To simplify things for this example, we will add this new view directly to your [**Django project**'s `urls.py`](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view) rather than adding to a **Django app**'s `urls.py`. +We will add this new view into your [`urls.py`](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view). ```python title="urls.py" from django.urls import path @@ -27,3 +29,11 @@ urlpatterns = [ ``` Now, navigate to `http://127.0.0.1:8000/example/`. If you copy-pasted the component from the previous example, you will now see your component display "Hello World". + +??? question "Which urls.py do I add my views to?" + + For simple Django projects, you can easily add all of your views directly into the **Django project**'s `urls.py`. However, as you start increase your project's complexity you might end up with way too much within one file. + + Once you reach that point, we recommend creating individual `urls.py` within each of your **Django apps**. + + Then, within your **Django project**'s `urls.py` you will use Django's [`include` function](https://docs.djangoproject.com/en/dev/ref/urls/) to link each of these back in. diff --git a/mkdocs.yml b/mkdocs.yml index 81cb4622..d6d8d567 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -51,6 +51,7 @@ markdown_extensions: - pymdownx.highlight - pymdownx.superfences - pymdownx.details + - pymdownx.inlinehilite - admonition - attr_list From 45159b6282480e0a0b8d3eee530cc48bb81aba16 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 25 Apr 2022 17:56:06 -0700 Subject: [PATCH 31/53] better examples --- docs/django/templatetag.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/django/templatetag.md b/docs/django/templatetag.md index 18827d38..d3da5649 100644 --- a/docs/django/templatetag.md +++ b/docs/django/templatetag.md @@ -47,16 +47,16 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca ??? question "Can I use multiple components on one page?" - You can add as many components to a webpage as needed by using the template tag multiple times. Retrofitting legacy sites to use reactive components will typically involve many components on one page. + You can add as many components to a webpage as needed by using the template tag multiple times. Retrofitting legacy sites to use IDOM will typically involve many components on one page. ```jinja {% load idom %} - {% component "example.my_app_1.components.MyFirstComponent" %} - {% component "example.my_app_2.components.MySecondComponent" %} -
{% component "example.my_app_3.components.MyThirdComponent" %}
+ {% component "example_project.my_app.components.HelloComponent" recipient="World" %} + {% component "example_project.my_app_2.components.StyledComponent" class="bold small-font"%} +
{% component "example_project.my_app_3.components.SimpleComponent" %}
``` From 1f1a2b114e782a32ad37b3b6b5262983b5d4ea17 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 25 Apr 2022 17:59:44 -0700 Subject: [PATCH 32/53] fix example --- docs/django/templatetag.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/django/templatetag.md b/docs/django/templatetag.md index d3da5649..e0554510 100644 --- a/docs/django/templatetag.md +++ b/docs/django/templatetag.md @@ -55,7 +55,7 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca {% component "example_project.my_app.components.HelloComponent" recipient="World" %} - {% component "example_project.my_app_2.components.StyledComponent" class="bold small-font"%} + {% component "example_project.my_app_2.components.ClassComponent" class="bold small-font" %}
{% component "example_project.my_app_3.components.SimpleComponent" %}
From f1d6afede026bd09b769792a1b057599a8b28d3d Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 25 Apr 2022 18:02:06 -0700 Subject: [PATCH 33/53] highlight body tag --- docs/django/templatetag.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/django/templatetag.md b/docs/django/templatetag.md index e0554510..441e3904 100644 --- a/docs/django/templatetag.md +++ b/docs/django/templatetag.md @@ -61,7 +61,7 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca ``` - But keep in mind, in scenarios where you are trying to create a Single Page Application (SPA) within Django, you will only have one central component within your body tag. + But keep in mind, in scenarios where you are trying to create a Single Page Application (SPA) within Django, you will only have one central component within your `#!html ` tag. From 9d9842553da775be776a3f1cc30137e4da8e164a Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 25 Apr 2022 18:09:33 -0700 Subject: [PATCH 34/53] add more guidance --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6edfb525..bce13599 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ def HelloComponent(recipient: str): In your **Django app**'s HTML located within your `templates` folder, you can now embed your IDOM component using the `component` template tag. Within this tag, you will need to type in your dotted path to the component function as the first argument. -Additonally, you can pass in keyword arguments into your component function. For example, pay attention to how the function definition for HelloComponent (_in the previous example_) accepts a 'recipient' argument. +Additonally, you can pass in keyword arguments into your component function. For example, after reading the code below, pay attention to how the function definition for `HelloComponent` (_in the previous example_) accepts a 'recipient' argument. From a142bfb10ad736d352d26df07c103366e8285647 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 25 Apr 2022 22:53:12 -0700 Subject: [PATCH 35/53] smithy --- README.md | 6 +++--- docs/django/templatetag.md | 2 +- docs/how-to-use/render-view.md | 2 +- mkdocs.yml | 3 +-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index bce13599..2c434a42 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,13 @@ -IDOM is a Python micro-framework that links your web framework of choice to a ReactJS frontend, allowing you to create **interactive websites without needing JavaScript!** +IDOM connects your Python web framework of choice to a ReactJS frontend, allowing you to create **interactive websites without needing JavaScript!** Following ReactJS styling, web elements are combined into [reusable "components"](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/your-first-components/index.html#parametrizing-components). These components can utilize [hooks](https://idom-docs.herokuapp.com/docs/reference/hooks-api.html) and [events](https://idom-docs.herokuapp.com/docs/guides/adding-interactivity/responding-to-events/index.html#async-event-handlers) to create infinitely complex web pages. -When needed, IDOM can [use JavaScript components](https://idom-docs.herokuapp.com/docs/guides/escape-hatches/javascript-components.html#dynamically-loaded-components) directly from NPM. Components can also be [developed in JavaScript](https://idom-docs.herokuapp.com/docs/guides/escape-hatches/javascript-components.html#custom-javascript-components) for additional flexibility. +When needed, IDOM can [use components directly from NPM](https://idom-docs.herokuapp.com/docs/guides/escape-hatches/javascript-components.html#dynamically-loaded-components). For additional flexibility, components can also be [fully developed in JavaScript](https://idom-docs.herokuapp.com/docs/guides/escape-hatches/javascript-components.html#custom-javascript-components). -IDOM's ecosystem independent design allows components to be reused across a variety of web frameworks. Pre-existing support is included for many popular Python frameworks, however, any framework with WebSocket support can be adapted to utilize IDOM. +Any Python web framework with Websockets can support IDOM. See below for what frameworks are supported out of the box. | Supported Frameworks | Supported Frameworks (External) | | ------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | diff --git a/docs/django/templatetag.md b/docs/django/templatetag.md index 441e3904..c3b827cc 100644 --- a/docs/django/templatetag.md +++ b/docs/django/templatetag.md @@ -75,7 +75,7 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca ??? question "What is a "template tag"?" - Template tags are Django's way of allowing you to run Python code within your HTML. Django IDOM uses a `#!jinja {% component ... %}` template tag to perform it's magic. + You can think of template tags as Django's way of allowing you to run Python code within your HTML. Django IDOM uses a `#!jinja {% component ... %}` template tag to perform it's magic. Keep in mind, in order to use the `#!jinja {% component ... %}` tag, you'll need to first call `#!jinja {% load idom %}` to gain access to it. diff --git a/docs/how-to-use/render-view.md b/docs/how-to-use/render-view.md index cc963872..a660b37b 100644 --- a/docs/how-to-use/render-view.md +++ b/docs/how-to-use/render-view.md @@ -36,4 +36,4 @@ Now, navigate to `http://127.0.0.1:8000/example/`. If you copy-pasted the compon Once you reach that point, we recommend creating individual `urls.py` within each of your **Django apps**. - Then, within your **Django project**'s `urls.py` you will use Django's [`include` function](https://docs.djangoproject.com/en/dev/ref/urls/) to link each of these back in. + Then, within your **Django project**'s `urls.py` you will use Django's [`include` function](https://docs.djangoproject.com/en/dev/ref/urls/) to link it all together. diff --git a/mkdocs.yml b/mkdocs.yml index d6d8d567..ab3525ac 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -30,8 +30,7 @@ theme: toggle: icon: material/toggle-switch-off-outline name: Switch to dark mode - primary: deep-orange - accent: deep-orange + primary: black features: - navigation.instant - navigation.tracking From c2104ca1d6acf5817d35c9446b2a8a09905df3b2 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 25 Apr 2022 23:27:18 -0700 Subject: [PATCH 36/53] english tweaks --- README.md | 2 +- docs/how-to-use/create-component.md | 2 +- docs/how-to-use/initial-steps.md | 10 +++++----- docs/how-to-use/render-view.md | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 2c434a42..885dde83 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ def HelloComponent(recipient: str): In your **Django app**'s HTML located within your `templates` folder, you can now embed your IDOM component using the `component` template tag. Within this tag, you will need to type in your dotted path to the component function as the first argument. -Additonally, you can pass in keyword arguments into your component function. For example, after reading the code below, pay attention to how the function definition for `HelloComponent` (_in the previous example_) accepts a 'recipient' argument. +Additonally, you can pass in keyword arguments into your component function. For example, after reading the code below, pay attention to how the function definition for `HelloComponent` (_in the previous example_) accepts a `recipient` argument. diff --git a/docs/how-to-use/create-component.md b/docs/how-to-use/create-component.md index 333b7b92..75721519 100644 --- a/docs/how-to-use/create-component.md +++ b/docs/how-to-use/create-component.md @@ -7,7 +7,7 @@ {% include-markdown "../../README.md" start="" end="" %} {% include-markdown "../../README.md" start="" end="" %} -??? question "What do I name my IDOM files and functions?" +??? question "What should I name my IDOM files and functions?" You have full freedom in naming/placement of your files and functions. diff --git a/docs/how-to-use/initial-steps.md b/docs/how-to-use/initial-steps.md index e5136ac9..daef5d4d 100644 --- a/docs/how-to-use/initial-steps.md +++ b/docs/how-to-use/initial-steps.md @@ -8,12 +8,12 @@ If you've reached this point, you should have already [installed Django-IDOM](.. For the examples within this section, we will assume you've placed the files [generated by `startapp`](https://docs.djangoproject.com/en/dev/intro/tutorial01/#creating-the-polls-app) directly into your **Django project** folder. This is common for small projects. -??? question "I've never used Django, what do I do now?" +??? question "How do I organize my Django project for IDOM?" - {% include-markdown "../installation/index.md" start="" end="" %} + Django-IDOM has no project structure requirements. Organize everything as you wish, just like any Django project. - Afterwards, make sure to follow the [Django-IDOM installation instructions](../installation/index.md). +??? question "I've never used Django, what do I need to learn?" -??? question "How do I organize my Django project for IDOM?" + {% include-markdown "../installation/index.md" start="" end="" %} - Django-IDOM has no project structure requirements. Organize everything as you wish, just like any Django project. + Afterwards, make sure to follow the [Django-IDOM installation instructions](../installation/index.md). diff --git a/docs/how-to-use/render-view.md b/docs/how-to-use/render-view.md index a660b37b..edab7d25 100644 --- a/docs/how-to-use/render-view.md +++ b/docs/how-to-use/render-view.md @@ -4,7 +4,7 @@ --- -We will assume you've [created a Django View](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view) before, but we'll give a simple example below. +We will assume you've [created a Django View](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view) before, but here's a simple example below. Within your **Django app**'s `views.py` file, you'll need to create a function to render the HTML template containing your IDOM components. @@ -34,6 +34,6 @@ Now, navigate to `http://127.0.0.1:8000/example/`. If you copy-pasted the compon For simple Django projects, you can easily add all of your views directly into the **Django project**'s `urls.py`. However, as you start increase your project's complexity you might end up with way too much within one file. - Once you reach that point, we recommend creating individual `urls.py` within each of your **Django apps**. + Once you reach that point, we recommend creating an individual `urls.py` within each of your **Django apps**. Then, within your **Django project**'s `urls.py` you will use Django's [`include` function](https://docs.djangoproject.com/en/dev/ref/urls/) to link it all together. From 1d072dc2b831fac7afad940c8ad86aaad7897f1c Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Tue, 26 Apr 2022 19:04:21 -0700 Subject: [PATCH 37/53] minor rework --- docs/how-to-use/render-view.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/how-to-use/render-view.md b/docs/how-to-use/render-view.md index edab7d25..03fb8d6f 100644 --- a/docs/how-to-use/render-view.md +++ b/docs/how-to-use/render-view.md @@ -8,7 +8,7 @@ We will assume you've [created a Django View](https://docs.djangoproject.com/en/ Within your **Django app**'s `views.py` file, you'll need to create a function to render the HTML template containing your IDOM components. -In this example, we will render the `my-template.html` from the previous step. +In this example, we will create a view that renders `my-template.html` (_from the previous step_). ```python title="views.py" from django.shortcuts import render From bb35d0d7fa8e550a5fc7873ba225d54ff882238d Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sat, 30 Apr 2022 19:57:15 -0700 Subject: [PATCH 38/53] rename component to HelloWorld --- README.md | 7 +++---- docs/django/templatetag.md | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 885dde83..c3d31ec7 100644 --- a/README.md +++ b/README.md @@ -35,9 +35,8 @@ You'll need a file to define your [IDOM](https://github.com/idom-team/idom) comp ```python title="components.py" from idom import component, html -# Components are CamelCase by ReactJS convention @component -def HelloComponent(recipient: str): +def HelloWorld(recipient: str): return html.h1(f"Hello {recipient}!") ``` @@ -49,7 +48,7 @@ def HelloComponent(recipient: str): In your **Django app**'s HTML located within your `templates` folder, you can now embed your IDOM component using the `component` template tag. Within this tag, you will need to type in your dotted path to the component function as the first argument. -Additonally, you can pass in keyword arguments into your component function. For example, after reading the code below, pay attention to how the function definition for `HelloComponent` (_in the previous example_) accepts a `recipient` argument. +Additonally, you can pass in keyword arguments into your component function. For example, after reading the code below, pay attention to how the function definition for `HelloWorld` (_in the previous example_) accepts a `recipient` argument. @@ -59,7 +58,7 @@ Additonally, you can pass in keyword arguments into your component function. For - {% component "example_project.my_app.components.HelloComponent" recipient="World" %} + {% component "example_project.my_app.components.HelloWorld" recipient="World" %} ``` diff --git a/docs/django/templatetag.md b/docs/django/templatetag.md index c3b827cc..c4a30eba 100644 --- a/docs/django/templatetag.md +++ b/docs/django/templatetag.md @@ -12,7 +12,7 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca ```python title="views.py" def example_view(): - context_vars = {"DontDoThis": "example_project.my_app.components.HelloComponent"} + context_vars = {"DontDoThis": "example_project.my_app.components.HelloWorld"} return render(request, "my-template.html", context_vars) ``` @@ -21,7 +21,7 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca {% component DontDoThis recipient="World" %} - {% component "example_project.my_app.components.HelloComponent" recipient="World" %} + {% component "example_project.my_app.components.HelloWorld" recipient="World" %} ``` Failure to follow this warning will result in a performance penalty and also jankiness when using the Django autoreloader. @@ -54,7 +54,7 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca - {% component "example_project.my_app.components.HelloComponent" recipient="World" %} + {% component "example_project.my_app.components.HelloWorld" recipient="World" %} {% component "example_project.my_app_2.components.ClassComponent" class="bold small-font" %}
{% component "example_project.my_app_3.components.SimpleComponent" %}
From c9646f05f876101901effc5dfb029e510464c272 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Wed, 4 May 2022 23:54:12 -0700 Subject: [PATCH 39/53] warning if no components are found --- CHANGELOG.md | 2 +- src/django_idom/utils.py | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5343a3eb..c51e8e0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,7 +30,7 @@ Types of changes are to be listed in this order - Django-specific hooks! `use_websocket`, `use_scope`, and `use_location` are now available within the `django_idom.hooks` module. - Documentation has been placed into a formal docs webpage. -- More verbose logging information for when a component fails to import. +- Logging information for when a component fails to import, or if no components were found within Django. ### Changed diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py index 2212e83b..4c54221a 100644 --- a/src/django_idom/utils.py +++ b/src/django_idom/utils.py @@ -107,6 +107,13 @@ def _get_components(self, templates: Set) -> Set: components.update( [group[0].replace('"', "").replace("'", "") for group in match] ) + if not components: + _logger.warning( + """IDOM did not find any components! + You are either not using any IDOM components, + not using the template tag correctly, + or your templates are not registered correctly within Django.""", + ) return components def _register_components(self, components: Set) -> None: @@ -123,6 +130,8 @@ def _register_components(self, components: Set) -> None: _register_component(component) except Exception: _logger.exception( - "IDOM failed to register component %s! This component path may not be valid, or an error may have occurred while importing.", + """IDOM failed to register component %s! + This component path may not be valid, + or an error may have occurred while importing.""", component, ) From 059ae0e146b0ef0d79aa4bb1705fb3128cff3698 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Wed, 4 May 2022 23:59:12 -0700 Subject: [PATCH 40/53] fix spacing in templatetag.md --- docs/django/templatetag.md | 58 +++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/docs/django/templatetag.md b/docs/django/templatetag.md index c4a30eba..26a2f4ad 100644 --- a/docs/django/templatetag.md +++ b/docs/django/templatetag.md @@ -6,25 +6,25 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca ??? warning "Do not use context variables for the IDOM component name" - Our pre-processor relies on the template tag containing a string. + Our pre-processor relies on the template tag containing a string. - **Do not** use a Django context variable for the path string. For example, **do not** do the following: + **Do not** use a Django context variable for the path string. Failure to follow this warning will result in a performance penalty and also jankiness when using the Django autoreloader. - ```python title="views.py" - def example_view(): - context_vars = {"DontDoThis": "example_project.my_app.components.HelloWorld"} - return render(request, "my-template.html", context_vars) - ``` + For example, **do not** do the following: - ```jinja title="my-template.html" - - {% component DontDoThis recipient="World" %} + ```python title="views.py" + def example_view(): + context_vars = {"DontDoThis": "example_project.my_app.components.HelloWorld"} + return render(request, "my-template.html", context_vars) + ``` - - {% component "example_project.my_app.components.HelloWorld" recipient="World" %} - ``` + ```jinja title="my-template.html" + + {% component DontDoThis recipient="World" %} - Failure to follow this warning will result in a performance penalty and also jankiness when using the Django autoreloader. + + {% component "example_project.my_app.components.HelloWorld" recipient="World" %} + ``` @@ -49,17 +49,17 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca You can add as many components to a webpage as needed by using the template tag multiple times. Retrofitting legacy sites to use IDOM will typically involve many components on one page. - ```jinja - {% load idom %} - - - - {% component "example_project.my_app.components.HelloWorld" recipient="World" %} - {% component "example_project.my_app_2.components.ClassComponent" class="bold small-font" %} -
{% component "example_project.my_app_3.components.SimpleComponent" %}
- - - ``` + ```jinja + {% load idom %} + + + + {% component "example_project.my_app.components.HelloWorld" recipient="World" %} + {% component "example_project.my_app_2.components.ClassComponent" class="bold small-font" %} +
{% component "example_project.my_app_3.components.SimpleComponent" %}
+ + + ``` But keep in mind, in scenarios where you are trying to create a Single Page Application (SPA) within Django, you will only have one central component within your `#!html ` tag. @@ -68,17 +68,17 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca ??? question "Can I use positional arguments instead of keyword arguments?" - You can only pass in **keyword arguments** within the template tag. Due to technical limitations, **positional arguments** are not supported at this time. + You can only pass in **keyword arguments** within the template tag. Due to technical limitations, **positional arguments** are not supported at this time. ??? question "What is a "template tag"?" - You can think of template tags as Django's way of allowing you to run Python code within your HTML. Django IDOM uses a `#!jinja {% component ... %}` template tag to perform it's magic. + You can think of template tags as Django's way of allowing you to run Python code within your HTML. Django IDOM uses a `#!jinja {% component ... %}` template tag to perform it's magic. - Keep in mind, in order to use the `#!jinja {% component ... %}` tag, you'll need to first call `#!jinja {% load idom %}` to gain access to it. + Keep in mind, in order to use the `#!jinja {% component ... %}` tag, you'll need to first call `#!jinja {% load idom %}` to gain access to it. - {% include-markdown "../../README.md" start="" end="" %} + {% include-markdown "../../README.md" start="" end="" %} From 1ea9e8015150a9e62c52ae9060d42464b41146cd Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Thu, 5 May 2022 00:29:22 -0700 Subject: [PATCH 41/53] fix multiline strings --- src/django_idom/utils.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py index 4c54221a..c39e977b 100644 --- a/src/django_idom/utils.py +++ b/src/django_idom/utils.py @@ -109,10 +109,10 @@ def _get_components(self, templates: Set) -> Set: ) if not components: _logger.warning( - """IDOM did not find any components! - You are either not using any IDOM components, - not using the template tag correctly, - or your templates are not registered correctly within Django.""", + "IDOM did not find any components! " + "You are either not using any IDOM components, " + "not using the template tag correctly, " + "or your templates are not registered correctly within Django.", ) return components @@ -130,8 +130,8 @@ def _register_components(self, components: Set) -> None: _register_component(component) except Exception: _logger.exception( - """IDOM failed to register component %s! - This component path may not be valid, - or an error may have occurred while importing.""", + "IDOM failed to register component '%s'! " + "This component path may not be valid, " + "or an error may have occurred while importing.", component, ) From 34ae18caaa07d7658c214728d185a87df5db9f7e Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Thu, 5 May 2022 00:30:10 -0700 Subject: [PATCH 42/53] clean changelong --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c51e8e0c..22c3ebce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,7 +30,7 @@ Types of changes are to be listed in this order - Django-specific hooks! `use_websocket`, `use_scope`, and `use_location` are now available within the `django_idom.hooks` module. - Documentation has been placed into a formal docs webpage. -- Logging information for when a component fails to import, or if no components were found within Django. +- Logging for when a component fails to import, or if no components were found within Django. ### Changed From 9e3c035e9280060fb2208f78b27f39899453346d Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Fri, 6 May 2022 00:43:58 -0700 Subject: [PATCH 43/53] fix unreleased link --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 22c3ebce..6a696e82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -102,7 +102,7 @@ Types of changes are to be listed in this order - Support for IDOM within the Django -[unreleased]: https://github.com/idom-team/django-idom/compare/0.0.2...HEAD +[unreleased]: https://github.com/idom-team/django-idom/compare/1.0.0...HEAD [1.0.0]: https://github.com/idom-team/django-idom/compare/0.0.5...1.0.0 [0.0.5]: https://github.com/idom-team/django-idom/compare/0.0.4...0.0.5 [0.0.4]: https://github.com/idom-team/django-idom/compare/0.0.3...0.0.4 From f22d60eba662a9e55a60b90e0a82bb05bedc29c6 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 9 May 2022 16:02:24 -0700 Subject: [PATCH 44/53] Add link to django only features --- docs/how-to-use/learn-more.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/how-to-use/learn-more.md b/docs/how-to-use/learn-more.md index abe21cfa..e971aea8 100644 --- a/docs/how-to-use/learn-more.md +++ b/docs/how-to-use/learn-more.md @@ -6,4 +6,6 @@ The docs you are reading only covers our Django integration. To learn more about our advanced features, such as interactive events and hooks, check out the [IDOM Core Documentation](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/index.html)! -[Learn More](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/index.html){ .md-button .md-button--primary} +| Learn More | +| --- | +| [Django-Only Features](../django/hooks.md){ .md-button } [IDOM Core — Hooks, Events, and More](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/index.html){ .md-button } | From 50955880bd37e25125a4d93ff80af2fa48128255 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 9 May 2022 16:05:01 -0700 Subject: [PATCH 45/53] disable prose wrap formatting --- docs/contribute/idom-env.md | 6 ++---- docs/how-to-use/create-component.md | 1 + docs/how-to-use/reference-component.md | 6 ++++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/contribute/idom-env.md b/docs/contribute/idom-env.md index 2046a6c1..1307c8ef 100644 --- a/docs/contribute/idom-env.md +++ b/docs/contribute/idom-env.md @@ -2,10 +2,8 @@ If you plan to make code changes to this repository, you'll need to install the - [Python 3.8+](https://www.python.org/downloads/) - [Git](https://git-scm.com/downloads) -- [NPM](https://docs.npmjs.com/try-the-latest-stable-version-of-npm) for - installing and managing Javascript -- [ChromeDriver](https://chromedriver.chromium.org/downloads) for testing with - [Selenium](https://www.seleniumhq.org/) +- [NPM](https://docs.npmjs.com/try-the-latest-stable-version-of-npm) for installing and managing Javascript +- [ChromeDriver](https://chromedriver.chromium.org/downloads) for testing with [Selenium](https://www.seleniumhq.org/) Once done, you should clone this repository: diff --git a/docs/how-to-use/create-component.md b/docs/how-to-use/create-component.md index 75721519..ca6e2a18 100644 --- a/docs/how-to-use/create-component.md +++ b/docs/how-to-use/create-component.md @@ -5,6 +5,7 @@ --- {% include-markdown "../../README.md" start="" end="" %} + {% include-markdown "../../README.md" start="" end="" %} ??? question "What should I name my IDOM files and functions?" diff --git a/docs/how-to-use/reference-component.md b/docs/how-to-use/reference-component.md index b8eee98e..811a09ec 100644 --- a/docs/how-to-use/reference-component.md +++ b/docs/how-to-use/reference-component.md @@ -5,11 +5,17 @@ --- {% include-markdown "../../README.md" start="" end="" %} + {% include-markdown "../../README.md" start="" end="" %} + {% include-markdown "../django/templatetag.md" start="" end="" %} + {% include-markdown "../django/templatetag.md" start="" end="" %} + {% include-markdown "../django/templatetag.md" start="" end="" %} + {% include-markdown "../django/templatetag.md" start="" end="" %} + {% include-markdown "../django/templatetag.md" start="" end="" %} ??? question "Where is my templates folder?" From dbc2ace6ac8eb4926311b0672d471c7a07d96c06 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 9 May 2022 23:28:52 -0700 Subject: [PATCH 46/53] how to use -> getting started --- .../create-component.md | 0 .../{how-to-use => getting-started}/initial-steps.md | 0 docs/{how-to-use => getting-started}/learn-more.md | 0 .../reference-component.md | 0 docs/{how-to-use => getting-started}/render-view.md | 0 mkdocs.yml | 12 ++++++------ 6 files changed, 6 insertions(+), 6 deletions(-) rename docs/{how-to-use => getting-started}/create-component.md (100%) rename docs/{how-to-use => getting-started}/initial-steps.md (100%) rename docs/{how-to-use => getting-started}/learn-more.md (100%) rename docs/{how-to-use => getting-started}/reference-component.md (100%) rename docs/{how-to-use => getting-started}/render-view.md (100%) diff --git a/docs/how-to-use/create-component.md b/docs/getting-started/create-component.md similarity index 100% rename from docs/how-to-use/create-component.md rename to docs/getting-started/create-component.md diff --git a/docs/how-to-use/initial-steps.md b/docs/getting-started/initial-steps.md similarity index 100% rename from docs/how-to-use/initial-steps.md rename to docs/getting-started/initial-steps.md diff --git a/docs/how-to-use/learn-more.md b/docs/getting-started/learn-more.md similarity index 100% rename from docs/how-to-use/learn-more.md rename to docs/getting-started/learn-more.md diff --git a/docs/how-to-use/reference-component.md b/docs/getting-started/reference-component.md similarity index 100% rename from docs/how-to-use/reference-component.md rename to docs/getting-started/reference-component.md diff --git a/docs/how-to-use/render-view.md b/docs/getting-started/render-view.md similarity index 100% rename from docs/how-to-use/render-view.md rename to docs/getting-started/render-view.md diff --git a/mkdocs.yml b/mkdocs.yml index ab3525ac..ed2fdac6 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -2,12 +2,12 @@ nav: - Home: index.md - Installation: installation/index.md - - How to Use: - - 1. Initial Steps: how-to-use/initial-steps.md - - 2. Create a Component: how-to-use/create-component.md - - 3. Use the Template Tag: how-to-use/reference-component.md - - 4. Render Your View: how-to-use/render-view.md - - 5. Learn More: how-to-use/learn-more.md + - Getting Started: + - 1. Initial Steps: getting-started/initial-steps.md + - 2. Create a Component: getting-started/create-component.md + - 3. Use the Template Tag: getting-started/reference-component.md + - 4. Render Your View: getting-started/render-view.md + - 5. Learn More: getting-started/learn-more.md - Django-Only Features: - Hooks: django/hooks.md - Template Tag: django/templatetag.md From 12cfc99a8e1dd051e58518414bca0a9d57b1e9b8 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 9 May 2022 23:34:35 -0700 Subject: [PATCH 47/53] django-only -> exclusive --- docs/{django => features}/hooks.md | 0 docs/{django => features}/templatetag.md | 0 docs/getting-started/learn-more.md | 2 +- docs/getting-started/reference-component.md | 10 +++++----- mkdocs.yml | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) rename docs/{django => features}/hooks.md (100%) rename docs/{django => features}/templatetag.md (100%) diff --git a/docs/django/hooks.md b/docs/features/hooks.md similarity index 100% rename from docs/django/hooks.md rename to docs/features/hooks.md diff --git a/docs/django/templatetag.md b/docs/features/templatetag.md similarity index 100% rename from docs/django/templatetag.md rename to docs/features/templatetag.md diff --git a/docs/getting-started/learn-more.md b/docs/getting-started/learn-more.md index e971aea8..abbc1099 100644 --- a/docs/getting-started/learn-more.md +++ b/docs/getting-started/learn-more.md @@ -8,4 +8,4 @@ To learn more about our advanced features, such as interactive events and hooks, | Learn More | | --- | -| [Django-Only Features](../django/hooks.md){ .md-button } [IDOM Core — Hooks, Events, and More](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/index.html){ .md-button } | +| [Django-IDOM — Exclusive Features](../features/hooks.md){ .md-button } [IDOM Core — Hooks, Events, and More](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/index.html){ .md-button } | diff --git a/docs/getting-started/reference-component.md b/docs/getting-started/reference-component.md index 811a09ec..af7dd77c 100644 --- a/docs/getting-started/reference-component.md +++ b/docs/getting-started/reference-component.md @@ -8,15 +8,15 @@ {% include-markdown "../../README.md" start="" end="" %} -{% include-markdown "../django/templatetag.md" start="" end="" %} +{% include-markdown "../features/templatetag.md" start="" end="" %} -{% include-markdown "../django/templatetag.md" start="" end="" %} +{% include-markdown "../features/templatetag.md" start="" end="" %} -{% include-markdown "../django/templatetag.md" start="" end="" %} +{% include-markdown "../features/templatetag.md" start="" end="" %} -{% include-markdown "../django/templatetag.md" start="" end="" %} +{% include-markdown "../features/templatetag.md" start="" end="" %} -{% include-markdown "../django/templatetag.md" start="" end="" %} +{% include-markdown "../features/templatetag.md" start="" end="" %} ??? question "Where is my templates folder?" diff --git a/mkdocs.yml b/mkdocs.yml index ed2fdac6..36c48a8b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -8,9 +8,9 @@ nav: - 3. Use the Template Tag: getting-started/reference-component.md - 4. Render Your View: getting-started/render-view.md - 5. Learn More: getting-started/learn-more.md - - Django-Only Features: - - Hooks: django/hooks.md - - Template Tag: django/templatetag.md + - Exclusive Features: + - Hooks: features/hooks.md + - Template Tag: features/templatetag.md - Contribute: - Django-IDOM Environment: contribute/idom-env.md - Documentation Environment: contribute/docs-env.md From b1c41f857adff766c3c9bf4abca0ebb40a663284 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Thu, 12 May 2022 19:06:09 -0700 Subject: [PATCH 48/53] color error/warning log messages --- src/django_idom/utils.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py index c39e977b..4507ee25 100644 --- a/src/django_idom/utils.py +++ b/src/django_idom/utils.py @@ -109,10 +109,12 @@ def _get_components(self, templates: Set) -> Set: ) if not components: _logger.warning( + "\033[93m" "IDOM did not find any components! " "You are either not using any IDOM components, " - "not using the template tag correctly, " - "or your templates are not registered correctly within Django.", + "using the template tag incorrectly, " + "or your HTML templates are not registered correctly within Django." + "\033[0m" ) return components @@ -120,7 +122,9 @@ def _register_components(self, components: Set) -> None: """Registers all IDOM components in an iterable.""" if not components: _logger.warning( + "\033[93m" "No IDOM components were found. Are you sure you are using the template tag correctly?" + "\033[0m" ) return @@ -129,9 +133,11 @@ def _register_components(self, components: Set) -> None: _logger.info("IDOM preloader has detected component %s", component) _register_component(component) except Exception: - _logger.exception( + _logger.error( + "\033[91m" "IDOM failed to register component '%s'! " "This component path may not be valid, " - "or an error may have occurred while importing.", + "or an exception may have occurred while importing." + "\033[0m", component, ) From 7e8ace870b548415f874c1dcefdb199166c10782 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Thu, 12 May 2022 19:09:07 -0700 Subject: [PATCH 49/53] remove duplicate log message --- src/django_idom/utils.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py index 4507ee25..81783013 100644 --- a/src/django_idom/utils.py +++ b/src/django_idom/utils.py @@ -113,21 +113,13 @@ def _get_components(self, templates: Set) -> Set: "IDOM did not find any components! " "You are either not using any IDOM components, " "using the template tag incorrectly, " - "or your HTML templates are not registered correctly within Django." + "or your HTML templates are not registered with Django." "\033[0m" ) return components def _register_components(self, components: Set) -> None: """Registers all IDOM components in an iterable.""" - if not components: - _logger.warning( - "\033[93m" - "No IDOM components were found. Are you sure you are using the template tag correctly?" - "\033[0m" - ) - return - for component in components: try: _logger.info("IDOM preloader has detected component %s", component) From 4a4e51d2763288f1962b1e54b58aae1fdf361263 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Fri, 27 May 2022 16:13:23 -0700 Subject: [PATCH 50/53] add newline --- .github/workflows/publish-docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml index af8abe99..a87f2f1c 100644 --- a/.github/workflows/publish-docs.yml +++ b/.github/workflows/publish-docs.yml @@ -12,4 +12,4 @@ jobs: with: python-version: 3.x - run: pip install requirements/build-docs.txt - - run: mkdocs gh-deploy --force \ No newline at end of file + - run: mkdocs gh-deploy --force From 52f335a896468b45a4b96bc8ef3d51144846ad36 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 30 May 2022 17:19:48 -0700 Subject: [PATCH 51/53] minor readme revision --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c3d31ec7..0e72bd99 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ -IDOM connects your Python web framework of choice to a ReactJS frontend, allowing you to create **interactive websites without needing JavaScript!** +Django-IDOM connects your project to a ReactJS frontend, allowing you to create **interactive websites without needing JavaScript!** Following ReactJS styling, web elements are combined into [reusable "components"](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/your-first-components/index.html#parametrizing-components). These components can utilize [hooks](https://idom-docs.herokuapp.com/docs/reference/hooks-api.html) and [events](https://idom-docs.herokuapp.com/docs/guides/adding-interactivity/responding-to-events/index.html#async-event-handlers) to create infinitely complex web pages. From 8f645119f81d6a887011c7ec1e78b12307a6ed9c Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 30 May 2022 17:38:04 -0700 Subject: [PATCH 52/53] change contribute section names --- docs/contribute/{idom-env.md => django-idom.md} | 0 docs/contribute/{docs-env.md => docs.md} | 2 +- mkdocs.yml | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) rename docs/contribute/{idom-env.md => django-idom.md} (100%) rename docs/contribute/{docs-env.md => docs.md} (84%) diff --git a/docs/contribute/idom-env.md b/docs/contribute/django-idom.md similarity index 100% rename from docs/contribute/idom-env.md rename to docs/contribute/django-idom.md diff --git a/docs/contribute/docs-env.md b/docs/contribute/docs.md similarity index 84% rename from docs/contribute/docs-env.md rename to docs/contribute/docs.md index 00ade941..231fb603 100644 --- a/docs/contribute/docs-env.md +++ b/docs/contribute/docs.md @@ -1,4 +1,4 @@ -If you plan to make documentation changes to this repository, you'll need to install the following dependencies first: +If you plan to make changes to this documentation, you'll need to install the following dependencies first: - [Python 3.8+](https://www.python.org/downloads/) - [Git](https://git-scm.com/downloads) diff --git a/mkdocs.yml b/mkdocs.yml index 36c48a8b..487f21ae 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -12,8 +12,8 @@ nav: - Hooks: features/hooks.md - Template Tag: features/templatetag.md - Contribute: - - Django-IDOM Environment: contribute/idom-env.md - - Documentation Environment: contribute/docs-env.md + - Code: contribute/django-idom.md + - Docs: contribute/docs.md - Running Tests: contribute/running-tests.md - Changelog: changelog/index.md From d758ec828b12f1a5020cf337b2c0e7940de3068e Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 30 May 2022 17:42:00 -0700 Subject: [PATCH 53/53] IDOM Core tip --- docs/contribute/django-idom.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/contribute/django-idom.md b/docs/contribute/django-idom.md index 1307c8ef..4284ef66 100644 --- a/docs/contribute/django-idom.md +++ b/docs/contribute/django-idom.md @@ -1,3 +1,7 @@ +???+ tip "Looking to contribute features that are not Django specific?" + + Everything within the `django-idom` repository must be specific to Django integration. Check out the [IDOM Core documentation](https://idom-docs.herokuapp.com/docs/about/contributor-guide.html) to contribute general features, such as: components, hooks, events, etc. + If you plan to make code changes to this repository, you'll need to install the following dependencies first: - [Python 3.8+](https://www.python.org/downloads/)