{{define "content" -}}

~{{.Repo.OwnerName}}/{{.Repo.Name}} · parade

{{template "beadsHead" (dict "Repo" .Repo "Ref" .Ref "Head" .Head)}} {{template "viewtabs" (dict "Repo" .Repo "Views" .Views "Current" "beads" "Ref" .Ref)}} {{if or (eq .Data.Mode "detail") (eq .Data.Mode "epic")}} {{/* ------------- detail / epic pane ------------- */}}

← Back to the parade

{{with .Data.Issue}}

{{.ID}} {{.Title}} {{if eq $.Data.Mode "epic"}}epic{{end}} {{.Lane}}

status: {{.Status}} {{if .Priority}}P{{.Priority}}{{end}} {{if .IssueType}}{{.IssueType}}{{end}} {{if .Assignee}}@{{.Assignee}}{{end}} {{range .Labels}}{{.}}{{end}}
{{/* The command this page cannot run for you. Which ones are offered follows the issue's status through the lane the detail pane already derived from it (Rolling = in progress, Past Stand = closed, Lined Up = open), so there is no second status vocabulary here — and nothing is offered that bd would refuse. The command names the issue and nothing about paths: this service does not know where the tracker is checked out, and the database name is in the breadcrumb if the reader needs to pick a directory. */}}
{{if eq .Lane "Rolling"}} bd close {{.ID}} bd update {{.ID}} --status=open {{else if eq .Lane "Past Stand"}} bd reopen {{.ID}} {{else}} bd update {{.ID}} --claim bd close {{.ID}} {{end}}
{{if .CreatedBy}}{{end}} {{if .Owner}}{{end}} {{if .EstimatedMinutes}}{{end}} {{if .ExternalRef}}{{end}} {{if .SpecID}}{{end}} {{if .CreatedAt}}{{end}} {{if .StartedAt}}{{end}} {{if .UpdatedAt}}{{end}} {{if .ClosedAt}}{{end}}
Created by{{.CreatedBy}}
Owner{{.Owner}}
Estimate{{.EstimatedMinutes}} min
External ref{{.ExternalRef}}
Spec{{.SpecID}}
Created{{.CreatedAt}}
Started{{.StartedAt}}
Updated{{.UpdatedAt}}
Closed{{.ClosedAt}}
{{/* The long-text bodies go through $.Links, which escapes the stored text and then wraps the issue ids it recognises in links to the database that owns them. An id whose prefix belongs to no database this viewer may browse is left as the text it is. */}} {{if .Description}}
Description
{{$.Links.Text .Description}}
{{end}} {{if .Design}}
Design
{{$.Links.Text .Design}}
{{end}} {{if .AcceptanceCriteria}}
Acceptance criteria
{{$.Links.Text .AcceptanceCriteria}}
{{end}} {{if .Notes}}
Notes
{{$.Links.Text .Notes}}
{{end}}
{{if eq $.Data.Mode "epic"}}

Subtasks{{if $.Data.SubtaskTotal}} {{$.Data.SubtaskDone}} of {{$.Data.SubtaskTotal}} done{{end}}

{{if $.Data.SubtaskTotal}}
{{else}}

No subtasks linked to this epic.

{{end}}
{{end}}

Depends on

{{if $.Data.DependsOn}}
    {{range $.Data.DependsOn}}
  • {{.IssueID}} {{if .Title}}— {{.Title}}{{end}} {{.Type}} {{if .Closed}}closed{{else}}{{.Status}}{{end}}
  • {{end}}
{{else}}

No outgoing dependencies.

{{end}}

Depended on by

{{if $.Data.DependedOnBy}}
    {{range $.Data.DependedOnBy}}
  • {{.IssueID}} {{if .Title}}— {{.Title}}{{end}} {{.Type}}
  • {{end}}
{{else}}

Nothing depends on this issue.

{{end}}
{{if or $.Data.DependsTree $.Data.DependentTree}}
{{if $.Data.DependsTree}}

Prerequisite chain — everything this waits on, transitively

{{end}} {{if $.Data.DependentTree}}

Unblocks — everything waiting on this, transitively

{{end}}
{{end}}
{{if $.Data.Comments}} {{range $.Data.Comments}}
{{.Author}} {{if .CreatedAt}}· {{.CreatedAt}}{{end}}
{{$.Links.Text .Text}}
{{end}} {{else}}

No comments.

{{end}} {{/* The Comments tab has no closed event, so the close reason is shown here at the end; the History tab already carries it as the closed event. */}} {{if .CloseReason}}

Close reason

{{.CloseReason}}
{{end}}
{{if $.Data.History}}
    {{range $.Data.History}}
  • {{.Actor}} {{$.Links.Text .Summary}} {{if .CreatedAt}}· {{.CreatedAt}}{{end}}
    {{if .Text}}
    {{$.Links.Text .Text}}
    {{end}}
  • {{end}}
{{else}}

No activity yet.

{{end}}
{{else}}
Issue not found.
{{end}} {{else}} {{/* ---------------- board ---------------- */}} {{if .Data.Truncated}}
Showing the first {{.Data.Total}} of {{.Data.ShownOf}} issues.
{{end}}
{{if .Ref}}{{end}} {{/* The layout is not a filter, but this form is a GET: without carrying it, submitting a filter from the stream would answer with the board. */}} {{if eq .Data.Layout "stream"}}{{end}} {{/* Clear drops the filters and keeps the layout: the layout is how the page is read, not what it is filtered to. */}} {{if .Data.Filter.Active}}Clear{{end}}
view: {{if eq .Data.Layout "stream"}} Board {{else}}Board{{end}} · {{if eq .Data.Layout "stream"}}Stream {{else}}Stream{{end}}
{{.Data.Counts.Rolling}}
Rolling
{{.Data.Counts.LinedUp}}
Lined Up
{{.Data.Counts.Stalled}}
Stalled
{{.Data.Counts.PastStand}}
Past Stand
{{.Data.Counts.Total}}
Total
{{if eq .Data.Layout "stream"}} {{/* ---------------- stream: the same buckets as one column ---------------- */}}
{{range .Data.Sections}} {{if .Collapsed}}
{{.Name}}{{if .Note}}{{.Note}}{{end}}{{len .Issues}} {{template "beadStreamRows" (dict "Repo" $.Repo "Section" .)}}
{{else}}
{{.Name}}{{if .Note}}{{.Note}}{{end}}{{len .Issues}}
{{template "beadStreamRows" (dict "Repo" $.Repo "Section" .)}}
{{end}} {{end}}
{{else}} {{/* ---------------- board: four lanes side by side ---------------- */}}
{{range .Data.Lanes}} {{end}}
{{end}}{{/* layout */}} {{end}}{{/* detail vs board */}}
{{- end}} {{/* One stream section's cards. The row markup is the board's row markup: the same card, only differently arranged — so the two copies move together. It is copied rather than shared because folding the board's lane body into this partial would reflow the board's output, and the board is meant to render exactly what it rendered before this layout existed. */}} {{define "beadStreamRows"}}
{{range .Section.Issues}} {{if .Ready}}{{end}}{{.ID}} {{.Title}} {{if .PriorityLabel}}{{.PriorityLabel}}{{end}} {{if .Type}}{{.Type}}{{end}} {{if .Assignee}}@{{.Assignee}}{{end}} {{range .Labels}}{{.}}{{end}} {{if .BlockedBy}}🚧 {{.BlockedBy}}{{end}} {{if .Blocks}}blocks {{.Blocks}}{{end}} {{else}}

Nothing in this section.

{{end}}
{{end}}