Add in-app help page with user manual (Romanian)
Adds a /help page served from the dashboard navigation, containing the full
Romanian user manual for operators: dashboard, playlist management, adding
media, removing files from playlists, player management, and the advanced
edited-media view.
Implementation notes
- Manual is pre-rendered to HTML with pandoc and shipped as a static asset
(app/static/help/_manual_body.html) rather than parsed at runtime. This
keeps the container free of a Markdown dependency and makes the page render
identically regardless of what is installed.
- /help is login-protected; the sidebar table of contents is derived from the
level-2 headings at request time.
- Screenshots are served from app/static/help/screenshots/ (32 images).
- Regenerate after editing the manual:
documentatie/convert_help_page.sh
docker compose up -d --build
Also adds
- backup_players_playlists.sh / restore_database.sh for DB backup and restore.
- .gitignore rules so local database backups (real production data), generated
.docx files and duplicate screenshot copies are never committed.
This commit is contained in:
@@ -89,6 +89,50 @@ def dashboard():
|
||||
)
|
||||
|
||||
|
||||
@main_bp.route('/help')
|
||||
@login_required
|
||||
def help_page():
|
||||
"""User manual / help page.
|
||||
|
||||
The manual lives at ``app/static/help/_manual_body.html`` — a pre-rendered
|
||||
HTML fragment generated from ``documentatie/Manual-Utilizare-DigiServer.md``
|
||||
with ``pandoc`` (see ``documentatie/convert_help_page.sh``).
|
||||
|
||||
It is shipped as a static asset rather than parsed at runtime on purpose:
|
||||
it keeps the runtime free of a Markdown dependency and means the help page
|
||||
renders identically regardless of what is installed in the container.
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
|
||||
base_dir = os.path.dirname(os.path.dirname(__file__)) # -> app/
|
||||
manual_path = os.path.join(base_dir, 'static', 'help', '_manual_body.html')
|
||||
|
||||
manual_html = ''
|
||||
toc = []
|
||||
try:
|
||||
with open(manual_path, 'r', encoding='utf-8') as f:
|
||||
manual_html = f.read()
|
||||
|
||||
# Build the sidebar from the level-2 headings (`<h2 id="...">`), which
|
||||
# is exactly the printed table of contents of the manual. Nested <h3>
|
||||
# entries would make the sidebar unwieldy, so they are left out.
|
||||
for anchor, title in re.findall(
|
||||
r'<h2 id="([^"]+)"[^>]*>(.*?)</h2>', manual_html, re.DOTALL
|
||||
):
|
||||
clean = re.sub(r'<[^>]+>', '', title).strip()
|
||||
if clean:
|
||||
toc.append({'anchor': anchor, 'title': clean})
|
||||
except FileNotFoundError:
|
||||
manual_html = (
|
||||
'<h1>Manual indisponibil</h1>'
|
||||
'<p>Fișierul manualului nu a fost găsit. '
|
||||
'Rulați <code>documentatie/convert_help_page.sh</code> pentru a-l genera.</p>'
|
||||
)
|
||||
|
||||
return render_template('help.html', manual_html=manual_html, toc=toc)
|
||||
|
||||
|
||||
@main_bp.route('/health')
|
||||
def health():
|
||||
"""Health check endpoint"""
|
||||
|
||||
Reference in New Issue
Block a user