detached 079d98b

refactor(web): share the fragment layout rule and document the API omission reasons

commit
079d98b86b72ee8d83bcb99a9bad161c2bcbace3
author
brice · · 2026-10-20 08:26 UTC
parent
4ee449b
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
3 files · +12 -9
M docs/merge-requests.md +2 -0
@@ -69,6 +69,8 @@ The merge request, commit and compare pages list every changed file. Generated f
6969
7070 A commit page reads the hunks of its first 300 files with the page; the other files are listed collapsed and load one at a time. A file that cannot be shown in the browser, over 8 MiB of text or over 50,000 changed lines when loaded alone, has no "load diff": the page links to its raw blob instead, and its lines take no comment.
7171
72+The API and `mr show --diff --json` keep their limits (300 files, 2,000 changed lines per file, 20,000 in total, 8 MiB). A file read without its hunks has `truncated` set and `omitted` giving the reason: `large`, `budget` (the earlier files used the limits) or `unavailable` (too large to read even alone).
73+
7274 ## Notes
7375
7476 A note is the only review object. It is published as soon as it is written: there is no draft and no submit step.
@@ -69,6 +69,8 @@ The merge request, commit and compare pages list every changed file. Generated f
69 69
70 A commit page reads the hunks of its first 300 files with the page; the other files are listed collapsed and load one at a time. A file that cannot be shown in the browser, over 8 MiB of text or over 50,000 changed lines when loaded alone, has no "load diff": the page links to its raw blob instead, and its lines take no comment.70 A commit page reads the hunks of its first 300 files with the page; the other files are listed collapsed and load one at a time. A file that cannot be shown in the browser, over 8 MiB of text or over 50,000 changed lines when loaded alone, has no "load diff": the page links to its raw blob instead, and its lines take no comment.
71 71
72+The API and `mr show --diff --json` keep their limits (300 files, 2,000 changed lines per file, 20,000 in total, 8 MiB). A file read without its hunks has `truncated` set and `omitted` giving the reason: `large`, `budget` (the earlier files used the limits) or `unavailable` (too large to read even alone).
73+
72 ## Notes74 ## Notes
73 75
74 A note is the only review object. It is published as soon as it is written: there is no draft and no submit step.76 A note is the only review object. It is published as soon as it is written: there is no draft and no submit step.
M internal/adapters/web/diff.go +9 -2
@@ -380,7 +380,7 @@ func diffFiles(files []domain.FileDiff) []DiffFile {
380380 ID: "f" + itoa(i+1), Status: statusLetter(f.Status),
381381 Add: f.Additions, Del: f.Deletions, Bin: f.Binary,
382382 // A file that is shown in full opens; a file with nothing to read
383- // (binary, truncated) stays closed under its note.
383+ // (binary, omitted) stays closed under its note.
384384 Open: len(f.Hunks) > 0 && f.Omitted == domain.OmitNone,
385385 Manual: f.Omitted.Collapsed(),
386386 }
@@ -535,6 +535,14 @@ func fileParam(r *http.Request, n int) (int, bool) {
535535 // ?view= is the layout shown and ?layouts= says whether the page holds both.
536536 func fragmentView(r *http.Request, lines int) DiffView {
537537 v := newDiffView(r, lines, "", "")
538+ v.pageLayouts(r)
539+ return v
540+}
541+
542+// pageLayouts makes a fragment send the layouts of the page that asks for
543+// it: ?layouts=both when the page holds both and switches them itself,
544+// ?layouts=one when it holds only the shown one.
545+func (v *DiffView) pageLayouts(r *http.Request) {
538546 switch r.URL.Query().Get("layouts") {
539547 case "both":
540548 v.Both = true
@@ -542,5 +550,4 @@ func fragmentView(r *http.Request, lines int) DiffView {
542550 v.Both = false
543551 }
544552 v.ShowUnified, v.ShowSplit = v.Both || v.View == "unified", v.Both || v.View == "split"
545- return v
546553 }
@@ -380,7 +380,7 @@ func diffFiles(files []domain.FileDiff) []DiffFile {
380 ID: "f" + itoa(i+1), Status: statusLetter(f.Status),380 ID: "f" + itoa(i+1), Status: statusLetter(f.Status),
381 Add: f.Additions, Del: f.Deletions, Bin: f.Binary,381 Add: f.Additions, Del: f.Deletions, Bin: f.Binary,
382 // A file that is shown in full opens; a file with nothing to read382 // A file that is shown in full opens; a file with nothing to read
383- // (binary, truncated) stays closed under its note.383+ // (binary, omitted) stays closed under its note.
384 Open: len(f.Hunks) > 0 && f.Omitted == domain.OmitNone,384 Open: len(f.Hunks) > 0 && f.Omitted == domain.OmitNone,
385 Manual: f.Omitted.Collapsed(),385 Manual: f.Omitted.Collapsed(),
386 }386 }
@@ -535,6 +535,14 @@ func fileParam(r *http.Request, n int) (int, bool) {
535 // ?view= is the layout shown and ?layouts= says whether the page holds both.535 // ?view= is the layout shown and ?layouts= says whether the page holds both.
536 func fragmentView(r *http.Request, lines int) DiffView {536 func fragmentView(r *http.Request, lines int) DiffView {
537 v := newDiffView(r, lines, "", "")537 v := newDiffView(r, lines, "", "")
538+ v.pageLayouts(r)
539+ return v
540+}
541+
542+// pageLayouts makes a fragment send the layouts of the page that asks for
543+// it: ?layouts=both when the page holds both and switches them itself,
544+// ?layouts=one when it holds only the shown one.
545+func (v *DiffView) pageLayouts(r *http.Request) {
538 switch r.URL.Query().Get("layouts") {546 switch r.URL.Query().Get("layouts") {
539 case "both":547 case "both":
540 v.Both = true548 v.Both = true
@@ -542,5 +550,4 @@ func fragmentView(r *http.Request, lines int) DiffView {
542 v.Both = false550 v.Both = false
543 }551 }
544 v.ShowUnified, v.ShowSplit = v.Both || v.View == "unified", v.Both || v.View == "split"552 v.ShowUnified, v.ShowSplit = v.Both || v.View == "unified", v.Both || v.View == "split"
545- return v
546 }553 }
M internal/adapters/web/mr_files.go +1 -7
@@ -241,12 +241,6 @@ func (s *Server) mrFiles(ctx context.Context, r *http.Request) (templ.Component,
241241 }
242242 lines, _ := diffLines(window)
243243 v := newDiffView(r, lines, withFrom(self+"?view=unified", from), withFrom(self+"?view=split", from))
244- switch r.URL.Query().Get("layouts") {
245- case "both":
246- v.Both = true
247- case "one":
248- v.Both = false
249- }
250- v.ShowUnified, v.ShowSplit = v.Both || v.View == "unified", v.Both || v.View == "split"
244+ v.pageLayouts(r)
251245 return MRFiles(MRFilesPage{Files: window, DiffView: v}), http.StatusOK, nil
252246 }
@@ -241,12 +241,6 @@ func (s *Server) mrFiles(ctx context.Context, r *http.Request) (templ.Component,
241 }241 }
242 lines, _ := diffLines(window)242 lines, _ := diffLines(window)
243 v := newDiffView(r, lines, withFrom(self+"?view=unified", from), withFrom(self+"?view=split", from))243 v := newDiffView(r, lines, withFrom(self+"?view=unified", from), withFrom(self+"?view=split", from))
244- switch r.URL.Query().Get("layouts") {244+ v.pageLayouts(r)
245- case "both":
246- v.Both = true
247- case "one":
248- v.Both = false
249- }
250- v.ShowUnified, v.ShowSplit = v.Both || v.View == "unified", v.Both || v.View == "split"
251 return MRFiles(MRFilesPage{Files: window, DiffView: v}), http.StatusOK, nil245 return MRFiles(MRFilesPage{Files: window, DiffView: v}), http.StatusOK, nil
252 }246 }

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 45

↑↓ moveenter openesc close