7 Commits

10 changed files with 39 additions and 14 deletions

View File

@ -0,0 +1,3 @@
import { polyfillCountryFlagEmojis } from "country-flag-emoji-polyfill";
polyfillCountryFlagEmojis();

View File

@ -106,6 +106,7 @@ $hovered-red-text-color: #ff4d4d;
color: $text-color; color: $text-color;
font-weight: normal; font-weight: normal;
line-height: 1.3em; line-height: 1.3em;
font-family: "Twemoji Country Flags", sans-serif;
&:hover { &:hover {
background-color: $background-color-hovered; background-color: $background-color-hovered;

View File

@ -23,6 +23,7 @@
<script type="module" src={{ static("bundled/core/components/include-index.ts") }}></script> <script type="module" src={{ static("bundled/core/components/include-index.ts") }}></script>
<script type="module" src="{{ static('bundled/alpine-index.js') }}"></script> <script type="module" src="{{ static('bundled/alpine-index.js') }}"></script>
<script type="module" src="{{ static('bundled/htmx-index.js') }}"></script> <script type="module" src="{{ static('bundled/htmx-index.js') }}"></script>
<script type="module" src="{{ static('bundled/country-flags-index.ts') }}"></script>
<!-- Jquery declared here to be accessible in every django widgets --> <!-- Jquery declared here to be accessible in every django widgets -->
<script src="{{ static('bundled/vendored/jquery.min.js') }}"></script> <script src="{{ static('bundled/vendored/jquery.min.js') }}"></script>

View File

@ -6,9 +6,7 @@ import { defineConfig } from "@hey-api/openapi-ts";
export default defineConfig({ export default defineConfig({
input: resolve(__dirname, "./staticfiles/generated/openapi/schema.json"), input: resolve(__dirname, "./staticfiles/generated/openapi/schema.json"),
output: { output: {
lint: "biome", path: resolve(__dirname, "./staticfiles/generated/openapi/client"),
format: "biome",
path: resolve(__dirname, "./staticfiles/generated/openapi"),
}, },
plugins: [ plugins: [
{ {

7
package-lock.json generated
View File

@ -22,6 +22,7 @@
"3d-force-graph": "^1.73.4", "3d-force-graph": "^1.73.4",
"alpinejs": "^3.14.7", "alpinejs": "^3.14.7",
"chart.js": "^4.4.4", "chart.js": "^4.4.4",
"country-flag-emoji-polyfill": "^0.1.8",
"cytoscape": "^3.30.2", "cytoscape": "^3.30.2",
"cytoscape-cxtmenu": "^3.5.0", "cytoscape-cxtmenu": "^3.5.0",
"cytoscape-klay": "^3.1.4", "cytoscape-klay": "^3.1.4",
@ -3379,6 +3380,12 @@
"url": "https://opencollective.com/core-js" "url": "https://opencollective.com/core-js"
} }
}, },
"node_modules/country-flag-emoji-polyfill": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/country-flag-emoji-polyfill/-/country-flag-emoji-polyfill-0.1.8.tgz",
"integrity": "sha512-Mbah52sADS3gshUYhK5142gtUuJpHYOXlXtLFI3Ly4RqgkmPMvhX9kMZSTqDM8P7UqtSW99eHKFphhQSGXA3Cg==",
"license": "MIT"
},
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.6", "version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",

View File

@ -7,6 +7,7 @@
"compile": "vite build --mode production", "compile": "vite build --mode production",
"compile-dev": "vite build --mode development", "compile-dev": "vite build --mode development",
"serve": "vite build --mode development --watch --minify false", "serve": "vite build --mode development --watch --minify false",
"openapi": "openapi-ts",
"analyse-dev": "vite-bundle-visualizer --mode development", "analyse-dev": "vite-bundle-visualizer --mode development",
"analyse-prod": "vite-bundle-visualizer --mode production", "analyse-prod": "vite-bundle-visualizer --mode production",
"check": "biome check --write" "check": "biome check --write"
@ -16,7 +17,7 @@
"license": "GPL-3.0-only", "license": "GPL-3.0-only",
"sideEffects": [".css"], "sideEffects": [".css"],
"imports": { "imports": {
"#openapi": "./staticfiles/generated/openapi/index.ts", "#openapi": "./staticfiles/generated/openapi/client/index.ts",
"#core:*": "./core/static/bundled/*", "#core:*": "./core/static/bundled/*",
"#pedagogy:*": "./pedagogy/static/bundled/*", "#pedagogy:*": "./pedagogy/static/bundled/*",
"#counter:*": "./counter/static/bundled/*", "#counter:*": "./counter/static/bundled/*",
@ -48,6 +49,7 @@
"3d-force-graph": "^1.73.4", "3d-force-graph": "^1.73.4",
"alpinejs": "^3.14.7", "alpinejs": "^3.14.7",
"chart.js": "^4.4.4", "chart.js": "^4.4.4",
"country-flag-emoji-polyfill": "^0.1.8",
"cytoscape": "^3.30.2", "cytoscape": "^3.30.2",
"cytoscape-cxtmenu": "^3.5.0", "cytoscape-cxtmenu": "^3.5.0",
"cytoscape-klay": "^3.1.4", "cytoscape-klay": "^3.1.4",

View File

@ -50,7 +50,13 @@ class Command(CollectStatic):
return Path(location) return Path(location)
Scss.compile(self.collect_scss()) Scss.compile(self.collect_scss())
OpenApi.compile() # This needs to be prior to javascript bundling openapi = OpenApi.compile() # This needs to be prior to javascript bundling
if openapi is not None:
_ = openapi.wait()
if openapi.returncode:
raise RuntimeError(
f"Openapi generation failed with returncode {openapi.returncode}"
)
JSBundler.compile() JSBundler.compile()
collected = super().collect() collected = super().collect()

View File

@ -15,11 +15,18 @@ class Command(Runserver):
"""Light wrapper around default runserver that integrates javascirpt auto bundling.""" """Light wrapper around default runserver that integrates javascirpt auto bundling."""
def run(self, **options): def run(self, **options):
OpenApi.compile() is_django_reload = os.environ.get(DJANGO_AUTORELOAD_ENV) is not None
if (
os.environ.get(DJANGO_AUTORELOAD_ENV) is None proc = OpenApi.compile()
and settings.PROCFILE_STATIC is not None # Ensure that the first runserver launch creates openapi files
): # before the bundler starts so that it detects them
# When django is reloaded, we can keep this process in background
# to reduce reload time
if proc is not None and not is_django_reload:
_ = proc.wait()
if not is_django_reload and settings.PROCFILE_STATIC is not None:
start_composer(settings.PROCFILE_STATIC) start_composer(settings.PROCFILE_STATIC)
_ = atexit.register(stop_composer, procfile=settings.PROCFILE_STATIC) _ = atexit.register(stop_composer, procfile=settings.PROCFILE_STATIC)
super().run(**options) super().run(**options)

View File

@ -95,7 +95,7 @@ class JSBundler:
def compile(): def compile():
"""Bundle js files with the javascript bundler for production.""" """Bundle js files with the javascript bundler for production."""
process = subprocess.Popen(["npm", "run", "compile"]) process = subprocess.Popen(["npm", "run", "compile"])
process.wait() _ = process.wait()
if process.returncode: if process.returncode:
raise RuntimeError(f"Bundler failed with returncode {process.returncode}") raise RuntimeError(f"Bundler failed with returncode {process.returncode}")
@ -163,7 +163,7 @@ class OpenApi:
OPENAPI_DIR = GENERATED_ROOT / "openapi" OPENAPI_DIR = GENERATED_ROOT / "openapi"
@classmethod @classmethod
def compile(cls): def compile(cls) -> subprocess.Popen[bytes] | None:
"""Compile a TS client for the sith API. Only generates it if it changed.""" """Compile a TS client for the sith API. Only generates it if it changed."""
logging.getLogger("django").info("Compiling open api typescript client") logging.getLogger("django").info("Compiling open api typescript client")
out = cls.OPENAPI_DIR / "schema.json" out = cls.OPENAPI_DIR / "schema.json"
@ -191,4 +191,4 @@ class OpenApi:
with open(out, "w") as f: with open(out, "w") as f:
_ = f.write(schema) _ = f.write(schema)
subprocess.run(["npx", "openapi-ts"], check=True) return subprocess.Popen(["npm", "run", "openapi"])

View File

@ -14,7 +14,7 @@
"types": ["jquery", "alpinejs"], "types": ["jquery", "alpinejs"],
"lib": ["es7"], "lib": ["es7"],
"paths": { "paths": {
"#openapi": ["./staticfiles/generated/openapi/index.ts"], "#openapi": ["./staticfiles/generated/openapi/client/index.ts"],
"#core:*": ["./core/static/bundled/*"], "#core:*": ["./core/static/bundled/*"],
"#pedagogy:*": ["./pedagogy/static/bundled/*"], "#pedagogy:*": ["./pedagogy/static/bundled/*"],
"#counter:*": ["./counter/static/bundled/*"], "#counter:*": ["./counter/static/bundled/*"],