a73x

8db86782

add patches list and detail pages

a73x   2026-03-30 19:07

Adds PatchesTemplate/patches handler listing all patches with status
coloring, and PatchDetailTemplate/patch_detail handler showing title,
status, revisions table, reviews, inline comments, and thread comments.
Routes: /{repo}/patches, /{repo}/patches/{id}.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

diff --git a/src/server/http/templates/patch_detail.html b/src/server/http/templates/patch_detail.html
new file mode 100644
index 0000000..0bf3834
--- /dev/null
+++ b/src/server/http/templates/patch_detail.html
@@ -0,0 +1,86 @@
{% extends "repo_base.html" %}

{% block title %}{{ patch.title }} — {{ repo_name }} — {{ site_title }}{% endblock %}

{% block content %}
<h2>{{ patch.title }}</h2>
<p>
  <span class="status-{{ patch.status }}">{{ patch.status }}</span>
  &nbsp; by <strong>{{ patch.author }}</strong>
  &nbsp; <span class="mono" style="color: var(--text-muted);">{{ patch.branch }} → {{ patch.base_ref }}</span>
</p>
{% if !patch.body.is_empty() %}
<pre style="background: var(--bg-code, #f6f8fa); padding: 12px; border-radius: 4px; white-space: pre-wrap;">{{ patch.body }}</pre>
{% endif %}

<h3>Revisions</h3>
{% if patch.revisions.is_empty() %}
<p style="color: var(--text-muted);">No revisions.</p>
{% else %}
<table>
  <thead>
    <tr>
      <th>#</th>
      <th>Commit</th>
      <th>Date</th>
      <th>Notes</th>
    </tr>
  </thead>
  <tbody>
    {% for rev in patch.revisions %}
    <tr>
      <td>{{ rev.number }}</td>
      <td class="mono"><a href="/{{ repo_name }}/diff/{{ rev.commit }}">{{ rev.commit }}</a></td>
      <td class="mono" style="color: var(--text-muted);">{{ rev.timestamp }}</td>
      <td>{% if let Some(body) = rev.body %}{{ body }}{% endif %}</td>
    </tr>
    {% endfor %}
  </tbody>
</table>
{% endif %}

{% if !patch.reviews.is_empty() %}
<h3>Reviews</h3>
{% for review in patch.reviews %}
<div style="border: 1px solid var(--border, #ddd); border-radius: 4px; padding: 12px; margin-bottom: 12px;">
  <p style="margin: 0 0 8px 0;">
    <strong>{{ review.author }}</strong>
    &nbsp; <span class="status-{{ review.verdict }}">{{ review.verdict }}</span>
    &nbsp; <span class="mono" style="color: var(--text-muted); font-size: 0.85em;">{{ review.timestamp }}</span>
    {% if let Some(rev) = review.revision %}&nbsp; rev {{ rev }}{% endif %}
  </p>
  {% if !review.body.is_empty() %}
  <pre style="margin: 0; white-space: pre-wrap;">{{ review.body }}</pre>
  {% endif %}
</div>
{% endfor %}
{% endif %}

{% if !patch.inline_comments.is_empty() %}
<h3>Inline Comments</h3>
{% for ic in patch.inline_comments %}
<div style="border: 1px solid var(--border, #ddd); border-radius: 4px; padding: 12px; margin-bottom: 12px;">
  <p style="margin: 0 0 8px 0;">
    <strong>{{ ic.author }}</strong>
    &nbsp; <span class="mono" style="color: var(--text-muted);">{{ ic.file }}:{{ ic.line }}</span>
    &nbsp; <span class="mono" style="color: var(--text-muted); font-size: 0.85em;">{{ ic.timestamp }}</span>
    {% if let Some(rev) = ic.revision %}&nbsp; rev {{ rev }}{% endif %}
  </p>
  <pre style="margin: 0; white-space: pre-wrap;">{{ ic.body }}</pre>
</div>
{% endfor %}
{% endif %}

{% if !patch.comments.is_empty() %}
<h3>Comments</h3>
{% for comment in patch.comments %}
<div style="border: 1px solid var(--border, #ddd); border-radius: 4px; padding: 12px; margin-bottom: 12px;">
  <p style="margin: 0 0 8px 0;">
    <strong>{{ comment.author }}</strong>
    &nbsp; <span class="mono" style="color: var(--text-muted); font-size: 0.85em;">{{ comment.timestamp }}</span>
  </p>
  <pre style="margin: 0; white-space: pre-wrap;">{{ comment.body }}</pre>
</div>
{% endfor %}
{% endif %}
{% endblock %}
diff --git a/src/server/http/templates/patches.html b/src/server/http/templates/patches.html
new file mode 100644
index 0000000..d946c85
--- /dev/null
+++ b/src/server/http/templates/patches.html
@@ -0,0 +1,35 @@
{% extends "repo_base.html" %}

{% block title %}Patches — {{ repo_name }} — {{ site_title }}{% endblock %}

{% block content %}
<h2>Patches</h2>
{% if patches.is_empty() %}
<p style="color: var(--text-muted);">No patches.</p>
{% else %}
<table>
  <thead>
    <tr>
      <th>ID</th>
      <th>Status</th>
      <th>Title</th>
      <th>Author</th>
      <th>Branch</th>
      <th>Updated</th>
    </tr>
  </thead>
  <tbody>
    {% for p in patches %}
    <tr>
      <td class="mono"><a href="/{{ repo_name }}/patches/{{ p.id }}">{{ p.short_id }}</a></td>
      <td><span class="status-{{ p.status }}">{{ p.status }}</span></td>
      <td><a href="/{{ repo_name }}/patches/{{ p.id }}">{{ p.title }}</a></td>
      <td style="color: var(--text-muted);">{{ p.author }}</td>
      <td class="mono" style="color: var(--text-muted);">{{ p.branch }}</td>
      <td class="mono" style="color: var(--text-muted);">{{ p.updated }}</td>
    </tr>
    {% endfor %}
  </tbody>
</table>
{% endif %}
{% endblock %}