- gitea pkg: CloseIssue, ReopenIssue, CreateIssue, AddComment + ErrForbidden
classification on 401/403. Client.do sets Content-Type on non-empty bodies.
- web handler: POST /i/{path}/issues/{close|reopen|comment|create}
- authorisation guard: repo form value must match a gitea-repo item_link
on the target item (rejects form-crafted writes to unrelated repos)
- HTMX re-renders issues_section partial after each action
- busts gitea per-repo cache (open + closed-recent) and dashboard 60s TTL
- templates: ✓ close button + reopen + collapsible comment box on every
issue row; "+ new issue" disclosure per repo
- design.md §6 retitled "Phase 2.d read; 3h writeback" with auth/perm
semantics + parked list
- 5 unit tests in gitea/, 5 integration tests in web/ covering happy paths
+ 403 → inline banner fallback
90 lines
4.2 KiB
Cheetah
90 lines
4.2 KiB
Cheetah
{{define "issues-section"}}
|
|
<section class="issues" id="issues-section">
|
|
<h2>Issues{{if .IssuesOpenTotal}} ({{.IssuesOpenTotal}}){{end}}</h2>
|
|
{{if .Banner}}<p class="banner warn">{{.Banner}}</p>{{end}}
|
|
{{range .Issues}}
|
|
{{$repo := .Repo}}
|
|
<div class="repo-block" data-repo="{{.Repo}}">
|
|
<h3>
|
|
<a href="{{.RepoURL}}" target="_blank" rel="noopener noreferrer">{{.Repo}}</a>
|
|
<small class="muted"><a href="{{.IssuesURL}}" target="_blank" rel="noopener noreferrer">↗ Gitea repo</a></small>
|
|
</h3>
|
|
{{if .Error}}<p class="banner warn">{{.Error}}</p>{{end}}
|
|
|
|
<details class="new-issue">
|
|
<summary class="muted">+ new issue</summary>
|
|
<form class="new-issue-form"
|
|
hx-post="/i/{{$.Item.PrimaryPath}}/issues/create"
|
|
hx-target="#issues-section"
|
|
hx-swap="outerHTML">
|
|
<input type="hidden" name="repo" value="{{.Repo}}">
|
|
<input name="title" placeholder="title" required>
|
|
<textarea name="body" placeholder="body (markdown)" rows="3"></textarea>
|
|
<button type="submit">create</button>
|
|
</form>
|
|
</details>
|
|
|
|
{{if .Open}}
|
|
<ul class="issues open">
|
|
{{range .Open}}
|
|
<li class="issue-row" id="issue-{{$repo}}-{{.Number}}">
|
|
<a class="num" href="{{.HTMLURL}}" target="_blank" rel="noopener noreferrer">#{{.Number}}</a>
|
|
<a class="title" href="{{.HTMLURL}}" target="_blank" rel="noopener noreferrer">{{.Title}}</a>
|
|
{{range .Labels}}<span class="label">{{.}}</span>{{end}}
|
|
{{if .Milestone}}<span class="milestone">{{.Milestone}}</span>{{end}}
|
|
{{range .Assignees}}<span class="assignee">@{{.}}</span>{{end}}
|
|
{{if .UpdatedRel}}<small class="muted">updated {{.UpdatedRel}}</small>{{end}}
|
|
<form class="issue-close"
|
|
hx-post="/i/{{$.Item.PrimaryPath}}/issues/close"
|
|
hx-target="#issues-section"
|
|
hx-swap="outerHTML">
|
|
<input type="hidden" name="repo" value="{{$repo}}">
|
|
<input type="hidden" name="number" value="{{.Number}}">
|
|
<button type="submit" title="close issue">✓ close</button>
|
|
</form>
|
|
<details class="issue-comment">
|
|
<summary class="muted">comment</summary>
|
|
<form class="comment-form"
|
|
hx-post="/i/{{$.Item.PrimaryPath}}/issues/comment"
|
|
hx-target="#issues-section"
|
|
hx-swap="outerHTML">
|
|
<input type="hidden" name="repo" value="{{$repo}}">
|
|
<input type="hidden" name="number" value="{{.Number}}">
|
|
<textarea name="body" placeholder="comment (markdown)" rows="2" required></textarea>
|
|
<button type="submit">post</button>
|
|
</form>
|
|
</details>
|
|
</li>
|
|
{{end}}
|
|
</ul>
|
|
{{else if not .Error}}
|
|
<p class="muted">No open issues.</p>
|
|
{{end}}
|
|
{{if .ClosedRecent}}
|
|
<details>
|
|
<summary class="muted">{{len .ClosedRecent}} closed in last 30 days</summary>
|
|
<ul class="issues closed">
|
|
{{range .ClosedRecent}}
|
|
<li class="issue-row">
|
|
<a class="num" href="{{.HTMLURL}}" target="_blank" rel="noopener noreferrer">#{{.Number}}</a>
|
|
<a class="title" href="{{.HTMLURL}}" target="_blank" rel="noopener noreferrer">{{.Title}}</a>
|
|
{{range .Labels}}<span class="label">{{.}}</span>{{end}}
|
|
{{if .UpdatedRel}}<small class="muted">{{.UpdatedRel}}</small>{{end}}
|
|
<form class="issue-reopen"
|
|
hx-post="/i/{{$.Item.PrimaryPath}}/issues/reopen"
|
|
hx-target="#issues-section"
|
|
hx-swap="outerHTML">
|
|
<input type="hidden" name="repo" value="{{$repo}}">
|
|
<input type="hidden" name="number" value="{{.Number}}">
|
|
<button type="submit" title="reopen">↻ reopen</button>
|
|
</form>
|
|
</li>
|
|
{{end}}
|
|
</ul>
|
|
</details>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
</section>
|
|
{{end}}
|