{% extends "base.html" %} {% block title %}Issues{% endblock %} {# MODERN issues list (design A/B test). Same context variables, query params, form field names and JS as templates/issues/list.html — only the chrome differs. Every filter, column, badge, the quick-assign control, follow/unfollow, delete and the pagination links are carried over verbatim. #} {% block content %} {# Any non-empty query param other than the page number means the user has actually filtered — used to show the match count only when it is meaningful. #} {% set active_filters = [] %} {% for _k, _v in request.args.items() %} {% if _k != 'page' and _v %}{% set _ = active_filters.append(_k) %}{% endif %} {% endfor %} {# ── Header ───────────────────────────────────────────────────────────── #}
Issues
{% if current_user.role in ['admin','director','customer','auditor'] %} Log Issue {% endif %}
{# ── Filters ──────────────────────────────────────────────────────────── #} {# Same layout as the modern inspections list: fields fill two rows on the left, actions in a block on the right spanning both — Filter full-height, Clear above Export PDF. Contract and Facility stay adjacent because they cascade (rule 61). Below md the action block wraps underneath, full width. #}
{# ── Fields ──────────────────────────────────────────────────────── #}
{# ── Actions — spans both field rows ─────────────────────────────── #} {# mt-md-4 drops the block by roughly one label's height, so the buttons line up with the first row's INPUTS rather than its labels — that is what makes them shorter, since they still stretch to the bottom of the second row. The margin is md-only; below that the block wraps underneath the fields and needs its full width and natural height. #}
{# ── Results ──────────────────────────────────────────────────────────── #}
{% if active_filters %}
{{ issues.total }} issue{{ 's' if issues.total != 1 }} match {{ 'es' if issues.total == 1 }} your filters
{% endif %} {% if issues.items %}
{% for issue in issues.items %} {% set is_following = issue.id in followed_ids %} {% set sla = sla_status(issue) %} {% endfor %}
# Reported Severity Contract Facility / Area Description Status SLA Reporter Assigned
#{{ issue.id }} {{ issue.reported_at.strftime('%Y-%m-%d %H:%M') }} {{ issue.severity|title }} {% set _c = issue.resolved_facility.project if issue.resolved_facility else none %} {{ _c.name if _c else '—' }} {{ issue.resolved_facility.name if issue.resolved_facility else '—' }}
{{ issue.area.name if issue.area else '—' }}
60 %} title="{{ issue.description }}" style="cursor:help;"{% endif %}> {{ issue.description[:60] }}{% if issue.description|length > 60 %}…{% endif %} {{ issue.status|replace('_',' ')|title }} {% if sla == 'breached' %} Breached {% elif sla == 'at_risk' %} {% set hrs = sla_hours_remaining(issue) %} {{ hrs|abs|round(1) }}h left {% elif sla == 'ok' %} OK {% else %} {% endif %} {% if issue.reporter %} {{ issue.reporter.display_name }} {% else %}{% endif %} {% if current_user.role in ['admin', 'director', 'auditor'] and issue.status != 'resolved' %}
{% else %} {% if issue.assigned_user %}{{ issue.assigned_user.display_name }} {% else %}{% endif %} {% endif %} {% if issue.handler_type == 'facility' %}
Facility
{% elif issue.handler_type == 'vendor' %}
Vendor
{% endif %}
{# Following badge + inline unfollow #} {% if is_following %} Following
{% endif %} {% if current_user.role in ['admin','director','auditor'] or issue.assigned_to == current_user.id %} Edit {% else %} View {% endif %} {% if current_user.role in ['admin', 'director'] %}
{% endif %}
{% if issues.pages > 1 %}
{% endif %} {% else %}
No issues found.
{% endif %}
{% endblock %} {% block extra_js %} {% if current_user.role in ['admin', 'director', 'auditor'] %} {% endif %} {% endblock %}