Files
Buffteks-Dev-Server/templates/tickets.html
2025-11-20 15:49:45 +00:00

131 lines
6.4 KiB
HTML

{% extends "base.html" %}
{% block title %}Tickets — {{ brand }}{% endblock %}
{% block content %}
<h1 class="text-3xl font-bold">Tickets</h1>
<p class="text-white/60 text-sm">{{ tagline }}</p>
{# ---------------- Filter Panel (dark) ---------------- #}
<section class="mt-5 rounded-2xl overflow-hidden border shadow-lg"
style="border-color: color-mix(in oklab, var(--bt-accent) 35%, transparent);">
<div class="h-1.5" style="background: var(--bt-accent);"></div>
<div class="bg-slate-900/60 backdrop-blur-sm text-white p-4 sm:p-5">
<h2 class="text-base font-semibold flex items-center gap-2">
<span class="inline-block w-2.5 h-2.5 rounded-full" style="background: var(--bt-accent);"></span>
Filter & Search
</h2>
<form method="get" class="mt-3 grid grid-cols-1 md:grid-cols-4 gap-3">
<div>
<label class="text-xs text-white/60">Status</label>
<select name="status"
class="block w-full bg-slate-900/70 text-white border border-white/15 rounded-lg px-2 py-2
focus:outline-none focus:ring-2"
style="--tw-ring-color: color-mix(in oklab, var(--bt-accent) 60%, transparent);">
<option value="">Any</option>
{% for s in ['submitted','triage','in_progress','awaiting_review','done','blocked','needs_more_info','cancelled'] %}
<option value="{{s}}" {{ 'selected' if request.args.get('status')==s else '' }}>{{ s.replace('_',' ').title() }}</option>
{% endfor %}
</select>
</div>
<div>
<label class="text-xs text-white/60">Assignee (Discord ID)</label>
<input name="assignee" value="{{ request.args.get('assignee','') }}"
class="w-full bg-slate-900/70 text-white placeholder-white/40 border border-white/15 rounded-lg px-3 py-2
focus:outline-none focus:ring-2"
style="--tw-ring-color: color-mix(in oklab, var(--bt-accent) 60%, transparent);"
placeholder="1234567890" />
</div>
<div class="md:col-span-2">
<label class="text-xs text-white/60">Search</label>
<div class="flex gap-2">
<input name="q" value="{{ request.args.get('q','') }}"
class="w-full bg-slate-900/70 text-white placeholder-white/40 border border-white/15 rounded-lg px-3 py-2
focus:outline-none focus:ring-2"
style="--tw-ring-color: color-mix(in oklab, var(--bt-accent) 60%, transparent);"
placeholder="title, description, labels…" />
<button type="submit"
class="px-4 py-2 rounded-lg border border-white/15"
style="background: var(--bt-accent); color:#0a0a0a;">Apply</button>
</div>
</div>
</form>
</div>
</section>
{# ---------------- Card helpers ---------------- #}
{% macro status_badge(s) -%}
{% set label = s.replace('_',' ').title() %}
{% if s == 'done' %}
<span class="px-2 py-0.5 text-xs rounded-full bg-emerald-500/15 text-emerald-300 border border-emerald-400/30">{{ label }}</span>
{% elif s in ['blocked','cancelled'] %}
<span class="px-2 py-0.5 text-xs rounded-full bg-rose-500/15 text-rose-300 border border-rose-400/30">{{ label }}</span>
{% elif s in ['awaiting_review','needs_more_info'] %}
<span class="px-2 py-0.5 text-xs rounded-full bg-amber-500/15 text-amber-300 border border-amber-400/30">{{ label }}</span>
{% elif s in ['in_progress','triage'] %}
<span class="px-2 py-0.5 text-xs rounded-full bg-sky-500/15 text-sky-300 border border-sky-400/30">{{ label }}</span>
{% else %}
<span class="px-2 py-0.5 text-xs rounded-full bg-white/10 text-white/80 border border-white/20">{{ label }}</span>
{% endif %}
{%- endmacro %}
{% macro priority_chip(p) -%}
{% if p == 'urgent' %}
<span class="tag bg-rose-500/20 border-rose-400/30 text-rose-200">Priority: Urgent</span>
{% elif p == 'high' %}
<span class="tag bg-amber-500/20 border-amber-400/30 text-amber-100">Priority: High</span>
{% elif p == 'low' %}
<span class="tag bg-slate-500/20 border-slate-400/30 text-slate-200">Priority: Low</span>
{% else %}
<span class="tag">Priority: Normal</span>
{% endif %}
{%- endmacro %}
{# ---------------- Ticket Grid ---------------- #}
<div class="mt-6 grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-5">
{% for t in tickets %}
<a href="{{ url_for('ticket_detail', ticket_id=t.id) }}"
class="group relative block rounded-2xl border border-white/10 bg-gradient-to-b from-white/5 to-white/[0.02] p-4 sm:p-5
shadow-[0_10px_30px_-10px_rgba(0,0,0,.4)] hover:border-white/20 hover:shadow-[0_18px_40px_-12px_rgba(0,0,0,.6)] transition">
<span class="pointer-events-none absolute inset-0 rounded-2xl ring-1 ring-transparent group-hover:ring-[color:var(--bt-accent)]/40"></span>
<div class="flex items-start justify-between gap-3">
<div class="min-w-0">
<h3 class="font-semibold text-base sm:text-lg leading-snug truncate">
<span class="text-white/50">#{{ t.id }}</span> · {{ t.title }}
</h3>
<div class="mt-1 text-xs text-white/60">Opened by {{ t.created_by_name or t.created_by_id or 'Unknown' }}</div>
</div>
{{ status_badge(t.status) }}
</div>
<p class="mt-3 text-white/85 text-sm sm:text-[0.95rem]"
style="display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;">
{{ t.description }}
</p>
<div class="mt-3 flex flex-wrap items-center gap-2 text-xs">
{{ priority_chip(t.priority) }}
{% if t.sprint %}<span class="tag">Sprint: {{ t.sprint }}</span>{% endif %}
{% if t.due_at %}<span class="tag bg-rose-500/15 border-rose-400/30 text-rose-200">Due: {{ t.due_at.strftime('%Y-%m-%d') }}</span>{% endif %}
{% for label in t.label_list() %}<span class="tag">{{ label }}</span>{% endfor %}
</div>
<div class="mt-4 flex items-center justify-between text-xs text-white/60">
<div>
{% if t.assignee_name or t.assignee_id %}
Assigned to <b class="text-white/80">{{ t.assignee_name or ('<@' ~ t.assignee_id ~ '>') }}</b>
{% else %}
<span class="text-white/40 italic">Unassigned</span>
{% endif %}
</div>
<div class="whitespace-nowrap">Updated {{ t.updated_at.strftime('%Y-%m-%d %H:%M') }} UTC</div>
</div>
</a>
{% else %}
<div class="text-white/60">No tickets found.</div>
{% endfor %}
</div>
{% endblock %}