Files
EpiSupport-Zammad-Scraper/templates/index.html
T
leopold.stroblandClaude Opus 4.8 bdcb17285c Watch EPIRent version and archive its download packages
- Poll the public download page for "Aktuelle Version <nr> vom <date>",
  report changes through the normal change feed and notification mail,
  and show the current version as a card on the overview. Runs on its own
  interval (default 30 min); the first run only records a baseline.
- Archive epirentServer.zip / epirentClient.zip per version number so we
  keep a download cache and history: streamed to disk with SHA-256 and
  size, fetched in a background thread so ticket polling is unaffected,
  with a free-space check before downloading (~1.1 GB per version).
- Retention is configurable via EPIRENT_DOWNLOAD_KEEP, where 0 means
  unlimited; a successful archive is reported as a change and by mail.
- New Downloads page listing the archived versions with checksums and
  links to fetch the cached files.
- Notification lines now omit the arrow when there is no previous value
  and drop the "#" for entries without a ticket.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 15:12:48 +02:00

130 lines
5.5 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% from "_macros.html" import change_row %}
{% block title %}Übersicht · EPI-Support{% endblock %}
{% block content %}
<section class="cards">
<div class="card"><span class="num">{{ stats.total }}</span><span class="lbl">Tickets gesamt</span></div>
<div class="card"><span class="num">{{ stats.open }}</span><span class="lbl">offen</span></div>
<div class="card {{ 'alert' if stats.unseen else '' }}">
<span class="num">{{ stats.unseen }}</span><span class="lbl">ungelesene Änderungen</span>
</div>
{% if epirent_version %}
<div class="card">
<span class="num">{{ epirent_version.version }}</span>
<span class="lbl">EPIRent-Version<br>vom {{ epirent_version.released_at }}</span>
</div>
{% endif %}
<div class="card status">
{% if last_run %}
<span class="num {{ 'ok' if last_run.status == 'ok' else 'err' }}">
{{ '✓' if last_run.status == 'ok' else '!' }}
</span>
<span class="lbl">letzter Abruf<br>{{ last_run.finished_at|dt }}</span>
{% else %}
<span class="num"></span><span class="lbl">startet</span>
{% endif %}
</div>
</section>
<div class="grid">
<section class="panel">
<div class="panel-head">
<h2>Ungelesene Änderungen{% if stats.unseen %} ({{ stats.unseen }}){% endif %}</h2>
{% if stats.unseen %}
<form method="post" action="{{ url_for('mark_read') }}">
<button class="btn-sm" type="submit">alle als gelesen</button>
</form>
{% endif %}
</div>
{% if recent %}
<ul class="feed compact">
{% for c in recent %}{{ change_row(c) }}{% endfor %}
</ul>
{% if stats.unseen > recent|length %}
<a class="more" href="{{ url_for('changes', show='unseen') }}">
+ {{ stats.unseen - recent|length }} weitere ungelesene anzeigen →</a>
{% endif %}
{% else %}
<p class="muted">Alles gelesen keine offenen Änderungen. 🎉</p>
{% endif %}
</section>
<section class="panel">
<div class="panel-head"><h2>Status-Filter</h2></div>
{% set arch = '1' if show_archived else none %}
<div class="chips">
<a class="chip {{ 'on' if not active_state }}" href="{{ url_for('index', sort=sort, dir=dir, archived=arch) }}">alle</a>
<a class="chip {{ 'on' if active_state == 'not_closed' }}"
href="{{ url_for('index', state='not_closed', sort=sort, dir=dir, archived=arch) }}">nicht geschlossen</a>
{% for s in states %}
<a class="chip {{ 'on' if active_state == s.state }}"
href="{{ url_for('index', state=s.state, sort=sort, dir=dir, archived=arch) }}">{{ s.state }} ({{ s.c }})</a>
{% endfor %}
</div>
<div class="chips" style="margin-top:.5rem">
{% if show_archived %}
<a class="chip on" href="{{ url_for('index', state=active_state or none, sort=sort, dir=dir) }}">erledigte ausblenden</a>
{% else %}
<a class="chip" href="{{ url_for('index', state=active_state or none, sort=sort, dir=dir, archived='1') }}">erledigte einblenden{% if archived_count %} ({{ archived_count }}){% endif %}</a>
{% endif %}
</div>
</section>
</div>
{% macro th(col, label) %}
{% set nextdir = 'asc' if (sort == col and dir == 'desc') else 'desc' %}
<th class="{{ 'sorted' if sort == col }}">
<a href="{{ url_for('index', state=active_state or none, sort=col, dir=nextdir, archived=request.args.get('archived')) }}">
{{ label }}{% if sort == col %} <span class="arrow">{{ '▼' if dir == 'desc' else '▲' }}</span>{% endif %}
</a>
</th>
{% endmacro %}
<section class="panel">
<div class="panel-head">
<h2>Tickets{% if active_state == 'not_closed' %} nicht geschlossen{% elif active_state %} {{ active_state }}{% endif %}</h2>
</div>
<table class="tickets">
<thead>
<tr>
{{ th('number', '#') }}{{ th('title', 'Titel') }}{{ th('state', 'Status') }}
{{ th('priority', 'Priorität') }}{{ th('owner', 'Bearbeiter') }}
{{ th('articles', 'Artikel') }}{{ th('updated', 'zuletzt geändert') }}
<th></th>
</tr>
</thead>
<tbody>
{% for t in tickets %}
{% set n = unseen_map.get(t.id) %}
<tr class="{{ 'row-unseen' if n }}{{ ' row-archived' if t.archived }}">
<td>
{% if n %}<span class="badge" title="{{ n }} unbestätigte Änderung(en)">{{ n }}</span>{% endif %}
<a href="{{ url_for('ticket_detail', ticket_id=t.id) }}">{{ t.number }}</a>
</td>
<td class="title">{{ t.title }}{% if t.archived %} <span class="tag">erledigt</span>{% endif %}</td>
<td><span class="state state-{{ t.state }}">{{ t.state }}</span></td>
<td>{{ t.priority }}</td>
<td>{{ t.owner if t.owner and t.owner != '-' else '—' }}</td>
<td>{{ t.article_count }}</td>
<td><time>{{ t.zammad_updated_at|dt }}</time></td>
<td class="rowact">
{% if t.archived %}
<form method="post" action="{{ url_for('unarchive_ticket', ticket_id=t.id) }}">
<button type="submit" title="Wieder einblenden"></button>
</form>
{% else %}
<form method="post" action="{{ url_for('archive_ticket', ticket_id=t.id) }}">
<button type="submit" title="Als wirklich erledigt ablegen (ausblenden)"></button>
</form>
{% endif %}
</td>
</tr>
{% else %}
<tr><td colspan="8" class="muted">Keine Tickets.</td></tr>
{% endfor %}
</tbody>
</table>
</section>
{% endblock %}