Skip to content

Commit a0b75e0

Browse files
committed
parametrized components + serve web modules
1 parent b4f256b commit a0b75e0

File tree

16 files changed

+137
-51
lines changed

16 files changed

+137
-51
lines changed

src/django_idom/__init__.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
from .websocket_consumer import (
2-
IdomAsyncWebSocketConsumer,
3-
django_idom_websocket_consumer_url,
4-
)
1+
from .app_paths import django_idom_web_modules_path, django_idom_websocket_consumer_path
52

63

74
__version__ = "0.0.1"
8-
__all__ = ["IdomAsyncWebSocketConsumer", "django_idom_websocket_consumer_url"]
5+
__all__ = ["django_idom_websocket_consumer_path", "django_idom_web_modules_path"]

src/django_idom/app_paths.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from django.urls import path
2+
3+
from . import views
4+
from .app_settings import IDOM_WEB_MODULES_URL, IDOM_WEBSOCKET_URL
5+
from .websocket_consumer import IdomAsyncWebSocketConsumer
6+
7+
8+
def django_idom_websocket_consumer_path(*args, **kwargs):
9+
"""Return a URL resolver for :class:`IdomAsyncWebSocketConsumer`
10+
11+
While this is relatively uncommon in most Django apps, because the URL of the
12+
websocket must be defined by the setting ``IDOM_WEBSOCKET_URL``. There's no need
13+
to allow users to configure the URL themselves
14+
"""
15+
return path(
16+
IDOM_WEBSOCKET_URL + "<view_id>/",
17+
IdomAsyncWebSocketConsumer.as_asgi(),
18+
*args,
19+
**kwargs,
20+
)
21+
22+
23+
def django_idom_web_modules_path(*args, **kwargs):
24+
return path(
25+
IDOM_WEB_MODULES_URL + "<path:file>",
26+
views.web_modules_file,
27+
*args,
28+
**kwargs,
29+
)

src/django_idom/app_settings.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@
1010
for file in (APP_DIR / "templates" / "idom").iterdir()
1111
}
1212

13-
IDOM_WEBSOCKET_URL = getattr(settings, "IDOM_WEBSOCKET_URL", "_idom/")
14-
if not IDOM_WEBSOCKET_URL.endswith("/"):
15-
IDOM_WEBSOCKET_URL += "/"
13+
IDOM_BASE_URL = getattr(settings, "IDOM_BASE_URL", "_idom/")
14+
IDOM_WEBSOCKET_URL = IDOM_BASE_URL + "websocket/"
15+
IDOM_WEB_MODULES_URL = IDOM_BASE_URL + "web_module/"

src/django_idom/templates/idom/view.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
mountViewToElement(
77
mountPoint,
88
"{{ idom_websocket_url }}",
9+
"{{ idom_web_modules_url }}",
910
"{{ idom_view_id }}",
1011
"{{ idom_view_params }}"
1112
);

src/django_idom/templatetags/idom.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
1+
import json
2+
from urllib.parse import urlencode
13
from uuid import uuid4
24

35
from django import template
46

5-
from django_idom.app_settings import IDOM_WEBSOCKET_URL, TEMPLATE_FILE_PATHS
7+
from django_idom.app_settings import (
8+
IDOM_WEB_MODULES_URL,
9+
IDOM_WEBSOCKET_URL,
10+
TEMPLATE_FILE_PATHS,
11+
)
12+
from ..app_components import has_component
613

714

815
register = template.Library()
@@ -15,10 +22,16 @@ def idom_head():
1522

1623

1724
@register.inclusion_tag(TEMPLATE_FILE_PATHS["view"])
18-
def idom_view(view_id, view_params=""):
25+
def idom_view(_component_id_, **kwargs):
26+
if not has_component(_component_id_):
27+
raise ValueError(f"No component {_component_id_!r} exists")
28+
29+
json_kwargs = json.dumps(kwargs, separators=(",", ":"))
30+
1931
return {
2032
"idom_websocket_url": IDOM_WEBSOCKET_URL,
33+
"idom_web_modules_url": IDOM_WEB_MODULES_URL,
2134
"idom_mount_uuid": uuid4().hex,
22-
"idom_view_id": view_id,
23-
"idom_view_params": view_params,
35+
"idom_view_id": _component_id_,
36+
"idom_view_params": urlencode({"kwargs": json_kwargs}),
2437
}

