// SPDX-License-Identifier: AGPL-3.0-or-later package web import "strings" // MRList is the list of the merge requests of a repository: the open ones, // then the merged and closed ones. templ MRList(l Layout, p MRListPage) { @Shell(l, mrListRail(p)) { if p.Live { @LiveSlot("mr-notice") }
if p.Newest == "" {

Open{ itoa(len(p.Open)) }

@mrRows(p.Open, "Open merge requests") if len(p.Open) == 0 {

no open merge requests.

} if p.OpenNote != "" {

{ p.OpenNote }

} }

Merged and closed{ itoa(len(p.Done)) }

@mrRows(p.Done, "Merged and closed merge requests") if len(p.Done) == 0 {

nothing merged or closed yet.

} if p.Older != "" || p.Newest != "" { } } } templ mrRows(rows []MRRow, label string) { if len(rows) > 0 { for _, m := range rows { }
{ m.Number } { m.State } { m.Title } { m.Branches } { m.Author } if m.WhenAt != "" { }
} } templ mrListRail(p MRListPage) {

States

open
awaits review
merged
the target took the branch
closed
refused, branch kept

Open one

if len(p.Branches) > 0 {

compare a branch with { p.Default }:

} else {

there is no other branch to merge yet.

} @CloneBlock(p.CLI)
} // MergeRequest is a merge request: its facts, its description, the diff with // the notes under their lines, the general comments; and in the rail the merge // form, the checks, the settings, the commits and the files. templ MergeRequest(l Layout, p MRPage) { @Shell(l, mrRail(p)) {

{ p.Number } { p.Title }

state
{ p.State } if p.MergedShort != "" { { " · " }{ p.MergedShort }{ " · " + p.MergeMode } }
branch
@branchLink(p.Source, p.SourceHref) { " → " } @branchLink(p.Target, p.TargetHref)
opened
{ p.Opened.Name } if p.Opened.WhenAt != "" { { " · " } }
if p.UpdatedAt != "" {
updated
}
@LiveSlot("mr-notice") if len(p.Desc) > 0 {

@userText(p.Desc)

} if p.Since != nil { } if p.SinceNote != "" {

{ p.SinceNote }

} @mrBar(p) if p.Invisible {

this diff holds invisible characters (direction controls, zero-width characters). They are shown as <U+XXXX> markers, never applied.

} if p.Note != "" {

{ p.Note }

}
for _, f := range p.Files { @DiffFileView(f, p.DiffView) } if len(p.Files) == 0 {

no changed files.

}

Comments{ itoa(p.NUnresolved) } open / { itoa(p.NComments) }

for _, c := range p.Loose { @commentView(c, "") } for _, c := range p.General { @commentView(c, "") } if p.NComments == 0 {

no comments yet.

} if p.GeneralForm != nil { @commentForm(*p.GeneralForm, "") } } } templ branchLink(name, href string) { if href != "" { { name } } else { { name } } } // lineNotes are the comments under a line of the diff, and the form to write // one when the reader asked for it. The diff is in the page twice (unified and // split); the suffix keeps the ids unique, the unified table having none. templ lineNotes(notes []CommentView, form *CommentForm, suffix string) { for _, c := range notes { @commentView(c, suffix) } if form != nil { @commentForm(*form, suffix) } } // commentView is a note: a ruled block, under its line in the diff or in the // list of comments. The text is plain: escaped, its line breaks kept, its // http(s) addresses linked. templ commentView(c CommentView, suffix string) {

{ c.Author } if c.WhenAt != "" { { " " } } if c.Resolved { { " " }resolved } if c.Outdated { { " " }outdated } if c.Where != "" { { " " }{ c.Where } }

@userText(c.Parts)

if c.Resolve != nil {
if c.Resolve.From > 0 { }
}
} func boolText(b bool) string { if b { return "true" } return "false" } // commentForm writes a comment, general or on a line. templ commentForm(f CommentForm, suffix string) {
if f.Path != "" { } if f.From > 0 { }
if f.Cancel != "" { Cancel }
} templ mrRail(p MRPage) {

Files { itoa(len(p.Files)) }

@FileList(p.Files)
@MRChecks(p.Checks)

Commits { itoa(len(p.Commits)) }

if len(p.Commits) == 0 {

no commit to merge.

} if p.CommitsNote != "" {

{ p.CommitsNote }

}

Settings

modes
{ strings.Join(p.Modes, ", ") }
checks
if p.ChecksBlock { failing ones block the merge } else { do not block the merge }
} // mrBar is the bar above the diff, which follows the review: the totals, the // layout of the diff, the state of the checks and, for the owner of an open // request, the merge menu and the other actions. Each menu is a
: it // works without scripts; with them, M and the keys of the menu drive it. templ mrBar(p MRPage) {
{ plural(p.NFiles, "file", "files") } · +{ itoa(p.Adds) } -{ itoa(p.Dels) } @viewLink(p.DiffView, "unified", "Unified", "u", p.UnifiedHref) @viewLink(p.DiffView, "split", "Split", "d", p.SplitHref) @collapseButton() @MRChecksSum(p.ChecksSum) if p.Box != nil { @mergeMenu(p) @moreMenu(p) }
} // mergeMenu is the merge of an open request, for the owner: the form (it // carries the head that was read), or "Ready for review" for a draft. The // mode and the branch deletion have keys (1-3, D) while it is open. templ mergeMenu(p MRPage) { } // moreMenu is what else the owner does with an open request: mark the head // read, close it, merge it from a terminal. templ moreMenu(p MRPage) { } templ Compare(l Layout, p ComparePage) { @Shell(l, compareRail(p)) {

{ p.Source } → { p.Target }

branch
{ p.Source }
target
{ p.Target }
ahead
{ p.AheadText }
if p.Note != "" {

{ p.Note }

} if p.Existing != nil {

an open merge request already covers these branches: { p.Existing.Label }

} if p.Create != nil {
} if p.HasDiff {
{ plural(p.NFiles, "file", "files") } · +{ itoa(p.Adds) } -{ itoa(p.Dels) } @viewLink(p.DiffView, "unified", "Unified", "u", p.UnifiedHref) @viewLink(p.DiffView, "split", "Split", "d", p.SplitHref) @collapseButton()
if p.Invisible {

this diff holds invisible characters (direction controls, zero-width characters). They are shown as <U+XXXX> markers, never applied.

}
for _, f := range p.Files { @DiffFileView(f, p.DiffView) }
} } } templ compareRail(p ComparePage) {

Commits { itoa(len(p.Ahead)) }

if len(p.Ahead) == 0 {

no commit ahead of { p.Target }.

}
if p.HasDiff {

Files { itoa(len(p.Files)) }

@FileList(p.Files)
}

From a terminal

@CloneBlock(p.CLI)
}