diff --git a/plugins/trainingsplan/app.py b/plugins/trainingsplan/app.py index b599e81..199c295 100644 --- a/plugins/trainingsplan/app.py +++ b/plugins/trainingsplan/app.py @@ -16,7 +16,25 @@ from schema_contract import default_config, normalize_training_config, stable_id from storage import atomic_json_write, utc_now BASE_DIR = Path(__file__).resolve().parent -DATA_DIR = Path(os.environ.get("DATA_DIR", BASE_DIR / "data")).resolve() + + +def resolve_data_dir() -> Path: + configured = os.environ.get("DATA_DIR", "").strip() + if configured: + return Path(configured).expanduser().resolve() + suite_data = os.environ.get("BOEHMITOOLS_DATA", "").strip() + for candidate in ( + Path("/home/michael/boehmitools/runtime/training/data/trainingsplan"), + Path("/home/michael/runtime/training/data/trainingsplan"), + ): + if any((candidate / "plans").glob("*.json")): + return candidate.resolve() + if suite_data: + return (Path(suite_data).expanduser() / "trainingsplan").resolve() + return (BASE_DIR / "data").resolve() + + +DATA_DIR = resolve_data_dir() PLANS_DIR = DATA_DIR / "plans" ACTIVE_FILE = DATA_DIR / "active.txt" LEGACY_CONFIG = DATA_DIR / "config.json" @@ -209,6 +227,18 @@ def index(): return Response((STATIC_DIR / "index.html").read_text(encoding="utf-8"), mimetype="text/html") +@app.route("/api/status") +def api_status(): + return jsonify({ + "name": "Trainingsplan-Backend", + "status": "ok", + "data_dir": str(DATA_DIR), + "plans_dir": str(PLANS_DIR), + "plans": list_plan_ids(), + "active": get_active(), + }) + + @app.route("/api/plans", methods=["GET"]) def api_plans(): active = get_active() diff --git a/plugins/trainingsplan/backend.py b/plugins/trainingsplan/backend.py index ab97b2c..2924a87 100644 --- a/plugins/trainingsplan/backend.py +++ b/plugins/trainingsplan/backend.py @@ -3,16 +3,33 @@ from __future__ import annotations import os +from pathlib import Path from a2wsgi import WSGIMiddleware from core.loader import load_module +def _has_plans(path: Path) -> bool: + return any((path / "plans").glob("*.json")) + + +def _resolve_data_dir(default: Path) -> Path: + for candidate in ( + Path("/home/michael/boehmitools/runtime/training/data/trainingsplan"), + Path("/home/michael/runtime/training/data/trainingsplan"), + ): + if _has_plans(candidate): + return candidate.resolve() + if _has_plans(default): + return default + return default + + def create_app(ctx): # app.py liest DATA_DIR beim Import und legt dort den ersten Plan an. previous = os.environ.get("DATA_DIR") - os.environ["DATA_DIR"] = str(ctx.data_dir) + os.environ["DATA_DIR"] = str(_resolve_data_dir(ctx.data_dir)) try: module = load_module(ctx.path("app.py"), f"btp_{ctx.id}_app") finally: diff --git a/plugins/trainingsplan/static/index.html b/plugins/trainingsplan/static/index.html index c8a61aa..c7a3d86 100644 --- a/plugins/trainingsplan/static/index.html +++ b/plugins/trainingsplan/static/index.html @@ -1,850 +1,540 @@ - - - Trainingsplan-Editor - + + +Trainingsplan-Editor + + + - -
-
-
TP
-
-

Trainingsplan-Editor

-
Lade...
+ +
+
+
+
+

Trainingsplan-Editor

+

Pläne, Tage, Warm-up, Cool-down und Übungen pflegen.

+
+
+ + + + + +
-
- - - - - - -
-
- -
- - -
-
- - -
-
+
- +$("planSelect").addEventListener("change", async (event) => { + if (state.dirty && !confirm("Ungespeicherte Änderungen verwerfen?")) { + renderPlanSelect(); + return; + } + try { + await api(`/api/plans/${encodeURIComponent(event.target.value)}/select`, {method: "POST"}); + await loadPlan(event.target.value); + } catch (err) { + toast(err.message, "err"); + } +}); + +window.addEventListener("beforeunload", (event) => { + if (!state.dirty) return; + event.preventDefault(); + event.returnValue = ""; +}); + +const ready = window.BT?.ready || Promise.resolve(); +ready.then(() => loadPlans()).catch((err) => showError(err.message)); +