src/django_idom/views.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from django.http import HttpResponse
2+
from idom.config import IDOM_WED_MODULES_DIR
3+
4+
5+
def web_modules_file(request, file: str) -> HttpResponse:
6+
file_path = IDOM_WED_MODULES_DIR.current.joinpath(*file.split("/"))
7+
return HttpResponse(file_path.read_text(), content_type="text/javascript")

src/django_idom/websocket_consumer.py

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,20 @@
11
"""Anything used to construct a websocket endpoint"""
22
import asyncio
3+
import json
34
import logging
45
from typing import Any
56
from urllib.parse import parse_qsl
67

78
from channels.generic.websocket import AsyncJsonWebsocketConsumer
8-
from django.urls import path
99
from idom.core.dispatcher import dispatch_single_view
1010
from idom.core.layout import Layout, LayoutEvent
1111

1212
from .app_components import get_component, has_component
13-
from .app_settings import IDOM_WEBSOCKET_URL
1413

1514

1615
logger = logging.getLogger(__name__)
1716

1817

19-
def django_idom_websocket_consumer_url(*args, **kwargs):
20-
"""Return a URL resolver for :class:`IdomAsyncWebSocketConsumer`
21-
22-
While this is relatively uncommon in most Django apps, because the URL of the
23-
websocket must be defined by the setting ``IDOM_WEBSOCKET_URL``. There's no need
24-
to allow users to configure the URL themselves
25-
"""
26-
return path(
27-
IDOM_WEBSOCKET_URL + "<view_id>/",
28-
IdomAsyncWebSocketConsumer.as_asgi(),
29-
*args,
30-
**kwargs,
31-
)
32-
33-
3418
class IdomAsyncWebSocketConsumer(AsyncJsonWebsocketConsumer):
3519
"""Communicates with the browser to perform actions on-demand."""
3620

@@ -59,7 +43,9 @@ async def _run_dispatch_loop(self):
5943
return
6044

6145
component_constructor = get_component(view_id)
62-
component_kwargs = dict(parse_qsl(self.scope["query_string"]))
46+
47+
query_dict = dict(parse_qsl(self.scope["query_string"].decode()))
48+
component_kwargs = json.loads(query_dict.get("kwargs", "{}"))
6349

6450
try:
6551
component_instance = component_constructor(**component_kwargs)

src/js/package-lock.json

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/js/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@
1010
"build": "rollup --config",
1111
"format": "prettier --ignore-path .gitignore --write ."
1212
},
13-
"dependencies": {
14-
"idom-client-react": "^0.8.2"
15-
},
1613
"devDependencies": {
1714
"prettier": "^2.2.1",
1815
"rollup": "^2.35.1",
1916
"rollup-plugin-commonjs": "^10.1.0",
2017
"rollup-plugin-node-resolve": "^5.2.0",
2118
"rollup-plugin-replace": "^2.2.0"
19+
},
20+
"dependencies": {
21+
"idom-client-react": "^0.8.5"
2222
}
2323
}

src/js/src/index.js

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { mountLayoutWithWebSocket } from "idom-client-react";
22

3-
43
// Set up a websocket at the base endpoint
54
let LOCATION = window.location;
65
let WS_PROTOCOL = "";
@@ -11,8 +10,22 @@ if (LOCATION.protocol == "https:") {
1110
}
1211
let WS_ENDPOINT_URL = WS_PROTOCOL + LOCATION.host + "/";
1312

13+
export function mountViewToElement(
14+
mountPoint,
15+
idomWebsocketUrl,
16+
idomWebModulesUrl,
17+
viewId,
18+
queryParams
19+
) {
20+
const fullWebsocketUrl =
21+
WS_ENDPOINT_URL + idomWebsocketUrl + viewId + "/?" + queryParams;
22+
23+
const fullWebModulesUrl = LOCATION.origin + "/" + idomWebModulesUrl
24+
const loadImportSource = (source, sourceType) => {
25+
return import(
26+
sourceType == "NAME" ? `${fullWebModulesUrl}${source}` : source
27+
);
28+
};
1429

15-
export function mountViewToElement(mountPoint, idomWebsocketUrl, viewId, queryParams) {
16-
const fullWebsocketUrl = WS_ENDPOINT_URL + idomWebsocketUrl + viewId + "/";
17-
mountLayoutWithWebSocket(mountPoint, fullWebsocketUrl);
30+
mountLayoutWithWebSocket(mountPoint, fullWebsocketUrl, loadImportSource);
1831
}

0 commit comments

Comments
 (0)