diff --git a/Doc/Guide utilisateur.odt b/Doc/Guide utilisateur.odt new file mode 100644 index 0000000..64ceb5a Binary files /dev/null and b/Doc/Guide utilisateur.odt differ diff --git a/Doc/Guide utilisateur.pdf b/Doc/Guide utilisateur.pdf new file mode 100644 index 0000000..f9fd240 Binary files /dev/null and b/Doc/Guide utilisateur.pdf differ diff --git a/frontend/app/routes.py b/frontend/app/routes.py index 3699c96..266de87 100644 --- a/frontend/app/routes.py +++ b/frontend/app/routes.py @@ -46,6 +46,9 @@ YOUTUBE_JOBS_DIR = Path(tempfile.gettempdir()) / "pysonnerie-youtube-jobs" _YOUTUBE_JOBS_LOCK = threading.Lock() _YOUTUBE_JOBS: dict[str, dict[str, object]] = {} +AUTH_HTTP_ERRORS = ("Erreur HTTP 401", "Erreur HTTP 403") +BACKEND_UNAVAILABLE_ERRORS = ("Backend inaccessible", "Echec du controle de sante") + def _backend_client() -> BackendClient | None: backend_url = session.get("backend_url") @@ -330,10 +333,17 @@ def login() -> str | Response: try: client.health() client.list_triggers() - except BackendApiError: + except BackendApiError as exc: + error_text = str(exc) + if any(code in error_text for code in AUTH_HTTP_ERRORS): + login_error = "Identifiant ou mot de passe incorrect." + elif any(code in error_text for code in BACKEND_UNAVAILABLE_ERRORS): + login_error = "Impossible de se connecter au service pour le moment. Vérifiez que le backend est demarré puis réessayez." + else: + login_error = "Connexion impossible pour le moment. Réessayez dans quelques instants." return render_template( "login.html", - login_error="Impossible de se connecter au service pour le moment. Vérifiez que le backend est demarré puis réessayez.", + login_error=login_error, attempted_username=username, ) diff --git a/frontend/app/templates/base.html b/frontend/app/templates/base.html index 79ce6dd..a932d21 100644 --- a/frontend/app/templates/base.html +++ b/frontend/app/templates/base.html @@ -26,7 +26,7 @@ html, body { margin: 0; padding: 0; - min-height: 100%; + height: 100%; } body { @@ -37,6 +37,15 @@ body { radial-gradient(circle at 100% 100%, #d5efe6 0%, transparent 40%), var(--bg); overflow-x: hidden; + min-height: 100dvh; + display: flex; + flex-direction: column; +} + +.app-content { + flex: 1 0 auto; + min-height: 0; + display: flow-root; } h1, @@ -142,7 +151,7 @@ h3 { } .auth-wrap { - min-height: 100vh; + min-height: 100%; display: grid; place-items: center; padding: 1rem; @@ -528,6 +537,17 @@ td { background: #fff; } +.app-footer { + flex-shrink: 0; + margin: 0; + padding: 0.75rem 1.2rem 1rem; + padding-top: 0.75rem; + border-top: 1px solid var(--line); + color: var(--muted); + font-size: 0.85rem; + text-align: center; +} + @media (max-width: 1080px) { .panel:nth-child(1), .panel:nth-child(2), @@ -572,7 +592,9 @@ td { {% endif %} {% endwith %} - {% block content %}{% endblock %} +
{% block content %}{% endblock %}
+ +