136 lines
6.2 KiB
HTML
136 lines
6.2 KiB
HTML
{{define "title"}}Ticket Detail{{end}}
|
|
|
|
{{define "content"}}
|
|
{{with .Data}}
|
|
<div class="mb-4">
|
|
<a href="/tickets" class="text-sm text-blue-600 hover:text-blue-500">← Back to tickets</a>
|
|
</div>
|
|
|
|
<div class="bg-white p-6 rounded-lg shadow ring-1 ring-gray-200">
|
|
<div class="flex items-start justify-between">
|
|
<div>
|
|
<div class="flex items-center gap-2">
|
|
{{if .Ticket.Pinned}}<span class="text-gray-400" title="Pinned">📌</span>{{end}}
|
|
<h1 class="text-xl font-bold text-gray-900">{{.Ticket.Title}}</h1>
|
|
</div>
|
|
<p class="mt-1 text-sm text-gray-500">
|
|
{{if .Repo}}{{.Repo.Name}} · {{end}}
|
|
{{if .User}}by {{.User.Email}} · {{end}}
|
|
Created {{formatDate .Ticket.CreatedAt}}
|
|
{{if .Ticket.ForgejoIssueNumber}} · Forgejo #{{.Ticket.ForgejoIssueNumber}}{{end}}
|
|
</p>
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
{{if .Ticket.Priority}}{{priorityBadge (print .Ticket.Priority)}}{{end}}
|
|
{{statusBadge (print .Ticket.Status)}}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Metadata -->
|
|
<div class="mt-4 flex flex-wrap gap-x-6 gap-y-1 text-sm text-gray-600">
|
|
{{if .Ticket.Assignees}}
|
|
<div>Assigned to: <span class="font-medium text-gray-900">{{.Ticket.Assignees}}</span></div>
|
|
{{end}}
|
|
{{if .Ticket.DueDate}}
|
|
<div>
|
|
Due: <span class="font-medium {{if isOverdue .Ticket.DueDate}}text-red-600{{else}}text-gray-900{{end}}">{{formatDatePtr .Ticket.DueDate}}</span>
|
|
{{if isOverdue .Ticket.DueDate}}<span class="text-xs text-red-600 font-medium">(overdue)</span>{{end}}
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
|
|
<div class="mt-6 prose prose-sm max-w-none text-gray-700">
|
|
{{renderMarkdown .Ticket.Description .Mentions}}
|
|
</div>
|
|
|
|
<!-- Issue Attachments -->
|
|
{{if .Ticket.Attachments}}
|
|
<div class="mt-4 border-t border-gray-200 pt-4">
|
|
<h3 class="text-sm font-medium text-gray-700 mb-2">Attachments</h3>
|
|
<div class="flex flex-wrap gap-2">
|
|
{{range .Ticket.Attachments}}
|
|
<a href="{{.DownloadURL}}" target="_blank" class="inline-flex items-center gap-1 rounded-md bg-gray-100 px-2.5 py-1.5 text-xs font-medium text-gray-700 hover:bg-gray-200">
|
|
{{.Name}} <span class="text-gray-400">({{.Size}} bytes)</span>
|
|
</a>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
|
|
<!-- Status Update -->
|
|
<div class="mt-6 pt-4 border-t border-gray-200">
|
|
<form method="POST" action="/tickets/{{.Ticket.ID}}/status" class="flex items-center gap-3">
|
|
<label for="status" class="text-sm font-medium text-gray-700">Update Status:</label>
|
|
<select name="status" id="status" class="rounded-md border border-gray-300 px-3 py-1.5 text-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500">
|
|
<option value="open" {{if eq (print .Ticket.Status) "open"}}selected{{end}}>Open</option>
|
|
<option value="in_progress" {{if eq (print .Ticket.Status) "in_progress"}}selected{{end}}>In Progress</option>
|
|
<option value="closed" {{if eq (print .Ticket.Status) "closed"}}selected{{end}}>Closed</option>
|
|
</select>
|
|
<button type="submit" class="rounded-md bg-gray-900 px-3 py-1.5 text-sm font-semibold text-white shadow hover:bg-gray-800">Update</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Related Issues -->
|
|
{{if .RelatedIssues}}
|
|
<div class="mt-6 bg-white p-4 rounded-lg shadow ring-1 ring-gray-200">
|
|
<h2 class="text-sm font-semibold text-gray-900 mb-2">Related Issues</h2>
|
|
<ul class="space-y-1">
|
|
{{range .RelatedIssues}}
|
|
<li class="text-sm">
|
|
{{if .TicketID}}
|
|
<a href="/tickets/{{.TicketID}}" class="text-blue-600 hover:text-blue-500">{{.DisplayText}}</a>
|
|
<span class="text-gray-400">(#{{.Number}})</span>
|
|
{{else}}
|
|
<span class="text-gray-600">{{.DisplayText}}</span>
|
|
<span class="text-gray-400">(#{{.Number}} - no ticket mapping)</span>
|
|
{{end}}
|
|
</li>
|
|
{{end}}
|
|
</ul>
|
|
</div>
|
|
{{end}}
|
|
|
|
<!-- Timeline -->
|
|
<div class="mt-8">
|
|
<h2 class="text-lg font-semibold text-gray-900 mb-4">Timeline</h2>
|
|
{{if .Timeline}}
|
|
<div class="space-y-4">
|
|
{{range .Timeline}}
|
|
{{if eq .Type "comment"}}
|
|
<div class="{{if .IsTeam}}bg-blue-50 ring-blue-200{{else}}bg-white ring-gray-200{{end}} p-4 rounded-lg shadow ring-1">
|
|
<div class="flex items-center justify-between mb-2">
|
|
<div class="flex items-center gap-2">
|
|
<span class="text-sm font-medium text-gray-900">{{.AuthorName}}</span>
|
|
{{if .IsTeam}}<span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">Team</span>{{end}}
|
|
</div>
|
|
<span class="text-xs text-gray-500">{{formatDateTime .CreatedAt}}</span>
|
|
</div>
|
|
<div class="text-sm text-gray-700 prose prose-sm max-w-none">{{renderMarkdown .Body $.Data.Mentions}}</div>
|
|
{{if .Attachments}}
|
|
<div class="mt-2 flex flex-wrap gap-2">
|
|
{{range .Attachments}}
|
|
<a href="{{.DownloadURL}}" target="_blank" class="inline-flex items-center gap-1 rounded-md bg-gray-100 px-2 py-1 text-xs font-medium text-gray-700 hover:bg-gray-200">
|
|
{{.Name}}
|
|
</a>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
{{else}}
|
|
<div class="flex items-center gap-2 py-2 px-4 text-sm text-gray-500">
|
|
<span class="inline-block w-2 h-2 rounded-full {{if eq .Type "status_change"}}bg-yellow-400{{else if eq .Type "label"}}bg-purple-400{{else if eq .Type "assignment"}}bg-green-400{{else}}bg-gray-300{{end}}"></span>
|
|
<span class="font-medium text-gray-700">{{.AuthorName}}</span>
|
|
<span>{{.EventText}}</span>
|
|
<span class="text-xs">· {{formatDateTime .CreatedAt}}</span>
|
|
</div>
|
|
{{end}}
|
|
{{end}}
|
|
</div>
|
|
{{else}}
|
|
<p class="text-sm text-gray-500">No activity.</p>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
{{end}}
|