Files
devplacepy/devplacepy/templates/issues.html
T
retoor 741d7aade6 docs: add block/mute user relations, emoji-sync CLI, and uid indexes
- Add `/block`, `/mute` endpoints with block/unblock and mute/unmute functionality in `routers/relations.py`, hiding blocked users' content everywhere except their own profile while muting only suppresses notifications
- Introduce `devplace emoji-sync` CLI command to regenerate `static/js/emoji-shortcodes.js` from the emoji library, documented in `CLAUDE.md` and wired in `cli.py`
- Create `get_blocked_uids()` database helper and apply it in `content.py` `load_detail()` to filter blocked users' posts from detail views
- Implement `_uid_index()` and `_drop_index()` helpers in `database.py` for unique uid indexes across tables, with `user_relations` added to `SOFT_DELETE_TABLES`
- Document new routes in `AGENTS.md` and `README.md`, including emoji shortcodes rendering behavior distinct from the emoji picker
2026-06-19 08:06:09 +00:00

83 lines
4.4 KiB
HTML

{% extends "base.html" %}
{% from "_macros.html" import modal %}
{% block extra_head %}
<link rel="stylesheet" href="{{ static_url('/static/css/issues.css') }}">
{% endblock %}
{% block content %}
<div class="issues-layout">
<div class="issues-header">
<h1>Issue Reports</h1>
<div class="issues-header-actions">
{% if viewer_is_admin %}
<a href="/admin/issues/planning" class="btn btn-secondary btn-sm"><span class="icon">&#x1F5C2;&#xFE0F;</span> Generate planning</a>
{% endif %}
{% if user %}
<button type="button" class="btn btn-primary btn-sm" data-modal="create-issue-modal"><span class="icon">&#x1F41B;</span> Report Issue</button>
{% else %}
<a href="/auth/login" class="btn btn-primary btn-sm login-required"><span class="icon">&#x1F41B;</span> Report Issue</a>
{% endif %}
</div>
</div>
<div class="issues-filters" role="group" aria-label="Filter issues by state">
<a href="?state=open" class="issues-filter {% if state == 'open' %}active{% endif %}"{% if state == 'open' %} aria-current="true"{% endif %}>Open</a>
<a href="?state=closed" class="issues-filter {% if state == 'closed' %}active{% endif %}"{% if state == 'closed' %} aria-current="true"{% endif %}>Closed</a>
<a href="?state=all" class="issues-filter {% if state == 'all' %}active{% endif %}"{% if state == 'all' %} aria-current="true"{% endif %}>All</a>
</div>
{% if not configured or error_message %}
<div class="empty-state">{{ error_message }}</div>
{% else %}
<div class="issues-list" role="list" aria-label="Issue reports">
{% for issue in issues %}
<div class="issue-card card-link-host" role="listitem">
{% set _href = "/issues/" ~ issue.number %}
{% set _label = issue.title %}
{% include "_card_link.html" %}
<div class="issue-card-header">
<span class="issue-number">#{{ issue.number }}</span>
<span class="issue-title">{{ render_title(issue.title) }}</span>
<span class="issue-status {{ issue.state }}"><span class="sr-only">Status: </span>{{ issue.state }}</span>
</div>
<div class="issue-meta">
{% if issue.is_local_author %}
{% set _user = {'username': issue.author_username} %}{% set _size = 20 %}{% set _size_class = "sm" %}{% include "_avatar_link.html" %}
{% endif %}
<span class="issue-author">{{ issue.author_username }}</span>
<span class="issue-dot">&middot;</span>
<span class="issue-date">{{ local_dt(issue.created_at) }}</span>
<span class="issue-dot">&middot;</span>
<span class="issue-comments">{{ issue.comments_count }} comment{{ '' if issue.comments_count == 1 else 's' }}</span>
</div>
</div>
{% else %}
<div class="empty-state">No issue reports yet.</div>
{% endfor %}
</div>
{% set pagination_query = 'state=' ~ state ~ '&' %}
{% include "_pagination.html" %}
{% endif %}
</div>
{% if user %}
{% call modal('create-issue-modal', 'Report an Issue') %}
<form method="POST" action="/issues/create" data-issue-create>
<p class="issues-modal-hint">Your report is improved by AI into a consistent ticket and filed on the tracker.</p>
<div class="auth-field auth-field-gap">
<label for="issue-title">Title</label>
<input type="text" id="issue-title" name="title" required aria-required="true" maxlength="200" placeholder="Brief description of the issue">
</div>
<div class="auth-field auth-field-gap">
<label for="issue-description">Description</label>
<textarea id="issue-description" name="description" required aria-required="true" maxlength="5000" placeholder="Steps to reproduce, expected vs actual, environment..." class="min-h-120" data-mention></textarea>
</div>
<div class="modal-footer">
<button type="button" class="modal-close btn btn-secondary">Cancel</button>
<button type="submit" class="btn btn-primary"><span class="btn-spinner" aria-hidden="true"></span><span class="icon">&#x1F4E4;</span> Submit Report</button>
</div>
</form>
{% endcall %}
{% endif %}
{% endblock %}