Files
EpiSupport-Zammad-Scraper/templates/index.html
T
leopold.stroblandClaude Opus 4.8 528d66b2b0 Add "truly done" ticket archiving with auto-unhide
- Let the user mark closed tickets as really done and hide them, so
  tickets closed prematurely by an agent stay visible until confirmed
- User-side "archived" flag stored in the DB (independent of Zammad),
  added via a schema migration on existing databases
- Hide archived tickets from the overview by default with an
  "erledigte einblenden" toggle; archive/unarchive from the ticket
  detail page and via a per-row quick action
- Poller automatically un-hides an archived ticket when new activity is
  detected, so nothing is missed

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 17:34:09 +02:00

124 lines
5.3 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>
<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 %}