// SPDX-License-Identifier: AGPL-3.0-or-later
package web
import (
"strconv"
"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 {
}
@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)) {
if p.Desc != "" {
@templ.Raw(string(p.Desc))
}
if p.Deleting != "" {
merged. the branch { p.Deleting } is being deleted.
}
if p.MergeError != "" {
{ p.MergeError }
}
@LiveSlot("mr-notice")
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. Body comes only from the safe Markdown renderer.
templ commentView(c CommentView, suffix string) {
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) {
}
// 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.
//
// The badge is a live slot (mr-mergeability); the modes and the button read
// its data-* attributes (hx-live bindings), so that they follow the slot when
// the stream replaces its content. The server renders the same state in the
// attributes, for a page without scripts.
templ mergeMenu(p MRPage) {
if p.Box.ReadyAction != "" {
Draft
} else {
Merge
}
M
head
if p.Box.HeadGone {
gone: the source branch was deleted
} else {
{ p.HeadShort }
}
into
{ p.Target }
if p.Box.Error != "" {
{ p.Box.Error }
}
if p.Box.ReadyAction != "" {
this is a draft: it cannot be merged until it is ready for review.
} else if !p.Box.HeadGone {
@mrMergeabilitySlot(p.Box.Mergeability)
}
}
// MRMergeability is the content of the mergeability slot: the badge, and the
// state the controls of the merge box read.
templ MRMergeability(v MergeabilityView) {
{ v.Label }
if v.Detail != "" {
{ " " }{ v.Detail }
}
if len(v.Paths) > 0 {
for _, path := range v.Paths {
{ path }
}
}
if v.PathsNote != "" {
{ v.PathsNote }
}
}
// mrMergeabilitySlot is the status region of the badge, with its content: the
// stream replaces the children, never the element (see LiveSlot).
templ mrMergeabilitySlot(v MergeabilityView) {
@MRMergeability(v)
}
// MRMergeabilityFragment is the slot as the stream sends it.
templ MRMergeabilityFragment(v MergeabilityView) {
@mrMergeabilitySlot(v)
}
// 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) {
⋯
if p.Box.CanMarkRead {
}
if !p.Box.HeadGone && p.Box.ReadyAction == "" {
or from a terminal
@CloneBlock(p.Box.CLI)
}
}
templ Compare(l Layout, p ComparePage) {
@Shell(l, compareRail(p)) {