detached 8b72cc8

Merge 52bc7c76204e3378ca0e95aac7ac99f3079a6409 into cc7ba64ee52412f41c3ce5207bac7e47b9f01f30

commit
8b72cc861258f23074c7c27f7a5920a914bb943b
author
ermite · · 2026-10-20 05:13 UTC
merge of
cc7ba64 + 52bc7c7 · diff against the first parent
signature
unsigned
26 files · +1366 -866
M docs/merge-requests.md +14 -0
@@ -104,3 +104,17 @@ report whether more exist; ancestry, rather than the bounded list, detects a
104104 rewrite. Merge-request details include at most `ports.MaxMergeRequestCommits`
105105 (100) commits. These history queries remain on the merge-request service
106106 because it owns the merge-git port.
107+
108+### Review page panels
109+
110+The main request card ends with a collapsed Commits / Checks footer. With
111+scripts, arrow keys (and Home / End) switch its tabs; without scripts, opening
112+the footer shows both sections. The checks summary above the diff opens the
113+Checks tab and continues to update live. Commit totals use `N+` when the branch
114+list is capped: the reader's existing count operation counts all reachable
115+ancestors, not the source-minus-target range.
116+
117+The rail keeps Files (including its `g f` shortcut) and Verdicts. Merge settings
118+are read-only information in the More (⋯) menu, available to every viewer.
119+Signing-key information is also there when a merge box offers signed modes;
120+merge actions remain restricted to their existing permissions.
@@ -104,3 +104,17 @@ report whether more exist; ancestry, rather than the bounded list, detects a
104 rewrite. Merge-request details include at most `ports.MaxMergeRequestCommits`104 rewrite. Merge-request details include at most `ports.MaxMergeRequestCommits`
105 (100) commits. These history queries remain on the merge-request service105 (100) commits. These history queries remain on the merge-request service
106 because it owns the merge-git port.106 because it owns the merge-git port.
107+
108+### Review page panels
109+
110+The main request card ends with a collapsed Commits / Checks footer. With
111+scripts, arrow keys (and Home / End) switch its tabs; without scripts, opening
112+the footer shows both sections. The checks summary above the diff opens the
113+Checks tab and continues to update live. Commit totals use `N+` when the branch
114+list is capped: the reader's existing count operation counts all reachable
115+ancestors, not the source-minus-target range.
116+
117+The rail keeps Files (including its `g f` shortcut) and Verdicts. Merge settings
118+are read-only information in the More (⋯) menu, available to every viewer.
119+Signing-key information is also there when a merge box offers signed modes;
120+merge actions remain restricted to their existing permissions.
M internal/adapters/web/actions.templ +2 -2
@@ -434,7 +434,7 @@ templ CommitChecks(c ChecksSummary) {
434434 }
435435
436436 // MRChecksSum is the state of the checks of a merge request in the bar above
437-// the diff, a link to the checks of the rail. The event stream replaces it
437+// the diff, a link to the checks of the card footer. The event stream replaces it
438438 // with the checks section (same event, fragments.go).
439439 templ MRChecksSum(c ChecksSummary) {
440440 <a class="ck-sum mr-ck" id="mr-ck" href="#mr-checks" title={ c.Title }>
@@ -447,7 +447,7 @@ templ MRChecksSum(c ChecksSummary) {
447447 </a>
448448 }
449449
450-// MRChecks is the checks section of the rail of a merge request.
450+// MRChecks is the checks section of the footer of a merge request.
451451 templ MRChecks(c ChecksSection) {
452452 <section aria-labelledby="r-checks" id="mr-checks">
453453 <h2 id="r-checks">Checks <span class="count">{ itoa(len(c.Rows)) }</span></h2>
@@ -434,7 +434,7 @@ templ CommitChecks(c ChecksSummary) {
434 }434 }
435 435
436 // MRChecksSum is the state of the checks of a merge request in the bar above436 // MRChecksSum is the state of the checks of a merge request in the bar above
437-// the diff, a link to the checks of the rail. The event stream replaces it437+// the diff, a link to the checks of the card footer. The event stream replaces it
438 // with the checks section (same event, fragments.go).438 // with the checks section (same event, fragments.go).
439 templ MRChecksSum(c ChecksSummary) {439 templ MRChecksSum(c ChecksSummary) {
440 <a class="ck-sum mr-ck" id="mr-ck" href="#mr-checks" title={ c.Title }>440 <a class="ck-sum mr-ck" id="mr-ck" href="#mr-checks" title={ c.Title }>
@@ -447,7 +447,7 @@ templ MRChecksSum(c ChecksSummary) {
447 </a>447 </a>
448 }448 }
449 449
450-// MRChecks is the checks section of the rail of a merge request.450+// MRChecks is the checks section of the footer of a merge request.
451 templ MRChecks(c ChecksSection) {451 templ MRChecks(c ChecksSection) {
452 <section aria-labelledby="r-checks" id="mr-checks">452 <section aria-labelledby="r-checks" id="mr-checks">
453 <h2 id="r-checks">Checks <span class="count">{ itoa(len(c.Rows)) }</span></h2>453 <h2 id="r-checks">Checks <span class="count">{ itoa(len(c.Rows)) }</span></h2>
M internal/adapters/web/actions_templ.go +2 -2 generated file: collapsed
M internal/adapters/web/checks.go +1 -1
@@ -81,7 +81,7 @@ func checksSummary(repo domain.RepoName, sha string, checks []ports.CheckView) C
8181 return sum
8282 }
8383
84-// checksSection is the checks of the rail of a merge request, with the rule of
84+// checksSection is the checks of the footer of a merge request, with the rule of
8585 // the repository that applies to them.
8686 func checksSection(repo domain.Repo, checks []ports.CheckView) ChecksSection {
8787 sec := ChecksSection{}
@@ -81,7 +81,7 @@ func checksSummary(repo domain.RepoName, sha string, checks []ports.CheckView) C
81 return sum81 return sum
82 }82 }
83 83
84-// checksSection is the checks of the rail of a merge request, with the rule of84+// checksSection is the checks of the footer of a merge request, with the rule of
85 // the repository that applies to them.85 // the repository that applies to them.
86 func checksSection(repo domain.Repo, checks []ports.CheckView) ChecksSection {86 func checksSection(repo domain.Repo, checks []ports.CheckView) ChecksSection {
87 sec := ChecksSection{}87 sec := ChecksSection{}
M internal/adapters/web/diff.templ +6 -2
@@ -117,7 +117,7 @@ templ diffViewMenu(p DiffView) {
117117 <details class="menu vmenu">
118118 <summary class="btn" aria-label="Diff view">
119119 if p.Both {
120- <span hx-live="this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">{ viewLabel(p.View) }</span>
120+ <span hx-live="this.textContent = q('#diffs').attr['data-mobile'] !== 'true' && q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">{ viewLabel(p.View) }</span>
121121 } else {
122122 { viewLabel(p.View) }
123123 }
@@ -139,12 +139,16 @@ templ viewLink(p DiffView, view, label, key, href string) {
139139 class="btn vbtn"
140140 data-view={ view }
141141 aria-keyshortcuts={ key }
142+ if view == "split" {
143+ :aria-disabled="q('#diffs').attr['data-mobile'] === 'true' ? 'true' : false"
144+ :title="q('#diffs').attr['data-mobile'] === 'true' ? 'Split view requires a wider screen' : 'Split view'"
145+ }
142146 if p.View == view {
143147 aria-current="true"
144148 }
145149 if p.Both {
146150 data-fire={ view }
147- :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false"
151+ :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false"
148152 }
149153 >{ label }<kbd aria-hidden="true">{ key }</kbd></a>
150154 }
@@ -117,7 +117,7 @@ templ diffViewMenu(p DiffView) {
117 <details class="menu vmenu">117 <details class="menu vmenu">
118 <summary class="btn" aria-label="Diff view">118 <summary class="btn" aria-label="Diff view">
119 if p.Both {119 if p.Both {
120- <span hx-live="this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">{ viewLabel(p.View) }</span>120+ <span hx-live="this.textContent = q('#diffs').attr['data-mobile'] !== 'true' && q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">{ viewLabel(p.View) }</span>
121 } else {121 } else {
122 { viewLabel(p.View) }122 { viewLabel(p.View) }
123 }123 }
@@ -139,12 +139,16 @@ templ viewLink(p DiffView, view, label, key, href string) {
139 class="btn vbtn"139 class="btn vbtn"
140 data-view={ view }140 data-view={ view }
141 aria-keyshortcuts={ key }141 aria-keyshortcuts={ key }
142+ if view == "split" {
143+ :aria-disabled="q('#diffs').attr['data-mobile'] === 'true' ? 'true' : false"
144+ :title="q('#diffs').attr['data-mobile'] === 'true' ? 'Split view requires a wider screen' : 'Split view'"
145+ }
142 if p.View == view {146 if p.View == view {
143 aria-current="true"147 aria-current="true"
144 }148 }
145 if p.Both {149 if p.Both {
146 data-fire={ view }150 data-fire={ view }
147- :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false"151+ :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false"
148 }152 }
149 >{ label }<kbd aria-hidden="true">{ key }</kbd></a>153 >{ label }<kbd aria-hidden="true">{ key }</kbd></a>
150 }154 }
M internal/adapters/web/diff_templ.go +190 -184 generated file: collapsed
M internal/adapters/web/jstest/a11y.test.mjs +23 -0
@@ -358,3 +358,26 @@ test('activity moves a home row up only in newest activity order, preserving foc
358358 assert.ok(fresh.hasAttribute('data-cursor'));
359359 }
360360 });
361+
362+test('mobile MR layout shortcuts preserve the saved preference until back on desktop', () => {
363+ const diffs = el('div', { id: 'diffs', attrs: { 'data-mr': '', 'data-diff': 'split', 'data-mobile': 'true' } });
364+ dom.body.replaceChildren(diffs);
365+ const oldQuery = doc.querySelector;
366+ doc.querySelector = query.one;
367+ const previous = globalThis.sessionStorage;
368+ const writes = [];
369+ globalThis.sessionStorage = { setItem: (...args) => writes.push(args) };
370+ try {
371+ window.ermite.layout('unified');
372+ window.ermite.layout('split');
373+ assert.equal(diffs.dataset.diff, 'split');
374+ assert.deepEqual(writes, []);
375+ diffs.dataset.mobile = 'false';
376+ window.ermite.layout('unified');
377+ assert.equal(diffs.dataset.diff, 'unified');
378+ assert.deepEqual(writes, [['diff', 'unified']]);
379+ } finally {
380+ globalThis.sessionStorage = previous;
381+ doc.querySelector = oldQuery;
382+ }
383+});
@@ -358,3 +358,26 @@ test('activity moves a home row up only in newest activity order, preserving foc
358 assert.ok(fresh.hasAttribute('data-cursor'));358 assert.ok(fresh.hasAttribute('data-cursor'));
359 }359 }
360 });360 });
361+
362+test('mobile MR layout shortcuts preserve the saved preference until back on desktop', () => {
363+ const diffs = el('div', { id: 'diffs', attrs: { 'data-mr': '', 'data-diff': 'split', 'data-mobile': 'true' } });
364+ dom.body.replaceChildren(diffs);
365+ const oldQuery = doc.querySelector;
366+ doc.querySelector = query.one;
367+ const previous = globalThis.sessionStorage;
368+ const writes = [];
369+ globalThis.sessionStorage = { setItem: (...args) => writes.push(args) };
370+ try {
371+ window.ermite.layout('unified');
372+ window.ermite.layout('split');
373+ assert.equal(diffs.dataset.diff, 'split');
374+ assert.deepEqual(writes, []);
375+ diffs.dataset.mobile = 'false';
376+ window.ermite.layout('unified');
377+ assert.equal(diffs.dataset.diff, 'unified');
378+ assert.deepEqual(writes, [['diff', 'unified']]);
379+ } finally {
380+ globalThis.sessionStorage = previous;
381+ doc.querySelector = oldQuery;
382+ }
383+});
M internal/adapters/web/jstest/mr.test.mjs +149 -0
@@ -92,3 +92,152 @@ for (const dataset of [{diff:'split'}, {view:'split'}]) test(`reveal selects the
9292 globalThis.requestAnimationFrame=savedRAF;
9393 }
9494 });
95+
96+test('footer tabs switch panels, support arrows, and open on checks hash', () => {
97+ const oldDocument = globalThis.document;
98+ const oldLocation = globalThis.location;
99+ const oldAdd = globalThis.addEventListener;
100+ const listeners = {};
101+ const node = (id) => ({ id, attrs: {}, events: {}, hidden: false,
102+ setAttribute(k,v) { this.attrs[k]=v; },
103+ addEventListener(k,v) { this.events[k]=v; }, focus() { this.focused=true; } });
104+ const tabs = [node('mr-tab-commits'), node('mr-tab-checks')];
105+ const panels = [node('mr-commits'), node('mr-checks-panel')];
106+ const footer = node('mr-panels'); footer.open=false;
107+ const nav = node('tabs'); nav.querySelectorAll=()=>tabs;
108+ footer.querySelectorAll=()=>panels;
109+ globalThis.document = {querySelector: (s) => s === '#mr-panels' ? footer : s === '[data-mr-tabs]' ? nav : null,
110+ addEventListener(k,v) {listeners[k]=v;} };
111+ globalThis.location = {hash:''};
112+ globalThis.addEventListener = (k,v) => {listeners[k]=v;};
113+ try {
114+ window.ermiteMR.panels();
115+ assert.equal(footer.open,false);
116+ assert.equal(panels[0].hidden,false);
117+ assert.equal(panels[1].hidden,true);
118+ tabs[1].events.click({preventDefault(){}});
119+ assert.equal(panels[0].hidden,true);
120+ assert.equal(tabs[1].attrs['aria-selected'],'true');
121+ tabs[1].events.keydown({key:'ArrowRight',preventDefault(){}});
122+ assert.equal(tabs[0].focused,true);
123+ assert.equal(panels[0].hidden,false);
124+ location.hash='#mr-checks'; listeners.hashchange();
125+ assert.equal(footer.open,true);
126+ assert.equal(panels[1].hidden,false);
127+ footer.open=false;
128+ listeners.click({target:{closest:()=>true}});
129+ assert.equal(footer.open,true);
130+ assert.equal(C.tabIndex('Home',1,2),0);
131+ assert.equal(C.tabIndex('End',0,2),1);
132+ assert.equal(C.tabIndex('ArrowLeft',0,2),1);
133+ assert.equal(C.tabIndex('Escape',0,2),null);
134+ } finally {
135+ globalThis.document=oldDocument; globalThis.location=oldLocation; globalThis.addEventListener=oldAdd;
136+ }
137+});
138+
139+test('touch range: first tap anchors, second tap opens the sorted range', () => {
140+ const base = 'https://forge.test/demo/merge-requests/1';
141+ const first = base + '?on=new:24:a.go#f1';
142+ const last = base + '?on=new:10:a.go#f1';
143+ assert.deepEqual(C.touchRange(null, first, base), { start: first, url: null });
144+ const result = C.touchRange(first, last, base);
145+ assert.equal(result.start, null);
146+ assert.equal(new URL(result.url).searchParams.get('on'), 'new:10-24:a.go');
147+ assert.deepEqual(C.touchRange(first, first, base), { start: null, url: first });
148+});
149+
150+test('touch range: a different file, side or request becomes a new anchor', () => {
151+ const base = 'https://forge.test/demo/merge-requests/1';
152+ const first = base + '?on=new:24:a.go#f1';
153+ for (const next of [first.replace('new:', 'old:'), first.replace('a.go', 'b.go'), first.replace('/1?', '/2?')]) {
154+ assert.deepEqual(C.touchRange(first, next, base), { start: next, url: null });
155+ }
156+});
157+
158+test('mobile unified fallback only redirects single-layout split pages and preserves query/hash', () => {
159+ const href = 'https://forge.test/demo/merge-requests/1?view=split&from=25&on=new:3:a.go#f26';
160+ assert.equal(C.mobileURL(href, 'split', false), null);
161+ assert.equal(C.mobileURL(href, undefined, true), null, 'both layouts are switched by CSS');
162+ assert.equal(C.mobileURL(href, 'unified', true), null, 'no redirect loop');
163+ const url = new URL(C.mobileURL(href, 'split', true));
164+ assert.equal(url.searchParams.get('view'), 'unified');
165+ assert.equal(url.searchParams.get('from'), '25');
166+ assert.equal(url.searchParams.get('on'), 'new:3:a.go');
167+ assert.equal(url.hash, '#f26');
168+});
169+
170+test('touch control: lazy links enable toolbar; ordinary taps pass through; ranges navigate and cancel', async () => {
171+ const saved = Object.fromEntries(['document', 'location', 'addEventListener', 'localStorage', 'sessionStorage', 'fetch', 'matchMedia'].map((k) => [k, globalThis[k]]));
172+ const make = () => ({
173+ attrs: {}, events: {}, children: [], textContent: '',
174+ setAttribute(k, v) { this.attrs[k] = v; },
175+ removeAttribute(k) { delete this.attrs[k]; },
176+ addEventListener(k, fn) { this.events[k] = fn; },
177+ append(...nodes) { this.children.push(...nodes); },
178+ prepend(node) { this.children.unshift(node); },
179+ querySelector() { return null; }, querySelectorAll() { return []; },
180+ });
181+ const diffs = make();
182+ diffs.dataset = { diff: 'split' };
183+ const base = 'https://forge.test/demo/merge-requests/1';
184+ const line = (n) => Object.assign(make(), { href: `${base}?on=new:${n}:a.go#f1`, textContent: String(n) });
185+ const a = line(20), b = line(10);
186+ let loaded = false;
187+ diffs.querySelector = () => loaded ? a : null;
188+ let assigned = null;
189+ globalThis.document = {
190+ querySelector: (sel) => sel === '#diffs[data-mr]' || sel === '#diffs' ? diffs : null,
191+ querySelectorAll: () => [], createElement: (tag) => tag === 'template' ? { content: { querySelectorAll: () => [] } } : make(),
192+ };
193+ globalThis.location = { href: base, pathname: '/demo/merge-requests/1', hash: '', assign(url) { assigned = url; } };
194+ globalThis.addEventListener = () => {};
195+ let resize;
196+ const media = { matches: true, addEventListener(type, fn) { resize = fn; } };
197+ globalThis.matchMedia = () => media;
198+ globalThis.fetch = async () => { loaded = true; return { ok: true, status: 200, text: async () => '' }; };
199+ globalThis.localStorage = globalThis.sessionStorage = { getItem: () => null };
200+ const click = (link, modifiers = {}) => {
201+ const e = { target: { closest: () => link }, prevented: false, stopped: false,
202+ preventDefault() { this.prevented = true; }, stopPropagation() { this.stopped = true; }, ...modifiers };
203+ diffs.events.click(e);
204+ return e;
205+ };
206+ try {
207+ window.ermiteMR.start();
208+ const bar = diffs.children[0];
209+ const [button, status] = bar.children;
210+ assert.equal(bar.hidden, true, 'no commentable links in the initial window');
211+ assert.equal(typeof diffs.events.click, 'function', 'delegation installed before lazy load');
212+ await window.ermiteMR.load({ dataset: { src: '/files?from=25' } });
213+ assert.equal(bar.hidden, false, 'lazy window refresh reveals range control');
214+ assert.equal(diffs.dataset.mobile, 'true');
215+ assert.equal(diffs.dataset.diff, 'split', 'preferred layout is retained');
216+ media.matches = false;
217+ resize();
218+ assert.equal(diffs.dataset.mobile, 'false', 'desktop menu returns to preferred layout');
219+ assert.equal(diffs.dataset.diff, 'split');
220+ assert.equal(click(a).prevented, false, 'normal single-line navigation is untouched');
221+ button.events.click();
222+ assert.equal(button.attrs['aria-pressed'], 'true');
223+ assert.equal(click(a, { shiftKey: true }).prevented, false, 'desktop range selection is untouched');
224+ const event = click(a);
225+ assert.equal(event.prevented, true);
226+ assert.equal(event.stopped, true);
227+ assert.ok('data-range-start' in a.attrs);
228+ assert.match(status.textContent, /20/);
229+ click(b);
230+ assert.equal(new URL(assigned).searchParams.get('on'), 'new:10-20:a.go');
231+ assert.equal('data-range-start' in a.attrs, false);
232+ click(a);
233+ button.events.click();
234+ assert.equal(button.attrs['aria-pressed'], 'false');
235+ assert.equal(status.textContent, '');
236+ assert.equal('data-range-start' in a.attrs, false);
237+ assert.equal(click(b).prevented, false);
238+ } finally {
239+ for (const [k, v] of Object.entries(saved)) {
240+ if (v === undefined) delete globalThis[k]; else globalThis[k] = v;
241+ }
242+ }
243+});
@@ -92,3 +92,152 @@ for (const dataset of [{diff:'split'}, {view:'split'}]) test(`reveal selects the
92 globalThis.requestAnimationFrame=savedRAF;92 globalThis.requestAnimationFrame=savedRAF;
93 }93 }
94 });94 });
95+
96+test('footer tabs switch panels, support arrows, and open on checks hash', () => {
97+ const oldDocument = globalThis.document;
98+ const oldLocation = globalThis.location;
99+ const oldAdd = globalThis.addEventListener;
100+ const listeners = {};
101+ const node = (id) => ({ id, attrs: {}, events: {}, hidden: false,
102+ setAttribute(k,v) { this.attrs[k]=v; },
103+ addEventListener(k,v) { this.events[k]=v; }, focus() { this.focused=true; } });
104+ const tabs = [node('mr-tab-commits'), node('mr-tab-checks')];
105+ const panels = [node('mr-commits'), node('mr-checks-panel')];
106+ const footer = node('mr-panels'); footer.open=false;
107+ const nav = node('tabs'); nav.querySelectorAll=()=>tabs;
108+ footer.querySelectorAll=()=>panels;
109+ globalThis.document = {querySelector: (s) => s === '#mr-panels' ? footer : s === '[data-mr-tabs]' ? nav : null,
110+ addEventListener(k,v) {listeners[k]=v;} };
111+ globalThis.location = {hash:''};
112+ globalThis.addEventListener = (k,v) => {listeners[k]=v;};
113+ try {
114+ window.ermiteMR.panels();
115+ assert.equal(footer.open,false);
116+ assert.equal(panels[0].hidden,false);
117+ assert.equal(panels[1].hidden,true);
118+ tabs[1].events.click({preventDefault(){}});
119+ assert.equal(panels[0].hidden,true);
120+ assert.equal(tabs[1].attrs['aria-selected'],'true');
121+ tabs[1].events.keydown({key:'ArrowRight',preventDefault(){}});
122+ assert.equal(tabs[0].focused,true);
123+ assert.equal(panels[0].hidden,false);
124+ location.hash='#mr-checks'; listeners.hashchange();
125+ assert.equal(footer.open,true);
126+ assert.equal(panels[1].hidden,false);
127+ footer.open=false;
128+ listeners.click({target:{closest:()=>true}});
129+ assert.equal(footer.open,true);
130+ assert.equal(C.tabIndex('Home',1,2),0);
131+ assert.equal(C.tabIndex('End',0,2),1);
132+ assert.equal(C.tabIndex('ArrowLeft',0,2),1);
133+ assert.equal(C.tabIndex('Escape',0,2),null);
134+ } finally {
135+ globalThis.document=oldDocument; globalThis.location=oldLocation; globalThis.addEventListener=oldAdd;
136+ }
137+});
138+
139+test('touch range: first tap anchors, second tap opens the sorted range', () => {
140+ const base = 'https://forge.test/demo/merge-requests/1';
141+ const first = base + '?on=new:24:a.go#f1';
142+ const last = base + '?on=new:10:a.go#f1';
143+ assert.deepEqual(C.touchRange(null, first, base), { start: first, url: null });
144+ const result = C.touchRange(first, last, base);
145+ assert.equal(result.start, null);
146+ assert.equal(new URL(result.url).searchParams.get('on'), 'new:10-24:a.go');
147+ assert.deepEqual(C.touchRange(first, first, base), { start: null, url: first });
148+});
149+
150+test('touch range: a different file, side or request becomes a new anchor', () => {
151+ const base = 'https://forge.test/demo/merge-requests/1';
152+ const first = base + '?on=new:24:a.go#f1';
153+ for (const next of [first.replace('new:', 'old:'), first.replace('a.go', 'b.go'), first.replace('/1?', '/2?')]) {
154+ assert.deepEqual(C.touchRange(first, next, base), { start: next, url: null });
155+ }
156+});
157+
158+test('mobile unified fallback only redirects single-layout split pages and preserves query/hash', () => {
159+ const href = 'https://forge.test/demo/merge-requests/1?view=split&from=25&on=new:3:a.go#f26';
160+ assert.equal(C.mobileURL(href, 'split', false), null);
161+ assert.equal(C.mobileURL(href, undefined, true), null, 'both layouts are switched by CSS');
162+ assert.equal(C.mobileURL(href, 'unified', true), null, 'no redirect loop');
163+ const url = new URL(C.mobileURL(href, 'split', true));
164+ assert.equal(url.searchParams.get('view'), 'unified');
165+ assert.equal(url.searchParams.get('from'), '25');
166+ assert.equal(url.searchParams.get('on'), 'new:3:a.go');
167+ assert.equal(url.hash, '#f26');
168+});
169+
170+test('touch control: lazy links enable toolbar; ordinary taps pass through; ranges navigate and cancel', async () => {
171+ const saved = Object.fromEntries(['document', 'location', 'addEventListener', 'localStorage', 'sessionStorage', 'fetch', 'matchMedia'].map((k) => [k, globalThis[k]]));
172+ const make = () => ({
173+ attrs: {}, events: {}, children: [], textContent: '',
174+ setAttribute(k, v) { this.attrs[k] = v; },
175+ removeAttribute(k) { delete this.attrs[k]; },
176+ addEventListener(k, fn) { this.events[k] = fn; },
177+ append(...nodes) { this.children.push(...nodes); },
178+ prepend(node) { this.children.unshift(node); },
179+ querySelector() { return null; }, querySelectorAll() { return []; },
180+ });
181+ const diffs = make();
182+ diffs.dataset = { diff: 'split' };
183+ const base = 'https://forge.test/demo/merge-requests/1';
184+ const line = (n) => Object.assign(make(), { href: `${base}?on=new:${n}:a.go#f1`, textContent: String(n) });
185+ const a = line(20), b = line(10);
186+ let loaded = false;
187+ diffs.querySelector = () => loaded ? a : null;
188+ let assigned = null;
189+ globalThis.document = {
190+ querySelector: (sel) => sel === '#diffs[data-mr]' || sel === '#diffs' ? diffs : null,
191+ querySelectorAll: () => [], createElement: (tag) => tag === 'template' ? { content: { querySelectorAll: () => [] } } : make(),
192+ };
193+ globalThis.location = { href: base, pathname: '/demo/merge-requests/1', hash: '', assign(url) { assigned = url; } };
194+ globalThis.addEventListener = () => {};
195+ let resize;
196+ const media = { matches: true, addEventListener(type, fn) { resize = fn; } };
197+ globalThis.matchMedia = () => media;
198+ globalThis.fetch = async () => { loaded = true; return { ok: true, status: 200, text: async () => '' }; };
199+ globalThis.localStorage = globalThis.sessionStorage = { getItem: () => null };
200+ const click = (link, modifiers = {}) => {
201+ const e = { target: { closest: () => link }, prevented: false, stopped: false,
202+ preventDefault() { this.prevented = true; }, stopPropagation() { this.stopped = true; }, ...modifiers };
203+ diffs.events.click(e);
204+ return e;
205+ };
206+ try {
207+ window.ermiteMR.start();
208+ const bar = diffs.children[0];
209+ const [button, status] = bar.children;
210+ assert.equal(bar.hidden, true, 'no commentable links in the initial window');
211+ assert.equal(typeof diffs.events.click, 'function', 'delegation installed before lazy load');
212+ await window.ermiteMR.load({ dataset: { src: '/files?from=25' } });
213+ assert.equal(bar.hidden, false, 'lazy window refresh reveals range control');
214+ assert.equal(diffs.dataset.mobile, 'true');
215+ assert.equal(diffs.dataset.diff, 'split', 'preferred layout is retained');
216+ media.matches = false;
217+ resize();
218+ assert.equal(diffs.dataset.mobile, 'false', 'desktop menu returns to preferred layout');
219+ assert.equal(diffs.dataset.diff, 'split');
220+ assert.equal(click(a).prevented, false, 'normal single-line navigation is untouched');
221+ button.events.click();
222+ assert.equal(button.attrs['aria-pressed'], 'true');
223+ assert.equal(click(a, { shiftKey: true }).prevented, false, 'desktop range selection is untouched');
224+ const event = click(a);
225+ assert.equal(event.prevented, true);
226+ assert.equal(event.stopped, true);
227+ assert.ok('data-range-start' in a.attrs);
228+ assert.match(status.textContent, /20/);
229+ click(b);
230+ assert.equal(new URL(assigned).searchParams.get('on'), 'new:10-20:a.go');
231+ assert.equal('data-range-start' in a.attrs, false);
232+ click(a);
233+ button.events.click();
234+ assert.equal(button.attrs['aria-pressed'], 'false');
235+ assert.equal(status.textContent, '');
236+ assert.equal('data-range-start' in a.attrs, false);
237+ assert.equal(click(b).prevented, false);
238+ } finally {
239+ for (const [k, v] of Object.entries(saved)) {
240+ if (v === undefined) delete globalThis[k]; else globalThis[k] = v;
241+ }
242+ }
243+});
M internal/adapters/web/mr.go +3 -0
@@ -291,6 +291,7 @@ type MRPage struct {
291291
292292 Commits []MRCommit
293293 CommitsNote string
294+ CommitCount string
294295 Modes []string
295296 ChecksBlock bool
296297 // Checks are the CI checks of the head of the request, ChecksSum their
@@ -734,7 +735,9 @@ func (s *Server) mrReadPresentation(p *MRPage, name string, n int64, res ports.M
734735 })
735736 }
736737 lastRead := res.LastReadID.String()
738+ p.CommitCount = itoa(len(p.Commits))
737739 if res.CommitsTruncated {
740+ p.CommitCount += "+"
738741 p.CommitsNote = "the branch has more commits than the " + itoa(len(p.Commits)) + " listed."
739742 }
740743
@@ -291,6 +291,7 @@ type MRPage struct {
291 291
292 Commits []MRCommit292 Commits []MRCommit
293 CommitsNote string293 CommitsNote string
294+ CommitCount string
294 Modes []string295 Modes []string
295 ChecksBlock bool296 ChecksBlock bool
296 // Checks are the CI checks of the head of the request, ChecksSum their297 // Checks are the CI checks of the head of the request, ChecksSum their
@@ -734,7 +735,9 @@ func (s *Server) mrReadPresentation(p *MRPage, name string, n int64, res ports.M
734 })735 })
735 }736 }
736 lastRead := res.LastReadID.String()737 lastRead := res.LastReadID.String()
738+ p.CommitCount = itoa(len(p.Commits))
737 if res.CommitsTruncated {739 if res.CommitsTruncated {
740+ p.CommitCount += "+"
738 p.CommitsNote = "the branch has more commits than the " + itoa(len(p.Commits)) + " listed."741 p.CommitsNote = "the branch has more commits than the " + itoa(len(p.Commits)) + " listed."
739 }742 }
740 743
M internal/adapters/web/mr.templ +105 -82
@@ -147,6 +147,7 @@ templ MergeRequest(l Layout, p MRPage) {
147147 @templ.Raw(string(p.Desc))
148148 </article>
149149 }
150+ @mrFooter(p)
150151 </section>
151152 if p.Deleting != "" {
152153 <p class="note" role="status">merged. the branch { p.Deleting } is being deleted.</p>
@@ -366,6 +367,65 @@ templ commentForm(f CommentForm, suffix string) {
366367 </form>
367368 }
368369
370+templ mrFooter(p MRPage) {
371+ <footer class="mr-footer">
372+ <details id="mr-panels">
373+ <summary>Commits <span class="count">{ p.CommitCount }</span> · Checks</summary>
374+ <nav data-mr-tabs aria-label="Branch details">
375+ <a id="mr-tab-commits" href="#mr-commits">Commits <span class="count">{ p.CommitCount }</span></a>
376+ <a id="mr-tab-checks" href="#mr-checks">
377+ { "Checks " }
378+ <span data-checks-label>
379+ if p.ChecksSum.Total > 0 {
380+ { p.ChecksSum.Title }
381+ } else {
382+ no checks
383+ }
384+ </span>
385+ </a>
386+ </nav>
387+ <div id="mr-commits" data-mr-panel aria-labelledby="mr-tab-commits">
388+ <table class="mr-commits">
389+ <thead><tr><th>Commit</th><th>Subject</th><th>Author</th><th>Date</th><th>Signature</th><th>Status</th></tr></thead>
390+ <tbody>
391+ for _, c := range p.Commits {
392+ <tr data-new?={ c.New }>
393+ <td><a href={ templ.SafeURL(c.Href) }>{ c.Short }</a></td>
394+ <td>{ c.Subject }</td>
395+ <td>{ c.Author }</td>
396+ <td>
397+ if c.WhenAt != "" {
398+ <time datetime={ c.WhenAt }>{ c.When }</time>
399+ }
400+ </td>
401+ <td>
402+ if c.Sig != nil {
403+ @signaturePill(c.Sig)
404+ }
405+ </td>
406+ <td>
407+ if c.New {
408+ <span>new</span>
409+ }
410+ </td>
411+ </tr>
412+ }
413+ </tbody>
414+ </table>
415+ if len(p.Commits) == 0 {
416+ <p class="dim">no commit to merge.</p>
417+ }
418+ if p.CommitsNote != "" {
419+ <p class="note">{ p.CommitsNote }</p>
420+ }
421+ </div>
422+ <div id="mr-checks-panel" data-mr-panel aria-labelledby="mr-tab-checks">
423+ @MRChecks(p.Checks)
424+ </div>
425+ </details>
426+ </footer>
427+}
428+
369429 templ mrRail(p MRPage) {
370430 <section aria-labelledby="r-files" class="r-files">
371431 <h2 id="r-files">
@@ -391,51 +451,6 @@ templ mrRail(p MRPage) {
391451 </ul>
392452 </section>
393453 }
394- @MRChecks(p.Checks)
395- <section aria-labelledby="r-commits">
396- <h2 id="r-commits">Commits <span class="count">{ itoa(len(p.Commits)) }</span></h2>
397- <ul class="pcommits">
398- for _, c := range p.Commits {
399- <li data-new?={ c.New }>
400- <a href={ templ.SafeURL(c.Href) }>{ c.Short }</a>
401- <span class="s">{ c.Subject }</span>
402- if c.Sig != nil {
403- @signaturePill(c.Sig)
404- }
405- <span class="mute">
406- { c.Author }
407- if c.WhenAt != "" {
408- { " · " }<time datetime={ c.WhenAt }>{ c.When }</time>
409- }
410- if c.New {
411- { " · new" }
412- }
413- </span>
414- </li>
415- }
416- </ul>
417- if len(p.Commits) == 0 {
418- <p class="dim">no commit to merge.</p>
419- }
420- if p.CommitsNote != "" {
421- <p class="note">{ p.CommitsNote }</p>
422- }
423- </section>
424- <section aria-labelledby="r-settings">
425- <h2 id="r-settings">Settings</h2>
426- <dl class="kv">
427- <dt>modes</dt>
428- <dd>{ strings.Join(p.Modes, ", ") }</dd>
429- <dt>checks</dt>
430- <dd>
431- if p.ChecksBlock {
432- failing ones block the merge
433- } else {
434- do not block the merge
435- }
436- </dd>
437- </dl>
438- </section>
439454 }
440455
441456 // mrBar is the bar above the diff, which follows the review: the totals, the
@@ -450,8 +465,8 @@ templ mrBar(p MRPage) {
450465 @MRChecksSum(p.ChecksSum)
451466 if p.Box != nil {
452467 @mergeMenu(p)
453- @moreMenu(p)
454468 }
469+ @moreMenu(p)
455470 </div>
456471 }
457472
@@ -474,18 +489,9 @@ templ mergeMenu(p MRPage) {
474489 <kbd aria-hidden="true">M</kbd>
475490 </summary>
476491 <div class="menu-pop" role="group" aria-label="Merge">
477- <dl class="kv">
478- <dt>head</dt>
479- <dd>
480- if p.Box.HeadGone {
481- gone: the source branch was deleted
482- } else {
483- { p.HeadShort }
484- }
485- </dd>
486- <dt>into</dt>
487- <dd>{ p.Target }</dd>
488- </dl>
492+ if p.Box.HeadGone {
493+ <p class="dim">the source branch was deleted</p>
494+ }
489495 if p.Box.Error != "" {
490496 <p class="d-err" role="alert">{ p.Box.Error }</p>
491497 }
@@ -519,15 +525,6 @@ templ mergeMenu(p MRPage) {
519525 </label>
520526 }
521527 </fieldset>
522- if p.Box.Signed {
523- <p class="d-note" id="mr-signing">
524- squash and merge commits are signed with ermite's own key (generated on first start).
525- if p.Box.Fingerprint != "" {
526- fingerprint <code>{ p.Box.Fingerprint }</code>
527- }
528- <code>ermite signing-key show</code> prints it.
529- </p>
530- }
531528 if p.Box.CanDeleteBranch {
532529 <label class="d-check"><input type="checkbox" name="delete_branch" value="1"/> delete { p.Source } after the merge <kbd aria-hidden="true">D</kbd></label>
533530 }
@@ -589,26 +586,52 @@ templ MRMergeabilityFragment(v MergeabilityView) {
589586 @mrMergeabilitySlot(v)
590587 }
591588
592-// moreMenu is what else the owner does with an open request: mark the head
593-// read, close it, merge it from a terminal.
589+// moreMenu shows read-only settings to every viewer, and keeps owner actions
590+// behind the same merge-box permission as before.
594591 templ moreMenu(p MRPage) {
595592 <details class="menu omenu">
596593 <summary class="btn icon" aria-label="More actions" title="more actions">⋯</summary>
597594 <div class="menu-pop" role="group" aria-label="More actions">
598- if p.Box.CanMarkRead {
599- <form method="post" action={ templ.SafeURL(p.Box.ReadAction) }>
600- <input type="hidden" name="head_id" value={ p.Box.Head }/>
601- <button type="submit" title="the next visit can show only what changed after this head" class="btn" aria-keyshortcuts="Shift+R" data-read>Mark read <kbd aria-hidden="true">R</kbd></button>
595+ <section class="merge-settings">
596+ <h2>Merge settings</h2>
597+ <dl class="kv">
598+ <dt>modes</dt>
599+ <dd>{ strings.Join(p.Modes, ", ") }</dd>
600+ <dt>checks</dt>
601+ <dd>
602+ if p.ChecksBlock {
603+ failing ones block the merge
604+ } else {
605+ do not block the merge
606+ }
607+ </dd>
608+ </dl>
609+ </section>
610+ if p.Box != nil {
611+ if p.Box.Signed {
612+ <p class="d-note" id="mr-signing">
613+ squash and merge commits are signed with ermite's own key (generated on first start).
614+ if p.Box.Fingerprint != "" {
615+ fingerprint <code>{ p.Box.Fingerprint }</code>
616+ }
617+ <code>ermite signing-key show</code> prints it.
618+ </p>
619+ }
620+ if p.Box.CanMarkRead {
621+ <form method="post" action={ templ.SafeURL(p.Box.ReadAction) }>
622+ <input type="hidden" name="head_id" value={ p.Box.Head }/>
623+ <button type="submit" title="the next visit can show only what changed after this head" class="btn" aria-keyshortcuts="Shift+R" data-read>Mark read <kbd aria-hidden="true">R</kbd></button>
624+ </form>
625+ }
626+ <form method="post" action={ templ.SafeURL(p.Box.CloseAction) }>
627+ <button type="submit" title="close without merging; the branch is kept" class="btn danger">Close</button>
602628 </form>
603- }
604- <form method="post" action={ templ.SafeURL(p.Box.CloseAction) }>
605- <button type="submit" title="close without merging; the branch is kept" class="btn danger">Close</button>
606- </form>
607- if !p.Box.HeadGone && p.Box.ReadyAction == "" {
608- <details class="d-or">
609- <summary class="mute">or from a terminal</summary>
610- @CloneBlock(p.Box.CLI)
611- </details>
629+ if !p.Box.HeadGone && p.Box.ReadyAction == "" {
630+ <details class="d-or">
631+ <summary class="mute">or from a terminal</summary>
632+ @CloneBlock(p.Box.CLI)
633+ </details>
634+ }
612635 }
613636 </div>
614637 </details>
@@ -147,6 +147,7 @@ templ MergeRequest(l Layout, p MRPage) {
147 @templ.Raw(string(p.Desc))147 @templ.Raw(string(p.Desc))
148 </article>148 </article>
149 }149 }
150+ @mrFooter(p)
150 </section>151 </section>
151 if p.Deleting != "" {152 if p.Deleting != "" {
152 <p class="note" role="status">merged. the branch { p.Deleting } is being deleted.</p>153 <p class="note" role="status">merged. the branch { p.Deleting } is being deleted.</p>
@@ -366,6 +367,65 @@ templ commentForm(f CommentForm, suffix string) {
366 </form>367 </form>
367 }368 }
368 369
370+templ mrFooter(p MRPage) {
371+ <footer class="mr-footer">
372+ <details id="mr-panels">
373+ <summary>Commits <span class="count">{ p.CommitCount }</span> · Checks</summary>
374+ <nav data-mr-tabs aria-label="Branch details">
375+ <a id="mr-tab-commits" href="#mr-commits">Commits <span class="count">{ p.CommitCount }</span></a>
376+ <a id="mr-tab-checks" href="#mr-checks">
377+ { "Checks " }
378+ <span data-checks-label>
379+ if p.ChecksSum.Total > 0 {
380+ { p.ChecksSum.Title }
381+ } else {
382+ no checks
383+ }
384+ </span>
385+ </a>
386+ </nav>
387+ <div id="mr-commits" data-mr-panel aria-labelledby="mr-tab-commits">
388+ <table class="mr-commits">
389+ <thead><tr><th>Commit</th><th>Subject</th><th>Author</th><th>Date</th><th>Signature</th><th>Status</th></tr></thead>
390+ <tbody>
391+ for _, c := range p.Commits {
392+ <tr data-new?={ c.New }>
393+ <td><a href={ templ.SafeURL(c.Href) }>{ c.Short }</a></td>
394+ <td>{ c.Subject }</td>
395+ <td>{ c.Author }</td>
396+ <td>
397+ if c.WhenAt != "" {
398+ <time datetime={ c.WhenAt }>{ c.When }</time>
399+ }
400+ </td>
401+ <td>
402+ if c.Sig != nil {
403+ @signaturePill(c.Sig)
404+ }
405+ </td>
406+ <td>
407+ if c.New {
408+ <span>new</span>
409+ }
410+ </td>
411+ </tr>
412+ }
413+ </tbody>
414+ </table>
415+ if len(p.Commits) == 0 {
416+ <p class="dim">no commit to merge.</p>
417+ }
418+ if p.CommitsNote != "" {
419+ <p class="note">{ p.CommitsNote }</p>
420+ }
421+ </div>
422+ <div id="mr-checks-panel" data-mr-panel aria-labelledby="mr-tab-checks">
423+ @MRChecks(p.Checks)
424+ </div>
425+ </details>
426+ </footer>
427+}
428+
369 templ mrRail(p MRPage) {429 templ mrRail(p MRPage) {
370 <section aria-labelledby="r-files" class="r-files">430 <section aria-labelledby="r-files" class="r-files">
371 <h2 id="r-files">431 <h2 id="r-files">
@@ -391,51 +451,6 @@ templ mrRail(p MRPage) {
391 </ul>451 </ul>
392 </section>452 </section>
393 }453 }
394- @MRChecks(p.Checks)
395- <section aria-labelledby="r-commits">
396- <h2 id="r-commits">Commits <span class="count">{ itoa(len(p.Commits)) }</span></h2>
397- <ul class="pcommits">
398- for _, c := range p.Commits {
399- <li data-new?={ c.New }>
400- <a href={ templ.SafeURL(c.Href) }>{ c.Short }</a>
401- <span class="s">{ c.Subject }</span>
402- if c.Sig != nil {
403- @signaturePill(c.Sig)
404- }
405- <span class="mute">
406- { c.Author }
407- if c.WhenAt != "" {
408- { " · " }<time datetime={ c.WhenAt }>{ c.When }</time>
409- }
410- if c.New {
411- { " · new" }
412- }
413- </span>
414- </li>
415- }
416- </ul>
417- if len(p.Commits) == 0 {
418- <p class="dim">no commit to merge.</p>
419- }
420- if p.CommitsNote != "" {
421- <p class="note">{ p.CommitsNote }</p>
422- }
423- </section>
424- <section aria-labelledby="r-settings">
425- <h2 id="r-settings">Settings</h2>
426- <dl class="kv">
427- <dt>modes</dt>
428- <dd>{ strings.Join(p.Modes, ", ") }</dd>
429- <dt>checks</dt>
430- <dd>
431- if p.ChecksBlock {
432- failing ones block the merge
433- } else {
434- do not block the merge
435- }
436- </dd>
437- </dl>
438- </section>
439 }454 }
440 455
441 // mrBar is the bar above the diff, which follows the review: the totals, the456 // mrBar is the bar above the diff, which follows the review: the totals, the
@@ -450,8 +465,8 @@ templ mrBar(p MRPage) {
450 @MRChecksSum(p.ChecksSum)465 @MRChecksSum(p.ChecksSum)
451 if p.Box != nil {466 if p.Box != nil {
452 @mergeMenu(p)467 @mergeMenu(p)
453- @moreMenu(p)
454 }468 }
469+ @moreMenu(p)
455 </div>470 </div>
456 }471 }
457 472
@@ -474,18 +489,9 @@ templ mergeMenu(p MRPage) {
474 <kbd aria-hidden="true">M</kbd>489 <kbd aria-hidden="true">M</kbd>
475 </summary>490 </summary>
476 <div class="menu-pop" role="group" aria-label="Merge">491 <div class="menu-pop" role="group" aria-label="Merge">
477- <dl class="kv">492+ if p.Box.HeadGone {
478- <dt>head</dt>493+ <p class="dim">the source branch was deleted</p>
479- <dd>494+ }
480- if p.Box.HeadGone {
481- gone: the source branch was deleted
482- } else {
483- { p.HeadShort }
484- }
485- </dd>
486- <dt>into</dt>
487- <dd>{ p.Target }</dd>
488- </dl>
489 if p.Box.Error != "" {495 if p.Box.Error != "" {
490 <p class="d-err" role="alert">{ p.Box.Error }</p>496 <p class="d-err" role="alert">{ p.Box.Error }</p>
491 }497 }
@@ -519,15 +525,6 @@ templ mergeMenu(p MRPage) {
519 </label>525 </label>
520 }526 }
521 </fieldset>527 </fieldset>
522- if p.Box.Signed {
523- <p class="d-note" id="mr-signing">
524- squash and merge commits are signed with ermite's own key (generated on first start).
525- if p.Box.Fingerprint != "" {
526- fingerprint <code>{ p.Box.Fingerprint }</code>
527- }
528- <code>ermite signing-key show</code> prints it.
529- </p>
530- }
531 if p.Box.CanDeleteBranch {528 if p.Box.CanDeleteBranch {
532 <label class="d-check"><input type="checkbox" name="delete_branch" value="1"/> delete { p.Source } after the merge <kbd aria-hidden="true">D</kbd></label>529 <label class="d-check"><input type="checkbox" name="delete_branch" value="1"/> delete { p.Source } after the merge <kbd aria-hidden="true">D</kbd></label>
533 }530 }
@@ -589,26 +586,52 @@ templ MRMergeabilityFragment(v MergeabilityView) {
589 @mrMergeabilitySlot(v)586 @mrMergeabilitySlot(v)
590 }587 }
591 588
592-// moreMenu is what else the owner does with an open request: mark the head589+// moreMenu shows read-only settings to every viewer, and keeps owner actions
593-// read, close it, merge it from a terminal.590+// behind the same merge-box permission as before.
594 templ moreMenu(p MRPage) {591 templ moreMenu(p MRPage) {
595 <details class="menu omenu">592 <details class="menu omenu">
596 <summary class="btn icon" aria-label="More actions" title="more actions">⋯</summary>593 <summary class="btn icon" aria-label="More actions" title="more actions">⋯</summary>
597 <div class="menu-pop" role="group" aria-label="More actions">594 <div class="menu-pop" role="group" aria-label="More actions">
598- if p.Box.CanMarkRead {595+ <section class="merge-settings">
599- <form method="post" action={ templ.SafeURL(p.Box.ReadAction) }>596+ <h2>Merge settings</h2>
600- <input type="hidden" name="head_id" value={ p.Box.Head }/>597+ <dl class="kv">
601- <button type="submit" title="the next visit can show only what changed after this head" class="btn" aria-keyshortcuts="Shift+R" data-read>Mark read <kbd aria-hidden="true">R</kbd></button>598+ <dt>modes</dt>
599+ <dd>{ strings.Join(p.Modes, ", ") }</dd>
600+ <dt>checks</dt>
601+ <dd>
602+ if p.ChecksBlock {
603+ failing ones block the merge
604+ } else {
605+ do not block the merge
606+ }
607+ </dd>
608+ </dl>
609+ </section>
610+ if p.Box != nil {
611+ if p.Box.Signed {
612+ <p class="d-note" id="mr-signing">
613+ squash and merge commits are signed with ermite's own key (generated on first start).
614+ if p.Box.Fingerprint != "" {
615+ fingerprint <code>{ p.Box.Fingerprint }</code>
616+ }
617+ <code>ermite signing-key show</code> prints it.
618+ </p>
619+ }
620+ if p.Box.CanMarkRead {
621+ <form method="post" action={ templ.SafeURL(p.Box.ReadAction) }>
622+ <input type="hidden" name="head_id" value={ p.Box.Head }/>
623+ <button type="submit" title="the next visit can show only what changed after this head" class="btn" aria-keyshortcuts="Shift+R" data-read>Mark read <kbd aria-hidden="true">R</kbd></button>
624+ </form>
625+ }
626+ <form method="post" action={ templ.SafeURL(p.Box.CloseAction) }>
627+ <button type="submit" title="close without merging; the branch is kept" class="btn danger">Close</button>
602 </form>628 </form>
603- }629+ if !p.Box.HeadGone && p.Box.ReadyAction == "" {
604- <form method="post" action={ templ.SafeURL(p.Box.CloseAction) }>630+ <details class="d-or">
605- <button type="submit" title="close without merging; the branch is kept" class="btn danger">Close</button>631+ <summary class="mute">or from a terminal</summary>
606- </form>632+ @CloneBlock(p.Box.CLI)
607- if !p.Box.HeadGone && p.Box.ReadyAction == "" {633+ </details>
608- <details class="d-or">634+ }
609- <summary class="mute">or from a terminal</summary>
610- @CloneBlock(p.Box.CLI)
611- </details>
612 }635 }
613 </div>636 </div>
614 </details>637 </details>
M internal/adapters/web/mr_templ.go +607 -563
@@ -808,6 +808,10 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
808808 return templ_7745c5c3_Err
809809 }
810810 }
811+ templ_7745c5c3_Err = mrFooter(p).Render(ctx, templ_7745c5c3_Buffer)
812+ if templ_7745c5c3_Err != nil {
813+ return templ_7745c5c3_Err
814+ }
811815 templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "</section>")
812816 if templ_7745c5c3_Err != nil {
813817 return templ_7745c5c3_Err
@@ -820,7 +824,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
820824 var templ_7745c5c3_Var42 string
821825 templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.JoinStringErrs(p.Deleting)
822826 if templ_7745c5c3_Err != nil {
823- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 152, Col: 64}
827+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 153, Col: 64}
824828 }
825829 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var42))
826830 if templ_7745c5c3_Err != nil {
@@ -843,7 +847,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
843847 var templ_7745c5c3_Var43 string
844848 templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinStringErrs(p.MergeError)
845849 if templ_7745c5c3_Err != nil {
846- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 155, Col: 47}
850+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 156, Col: 47}
847851 }
848852 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43))
849853 if templ_7745c5c3_Err != nil {
@@ -874,7 +878,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
874878 var templ_7745c5c3_Var44 templ.SafeURL
875879 templ_7745c5c3_Var44, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Since.AllHref))
876880 if templ_7745c5c3_Err != nil {
877- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 161, Col: 42}
881+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 162, Col: 42}
878882 }
879883 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var44))
880884 if templ_7745c5c3_Err != nil {
@@ -897,7 +901,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
897901 var templ_7745c5c3_Var45 string
898902 templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
899903 if templ_7745c5c3_Err != nil {
900- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 165, Col: 49}
904+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 166, Col: 49}
901905 }
902906 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var45))
903907 if templ_7745c5c3_Err != nil {
@@ -910,7 +914,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
910914 var templ_7745c5c3_Var46 templ.SafeURL
911915 templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Since.SinceHref))
912916 if templ_7745c5c3_Err != nil {
913- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 167, Col: 44}
917+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 168, Col: 44}
914918 }
915919 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var46))
916920 if templ_7745c5c3_Err != nil {
@@ -933,7 +937,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
933937 var templ_7745c5c3_Var47 string
934938 templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.JoinStringErrs(p.Since.ReadShort)
935939 if templ_7745c5c3_Err != nil {
936- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 171, Col: 64}
940+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 172, Col: 64}
937941 }
938942 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var47))
939943 if templ_7745c5c3_Err != nil {
@@ -946,7 +950,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
946950 var templ_7745c5c3_Var48 string
947951 templ_7745c5c3_Var48, templ_7745c5c3_Err = templ.JoinStringErrs(p.Since.HeadShort)
948952 if templ_7745c5c3_Err != nil {
949- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 171, Col: 90}
953+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 172, Col: 90}
950954 }
951955 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var48))
952956 if templ_7745c5c3_Err != nil {
@@ -969,7 +973,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
969973 var templ_7745c5c3_Var49 string
970974 templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.JoinStringErrs(p.SinceNote)
971975 if templ_7745c5c3_Err != nil {
972- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 175, Col: 34}
976+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 176, Col: 34}
973977 }
974978 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var49))
975979 if templ_7745c5c3_Err != nil {
@@ -1010,7 +1014,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
10101014 var templ_7745c5c3_Var50 string
10111015 templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note)
10121016 if templ_7745c5c3_Err != nil {
1013- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 185, Col: 29}
1017+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 186, Col: 29}
10141018 }
10151019 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var50))
10161020 if templ_7745c5c3_Err != nil {
@@ -1033,7 +1037,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
10331037 var templ_7745c5c3_Var51 string
10341038 templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Canonical)
10351039 if templ_7745c5c3_Err != nil {
1036- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 191, Col: 32}
1040+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 192, Col: 32}
10371041 }
10381042 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var51)
10391043 if templ_7745c5c3_Err != nil {
@@ -1052,7 +1056,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
10521056 var templ_7745c5c3_Var52 string
10531057 templ_7745c5c3_Var52, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
10541058 if templ_7745c5c3_Err != nil {
1055- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 194, Col: 22}
1059+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 195, Col: 22}
10561060 }
10571061 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var52)
10581062 if templ_7745c5c3_Err != nil {
@@ -1070,7 +1074,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
10701074 var templ_7745c5c3_Var53 string
10711075 templ_7745c5c3_Var53, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
10721076 if templ_7745c5c3_Err != nil {
1073- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 196, Col: 22}
1077+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 197, Col: 22}
10741078 }
10751079 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var53)
10761080 if templ_7745c5c3_Err != nil {
@@ -1110,7 +1114,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
11101114 var templ_7745c5c3_Var54 string
11111115 templ_7745c5c3_Var54, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.NUnresolved))
11121116 if templ_7745c5c3_Err != nil {
1113- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 209, Col: 97}
1117+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 210, Col: 97}
11141118 }
11151119 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var54))
11161120 if templ_7745c5c3_Err != nil {
@@ -1123,7 +1127,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
11231127 var templ_7745c5c3_Var55 string
11241128 templ_7745c5c3_Var55, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.NComments))
11251129 if templ_7745c5c3_Err != nil {
1126- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 209, Col: 126}
1130+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 210, Col: 126}
11271131 }
11281132 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var55))
11291133 if templ_7745c5c3_Err != nil {
@@ -1204,7 +1208,7 @@ func branchLink(name, href string) templ.Component {
12041208 var templ_7745c5c3_Var57 templ.SafeURL
12051209 templ_7745c5c3_Var57, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))
12061210 if templ_7745c5c3_Err != nil {
1207- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 227, Col: 31}
1211+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 228, Col: 31}
12081212 }
12091213 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var57))
12101214 if templ_7745c5c3_Err != nil {
@@ -1217,7 +1221,7 @@ func branchLink(name, href string) templ.Component {
12171221 var templ_7745c5c3_Var58 string
12181222 templ_7745c5c3_Var58, templ_7745c5c3_Err = templ.JoinStringErrs(name)
12191223 if templ_7745c5c3_Err != nil {
1220- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 227, Col: 40}
1224+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 228, Col: 40}
12211225 }
12221226 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var58))
12231227 if templ_7745c5c3_Err != nil {
@@ -1231,7 +1235,7 @@ func branchLink(name, href string) templ.Component {
12311235 var templ_7745c5c3_Var59 string
12321236 templ_7745c5c3_Var59, templ_7745c5c3_Err = templ.JoinStringErrs(name)
12331237 if templ_7745c5c3_Err != nil {
1234- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 229, Col: 8}
1238+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 230, Col: 8}
12351239 }
12361240 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var59))
12371241 if templ_7745c5c3_Err != nil {
@@ -1312,7 +1316,7 @@ func commentView(c CommentView, suffix string) templ.Component {
13121316 var templ_7745c5c3_Var62 string
13131317 templ_7745c5c3_Var62, templ_7745c5c3_Err = templ.ResolveAttributeValue("c" + c.ID + suffix)
13141318 if templ_7745c5c3_Err != nil {
1315- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 248, Col: 42}
1319+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 249, Col: 42}
13161320 }
13171321 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var62)
13181322 if templ_7745c5c3_Err != nil {
@@ -1325,7 +1329,7 @@ func commentView(c CommentView, suffix string) templ.Component {
13251329 var templ_7745c5c3_Var63 string
13261330 templ_7745c5c3_Var63, templ_7745c5c3_Err = templ.ResolveAttributeValue(boolText(c.Resolved))
13271331 if templ_7745c5c3_Err != nil {
1328- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 248, Col: 81}
1332+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 249, Col: 81}
13291333 }
13301334 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var63)
13311335 if templ_7745c5c3_Err != nil {
@@ -1348,7 +1352,7 @@ func commentView(c CommentView, suffix string) templ.Component {
13481352 var templ_7745c5c3_Var64 string
13491353 templ_7745c5c3_Var64, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)
13501354 if templ_7745c5c3_Err != nil {
1351- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 250, Col: 33}
1355+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 251, Col: 33}
13521356 }
13531357 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var64))
13541358 if templ_7745c5c3_Err != nil {
@@ -1362,7 +1366,7 @@ func commentView(c CommentView, suffix string) templ.Component {
13621366 var templ_7745c5c3_Var65 string
13631367 templ_7745c5c3_Var65, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
13641368 if templ_7745c5c3_Err != nil {
1365- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 252, Col: 9}
1369+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 253, Col: 9}
13661370 }
13671371 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var65))
13681372 if templ_7745c5c3_Err != nil {
@@ -1375,7 +1379,7 @@ func commentView(c CommentView, suffix string) templ.Component {
13751379 var templ_7745c5c3_Var66 string
13761380 templ_7745c5c3_Var66, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)
13771381 if templ_7745c5c3_Err != nil {
1378- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 252, Col: 49}
1382+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 253, Col: 49}
13791383 }
13801384 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var66)
13811385 if templ_7745c5c3_Err != nil {
@@ -1388,7 +1392,7 @@ func commentView(c CommentView, suffix string) templ.Component {
13881392 var templ_7745c5c3_Var67 string
13891393 templ_7745c5c3_Var67, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.Abs)
13901394 if templ_7745c5c3_Err != nil {
1391- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 252, Col: 65}
1395+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 253, Col: 65}
13921396 }
13931397 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var67)
13941398 if templ_7745c5c3_Err != nil {
@@ -1401,7 +1405,7 @@ func commentView(c CommentView, suffix string) templ.Component {
14011405 var templ_7745c5c3_Var68 string
14021406 templ_7745c5c3_Var68, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)
14031407 if templ_7745c5c3_Err != nil {
1404- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 252, Col: 76}
1408+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 253, Col: 76}
14051409 }
14061410 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var68))
14071411 if templ_7745c5c3_Err != nil {
@@ -1416,7 +1420,7 @@ func commentView(c CommentView, suffix string) templ.Component {
14161420 var templ_7745c5c3_Var69 string
14171421 templ_7745c5c3_Var69, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
14181422 if templ_7745c5c3_Err != nil {
1419- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 255, Col: 9}
1423+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 256, Col: 9}
14201424 }
14211425 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var69))
14221426 if templ_7745c5c3_Err != nil {
@@ -1431,7 +1435,7 @@ func commentView(c CommentView, suffix string) templ.Component {
14311435 var templ_7745c5c3_Var70 string
14321436 templ_7745c5c3_Var70, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
14331437 if templ_7745c5c3_Err != nil {
1434- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 258, Col: 9}
1438+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 259, Col: 9}
14351439 }
14361440 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var70))
14371441 if templ_7745c5c3_Err != nil {
@@ -1446,7 +1450,7 @@ func commentView(c CommentView, suffix string) templ.Component {
14461450 var templ_7745c5c3_Var71 string
14471451 templ_7745c5c3_Var71, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
14481452 if templ_7745c5c3_Err != nil {
1449- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 261, Col: 9}
1453+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 262, Col: 9}
14501454 }
14511455 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var71))
14521456 if templ_7745c5c3_Err != nil {
@@ -1459,7 +1463,7 @@ func commentView(c CommentView, suffix string) templ.Component {
14591463 var templ_7745c5c3_Var72 string
14601464 templ_7745c5c3_Var72, templ_7745c5c3_Err = templ.JoinStringErrs(c.Where)
14611465 if templ_7745c5c3_Err != nil {
1462- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 261, Col: 47}
1466+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 262, Col: 47}
14631467 }
14641468 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var72))
14651469 if templ_7745c5c3_Err != nil {
@@ -1534,7 +1538,7 @@ func commentView(c CommentView, suffix string) templ.Component {
15341538 var templ_7745c5c3_Var73 string
15351539 templ_7745c5c3_Var73, templ_7745c5c3_Err = templ.JoinStringErrs(c.Verdict)
15361540 if templ_7745c5c3_Err != nil {
1537- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 285, Col: 36}
1541+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 286, Col: 36}
15381542 }
15391543 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var73))
15401544 if templ_7745c5c3_Err != nil {
@@ -1553,7 +1557,7 @@ func commentView(c CommentView, suffix string) templ.Component {
15531557 var templ_7745c5c3_Var74 string
15541558 templ_7745c5c3_Var74, templ_7745c5c3_Err = templ.JoinStringErrs(c.Range)
15551559 if templ_7745c5c3_Err != nil {
1556- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 288, Col: 31}
1560+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 289, Col: 31}
15571561 }
15581562 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var74))
15591563 if templ_7745c5c3_Err != nil {
@@ -1572,7 +1576,7 @@ func commentView(c CommentView, suffix string) templ.Component {
15721576 var templ_7745c5c3_Var75 string
15731577 templ_7745c5c3_Var75, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.Quote)
15741578 if templ_7745c5c3_Err != nil {
1575- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 291, Col: 65}
1579+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 292, Col: 65}
15761580 }
15771581 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var75)
15781582 if templ_7745c5c3_Err != nil {
@@ -1591,7 +1595,7 @@ func commentView(c CommentView, suffix string) templ.Component {
15911595 var templ_7745c5c3_Var76 templ.SafeURL
15921596 templ_7745c5c3_Var76, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Edit.Action))
15931597 if templ_7745c5c3_Err != nil {
1594- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 294, Col: 92}
1598+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 295, Col: 92}
15951599 }
15961600 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var76))
15971601 if templ_7745c5c3_Err != nil {
@@ -1604,7 +1608,7 @@ func commentView(c CommentView, suffix string) templ.Component {
16041608 var templ_7745c5c3_Var77 string
16051609 templ_7745c5c3_Var77, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(c.Edit.From))
16061610 if templ_7745c5c3_Err != nil {
1607- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 294, Col: 153}
1611+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 295, Col: 153}
16081612 }
16091613 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var77)
16101614 if templ_7745c5c3_Err != nil {
@@ -1617,7 +1621,7 @@ func commentView(c CommentView, suffix string) templ.Component {
16171621 var templ_7745c5c3_Var78 string
16181622 templ_7745c5c3_Var78, templ_7745c5c3_Err = templ.JoinStringErrs(c.Edit.Text)
16191623 if templ_7745c5c3_Err != nil {
1620- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 294, Col: 209}
1624+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 295, Col: 209}
16211625 }
16221626 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var78))
16231627 if templ_7745c5c3_Err != nil {
@@ -1636,7 +1640,7 @@ func commentView(c CommentView, suffix string) templ.Component {
16361640 var templ_7745c5c3_Var79 templ.SafeURL
16371641 templ_7745c5c3_Var79, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Delete.Action))
16381642 if templ_7745c5c3_Err != nil {
1639- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 297, Col: 96}
1643+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 298, Col: 96}
16401644 }
16411645 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var79))
16421646 if templ_7745c5c3_Err != nil {
@@ -1649,7 +1653,7 @@ func commentView(c CommentView, suffix string) templ.Component {
16491653 var templ_7745c5c3_Var80 string
16501654 templ_7745c5c3_Var80, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(c.Delete.From))
16511655 if templ_7745c5c3_Err != nil {
1652- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 297, Col: 159}
1656+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 298, Col: 159}
16531657 }
16541658 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var80)
16551659 if templ_7745c5c3_Err != nil {
@@ -1688,7 +1692,7 @@ func commentView(c CommentView, suffix string) templ.Component {
16881692 var templ_7745c5c3_Var81 templ.SafeURL
16891693 templ_7745c5c3_Var81, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Resolve.Action))
16901694 if templ_7745c5c3_Err != nil {
1691- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 308, Col: 77}
1695+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 309, Col: 77}
16921696 }
16931697 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var81))
16941698 if templ_7745c5c3_Err != nil {
@@ -1701,7 +1705,7 @@ func commentView(c CommentView, suffix string) templ.Component {
17011705 var templ_7745c5c3_Var82 string
17021706 templ_7745c5c3_Var82, templ_7745c5c3_Err = templ.ResolveAttributeValue(boolText(c.Resolve.Value))
17031707 if templ_7745c5c3_Err != nil {
1704- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 309, Col: 74}
1708+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 310, Col: 74}
17051709 }
17061710 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var82)
17071711 if templ_7745c5c3_Err != nil {
@@ -1719,7 +1723,7 @@ func commentView(c CommentView, suffix string) templ.Component {
17191723 var templ_7745c5c3_Var83 string
17201724 templ_7745c5c3_Var83, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(c.Resolve.From))
17211725 if templ_7745c5c3_Err != nil {
1722- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 311, Col: 66}
1726+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 312, Col: 66}
17231727 }
17241728 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var83)
17251729 if templ_7745c5c3_Err != nil {
@@ -1737,7 +1741,7 @@ func commentView(c CommentView, suffix string) templ.Component {
17371741 var templ_7745c5c3_Var84 string
17381742 templ_7745c5c3_Var84, templ_7745c5c3_Err = templ.JoinStringErrs(c.Resolve.Label)
17391743 if templ_7745c5c3_Err != nil {
1740- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 313, Col: 55}
1744+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 314, Col: 55}
17411745 }
17421746 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var84))
17431747 if templ_7745c5c3_Err != nil {
@@ -1792,7 +1796,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
17921796 var templ_7745c5c3_Var86 templ.SafeURL
17931797 templ_7745c5c3_Var86, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(f.Action))
17941798 if templ_7745c5c3_Err != nil {
1795- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 328, Col: 67}
1799+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 329, Col: 67}
17961800 }
17971801 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var86))
17981802 if templ_7745c5c3_Err != nil {
@@ -1805,7 +1809,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
18051809 var templ_7745c5c3_Var87 string
18061810 templ_7745c5c3_Var87, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID + suffix)
18071811 if templ_7745c5c3_Err != nil {
1808- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 329, Col: 28}
1812+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 330, Col: 28}
18091813 }
18101814 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var87)
18111815 if templ_7745c5c3_Err != nil {
@@ -1818,7 +1822,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
18181822 var templ_7745c5c3_Var88 string
18191823 templ_7745c5c3_Var88, templ_7745c5c3_Err = templ.JoinStringErrs(f.Title)
18201824 if templ_7745c5c3_Err != nil {
1821- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 329, Col: 40}
1825+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 330, Col: 40}
18221826 }
18231827 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var88))
18241828 if templ_7745c5c3_Err != nil {
@@ -1831,7 +1835,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
18311835 var templ_7745c5c3_Var89 string
18321836 templ_7745c5c3_Var89, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID + suffix)
18331837 if templ_7745c5c3_Err != nil {
1834- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 331, Col: 21}
1838+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 332, Col: 21}
18351839 }
18361840 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var89)
18371841 if templ_7745c5c3_Err != nil {
@@ -1870,7 +1874,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
18701874 var templ_7745c5c3_Var90 string
18711875 templ_7745c5c3_Var90, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Path)
18721876 if templ_7745c5c3_Err != nil {
1873- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 346, Col: 50}
1877+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 347, Col: 50}
18741878 }
18751879 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var90)
18761880 if templ_7745c5c3_Err != nil {
@@ -1883,7 +1887,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
18831887 var templ_7745c5c3_Var91 string
18841888 templ_7745c5c3_Var91, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Line)
18851889 if templ_7745c5c3_Err != nil {
1886- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 347, Col: 50}
1890+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 348, Col: 50}
18871891 }
18881892 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var91)
18891893 if templ_7745c5c3_Err != nil {
@@ -1896,7 +1900,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
18961900 var templ_7745c5c3_Var92 string
18971901 templ_7745c5c3_Var92, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Side)
18981902 if templ_7745c5c3_Err != nil {
1899- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 348, Col: 50}
1903+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 349, Col: 50}
19001904 }
19011905 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var92)
19021906 if templ_7745c5c3_Err != nil {
@@ -1909,7 +1913,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
19091913 var templ_7745c5c3_Var93 string
19101914 templ_7745c5c3_Var93, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.StartLine)
19111915 if templ_7745c5c3_Err != nil {
1912- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 349, Col: 86}
1916+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 350, Col: 86}
19131917 }
19141918 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var93)
19151919 if templ_7745c5c3_Err != nil {
@@ -1928,7 +1932,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
19281932 var templ_7745c5c3_Var94 string
19291933 templ_7745c5c3_Var94, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ReplyTo)
19301934 if templ_7745c5c3_Err != nil {
1931- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 352, Col: 57}
1935+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 353, Col: 57}
19321936 }
19331937 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var94)
19341938 if templ_7745c5c3_Err != nil {
@@ -1953,7 +1957,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
19531957 var templ_7745c5c3_Var95 string
19541958 templ_7745c5c3_Var95, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(f.From))
19551959 if templ_7745c5c3_Err != nil {
1956- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 358, Col: 56}
1960+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 359, Col: 56}
19571961 }
19581962 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var95)
19591963 if templ_7745c5c3_Err != nil {
@@ -1976,7 +1980,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
19761980 var templ_7745c5c3_Var96 templ.SafeURL
19771981 templ_7745c5c3_Var96, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(f.Cancel))
19781982 if templ_7745c5c3_Err != nil {
1979- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 363, Col: 49}
1983+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 364, Col: 49}
19801984 }
19811985 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var96))
19821986 if templ_7745c5c3_Err != nil {
@@ -1995,7 +1999,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
19951999 })
19962000 }
19972001
1998-func mrRail(p MRPage) templ.Component {
2002+func mrFooter(p MRPage) templ.Component {
19992003 return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
20002004 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
20012005 if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -2016,312 +2020,349 @@ func mrRail(p MRPage) templ.Component {
20162020 templ_7745c5c3_Var97 = templ.NopComponent
20172021 }
20182022 ctx = templ.ClearChildren(ctx)
2019- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 185, "<section aria-labelledby=\"r-files\" class=\"r-files\"><h2 id=\"r-files\">Files <span class=\"count\">")
2023+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 185, "<footer class=\"mr-footer\"><details id=\"mr-panels\"><summary>Commits <span class=\"count\">")
20202024 if templ_7745c5c3_Err != nil {
20212025 return templ_7745c5c3_Err
20222026 }
20232027 var templ_7745c5c3_Var98 string
2024- templ_7745c5c3_Var98, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))
2028+ templ_7745c5c3_Var98, templ_7745c5c3_Err = templ.JoinStringErrs(p.CommitCount)
20252029 if templ_7745c5c3_Err != nil {
2026- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 372, Col: 49}
2030+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 373, Col: 55}
20272031 }
20282032 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var98))
20292033 if templ_7745c5c3_Err != nil {
20302034 return templ_7745c5c3_Err
20312035 }
2032- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 186, "</span><kbd aria-hidden=\"true\">g f</kbd> <button type=\"button\" class=\"btn icon fold\" data-js aria-expanded=\"true\" title=\"fold the list of files\" hx-on:click=\"ermiteMR.foldFiles()\"><span class=\"ico i-chevron\" aria-hidden=\"true\"></span><span class=\"sr\">fold the list of files</span></button></h2>")
2036+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 186, "</span> · Checks</summary><nav data-mr-tabs aria-label=\"Branch details\"><a id=\"mr-tab-commits\" href=\"#mr-commits\">Commits <span class=\"count\">")
20332037 if templ_7745c5c3_Err != nil {
20342038 return templ_7745c5c3_Err
20352039 }
2036- templ_7745c5c3_Err = FileList(p.Files).Render(ctx, templ_7745c5c3_Buffer)
2040+ var templ_7745c5c3_Var99 string
2041+ templ_7745c5c3_Var99, templ_7745c5c3_Err = templ.JoinStringErrs(p.CommitCount)
20372042 if templ_7745c5c3_Err != nil {
2038- return templ_7745c5c3_Err
2043+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 375, Col: 89}
20392044 }
2040- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 187, "</section>")
2045+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var99))
20412046 if templ_7745c5c3_Err != nil {
20422047 return templ_7745c5c3_Err
20432048 }
2044- if len(p.Verdicts) > 0 {
2045- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 188, "<section><h2>Verdicts</h2><ul>")
2046- if templ_7745c5c3_Err != nil {
2047- return templ_7745c5c3_Err
2048- }
2049- for _, v := range p.Verdicts {
2050- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 189, "<li><a href=\"")
2051- if templ_7745c5c3_Err != nil {
2052- return templ_7745c5c3_Err
2053- }
2054- var templ_7745c5c3_Var99 templ.SafeURL
2055- templ_7745c5c3_Var99, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(v.Href))
2056- if templ_7745c5c3_Err != nil {
2057- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 385, Col: 37}
2058- }
2059- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var99))
2060- if templ_7745c5c3_Err != nil {
2061- return templ_7745c5c3_Err
2062- }
2063- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 190, "\">")
2064- if templ_7745c5c3_Err != nil {
2065- return templ_7745c5c3_Err
2066- }
2067- var templ_7745c5c3_Var100 string
2068- templ_7745c5c3_Var100, templ_7745c5c3_Err = templ.JoinStringErrs(v.Author)
2069- if templ_7745c5c3_Err != nil {
2070- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 385, Col: 50}
2071- }
2072- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var100))
2073- if templ_7745c5c3_Err != nil {
2074- return templ_7745c5c3_Err
2075- }
2076- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 191, ": ")
2077- if templ_7745c5c3_Err != nil {
2078- return templ_7745c5c3_Err
2079- }
2080- var templ_7745c5c3_Var101 string
2081- templ_7745c5c3_Var101, templ_7745c5c3_Err = templ.JoinStringErrs(v.Label)
2082- if templ_7745c5c3_Err != nil {
2083- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 385, Col: 63}
2084- }
2085- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var101))
2086- if templ_7745c5c3_Err != nil {
2087- return templ_7745c5c3_Err
2088- }
2089- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 192, "</a> ")
2090- if templ_7745c5c3_Err != nil {
2091- return templ_7745c5c3_Err
2092- }
2093- if v.Stale {
2094- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 193, "<span class=\"mute\">(stale)</span>")
2095- if templ_7745c5c3_Err != nil {
2096- return templ_7745c5c3_Err
2097- }
2098- }
2099- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 194, "</li>")
2100- if templ_7745c5c3_Err != nil {
2101- return templ_7745c5c3_Err
2102- }
2103- }
2104- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 195, "</ul></section>")
2105- if templ_7745c5c3_Err != nil {
2106- return templ_7745c5c3_Err
2107- }
2108- }
2109- templ_7745c5c3_Err = MRChecks(p.Checks).Render(ctx, templ_7745c5c3_Buffer)
2049+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 187, "</span></a> <a id=\"mr-tab-checks\" href=\"#mr-checks\">")
21102050 if templ_7745c5c3_Err != nil {
21112051 return templ_7745c5c3_Err
21122052 }
2113- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 196, "<section aria-labelledby=\"r-commits\"><h2 id=\"r-commits\">Commits <span class=\"count\">")
2053+ var templ_7745c5c3_Var100 string
2054+ templ_7745c5c3_Var100, templ_7745c5c3_Err = templ.JoinStringErrs("Checks ")
21142055 if templ_7745c5c3_Err != nil {
2115- return templ_7745c5c3_Err
2056+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 377, Col: 16}
21162057 }
2117- var templ_7745c5c3_Var102 string
2118- templ_7745c5c3_Var102, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Commits)))
2058+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var100))
21192059 if templ_7745c5c3_Err != nil {
2120- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 396, Col: 71}
2060+ return templ_7745c5c3_Err
21212061 }
2122- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var102))
2062+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 188, " <span data-checks-label>")
21232063 if templ_7745c5c3_Err != nil {
21242064 return templ_7745c5c3_Err
21252065 }
2126- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 197, "</span></h2><ul class=\"pcommits\">")
2066+ if p.ChecksSum.Total > 0 {
2067+ var templ_7745c5c3_Var101 string
2068+ templ_7745c5c3_Var101, templ_7745c5c3_Err = templ.JoinStringErrs(p.ChecksSum.Title)
2069+ if templ_7745c5c3_Err != nil {
2070+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 380, Col: 26}
2071+ }
2072+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var101))
2073+ if templ_7745c5c3_Err != nil {
2074+ return templ_7745c5c3_Err
2075+ }
2076+ } else {
2077+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 189, "no checks")
2078+ if templ_7745c5c3_Err != nil {
2079+ return templ_7745c5c3_Err
2080+ }
2081+ }
2082+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 190, "</span></a></nav><div id=\"mr-commits\" data-mr-panel aria-labelledby=\"mr-tab-commits\"><table class=\"mr-commits\"><thead><tr><th>Commit</th><th>Subject</th><th>Author</th><th>Date</th><th>Signature</th><th>Status</th></tr></thead> <tbody>")
21272083 if templ_7745c5c3_Err != nil {
21282084 return templ_7745c5c3_Err
21292085 }
21302086 for _, c := range p.Commits {
2131- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 198, "<li")
2087+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 191, "<tr")
21322088 if templ_7745c5c3_Err != nil {
21332089 return templ_7745c5c3_Err
21342090 }
21352091 if c.New {
2136- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 199, " data-new")
2092+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 192, " data-new")
21372093 if templ_7745c5c3_Err != nil {
21382094 return templ_7745c5c3_Err
21392095 }
21402096 }
2141- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 200, "><a href=\"")
2097+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 193, "><td><a href=\"")
21422098 if templ_7745c5c3_Err != nil {
21432099 return templ_7745c5c3_Err
21442100 }
2145- var templ_7745c5c3_Var103 templ.SafeURL
2146- templ_7745c5c3_Var103, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Href))
2101+ var templ_7745c5c3_Var102 templ.SafeURL
2102+ templ_7745c5c3_Var102, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Href))
21472103 if templ_7745c5c3_Err != nil {
2148- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 400, Col: 36}
2104+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 393, Col: 43}
21492105 }
2150- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var103))
2106+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var102))
21512107 if templ_7745c5c3_Err != nil {
21522108 return templ_7745c5c3_Err
21532109 }
2154- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 201, "\">")
2110+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 194, "\">")
21552111 if templ_7745c5c3_Err != nil {
21562112 return templ_7745c5c3_Err
21572113 }
2158- var templ_7745c5c3_Var104 string
2159- templ_7745c5c3_Var104, templ_7745c5c3_Err = templ.JoinStringErrs(c.Short)
2114+ var templ_7745c5c3_Var103 string
2115+ templ_7745c5c3_Var103, templ_7745c5c3_Err = templ.JoinStringErrs(c.Short)
21602116 if templ_7745c5c3_Err != nil {
2161- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 400, Col: 48}
2117+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 393, Col: 55}
21622118 }
2163- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var104))
2119+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var103))
21642120 if templ_7745c5c3_Err != nil {
21652121 return templ_7745c5c3_Err
21662122 }
2167- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 202, "</a> <span class=\"s\">")
2123+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 195, "</a></td><td>")
21682124 if templ_7745c5c3_Err != nil {
21692125 return templ_7745c5c3_Err
21702126 }
2171- var templ_7745c5c3_Var105 string
2172- templ_7745c5c3_Var105, templ_7745c5c3_Err = templ.JoinStringErrs(c.Subject)
2127+ var templ_7745c5c3_Var104 string
2128+ templ_7745c5c3_Var104, templ_7745c5c3_Err = templ.JoinStringErrs(c.Subject)
21732129 if templ_7745c5c3_Err != nil {
2174- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 401, Col: 32}
2130+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 394, Col: 23}
21752131 }
2176- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var105))
2132+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var104))
21772133 if templ_7745c5c3_Err != nil {
21782134 return templ_7745c5c3_Err
21792135 }
2180- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 203, "</span> ")
2136+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 196, "</td><td>")
21812137 if templ_7745c5c3_Err != nil {
21822138 return templ_7745c5c3_Err
21832139 }
2184- if c.Sig != nil {
2185- templ_7745c5c3_Err = signaturePill(c.Sig).Render(ctx, templ_7745c5c3_Buffer)
2186- if templ_7745c5c3_Err != nil {
2187- return templ_7745c5c3_Err
2188- }
2189- }
2190- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 204, "<span class=\"mute\">")
2191- if templ_7745c5c3_Err != nil {
2192- return templ_7745c5c3_Err
2193- }
2194- var templ_7745c5c3_Var106 string
2195- templ_7745c5c3_Var106, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)
2140+ var templ_7745c5c3_Var105 string
2141+ templ_7745c5c3_Var105, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)
21962142 if templ_7745c5c3_Err != nil {
2197- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 406, Col: 16}
2143+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 395, Col: 22}
21982144 }
2199- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var106))
2145+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var105))
22002146 if templ_7745c5c3_Err != nil {
22012147 return templ_7745c5c3_Err
22022148 }
2203- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 205, " ")
2149+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 197, "</td><td>")
22042150 if templ_7745c5c3_Err != nil {
22052151 return templ_7745c5c3_Err
22062152 }
22072153 if c.WhenAt != "" {
2208- var templ_7745c5c3_Var107 string
2209- templ_7745c5c3_Var107, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")
2210- if templ_7745c5c3_Err != nil {
2211- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 408, Col: 15}
2212- }
2213- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var107))
2154+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 198, "<time datetime=\"")
22142155 if templ_7745c5c3_Err != nil {
22152156 return templ_7745c5c3_Err
22162157 }
2217- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 206, "<time datetime=\"")
2158+ var templ_7745c5c3_Var106 string
2159+ templ_7745c5c3_Var106, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)
22182160 if templ_7745c5c3_Err != nil {
2219- return templ_7745c5c3_Err
2161+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 398, Col: 35}
22202162 }
2221- var templ_7745c5c3_Var108 string
2222- templ_7745c5c3_Var108, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)
2223- if templ_7745c5c3_Err != nil {
2224- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 408, Col: 42}
2225- }
2226- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var108)
2163+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var106)
22272164 if templ_7745c5c3_Err != nil {
22282165 return templ_7745c5c3_Err
22292166 }
2230- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 207, "\">")
2167+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 199, "\">")
22312168 if templ_7745c5c3_Err != nil {
22322169 return templ_7745c5c3_Err
22332170 }
2234- var templ_7745c5c3_Var109 string
2235- templ_7745c5c3_Var109, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)
2171+ var templ_7745c5c3_Var107 string
2172+ templ_7745c5c3_Var107, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)
22362173 if templ_7745c5c3_Err != nil {
2237- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 408, Col: 53}
2174+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 398, Col: 46}
22382175 }
2239- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var109))
2176+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var107))
22402177 if templ_7745c5c3_Err != nil {
22412178 return templ_7745c5c3_Err
22422179 }
2243- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 208, "</time> ")
2180+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 200, "</time>")
22442181 if templ_7745c5c3_Err != nil {
22452182 return templ_7745c5c3_Err
22462183 }
22472184 }
2248- if c.New {
2249- var templ_7745c5c3_Var110 string
2250- templ_7745c5c3_Var110, templ_7745c5c3_Err = templ.JoinStringErrs(" · new")
2185+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 201, "</td><td>")
2186+ if templ_7745c5c3_Err != nil {
2187+ return templ_7745c5c3_Err
2188+ }
2189+ if c.Sig != nil {
2190+ templ_7745c5c3_Err = signaturePill(c.Sig).Render(ctx, templ_7745c5c3_Buffer)
22512191 if templ_7745c5c3_Err != nil {
2252- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 411, Col: 18}
2192+ return templ_7745c5c3_Err
22532193 }
2254- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var110))
2194+ }
2195+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 202, "</td><td>")
2196+ if templ_7745c5c3_Err != nil {
2197+ return templ_7745c5c3_Err
2198+ }
2199+ if c.New {
2200+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 203, "<span>new</span>")
22552201 if templ_7745c5c3_Err != nil {
22562202 return templ_7745c5c3_Err
22572203 }
22582204 }
2259- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 209, "</span></li>")
2205+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 204, "</td></tr>")
22602206 if templ_7745c5c3_Err != nil {
22612207 return templ_7745c5c3_Err
22622208 }
22632209 }
2264- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 210, "</ul>")
2210+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 205, "</tbody></table>")
22652211 if templ_7745c5c3_Err != nil {
22662212 return templ_7745c5c3_Err
22672213 }
22682214 if len(p.Commits) == 0 {
2269- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 211, "<p class=\"dim\">no commit to merge.</p>")
2215+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 206, "<p class=\"dim\">no commit to merge.</p>")
22702216 if templ_7745c5c3_Err != nil {
22712217 return templ_7745c5c3_Err
22722218 }
22732219 }
22742220 if p.CommitsNote != "" {
2275- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 212, "<p class=\"note\">")
2221+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 207, "<p class=\"note\">")
22762222 if templ_7745c5c3_Err != nil {
22772223 return templ_7745c5c3_Err
22782224 }
2279- var templ_7745c5c3_Var111 string
2280- templ_7745c5c3_Var111, templ_7745c5c3_Err = templ.JoinStringErrs(p.CommitsNote)
2225+ var templ_7745c5c3_Var108 string
2226+ templ_7745c5c3_Var108, templ_7745c5c3_Err = templ.JoinStringErrs(p.CommitsNote)
22812227 if templ_7745c5c3_Err != nil {
2282- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 421, Col: 34}
2228+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 419, Col: 36}
22832229 }
2284- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var111))
2230+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var108))
22852231 if templ_7745c5c3_Err != nil {
22862232 return templ_7745c5c3_Err
22872233 }
2288- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 213, "</p>")
2234+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 208, "</p>")
22892235 if templ_7745c5c3_Err != nil {
22902236 return templ_7745c5c3_Err
22912237 }
22922238 }
2293- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 214, "</section><section aria-labelledby=\"r-settings\"><h2 id=\"r-settings\">Settings</h2><dl class=\"kv\"><dt>modes</dt><dd>")
2239+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 209, "</div><div id=\"mr-checks-panel\" data-mr-panel aria-labelledby=\"mr-tab-checks\">")
22942240 if templ_7745c5c3_Err != nil {
22952241 return templ_7745c5c3_Err
22962242 }
2297- var templ_7745c5c3_Var112 string
2298- templ_7745c5c3_Var112, templ_7745c5c3_Err = templ.JoinStringErrs(strings.Join(p.Modes, ", "))
2243+ templ_7745c5c3_Err = MRChecks(p.Checks).Render(ctx, templ_7745c5c3_Buffer)
22992244 if templ_7745c5c3_Err != nil {
2300- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 428, Col: 36}
2245+ return templ_7745c5c3_Err
2246+ }
2247+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 210, "</div></details></footer>")
2248+ if templ_7745c5c3_Err != nil {
2249+ return templ_7745c5c3_Err
2250+ }
2251+ return nil
2252+ })
2253+}
2254+
2255+func mrRail(p MRPage) templ.Component {
2256+ return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
2257+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
2258+ if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
2259+ return templ_7745c5c3_CtxErr
23012260 }
2302- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var112))
2261+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
2262+ if !templ_7745c5c3_IsBuffer {
2263+ defer func() {
2264+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
2265+ if templ_7745c5c3_Err == nil {
2266+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
2267+ }
2268+ }()
2269+ }
2270+ ctx = templ.InitializeContext(ctx)
2271+ templ_7745c5c3_Var109 := templ.GetChildren(ctx)
2272+ if templ_7745c5c3_Var109 == nil {
2273+ templ_7745c5c3_Var109 = templ.NopComponent
2274+ }
2275+ ctx = templ.ClearChildren(ctx)
2276+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 211, "<section aria-labelledby=\"r-files\" class=\"r-files\"><h2 id=\"r-files\">Files <span class=\"count\">")
23032277 if templ_7745c5c3_Err != nil {
23042278 return templ_7745c5c3_Err
23052279 }
2306- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 215, "</dd><dt>checks</dt><dd>")
2280+ var templ_7745c5c3_Var110 string
2281+ templ_7745c5c3_Var110, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))
2282+ if templ_7745c5c3_Err != nil {
2283+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 432, Col: 49}
2284+ }
2285+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var110))
23072286 if templ_7745c5c3_Err != nil {
23082287 return templ_7745c5c3_Err
23092288 }
2310- if p.ChecksBlock {
2311- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 216, "failing ones block the merge")
2289+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 212, "</span><kbd aria-hidden=\"true\">g f</kbd> <button type=\"button\" class=\"btn icon fold\" data-js aria-expanded=\"true\" title=\"fold the list of files\" hx-on:click=\"ermiteMR.foldFiles()\"><span class=\"ico i-chevron\" aria-hidden=\"true\"></span><span class=\"sr\">fold the list of files</span></button></h2>")
2290+ if templ_7745c5c3_Err != nil {
2291+ return templ_7745c5c3_Err
2292+ }
2293+ templ_7745c5c3_Err = FileList(p.Files).Render(ctx, templ_7745c5c3_Buffer)
2294+ if templ_7745c5c3_Err != nil {
2295+ return templ_7745c5c3_Err
2296+ }
2297+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 213, "</section>")
2298+ if templ_7745c5c3_Err != nil {
2299+ return templ_7745c5c3_Err
2300+ }
2301+ if len(p.Verdicts) > 0 {
2302+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 214, "<section><h2>Verdicts</h2><ul>")
23122303 if templ_7745c5c3_Err != nil {
23132304 return templ_7745c5c3_Err
23142305 }
2315- } else {
2316- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 217, "do not block the merge")
2306+ for _, v := range p.Verdicts {
2307+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 215, "<li><a href=\"")
2308+ if templ_7745c5c3_Err != nil {
2309+ return templ_7745c5c3_Err
2310+ }
2311+ var templ_7745c5c3_Var111 templ.SafeURL
2312+ templ_7745c5c3_Var111, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(v.Href))
2313+ if templ_7745c5c3_Err != nil {
2314+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 445, Col: 37}
2315+ }
2316+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var111))
2317+ if templ_7745c5c3_Err != nil {
2318+ return templ_7745c5c3_Err
2319+ }
2320+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 216, "\">")
2321+ if templ_7745c5c3_Err != nil {
2322+ return templ_7745c5c3_Err
2323+ }
2324+ var templ_7745c5c3_Var112 string
2325+ templ_7745c5c3_Var112, templ_7745c5c3_Err = templ.JoinStringErrs(v.Author)
2326+ if templ_7745c5c3_Err != nil {
2327+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 445, Col: 50}
2328+ }
2329+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var112))
2330+ if templ_7745c5c3_Err != nil {
2331+ return templ_7745c5c3_Err
2332+ }
2333+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 217, ": ")
2334+ if templ_7745c5c3_Err != nil {
2335+ return templ_7745c5c3_Err
2336+ }
2337+ var templ_7745c5c3_Var113 string
2338+ templ_7745c5c3_Var113, templ_7745c5c3_Err = templ.JoinStringErrs(v.Label)
2339+ if templ_7745c5c3_Err != nil {
2340+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 445, Col: 63}
2341+ }
2342+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var113))
2343+ if templ_7745c5c3_Err != nil {
2344+ return templ_7745c5c3_Err
2345+ }
2346+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 218, "</a> ")
2347+ if templ_7745c5c3_Err != nil {
2348+ return templ_7745c5c3_Err
2349+ }
2350+ if v.Stale {
2351+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 219, "<span class=\"mute\">(stale)</span>")
2352+ if templ_7745c5c3_Err != nil {
2353+ return templ_7745c5c3_Err
2354+ }
2355+ }
2356+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 220, "</li>")
2357+ if templ_7745c5c3_Err != nil {
2358+ return templ_7745c5c3_Err
2359+ }
2360+ }
2361+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 221, "</ul></section>")
23172362 if templ_7745c5c3_Err != nil {
23182363 return templ_7745c5c3_Err
23192364 }
23202365 }
2321- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 218, "</dd></dl></section>")
2322- if templ_7745c5c3_Err != nil {
2323- return templ_7745c5c3_Err
2324- }
23252366 return nil
23262367 })
23272368 }
@@ -2346,51 +2387,51 @@ func mrBar(p MRPage) templ.Component {
23462387 }()
23472388 }
23482389 ctx = templ.InitializeContext(ctx)
2349- templ_7745c5c3_Var113 := templ.GetChildren(ctx)
2350- if templ_7745c5c3_Var113 == nil {
2351- templ_7745c5c3_Var113 = templ.NopComponent
2390+ templ_7745c5c3_Var114 := templ.GetChildren(ctx)
2391+ if templ_7745c5c3_Var114 == nil {
2392+ templ_7745c5c3_Var114 = templ.NopComponent
23522393 }
23532394 ctx = templ.ClearChildren(ctx)
2354- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 219, "<div class=\"diff-tools mr-bar\" role=\"group\" aria-label=\"Diff view and merge\"><span class=\"dim\">")
2395+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 222, "<div class=\"diff-tools mr-bar\" role=\"group\" aria-label=\"Diff view and merge\"><span class=\"dim\">")
23552396 if templ_7745c5c3_Err != nil {
23562397 return templ_7745c5c3_Err
23572398 }
2358- var templ_7745c5c3_Var114 string
2359- templ_7745c5c3_Var114, templ_7745c5c3_Err = templ.JoinStringErrs(plural(p.NFiles, "file", "files"))
2399+ var templ_7745c5c3_Var115 string
2400+ templ_7745c5c3_Var115, templ_7745c5c3_Err = templ.JoinStringErrs(plural(p.NFiles, "file", "files"))
23602401 if templ_7745c5c3_Err != nil {
2361- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 447, Col: 55}
2402+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 462, Col: 55}
23622403 }
2363- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var114))
2404+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var115))
23642405 if templ_7745c5c3_Err != nil {
23652406 return templ_7745c5c3_Err
23662407 }
2367- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 220, " · <span class=\"plus\">+")
2408+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 223, " · <span class=\"plus\">+")
23682409 if templ_7745c5c3_Err != nil {
23692410 return templ_7745c5c3_Err
23702411 }
2371- var templ_7745c5c3_Var115 string
2372- templ_7745c5c3_Var115, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Adds))
2412+ var templ_7745c5c3_Var116 string
2413+ templ_7745c5c3_Var116, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Adds))
23732414 if templ_7745c5c3_Err != nil {
2374- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 447, Col: 95}
2415+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 462, Col: 95}
23752416 }
2376- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var115))
2417+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var116))
23772418 if templ_7745c5c3_Err != nil {
23782419 return templ_7745c5c3_Err
23792420 }
2380- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 221, "</span> <span class=\"minus\">-")
2421+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 224, "</span> <span class=\"minus\">-")
23812422 if templ_7745c5c3_Err != nil {
23822423 return templ_7745c5c3_Err
23832424 }
2384- var templ_7745c5c3_Var116 string
2385- templ_7745c5c3_Var116, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Dels))
2425+ var templ_7745c5c3_Var117 string
2426+ templ_7745c5c3_Var117, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Dels))
23862427 if templ_7745c5c3_Err != nil {
2387- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 447, Col: 140}
2428+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 462, Col: 140}
23882429 }
2389- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var116))
2430+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var117))
23902431 if templ_7745c5c3_Err != nil {
23912432 return templ_7745c5c3_Err
23922433 }
2393- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 222, "</span></span>")
2434+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 225, "</span></span>")
23942435 if templ_7745c5c3_Err != nil {
23952436 return templ_7745c5c3_Err
23962437 }
@@ -2398,7 +2439,7 @@ func mrBar(p MRPage) templ.Component {
23982439 if templ_7745c5c3_Err != nil {
23992440 return templ_7745c5c3_Err
24002441 }
2401- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 223, "<span class=\"grow\"></span>")
2442+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 226, "<span class=\"grow\"></span>")
24022443 if templ_7745c5c3_Err != nil {
24032444 return templ_7745c5c3_Err
24042445 }
@@ -2411,16 +2452,12 @@ func mrBar(p MRPage) templ.Component {
24112452 if templ_7745c5c3_Err != nil {
24122453 return templ_7745c5c3_Err
24132454 }
2414- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 224, " ")
2415- if templ_7745c5c3_Err != nil {
2416- return templ_7745c5c3_Err
2417- }
2418- templ_7745c5c3_Err = moreMenu(p).Render(ctx, templ_7745c5c3_Buffer)
2419- if templ_7745c5c3_Err != nil {
2420- return templ_7745c5c3_Err
2421- }
24222455 }
2423- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 225, "</div>")
2456+ templ_7745c5c3_Err = moreMenu(p).Render(ctx, templ_7745c5c3_Buffer)
2457+ if templ_7745c5c3_Err != nil {
2458+ return templ_7745c5c3_Err
2459+ }
2460+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 227, "</div>")
24242461 if templ_7745c5c3_Err != nil {
24252462 return templ_7745c5c3_Err
24262463 }
@@ -2452,84 +2489,57 @@ func mergeMenu(p MRPage) templ.Component {
24522489 }()
24532490 }
24542491 ctx = templ.InitializeContext(ctx)
2455- templ_7745c5c3_Var117 := templ.GetChildren(ctx)
2456- if templ_7745c5c3_Var117 == nil {
2457- templ_7745c5c3_Var117 = templ.NopComponent
2492+ templ_7745c5c3_Var118 := templ.GetChildren(ctx)
2493+ if templ_7745c5c3_Var118 == nil {
2494+ templ_7745c5c3_Var118 = templ.NopComponent
24582495 }
24592496 ctx = templ.ClearChildren(ctx)
2460- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 226, "<details class=\"menu mmenu\" id=\"merge-menu\" data-state=\"open\"")
2497+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 228, "<details class=\"menu mmenu\" id=\"merge-menu\" data-state=\"open\"")
24612498 if templ_7745c5c3_Err != nil {
24622499 return templ_7745c5c3_Err
24632500 }
24642501 if p.Box.Error != "" {
2465- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 227, " open")
2502+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 229, " open")
24662503 if templ_7745c5c3_Err != nil {
24672504 return templ_7745c5c3_Err
24682505 }
24692506 }
2470- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 228, "><summary class=\"btn primary\" aria-keyshortcuts=\"Shift+M\">")
2507+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 230, "><summary class=\"btn primary\" aria-keyshortcuts=\"Shift+M\">")
24712508 if templ_7745c5c3_Err != nil {
24722509 return templ_7745c5c3_Err
24732510 }
24742511 if p.Box.ReadyAction != "" {
2475- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 229, "Draft ")
2512+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 231, "Draft ")
24762513 if templ_7745c5c3_Err != nil {
24772514 return templ_7745c5c3_Err
24782515 }
24792516 } else {
2480- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 230, "Merge ")
2517+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 232, "Merge ")
24812518 if templ_7745c5c3_Err != nil {
24822519 return templ_7745c5c3_Err
24832520 }
24842521 }
2485- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 231, "<kbd aria-hidden=\"true\">M</kbd></summary><div class=\"menu-pop\" role=\"group\" aria-label=\"Merge\"><dl class=\"kv\"><dt>head</dt><dd>")
2522+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 233, "<kbd aria-hidden=\"true\">M</kbd></summary><div class=\"menu-pop\" role=\"group\" aria-label=\"Merge\">")
24862523 if templ_7745c5c3_Err != nil {
24872524 return templ_7745c5c3_Err
24882525 }
24892526 if p.Box.HeadGone {
2490- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 232, "gone: the source branch was deleted")
2491- if templ_7745c5c3_Err != nil {
2492- return templ_7745c5c3_Err
2493- }
2494- } else {
2495- var templ_7745c5c3_Var118 string
2496- templ_7745c5c3_Var118, templ_7745c5c3_Err = templ.JoinStringErrs(p.HeadShort)
2497- if templ_7745c5c3_Err != nil {
2498- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 483, Col: 19}
2499- }
2500- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var118))
2527+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 234, "<p class=\"dim\">the source branch was deleted</p>")
25012528 if templ_7745c5c3_Err != nil {
25022529 return templ_7745c5c3_Err
25032530 }
25042531 }
2505- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 233, "</dd><dt>into</dt><dd>")
2506- if templ_7745c5c3_Err != nil {
2507- return templ_7745c5c3_Err
2508- }
2509- var templ_7745c5c3_Var119 string
2510- templ_7745c5c3_Var119, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
2511- if templ_7745c5c3_Err != nil {
2512- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 487, Col: 18}
2513- }
2514- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var119))
2515- if templ_7745c5c3_Err != nil {
2516- return templ_7745c5c3_Err
2517- }
2518- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 234, "</dd></dl>")
2519- if templ_7745c5c3_Err != nil {
2520- return templ_7745c5c3_Err
2521- }
25222532 if p.Box.Error != "" {
25232533 templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 235, "<p class=\"d-err\" role=\"alert\">")
25242534 if templ_7745c5c3_Err != nil {
25252535 return templ_7745c5c3_Err
25262536 }
2527- var templ_7745c5c3_Var120 string
2528- templ_7745c5c3_Var120, templ_7745c5c3_Err = templ.JoinStringErrs(p.Box.Error)
2537+ var templ_7745c5c3_Var119 string
2538+ templ_7745c5c3_Var119, templ_7745c5c3_Err = templ.JoinStringErrs(p.Box.Error)
25292539 if templ_7745c5c3_Err != nil {
2530- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 490, Col: 47}
2540+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 496, Col: 47}
25312541 }
2532- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var120))
2542+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var119))
25332543 if templ_7745c5c3_Err != nil {
25342544 return templ_7745c5c3_Err
25352545 }
@@ -2543,12 +2553,12 @@ func mergeMenu(p MRPage) templ.Component {
25432553 if templ_7745c5c3_Err != nil {
25442554 return templ_7745c5c3_Err
25452555 }
2546- var templ_7745c5c3_Var121 templ.SafeURL
2547- templ_7745c5c3_Var121, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.ReadyAction))
2556+ var templ_7745c5c3_Var120 templ.SafeURL
2557+ templ_7745c5c3_Var120, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.ReadyAction))
25482558 if templ_7745c5c3_Err != nil {
2549- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 494, Col: 80}
2559+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 500, Col: 80}
25502560 }
2551- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var121))
2561+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var120))
25522562 if templ_7745c5c3_Err != nil {
25532563 return templ_7745c5c3_Err
25542564 }
@@ -2565,12 +2575,12 @@ func mergeMenu(p MRPage) templ.Component {
25652575 if templ_7745c5c3_Err != nil {
25662576 return templ_7745c5c3_Err
25672577 }
2568- var templ_7745c5c3_Var122 templ.SafeURL
2569- templ_7745c5c3_Var122, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.MergeAction))
2578+ var templ_7745c5c3_Var121 templ.SafeURL
2579+ templ_7745c5c3_Var121, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.MergeAction))
25702580 if templ_7745c5c3_Err != nil {
2571- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 499, Col: 80}
2581+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 505, Col: 80}
25722582 }
2573- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var122))
2583+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var121))
25742584 if templ_7745c5c3_Err != nil {
25752585 return templ_7745c5c3_Err
25762586 }
@@ -2578,12 +2588,12 @@ func mergeMenu(p MRPage) templ.Component {
25782588 if templ_7745c5c3_Err != nil {
25792589 return templ_7745c5c3_Err
25802590 }
2581- var templ_7745c5c3_Var123 string
2582- templ_7745c5c3_Var123, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.Head)
2591+ var templ_7745c5c3_Var122 string
2592+ templ_7745c5c3_Var122, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.Head)
25832593 if templ_7745c5c3_Err != nil {
2584- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 500, Col: 59}
2594+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 506, Col: 59}
25852595 }
2586- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var123)
2596+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var122)
25872597 if templ_7745c5c3_Err != nil {
25882598 return templ_7745c5c3_Err
25892599 }
@@ -2596,12 +2606,12 @@ func mergeMenu(p MRPage) templ.Component {
25962606 if templ_7745c5c3_Err != nil {
25972607 return templ_7745c5c3_Err
25982608 }
2599- var templ_7745c5c3_Var124 string
2600- templ_7745c5c3_Var124, templ_7745c5c3_Err = templ.ResolveAttributeValue(m.Value)
2609+ var templ_7745c5c3_Var123 string
2610+ templ_7745c5c3_Var123, templ_7745c5c3_Err = templ.ResolveAttributeValue(m.Value)
26012611 if templ_7745c5c3_Err != nil {
2602- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 508, Col: 24}
2612+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 514, Col: 24}
26032613 }
2604- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var124)
2614+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var123)
26052615 if templ_7745c5c3_Err != nil {
26062616 return templ_7745c5c3_Err
26072617 }
@@ -2625,12 +2635,12 @@ func mergeMenu(p MRPage) templ.Component {
26252635 if templ_7745c5c3_Err != nil {
26262636 return templ_7745c5c3_Err
26272637 }
2628- var templ_7745c5c3_Var125 string
2629- templ_7745c5c3_Var125, templ_7745c5c3_Err = templ.ResolveAttributeValue(m.Reason)
2638+ var templ_7745c5c3_Var124 string
2639+ templ_7745c5c3_Var124, templ_7745c5c3_Err = templ.ResolveAttributeValue(m.Reason)
26302640 if templ_7745c5c3_Err != nil {
2631- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 511, Col: 25}
2641+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 517, Col: 25}
26322642 }
2633- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var125)
2643+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var124)
26342644 if templ_7745c5c3_Err != nil {
26352645 return templ_7745c5c3_Err
26362646 }
@@ -2638,12 +2648,12 @@ func mergeMenu(p MRPage) templ.Component {
26382648 if templ_7745c5c3_Err != nil {
26392649 return templ_7745c5c3_Err
26402650 }
2641- var templ_7745c5c3_Var126 string
2642- templ_7745c5c3_Var126, templ_7745c5c3_Err = templ.JoinStringErrs(m.Label)
2651+ var templ_7745c5c3_Var125 string
2652+ templ_7745c5c3_Var125, templ_7745c5c3_Err = templ.JoinStringErrs(m.Label)
26432653 if templ_7745c5c3_Err != nil {
2644- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 515, Col: 17}
2654+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 521, Col: 17}
26452655 }
2646- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var126))
2656+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var125))
26472657 if templ_7745c5c3_Err != nil {
26482658 return templ_7745c5c3_Err
26492659 }
@@ -2656,12 +2666,12 @@ func mergeMenu(p MRPage) templ.Component {
26562666 if templ_7745c5c3_Err != nil {
26572667 return templ_7745c5c3_Err
26582668 }
2659- var templ_7745c5c3_Var127 string
2660- templ_7745c5c3_Var127, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(i + 1))
2669+ var templ_7745c5c3_Var126 string
2670+ templ_7745c5c3_Var126, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(i + 1))
26612671 if templ_7745c5c3_Err != nil {
2662- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 517, Col: 46}
2672+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 523, Col: 46}
26632673 }
2664- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var127))
2674+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var126))
26652675 if templ_7745c5c3_Err != nil {
26662676 return templ_7745c5c3_Err
26672677 }
@@ -2679,96 +2689,67 @@ func mergeMenu(p MRPage) templ.Component {
26792689 if templ_7745c5c3_Err != nil {
26802690 return templ_7745c5c3_Err
26812691 }
2682- if p.Box.Signed {
2683- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 253, "<p class=\"d-note\" id=\"mr-signing\">squash and merge commits are signed with ermite's own key (generated on first start). ")
2684- if templ_7745c5c3_Err != nil {
2685- return templ_7745c5c3_Err
2686- }
2687- if p.Box.Fingerprint != "" {
2688- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 254, "fingerprint <code>")
2689- if templ_7745c5c3_Err != nil {
2690- return templ_7745c5c3_Err
2691- }
2692- var templ_7745c5c3_Var128 string
2693- templ_7745c5c3_Var128, templ_7745c5c3_Err = templ.JoinStringErrs(p.Box.Fingerprint)
2694- if templ_7745c5c3_Err != nil {
2695- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 526, Col: 45}
2696- }
2697- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var128))
2698- if templ_7745c5c3_Err != nil {
2699- return templ_7745c5c3_Err
2700- }
2701- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 255, "</code> ")
2702- if templ_7745c5c3_Err != nil {
2703- return templ_7745c5c3_Err
2704- }
2705- }
2706- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 256, "<code>ermite signing-key show</code> prints it.</p>")
2707- if templ_7745c5c3_Err != nil {
2708- return templ_7745c5c3_Err
2709- }
2710- }
27112692 if p.Box.CanDeleteBranch {
2712- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 257, "<label class=\"d-check\"><input type=\"checkbox\" name=\"delete_branch\" value=\"1\"> delete ")
2693+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 253, "<label class=\"d-check\"><input type=\"checkbox\" name=\"delete_branch\" value=\"1\"> delete ")
27132694 if templ_7745c5c3_Err != nil {
27142695 return templ_7745c5c3_Err
27152696 }
2716- var templ_7745c5c3_Var129 string
2717- templ_7745c5c3_Var129, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)
2697+ var templ_7745c5c3_Var127 string
2698+ templ_7745c5c3_Var127, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)
27182699 if templ_7745c5c3_Err != nil {
2719- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 532, Col: 102}
2700+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 529, Col: 102}
27202701 }
2721- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var129))
2702+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var127))
27222703 if templ_7745c5c3_Err != nil {
27232704 return templ_7745c5c3_Err
27242705 }
2725- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 258, " after the merge <kbd aria-hidden=\"true\">D</kbd></label>")
2706+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 254, " after the merge <kbd aria-hidden=\"true\">D</kbd></label>")
27262707 if templ_7745c5c3_Err != nil {
27272708 return templ_7745c5c3_Err
27282709 }
27292710 }
2730- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 259, "<div class=\"d-btns\"><button type=\"submit\" class=\"btn primary\" data-default")
2711+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 255, "<div class=\"d-btns\"><button type=\"submit\" class=\"btn primary\" data-default")
27312712 if templ_7745c5c3_Err != nil {
27322713 return templ_7745c5c3_Err
27332714 }
27342715 if !p.Box.CanMerge() {
2735- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 260, " disabled")
2716+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 256, " disabled")
27362717 if templ_7745c5c3_Err != nil {
27372718 return templ_7745c5c3_Err
27382719 }
27392720 }
2740- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 261, " title=\"")
2721+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 257, " title=\"")
27412722 if templ_7745c5c3_Err != nil {
27422723 return templ_7745c5c3_Err
27432724 }
2744- var templ_7745c5c3_Var130 string
2745- templ_7745c5c3_Var130, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.MergeTitle())
2725+ var templ_7745c5c3_Var128 string
2726+ templ_7745c5c3_Var128, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.MergeTitle())
27462727 if templ_7745c5c3_Err != nil {
2747- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 540, Col: 33}
2728+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 537, Col: 33}
27482729 }
2749- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var130)
2730+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var128)
27502731 if templ_7745c5c3_Err != nil {
27512732 return templ_7745c5c3_Err
27522733 }
2753- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 262, "\" :disabled=\"!this.form.querySelector('input[name=mode]:checked:not(:disabled)')\" :title=\"(this.form.querySelector('input[name=mode]:checked') || {}).title || ''\">Merge into ")
2734+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 258, "\" :disabled=\"!this.form.querySelector('input[name=mode]:checked:not(:disabled)')\" :title=\"(this.form.querySelector('input[name=mode]:checked') || {}).title || ''\">Merge into ")
27542735 if templ_7745c5c3_Err != nil {
27552736 return templ_7745c5c3_Err
27562737 }
2757- var templ_7745c5c3_Var131 string
2758- templ_7745c5c3_Var131, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
2738+ var templ_7745c5c3_Var129 string
2739+ templ_7745c5c3_Var129, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
27592740 if templ_7745c5c3_Err != nil {
2760- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 543, Col: 28}
2741+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 540, Col: 28}
27612742 }
2762- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var131))
2743+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var129))
27632744 if templ_7745c5c3_Err != nil {
27642745 return templ_7745c5c3_Err
27652746 }
2766- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 263, "</button></div></form>")
2747+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 259, "</button></div></form>")
27672748 if templ_7745c5c3_Err != nil {
27682749 return templ_7745c5c3_Err
27692750 }
27702751 }
2771- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 264, "</div></details>")
2752+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 260, "</div></details>")
27722753 if templ_7745c5c3_Err != nil {
27732754 return templ_7745c5c3_Err
27742755 }
@@ -2794,182 +2775,182 @@ func MRMergeability(v MergeabilityView) templ.Component {
27942775 }()
27952776 }
27962777 ctx = templ.InitializeContext(ctx)
2797- templ_7745c5c3_Var132 := templ.GetChildren(ctx)
2798- if templ_7745c5c3_Var132 == nil {
2799- templ_7745c5c3_Var132 = templ.NopComponent
2778+ templ_7745c5c3_Var130 := templ.GetChildren(ctx)
2779+ if templ_7745c5c3_Var130 == nil {
2780+ templ_7745c5c3_Var130 = templ.NopComponent
28002781 }
28012782 ctx = templ.ClearChildren(ctx)
2802- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 265, "<span data-mergeability data-state=\"")
2783+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 261, "<span data-mergeability data-state=\"")
28032784 if templ_7745c5c3_Err != nil {
28042785 return templ_7745c5c3_Err
28052786 }
2806- var templ_7745c5c3_Var133 string
2807- templ_7745c5c3_Var133, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.State)
2787+ var templ_7745c5c3_Var131 string
2788+ templ_7745c5c3_Var131, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.State)
28082789 if templ_7745c5c3_Err != nil {
2809- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 556, Col: 22}
2790+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 553, Col: 22}
28102791 }
2811- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var133)
2792+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var131)
28122793 if templ_7745c5c3_Err != nil {
28132794 return templ_7745c5c3_Err
28142795 }
2815- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 266, "\" data-ff-ok=\"")
2796+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 262, "\" data-ff-ok=\"")
28162797 if templ_7745c5c3_Err != nil {
28172798 return templ_7745c5c3_Err
28182799 }
2819- var templ_7745c5c3_Var134 string
2820- templ_7745c5c3_Var134, templ_7745c5c3_Err = templ.ResolveAttributeValue(strconv.FormatBool(v.FFOk))
2800+ var templ_7745c5c3_Var132 string
2801+ templ_7745c5c3_Var132, templ_7745c5c3_Err = templ.ResolveAttributeValue(strconv.FormatBool(v.FFOk))
28212802 if templ_7745c5c3_Err != nil {
2822- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 557, Col: 41}
2803+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 554, Col: 41}
28232804 }
2824- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var134)
2805+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var132)
28252806 if templ_7745c5c3_Err != nil {
28262807 return templ_7745c5c3_Err
28272808 }
2828- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 267, "\" data-merge-ok=\"")
2809+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 263, "\" data-merge-ok=\"")
28292810 if templ_7745c5c3_Err != nil {
28302811 return templ_7745c5c3_Err
28312812 }
2832- var templ_7745c5c3_Var135 string
2833- templ_7745c5c3_Var135, templ_7745c5c3_Err = templ.ResolveAttributeValue(strconv.FormatBool(v.MergeOk))
2813+ var templ_7745c5c3_Var133 string
2814+ templ_7745c5c3_Var133, templ_7745c5c3_Err = templ.ResolveAttributeValue(strconv.FormatBool(v.MergeOk))
28342815 if templ_7745c5c3_Err != nil {
2835- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 558, Col: 47}
2816+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 555, Col: 47}
28362817 }
2837- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var135)
2818+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var133)
28382819 if templ_7745c5c3_Err != nil {
28392820 return templ_7745c5c3_Err
28402821 }
2841- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 268, "\" data-ff-reason=\"")
2822+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 264, "\" data-ff-reason=\"")
28422823 if templ_7745c5c3_Err != nil {
28432824 return templ_7745c5c3_Err
28442825 }
2845- var templ_7745c5c3_Var136 string
2846- templ_7745c5c3_Var136, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.FFReason)
2826+ var templ_7745c5c3_Var134 string
2827+ templ_7745c5c3_Var134, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.FFReason)
28472828 if templ_7745c5c3_Err != nil {
2848- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 559, Col: 29}
2829+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 556, Col: 29}
28492830 }
2850- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var136)
2831+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var134)
28512832 if templ_7745c5c3_Err != nil {
28522833 return templ_7745c5c3_Err
28532834 }
2854- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 269, "\" data-merge-reason=\"")
2835+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 265, "\" data-merge-reason=\"")
28552836 if templ_7745c5c3_Err != nil {
28562837 return templ_7745c5c3_Err
28572838 }
2858- var templ_7745c5c3_Var137 string
2859- templ_7745c5c3_Var137, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.MergeReason)
2839+ var templ_7745c5c3_Var135 string
2840+ templ_7745c5c3_Var135, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.MergeReason)
28602841 if templ_7745c5c3_Err != nil {
2861- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 560, Col: 35}
2842+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 557, Col: 35}
28622843 }
2863- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var137)
2844+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var135)
28642845 if templ_7745c5c3_Err != nil {
28652846 return templ_7745c5c3_Err
28662847 }
2867- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 270, "\"><span class=\"badge\" data-state=\"")
2848+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 266, "\"><span class=\"badge\" data-state=\"")
28682849 if templ_7745c5c3_Err != nil {
28692850 return templ_7745c5c3_Err
28702851 }
2871- var templ_7745c5c3_Var138 string
2872- templ_7745c5c3_Var138, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.State)
2852+ var templ_7745c5c3_Var136 string
2853+ templ_7745c5c3_Var136, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.State)
28732854 if templ_7745c5c3_Err != nil {
2874- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 562, Col: 42}
2855+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 559, Col: 42}
28752856 }
2876- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var138)
2857+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var136)
28772858 if templ_7745c5c3_Err != nil {
28782859 return templ_7745c5c3_Err
28792860 }
2880- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 271, "\">")
2861+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 267, "\">")
28812862 if templ_7745c5c3_Err != nil {
28822863 return templ_7745c5c3_Err
28832864 }
2884- var templ_7745c5c3_Var139 string
2885- templ_7745c5c3_Var139, templ_7745c5c3_Err = templ.JoinStringErrs(v.Label)
2865+ var templ_7745c5c3_Var137 string
2866+ templ_7745c5c3_Var137, templ_7745c5c3_Err = templ.JoinStringErrs(v.Label)
28862867 if templ_7745c5c3_Err != nil {
2887- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 562, Col: 54}
2868+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 559, Col: 54}
28882869 }
2889- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var139))
2870+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var137))
28902871 if templ_7745c5c3_Err != nil {
28912872 return templ_7745c5c3_Err
28922873 }
2893- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 272, "</span> ")
2874+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 268, "</span> ")
28942875 if templ_7745c5c3_Err != nil {
28952876 return templ_7745c5c3_Err
28962877 }
28972878 if v.Detail != "" {
2898- var templ_7745c5c3_Var140 string
2899- templ_7745c5c3_Var140, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
2879+ var templ_7745c5c3_Var138 string
2880+ templ_7745c5c3_Var138, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
29002881 if templ_7745c5c3_Err != nil {
2901- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 564, Col: 8}
2882+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 561, Col: 8}
29022883 }
2903- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var140))
2884+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var138))
29042885 if templ_7745c5c3_Err != nil {
29052886 return templ_7745c5c3_Err
29062887 }
2907- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 273, "<span class=\"dim\">")
2888+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 269, "<span class=\"dim\">")
29082889 if templ_7745c5c3_Err != nil {
29092890 return templ_7745c5c3_Err
29102891 }
2911- var templ_7745c5c3_Var141 string
2912- templ_7745c5c3_Var141, templ_7745c5c3_Err = templ.JoinStringErrs(v.Detail)
2892+ var templ_7745c5c3_Var139 string
2893+ templ_7745c5c3_Var139, templ_7745c5c3_Err = templ.JoinStringErrs(v.Detail)
29132894 if templ_7745c5c3_Err != nil {
2914- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 564, Col: 38}
2895+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 561, Col: 38}
29152896 }
2916- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var141))
2897+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var139))
29172898 if templ_7745c5c3_Err != nil {
29182899 return templ_7745c5c3_Err
29192900 }
2920- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 274, "</span>")
2901+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 270, "</span>")
29212902 if templ_7745c5c3_Err != nil {
29222903 return templ_7745c5c3_Err
29232904 }
29242905 }
2925- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 275, "</span> ")
2906+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 271, "</span> ")
29262907 if templ_7745c5c3_Err != nil {
29272908 return templ_7745c5c3_Err
29282909 }
29292910 if len(v.Paths) > 0 {
2930- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 276, "<ul class=\"mg-paths\" aria-label=\"conflicting files\">")
2911+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 272, "<ul class=\"mg-paths\" aria-label=\"conflicting files\">")
29312912 if templ_7745c5c3_Err != nil {
29322913 return templ_7745c5c3_Err
29332914 }
29342915 for _, path := range v.Paths {
2935- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 277, "<li><code>")
2916+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 273, "<li><code>")
29362917 if templ_7745c5c3_Err != nil {
29372918 return templ_7745c5c3_Err
29382919 }
2939- var templ_7745c5c3_Var142 string
2940- templ_7745c5c3_Var142, templ_7745c5c3_Err = templ.JoinStringErrs(path)
2920+ var templ_7745c5c3_Var140 string
2921+ templ_7745c5c3_Var140, templ_7745c5c3_Err = templ.JoinStringErrs(path)
29412922 if templ_7745c5c3_Err != nil {
2942- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 570, Col: 20}
2923+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 567, Col: 20}
29432924 }
2944- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var142))
2925+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var140))
29452926 if templ_7745c5c3_Err != nil {
29462927 return templ_7745c5c3_Err
29472928 }
2948- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 278, "</code></li>")
2929+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 274, "</code></li>")
29492930 if templ_7745c5c3_Err != nil {
29502931 return templ_7745c5c3_Err
29512932 }
29522933 }
2953- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 279, "</ul>")
2934+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 275, "</ul>")
29542935 if templ_7745c5c3_Err != nil {
29552936 return templ_7745c5c3_Err
29562937 }
29572938 }
29582939 if v.PathsNote != "" {
2959- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 280, "<p class=\"dim\">")
2940+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 276, "<p class=\"dim\">")
29602941 if templ_7745c5c3_Err != nil {
29612942 return templ_7745c5c3_Err
29622943 }
2963- var templ_7745c5c3_Var143 string
2964- templ_7745c5c3_Var143, templ_7745c5c3_Err = templ.JoinStringErrs(v.PathsNote)
2944+ var templ_7745c5c3_Var141 string
2945+ templ_7745c5c3_Var141, templ_7745c5c3_Err = templ.JoinStringErrs(v.PathsNote)
29652946 if templ_7745c5c3_Err != nil {
2966- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 575, Col: 30}
2947+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 572, Col: 30}
29672948 }
2968- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var143))
2949+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var141))
29692950 if templ_7745c5c3_Err != nil {
29702951 return templ_7745c5c3_Err
29712952 }
2972- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 281, "</p>")
2953+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 277, "</p>")
29732954 if templ_7745c5c3_Err != nil {
29742955 return templ_7745c5c3_Err
29752956 }
@@ -2996,12 +2977,12 @@ func mrMergeabilitySlot(v MergeabilityView) templ.Component {
29962977 }()
29972978 }
29982979 ctx = templ.InitializeContext(ctx)
2999- templ_7745c5c3_Var144 := templ.GetChildren(ctx)
3000- if templ_7745c5c3_Var144 == nil {
3001- templ_7745c5c3_Var144 = templ.NopComponent
2980+ templ_7745c5c3_Var142 := templ.GetChildren(ctx)
2981+ if templ_7745c5c3_Var142 == nil {
2982+ templ_7745c5c3_Var142 = templ.NopComponent
30022983 }
30032984 ctx = templ.ClearChildren(ctx)
3004- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 282, "<div id=\"mr-mergeability\" class=\"live-slot\" role=\"status\" data-slot>")
2985+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 278, "<div id=\"mr-mergeability\" class=\"live-slot\" role=\"status\" data-slot>")
30052986 if templ_7745c5c3_Err != nil {
30062987 return templ_7745c5c3_Err
30072988 }
@@ -3009,7 +2990,7 @@ func mrMergeabilitySlot(v MergeabilityView) templ.Component {
30092990 if templ_7745c5c3_Err != nil {
30102991 return templ_7745c5c3_Err
30112992 }
3012- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 283, "</div>")
2993+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 279, "</div>")
30132994 if templ_7745c5c3_Err != nil {
30142995 return templ_7745c5c3_Err
30152996 }
@@ -3034,9 +3015,9 @@ func MRMergeabilityFragment(v MergeabilityView) templ.Component {
30343015 }()
30353016 }
30363017 ctx = templ.InitializeContext(ctx)
3037- templ_7745c5c3_Var145 := templ.GetChildren(ctx)
3038- if templ_7745c5c3_Var145 == nil {
3039- templ_7745c5c3_Var145 = templ.NopComponent
3018+ templ_7745c5c3_Var143 := templ.GetChildren(ctx)
3019+ if templ_7745c5c3_Var143 == nil {
3020+ templ_7745c5c3_Var143 = templ.NopComponent
30403021 }
30413022 ctx = templ.ClearChildren(ctx)
30423023 templ_7745c5c3_Err = mrMergeabilitySlot(v).Render(ctx, templ_7745c5c3_Buffer)
@@ -3047,8 +3028,8 @@ func MRMergeabilityFragment(v MergeabilityView) templ.Component {
30473028 })
30483029 }
30493030
3050-// moreMenu is what else the owner does with an open request: mark the head
3051-// read, close it, merge it from a terminal.
3031+// moreMenu shows read-only settings to every viewer, and keeps owner actions
3032+// behind the same merge-box permission as before.
30523033 func moreMenu(p MRPage) templ.Component {
30533034 return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
30543035 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@@ -3065,79 +3046,142 @@ func moreMenu(p MRPage) templ.Component {
30653046 }()
30663047 }
30673048 ctx = templ.InitializeContext(ctx)
3068- templ_7745c5c3_Var146 := templ.GetChildren(ctx)
3069- if templ_7745c5c3_Var146 == nil {
3070- templ_7745c5c3_Var146 = templ.NopComponent
3049+ templ_7745c5c3_Var144 := templ.GetChildren(ctx)
3050+ if templ_7745c5c3_Var144 == nil {
3051+ templ_7745c5c3_Var144 = templ.NopComponent
30713052 }
30723053 ctx = templ.ClearChildren(ctx)
3073- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 284, "<details class=\"menu omenu\"><summary class=\"btn icon\" aria-label=\"More actions\" title=\"more actions\">⋯</summary><div class=\"menu-pop\" role=\"group\" aria-label=\"More actions\">")
3054+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 280, "<details class=\"menu omenu\"><summary class=\"btn icon\" aria-label=\"More actions\" title=\"more actions\">⋯</summary><div class=\"menu-pop\" role=\"group\" aria-label=\"More actions\"><section class=\"merge-settings\"><h2>Merge settings</h2><dl class=\"kv\"><dt>modes</dt><dd>")
30743055 if templ_7745c5c3_Err != nil {
30753056 return templ_7745c5c3_Err
30763057 }
3077- if p.Box.CanMarkRead {
3078- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 285, "<form method=\"post\" action=\"")
3058+ var templ_7745c5c3_Var145 string
3059+ templ_7745c5c3_Var145, templ_7745c5c3_Err = templ.JoinStringErrs(strings.Join(p.Modes, ", "))
3060+ if templ_7745c5c3_Err != nil {
3061+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 599, Col: 38}
3062+ }
3063+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var145))
3064+ if templ_7745c5c3_Err != nil {
3065+ return templ_7745c5c3_Err
3066+ }
3067+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 281, "</dd><dt>checks</dt><dd>")
3068+ if templ_7745c5c3_Err != nil {
3069+ return templ_7745c5c3_Err
3070+ }
3071+ if p.ChecksBlock {
3072+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 282, "failing ones block the merge")
30793073 if templ_7745c5c3_Err != nil {
30803074 return templ_7745c5c3_Err
30813075 }
3082- var templ_7745c5c3_Var147 templ.SafeURL
3083- templ_7745c5c3_Var147, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.ReadAction))
3084- if templ_7745c5c3_Err != nil {
3085- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 599, Col: 64}
3086- }
3087- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var147))
3076+ } else {
3077+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 283, "do not block the merge")
30883078 if templ_7745c5c3_Err != nil {
30893079 return templ_7745c5c3_Err
30903080 }
3091- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 286, "\"><input type=\"hidden\" name=\"head_id\" value=\"")
3081+ }
3082+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 284, "</dd></dl></section>")
3083+ if templ_7745c5c3_Err != nil {
3084+ return templ_7745c5c3_Err
3085+ }
3086+ if p.Box != nil {
3087+ if p.Box.Signed {
3088+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 285, "<p class=\"d-note\" id=\"mr-signing\">squash and merge commits are signed with ermite's own key (generated on first start). ")
3089+ if templ_7745c5c3_Err != nil {
3090+ return templ_7745c5c3_Err
3091+ }
3092+ if p.Box.Fingerprint != "" {
3093+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 286, "fingerprint <code>")
3094+ if templ_7745c5c3_Err != nil {
3095+ return templ_7745c5c3_Err
3096+ }
3097+ var templ_7745c5c3_Var146 string
3098+ templ_7745c5c3_Var146, templ_7745c5c3_Err = templ.JoinStringErrs(p.Box.Fingerprint)
3099+ if templ_7745c5c3_Err != nil {
3100+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 615, Col: 44}
3101+ }
3102+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var146))
3103+ if templ_7745c5c3_Err != nil {
3104+ return templ_7745c5c3_Err
3105+ }
3106+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 287, "</code> ")
3107+ if templ_7745c5c3_Err != nil {
3108+ return templ_7745c5c3_Err
3109+ }
3110+ }
3111+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 288, "<code>ermite signing-key show</code> prints it.</p>")
3112+ if templ_7745c5c3_Err != nil {
3113+ return templ_7745c5c3_Err
3114+ }
3115+ }
3116+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 289, " ")
30923117 if templ_7745c5c3_Err != nil {
30933118 return templ_7745c5c3_Err
30943119 }
3095- var templ_7745c5c3_Var148 string
3096- templ_7745c5c3_Var148, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.Head)
3097- if templ_7745c5c3_Err != nil {
3098- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 600, Col: 59}
3120+ if p.Box.CanMarkRead {
3121+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 290, "<form method=\"post\" action=\"")
3122+ if templ_7745c5c3_Err != nil {
3123+ return templ_7745c5c3_Err
3124+ }
3125+ var templ_7745c5c3_Var147 templ.SafeURL
3126+ templ_7745c5c3_Var147, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.ReadAction))
3127+ if templ_7745c5c3_Err != nil {
3128+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 621, Col: 65}
3129+ }
3130+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var147))
3131+ if templ_7745c5c3_Err != nil {
3132+ return templ_7745c5c3_Err
3133+ }
3134+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 291, "\"><input type=\"hidden\" name=\"head_id\" value=\"")
3135+ if templ_7745c5c3_Err != nil {
3136+ return templ_7745c5c3_Err
3137+ }
3138+ var templ_7745c5c3_Var148 string
3139+ templ_7745c5c3_Var148, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.Head)
3140+ if templ_7745c5c3_Err != nil {
3141+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 622, Col: 60}
3142+ }
3143+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var148)
3144+ if templ_7745c5c3_Err != nil {
3145+ return templ_7745c5c3_Err
3146+ }
3147+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 292, "\"> <button type=\"submit\" title=\"the next visit can show only what changed after this head\" class=\"btn\" aria-keyshortcuts=\"Shift+R\" data-read>Mark read <kbd aria-hidden=\"true\">R</kbd></button></form>")
3148+ if templ_7745c5c3_Err != nil {
3149+ return templ_7745c5c3_Err
3150+ }
30993151 }
3100- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var148)
3152+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 293, " <form method=\"post\" action=\"")
31013153 if templ_7745c5c3_Err != nil {
31023154 return templ_7745c5c3_Err
31033155 }
3104- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 287, "\"> <button type=\"submit\" title=\"the next visit can show only what changed after this head\" class=\"btn\" aria-keyshortcuts=\"Shift+R\" data-read>Mark read <kbd aria-hidden=\"true\">R</kbd></button></form>")
3156+ var templ_7745c5c3_Var149 templ.SafeURL
3157+ templ_7745c5c3_Var149, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.CloseAction))
31053158 if templ_7745c5c3_Err != nil {
3106- return templ_7745c5c3_Err
3159+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 626, Col: 65}
31073160 }
3108- }
3109- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 288, "<form method=\"post\" action=\"")
3110- if templ_7745c5c3_Err != nil {
3111- return templ_7745c5c3_Err
3112- }
3113- var templ_7745c5c3_Var149 templ.SafeURL
3114- templ_7745c5c3_Var149, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.CloseAction))
3115- if templ_7745c5c3_Err != nil {
3116- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 604, Col: 64}
3117- }
3118- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var149))
3119- if templ_7745c5c3_Err != nil {
3120- return templ_7745c5c3_Err
3121- }
3122- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 289, "\"><button type=\"submit\" title=\"close without merging; the branch is kept\" class=\"btn danger\">Close</button></form>")
3123- if templ_7745c5c3_Err != nil {
3124- return templ_7745c5c3_Err
3125- }
3126- if !p.Box.HeadGone && p.Box.ReadyAction == "" {
3127- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 290, "<details class=\"d-or\"><summary class=\"mute\">or from a terminal</summary>")
3161+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var149))
31283162 if templ_7745c5c3_Err != nil {
31293163 return templ_7745c5c3_Err
31303164 }
3131- templ_7745c5c3_Err = CloneBlock(p.Box.CLI).Render(ctx, templ_7745c5c3_Buffer)
3165+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 294, "\"><button type=\"submit\" title=\"close without merging; the branch is kept\" class=\"btn danger\">Close</button></form>")
31323166 if templ_7745c5c3_Err != nil {
31333167 return templ_7745c5c3_Err
31343168 }
3135- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 291, "</details>")
3136- if templ_7745c5c3_Err != nil {
3137- return templ_7745c5c3_Err
3169+ if !p.Box.HeadGone && p.Box.ReadyAction == "" {
3170+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 295, "<details class=\"d-or\"><summary class=\"mute\">or from a terminal</summary>")
3171+ if templ_7745c5c3_Err != nil {
3172+ return templ_7745c5c3_Err
3173+ }
3174+ templ_7745c5c3_Err = CloneBlock(p.Box.CLI).Render(ctx, templ_7745c5c3_Buffer)
3175+ if templ_7745c5c3_Err != nil {
3176+ return templ_7745c5c3_Err
3177+ }
3178+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 296, "</details>")
3179+ if templ_7745c5c3_Err != nil {
3180+ return templ_7745c5c3_Err
3181+ }
31383182 }
31393183 }
3140- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 292, "</div></details>")
3184+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 297, "</div></details>")
31413185 if templ_7745c5c3_Err != nil {
31423186 return templ_7745c5c3_Err
31433187 }
@@ -3178,263 +3222,263 @@ func Compare(l Layout, p ComparePage) templ.Component {
31783222 }()
31793223 }
31803224 ctx = templ.InitializeContext(ctx)
3181- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 293, "<header class=\"show mr-h\"><h1>")
3225+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 298, "<header class=\"show mr-h\"><h1>")
31823226 if templ_7745c5c3_Err != nil {
31833227 return templ_7745c5c3_Err
31843228 }
31853229 var templ_7745c5c3_Var152 string
31863230 templ_7745c5c3_Var152, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)
31873231 if templ_7745c5c3_Err != nil {
3188- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 620, Col: 17}
3232+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 643, Col: 17}
31893233 }
31903234 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var152))
31913235 if templ_7745c5c3_Err != nil {
31923236 return templ_7745c5c3_Err
31933237 }
3194- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 294, " → ")
3238+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 299, " → ")
31953239 if templ_7745c5c3_Err != nil {
31963240 return templ_7745c5c3_Err
31973241 }
31983242 var templ_7745c5c3_Var153 string
31993243 templ_7745c5c3_Var153, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
32003244 if templ_7745c5c3_Err != nil {
3201- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 620, Col: 34}
3245+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 643, Col: 34}
32023246 }
32033247 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var153))
32043248 if templ_7745c5c3_Err != nil {
32053249 return templ_7745c5c3_Err
32063250 }
3207- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 295, "</h1><dl class=\"kv show-kv\"><dt>branch</dt><dd><a href=\"")
3251+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 300, "</h1><dl class=\"kv show-kv\"><dt>branch</dt><dd><a href=\"")
32083252 if templ_7745c5c3_Err != nil {
32093253 return templ_7745c5c3_Err
32103254 }
32113255 var templ_7745c5c3_Var154 templ.SafeURL
32123256 templ_7745c5c3_Var154, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.SourceHref))
32133257 if templ_7745c5c3_Err != nil {
3214- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 623, Col: 45}
3258+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 646, Col: 45}
32153259 }
32163260 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var154))
32173261 if templ_7745c5c3_Err != nil {
32183262 return templ_7745c5c3_Err
32193263 }
3220- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 296, "\">")
3264+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 301, "\">")
32213265 if templ_7745c5c3_Err != nil {
32223266 return templ_7745c5c3_Err
32233267 }
32243268 var templ_7745c5c3_Var155 string
32253269 templ_7745c5c3_Var155, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)
32263270 if templ_7745c5c3_Err != nil {
3227- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 623, Col: 58}
3271+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 646, Col: 58}
32283272 }
32293273 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var155))
32303274 if templ_7745c5c3_Err != nil {
32313275 return templ_7745c5c3_Err
32323276 }
3233- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 297, "</a></dd><dt>target</dt><dd><a href=\"")
3277+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 302, "</a></dd><dt>target</dt><dd><a href=\"")
32343278 if templ_7745c5c3_Err != nil {
32353279 return templ_7745c5c3_Err
32363280 }
32373281 var templ_7745c5c3_Var156 templ.SafeURL
32383282 templ_7745c5c3_Var156, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.TargetHref))
32393283 if templ_7745c5c3_Err != nil {
3240- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 625, Col: 45}
3284+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 648, Col: 45}
32413285 }
32423286 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var156))
32433287 if templ_7745c5c3_Err != nil {
32443288 return templ_7745c5c3_Err
32453289 }
3246- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 298, "\">")
3290+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 303, "\">")
32473291 if templ_7745c5c3_Err != nil {
32483292 return templ_7745c5c3_Err
32493293 }
32503294 var templ_7745c5c3_Var157 string
32513295 templ_7745c5c3_Var157, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
32523296 if templ_7745c5c3_Err != nil {
3253- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 625, Col: 58}
3297+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 648, Col: 58}
32543298 }
32553299 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var157))
32563300 if templ_7745c5c3_Err != nil {
32573301 return templ_7745c5c3_Err
32583302 }
3259- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 299, "</a></dd><dt>ahead</dt><dd>")
3303+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 304, "</a></dd><dt>ahead</dt><dd>")
32603304 if templ_7745c5c3_Err != nil {
32613305 return templ_7745c5c3_Err
32623306 }
32633307 var templ_7745c5c3_Var158 string
32643308 templ_7745c5c3_Var158, templ_7745c5c3_Err = templ.JoinStringErrs(p.AheadText)
32653309 if templ_7745c5c3_Err != nil {
3266- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 627, Col: 21}
3310+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 650, Col: 21}
32673311 }
32683312 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var158))
32693313 if templ_7745c5c3_Err != nil {
32703314 return templ_7745c5c3_Err
32713315 }
3272- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 300, "</dd></dl></header>")
3316+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 305, "</dd></dl></header>")
32733317 if templ_7745c5c3_Err != nil {
32743318 return templ_7745c5c3_Err
32753319 }
32763320 if p.Note != "" {
3277- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 301, "<p class=\"notice\">")
3321+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 306, "<p class=\"notice\">")
32783322 if templ_7745c5c3_Err != nil {
32793323 return templ_7745c5c3_Err
32803324 }
32813325 var templ_7745c5c3_Var159 string
32823326 templ_7745c5c3_Var159, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note)
32833327 if templ_7745c5c3_Err != nil {
3284- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 631, Col: 29}
3328+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 654, Col: 29}
32853329 }
32863330 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var159))
32873331 if templ_7745c5c3_Err != nil {
32883332 return templ_7745c5c3_Err
32893333 }
3290- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 302, "</p>")
3334+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 307, "</p>")
32913335 if templ_7745c5c3_Err != nil {
32923336 return templ_7745c5c3_Err
32933337 }
32943338 }
3295- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 303, " ")
3339+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 308, " ")
32963340 if templ_7745c5c3_Err != nil {
32973341 return templ_7745c5c3_Err
32983342 }
32993343 if p.Existing != nil {
3300- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 304, "<p class=\"notice\">an open merge request already covers these branches: <a href=\"")
3344+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 309, "<p class=\"notice\">an open merge request already covers these branches: <a href=\"")
33013345 if templ_7745c5c3_Err != nil {
33023346 return templ_7745c5c3_Err
33033347 }
33043348 var templ_7745c5c3_Var160 templ.SafeURL
33053349 templ_7745c5c3_Var160, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Existing.Href))
33063350 if templ_7745c5c3_Err != nil {
3307- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 634, Col: 114}
3351+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 657, Col: 114}
33083352 }
33093353 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var160))
33103354 if templ_7745c5c3_Err != nil {
33113355 return templ_7745c5c3_Err
33123356 }
3313- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 305, "\">")
3357+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 310, "\">")
33143358 if templ_7745c5c3_Err != nil {
33153359 return templ_7745c5c3_Err
33163360 }
33173361 var templ_7745c5c3_Var161 string
33183362 templ_7745c5c3_Var161, templ_7745c5c3_Err = templ.JoinStringErrs(p.Existing.Label)
33193363 if templ_7745c5c3_Err != nil {
3320- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 634, Col: 135}
3364+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 657, Col: 135}
33213365 }
33223366 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var161))
33233367 if templ_7745c5c3_Err != nil {
33243368 return templ_7745c5c3_Err
33253369 }
3326- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 306, "</a></p>")
3370+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 311, "</a></p>")
33273371 if templ_7745c5c3_Err != nil {
33283372 return templ_7745c5c3_Err
33293373 }
33303374 }
3331- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 307, " ")
3375+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 312, " ")
33323376 if templ_7745c5c3_Err != nil {
33333377 return templ_7745c5c3_Err
33343378 }
33353379 if p.Create != nil {
3336- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 308, "<form class=\"cform create\" method=\"post\" action=\"")
3380+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 313, "<form class=\"cform create\" method=\"post\" action=\"")
33373381 if templ_7745c5c3_Err != nil {
33383382 return templ_7745c5c3_Err
33393383 }
33403384 var templ_7745c5c3_Var162 templ.SafeURL
33413385 templ_7745c5c3_Var162, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Create.Action))
33423386 if templ_7745c5c3_Err != nil {
3343- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 637, Col: 83}
3387+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 660, Col: 83}
33443388 }
33453389 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var162))
33463390 if templ_7745c5c3_Err != nil {
33473391 return templ_7745c5c3_Err
33483392 }
3349- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 309, "\"><input type=\"hidden\" name=\"source\" value=\"")
3393+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 314, "\"><input type=\"hidden\" name=\"source\" value=\"")
33503394 if templ_7745c5c3_Err != nil {
33513395 return templ_7745c5c3_Err
33523396 }
33533397 var templ_7745c5c3_Var163 string
33543398 templ_7745c5c3_Var163, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Source)
33553399 if templ_7745c5c3_Err != nil {
3356- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 638, Col: 62}
3400+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 661, Col: 62}
33573401 }
33583402 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var163)
33593403 if templ_7745c5c3_Err != nil {
33603404 return templ_7745c5c3_Err
33613405 }
3362- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 310, "\"> <input type=\"hidden\" name=\"target\" value=\"")
3406+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 315, "\"> <input type=\"hidden\" name=\"target\" value=\"")
33633407 if templ_7745c5c3_Err != nil {
33643408 return templ_7745c5c3_Err
33653409 }
33663410 var templ_7745c5c3_Var164 string
33673411 templ_7745c5c3_Var164, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Target)
33683412 if templ_7745c5c3_Err != nil {
3369- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 639, Col: 62}
3413+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 662, Col: 62}
33703414 }
33713415 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var164)
33723416 if templ_7745c5c3_Err != nil {
33733417 return templ_7745c5c3_Err
33743418 }
3375- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 311, "\"> <label for=\"mr-title\">title</label> <input id=\"mr-title\" name=\"title\" type=\"text\" maxlength=\"120\" required value=\"")
3419+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 316, "\"> <label for=\"mr-title\">title</label> <input id=\"mr-title\" name=\"title\" type=\"text\" maxlength=\"120\" required value=\"")
33763420 if templ_7745c5c3_Err != nil {
33773421 return templ_7745c5c3_Err
33783422 }
33793423 var templ_7745c5c3_Var165 string
33803424 templ_7745c5c3_Var165, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Title)
33813425 if templ_7745c5c3_Err != nil {
3382- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 641, Col: 97}
3426+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 664, Col: 97}
33833427 }
33843428 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var165)
33853429 if templ_7745c5c3_Err != nil {
33863430 return templ_7745c5c3_Err
33873431 }
3388- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 312, "\" autocomplete=\"off\"> <label for=\"mr-desc\">description</label> <textarea id=\"mr-desc\" name=\"description\" rows=\"4\" maxlength=\"8000\" placeholder=\"Markdown, optional\"></textarea><div class=\"f-btns\"><button type=\"submit\" class=\"btn primary\">Create merge request</button></div></form>")
3432+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 317, "\" autocomplete=\"off\"> <label for=\"mr-desc\">description</label> <textarea id=\"mr-desc\" name=\"description\" rows=\"4\" maxlength=\"8000\" placeholder=\"Markdown, optional\"></textarea><div class=\"f-btns\"><button type=\"submit\" class=\"btn primary\">Create merge request</button></div></form>")
33893433 if templ_7745c5c3_Err != nil {
33903434 return templ_7745c5c3_Err
33913435 }
33923436 }
3393- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 313, " ")
3437+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 318, " ")
33943438 if templ_7745c5c3_Err != nil {
33953439 return templ_7745c5c3_Err
33963440 }
33973441 if p.HasDiff {
3398- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 314, "<div class=\"diff-tools\" role=\"group\" aria-label=\"Diff view\"><span class=\"dim\">")
3442+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 319, "<div class=\"diff-tools\" role=\"group\" aria-label=\"Diff view\"><span class=\"dim\">")
33993443 if templ_7745c5c3_Err != nil {
34003444 return templ_7745c5c3_Err
34013445 }
34023446 var templ_7745c5c3_Var166 string
34033447 templ_7745c5c3_Var166, templ_7745c5c3_Err = templ.JoinStringErrs(plural(p.NFiles, "file", "files"))
34043448 if templ_7745c5c3_Err != nil {
3405- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 651, Col: 57}
3449+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 674, Col: 57}
34063450 }
34073451 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var166))
34083452 if templ_7745c5c3_Err != nil {
34093453 return templ_7745c5c3_Err
34103454 }
3411- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 315, " · <span class=\"plus\">+")
3455+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 320, " · <span class=\"plus\">+")
34123456 if templ_7745c5c3_Err != nil {
34133457 return templ_7745c5c3_Err
34143458 }
34153459 var templ_7745c5c3_Var167 string
34163460 templ_7745c5c3_Var167, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Adds))
34173461 if templ_7745c5c3_Err != nil {
3418- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 651, Col: 97}
3462+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 674, Col: 97}
34193463 }
34203464 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var167))
34213465 if templ_7745c5c3_Err != nil {
34223466 return templ_7745c5c3_Err
34233467 }
3424- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 316, "</span> <span class=\"minus\">-")
3468+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 321, "</span> <span class=\"minus\">-")
34253469 if templ_7745c5c3_Err != nil {
34263470 return templ_7745c5c3_Err
34273471 }
34283472 var templ_7745c5c3_Var168 string
34293473 templ_7745c5c3_Var168, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Dels))
34303474 if templ_7745c5c3_Err != nil {
3431- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 651, Col: 142}
3475+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 674, Col: 142}
34323476 }
34333477 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var168))
34343478 if templ_7745c5c3_Err != nil {
34353479 return templ_7745c5c3_Err
34363480 }
3437- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 317, "</span></span> <span class=\"grow\"></span>")
3481+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 322, "</span></span> <span class=\"grow\"></span>")
34383482 if templ_7745c5c3_Err != nil {
34393483 return templ_7745c5c3_Err
34403484 }
@@ -3442,64 +3486,64 @@ func Compare(l Layout, p ComparePage) templ.Component {
34423486 if templ_7745c5c3_Err != nil {
34433487 return templ_7745c5c3_Err
34443488 }
3445- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 318, "</div>")
3489+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 323, "</div>")
34463490 if templ_7745c5c3_Err != nil {
34473491 return templ_7745c5c3_Err
34483492 }
34493493 if p.Invisible {
3450- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 319, "<p class=\"notice\">this diff holds invisible characters (direction controls, zero-width characters). They are shown as <span class=\"inv\">&lt;U+XXXX&gt;</span> markers, never applied.</p>")
3494+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 324, "<p class=\"notice\">this diff holds invisible characters (direction controls, zero-width characters). They are shown as <span class=\"inv\">&lt;U+XXXX&gt;</span> markers, never applied.</p>")
34513495 if templ_7745c5c3_Err != nil {
34523496 return templ_7745c5c3_Err
34533497 }
34543498 }
3455- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 320, " <div id=\"diffs\"")
3499+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 325, " <div id=\"diffs\"")
34563500 if templ_7745c5c3_Err != nil {
34573501 return templ_7745c5c3_Err
34583502 }
34593503 if p.Both {
3460- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 321, " data-diff=\"")
3504+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 326, " data-diff=\"")
34613505 if templ_7745c5c3_Err != nil {
34623506 return templ_7745c5c3_Err
34633507 }
34643508 var templ_7745c5c3_Var169 string
34653509 templ_7745c5c3_Var169, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
34663510 if templ_7745c5c3_Err != nil {
3467- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 664, Col: 23}
3511+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 687, Col: 23}
34683512 }
34693513 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var169)
34703514 if templ_7745c5c3_Err != nil {
34713515 return templ_7745c5c3_Err
34723516 }
3473- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 322, "\"")
3517+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 327, "\"")
34743518 if templ_7745c5c3_Err != nil {
34753519 return templ_7745c5c3_Err
34763520 }
34773521 } else {
3478- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 323, " data-view=\"")
3522+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 328, " data-view=\"")
34793523 if templ_7745c5c3_Err != nil {
34803524 return templ_7745c5c3_Err
34813525 }
34823526 var templ_7745c5c3_Var170 string
34833527 templ_7745c5c3_Var170, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
34843528 if templ_7745c5c3_Err != nil {
3485- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 666, Col: 23}
3529+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 689, Col: 23}
34863530 }
34873531 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var170)
34883532 if templ_7745c5c3_Err != nil {
34893533 return templ_7745c5c3_Err
34903534 }
3491- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 324, "\"")
3535+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 329, "\"")
34923536 if templ_7745c5c3_Err != nil {
34933537 return templ_7745c5c3_Err
34943538 }
34953539 }
34963540 if p.Both && !p.Pinned {
3497- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 325, " hx-live=\"this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff\"")
3541+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 330, " hx-live=\"this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff\"")
34983542 if templ_7745c5c3_Err != nil {
34993543 return templ_7745c5c3_Err
35003544 }
35013545 }
3502- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 326, ">")
3546+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 331, ">")
35033547 if templ_7745c5c3_Err != nil {
35043548 return templ_7745c5c3_Err
35053549 }
@@ -3509,7 +3553,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
35093553 return templ_7745c5c3_Err
35103554 }
35113555 }
3512- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 327, "</div>")
3556+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 332, "</div>")
35133557 if templ_7745c5c3_Err != nil {
35143558 return templ_7745c5c3_Err
35153559 }
@@ -3545,77 +3589,77 @@ func compareRail(p ComparePage) templ.Component {
35453589 templ_7745c5c3_Var171 = templ.NopComponent
35463590 }
35473591 ctx = templ.ClearChildren(ctx)
3548- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 328, "<section aria-labelledby=\"r-ahead\"><h2 id=\"r-ahead\">Commits <span class=\"count\">")
3592+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 333, "<section aria-labelledby=\"r-ahead\"><h2 id=\"r-ahead\">Commits <span class=\"count\">")
35493593 if templ_7745c5c3_Err != nil {
35503594 return templ_7745c5c3_Err
35513595 }
35523596 var templ_7745c5c3_Var172 string
35533597 templ_7745c5c3_Var172, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Ahead)))
35543598 if templ_7745c5c3_Err != nil {
3555- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 682, Col: 67}
3599+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 705, Col: 67}
35563600 }
35573601 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var172))
35583602 if templ_7745c5c3_Err != nil {
35593603 return templ_7745c5c3_Err
35603604 }
3561- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 329, "</span></h2><ul class=\"pcommits\">")
3605+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 334, "</span></h2><ul class=\"pcommits\">")
35623606 if templ_7745c5c3_Err != nil {
35633607 return templ_7745c5c3_Err
35643608 }
35653609 for _, c := range p.Ahead {
3566- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 330, "<li><a href=\"")
3610+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 335, "<li><a href=\"")
35673611 if templ_7745c5c3_Err != nil {
35683612 return templ_7745c5c3_Err
35693613 }
35703614 var templ_7745c5c3_Var173 templ.SafeURL
35713615 templ_7745c5c3_Var173, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.CHref))
35723616 if templ_7745c5c3_Err != nil {
3573- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 686, Col: 37}
3617+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 709, Col: 37}
35743618 }
35753619 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var173))
35763620 if templ_7745c5c3_Err != nil {
35773621 return templ_7745c5c3_Err
35783622 }
3579- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 331, "\">")
3623+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 336, "\">")
35803624 if templ_7745c5c3_Err != nil {
35813625 return templ_7745c5c3_Err
35823626 }
35833627 var templ_7745c5c3_Var174 string
35843628 templ_7745c5c3_Var174, templ_7745c5c3_Err = templ.JoinStringErrs(c.Short)
35853629 if templ_7745c5c3_Err != nil {
3586- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 686, Col: 49}
3630+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 709, Col: 49}
35873631 }
35883632 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var174))
35893633 if templ_7745c5c3_Err != nil {
35903634 return templ_7745c5c3_Err
35913635 }
3592- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 332, "</a> <span class=\"s\">")
3636+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 337, "</a> <span class=\"s\">")
35933637 if templ_7745c5c3_Err != nil {
35943638 return templ_7745c5c3_Err
35953639 }
35963640 var templ_7745c5c3_Var175 string
35973641 templ_7745c5c3_Var175, templ_7745c5c3_Err = templ.JoinStringErrs(c.Subject)
35983642 if templ_7745c5c3_Err != nil {
3599- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 687, Col: 32}
3643+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 710, Col: 32}
36003644 }
36013645 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var175))
36023646 if templ_7745c5c3_Err != nil {
36033647 return templ_7745c5c3_Err
36043648 }
3605- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 333, "</span> <span class=\"mute\">")
3649+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 338, "</span> <span class=\"mute\">")
36063650 if templ_7745c5c3_Err != nil {
36073651 return templ_7745c5c3_Err
36083652 }
36093653 var templ_7745c5c3_Var176 string
36103654 templ_7745c5c3_Var176, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)
36113655 if templ_7745c5c3_Err != nil {
3612- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 689, Col: 16}
3656+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 712, Col: 16}
36133657 }
36143658 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var176))
36153659 if templ_7745c5c3_Err != nil {
36163660 return templ_7745c5c3_Err
36173661 }
3618- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 334, " ")
3662+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 339, " ")
36193663 if templ_7745c5c3_Err != nil {
36203664 return templ_7745c5c3_Err
36213665 }
@@ -3623,90 +3667,90 @@ func compareRail(p ComparePage) templ.Component {
36233667 var templ_7745c5c3_Var177 string
36243668 templ_7745c5c3_Var177, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")
36253669 if templ_7745c5c3_Err != nil {
3626- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 691, Col: 15}
3670+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 714, Col: 15}
36273671 }
36283672 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var177))
36293673 if templ_7745c5c3_Err != nil {
36303674 return templ_7745c5c3_Err
36313675 }
3632- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 335, "<time datetime=\"")
3676+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 340, "<time datetime=\"")
36333677 if templ_7745c5c3_Err != nil {
36343678 return templ_7745c5c3_Err
36353679 }
36363680 var templ_7745c5c3_Var178 string
36373681 templ_7745c5c3_Var178, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)
36383682 if templ_7745c5c3_Err != nil {
3639- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 691, Col: 42}
3683+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 714, Col: 42}
36403684 }
36413685 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var178)
36423686 if templ_7745c5c3_Err != nil {
36433687 return templ_7745c5c3_Err
36443688 }
3645- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 336, "\">")
3689+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 341, "\">")
36463690 if templ_7745c5c3_Err != nil {
36473691 return templ_7745c5c3_Err
36483692 }
36493693 var templ_7745c5c3_Var179 string
36503694 templ_7745c5c3_Var179, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)
36513695 if templ_7745c5c3_Err != nil {
3652- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 691, Col: 53}
3696+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 714, Col: 53}
36533697 }
36543698 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var179))
36553699 if templ_7745c5c3_Err != nil {
36563700 return templ_7745c5c3_Err
36573701 }
3658- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 337, "</time>")
3702+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 342, "</time>")
36593703 if templ_7745c5c3_Err != nil {
36603704 return templ_7745c5c3_Err
36613705 }
36623706 }
3663- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 338, "</span></li>")
3707+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 343, "</span></li>")
36643708 if templ_7745c5c3_Err != nil {
36653709 return templ_7745c5c3_Err
36663710 }
36673711 }
3668- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 339, "</ul>")
3712+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 344, "</ul>")
36693713 if templ_7745c5c3_Err != nil {
36703714 return templ_7745c5c3_Err
36713715 }
36723716 if len(p.Ahead) == 0 {
3673- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 340, "<p class=\"dim\">no commit ahead of ")
3717+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 345, "<p class=\"dim\">no commit ahead of ")
36743718 if templ_7745c5c3_Err != nil {
36753719 return templ_7745c5c3_Err
36763720 }
36773721 var templ_7745c5c3_Var180 string
36783722 templ_7745c5c3_Var180, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
36793723 if templ_7745c5c3_Err != nil {
3680- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 698, Col: 47}
3724+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 721, Col: 47}
36813725 }
36823726 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var180))
36833727 if templ_7745c5c3_Err != nil {
36843728 return templ_7745c5c3_Err
36853729 }
3686- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 341, ".</p>")
3730+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 346, ".</p>")
36873731 if templ_7745c5c3_Err != nil {
36883732 return templ_7745c5c3_Err
36893733 }
36903734 }
3691- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 342, "</section>")
3735+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 347, "</section>")
36923736 if templ_7745c5c3_Err != nil {
36933737 return templ_7745c5c3_Err
36943738 }
36953739 if p.HasDiff {
3696- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 343, "<section aria-labelledby=\"r-files\"><h2 id=\"r-files\">Files <span class=\"count\">")
3740+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 348, "<section aria-labelledby=\"r-files\"><h2 id=\"r-files\">Files <span class=\"count\">")
36973741 if templ_7745c5c3_Err != nil {
36983742 return templ_7745c5c3_Err
36993743 }
37003744 var templ_7745c5c3_Var181 string
37013745 templ_7745c5c3_Var181, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))
37023746 if templ_7745c5c3_Err != nil {
3703- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 703, Col: 66}
3747+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 726, Col: 66}
37043748 }
37053749 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var181))
37063750 if templ_7745c5c3_Err != nil {
37073751 return templ_7745c5c3_Err
37083752 }
3709- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 344, "</span></h2>")
3753+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 349, "</span></h2>")
37103754 if templ_7745c5c3_Err != nil {
37113755 return templ_7745c5c3_Err
37123756 }
@@ -3714,12 +3758,12 @@ func compareRail(p ComparePage) templ.Component {
37143758 if templ_7745c5c3_Err != nil {
37153759 return templ_7745c5c3_Err
37163760 }
3717- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 345, "</section>")
3761+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 350, "</section>")
37183762 if templ_7745c5c3_Err != nil {
37193763 return templ_7745c5c3_Err
37203764 }
37213765 }
3722- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 346, "<section aria-labelledby=\"r-cli\"><h2 id=\"r-cli\">From a terminal</h2>")
3766+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 351, "<section aria-labelledby=\"r-cli\"><h2 id=\"r-cli\">From a terminal</h2>")
37233767 if templ_7745c5c3_Err != nil {
37243768 return templ_7745c5c3_Err
37253769 }
@@ -3727,7 +3771,7 @@ func compareRail(p ComparePage) templ.Component {
37273771 if templ_7745c5c3_Err != nil {
37283772 return templ_7745c5c3_Err
37293773 }
3730- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 347, "</section>")
3774+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 352, "</section>")
37313775 if templ_7745c5c3_Err != nil {
37323776 return templ_7745c5c3_Err
37333777 }
@@ -808,6 +808,10 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
808 return templ_7745c5c3_Err808 return templ_7745c5c3_Err
809 }809 }
810 }810 }
811+ templ_7745c5c3_Err = mrFooter(p).Render(ctx, templ_7745c5c3_Buffer)
812+ if templ_7745c5c3_Err != nil {
813+ return templ_7745c5c3_Err
814+ }
811 templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "</section>")815 templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "</section>")
812 if templ_7745c5c3_Err != nil {816 if templ_7745c5c3_Err != nil {
813 return templ_7745c5c3_Err817 return templ_7745c5c3_Err
@@ -820,7 +824,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
820 var templ_7745c5c3_Var42 string824 var templ_7745c5c3_Var42 string
821 templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.JoinStringErrs(p.Deleting)825 templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.JoinStringErrs(p.Deleting)
822 if templ_7745c5c3_Err != nil {826 if templ_7745c5c3_Err != nil {
823- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 152, Col: 64}827+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 153, Col: 64}
824 }828 }
825 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var42))829 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var42))
826 if templ_7745c5c3_Err != nil {830 if templ_7745c5c3_Err != nil {
@@ -843,7 +847,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
843 var templ_7745c5c3_Var43 string847 var templ_7745c5c3_Var43 string
844 templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinStringErrs(p.MergeError)848 templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinStringErrs(p.MergeError)
845 if templ_7745c5c3_Err != nil {849 if templ_7745c5c3_Err != nil {
846- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 155, Col: 47}850+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 156, Col: 47}
847 }851 }
848 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43))852 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43))
849 if templ_7745c5c3_Err != nil {853 if templ_7745c5c3_Err != nil {
@@ -874,7 +878,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
874 var templ_7745c5c3_Var44 templ.SafeURL878 var templ_7745c5c3_Var44 templ.SafeURL
875 templ_7745c5c3_Var44, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Since.AllHref))879 templ_7745c5c3_Var44, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Since.AllHref))
876 if templ_7745c5c3_Err != nil {880 if templ_7745c5c3_Err != nil {
877- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 161, Col: 42}881+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 162, Col: 42}
878 }882 }
879 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var44))883 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var44))
880 if templ_7745c5c3_Err != nil {884 if templ_7745c5c3_Err != nil {
@@ -897,7 +901,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
897 var templ_7745c5c3_Var45 string901 var templ_7745c5c3_Var45 string
898 templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)902 templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
899 if templ_7745c5c3_Err != nil {903 if templ_7745c5c3_Err != nil {
900- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 165, Col: 49}904+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 166, Col: 49}
901 }905 }
902 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var45))906 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var45))
903 if templ_7745c5c3_Err != nil {907 if templ_7745c5c3_Err != nil {
@@ -910,7 +914,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
910 var templ_7745c5c3_Var46 templ.SafeURL914 var templ_7745c5c3_Var46 templ.SafeURL
911 templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Since.SinceHref))915 templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Since.SinceHref))
912 if templ_7745c5c3_Err != nil {916 if templ_7745c5c3_Err != nil {
913- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 167, Col: 44}917+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 168, Col: 44}
914 }918 }
915 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var46))919 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var46))
916 if templ_7745c5c3_Err != nil {920 if templ_7745c5c3_Err != nil {
@@ -933,7 +937,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
933 var templ_7745c5c3_Var47 string937 var templ_7745c5c3_Var47 string
934 templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.JoinStringErrs(p.Since.ReadShort)938 templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.JoinStringErrs(p.Since.ReadShort)
935 if templ_7745c5c3_Err != nil {939 if templ_7745c5c3_Err != nil {
936- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 171, Col: 64}940+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 172, Col: 64}
937 }941 }
938 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var47))942 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var47))
939 if templ_7745c5c3_Err != nil {943 if templ_7745c5c3_Err != nil {
@@ -946,7 +950,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
946 var templ_7745c5c3_Var48 string950 var templ_7745c5c3_Var48 string
947 templ_7745c5c3_Var48, templ_7745c5c3_Err = templ.JoinStringErrs(p.Since.HeadShort)951 templ_7745c5c3_Var48, templ_7745c5c3_Err = templ.JoinStringErrs(p.Since.HeadShort)
948 if templ_7745c5c3_Err != nil {952 if templ_7745c5c3_Err != nil {
949- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 171, Col: 90}953+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 172, Col: 90}
950 }954 }
951 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var48))955 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var48))
952 if templ_7745c5c3_Err != nil {956 if templ_7745c5c3_Err != nil {
@@ -969,7 +973,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
969 var templ_7745c5c3_Var49 string973 var templ_7745c5c3_Var49 string
970 templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.JoinStringErrs(p.SinceNote)974 templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.JoinStringErrs(p.SinceNote)
971 if templ_7745c5c3_Err != nil {975 if templ_7745c5c3_Err != nil {
972- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 175, Col: 34}976+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 176, Col: 34}
973 }977 }
974 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var49))978 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var49))
975 if templ_7745c5c3_Err != nil {979 if templ_7745c5c3_Err != nil {
@@ -1010,7 +1014,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
1010 var templ_7745c5c3_Var50 string1014 var templ_7745c5c3_Var50 string
1011 templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note)1015 templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note)
1012 if templ_7745c5c3_Err != nil {1016 if templ_7745c5c3_Err != nil {
1013- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 185, Col: 29}1017+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 186, Col: 29}
1014 }1018 }
1015 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var50))1019 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var50))
1016 if templ_7745c5c3_Err != nil {1020 if templ_7745c5c3_Err != nil {
@@ -1033,7 +1037,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
1033 var templ_7745c5c3_Var51 string1037 var templ_7745c5c3_Var51 string
1034 templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Canonical)1038 templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Canonical)
1035 if templ_7745c5c3_Err != nil {1039 if templ_7745c5c3_Err != nil {
1036- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 191, Col: 32}1040+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 192, Col: 32}
1037 }1041 }
1038 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var51)1042 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var51)
1039 if templ_7745c5c3_Err != nil {1043 if templ_7745c5c3_Err != nil {
@@ -1052,7 +1056,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
1052 var templ_7745c5c3_Var52 string1056 var templ_7745c5c3_Var52 string
1053 templ_7745c5c3_Var52, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)1057 templ_7745c5c3_Var52, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
1054 if templ_7745c5c3_Err != nil {1058 if templ_7745c5c3_Err != nil {
1055- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 194, Col: 22}1059+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 195, Col: 22}
1056 }1060 }
1057 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var52)1061 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var52)
1058 if templ_7745c5c3_Err != nil {1062 if templ_7745c5c3_Err != nil {
@@ -1070,7 +1074,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
1070 var templ_7745c5c3_Var53 string1074 var templ_7745c5c3_Var53 string
1071 templ_7745c5c3_Var53, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)1075 templ_7745c5c3_Var53, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
1072 if templ_7745c5c3_Err != nil {1076 if templ_7745c5c3_Err != nil {
1073- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 196, Col: 22}1077+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 197, Col: 22}
1074 }1078 }
1075 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var53)1079 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var53)
1076 if templ_7745c5c3_Err != nil {1080 if templ_7745c5c3_Err != nil {
@@ -1110,7 +1114,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
1110 var templ_7745c5c3_Var54 string1114 var templ_7745c5c3_Var54 string
1111 templ_7745c5c3_Var54, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.NUnresolved))1115 templ_7745c5c3_Var54, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.NUnresolved))
1112 if templ_7745c5c3_Err != nil {1116 if templ_7745c5c3_Err != nil {
1113- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 209, Col: 97}1117+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 210, Col: 97}
1114 }1118 }
1115 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var54))1119 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var54))
1116 if templ_7745c5c3_Err != nil {1120 if templ_7745c5c3_Err != nil {
@@ -1123,7 +1127,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
1123 var templ_7745c5c3_Var55 string1127 var templ_7745c5c3_Var55 string
1124 templ_7745c5c3_Var55, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.NComments))1128 templ_7745c5c3_Var55, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.NComments))
1125 if templ_7745c5c3_Err != nil {1129 if templ_7745c5c3_Err != nil {
1126- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 209, Col: 126}1130+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 210, Col: 126}
1127 }1131 }
1128 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var55))1132 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var55))
1129 if templ_7745c5c3_Err != nil {1133 if templ_7745c5c3_Err != nil {
@@ -1204,7 +1208,7 @@ func branchLink(name, href string) templ.Component {
1204 var templ_7745c5c3_Var57 templ.SafeURL1208 var templ_7745c5c3_Var57 templ.SafeURL
1205 templ_7745c5c3_Var57, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))1209 templ_7745c5c3_Var57, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))
1206 if templ_7745c5c3_Err != nil {1210 if templ_7745c5c3_Err != nil {
1207- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 227, Col: 31}1211+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 228, Col: 31}
1208 }1212 }
1209 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var57))1213 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var57))
1210 if templ_7745c5c3_Err != nil {1214 if templ_7745c5c3_Err != nil {
@@ -1217,7 +1221,7 @@ func branchLink(name, href string) templ.Component {
1217 var templ_7745c5c3_Var58 string1221 var templ_7745c5c3_Var58 string
1218 templ_7745c5c3_Var58, templ_7745c5c3_Err = templ.JoinStringErrs(name)1222 templ_7745c5c3_Var58, templ_7745c5c3_Err = templ.JoinStringErrs(name)
1219 if templ_7745c5c3_Err != nil {1223 if templ_7745c5c3_Err != nil {
1220- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 227, Col: 40}1224+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 228, Col: 40}
1221 }1225 }
1222 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var58))1226 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var58))
1223 if templ_7745c5c3_Err != nil {1227 if templ_7745c5c3_Err != nil {
@@ -1231,7 +1235,7 @@ func branchLink(name, href string) templ.Component {
1231 var templ_7745c5c3_Var59 string1235 var templ_7745c5c3_Var59 string
1232 templ_7745c5c3_Var59, templ_7745c5c3_Err = templ.JoinStringErrs(name)1236 templ_7745c5c3_Var59, templ_7745c5c3_Err = templ.JoinStringErrs(name)
1233 if templ_7745c5c3_Err != nil {1237 if templ_7745c5c3_Err != nil {
1234- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 229, Col: 8}1238+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 230, Col: 8}
1235 }1239 }
1236 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var59))1240 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var59))
1237 if templ_7745c5c3_Err != nil {1241 if templ_7745c5c3_Err != nil {
@@ -1312,7 +1316,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1312 var templ_7745c5c3_Var62 string1316 var templ_7745c5c3_Var62 string
1313 templ_7745c5c3_Var62, templ_7745c5c3_Err = templ.ResolveAttributeValue("c" + c.ID + suffix)1317 templ_7745c5c3_Var62, templ_7745c5c3_Err = templ.ResolveAttributeValue("c" + c.ID + suffix)
1314 if templ_7745c5c3_Err != nil {1318 if templ_7745c5c3_Err != nil {
1315- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 248, Col: 42}1319+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 249, Col: 42}
1316 }1320 }
1317 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var62)1321 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var62)
1318 if templ_7745c5c3_Err != nil {1322 if templ_7745c5c3_Err != nil {
@@ -1325,7 +1329,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1325 var templ_7745c5c3_Var63 string1329 var templ_7745c5c3_Var63 string
1326 templ_7745c5c3_Var63, templ_7745c5c3_Err = templ.ResolveAttributeValue(boolText(c.Resolved))1330 templ_7745c5c3_Var63, templ_7745c5c3_Err = templ.ResolveAttributeValue(boolText(c.Resolved))
1327 if templ_7745c5c3_Err != nil {1331 if templ_7745c5c3_Err != nil {
1328- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 248, Col: 81}1332+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 249, Col: 81}
1329 }1333 }
1330 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var63)1334 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var63)
1331 if templ_7745c5c3_Err != nil {1335 if templ_7745c5c3_Err != nil {
@@ -1348,7 +1352,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1348 var templ_7745c5c3_Var64 string1352 var templ_7745c5c3_Var64 string
1349 templ_7745c5c3_Var64, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)1353 templ_7745c5c3_Var64, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)
1350 if templ_7745c5c3_Err != nil {1354 if templ_7745c5c3_Err != nil {
1351- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 250, Col: 33}1355+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 251, Col: 33}
1352 }1356 }
1353 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var64))1357 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var64))
1354 if templ_7745c5c3_Err != nil {1358 if templ_7745c5c3_Err != nil {
@@ -1362,7 +1366,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1362 var templ_7745c5c3_Var65 string1366 var templ_7745c5c3_Var65 string
1363 templ_7745c5c3_Var65, templ_7745c5c3_Err = templ.JoinStringErrs(" ")1367 templ_7745c5c3_Var65, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
1364 if templ_7745c5c3_Err != nil {1368 if templ_7745c5c3_Err != nil {
1365- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 252, Col: 9}1369+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 253, Col: 9}
1366 }1370 }
1367 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var65))1371 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var65))
1368 if templ_7745c5c3_Err != nil {1372 if templ_7745c5c3_Err != nil {
@@ -1375,7 +1379,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1375 var templ_7745c5c3_Var66 string1379 var templ_7745c5c3_Var66 string
1376 templ_7745c5c3_Var66, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)1380 templ_7745c5c3_Var66, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)
1377 if templ_7745c5c3_Err != nil {1381 if templ_7745c5c3_Err != nil {
1378- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 252, Col: 49}1382+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 253, Col: 49}
1379 }1383 }
1380 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var66)1384 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var66)
1381 if templ_7745c5c3_Err != nil {1385 if templ_7745c5c3_Err != nil {
@@ -1388,7 +1392,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1388 var templ_7745c5c3_Var67 string1392 var templ_7745c5c3_Var67 string
1389 templ_7745c5c3_Var67, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.Abs)1393 templ_7745c5c3_Var67, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.Abs)
1390 if templ_7745c5c3_Err != nil {1394 if templ_7745c5c3_Err != nil {
1391- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 252, Col: 65}1395+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 253, Col: 65}
1392 }1396 }
1393 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var67)1397 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var67)
1394 if templ_7745c5c3_Err != nil {1398 if templ_7745c5c3_Err != nil {
@@ -1401,7 +1405,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1401 var templ_7745c5c3_Var68 string1405 var templ_7745c5c3_Var68 string
1402 templ_7745c5c3_Var68, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)1406 templ_7745c5c3_Var68, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)
1403 if templ_7745c5c3_Err != nil {1407 if templ_7745c5c3_Err != nil {
1404- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 252, Col: 76}1408+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 253, Col: 76}
1405 }1409 }
1406 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var68))1410 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var68))
1407 if templ_7745c5c3_Err != nil {1411 if templ_7745c5c3_Err != nil {
@@ -1416,7 +1420,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1416 var templ_7745c5c3_Var69 string1420 var templ_7745c5c3_Var69 string
1417 templ_7745c5c3_Var69, templ_7745c5c3_Err = templ.JoinStringErrs(" ")1421 templ_7745c5c3_Var69, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
1418 if templ_7745c5c3_Err != nil {1422 if templ_7745c5c3_Err != nil {
1419- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 255, Col: 9}1423+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 256, Col: 9}
1420 }1424 }
1421 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var69))1425 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var69))
1422 if templ_7745c5c3_Err != nil {1426 if templ_7745c5c3_Err != nil {
@@ -1431,7 +1435,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1431 var templ_7745c5c3_Var70 string1435 var templ_7745c5c3_Var70 string
1432 templ_7745c5c3_Var70, templ_7745c5c3_Err = templ.JoinStringErrs(" ")1436 templ_7745c5c3_Var70, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
1433 if templ_7745c5c3_Err != nil {1437 if templ_7745c5c3_Err != nil {
1434- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 258, Col: 9}1438+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 259, Col: 9}
1435 }1439 }
1436 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var70))1440 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var70))
1437 if templ_7745c5c3_Err != nil {1441 if templ_7745c5c3_Err != nil {
@@ -1446,7 +1450,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1446 var templ_7745c5c3_Var71 string1450 var templ_7745c5c3_Var71 string
1447 templ_7745c5c3_Var71, templ_7745c5c3_Err = templ.JoinStringErrs(" ")1451 templ_7745c5c3_Var71, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
1448 if templ_7745c5c3_Err != nil {1452 if templ_7745c5c3_Err != nil {
1449- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 261, Col: 9}1453+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 262, Col: 9}
1450 }1454 }
1451 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var71))1455 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var71))
1452 if templ_7745c5c3_Err != nil {1456 if templ_7745c5c3_Err != nil {
@@ -1459,7 +1463,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1459 var templ_7745c5c3_Var72 string1463 var templ_7745c5c3_Var72 string
1460 templ_7745c5c3_Var72, templ_7745c5c3_Err = templ.JoinStringErrs(c.Where)1464 templ_7745c5c3_Var72, templ_7745c5c3_Err = templ.JoinStringErrs(c.Where)
1461 if templ_7745c5c3_Err != nil {1465 if templ_7745c5c3_Err != nil {
1462- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 261, Col: 47}1466+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 262, Col: 47}
1463 }1467 }
1464 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var72))1468 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var72))
1465 if templ_7745c5c3_Err != nil {1469 if templ_7745c5c3_Err != nil {
@@ -1534,7 +1538,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1534 var templ_7745c5c3_Var73 string1538 var templ_7745c5c3_Var73 string
1535 templ_7745c5c3_Var73, templ_7745c5c3_Err = templ.JoinStringErrs(c.Verdict)1539 templ_7745c5c3_Var73, templ_7745c5c3_Err = templ.JoinStringErrs(c.Verdict)
1536 if templ_7745c5c3_Err != nil {1540 if templ_7745c5c3_Err != nil {
1537- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 285, Col: 36}1541+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 286, Col: 36}
1538 }1542 }
1539 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var73))1543 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var73))
1540 if templ_7745c5c3_Err != nil {1544 if templ_7745c5c3_Err != nil {
@@ -1553,7 +1557,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1553 var templ_7745c5c3_Var74 string1557 var templ_7745c5c3_Var74 string
1554 templ_7745c5c3_Var74, templ_7745c5c3_Err = templ.JoinStringErrs(c.Range)1558 templ_7745c5c3_Var74, templ_7745c5c3_Err = templ.JoinStringErrs(c.Range)
1555 if templ_7745c5c3_Err != nil {1559 if templ_7745c5c3_Err != nil {
1556- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 288, Col: 31}1560+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 289, Col: 31}
1557 }1561 }
1558 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var74))1562 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var74))
1559 if templ_7745c5c3_Err != nil {1563 if templ_7745c5c3_Err != nil {
@@ -1572,7 +1576,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1572 var templ_7745c5c3_Var75 string1576 var templ_7745c5c3_Var75 string
1573 templ_7745c5c3_Var75, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.Quote)1577 templ_7745c5c3_Var75, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.Quote)
1574 if templ_7745c5c3_Err != nil {1578 if templ_7745c5c3_Err != nil {
1575- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 291, Col: 65}1579+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 292, Col: 65}
1576 }1580 }
1577 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var75)1581 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var75)
1578 if templ_7745c5c3_Err != nil {1582 if templ_7745c5c3_Err != nil {
@@ -1591,7 +1595,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1591 var templ_7745c5c3_Var76 templ.SafeURL1595 var templ_7745c5c3_Var76 templ.SafeURL
1592 templ_7745c5c3_Var76, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Edit.Action))1596 templ_7745c5c3_Var76, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Edit.Action))
1593 if templ_7745c5c3_Err != nil {1597 if templ_7745c5c3_Err != nil {
1594- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 294, Col: 92}1598+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 295, Col: 92}
1595 }1599 }
1596 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var76))1600 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var76))
1597 if templ_7745c5c3_Err != nil {1601 if templ_7745c5c3_Err != nil {
@@ -1604,7 +1608,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1604 var templ_7745c5c3_Var77 string1608 var templ_7745c5c3_Var77 string
1605 templ_7745c5c3_Var77, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(c.Edit.From))1609 templ_7745c5c3_Var77, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(c.Edit.From))
1606 if templ_7745c5c3_Err != nil {1610 if templ_7745c5c3_Err != nil {
1607- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 294, Col: 153}1611+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 295, Col: 153}
1608 }1612 }
1609 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var77)1613 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var77)
1610 if templ_7745c5c3_Err != nil {1614 if templ_7745c5c3_Err != nil {
@@ -1617,7 +1621,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1617 var templ_7745c5c3_Var78 string1621 var templ_7745c5c3_Var78 string
1618 templ_7745c5c3_Var78, templ_7745c5c3_Err = templ.JoinStringErrs(c.Edit.Text)1622 templ_7745c5c3_Var78, templ_7745c5c3_Err = templ.JoinStringErrs(c.Edit.Text)
1619 if templ_7745c5c3_Err != nil {1623 if templ_7745c5c3_Err != nil {
1620- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 294, Col: 209}1624+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 295, Col: 209}
1621 }1625 }
1622 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var78))1626 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var78))
1623 if templ_7745c5c3_Err != nil {1627 if templ_7745c5c3_Err != nil {
@@ -1636,7 +1640,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1636 var templ_7745c5c3_Var79 templ.SafeURL1640 var templ_7745c5c3_Var79 templ.SafeURL
1637 templ_7745c5c3_Var79, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Delete.Action))1641 templ_7745c5c3_Var79, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Delete.Action))
1638 if templ_7745c5c3_Err != nil {1642 if templ_7745c5c3_Err != nil {
1639- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 297, Col: 96}1643+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 298, Col: 96}
1640 }1644 }
1641 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var79))1645 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var79))
1642 if templ_7745c5c3_Err != nil {1646 if templ_7745c5c3_Err != nil {
@@ -1649,7 +1653,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1649 var templ_7745c5c3_Var80 string1653 var templ_7745c5c3_Var80 string
1650 templ_7745c5c3_Var80, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(c.Delete.From))1654 templ_7745c5c3_Var80, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(c.Delete.From))
1651 if templ_7745c5c3_Err != nil {1655 if templ_7745c5c3_Err != nil {
1652- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 297, Col: 159}1656+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 298, Col: 159}
1653 }1657 }
1654 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var80)1658 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var80)
1655 if templ_7745c5c3_Err != nil {1659 if templ_7745c5c3_Err != nil {
@@ -1688,7 +1692,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1688 var templ_7745c5c3_Var81 templ.SafeURL1692 var templ_7745c5c3_Var81 templ.SafeURL
1689 templ_7745c5c3_Var81, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Resolve.Action))1693 templ_7745c5c3_Var81, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Resolve.Action))
1690 if templ_7745c5c3_Err != nil {1694 if templ_7745c5c3_Err != nil {
1691- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 308, Col: 77}1695+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 309, Col: 77}
1692 }1696 }
1693 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var81))1697 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var81))
1694 if templ_7745c5c3_Err != nil {1698 if templ_7745c5c3_Err != nil {
@@ -1701,7 +1705,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1701 var templ_7745c5c3_Var82 string1705 var templ_7745c5c3_Var82 string
1702 templ_7745c5c3_Var82, templ_7745c5c3_Err = templ.ResolveAttributeValue(boolText(c.Resolve.Value))1706 templ_7745c5c3_Var82, templ_7745c5c3_Err = templ.ResolveAttributeValue(boolText(c.Resolve.Value))
1703 if templ_7745c5c3_Err != nil {1707 if templ_7745c5c3_Err != nil {
1704- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 309, Col: 74}1708+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 310, Col: 74}
1705 }1709 }
1706 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var82)1710 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var82)
1707 if templ_7745c5c3_Err != nil {1711 if templ_7745c5c3_Err != nil {
@@ -1719,7 +1723,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1719 var templ_7745c5c3_Var83 string1723 var templ_7745c5c3_Var83 string
1720 templ_7745c5c3_Var83, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(c.Resolve.From))1724 templ_7745c5c3_Var83, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(c.Resolve.From))
1721 if templ_7745c5c3_Err != nil {1725 if templ_7745c5c3_Err != nil {
1722- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 311, Col: 66}1726+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 312, Col: 66}
1723 }1727 }
1724 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var83)1728 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var83)
1725 if templ_7745c5c3_Err != nil {1729 if templ_7745c5c3_Err != nil {
@@ -1737,7 +1741,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1737 var templ_7745c5c3_Var84 string1741 var templ_7745c5c3_Var84 string
1738 templ_7745c5c3_Var84, templ_7745c5c3_Err = templ.JoinStringErrs(c.Resolve.Label)1742 templ_7745c5c3_Var84, templ_7745c5c3_Err = templ.JoinStringErrs(c.Resolve.Label)
1739 if templ_7745c5c3_Err != nil {1743 if templ_7745c5c3_Err != nil {
1740- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 313, Col: 55}1744+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 314, Col: 55}
1741 }1745 }
1742 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var84))1746 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var84))
1743 if templ_7745c5c3_Err != nil {1747 if templ_7745c5c3_Err != nil {
@@ -1792,7 +1796,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1792 var templ_7745c5c3_Var86 templ.SafeURL1796 var templ_7745c5c3_Var86 templ.SafeURL
1793 templ_7745c5c3_Var86, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(f.Action))1797 templ_7745c5c3_Var86, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(f.Action))
1794 if templ_7745c5c3_Err != nil {1798 if templ_7745c5c3_Err != nil {
1795- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 328, Col: 67}1799+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 329, Col: 67}
1796 }1800 }
1797 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var86))1801 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var86))
1798 if templ_7745c5c3_Err != nil {1802 if templ_7745c5c3_Err != nil {
@@ -1805,7 +1809,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1805 var templ_7745c5c3_Var87 string1809 var templ_7745c5c3_Var87 string
1806 templ_7745c5c3_Var87, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID + suffix)1810 templ_7745c5c3_Var87, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID + suffix)
1807 if templ_7745c5c3_Err != nil {1811 if templ_7745c5c3_Err != nil {
1808- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 329, Col: 28}1812+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 330, Col: 28}
1809 }1813 }
1810 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var87)1814 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var87)
1811 if templ_7745c5c3_Err != nil {1815 if templ_7745c5c3_Err != nil {
@@ -1818,7 +1822,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1818 var templ_7745c5c3_Var88 string1822 var templ_7745c5c3_Var88 string
1819 templ_7745c5c3_Var88, templ_7745c5c3_Err = templ.JoinStringErrs(f.Title)1823 templ_7745c5c3_Var88, templ_7745c5c3_Err = templ.JoinStringErrs(f.Title)
1820 if templ_7745c5c3_Err != nil {1824 if templ_7745c5c3_Err != nil {
1821- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 329, Col: 40}1825+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 330, Col: 40}
1822 }1826 }
1823 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var88))1827 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var88))
1824 if templ_7745c5c3_Err != nil {1828 if templ_7745c5c3_Err != nil {
@@ -1831,7 +1835,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1831 var templ_7745c5c3_Var89 string1835 var templ_7745c5c3_Var89 string
1832 templ_7745c5c3_Var89, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID + suffix)1836 templ_7745c5c3_Var89, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID + suffix)
1833 if templ_7745c5c3_Err != nil {1837 if templ_7745c5c3_Err != nil {
1834- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 331, Col: 21}1838+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 332, Col: 21}
1835 }1839 }
1836 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var89)1840 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var89)
1837 if templ_7745c5c3_Err != nil {1841 if templ_7745c5c3_Err != nil {
@@ -1870,7 +1874,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1870 var templ_7745c5c3_Var90 string1874 var templ_7745c5c3_Var90 string
1871 templ_7745c5c3_Var90, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Path)1875 templ_7745c5c3_Var90, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Path)
1872 if templ_7745c5c3_Err != nil {1876 if templ_7745c5c3_Err != nil {
1873- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 346, Col: 50}1877+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 347, Col: 50}
1874 }1878 }
1875 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var90)1879 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var90)
1876 if templ_7745c5c3_Err != nil {1880 if templ_7745c5c3_Err != nil {
@@ -1883,7 +1887,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1883 var templ_7745c5c3_Var91 string1887 var templ_7745c5c3_Var91 string
1884 templ_7745c5c3_Var91, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Line)1888 templ_7745c5c3_Var91, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Line)
1885 if templ_7745c5c3_Err != nil {1889 if templ_7745c5c3_Err != nil {
1886- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 347, Col: 50}1890+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 348, Col: 50}
1887 }1891 }
1888 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var91)1892 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var91)
1889 if templ_7745c5c3_Err != nil {1893 if templ_7745c5c3_Err != nil {
@@ -1896,7 +1900,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1896 var templ_7745c5c3_Var92 string1900 var templ_7745c5c3_Var92 string
1897 templ_7745c5c3_Var92, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Side)1901 templ_7745c5c3_Var92, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Side)
1898 if templ_7745c5c3_Err != nil {1902 if templ_7745c5c3_Err != nil {
1899- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 348, Col: 50}1903+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 349, Col: 50}
1900 }1904 }
1901 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var92)1905 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var92)
1902 if templ_7745c5c3_Err != nil {1906 if templ_7745c5c3_Err != nil {
@@ -1909,7 +1913,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1909 var templ_7745c5c3_Var93 string1913 var templ_7745c5c3_Var93 string
1910 templ_7745c5c3_Var93, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.StartLine)1914 templ_7745c5c3_Var93, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.StartLine)
1911 if templ_7745c5c3_Err != nil {1915 if templ_7745c5c3_Err != nil {
1912- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 349, Col: 86}1916+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 350, Col: 86}
1913 }1917 }
1914 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var93)1918 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var93)
1915 if templ_7745c5c3_Err != nil {1919 if templ_7745c5c3_Err != nil {
@@ -1928,7 +1932,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1928 var templ_7745c5c3_Var94 string1932 var templ_7745c5c3_Var94 string
1929 templ_7745c5c3_Var94, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ReplyTo)1933 templ_7745c5c3_Var94, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ReplyTo)
1930 if templ_7745c5c3_Err != nil {1934 if templ_7745c5c3_Err != nil {
1931- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 352, Col: 57}1935+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 353, Col: 57}
1932 }1936 }
1933 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var94)1937 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var94)
1934 if templ_7745c5c3_Err != nil {1938 if templ_7745c5c3_Err != nil {
@@ -1953,7 +1957,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1953 var templ_7745c5c3_Var95 string1957 var templ_7745c5c3_Var95 string
1954 templ_7745c5c3_Var95, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(f.From))1958 templ_7745c5c3_Var95, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(f.From))
1955 if templ_7745c5c3_Err != nil {1959 if templ_7745c5c3_Err != nil {
1956- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 358, Col: 56}1960+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 359, Col: 56}
1957 }1961 }
1958 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var95)1962 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var95)
1959 if templ_7745c5c3_Err != nil {1963 if templ_7745c5c3_Err != nil {
@@ -1976,7 +1980,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1976 var templ_7745c5c3_Var96 templ.SafeURL1980 var templ_7745c5c3_Var96 templ.SafeURL
1977 templ_7745c5c3_Var96, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(f.Cancel))1981 templ_7745c5c3_Var96, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(f.Cancel))
1978 if templ_7745c5c3_Err != nil {1982 if templ_7745c5c3_Err != nil {
1979- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 363, Col: 49}1983+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 364, Col: 49}
1980 }1984 }
1981 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var96))1985 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var96))
1982 if templ_7745c5c3_Err != nil {1986 if templ_7745c5c3_Err != nil {
@@ -1995,7 +1999,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1995 })1999 })
1996 }2000 }
1997 2001
1998-func mrRail(p MRPage) templ.Component {2002+func mrFooter(p MRPage) templ.Component {
1999 return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {2003 return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
2000 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context2004 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
2001 if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {2005 if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -2016,312 +2020,349 @@ func mrRail(p MRPage) templ.Component {
2016 templ_7745c5c3_Var97 = templ.NopComponent2020 templ_7745c5c3_Var97 = templ.NopComponent
2017 }2021 }
2018 ctx = templ.ClearChildren(ctx)2022 ctx = templ.ClearChildren(ctx)
2019- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 185, "<section aria-labelledby=\"r-files\" class=\"r-files\"><h2 id=\"r-files\">Files <span class=\"count\">")2023+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 185, "<footer class=\"mr-footer\"><details id=\"mr-panels\"><summary>Commits <span class=\"count\">")
2020 if templ_7745c5c3_Err != nil {2024 if templ_7745c5c3_Err != nil {
2021 return templ_7745c5c3_Err2025 return templ_7745c5c3_Err
2022 }2026 }
2023 var templ_7745c5c3_Var98 string2027 var templ_7745c5c3_Var98 string
2024- templ_7745c5c3_Var98, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))2028+ templ_7745c5c3_Var98, templ_7745c5c3_Err = templ.JoinStringErrs(p.CommitCount)
2025 if templ_7745c5c3_Err != nil {2029 if templ_7745c5c3_Err != nil {
2026- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 372, Col: 49}2030+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 373, Col: 55}
2027 }2031 }
2028 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var98))2032 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var98))
2029 if templ_7745c5c3_Err != nil {2033 if templ_7745c5c3_Err != nil {
2030 return templ_7745c5c3_Err2034 return templ_7745c5c3_Err
2031 }2035 }
2032- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 186, "</span><kbd aria-hidden=\"true\">g f</kbd> <button type=\"button\" class=\"btn icon fold\" data-js aria-expanded=\"true\" title=\"fold the list of files\" hx-on:click=\"ermiteMR.foldFiles()\"><span class=\"ico i-chevron\" aria-hidden=\"true\"></span><span class=\"sr\">fold the list of files</span></button></h2>")2036+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 186, "</span> · Checks</summary><nav data-mr-tabs aria-label=\"Branch details\"><a id=\"mr-tab-commits\" href=\"#mr-commits\">Commits <span class=\"count\">")
2033 if templ_7745c5c3_Err != nil {2037 if templ_7745c5c3_Err != nil {
2034 return templ_7745c5c3_Err2038 return templ_7745c5c3_Err
2035 }2039 }
2036- templ_7745c5c3_Err = FileList(p.Files).Render(ctx, templ_7745c5c3_Buffer)2040+ var templ_7745c5c3_Var99 string
2041+ templ_7745c5c3_Var99, templ_7745c5c3_Err = templ.JoinStringErrs(p.CommitCount)
2037 if templ_7745c5c3_Err != nil {2042 if templ_7745c5c3_Err != nil {
2038- return templ_7745c5c3_Err2043+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 375, Col: 89}
2039 }2044 }
2040- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 187, "</section>")2045+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var99))
2041 if templ_7745c5c3_Err != nil {2046 if templ_7745c5c3_Err != nil {
2042 return templ_7745c5c3_Err2047 return templ_7745c5c3_Err
2043 }2048 }
2044- if len(p.Verdicts) > 0 {2049+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 187, "</span></a> <a id=\"mr-tab-checks\" href=\"#mr-checks\">")
2045- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 188, "<section><h2>Verdicts</h2><ul>")
2046- if templ_7745c5c3_Err != nil {
2047- return templ_7745c5c3_Err
2048- }
2049- for _, v := range p.Verdicts {
2050- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 189, "<li><a href=\"")
2051- if templ_7745c5c3_Err != nil {
2052- return templ_7745c5c3_Err
2053- }
2054- var templ_7745c5c3_Var99 templ.SafeURL
2055- templ_7745c5c3_Var99, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(v.Href))
2056- if templ_7745c5c3_Err != nil {
2057- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 385, Col: 37}
2058- }
2059- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var99))
2060- if templ_7745c5c3_Err != nil {
2061- return templ_7745c5c3_Err
2062- }
2063- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 190, "\">")
2064- if templ_7745c5c3_Err != nil {
2065- return templ_7745c5c3_Err
2066- }
2067- var templ_7745c5c3_Var100 string
2068- templ_7745c5c3_Var100, templ_7745c5c3_Err = templ.JoinStringErrs(v.Author)
2069- if templ_7745c5c3_Err != nil {
2070- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 385, Col: 50}
2071- }
2072- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var100))
2073- if templ_7745c5c3_Err != nil {
2074- return templ_7745c5c3_Err
2075- }
2076- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 191, ": ")
2077- if templ_7745c5c3_Err != nil {
2078- return templ_7745c5c3_Err
2079- }
2080- var templ_7745c5c3_Var101 string
2081- templ_7745c5c3_Var101, templ_7745c5c3_Err = templ.JoinStringErrs(v.Label)
2082- if templ_7745c5c3_Err != nil {
2083- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 385, Col: 63}
2084- }
2085- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var101))
2086- if templ_7745c5c3_Err != nil {
2087- return templ_7745c5c3_Err
2088- }
2089- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 192, "</a> ")
2090- if templ_7745c5c3_Err != nil {
2091- return templ_7745c5c3_Err
2092- }
2093- if v.Stale {
2094- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 193, "<span class=\"mute\">(stale)</span>")
2095- if templ_7745c5c3_Err != nil {
2096- return templ_7745c5c3_Err
2097- }
2098- }
2099- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 194, "</li>")
2100- if templ_7745c5c3_Err != nil {
2101- return templ_7745c5c3_Err
2102- }
2103- }
2104- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 195, "</ul></section>")
2105- if templ_7745c5c3_Err != nil {
2106- return templ_7745c5c3_Err
2107- }
2108- }
2109- templ_7745c5c3_Err = MRChecks(p.Checks).Render(ctx, templ_7745c5c3_Buffer)
2110 if templ_7745c5c3_Err != nil {2050 if templ_7745c5c3_Err != nil {
2111 return templ_7745c5c3_Err2051 return templ_7745c5c3_Err
2112 }2052 }
2113- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 196, "<section aria-labelledby=\"r-commits\"><h2 id=\"r-commits\">Commits <span class=\"count\">")2053+ var templ_7745c5c3_Var100 string
2054+ templ_7745c5c3_Var100, templ_7745c5c3_Err = templ.JoinStringErrs("Checks ")
2114 if templ_7745c5c3_Err != nil {2055 if templ_7745c5c3_Err != nil {
2115- return templ_7745c5c3_Err2056+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 377, Col: 16}
2116 }2057 }
2117- var templ_7745c5c3_Var102 string2058+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var100))
2118- templ_7745c5c3_Var102, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Commits)))
2119 if templ_7745c5c3_Err != nil {2059 if templ_7745c5c3_Err != nil {
2120- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 396, Col: 71}2060+ return templ_7745c5c3_Err
2121 }2061 }
2122- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var102))2062+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 188, " <span data-checks-label>")
2123 if templ_7745c5c3_Err != nil {2063 if templ_7745c5c3_Err != nil {
2124 return templ_7745c5c3_Err2064 return templ_7745c5c3_Err
2125 }2065 }
2126- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 197, "</span></h2><ul class=\"pcommits\">")2066+ if p.ChecksSum.Total > 0 {
2067+ var templ_7745c5c3_Var101 string
2068+ templ_7745c5c3_Var101, templ_7745c5c3_Err = templ.JoinStringErrs(p.ChecksSum.Title)
2069+ if templ_7745c5c3_Err != nil {
2070+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 380, Col: 26}
2071+ }
2072+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var101))
2073+ if templ_7745c5c3_Err != nil {
2074+ return templ_7745c5c3_Err
2075+ }
2076+ } else {
2077+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 189, "no checks")
2078+ if templ_7745c5c3_Err != nil {
2079+ return templ_7745c5c3_Err
2080+ }
2081+ }
2082+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 190, "</span></a></nav><div id=\"mr-commits\" data-mr-panel aria-labelledby=\"mr-tab-commits\"><table class=\"mr-commits\"><thead><tr><th>Commit</th><th>Subject</th><th>Author</th><th>Date</th><th>Signature</th><th>Status</th></tr></thead> <tbody>")
2127 if templ_7745c5c3_Err != nil {2083 if templ_7745c5c3_Err != nil {
2128 return templ_7745c5c3_Err2084 return templ_7745c5c3_Err
2129 }2085 }
2130 for _, c := range p.Commits {2086 for _, c := range p.Commits {
2131- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 198, "<li")2087+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 191, "<tr")
2132 if templ_7745c5c3_Err != nil {2088 if templ_7745c5c3_Err != nil {
2133 return templ_7745c5c3_Err2089 return templ_7745c5c3_Err
2134 }2090 }
2135 if c.New {2091 if c.New {
2136- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 199, " data-new")2092+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 192, " data-new")
2137 if templ_7745c5c3_Err != nil {2093 if templ_7745c5c3_Err != nil {
2138 return templ_7745c5c3_Err2094 return templ_7745c5c3_Err
2139 }2095 }
2140 }2096 }
2141- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 200, "><a href=\"")2097+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 193, "><td><a href=\"")
2142 if templ_7745c5c3_Err != nil {2098 if templ_7745c5c3_Err != nil {
2143 return templ_7745c5c3_Err2099 return templ_7745c5c3_Err
2144 }2100 }
2145- var templ_7745c5c3_Var103 templ.SafeURL2101+ var templ_7745c5c3_Var102 templ.SafeURL
2146- templ_7745c5c3_Var103, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Href))2102+ templ_7745c5c3_Var102, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Href))
2147 if templ_7745c5c3_Err != nil {2103 if templ_7745c5c3_Err != nil {
2148- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 400, Col: 36}2104+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 393, Col: 43}
2149 }2105 }
2150- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var103))2106+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var102))
2151 if templ_7745c5c3_Err != nil {2107 if templ_7745c5c3_Err != nil {
2152 return templ_7745c5c3_Err2108 return templ_7745c5c3_Err
2153 }2109 }
2154- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 201, "\">")2110+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 194, "\">")
2155 if templ_7745c5c3_Err != nil {2111 if templ_7745c5c3_Err != nil {
2156 return templ_7745c5c3_Err2112 return templ_7745c5c3_Err
2157 }2113 }
2158- var templ_7745c5c3_Var104 string2114+ var templ_7745c5c3_Var103 string
2159- templ_7745c5c3_Var104, templ_7745c5c3_Err = templ.JoinStringErrs(c.Short)2115+ templ_7745c5c3_Var103, templ_7745c5c3_Err = templ.JoinStringErrs(c.Short)
2160 if templ_7745c5c3_Err != nil {2116 if templ_7745c5c3_Err != nil {
2161- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 400, Col: 48}2117+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 393, Col: 55}
2162 }2118 }
2163- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var104))2119+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var103))
2164 if templ_7745c5c3_Err != nil {2120 if templ_7745c5c3_Err != nil {
2165 return templ_7745c5c3_Err2121 return templ_7745c5c3_Err
2166 }2122 }
2167- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 202, "</a> <span class=\"s\">")2123+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 195, "</a></td><td>")
2168 if templ_7745c5c3_Err != nil {2124 if templ_7745c5c3_Err != nil {
2169 return templ_7745c5c3_Err2125 return templ_7745c5c3_Err
2170 }2126 }
2171- var templ_7745c5c3_Var105 string2127+ var templ_7745c5c3_Var104 string
2172- templ_7745c5c3_Var105, templ_7745c5c3_Err = templ.JoinStringErrs(c.Subject)2128+ templ_7745c5c3_Var104, templ_7745c5c3_Err = templ.JoinStringErrs(c.Subject)
2173 if templ_7745c5c3_Err != nil {2129 if templ_7745c5c3_Err != nil {
2174- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 401, Col: 32}2130+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 394, Col: 23}
2175 }2131 }
2176- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var105))2132+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var104))
2177 if templ_7745c5c3_Err != nil {2133 if templ_7745c5c3_Err != nil {
2178 return templ_7745c5c3_Err2134 return templ_7745c5c3_Err
2179 }2135 }
2180- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 203, "</span> ")2136+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 196, "</td><td>")
2181 if templ_7745c5c3_Err != nil {2137 if templ_7745c5c3_Err != nil {
2182 return templ_7745c5c3_Err2138 return templ_7745c5c3_Err
2183 }2139 }
2184- if c.Sig != nil {2140+ var templ_7745c5c3_Var105 string
2185- templ_7745c5c3_Err = signaturePill(c.Sig).Render(ctx, templ_7745c5c3_Buffer)2141+ templ_7745c5c3_Var105, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)
2186- if templ_7745c5c3_Err != nil {
2187- return templ_7745c5c3_Err
2188- }
2189- }
2190- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 204, "<span class=\"mute\">")
2191- if templ_7745c5c3_Err != nil {
2192- return templ_7745c5c3_Err
2193- }
2194- var templ_7745c5c3_Var106 string
2195- templ_7745c5c3_Var106, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)
2196 if templ_7745c5c3_Err != nil {2142 if templ_7745c5c3_Err != nil {
2197- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 406, Col: 16}2143+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 395, Col: 22}
2198 }2144 }
2199- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var106))2145+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var105))
2200 if templ_7745c5c3_Err != nil {2146 if templ_7745c5c3_Err != nil {
2201 return templ_7745c5c3_Err2147 return templ_7745c5c3_Err
2202 }2148 }
2203- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 205, " ")2149+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 197, "</td><td>")
2204 if templ_7745c5c3_Err != nil {2150 if templ_7745c5c3_Err != nil {
2205 return templ_7745c5c3_Err2151 return templ_7745c5c3_Err
2206 }2152 }
2207 if c.WhenAt != "" {2153 if c.WhenAt != "" {
2208- var templ_7745c5c3_Var107 string2154+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 198, "<time datetime=\"")
2209- templ_7745c5c3_Var107, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")
2210- if templ_7745c5c3_Err != nil {
2211- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 408, Col: 15}
2212- }
2213- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var107))
2214 if templ_7745c5c3_Err != nil {2155 if templ_7745c5c3_Err != nil {
2215 return templ_7745c5c3_Err2156 return templ_7745c5c3_Err
2216 }2157 }
2217- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 206, "<time datetime=\"")2158+ var templ_7745c5c3_Var106 string
2159+ templ_7745c5c3_Var106, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)
2218 if templ_7745c5c3_Err != nil {2160 if templ_7745c5c3_Err != nil {
2219- return templ_7745c5c3_Err2161+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 398, Col: 35}
2220 }2162 }
2221- var templ_7745c5c3_Var108 string2163+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var106)
2222- templ_7745c5c3_Var108, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)
2223- if templ_7745c5c3_Err != nil {
2224- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 408, Col: 42}
2225- }
2226- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var108)
2227 if templ_7745c5c3_Err != nil {2164 if templ_7745c5c3_Err != nil {
2228 return templ_7745c5c3_Err2165 return templ_7745c5c3_Err
2229 }2166 }
2230- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 207, "\">")2167+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 199, "\">")
2231 if templ_7745c5c3_Err != nil {2168 if templ_7745c5c3_Err != nil {
2232 return templ_7745c5c3_Err2169 return templ_7745c5c3_Err
2233 }2170 }
2234- var templ_7745c5c3_Var109 string2171+ var templ_7745c5c3_Var107 string
2235- templ_7745c5c3_Var109, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)2172+ templ_7745c5c3_Var107, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)
2236 if templ_7745c5c3_Err != nil {2173 if templ_7745c5c3_Err != nil {
2237- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 408, Col: 53}2174+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 398, Col: 46}
2238 }2175 }
2239- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var109))2176+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var107))
2240 if templ_7745c5c3_Err != nil {2177 if templ_7745c5c3_Err != nil {
2241 return templ_7745c5c3_Err2178 return templ_7745c5c3_Err
2242 }2179 }
2243- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 208, "</time> ")2180+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 200, "</time>")
2244 if templ_7745c5c3_Err != nil {2181 if templ_7745c5c3_Err != nil {
2245 return templ_7745c5c3_Err2182 return templ_7745c5c3_Err
2246 }2183 }
2247 }2184 }
2248- if c.New {2185+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 201, "</td><td>")
2249- var templ_7745c5c3_Var110 string2186+ if templ_7745c5c3_Err != nil {
2250- templ_7745c5c3_Var110, templ_7745c5c3_Err = templ.JoinStringErrs(" · new")2187+ return templ_7745c5c3_Err
2188+ }
2189+ if c.Sig != nil {
2190+ templ_7745c5c3_Err = signaturePill(c.Sig).Render(ctx, templ_7745c5c3_Buffer)
2251 if templ_7745c5c3_Err != nil {2191 if templ_7745c5c3_Err != nil {
2252- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 411, Col: 18}2192+ return templ_7745c5c3_Err
2253 }2193 }
2254- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var110))2194+ }
2195+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 202, "</td><td>")
2196+ if templ_7745c5c3_Err != nil {
2197+ return templ_7745c5c3_Err
2198+ }
2199+ if c.New {
2200+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 203, "<span>new</span>")
2255 if templ_7745c5c3_Err != nil {2201 if templ_7745c5c3_Err != nil {
2256 return templ_7745c5c3_Err2202 return templ_7745c5c3_Err
2257 }2203 }
2258 }2204 }
2259- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 209, "</span></li>")2205+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 204, "</td></tr>")
2260 if templ_7745c5c3_Err != nil {2206 if templ_7745c5c3_Err != nil {
2261 return templ_7745c5c3_Err2207 return templ_7745c5c3_Err
2262 }2208 }
2263 }2209 }
2264- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 210, "</ul>")2210+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 205, "</tbody></table>")
2265 if templ_7745c5c3_Err != nil {2211 if templ_7745c5c3_Err != nil {
2266 return templ_7745c5c3_Err2212 return templ_7745c5c3_Err
2267 }2213 }
2268 if len(p.Commits) == 0 {2214 if len(p.Commits) == 0 {
2269- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 211, "<p class=\"dim\">no commit to merge.</p>")2215+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 206, "<p class=\"dim\">no commit to merge.</p>")
2270 if templ_7745c5c3_Err != nil {2216 if templ_7745c5c3_Err != nil {
2271 return templ_7745c5c3_Err2217 return templ_7745c5c3_Err
2272 }2218 }
2273 }2219 }
2274 if p.CommitsNote != "" {2220 if p.CommitsNote != "" {
2275- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 212, "<p class=\"note\">")2221+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 207, "<p class=\"note\">")
2276 if templ_7745c5c3_Err != nil {2222 if templ_7745c5c3_Err != nil {
2277 return templ_7745c5c3_Err2223 return templ_7745c5c3_Err
2278 }2224 }
2279- var templ_7745c5c3_Var111 string2225+ var templ_7745c5c3_Var108 string
2280- templ_7745c5c3_Var111, templ_7745c5c3_Err = templ.JoinStringErrs(p.CommitsNote)2226+ templ_7745c5c3_Var108, templ_7745c5c3_Err = templ.JoinStringErrs(p.CommitsNote)
2281 if templ_7745c5c3_Err != nil {2227 if templ_7745c5c3_Err != nil {
2282- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 421, Col: 34}2228+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 419, Col: 36}
2283 }2229 }
2284- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var111))2230+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var108))
2285 if templ_7745c5c3_Err != nil {2231 if templ_7745c5c3_Err != nil {
2286 return templ_7745c5c3_Err2232 return templ_7745c5c3_Err
2287 }2233 }
2288- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 213, "</p>")2234+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 208, "</p>")
2289 if templ_7745c5c3_Err != nil {2235 if templ_7745c5c3_Err != nil {
2290 return templ_7745c5c3_Err2236 return templ_7745c5c3_Err
2291 }2237 }
2292 }2238 }
2293- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 214, "</section><section aria-labelledby=\"r-settings\"><h2 id=\"r-settings\">Settings</h2><dl class=\"kv\"><dt>modes</dt><dd>")2239+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 209, "</div><div id=\"mr-checks-panel\" data-mr-panel aria-labelledby=\"mr-tab-checks\">")
2294 if templ_7745c5c3_Err != nil {2240 if templ_7745c5c3_Err != nil {
2295 return templ_7745c5c3_Err2241 return templ_7745c5c3_Err
2296 }2242 }
2297- var templ_7745c5c3_Var112 string2243+ templ_7745c5c3_Err = MRChecks(p.Checks).Render(ctx, templ_7745c5c3_Buffer)
2298- templ_7745c5c3_Var112, templ_7745c5c3_Err = templ.JoinStringErrs(strings.Join(p.Modes, ", "))
2299 if templ_7745c5c3_Err != nil {2244 if templ_7745c5c3_Err != nil {
2300- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 428, Col: 36}2245+ return templ_7745c5c3_Err
2246+ }
2247+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 210, "</div></details></footer>")
2248+ if templ_7745c5c3_Err != nil {
2249+ return templ_7745c5c3_Err
2250+ }
2251+ return nil
2252+ })
2253+}
2254+
2255+func mrRail(p MRPage) templ.Component {
2256+ return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
2257+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
2258+ if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
2259+ return templ_7745c5c3_CtxErr
2301 }2260 }
2302- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var112))2261+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
2262+ if !templ_7745c5c3_IsBuffer {
2263+ defer func() {
2264+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
2265+ if templ_7745c5c3_Err == nil {
2266+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
2267+ }
2268+ }()
2269+ }
2270+ ctx = templ.InitializeContext(ctx)
2271+ templ_7745c5c3_Var109 := templ.GetChildren(ctx)
2272+ if templ_7745c5c3_Var109 == nil {
2273+ templ_7745c5c3_Var109 = templ.NopComponent
2274+ }
2275+ ctx = templ.ClearChildren(ctx)
2276+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 211, "<section aria-labelledby=\"r-files\" class=\"r-files\"><h2 id=\"r-files\">Files <span class=\"count\">")
2303 if templ_7745c5c3_Err != nil {2277 if templ_7745c5c3_Err != nil {
2304 return templ_7745c5c3_Err2278 return templ_7745c5c3_Err
2305 }2279 }
2306- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 215, "</dd><dt>checks</dt><dd>")2280+ var templ_7745c5c3_Var110 string
2281+ templ_7745c5c3_Var110, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))
2282+ if templ_7745c5c3_Err != nil {
2283+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 432, Col: 49}
2284+ }
2285+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var110))
2307 if templ_7745c5c3_Err != nil {2286 if templ_7745c5c3_Err != nil {
2308 return templ_7745c5c3_Err2287 return templ_7745c5c3_Err
2309 }2288 }
2310- if p.ChecksBlock {2289+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 212, "</span><kbd aria-hidden=\"true\">g f</kbd> <button type=\"button\" class=\"btn icon fold\" data-js aria-expanded=\"true\" title=\"fold the list of files\" hx-on:click=\"ermiteMR.foldFiles()\"><span class=\"ico i-chevron\" aria-hidden=\"true\"></span><span class=\"sr\">fold the list of files</span></button></h2>")
2311- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 216, "failing ones block the merge")2290+ if templ_7745c5c3_Err != nil {
2291+ return templ_7745c5c3_Err
2292+ }
2293+ templ_7745c5c3_Err = FileList(p.Files).Render(ctx, templ_7745c5c3_Buffer)
2294+ if templ_7745c5c3_Err != nil {
2295+ return templ_7745c5c3_Err
2296+ }
2297+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 213, "</section>")
2298+ if templ_7745c5c3_Err != nil {
2299+ return templ_7745c5c3_Err
2300+ }
2301+ if len(p.Verdicts) > 0 {
2302+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 214, "<section><h2>Verdicts</h2><ul>")
2312 if templ_7745c5c3_Err != nil {2303 if templ_7745c5c3_Err != nil {
2313 return templ_7745c5c3_Err2304 return templ_7745c5c3_Err
2314 }2305 }
2315- } else {2306+ for _, v := range p.Verdicts {
2316- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 217, "do not block the merge")2307+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 215, "<li><a href=\"")
2308+ if templ_7745c5c3_Err != nil {
2309+ return templ_7745c5c3_Err
2310+ }
2311+ var templ_7745c5c3_Var111 templ.SafeURL
2312+ templ_7745c5c3_Var111, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(v.Href))
2313+ if templ_7745c5c3_Err != nil {
2314+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 445, Col: 37}
2315+ }
2316+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var111))
2317+ if templ_7745c5c3_Err != nil {
2318+ return templ_7745c5c3_Err
2319+ }
2320+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 216, "\">")
2321+ if templ_7745c5c3_Err != nil {
2322+ return templ_7745c5c3_Err
2323+ }
2324+ var templ_7745c5c3_Var112 string
2325+ templ_7745c5c3_Var112, templ_7745c5c3_Err = templ.JoinStringErrs(v.Author)
2326+ if templ_7745c5c3_Err != nil {
2327+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 445, Col: 50}
2328+ }
2329+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var112))
2330+ if templ_7745c5c3_Err != nil {
2331+ return templ_7745c5c3_Err
2332+ }
2333+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 217, ": ")
2334+ if templ_7745c5c3_Err != nil {
2335+ return templ_7745c5c3_Err
2336+ }
2337+ var templ_7745c5c3_Var113 string
2338+ templ_7745c5c3_Var113, templ_7745c5c3_Err = templ.JoinStringErrs(v.Label)
2339+ if templ_7745c5c3_Err != nil {
2340+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 445, Col: 63}
2341+ }
2342+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var113))
2343+ if templ_7745c5c3_Err != nil {
2344+ return templ_7745c5c3_Err
2345+ }
2346+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 218, "</a> ")
2347+ if templ_7745c5c3_Err != nil {
2348+ return templ_7745c5c3_Err
2349+ }
2350+ if v.Stale {
2351+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 219, "<span class=\"mute\">(stale)</span>")
2352+ if templ_7745c5c3_Err != nil {
2353+ return templ_7745c5c3_Err
2354+ }
2355+ }
2356+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 220, "</li>")
2357+ if templ_7745c5c3_Err != nil {
2358+ return templ_7745c5c3_Err
2359+ }
2360+ }
2361+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 221, "</ul></section>")
2317 if templ_7745c5c3_Err != nil {2362 if templ_7745c5c3_Err != nil {
2318 return templ_7745c5c3_Err2363 return templ_7745c5c3_Err
2319 }2364 }
2320 }2365 }
2321- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 218, "</dd></dl></section>")
2322- if templ_7745c5c3_Err != nil {
2323- return templ_7745c5c3_Err
2324- }
2325 return nil2366 return nil
2326 })2367 })
2327 }2368 }
@@ -2346,51 +2387,51 @@ func mrBar(p MRPage) templ.Component {
2346 }()2387 }()
2347 }2388 }
2348 ctx = templ.InitializeContext(ctx)2389 ctx = templ.InitializeContext(ctx)
2349- templ_7745c5c3_Var113 := templ.GetChildren(ctx)2390+ templ_7745c5c3_Var114 := templ.GetChildren(ctx)
2350- if templ_7745c5c3_Var113 == nil {2391+ if templ_7745c5c3_Var114 == nil {
2351- templ_7745c5c3_Var113 = templ.NopComponent2392+ templ_7745c5c3_Var114 = templ.NopComponent
2352 }2393 }
2353 ctx = templ.ClearChildren(ctx)2394 ctx = templ.ClearChildren(ctx)
2354- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 219, "<div class=\"diff-tools mr-bar\" role=\"group\" aria-label=\"Diff view and merge\"><span class=\"dim\">")2395+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 222, "<div class=\"diff-tools mr-bar\" role=\"group\" aria-label=\"Diff view and merge\"><span class=\"dim\">")
2355 if templ_7745c5c3_Err != nil {2396 if templ_7745c5c3_Err != nil {
2356 return templ_7745c5c3_Err2397 return templ_7745c5c3_Err
2357 }2398 }
2358- var templ_7745c5c3_Var114 string2399+ var templ_7745c5c3_Var115 string
2359- templ_7745c5c3_Var114, templ_7745c5c3_Err = templ.JoinStringErrs(plural(p.NFiles, "file", "files"))2400+ templ_7745c5c3_Var115, templ_7745c5c3_Err = templ.JoinStringErrs(plural(p.NFiles, "file", "files"))
2360 if templ_7745c5c3_Err != nil {2401 if templ_7745c5c3_Err != nil {
2361- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 447, Col: 55}2402+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 462, Col: 55}
2362 }2403 }
2363- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var114))2404+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var115))
2364 if templ_7745c5c3_Err != nil {2405 if templ_7745c5c3_Err != nil {
2365 return templ_7745c5c3_Err2406 return templ_7745c5c3_Err
2366 }2407 }
2367- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 220, " · <span class=\"plus\">+")2408+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 223, " · <span class=\"plus\">+")
2368 if templ_7745c5c3_Err != nil {2409 if templ_7745c5c3_Err != nil {
2369 return templ_7745c5c3_Err2410 return templ_7745c5c3_Err
2370 }2411 }
2371- var templ_7745c5c3_Var115 string2412+ var templ_7745c5c3_Var116 string
2372- templ_7745c5c3_Var115, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Adds))2413+ templ_7745c5c3_Var116, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Adds))
2373 if templ_7745c5c3_Err != nil {2414 if templ_7745c5c3_Err != nil {
2374- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 447, Col: 95}2415+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 462, Col: 95}
2375 }2416 }
2376- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var115))2417+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var116))
2377 if templ_7745c5c3_Err != nil {2418 if templ_7745c5c3_Err != nil {
2378 return templ_7745c5c3_Err2419 return templ_7745c5c3_Err
2379 }2420 }
2380- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 221, "</span> <span class=\"minus\">-")2421+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 224, "</span> <span class=\"minus\">-")
2381 if templ_7745c5c3_Err != nil {2422 if templ_7745c5c3_Err != nil {
2382 return templ_7745c5c3_Err2423 return templ_7745c5c3_Err
2383 }2424 }
2384- var templ_7745c5c3_Var116 string2425+ var templ_7745c5c3_Var117 string
2385- templ_7745c5c3_Var116, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Dels))2426+ templ_7745c5c3_Var117, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Dels))
2386 if templ_7745c5c3_Err != nil {2427 if templ_7745c5c3_Err != nil {
2387- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 447, Col: 140}2428+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 462, Col: 140}
2388 }2429 }
2389- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var116))2430+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var117))
2390 if templ_7745c5c3_Err != nil {2431 if templ_7745c5c3_Err != nil {
2391 return templ_7745c5c3_Err2432 return templ_7745c5c3_Err
2392 }2433 }
2393- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 222, "</span></span>")2434+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 225, "</span></span>")
2394 if templ_7745c5c3_Err != nil {2435 if templ_7745c5c3_Err != nil {
2395 return templ_7745c5c3_Err2436 return templ_7745c5c3_Err
2396 }2437 }
@@ -2398,7 +2439,7 @@ func mrBar(p MRPage) templ.Component {
2398 if templ_7745c5c3_Err != nil {2439 if templ_7745c5c3_Err != nil {
2399 return templ_7745c5c3_Err2440 return templ_7745c5c3_Err
2400 }2441 }
2401- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 223, "<span class=\"grow\"></span>")2442+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 226, "<span class=\"grow\"></span>")
2402 if templ_7745c5c3_Err != nil {2443 if templ_7745c5c3_Err != nil {
2403 return templ_7745c5c3_Err2444 return templ_7745c5c3_Err
2404 }2445 }
@@ -2411,16 +2452,12 @@ func mrBar(p MRPage) templ.Component {
2411 if templ_7745c5c3_Err != nil {2452 if templ_7745c5c3_Err != nil {
2412 return templ_7745c5c3_Err2453 return templ_7745c5c3_Err
2413 }2454 }
2414- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 224, " ")
2415- if templ_7745c5c3_Err != nil {
2416- return templ_7745c5c3_Err
2417- }
2418- templ_7745c5c3_Err = moreMenu(p).Render(ctx, templ_7745c5c3_Buffer)
2419- if templ_7745c5c3_Err != nil {
2420- return templ_7745c5c3_Err
2421- }
2422 }2455 }
2423- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 225, "</div>")2456+ templ_7745c5c3_Err = moreMenu(p).Render(ctx, templ_7745c5c3_Buffer)
2457+ if templ_7745c5c3_Err != nil {
2458+ return templ_7745c5c3_Err
2459+ }
2460+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 227, "</div>")
2424 if templ_7745c5c3_Err != nil {2461 if templ_7745c5c3_Err != nil {
2425 return templ_7745c5c3_Err2462 return templ_7745c5c3_Err
2426 }2463 }
@@ -2452,84 +2489,57 @@ func mergeMenu(p MRPage) templ.Component {
2452 }()2489 }()
2453 }2490 }
2454 ctx = templ.InitializeContext(ctx)2491 ctx = templ.InitializeContext(ctx)
2455- templ_7745c5c3_Var117 := templ.GetChildren(ctx)2492+ templ_7745c5c3_Var118 := templ.GetChildren(ctx)
2456- if templ_7745c5c3_Var117 == nil {2493+ if templ_7745c5c3_Var118 == nil {
2457- templ_7745c5c3_Var117 = templ.NopComponent2494+ templ_7745c5c3_Var118 = templ.NopComponent
2458 }2495 }
2459 ctx = templ.ClearChildren(ctx)2496 ctx = templ.ClearChildren(ctx)
2460- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 226, "<details class=\"menu mmenu\" id=\"merge-menu\" data-state=\"open\"")2497+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 228, "<details class=\"menu mmenu\" id=\"merge-menu\" data-state=\"open\"")
2461 if templ_7745c5c3_Err != nil {2498 if templ_7745c5c3_Err != nil {
2462 return templ_7745c5c3_Err2499 return templ_7745c5c3_Err
2463 }2500 }
2464 if p.Box.Error != "" {2501 if p.Box.Error != "" {
2465- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 227, " open")2502+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 229, " open")
2466 if templ_7745c5c3_Err != nil {2503 if templ_7745c5c3_Err != nil {
2467 return templ_7745c5c3_Err2504 return templ_7745c5c3_Err
2468 }2505 }
2469 }2506 }
2470- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 228, "><summary class=\"btn primary\" aria-keyshortcuts=\"Shift+M\">")2507+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 230, "><summary class=\"btn primary\" aria-keyshortcuts=\"Shift+M\">")
2471 if templ_7745c5c3_Err != nil {2508 if templ_7745c5c3_Err != nil {
2472 return templ_7745c5c3_Err2509 return templ_7745c5c3_Err
2473 }2510 }
2474 if p.Box.ReadyAction != "" {2511 if p.Box.ReadyAction != "" {
2475- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 229, "Draft ")2512+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 231, "Draft ")
2476 if templ_7745c5c3_Err != nil {2513 if templ_7745c5c3_Err != nil {
2477 return templ_7745c5c3_Err2514 return templ_7745c5c3_Err
2478 }2515 }
2479 } else {2516 } else {
2480- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 230, "Merge ")2517+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 232, "Merge ")
2481 if templ_7745c5c3_Err != nil {2518 if templ_7745c5c3_Err != nil {
2482 return templ_7745c5c3_Err2519 return templ_7745c5c3_Err
2483 }2520 }
2484 }2521 }
2485- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 231, "<kbd aria-hidden=\"true\">M</kbd></summary><div class=\"menu-pop\" role=\"group\" aria-label=\"Merge\"><dl class=\"kv\"><dt>head</dt><dd>")2522+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 233, "<kbd aria-hidden=\"true\">M</kbd></summary><div class=\"menu-pop\" role=\"group\" aria-label=\"Merge\">")
2486 if templ_7745c5c3_Err != nil {2523 if templ_7745c5c3_Err != nil {
2487 return templ_7745c5c3_Err2524 return templ_7745c5c3_Err
2488 }2525 }
2489 if p.Box.HeadGone {2526 if p.Box.HeadGone {
2490- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 232, "gone: the source branch was deleted")2527+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 234, "<p class=\"dim\">the source branch was deleted</p>")
2491- if templ_7745c5c3_Err != nil {
2492- return templ_7745c5c3_Err
2493- }
2494- } else {
2495- var templ_7745c5c3_Var118 string
2496- templ_7745c5c3_Var118, templ_7745c5c3_Err = templ.JoinStringErrs(p.HeadShort)
2497- if templ_7745c5c3_Err != nil {
2498- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 483, Col: 19}
2499- }
2500- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var118))
2501 if templ_7745c5c3_Err != nil {2528 if templ_7745c5c3_Err != nil {
2502 return templ_7745c5c3_Err2529 return templ_7745c5c3_Err
2503 }2530 }
2504 }2531 }
2505- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 233, "</dd><dt>into</dt><dd>")
2506- if templ_7745c5c3_Err != nil {
2507- return templ_7745c5c3_Err
2508- }
2509- var templ_7745c5c3_Var119 string
2510- templ_7745c5c3_Var119, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
2511- if templ_7745c5c3_Err != nil {
2512- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 487, Col: 18}
2513- }
2514- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var119))
2515- if templ_7745c5c3_Err != nil {
2516- return templ_7745c5c3_Err
2517- }
2518- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 234, "</dd></dl>")
2519- if templ_7745c5c3_Err != nil {
2520- return templ_7745c5c3_Err
2521- }
2522 if p.Box.Error != "" {2532 if p.Box.Error != "" {
2523 templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 235, "<p class=\"d-err\" role=\"alert\">")2533 templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 235, "<p class=\"d-err\" role=\"alert\">")
2524 if templ_7745c5c3_Err != nil {2534 if templ_7745c5c3_Err != nil {
2525 return templ_7745c5c3_Err2535 return templ_7745c5c3_Err
2526 }2536 }
2527- var templ_7745c5c3_Var120 string2537+ var templ_7745c5c3_Var119 string
2528- templ_7745c5c3_Var120, templ_7745c5c3_Err = templ.JoinStringErrs(p.Box.Error)2538+ templ_7745c5c3_Var119, templ_7745c5c3_Err = templ.JoinStringErrs(p.Box.Error)
2529 if templ_7745c5c3_Err != nil {2539 if templ_7745c5c3_Err != nil {
2530- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 490, Col: 47}2540+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 496, Col: 47}
2531 }2541 }
2532- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var120))2542+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var119))
2533 if templ_7745c5c3_Err != nil {2543 if templ_7745c5c3_Err != nil {
2534 return templ_7745c5c3_Err2544 return templ_7745c5c3_Err
2535 }2545 }
@@ -2543,12 +2553,12 @@ func mergeMenu(p MRPage) templ.Component {
2543 if templ_7745c5c3_Err != nil {2553 if templ_7745c5c3_Err != nil {
2544 return templ_7745c5c3_Err2554 return templ_7745c5c3_Err
2545 }2555 }
2546- var templ_7745c5c3_Var121 templ.SafeURL2556+ var templ_7745c5c3_Var120 templ.SafeURL
2547- templ_7745c5c3_Var121, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.ReadyAction))2557+ templ_7745c5c3_Var120, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.ReadyAction))
2548 if templ_7745c5c3_Err != nil {2558 if templ_7745c5c3_Err != nil {
2549- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 494, Col: 80}2559+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 500, Col: 80}
2550 }2560 }
2551- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var121))2561+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var120))
2552 if templ_7745c5c3_Err != nil {2562 if templ_7745c5c3_Err != nil {
2553 return templ_7745c5c3_Err2563 return templ_7745c5c3_Err
2554 }2564 }
@@ -2565,12 +2575,12 @@ func mergeMenu(p MRPage) templ.Component {
2565 if templ_7745c5c3_Err != nil {2575 if templ_7745c5c3_Err != nil {
2566 return templ_7745c5c3_Err2576 return templ_7745c5c3_Err
2567 }2577 }
2568- var templ_7745c5c3_Var122 templ.SafeURL2578+ var templ_7745c5c3_Var121 templ.SafeURL
2569- templ_7745c5c3_Var122, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.MergeAction))2579+ templ_7745c5c3_Var121, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.MergeAction))
2570 if templ_7745c5c3_Err != nil {2580 if templ_7745c5c3_Err != nil {
2571- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 499, Col: 80}2581+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 505, Col: 80}
2572 }2582 }
2573- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var122))2583+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var121))
2574 if templ_7745c5c3_Err != nil {2584 if templ_7745c5c3_Err != nil {
2575 return templ_7745c5c3_Err2585 return templ_7745c5c3_Err
2576 }2586 }
@@ -2578,12 +2588,12 @@ func mergeMenu(p MRPage) templ.Component {
2578 if templ_7745c5c3_Err != nil {2588 if templ_7745c5c3_Err != nil {
2579 return templ_7745c5c3_Err2589 return templ_7745c5c3_Err
2580 }2590 }
2581- var templ_7745c5c3_Var123 string2591+ var templ_7745c5c3_Var122 string
2582- templ_7745c5c3_Var123, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.Head)2592+ templ_7745c5c3_Var122, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.Head)
2583 if templ_7745c5c3_Err != nil {2593 if templ_7745c5c3_Err != nil {
2584- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 500, Col: 59}2594+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 506, Col: 59}
2585 }2595 }
2586- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var123)2596+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var122)
2587 if templ_7745c5c3_Err != nil {2597 if templ_7745c5c3_Err != nil {
2588 return templ_7745c5c3_Err2598 return templ_7745c5c3_Err
2589 }2599 }
@@ -2596,12 +2606,12 @@ func mergeMenu(p MRPage) templ.Component {
2596 if templ_7745c5c3_Err != nil {2606 if templ_7745c5c3_Err != nil {
2597 return templ_7745c5c3_Err2607 return templ_7745c5c3_Err
2598 }2608 }
2599- var templ_7745c5c3_Var124 string2609+ var templ_7745c5c3_Var123 string
2600- templ_7745c5c3_Var124, templ_7745c5c3_Err = templ.ResolveAttributeValue(m.Value)2610+ templ_7745c5c3_Var123, templ_7745c5c3_Err = templ.ResolveAttributeValue(m.Value)
2601 if templ_7745c5c3_Err != nil {2611 if templ_7745c5c3_Err != nil {
2602- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 508, Col: 24}2612+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 514, Col: 24}
2603 }2613 }
2604- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var124)2614+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var123)
2605 if templ_7745c5c3_Err != nil {2615 if templ_7745c5c3_Err != nil {
2606 return templ_7745c5c3_Err2616 return templ_7745c5c3_Err
2607 }2617 }
@@ -2625,12 +2635,12 @@ func mergeMenu(p MRPage) templ.Component {
2625 if templ_7745c5c3_Err != nil {2635 if templ_7745c5c3_Err != nil {
2626 return templ_7745c5c3_Err2636 return templ_7745c5c3_Err
2627 }2637 }
2628- var templ_7745c5c3_Var125 string2638+ var templ_7745c5c3_Var124 string
2629- templ_7745c5c3_Var125, templ_7745c5c3_Err = templ.ResolveAttributeValue(m.Reason)2639+ templ_7745c5c3_Var124, templ_7745c5c3_Err = templ.ResolveAttributeValue(m.Reason)
2630 if templ_7745c5c3_Err != nil {2640 if templ_7745c5c3_Err != nil {
2631- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 511, Col: 25}2641+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 517, Col: 25}
2632 }2642 }
2633- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var125)2643+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var124)
2634 if templ_7745c5c3_Err != nil {2644 if templ_7745c5c3_Err != nil {
2635 return templ_7745c5c3_Err2645 return templ_7745c5c3_Err
2636 }2646 }
@@ -2638,12 +2648,12 @@ func mergeMenu(p MRPage) templ.Component {
2638 if templ_7745c5c3_Err != nil {2648 if templ_7745c5c3_Err != nil {
2639 return templ_7745c5c3_Err2649 return templ_7745c5c3_Err
2640 }2650 }
2641- var templ_7745c5c3_Var126 string2651+ var templ_7745c5c3_Var125 string
2642- templ_7745c5c3_Var126, templ_7745c5c3_Err = templ.JoinStringErrs(m.Label)2652+ templ_7745c5c3_Var125, templ_7745c5c3_Err = templ.JoinStringErrs(m.Label)
2643 if templ_7745c5c3_Err != nil {2653 if templ_7745c5c3_Err != nil {
2644- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 515, Col: 17}2654+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 521, Col: 17}
2645 }2655 }
2646- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var126))2656+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var125))
2647 if templ_7745c5c3_Err != nil {2657 if templ_7745c5c3_Err != nil {
2648 return templ_7745c5c3_Err2658 return templ_7745c5c3_Err
2649 }2659 }
@@ -2656,12 +2666,12 @@ func mergeMenu(p MRPage) templ.Component {
2656 if templ_7745c5c3_Err != nil {2666 if templ_7745c5c3_Err != nil {
2657 return templ_7745c5c3_Err2667 return templ_7745c5c3_Err
2658 }2668 }
2659- var templ_7745c5c3_Var127 string2669+ var templ_7745c5c3_Var126 string
2660- templ_7745c5c3_Var127, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(i + 1))2670+ templ_7745c5c3_Var126, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(i + 1))
2661 if templ_7745c5c3_Err != nil {2671 if templ_7745c5c3_Err != nil {
2662- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 517, Col: 46}2672+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 523, Col: 46}
2663 }2673 }
2664- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var127))2674+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var126))
2665 if templ_7745c5c3_Err != nil {2675 if templ_7745c5c3_Err != nil {
2666 return templ_7745c5c3_Err2676 return templ_7745c5c3_Err
2667 }2677 }
@@ -2679,96 +2689,67 @@ func mergeMenu(p MRPage) templ.Component {
2679 if templ_7745c5c3_Err != nil {2689 if templ_7745c5c3_Err != nil {
2680 return templ_7745c5c3_Err2690 return templ_7745c5c3_Err
2681 }2691 }
2682- if p.Box.Signed {
2683- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 253, "<p class=\"d-note\" id=\"mr-signing\">squash and merge commits are signed with ermite's own key (generated on first start). ")
2684- if templ_7745c5c3_Err != nil {
2685- return templ_7745c5c3_Err
2686- }
2687- if p.Box.Fingerprint != "" {
2688- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 254, "fingerprint <code>")
2689- if templ_7745c5c3_Err != nil {
2690- return templ_7745c5c3_Err
2691- }
2692- var templ_7745c5c3_Var128 string
2693- templ_7745c5c3_Var128, templ_7745c5c3_Err = templ.JoinStringErrs(p.Box.Fingerprint)
2694- if templ_7745c5c3_Err != nil {
2695- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 526, Col: 45}
2696- }
2697- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var128))
2698- if templ_7745c5c3_Err != nil {
2699- return templ_7745c5c3_Err
2700- }
2701- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 255, "</code> ")
2702- if templ_7745c5c3_Err != nil {
2703- return templ_7745c5c3_Err
2704- }
2705- }
2706- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 256, "<code>ermite signing-key show</code> prints it.</p>")
2707- if templ_7745c5c3_Err != nil {
2708- return templ_7745c5c3_Err
2709- }
2710- }
2711 if p.Box.CanDeleteBranch {2692 if p.Box.CanDeleteBranch {
2712- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 257, "<label class=\"d-check\"><input type=\"checkbox\" name=\"delete_branch\" value=\"1\"> delete ")2693+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 253, "<label class=\"d-check\"><input type=\"checkbox\" name=\"delete_branch\" value=\"1\"> delete ")
2713 if templ_7745c5c3_Err != nil {2694 if templ_7745c5c3_Err != nil {
2714 return templ_7745c5c3_Err2695 return templ_7745c5c3_Err
2715 }2696 }
2716- var templ_7745c5c3_Var129 string2697+ var templ_7745c5c3_Var127 string
2717- templ_7745c5c3_Var129, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)2698+ templ_7745c5c3_Var127, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)
2718 if templ_7745c5c3_Err != nil {2699 if templ_7745c5c3_Err != nil {
2719- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 532, Col: 102}2700+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 529, Col: 102}
2720 }2701 }
2721- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var129))2702+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var127))
2722 if templ_7745c5c3_Err != nil {2703 if templ_7745c5c3_Err != nil {
2723 return templ_7745c5c3_Err2704 return templ_7745c5c3_Err
2724 }2705 }
2725- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 258, " after the merge <kbd aria-hidden=\"true\">D</kbd></label>")2706+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 254, " after the merge <kbd aria-hidden=\"true\">D</kbd></label>")
2726 if templ_7745c5c3_Err != nil {2707 if templ_7745c5c3_Err != nil {
2727 return templ_7745c5c3_Err2708 return templ_7745c5c3_Err
2728 }2709 }
2729 }2710 }
2730- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 259, "<div class=\"d-btns\"><button type=\"submit\" class=\"btn primary\" data-default")2711+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 255, "<div class=\"d-btns\"><button type=\"submit\" class=\"btn primary\" data-default")
2731 if templ_7745c5c3_Err != nil {2712 if templ_7745c5c3_Err != nil {
2732 return templ_7745c5c3_Err2713 return templ_7745c5c3_Err
2733 }2714 }
2734 if !p.Box.CanMerge() {2715 if !p.Box.CanMerge() {
2735- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 260, " disabled")2716+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 256, " disabled")
2736 if templ_7745c5c3_Err != nil {2717 if templ_7745c5c3_Err != nil {
2737 return templ_7745c5c3_Err2718 return templ_7745c5c3_Err
2738 }2719 }
2739 }2720 }
2740- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 261, " title=\"")2721+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 257, " title=\"")
2741 if templ_7745c5c3_Err != nil {2722 if templ_7745c5c3_Err != nil {
2742 return templ_7745c5c3_Err2723 return templ_7745c5c3_Err
2743 }2724 }
2744- var templ_7745c5c3_Var130 string2725+ var templ_7745c5c3_Var128 string
2745- templ_7745c5c3_Var130, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.MergeTitle())2726+ templ_7745c5c3_Var128, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.MergeTitle())
2746 if templ_7745c5c3_Err != nil {2727 if templ_7745c5c3_Err != nil {
2747- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 540, Col: 33}2728+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 537, Col: 33}
2748 }2729 }
2749- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var130)2730+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var128)
2750 if templ_7745c5c3_Err != nil {2731 if templ_7745c5c3_Err != nil {
2751 return templ_7745c5c3_Err2732 return templ_7745c5c3_Err
2752 }2733 }
2753- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 262, "\" :disabled=\"!this.form.querySelector('input[name=mode]:checked:not(:disabled)')\" :title=\"(this.form.querySelector('input[name=mode]:checked') || {}).title || ''\">Merge into ")2734+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 258, "\" :disabled=\"!this.form.querySelector('input[name=mode]:checked:not(:disabled)')\" :title=\"(this.form.querySelector('input[name=mode]:checked') || {}).title || ''\">Merge into ")
2754 if templ_7745c5c3_Err != nil {2735 if templ_7745c5c3_Err != nil {
2755 return templ_7745c5c3_Err2736 return templ_7745c5c3_Err
2756 }2737 }
2757- var templ_7745c5c3_Var131 string2738+ var templ_7745c5c3_Var129 string
2758- templ_7745c5c3_Var131, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)2739+ templ_7745c5c3_Var129, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
2759 if templ_7745c5c3_Err != nil {2740 if templ_7745c5c3_Err != nil {
2760- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 543, Col: 28}2741+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 540, Col: 28}
2761 }2742 }
2762- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var131))2743+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var129))
2763 if templ_7745c5c3_Err != nil {2744 if templ_7745c5c3_Err != nil {
2764 return templ_7745c5c3_Err2745 return templ_7745c5c3_Err
2765 }2746 }
2766- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 263, "</button></div></form>")2747+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 259, "</button></div></form>")
2767 if templ_7745c5c3_Err != nil {2748 if templ_7745c5c3_Err != nil {
2768 return templ_7745c5c3_Err2749 return templ_7745c5c3_Err
2769 }2750 }
2770 }2751 }
2771- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 264, "</div></details>")2752+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 260, "</div></details>")
2772 if templ_7745c5c3_Err != nil {2753 if templ_7745c5c3_Err != nil {
2773 return templ_7745c5c3_Err2754 return templ_7745c5c3_Err
2774 }2755 }
@@ -2794,182 +2775,182 @@ func MRMergeability(v MergeabilityView) templ.Component {
2794 }()2775 }()
2795 }2776 }
2796 ctx = templ.InitializeContext(ctx)2777 ctx = templ.InitializeContext(ctx)
2797- templ_7745c5c3_Var132 := templ.GetChildren(ctx)2778+ templ_7745c5c3_Var130 := templ.GetChildren(ctx)
2798- if templ_7745c5c3_Var132 == nil {2779+ if templ_7745c5c3_Var130 == nil {
2799- templ_7745c5c3_Var132 = templ.NopComponent2780+ templ_7745c5c3_Var130 = templ.NopComponent
2800 }2781 }
2801 ctx = templ.ClearChildren(ctx)2782 ctx = templ.ClearChildren(ctx)
2802- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 265, "<span data-mergeability data-state=\"")2783+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 261, "<span data-mergeability data-state=\"")
2803 if templ_7745c5c3_Err != nil {2784 if templ_7745c5c3_Err != nil {
2804 return templ_7745c5c3_Err2785 return templ_7745c5c3_Err
2805 }2786 }
2806- var templ_7745c5c3_Var133 string2787+ var templ_7745c5c3_Var131 string
2807- templ_7745c5c3_Var133, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.State)2788+ templ_7745c5c3_Var131, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.State)
2808 if templ_7745c5c3_Err != nil {2789 if templ_7745c5c3_Err != nil {
2809- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 556, Col: 22}2790+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 553, Col: 22}
2810 }2791 }
2811- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var133)2792+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var131)
2812 if templ_7745c5c3_Err != nil {2793 if templ_7745c5c3_Err != nil {
2813 return templ_7745c5c3_Err2794 return templ_7745c5c3_Err
2814 }2795 }
2815- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 266, "\" data-ff-ok=\"")2796+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 262, "\" data-ff-ok=\"")
2816 if templ_7745c5c3_Err != nil {2797 if templ_7745c5c3_Err != nil {
2817 return templ_7745c5c3_Err2798 return templ_7745c5c3_Err
2818 }2799 }
2819- var templ_7745c5c3_Var134 string2800+ var templ_7745c5c3_Var132 string
2820- templ_7745c5c3_Var134, templ_7745c5c3_Err = templ.ResolveAttributeValue(strconv.FormatBool(v.FFOk))2801+ templ_7745c5c3_Var132, templ_7745c5c3_Err = templ.ResolveAttributeValue(strconv.FormatBool(v.FFOk))
2821 if templ_7745c5c3_Err != nil {2802 if templ_7745c5c3_Err != nil {
2822- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 557, Col: 41}2803+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 554, Col: 41}
2823 }2804 }
2824- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var134)2805+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var132)
2825 if templ_7745c5c3_Err != nil {2806 if templ_7745c5c3_Err != nil {
2826 return templ_7745c5c3_Err2807 return templ_7745c5c3_Err
2827 }2808 }
2828- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 267, "\" data-merge-ok=\"")2809+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 263, "\" data-merge-ok=\"")
2829 if templ_7745c5c3_Err != nil {2810 if templ_7745c5c3_Err != nil {
2830 return templ_7745c5c3_Err2811 return templ_7745c5c3_Err
2831 }2812 }
2832- var templ_7745c5c3_Var135 string2813+ var templ_7745c5c3_Var133 string
2833- templ_7745c5c3_Var135, templ_7745c5c3_Err = templ.ResolveAttributeValue(strconv.FormatBool(v.MergeOk))2814+ templ_7745c5c3_Var133, templ_7745c5c3_Err = templ.ResolveAttributeValue(strconv.FormatBool(v.MergeOk))
2834 if templ_7745c5c3_Err != nil {2815 if templ_7745c5c3_Err != nil {
2835- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 558, Col: 47}2816+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 555, Col: 47}
2836 }2817 }
2837- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var135)2818+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var133)
2838 if templ_7745c5c3_Err != nil {2819 if templ_7745c5c3_Err != nil {
2839 return templ_7745c5c3_Err2820 return templ_7745c5c3_Err
2840 }2821 }
2841- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 268, "\" data-ff-reason=\"")2822+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 264, "\" data-ff-reason=\"")
2842 if templ_7745c5c3_Err != nil {2823 if templ_7745c5c3_Err != nil {
2843 return templ_7745c5c3_Err2824 return templ_7745c5c3_Err
2844 }2825 }
2845- var templ_7745c5c3_Var136 string2826+ var templ_7745c5c3_Var134 string
2846- templ_7745c5c3_Var136, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.FFReason)2827+ templ_7745c5c3_Var134, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.FFReason)
2847 if templ_7745c5c3_Err != nil {2828 if templ_7745c5c3_Err != nil {
2848- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 559, Col: 29}2829+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 556, Col: 29}
2849 }2830 }
2850- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var136)2831+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var134)
2851 if templ_7745c5c3_Err != nil {2832 if templ_7745c5c3_Err != nil {
2852 return templ_7745c5c3_Err2833 return templ_7745c5c3_Err
2853 }2834 }
2854- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 269, "\" data-merge-reason=\"")2835+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 265, "\" data-merge-reason=\"")
2855 if templ_7745c5c3_Err != nil {2836 if templ_7745c5c3_Err != nil {
2856 return templ_7745c5c3_Err2837 return templ_7745c5c3_Err
2857 }2838 }
2858- var templ_7745c5c3_Var137 string2839+ var templ_7745c5c3_Var135 string
2859- templ_7745c5c3_Var137, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.MergeReason)2840+ templ_7745c5c3_Var135, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.MergeReason)
2860 if templ_7745c5c3_Err != nil {2841 if templ_7745c5c3_Err != nil {
2861- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 560, Col: 35}2842+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 557, Col: 35}
2862 }2843 }
2863- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var137)2844+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var135)
2864 if templ_7745c5c3_Err != nil {2845 if templ_7745c5c3_Err != nil {
2865 return templ_7745c5c3_Err2846 return templ_7745c5c3_Err
2866 }2847 }
2867- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 270, "\"><span class=\"badge\" data-state=\"")2848+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 266, "\"><span class=\"badge\" data-state=\"")
2868 if templ_7745c5c3_Err != nil {2849 if templ_7745c5c3_Err != nil {
2869 return templ_7745c5c3_Err2850 return templ_7745c5c3_Err
2870 }2851 }
2871- var templ_7745c5c3_Var138 string2852+ var templ_7745c5c3_Var136 string
2872- templ_7745c5c3_Var138, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.State)2853+ templ_7745c5c3_Var136, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.State)
2873 if templ_7745c5c3_Err != nil {2854 if templ_7745c5c3_Err != nil {
2874- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 562, Col: 42}2855+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 559, Col: 42}
2875 }2856 }
2876- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var138)2857+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var136)
2877 if templ_7745c5c3_Err != nil {2858 if templ_7745c5c3_Err != nil {
2878 return templ_7745c5c3_Err2859 return templ_7745c5c3_Err
2879 }2860 }
2880- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 271, "\">")2861+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 267, "\">")
2881 if templ_7745c5c3_Err != nil {2862 if templ_7745c5c3_Err != nil {
2882 return templ_7745c5c3_Err2863 return templ_7745c5c3_Err
2883 }2864 }
2884- var templ_7745c5c3_Var139 string2865+ var templ_7745c5c3_Var137 string
2885- templ_7745c5c3_Var139, templ_7745c5c3_Err = templ.JoinStringErrs(v.Label)2866+ templ_7745c5c3_Var137, templ_7745c5c3_Err = templ.JoinStringErrs(v.Label)
2886 if templ_7745c5c3_Err != nil {2867 if templ_7745c5c3_Err != nil {
2887- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 562, Col: 54}2868+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 559, Col: 54}
2888 }2869 }
2889- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var139))2870+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var137))
2890 if templ_7745c5c3_Err != nil {2871 if templ_7745c5c3_Err != nil {
2891 return templ_7745c5c3_Err2872 return templ_7745c5c3_Err
2892 }2873 }
2893- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 272, "</span> ")2874+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 268, "</span> ")
2894 if templ_7745c5c3_Err != nil {2875 if templ_7745c5c3_Err != nil {
2895 return templ_7745c5c3_Err2876 return templ_7745c5c3_Err
2896 }2877 }
2897 if v.Detail != "" {2878 if v.Detail != "" {
2898- var templ_7745c5c3_Var140 string2879+ var templ_7745c5c3_Var138 string
2899- templ_7745c5c3_Var140, templ_7745c5c3_Err = templ.JoinStringErrs(" ")2880+ templ_7745c5c3_Var138, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
2900 if templ_7745c5c3_Err != nil {2881 if templ_7745c5c3_Err != nil {
2901- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 564, Col: 8}2882+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 561, Col: 8}
2902 }2883 }
2903- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var140))2884+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var138))
2904 if templ_7745c5c3_Err != nil {2885 if templ_7745c5c3_Err != nil {
2905 return templ_7745c5c3_Err2886 return templ_7745c5c3_Err
2906 }2887 }
2907- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 273, "<span class=\"dim\">")2888+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 269, "<span class=\"dim\">")
2908 if templ_7745c5c3_Err != nil {2889 if templ_7745c5c3_Err != nil {
2909 return templ_7745c5c3_Err2890 return templ_7745c5c3_Err
2910 }2891 }
2911- var templ_7745c5c3_Var141 string2892+ var templ_7745c5c3_Var139 string
2912- templ_7745c5c3_Var141, templ_7745c5c3_Err = templ.JoinStringErrs(v.Detail)2893+ templ_7745c5c3_Var139, templ_7745c5c3_Err = templ.JoinStringErrs(v.Detail)
2913 if templ_7745c5c3_Err != nil {2894 if templ_7745c5c3_Err != nil {
2914- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 564, Col: 38}2895+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 561, Col: 38}
2915 }2896 }
2916- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var141))2897+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var139))
2917 if templ_7745c5c3_Err != nil {2898 if templ_7745c5c3_Err != nil {
2918 return templ_7745c5c3_Err2899 return templ_7745c5c3_Err
2919 }2900 }
2920- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 274, "</span>")2901+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 270, "</span>")
2921 if templ_7745c5c3_Err != nil {2902 if templ_7745c5c3_Err != nil {
2922 return templ_7745c5c3_Err2903 return templ_7745c5c3_Err
2923 }2904 }
2924 }2905 }
2925- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 275, "</span> ")2906+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 271, "</span> ")
2926 if templ_7745c5c3_Err != nil {2907 if templ_7745c5c3_Err != nil {
2927 return templ_7745c5c3_Err2908 return templ_7745c5c3_Err
2928 }2909 }
2929 if len(v.Paths) > 0 {2910 if len(v.Paths) > 0 {
2930- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 276, "<ul class=\"mg-paths\" aria-label=\"conflicting files\">")2911+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 272, "<ul class=\"mg-paths\" aria-label=\"conflicting files\">")
2931 if templ_7745c5c3_Err != nil {2912 if templ_7745c5c3_Err != nil {
2932 return templ_7745c5c3_Err2913 return templ_7745c5c3_Err
2933 }2914 }
2934 for _, path := range v.Paths {2915 for _, path := range v.Paths {
2935- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 277, "<li><code>")2916+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 273, "<li><code>")
2936 if templ_7745c5c3_Err != nil {2917 if templ_7745c5c3_Err != nil {
2937 return templ_7745c5c3_Err2918 return templ_7745c5c3_Err
2938 }2919 }
2939- var templ_7745c5c3_Var142 string2920+ var templ_7745c5c3_Var140 string
2940- templ_7745c5c3_Var142, templ_7745c5c3_Err = templ.JoinStringErrs(path)2921+ templ_7745c5c3_Var140, templ_7745c5c3_Err = templ.JoinStringErrs(path)
2941 if templ_7745c5c3_Err != nil {2922 if templ_7745c5c3_Err != nil {
2942- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 570, Col: 20}2923+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 567, Col: 20}
2943 }2924 }
2944- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var142))2925+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var140))
2945 if templ_7745c5c3_Err != nil {2926 if templ_7745c5c3_Err != nil {
2946 return templ_7745c5c3_Err2927 return templ_7745c5c3_Err
2947 }2928 }
2948- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 278, "</code></li>")2929+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 274, "</code></li>")
2949 if templ_7745c5c3_Err != nil {2930 if templ_7745c5c3_Err != nil {
2950 return templ_7745c5c3_Err2931 return templ_7745c5c3_Err
2951 }2932 }
2952 }2933 }
2953- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 279, "</ul>")2934+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 275, "</ul>")
2954 if templ_7745c5c3_Err != nil {2935 if templ_7745c5c3_Err != nil {
2955 return templ_7745c5c3_Err2936 return templ_7745c5c3_Err
2956 }2937 }
2957 }2938 }
2958 if v.PathsNote != "" {2939 if v.PathsNote != "" {
2959- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 280, "<p class=\"dim\">")2940+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 276, "<p class=\"dim\">")
2960 if templ_7745c5c3_Err != nil {2941 if templ_7745c5c3_Err != nil {
2961 return templ_7745c5c3_Err2942 return templ_7745c5c3_Err
2962 }2943 }
2963- var templ_7745c5c3_Var143 string2944+ var templ_7745c5c3_Var141 string
2964- templ_7745c5c3_Var143, templ_7745c5c3_Err = templ.JoinStringErrs(v.PathsNote)2945+ templ_7745c5c3_Var141, templ_7745c5c3_Err = templ.JoinStringErrs(v.PathsNote)
2965 if templ_7745c5c3_Err != nil {2946 if templ_7745c5c3_Err != nil {
2966- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 575, Col: 30}2947+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 572, Col: 30}
2967 }2948 }
2968- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var143))2949+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var141))
2969 if templ_7745c5c3_Err != nil {2950 if templ_7745c5c3_Err != nil {
2970 return templ_7745c5c3_Err2951 return templ_7745c5c3_Err
2971 }2952 }
2972- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 281, "</p>")2953+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 277, "</p>")
2973 if templ_7745c5c3_Err != nil {2954 if templ_7745c5c3_Err != nil {
2974 return templ_7745c5c3_Err2955 return templ_7745c5c3_Err
2975 }2956 }
@@ -2996,12 +2977,12 @@ func mrMergeabilitySlot(v MergeabilityView) templ.Component {
2996 }()2977 }()
2997 }2978 }
2998 ctx = templ.InitializeContext(ctx)2979 ctx = templ.InitializeContext(ctx)
2999- templ_7745c5c3_Var144 := templ.GetChildren(ctx)2980+ templ_7745c5c3_Var142 := templ.GetChildren(ctx)
3000- if templ_7745c5c3_Var144 == nil {2981+ if templ_7745c5c3_Var142 == nil {
3001- templ_7745c5c3_Var144 = templ.NopComponent2982+ templ_7745c5c3_Var142 = templ.NopComponent
3002 }2983 }
3003 ctx = templ.ClearChildren(ctx)2984 ctx = templ.ClearChildren(ctx)
3004- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 282, "<div id=\"mr-mergeability\" class=\"live-slot\" role=\"status\" data-slot>")2985+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 278, "<div id=\"mr-mergeability\" class=\"live-slot\" role=\"status\" data-slot>")
3005 if templ_7745c5c3_Err != nil {2986 if templ_7745c5c3_Err != nil {
3006 return templ_7745c5c3_Err2987 return templ_7745c5c3_Err
3007 }2988 }
@@ -3009,7 +2990,7 @@ func mrMergeabilitySlot(v MergeabilityView) templ.Component {
3009 if templ_7745c5c3_Err != nil {2990 if templ_7745c5c3_Err != nil {
3010 return templ_7745c5c3_Err2991 return templ_7745c5c3_Err
3011 }2992 }
3012- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 283, "</div>")2993+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 279, "</div>")
3013 if templ_7745c5c3_Err != nil {2994 if templ_7745c5c3_Err != nil {
3014 return templ_7745c5c3_Err2995 return templ_7745c5c3_Err
3015 }2996 }
@@ -3034,9 +3015,9 @@ func MRMergeabilityFragment(v MergeabilityView) templ.Component {
3034 }()3015 }()
3035 }3016 }
3036 ctx = templ.InitializeContext(ctx)3017 ctx = templ.InitializeContext(ctx)
3037- templ_7745c5c3_Var145 := templ.GetChildren(ctx)3018+ templ_7745c5c3_Var143 := templ.GetChildren(ctx)
3038- if templ_7745c5c3_Var145 == nil {3019+ if templ_7745c5c3_Var143 == nil {
3039- templ_7745c5c3_Var145 = templ.NopComponent3020+ templ_7745c5c3_Var143 = templ.NopComponent
3040 }3021 }
3041 ctx = templ.ClearChildren(ctx)3022 ctx = templ.ClearChildren(ctx)
3042 templ_7745c5c3_Err = mrMergeabilitySlot(v).Render(ctx, templ_7745c5c3_Buffer)3023 templ_7745c5c3_Err = mrMergeabilitySlot(v).Render(ctx, templ_7745c5c3_Buffer)
@@ -3047,8 +3028,8 @@ func MRMergeabilityFragment(v MergeabilityView) templ.Component {
3047 })3028 })
3048 }3029 }
3049 3030
3050-// moreMenu is what else the owner does with an open request: mark the head3031+// moreMenu shows read-only settings to every viewer, and keeps owner actions
3051-// read, close it, merge it from a terminal.3032+// behind the same merge-box permission as before.
3052 func moreMenu(p MRPage) templ.Component {3033 func moreMenu(p MRPage) templ.Component {
3053 return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {3034 return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
3054 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context3035 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@@ -3065,79 +3046,142 @@ func moreMenu(p MRPage) templ.Component {
3065 }()3046 }()
3066 }3047 }
3067 ctx = templ.InitializeContext(ctx)3048 ctx = templ.InitializeContext(ctx)
3068- templ_7745c5c3_Var146 := templ.GetChildren(ctx)3049+ templ_7745c5c3_Var144 := templ.GetChildren(ctx)
3069- if templ_7745c5c3_Var146 == nil {3050+ if templ_7745c5c3_Var144 == nil {
3070- templ_7745c5c3_Var146 = templ.NopComponent3051+ templ_7745c5c3_Var144 = templ.NopComponent
3071 }3052 }
3072 ctx = templ.ClearChildren(ctx)3053 ctx = templ.ClearChildren(ctx)
3073- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 284, "<details class=\"menu omenu\"><summary class=\"btn icon\" aria-label=\"More actions\" title=\"more actions\">⋯</summary><div class=\"menu-pop\" role=\"group\" aria-label=\"More actions\">")3054+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 280, "<details class=\"menu omenu\"><summary class=\"btn icon\" aria-label=\"More actions\" title=\"more actions\">⋯</summary><div class=\"menu-pop\" role=\"group\" aria-label=\"More actions\"><section class=\"merge-settings\"><h2>Merge settings</h2><dl class=\"kv\"><dt>modes</dt><dd>")
3074 if templ_7745c5c3_Err != nil {3055 if templ_7745c5c3_Err != nil {
3075 return templ_7745c5c3_Err3056 return templ_7745c5c3_Err
3076 }3057 }
3077- if p.Box.CanMarkRead {3058+ var templ_7745c5c3_Var145 string
3078- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 285, "<form method=\"post\" action=\"")3059+ templ_7745c5c3_Var145, templ_7745c5c3_Err = templ.JoinStringErrs(strings.Join(p.Modes, ", "))
3060+ if templ_7745c5c3_Err != nil {
3061+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 599, Col: 38}
3062+ }
3063+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var145))
3064+ if templ_7745c5c3_Err != nil {
3065+ return templ_7745c5c3_Err
3066+ }
3067+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 281, "</dd><dt>checks</dt><dd>")
3068+ if templ_7745c5c3_Err != nil {
3069+ return templ_7745c5c3_Err
3070+ }
3071+ if p.ChecksBlock {
3072+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 282, "failing ones block the merge")
3079 if templ_7745c5c3_Err != nil {3073 if templ_7745c5c3_Err != nil {
3080 return templ_7745c5c3_Err3074 return templ_7745c5c3_Err
3081 }3075 }
3082- var templ_7745c5c3_Var147 templ.SafeURL3076+ } else {
3083- templ_7745c5c3_Var147, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.ReadAction))3077+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 283, "do not block the merge")
3084- if templ_7745c5c3_Err != nil {
3085- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 599, Col: 64}
3086- }
3087- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var147))
3088 if templ_7745c5c3_Err != nil {3078 if templ_7745c5c3_Err != nil {
3089 return templ_7745c5c3_Err3079 return templ_7745c5c3_Err
3090 }3080 }
3091- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 286, "\"><input type=\"hidden\" name=\"head_id\" value=\"")3081+ }
3082+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 284, "</dd></dl></section>")
3083+ if templ_7745c5c3_Err != nil {
3084+ return templ_7745c5c3_Err
3085+ }
3086+ if p.Box != nil {
3087+ if p.Box.Signed {
3088+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 285, "<p class=\"d-note\" id=\"mr-signing\">squash and merge commits are signed with ermite's own key (generated on first start). ")
3089+ if templ_7745c5c3_Err != nil {
3090+ return templ_7745c5c3_Err
3091+ }
3092+ if p.Box.Fingerprint != "" {
3093+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 286, "fingerprint <code>")
3094+ if templ_7745c5c3_Err != nil {
3095+ return templ_7745c5c3_Err
3096+ }
3097+ var templ_7745c5c3_Var146 string
3098+ templ_7745c5c3_Var146, templ_7745c5c3_Err = templ.JoinStringErrs(p.Box.Fingerprint)
3099+ if templ_7745c5c3_Err != nil {
3100+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 615, Col: 44}
3101+ }
3102+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var146))
3103+ if templ_7745c5c3_Err != nil {
3104+ return templ_7745c5c3_Err
3105+ }
3106+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 287, "</code> ")
3107+ if templ_7745c5c3_Err != nil {
3108+ return templ_7745c5c3_Err
3109+ }
3110+ }
3111+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 288, "<code>ermite signing-key show</code> prints it.</p>")
3112+ if templ_7745c5c3_Err != nil {
3113+ return templ_7745c5c3_Err
3114+ }
3115+ }
3116+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 289, " ")
3092 if templ_7745c5c3_Err != nil {3117 if templ_7745c5c3_Err != nil {
3093 return templ_7745c5c3_Err3118 return templ_7745c5c3_Err
3094 }3119 }
3095- var templ_7745c5c3_Var148 string3120+ if p.Box.CanMarkRead {
3096- templ_7745c5c3_Var148, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.Head)3121+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 290, "<form method=\"post\" action=\"")
3097- if templ_7745c5c3_Err != nil {3122+ if templ_7745c5c3_Err != nil {
3098- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 600, Col: 59}3123+ return templ_7745c5c3_Err
3124+ }
3125+ var templ_7745c5c3_Var147 templ.SafeURL
3126+ templ_7745c5c3_Var147, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.ReadAction))
3127+ if templ_7745c5c3_Err != nil {
3128+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 621, Col: 65}
3129+ }
3130+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var147))
3131+ if templ_7745c5c3_Err != nil {
3132+ return templ_7745c5c3_Err
3133+ }
3134+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 291, "\"><input type=\"hidden\" name=\"head_id\" value=\"")
3135+ if templ_7745c5c3_Err != nil {
3136+ return templ_7745c5c3_Err
3137+ }
3138+ var templ_7745c5c3_Var148 string
3139+ templ_7745c5c3_Var148, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.Head)
3140+ if templ_7745c5c3_Err != nil {
3141+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 622, Col: 60}
3142+ }
3143+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var148)
3144+ if templ_7745c5c3_Err != nil {
3145+ return templ_7745c5c3_Err
3146+ }
3147+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 292, "\"> <button type=\"submit\" title=\"the next visit can show only what changed after this head\" class=\"btn\" aria-keyshortcuts=\"Shift+R\" data-read>Mark read <kbd aria-hidden=\"true\">R</kbd></button></form>")
3148+ if templ_7745c5c3_Err != nil {
3149+ return templ_7745c5c3_Err
3150+ }
3099 }3151 }
3100- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var148)3152+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 293, " <form method=\"post\" action=\"")
3101 if templ_7745c5c3_Err != nil {3153 if templ_7745c5c3_Err != nil {
3102 return templ_7745c5c3_Err3154 return templ_7745c5c3_Err
3103 }3155 }
3104- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 287, "\"> <button type=\"submit\" title=\"the next visit can show only what changed after this head\" class=\"btn\" aria-keyshortcuts=\"Shift+R\" data-read>Mark read <kbd aria-hidden=\"true\">R</kbd></button></form>")3156+ var templ_7745c5c3_Var149 templ.SafeURL
3157+ templ_7745c5c3_Var149, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.CloseAction))
3105 if templ_7745c5c3_Err != nil {3158 if templ_7745c5c3_Err != nil {
3106- return templ_7745c5c3_Err3159+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 626, Col: 65}
3107 }3160 }
3108- }3161+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var149))
3109- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 288, "<form method=\"post\" action=\"")
3110- if templ_7745c5c3_Err != nil {
3111- return templ_7745c5c3_Err
3112- }
3113- var templ_7745c5c3_Var149 templ.SafeURL
3114- templ_7745c5c3_Var149, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.CloseAction))
3115- if templ_7745c5c3_Err != nil {
3116- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 604, Col: 64}
3117- }
3118- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var149))
3119- if templ_7745c5c3_Err != nil {
3120- return templ_7745c5c3_Err
3121- }
3122- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 289, "\"><button type=\"submit\" title=\"close without merging; the branch is kept\" class=\"btn danger\">Close</button></form>")
3123- if templ_7745c5c3_Err != nil {
3124- return templ_7745c5c3_Err
3125- }
3126- if !p.Box.HeadGone && p.Box.ReadyAction == "" {
3127- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 290, "<details class=\"d-or\"><summary class=\"mute\">or from a terminal</summary>")
3128 if templ_7745c5c3_Err != nil {3162 if templ_7745c5c3_Err != nil {
3129 return templ_7745c5c3_Err3163 return templ_7745c5c3_Err
3130 }3164 }
3131- templ_7745c5c3_Err = CloneBlock(p.Box.CLI).Render(ctx, templ_7745c5c3_Buffer)3165+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 294, "\"><button type=\"submit\" title=\"close without merging; the branch is kept\" class=\"btn danger\">Close</button></form>")
3132 if templ_7745c5c3_Err != nil {3166 if templ_7745c5c3_Err != nil {
3133 return templ_7745c5c3_Err3167 return templ_7745c5c3_Err
3134 }3168 }
3135- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 291, "</details>")3169+ if !p.Box.HeadGone && p.Box.ReadyAction == "" {
3136- if templ_7745c5c3_Err != nil {3170+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 295, "<details class=\"d-or\"><summary class=\"mute\">or from a terminal</summary>")
3137- return templ_7745c5c3_Err3171+ if templ_7745c5c3_Err != nil {
3172+ return templ_7745c5c3_Err
3173+ }
3174+ templ_7745c5c3_Err = CloneBlock(p.Box.CLI).Render(ctx, templ_7745c5c3_Buffer)
3175+ if templ_7745c5c3_Err != nil {
3176+ return templ_7745c5c3_Err
3177+ }
3178+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 296, "</details>")
3179+ if templ_7745c5c3_Err != nil {
3180+ return templ_7745c5c3_Err
3181+ }
3138 }3182 }
3139 }3183 }
3140- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 292, "</div></details>")3184+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 297, "</div></details>")
3141 if templ_7745c5c3_Err != nil {3185 if templ_7745c5c3_Err != nil {
3142 return templ_7745c5c3_Err3186 return templ_7745c5c3_Err
3143 }3187 }
@@ -3178,263 +3222,263 @@ func Compare(l Layout, p ComparePage) templ.Component {
3178 }()3222 }()
3179 }3223 }
3180 ctx = templ.InitializeContext(ctx)3224 ctx = templ.InitializeContext(ctx)
3181- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 293, "<header class=\"show mr-h\"><h1>")3225+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 298, "<header class=\"show mr-h\"><h1>")
3182 if templ_7745c5c3_Err != nil {3226 if templ_7745c5c3_Err != nil {
3183 return templ_7745c5c3_Err3227 return templ_7745c5c3_Err
3184 }3228 }
3185 var templ_7745c5c3_Var152 string3229 var templ_7745c5c3_Var152 string
3186 templ_7745c5c3_Var152, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)3230 templ_7745c5c3_Var152, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)
3187 if templ_7745c5c3_Err != nil {3231 if templ_7745c5c3_Err != nil {
3188- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 620, Col: 17}3232+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 643, Col: 17}
3189 }3233 }
3190 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var152))3234 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var152))
3191 if templ_7745c5c3_Err != nil {3235 if templ_7745c5c3_Err != nil {
3192 return templ_7745c5c3_Err3236 return templ_7745c5c3_Err
3193 }3237 }
3194- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 294, " → ")3238+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 299, " → ")
3195 if templ_7745c5c3_Err != nil {3239 if templ_7745c5c3_Err != nil {
3196 return templ_7745c5c3_Err3240 return templ_7745c5c3_Err
3197 }3241 }
3198 var templ_7745c5c3_Var153 string3242 var templ_7745c5c3_Var153 string
3199 templ_7745c5c3_Var153, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)3243 templ_7745c5c3_Var153, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
3200 if templ_7745c5c3_Err != nil {3244 if templ_7745c5c3_Err != nil {
3201- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 620, Col: 34}3245+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 643, Col: 34}
3202 }3246 }
3203 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var153))3247 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var153))
3204 if templ_7745c5c3_Err != nil {3248 if templ_7745c5c3_Err != nil {
3205 return templ_7745c5c3_Err3249 return templ_7745c5c3_Err
3206 }3250 }
3207- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 295, "</h1><dl class=\"kv show-kv\"><dt>branch</dt><dd><a href=\"")3251+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 300, "</h1><dl class=\"kv show-kv\"><dt>branch</dt><dd><a href=\"")
3208 if templ_7745c5c3_Err != nil {3252 if templ_7745c5c3_Err != nil {
3209 return templ_7745c5c3_Err3253 return templ_7745c5c3_Err
3210 }3254 }
3211 var templ_7745c5c3_Var154 templ.SafeURL3255 var templ_7745c5c3_Var154 templ.SafeURL
3212 templ_7745c5c3_Var154, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.SourceHref))3256 templ_7745c5c3_Var154, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.SourceHref))
3213 if templ_7745c5c3_Err != nil {3257 if templ_7745c5c3_Err != nil {
3214- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 623, Col: 45}3258+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 646, Col: 45}
3215 }3259 }
3216 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var154))3260 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var154))
3217 if templ_7745c5c3_Err != nil {3261 if templ_7745c5c3_Err != nil {
3218 return templ_7745c5c3_Err3262 return templ_7745c5c3_Err
3219 }3263 }
3220- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 296, "\">")3264+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 301, "\">")
3221 if templ_7745c5c3_Err != nil {3265 if templ_7745c5c3_Err != nil {
3222 return templ_7745c5c3_Err3266 return templ_7745c5c3_Err
3223 }3267 }
3224 var templ_7745c5c3_Var155 string3268 var templ_7745c5c3_Var155 string
3225 templ_7745c5c3_Var155, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)3269 templ_7745c5c3_Var155, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)
3226 if templ_7745c5c3_Err != nil {3270 if templ_7745c5c3_Err != nil {
3227- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 623, Col: 58}3271+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 646, Col: 58}
3228 }3272 }
3229 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var155))3273 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var155))
3230 if templ_7745c5c3_Err != nil {3274 if templ_7745c5c3_Err != nil {
3231 return templ_7745c5c3_Err3275 return templ_7745c5c3_Err
3232 }3276 }
3233- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 297, "</a></dd><dt>target</dt><dd><a href=\"")3277+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 302, "</a></dd><dt>target</dt><dd><a href=\"")
3234 if templ_7745c5c3_Err != nil {3278 if templ_7745c5c3_Err != nil {
3235 return templ_7745c5c3_Err3279 return templ_7745c5c3_Err
3236 }3280 }
3237 var templ_7745c5c3_Var156 templ.SafeURL3281 var templ_7745c5c3_Var156 templ.SafeURL
3238 templ_7745c5c3_Var156, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.TargetHref))3282 templ_7745c5c3_Var156, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.TargetHref))
3239 if templ_7745c5c3_Err != nil {3283 if templ_7745c5c3_Err != nil {
3240- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 625, Col: 45}3284+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 648, Col: 45}
3241 }3285 }
3242 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var156))3286 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var156))
3243 if templ_7745c5c3_Err != nil {3287 if templ_7745c5c3_Err != nil {
3244 return templ_7745c5c3_Err3288 return templ_7745c5c3_Err
3245 }3289 }
3246- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 298, "\">")3290+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 303, "\">")
3247 if templ_7745c5c3_Err != nil {3291 if templ_7745c5c3_Err != nil {
3248 return templ_7745c5c3_Err3292 return templ_7745c5c3_Err
3249 }3293 }
3250 var templ_7745c5c3_Var157 string3294 var templ_7745c5c3_Var157 string
3251 templ_7745c5c3_Var157, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)3295 templ_7745c5c3_Var157, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
3252 if templ_7745c5c3_Err != nil {3296 if templ_7745c5c3_Err != nil {
3253- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 625, Col: 58}3297+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 648, Col: 58}
3254 }3298 }
3255 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var157))3299 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var157))
3256 if templ_7745c5c3_Err != nil {3300 if templ_7745c5c3_Err != nil {
3257 return templ_7745c5c3_Err3301 return templ_7745c5c3_Err
3258 }3302 }
3259- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 299, "</a></dd><dt>ahead</dt><dd>")3303+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 304, "</a></dd><dt>ahead</dt><dd>")
3260 if templ_7745c5c3_Err != nil {3304 if templ_7745c5c3_Err != nil {
3261 return templ_7745c5c3_Err3305 return templ_7745c5c3_Err
3262 }3306 }
3263 var templ_7745c5c3_Var158 string3307 var templ_7745c5c3_Var158 string
3264 templ_7745c5c3_Var158, templ_7745c5c3_Err = templ.JoinStringErrs(p.AheadText)3308 templ_7745c5c3_Var158, templ_7745c5c3_Err = templ.JoinStringErrs(p.AheadText)
3265 if templ_7745c5c3_Err != nil {3309 if templ_7745c5c3_Err != nil {
3266- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 627, Col: 21}3310+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 650, Col: 21}
3267 }3311 }
3268 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var158))3312 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var158))
3269 if templ_7745c5c3_Err != nil {3313 if templ_7745c5c3_Err != nil {
3270 return templ_7745c5c3_Err3314 return templ_7745c5c3_Err
3271 }3315 }
3272- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 300, "</dd></dl></header>")3316+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 305, "</dd></dl></header>")
3273 if templ_7745c5c3_Err != nil {3317 if templ_7745c5c3_Err != nil {
3274 return templ_7745c5c3_Err3318 return templ_7745c5c3_Err
3275 }3319 }
3276 if p.Note != "" {3320 if p.Note != "" {
3277- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 301, "<p class=\"notice\">")3321+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 306, "<p class=\"notice\">")
3278 if templ_7745c5c3_Err != nil {3322 if templ_7745c5c3_Err != nil {
3279 return templ_7745c5c3_Err3323 return templ_7745c5c3_Err
3280 }3324 }
3281 var templ_7745c5c3_Var159 string3325 var templ_7745c5c3_Var159 string
3282 templ_7745c5c3_Var159, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note)3326 templ_7745c5c3_Var159, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note)
3283 if templ_7745c5c3_Err != nil {3327 if templ_7745c5c3_Err != nil {
3284- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 631, Col: 29}3328+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 654, Col: 29}
3285 }3329 }
3286 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var159))3330 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var159))
3287 if templ_7745c5c3_Err != nil {3331 if templ_7745c5c3_Err != nil {
3288 return templ_7745c5c3_Err3332 return templ_7745c5c3_Err
3289 }3333 }
3290- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 302, "</p>")3334+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 307, "</p>")
3291 if templ_7745c5c3_Err != nil {3335 if templ_7745c5c3_Err != nil {
3292 return templ_7745c5c3_Err3336 return templ_7745c5c3_Err
3293 }3337 }
3294 }3338 }
3295- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 303, " ")3339+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 308, " ")
3296 if templ_7745c5c3_Err != nil {3340 if templ_7745c5c3_Err != nil {
3297 return templ_7745c5c3_Err3341 return templ_7745c5c3_Err
3298 }3342 }
3299 if p.Existing != nil {3343 if p.Existing != nil {
3300- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 304, "<p class=\"notice\">an open merge request already covers these branches: <a href=\"")3344+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 309, "<p class=\"notice\">an open merge request already covers these branches: <a href=\"")
3301 if templ_7745c5c3_Err != nil {3345 if templ_7745c5c3_Err != nil {
3302 return templ_7745c5c3_Err3346 return templ_7745c5c3_Err
3303 }3347 }
3304 var templ_7745c5c3_Var160 templ.SafeURL3348 var templ_7745c5c3_Var160 templ.SafeURL
3305 templ_7745c5c3_Var160, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Existing.Href))3349 templ_7745c5c3_Var160, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Existing.Href))
3306 if templ_7745c5c3_Err != nil {3350 if templ_7745c5c3_Err != nil {
3307- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 634, Col: 114}3351+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 657, Col: 114}
3308 }3352 }
3309 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var160))3353 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var160))
3310 if templ_7745c5c3_Err != nil {3354 if templ_7745c5c3_Err != nil {
3311 return templ_7745c5c3_Err3355 return templ_7745c5c3_Err
3312 }3356 }
3313- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 305, "\">")3357+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 310, "\">")
3314 if templ_7745c5c3_Err != nil {3358 if templ_7745c5c3_Err != nil {
3315 return templ_7745c5c3_Err3359 return templ_7745c5c3_Err
3316 }3360 }
3317 var templ_7745c5c3_Var161 string3361 var templ_7745c5c3_Var161 string
3318 templ_7745c5c3_Var161, templ_7745c5c3_Err = templ.JoinStringErrs(p.Existing.Label)3362 templ_7745c5c3_Var161, templ_7745c5c3_Err = templ.JoinStringErrs(p.Existing.Label)
3319 if templ_7745c5c3_Err != nil {3363 if templ_7745c5c3_Err != nil {
3320- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 634, Col: 135}3364+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 657, Col: 135}
3321 }3365 }
3322 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var161))3366 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var161))
3323 if templ_7745c5c3_Err != nil {3367 if templ_7745c5c3_Err != nil {
3324 return templ_7745c5c3_Err3368 return templ_7745c5c3_Err
3325 }3369 }
3326- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 306, "</a></p>")3370+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 311, "</a></p>")
3327 if templ_7745c5c3_Err != nil {3371 if templ_7745c5c3_Err != nil {
3328 return templ_7745c5c3_Err3372 return templ_7745c5c3_Err
3329 }3373 }
3330 }3374 }
3331- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 307, " ")3375+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 312, " ")
3332 if templ_7745c5c3_Err != nil {3376 if templ_7745c5c3_Err != nil {
3333 return templ_7745c5c3_Err3377 return templ_7745c5c3_Err
3334 }3378 }
3335 if p.Create != nil {3379 if p.Create != nil {
3336- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 308, "<form class=\"cform create\" method=\"post\" action=\"")3380+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 313, "<form class=\"cform create\" method=\"post\" action=\"")
3337 if templ_7745c5c3_Err != nil {3381 if templ_7745c5c3_Err != nil {
3338 return templ_7745c5c3_Err3382 return templ_7745c5c3_Err
3339 }3383 }
3340 var templ_7745c5c3_Var162 templ.SafeURL3384 var templ_7745c5c3_Var162 templ.SafeURL
3341 templ_7745c5c3_Var162, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Create.Action))3385 templ_7745c5c3_Var162, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Create.Action))
3342 if templ_7745c5c3_Err != nil {3386 if templ_7745c5c3_Err != nil {
3343- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 637, Col: 83}3387+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 660, Col: 83}
3344 }3388 }
3345 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var162))3389 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var162))
3346 if templ_7745c5c3_Err != nil {3390 if templ_7745c5c3_Err != nil {
3347 return templ_7745c5c3_Err3391 return templ_7745c5c3_Err
3348 }3392 }
3349- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 309, "\"><input type=\"hidden\" name=\"source\" value=\"")3393+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 314, "\"><input type=\"hidden\" name=\"source\" value=\"")
3350 if templ_7745c5c3_Err != nil {3394 if templ_7745c5c3_Err != nil {
3351 return templ_7745c5c3_Err3395 return templ_7745c5c3_Err
3352 }3396 }
3353 var templ_7745c5c3_Var163 string3397 var templ_7745c5c3_Var163 string
3354 templ_7745c5c3_Var163, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Source)3398 templ_7745c5c3_Var163, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Source)
3355 if templ_7745c5c3_Err != nil {3399 if templ_7745c5c3_Err != nil {
3356- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 638, Col: 62}3400+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 661, Col: 62}
3357 }3401 }
3358 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var163)3402 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var163)
3359 if templ_7745c5c3_Err != nil {3403 if templ_7745c5c3_Err != nil {
3360 return templ_7745c5c3_Err3404 return templ_7745c5c3_Err
3361 }3405 }
3362- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 310, "\"> <input type=\"hidden\" name=\"target\" value=\"")3406+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 315, "\"> <input type=\"hidden\" name=\"target\" value=\"")
3363 if templ_7745c5c3_Err != nil {3407 if templ_7745c5c3_Err != nil {
3364 return templ_7745c5c3_Err3408 return templ_7745c5c3_Err
3365 }3409 }
3366 var templ_7745c5c3_Var164 string3410 var templ_7745c5c3_Var164 string
3367 templ_7745c5c3_Var164, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Target)3411 templ_7745c5c3_Var164, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Target)
3368 if templ_7745c5c3_Err != nil {3412 if templ_7745c5c3_Err != nil {
3369- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 639, Col: 62}3413+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 662, Col: 62}
3370 }3414 }
3371 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var164)3415 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var164)
3372 if templ_7745c5c3_Err != nil {3416 if templ_7745c5c3_Err != nil {
3373 return templ_7745c5c3_Err3417 return templ_7745c5c3_Err
3374 }3418 }
3375- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 311, "\"> <label for=\"mr-title\">title</label> <input id=\"mr-title\" name=\"title\" type=\"text\" maxlength=\"120\" required value=\"")3419+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 316, "\"> <label for=\"mr-title\">title</label> <input id=\"mr-title\" name=\"title\" type=\"text\" maxlength=\"120\" required value=\"")
3376 if templ_7745c5c3_Err != nil {3420 if templ_7745c5c3_Err != nil {
3377 return templ_7745c5c3_Err3421 return templ_7745c5c3_Err
3378 }3422 }
3379 var templ_7745c5c3_Var165 string3423 var templ_7745c5c3_Var165 string
3380 templ_7745c5c3_Var165, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Title)3424 templ_7745c5c3_Var165, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Title)
3381 if templ_7745c5c3_Err != nil {3425 if templ_7745c5c3_Err != nil {
3382- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 641, Col: 97}3426+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 664, Col: 97}
3383 }3427 }
3384 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var165)3428 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var165)
3385 if templ_7745c5c3_Err != nil {3429 if templ_7745c5c3_Err != nil {
3386 return templ_7745c5c3_Err3430 return templ_7745c5c3_Err
3387 }3431 }
3388- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 312, "\" autocomplete=\"off\"> <label for=\"mr-desc\">description</label> <textarea id=\"mr-desc\" name=\"description\" rows=\"4\" maxlength=\"8000\" placeholder=\"Markdown, optional\"></textarea><div class=\"f-btns\"><button type=\"submit\" class=\"btn primary\">Create merge request</button></div></form>")3432+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 317, "\" autocomplete=\"off\"> <label for=\"mr-desc\">description</label> <textarea id=\"mr-desc\" name=\"description\" rows=\"4\" maxlength=\"8000\" placeholder=\"Markdown, optional\"></textarea><div class=\"f-btns\"><button type=\"submit\" class=\"btn primary\">Create merge request</button></div></form>")
3389 if templ_7745c5c3_Err != nil {3433 if templ_7745c5c3_Err != nil {
3390 return templ_7745c5c3_Err3434 return templ_7745c5c3_Err
3391 }3435 }
3392 }3436 }
3393- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 313, " ")3437+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 318, " ")
3394 if templ_7745c5c3_Err != nil {3438 if templ_7745c5c3_Err != nil {
3395 return templ_7745c5c3_Err3439 return templ_7745c5c3_Err
3396 }3440 }
3397 if p.HasDiff {3441 if p.HasDiff {
3398- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 314, "<div class=\"diff-tools\" role=\"group\" aria-label=\"Diff view\"><span class=\"dim\">")3442+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 319, "<div class=\"diff-tools\" role=\"group\" aria-label=\"Diff view\"><span class=\"dim\">")
3399 if templ_7745c5c3_Err != nil {3443 if templ_7745c5c3_Err != nil {
3400 return templ_7745c5c3_Err3444 return templ_7745c5c3_Err
3401 }3445 }
3402 var templ_7745c5c3_Var166 string3446 var templ_7745c5c3_Var166 string
3403 templ_7745c5c3_Var166, templ_7745c5c3_Err = templ.JoinStringErrs(plural(p.NFiles, "file", "files"))3447 templ_7745c5c3_Var166, templ_7745c5c3_Err = templ.JoinStringErrs(plural(p.NFiles, "file", "files"))
3404 if templ_7745c5c3_Err != nil {3448 if templ_7745c5c3_Err != nil {
3405- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 651, Col: 57}3449+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 674, Col: 57}
3406 }3450 }
3407 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var166))3451 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var166))
3408 if templ_7745c5c3_Err != nil {3452 if templ_7745c5c3_Err != nil {
3409 return templ_7745c5c3_Err3453 return templ_7745c5c3_Err
3410 }3454 }
3411- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 315, " · <span class=\"plus\">+")3455+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 320, " · <span class=\"plus\">+")
3412 if templ_7745c5c3_Err != nil {3456 if templ_7745c5c3_Err != nil {
3413 return templ_7745c5c3_Err3457 return templ_7745c5c3_Err
3414 }3458 }
3415 var templ_7745c5c3_Var167 string3459 var templ_7745c5c3_Var167 string
3416 templ_7745c5c3_Var167, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Adds))3460 templ_7745c5c3_Var167, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Adds))
3417 if templ_7745c5c3_Err != nil {3461 if templ_7745c5c3_Err != nil {
3418- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 651, Col: 97}3462+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 674, Col: 97}
3419 }3463 }
3420 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var167))3464 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var167))
3421 if templ_7745c5c3_Err != nil {3465 if templ_7745c5c3_Err != nil {
3422 return templ_7745c5c3_Err3466 return templ_7745c5c3_Err
3423 }3467 }
3424- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 316, "</span> <span class=\"minus\">-")3468+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 321, "</span> <span class=\"minus\">-")
3425 if templ_7745c5c3_Err != nil {3469 if templ_7745c5c3_Err != nil {
3426 return templ_7745c5c3_Err3470 return templ_7745c5c3_Err
3427 }3471 }
3428 var templ_7745c5c3_Var168 string3472 var templ_7745c5c3_Var168 string
3429 templ_7745c5c3_Var168, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Dels))3473 templ_7745c5c3_Var168, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Dels))
3430 if templ_7745c5c3_Err != nil {3474 if templ_7745c5c3_Err != nil {
3431- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 651, Col: 142}3475+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 674, Col: 142}
3432 }3476 }
3433 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var168))3477 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var168))
3434 if templ_7745c5c3_Err != nil {3478 if templ_7745c5c3_Err != nil {
3435 return templ_7745c5c3_Err3479 return templ_7745c5c3_Err
3436 }3480 }
3437- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 317, "</span></span> <span class=\"grow\"></span>")3481+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 322, "</span></span> <span class=\"grow\"></span>")
3438 if templ_7745c5c3_Err != nil {3482 if templ_7745c5c3_Err != nil {
3439 return templ_7745c5c3_Err3483 return templ_7745c5c3_Err
3440 }3484 }
@@ -3442,64 +3486,64 @@ func Compare(l Layout, p ComparePage) templ.Component {
3442 if templ_7745c5c3_Err != nil {3486 if templ_7745c5c3_Err != nil {
3443 return templ_7745c5c3_Err3487 return templ_7745c5c3_Err
3444 }3488 }
3445- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 318, "</div>")3489+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 323, "</div>")
3446 if templ_7745c5c3_Err != nil {3490 if templ_7745c5c3_Err != nil {
3447 return templ_7745c5c3_Err3491 return templ_7745c5c3_Err
3448 }3492 }
3449 if p.Invisible {3493 if p.Invisible {
3450- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 319, "<p class=\"notice\">this diff holds invisible characters (direction controls, zero-width characters). They are shown as <span class=\"inv\">&lt;U+XXXX&gt;</span> markers, never applied.</p>")3494+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 324, "<p class=\"notice\">this diff holds invisible characters (direction controls, zero-width characters). They are shown as <span class=\"inv\">&lt;U+XXXX&gt;</span> markers, never applied.</p>")
3451 if templ_7745c5c3_Err != nil {3495 if templ_7745c5c3_Err != nil {
3452 return templ_7745c5c3_Err3496 return templ_7745c5c3_Err
3453 }3497 }
3454 }3498 }
3455- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 320, " <div id=\"diffs\"")3499+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 325, " <div id=\"diffs\"")
3456 if templ_7745c5c3_Err != nil {3500 if templ_7745c5c3_Err != nil {
3457 return templ_7745c5c3_Err3501 return templ_7745c5c3_Err
3458 }3502 }
3459 if p.Both {3503 if p.Both {
3460- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 321, " data-diff=\"")3504+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 326, " data-diff=\"")
3461 if templ_7745c5c3_Err != nil {3505 if templ_7745c5c3_Err != nil {
3462 return templ_7745c5c3_Err3506 return templ_7745c5c3_Err
3463 }3507 }
3464 var templ_7745c5c3_Var169 string3508 var templ_7745c5c3_Var169 string
3465 templ_7745c5c3_Var169, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)3509 templ_7745c5c3_Var169, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
3466 if templ_7745c5c3_Err != nil {3510 if templ_7745c5c3_Err != nil {
3467- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 664, Col: 23}3511+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 687, Col: 23}
3468 }3512 }
3469 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var169)3513 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var169)
3470 if templ_7745c5c3_Err != nil {3514 if templ_7745c5c3_Err != nil {
3471 return templ_7745c5c3_Err3515 return templ_7745c5c3_Err
3472 }3516 }
3473- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 322, "\"")3517+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 327, "\"")
3474 if templ_7745c5c3_Err != nil {3518 if templ_7745c5c3_Err != nil {
3475 return templ_7745c5c3_Err3519 return templ_7745c5c3_Err
3476 }3520 }
3477 } else {3521 } else {
3478- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 323, " data-view=\"")3522+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 328, " data-view=\"")
3479 if templ_7745c5c3_Err != nil {3523 if templ_7745c5c3_Err != nil {
3480 return templ_7745c5c3_Err3524 return templ_7745c5c3_Err
3481 }3525 }
3482 var templ_7745c5c3_Var170 string3526 var templ_7745c5c3_Var170 string
3483 templ_7745c5c3_Var170, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)3527 templ_7745c5c3_Var170, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
3484 if templ_7745c5c3_Err != nil {3528 if templ_7745c5c3_Err != nil {
3485- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 666, Col: 23}3529+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 689, Col: 23}
3486 }3530 }
3487 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var170)3531 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var170)
3488 if templ_7745c5c3_Err != nil {3532 if templ_7745c5c3_Err != nil {
3489 return templ_7745c5c3_Err3533 return templ_7745c5c3_Err
3490 }3534 }
3491- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 324, "\"")3535+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 329, "\"")
3492 if templ_7745c5c3_Err != nil {3536 if templ_7745c5c3_Err != nil {
3493 return templ_7745c5c3_Err3537 return templ_7745c5c3_Err
3494 }3538 }
3495 }3539 }
3496 if p.Both && !p.Pinned {3540 if p.Both && !p.Pinned {
3497- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 325, " hx-live=\"this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff\"")3541+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 330, " hx-live=\"this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff\"")
3498 if templ_7745c5c3_Err != nil {3542 if templ_7745c5c3_Err != nil {
3499 return templ_7745c5c3_Err3543 return templ_7745c5c3_Err
3500 }3544 }
3501 }3545 }
3502- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 326, ">")3546+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 331, ">")
3503 if templ_7745c5c3_Err != nil {3547 if templ_7745c5c3_Err != nil {
3504 return templ_7745c5c3_Err3548 return templ_7745c5c3_Err
3505 }3549 }
@@ -3509,7 +3553,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
3509 return templ_7745c5c3_Err3553 return templ_7745c5c3_Err
3510 }3554 }
3511 }3555 }
3512- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 327, "</div>")3556+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 332, "</div>")
3513 if templ_7745c5c3_Err != nil {3557 if templ_7745c5c3_Err != nil {
3514 return templ_7745c5c3_Err3558 return templ_7745c5c3_Err
3515 }3559 }
@@ -3545,77 +3589,77 @@ func compareRail(p ComparePage) templ.Component {
3545 templ_7745c5c3_Var171 = templ.NopComponent3589 templ_7745c5c3_Var171 = templ.NopComponent
3546 }3590 }
3547 ctx = templ.ClearChildren(ctx)3591 ctx = templ.ClearChildren(ctx)
3548- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 328, "<section aria-labelledby=\"r-ahead\"><h2 id=\"r-ahead\">Commits <span class=\"count\">")3592+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 333, "<section aria-labelledby=\"r-ahead\"><h2 id=\"r-ahead\">Commits <span class=\"count\">")
3549 if templ_7745c5c3_Err != nil {3593 if templ_7745c5c3_Err != nil {
3550 return templ_7745c5c3_Err3594 return templ_7745c5c3_Err
3551 }3595 }
3552 var templ_7745c5c3_Var172 string3596 var templ_7745c5c3_Var172 string
3553 templ_7745c5c3_Var172, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Ahead)))3597 templ_7745c5c3_Var172, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Ahead)))
3554 if templ_7745c5c3_Err != nil {3598 if templ_7745c5c3_Err != nil {
3555- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 682, Col: 67}3599+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 705, Col: 67}
3556 }3600 }
3557 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var172))3601 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var172))
3558 if templ_7745c5c3_Err != nil {3602 if templ_7745c5c3_Err != nil {
3559 return templ_7745c5c3_Err3603 return templ_7745c5c3_Err
3560 }3604 }
3561- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 329, "</span></h2><ul class=\"pcommits\">")3605+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 334, "</span></h2><ul class=\"pcommits\">")
3562 if templ_7745c5c3_Err != nil {3606 if templ_7745c5c3_Err != nil {
3563 return templ_7745c5c3_Err3607 return templ_7745c5c3_Err
3564 }3608 }
3565 for _, c := range p.Ahead {3609 for _, c := range p.Ahead {
3566- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 330, "<li><a href=\"")3610+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 335, "<li><a href=\"")
3567 if templ_7745c5c3_Err != nil {3611 if templ_7745c5c3_Err != nil {
3568 return templ_7745c5c3_Err3612 return templ_7745c5c3_Err
3569 }3613 }
3570 var templ_7745c5c3_Var173 templ.SafeURL3614 var templ_7745c5c3_Var173 templ.SafeURL
3571 templ_7745c5c3_Var173, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.CHref))3615 templ_7745c5c3_Var173, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.CHref))
3572 if templ_7745c5c3_Err != nil {3616 if templ_7745c5c3_Err != nil {
3573- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 686, Col: 37}3617+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 709, Col: 37}
3574 }3618 }
3575 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var173))3619 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var173))
3576 if templ_7745c5c3_Err != nil {3620 if templ_7745c5c3_Err != nil {
3577 return templ_7745c5c3_Err3621 return templ_7745c5c3_Err
3578 }3622 }
3579- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 331, "\">")3623+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 336, "\">")
3580 if templ_7745c5c3_Err != nil {3624 if templ_7745c5c3_Err != nil {
3581 return templ_7745c5c3_Err3625 return templ_7745c5c3_Err
3582 }3626 }
3583 var templ_7745c5c3_Var174 string3627 var templ_7745c5c3_Var174 string
3584 templ_7745c5c3_Var174, templ_7745c5c3_Err = templ.JoinStringErrs(c.Short)3628 templ_7745c5c3_Var174, templ_7745c5c3_Err = templ.JoinStringErrs(c.Short)
3585 if templ_7745c5c3_Err != nil {3629 if templ_7745c5c3_Err != nil {
3586- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 686, Col: 49}3630+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 709, Col: 49}
3587 }3631 }
3588 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var174))3632 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var174))
3589 if templ_7745c5c3_Err != nil {3633 if templ_7745c5c3_Err != nil {
3590 return templ_7745c5c3_Err3634 return templ_7745c5c3_Err
3591 }3635 }
3592- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 332, "</a> <span class=\"s\">")3636+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 337, "</a> <span class=\"s\">")
3593 if templ_7745c5c3_Err != nil {3637 if templ_7745c5c3_Err != nil {
3594 return templ_7745c5c3_Err3638 return templ_7745c5c3_Err
3595 }3639 }
3596 var templ_7745c5c3_Var175 string3640 var templ_7745c5c3_Var175 string
3597 templ_7745c5c3_Var175, templ_7745c5c3_Err = templ.JoinStringErrs(c.Subject)3641 templ_7745c5c3_Var175, templ_7745c5c3_Err = templ.JoinStringErrs(c.Subject)
3598 if templ_7745c5c3_Err != nil {3642 if templ_7745c5c3_Err != nil {
3599- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 687, Col: 32}3643+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 710, Col: 32}
3600 }3644 }
3601 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var175))3645 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var175))
3602 if templ_7745c5c3_Err != nil {3646 if templ_7745c5c3_Err != nil {
3603 return templ_7745c5c3_Err3647 return templ_7745c5c3_Err
3604 }3648 }
3605- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 333, "</span> <span class=\"mute\">")3649+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 338, "</span> <span class=\"mute\">")
3606 if templ_7745c5c3_Err != nil {3650 if templ_7745c5c3_Err != nil {
3607 return templ_7745c5c3_Err3651 return templ_7745c5c3_Err
3608 }3652 }
3609 var templ_7745c5c3_Var176 string3653 var templ_7745c5c3_Var176 string
3610 templ_7745c5c3_Var176, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)3654 templ_7745c5c3_Var176, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)
3611 if templ_7745c5c3_Err != nil {3655 if templ_7745c5c3_Err != nil {
3612- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 689, Col: 16}3656+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 712, Col: 16}
3613 }3657 }
3614 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var176))3658 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var176))
3615 if templ_7745c5c3_Err != nil {3659 if templ_7745c5c3_Err != nil {
3616 return templ_7745c5c3_Err3660 return templ_7745c5c3_Err
3617 }3661 }
3618- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 334, " ")3662+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 339, " ")
3619 if templ_7745c5c3_Err != nil {3663 if templ_7745c5c3_Err != nil {
3620 return templ_7745c5c3_Err3664 return templ_7745c5c3_Err
3621 }3665 }
@@ -3623,90 +3667,90 @@ func compareRail(p ComparePage) templ.Component {
3623 var templ_7745c5c3_Var177 string3667 var templ_7745c5c3_Var177 string
3624 templ_7745c5c3_Var177, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")3668 templ_7745c5c3_Var177, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")
3625 if templ_7745c5c3_Err != nil {3669 if templ_7745c5c3_Err != nil {
3626- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 691, Col: 15}3670+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 714, Col: 15}
3627 }3671 }
3628 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var177))3672 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var177))
3629 if templ_7745c5c3_Err != nil {3673 if templ_7745c5c3_Err != nil {
3630 return templ_7745c5c3_Err3674 return templ_7745c5c3_Err
3631 }3675 }
3632- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 335, "<time datetime=\"")3676+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 340, "<time datetime=\"")
3633 if templ_7745c5c3_Err != nil {3677 if templ_7745c5c3_Err != nil {
3634 return templ_7745c5c3_Err3678 return templ_7745c5c3_Err
3635 }3679 }
3636 var templ_7745c5c3_Var178 string3680 var templ_7745c5c3_Var178 string
3637 templ_7745c5c3_Var178, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)3681 templ_7745c5c3_Var178, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)
3638 if templ_7745c5c3_Err != nil {3682 if templ_7745c5c3_Err != nil {
3639- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 691, Col: 42}3683+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 714, Col: 42}
3640 }3684 }
3641 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var178)3685 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var178)
3642 if templ_7745c5c3_Err != nil {3686 if templ_7745c5c3_Err != nil {
3643 return templ_7745c5c3_Err3687 return templ_7745c5c3_Err
3644 }3688 }
3645- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 336, "\">")3689+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 341, "\">")
3646 if templ_7745c5c3_Err != nil {3690 if templ_7745c5c3_Err != nil {
3647 return templ_7745c5c3_Err3691 return templ_7745c5c3_Err
3648 }3692 }
3649 var templ_7745c5c3_Var179 string3693 var templ_7745c5c3_Var179 string
3650 templ_7745c5c3_Var179, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)3694 templ_7745c5c3_Var179, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)
3651 if templ_7745c5c3_Err != nil {3695 if templ_7745c5c3_Err != nil {
3652- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 691, Col: 53}3696+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 714, Col: 53}
3653 }3697 }
3654 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var179))3698 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var179))
3655 if templ_7745c5c3_Err != nil {3699 if templ_7745c5c3_Err != nil {
3656 return templ_7745c5c3_Err3700 return templ_7745c5c3_Err
3657 }3701 }
3658- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 337, "</time>")3702+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 342, "</time>")
3659 if templ_7745c5c3_Err != nil {3703 if templ_7745c5c3_Err != nil {
3660 return templ_7745c5c3_Err3704 return templ_7745c5c3_Err
3661 }3705 }
3662 }3706 }
3663- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 338, "</span></li>")3707+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 343, "</span></li>")
3664 if templ_7745c5c3_Err != nil {3708 if templ_7745c5c3_Err != nil {
3665 return templ_7745c5c3_Err3709 return templ_7745c5c3_Err
3666 }3710 }
3667 }3711 }
3668- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 339, "</ul>")3712+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 344, "</ul>")
3669 if templ_7745c5c3_Err != nil {3713 if templ_7745c5c3_Err != nil {
3670 return templ_7745c5c3_Err3714 return templ_7745c5c3_Err
3671 }3715 }
3672 if len(p.Ahead) == 0 {3716 if len(p.Ahead) == 0 {
3673- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 340, "<p class=\"dim\">no commit ahead of ")3717+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 345, "<p class=\"dim\">no commit ahead of ")
3674 if templ_7745c5c3_Err != nil {3718 if templ_7745c5c3_Err != nil {
3675 return templ_7745c5c3_Err3719 return templ_7745c5c3_Err
3676 }3720 }
3677 var templ_7745c5c3_Var180 string3721 var templ_7745c5c3_Var180 string
3678 templ_7745c5c3_Var180, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)3722 templ_7745c5c3_Var180, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
3679 if templ_7745c5c3_Err != nil {3723 if templ_7745c5c3_Err != nil {
3680- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 698, Col: 47}3724+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 721, Col: 47}
3681 }3725 }
3682 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var180))3726 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var180))
3683 if templ_7745c5c3_Err != nil {3727 if templ_7745c5c3_Err != nil {
3684 return templ_7745c5c3_Err3728 return templ_7745c5c3_Err
3685 }3729 }
3686- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 341, ".</p>")3730+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 346, ".</p>")
3687 if templ_7745c5c3_Err != nil {3731 if templ_7745c5c3_Err != nil {
3688 return templ_7745c5c3_Err3732 return templ_7745c5c3_Err
3689 }3733 }
3690 }3734 }
3691- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 342, "</section>")3735+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 347, "</section>")
3692 if templ_7745c5c3_Err != nil {3736 if templ_7745c5c3_Err != nil {
3693 return templ_7745c5c3_Err3737 return templ_7745c5c3_Err
3694 }3738 }
3695 if p.HasDiff {3739 if p.HasDiff {
3696- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 343, "<section aria-labelledby=\"r-files\"><h2 id=\"r-files\">Files <span class=\"count\">")3740+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 348, "<section aria-labelledby=\"r-files\"><h2 id=\"r-files\">Files <span class=\"count\">")
3697 if templ_7745c5c3_Err != nil {3741 if templ_7745c5c3_Err != nil {
3698 return templ_7745c5c3_Err3742 return templ_7745c5c3_Err
3699 }3743 }
3700 var templ_7745c5c3_Var181 string3744 var templ_7745c5c3_Var181 string
3701 templ_7745c5c3_Var181, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))3745 templ_7745c5c3_Var181, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))
3702 if templ_7745c5c3_Err != nil {3746 if templ_7745c5c3_Err != nil {
3703- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 703, Col: 66}3747+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 726, Col: 66}
3704 }3748 }
3705 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var181))3749 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var181))
3706 if templ_7745c5c3_Err != nil {3750 if templ_7745c5c3_Err != nil {
3707 return templ_7745c5c3_Err3751 return templ_7745c5c3_Err
3708 }3752 }
3709- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 344, "</span></h2>")3753+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 349, "</span></h2>")
3710 if templ_7745c5c3_Err != nil {3754 if templ_7745c5c3_Err != nil {
3711 return templ_7745c5c3_Err3755 return templ_7745c5c3_Err
3712 }3756 }
@@ -3714,12 +3758,12 @@ func compareRail(p ComparePage) templ.Component {
3714 if templ_7745c5c3_Err != nil {3758 if templ_7745c5c3_Err != nil {
3715 return templ_7745c5c3_Err3759 return templ_7745c5c3_Err
3716 }3760 }
3717- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 345, "</section>")3761+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 350, "</section>")
3718 if templ_7745c5c3_Err != nil {3762 if templ_7745c5c3_Err != nil {
3719 return templ_7745c5c3_Err3763 return templ_7745c5c3_Err
3720 }3764 }
3721 }3765 }
3722- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 346, "<section aria-labelledby=\"r-cli\"><h2 id=\"r-cli\">From a terminal</h2>")3766+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 351, "<section aria-labelledby=\"r-cli\"><h2 id=\"r-cli\">From a terminal</h2>")
3723 if templ_7745c5c3_Err != nil {3767 if templ_7745c5c3_Err != nil {
3724 return templ_7745c5c3_Err3768 return templ_7745c5c3_Err
3725 }3769 }
@@ -3727,7 +3771,7 @@ func compareRail(p ComparePage) templ.Component {
3727 if templ_7745c5c3_Err != nil {3771 if templ_7745c5c3_Err != nil {
3728 return templ_7745c5c3_Err3772 return templ_7745c5c3_Err
3729 }3773 }
3730- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 347, "</section>")3774+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 352, "</section>")
3731 if templ_7745c5c3_Err != nil {3775 if templ_7745c5c3_Err != nil {
3732 return templ_7745c5c3_Err3776 return templ_7745c5c3_Err
3733 }3777 }
M internal/adapters/web/mr_test.go +32 -0
@@ -128,3 +128,35 @@ func TestMergeabilityLiveEvents(t *testing.T) {
128128 require.NoError(t, err)
129129 assert.Empty(t, fs)
130130 }
131+
132+func TestMRPanelsAndMenus(t *testing.T) {
133+ p := MRPage{CommitCount: "500+", CommitsNote: "more commits", Modes: []string{"squash", "merge"}, ChecksBlock: true,
134+ ChecksSum: ChecksSummary{Total: 2, Label: "1/2", Title: "1/2 failed"}, Box: &MergeBox{Signed: true, Fingerprint: "fingerprint", HeadGone: true}}
135+ footer := renderToString(t, mrFooter(p))
136+ assert.Contains(t, footer, `<footer class="mr-footer"><details id="mr-panels">`)
137+ assert.Contains(t, footer, `data-mr-tabs`)
138+ assert.Contains(t, footer, `id="mr-commits"`)
139+ assert.Contains(t, footer, `id="mr-checks"`)
140+ assert.Contains(t, footer, `<table class="mr-commits">`)
141+ assert.Contains(t, footer, "500+")
142+ assert.Contains(t, footer, "more commits")
143+ assert.Contains(t, footer, "1/2 failed")
144+ rail := renderToString(t, mrRail(p))
145+ assert.Contains(t, rail, "g f")
146+ for _, text := range []string{"Checks", "Commits", "Settings", "mr-checks"} {
147+ assert.NotContains(t, rail, text)
148+ }
149+ more := renderToString(t, moreMenu(p))
150+ for _, text := range []string{"Merge settings", "squash, merge", "failing ones block", `id="mr-signing"`, "fingerprint", "ermite signing-key show"} {
151+ assert.Contains(t, more, text)
152+ }
153+ merge := renderToString(t, mergeMenu(p))
154+ assert.NotContains(t, merge, `<dl`)
155+ assert.NotContains(t, merge, `mr-signing`)
156+ assert.Contains(t, merge, "the source branch was deleted")
157+ bar := renderToString(t, mrBar(MRPage{}))
158+ assert.Contains(t, bar, `id="mr-ck"`)
159+ assert.Contains(t, bar, `href="#mr-checks"`)
160+ assert.Contains(t, bar, "Merge settings")
161+ assert.NotContains(t, bar, ">Close</button>")
162+}
@@ -128,3 +128,35 @@ func TestMergeabilityLiveEvents(t *testing.T) {
128 require.NoError(t, err)128 require.NoError(t, err)
129 assert.Empty(t, fs)129 assert.Empty(t, fs)
130 }130 }
131+
132+func TestMRPanelsAndMenus(t *testing.T) {
133+ p := MRPage{CommitCount: "500+", CommitsNote: "more commits", Modes: []string{"squash", "merge"}, ChecksBlock: true,
134+ ChecksSum: ChecksSummary{Total: 2, Label: "1/2", Title: "1/2 failed"}, Box: &MergeBox{Signed: true, Fingerprint: "fingerprint", HeadGone: true}}
135+ footer := renderToString(t, mrFooter(p))
136+ assert.Contains(t, footer, `<footer class="mr-footer"><details id="mr-panels">`)
137+ assert.Contains(t, footer, `data-mr-tabs`)
138+ assert.Contains(t, footer, `id="mr-commits"`)
139+ assert.Contains(t, footer, `id="mr-checks"`)
140+ assert.Contains(t, footer, `<table class="mr-commits">`)
141+ assert.Contains(t, footer, "500+")
142+ assert.Contains(t, footer, "more commits")
143+ assert.Contains(t, footer, "1/2 failed")
144+ rail := renderToString(t, mrRail(p))
145+ assert.Contains(t, rail, "g f")
146+ for _, text := range []string{"Checks", "Commits", "Settings", "mr-checks"} {
147+ assert.NotContains(t, rail, text)
148+ }
149+ more := renderToString(t, moreMenu(p))
150+ for _, text := range []string{"Merge settings", "squash, merge", "failing ones block", `id="mr-signing"`, "fingerprint", "ermite signing-key show"} {
151+ assert.Contains(t, more, text)
152+ }
153+ merge := renderToString(t, mergeMenu(p))
154+ assert.NotContains(t, merge, `<dl`)
155+ assert.NotContains(t, merge, `mr-signing`)
156+ assert.Contains(t, merge, "the source branch was deleted")
157+ bar := renderToString(t, mrBar(MRPage{}))
158+ assert.Contains(t, bar, `id="mr-ck"`)
159+ assert.Contains(t, bar, `href="#mr-checks"`)
160+ assert.Contains(t, bar, "Merge settings")
161+ assert.NotContains(t, bar, ">Close</button>")
162+}
M internal/adapters/web/signature_test.go +1 -1
@@ -145,7 +145,7 @@ func TestCommitPageShowsTheSignature(t *testing.T) {
145145 func TestMergeRequestCommitsShowTheSignatureBadge(t *testing.T) {
146146 t.Parallel()
147147 signed := signatureBadge(verification(domain.FormatGPG, domain.StatusVerified, gpgFP, ""), false)
148- got := renderToString(t, mrRail(MRPage{Commits: []MRCommit{
148+ got := renderToString(t, mrFooter(MRPage{Commits: []MRCommit{
149149 {Short: "aaaaaaa", Href: "/r/commit/a", Subject: "signed", Sig: signed},
150150 {Short: "bbbbbbb", Href: "/r/commit/b", Subject: "unsigned"},
151151 }}))
@@ -145,7 +145,7 @@ func TestCommitPageShowsTheSignature(t *testing.T) {
145 func TestMergeRequestCommitsShowTheSignatureBadge(t *testing.T) {145 func TestMergeRequestCommitsShowTheSignatureBadge(t *testing.T) {
146 t.Parallel()146 t.Parallel()
147 signed := signatureBadge(verification(domain.FormatGPG, domain.StatusVerified, gpgFP, ""), false)147 signed := signatureBadge(verification(domain.FormatGPG, domain.StatusVerified, gpgFP, ""), false)
148- got := renderToString(t, mrRail(MRPage{Commits: []MRCommit{148+ got := renderToString(t, mrFooter(MRPage{Commits: []MRCommit{
149 {Short: "aaaaaaa", Href: "/r/commit/a", Subject: "signed", Sig: signed},149 {Short: "aaaaaaa", Href: "/r/commit/a", Subject: "signed", Sig: signed},
150 {Short: "bbbbbbb", Href: "/r/commit/b", Subject: "unsigned"},150 {Short: "bbbbbbb", Href: "/r/commit/b", Subject: "unsigned"},
151 }}))151 }}))
M internal/adapters/web/static/css/60-mr.css +19 -2
@@ -8,6 +8,23 @@
88 & > .mr-desc.prose { border: 0; border-top: 1px solid var(--border); border-radius: 0; }
99 }
1010
11+ .mr-footer {
12+ border-top: 1px solid var(--border); padding: var(--s3) var(--s5);
13+ font-size: var(--fs-s);
14+ & summary { cursor: pointer; color: var(--ink-dim); }
15+ & nav { display: flex; gap: var(--s3); padding-block: var(--s3); }
16+ & [role="tab"] { padding: var(--s1) var(--s2); border-radius: var(--r-s); }
17+ & [aria-selected="true"] { background: var(--bg-raised); color: var(--ink-hi); }
18+ & [data-mr-panel] { overflow-x: auto; }
19+ & [hidden] { display: none; }
20+ & section h2 { font-size: var(--fs-s); color: var(--ink-dim); }
21+ & table { width: 100%; border-collapse: collapse; }
22+ & th, & td { text-align: left; padding: var(--s2); border-bottom: 1px solid var(--border); }
23+ & th { color: var(--ink-dim); font-weight: 500; }
24+ }
25+ .merge-settings { font-size: var(--fs-s); color: var(--ink-dim); }
26+ .merge-settings h2 { font-size: var(--fs-s); }
27+
1128 .mr-state[data-state="open"]::before { content: "● "; color: var(--teal); }
1229 .mr-state[data-state="merged"]::before { content: "✓ "; color: var(--teal); }
1330 .mr-state[data-state="closed"]::before { content: "✗ "; color: var(--red); }
@@ -112,11 +129,11 @@
112129 & .d-or > summary:hover { color: var(--ink-hi); }
113130 & .d-or[open] > .clone { margin-top: var(--s2); }
114131 & .clone code { white-space: pre-wrap; overflow-wrap: anywhere; }
132+ & #mr-signing code { overflow-wrap: anywhere; }
115133 }
116134
117135 /* the rail of a merge request follows the review: it sticks under the
118- header, one screen high, and scrolls on its own to its checks, commits
119- and settings. The list of files keeps its own scroll, under a height, so
136+ header, one screen high, and scrolls on its own to its verdicts. The list of files keeps its own scroll, under a height, so
120137 that the blocks below it stay in reach. Only on a two-column layout. */
121138 @media (min-width: 1081px) {
122139 .rail:has(.r-files) {
@@ -8,6 +8,23 @@
8 & > .mr-desc.prose { border: 0; border-top: 1px solid var(--border); border-radius: 0; }8 & > .mr-desc.prose { border: 0; border-top: 1px solid var(--border); border-radius: 0; }
9 }9 }
10 10
11+ .mr-footer {
12+ border-top: 1px solid var(--border); padding: var(--s3) var(--s5);
13+ font-size: var(--fs-s);
14+ & summary { cursor: pointer; color: var(--ink-dim); }
15+ & nav { display: flex; gap: var(--s3); padding-block: var(--s3); }
16+ & [role="tab"] { padding: var(--s1) var(--s2); border-radius: var(--r-s); }
17+ & [aria-selected="true"] { background: var(--bg-raised); color: var(--ink-hi); }
18+ & [data-mr-panel] { overflow-x: auto; }
19+ & [hidden] { display: none; }
20+ & section h2 { font-size: var(--fs-s); color: var(--ink-dim); }
21+ & table { width: 100%; border-collapse: collapse; }
22+ & th, & td { text-align: left; padding: var(--s2); border-bottom: 1px solid var(--border); }
23+ & th { color: var(--ink-dim); font-weight: 500; }
24+ }
25+ .merge-settings { font-size: var(--fs-s); color: var(--ink-dim); }
26+ .merge-settings h2 { font-size: var(--fs-s); }
27+
11 .mr-state[data-state="open"]::before { content: "● "; color: var(--teal); }28 .mr-state[data-state="open"]::before { content: "● "; color: var(--teal); }
12 .mr-state[data-state="merged"]::before { content: "✓ "; color: var(--teal); }29 .mr-state[data-state="merged"]::before { content: "✓ "; color: var(--teal); }
13 .mr-state[data-state="closed"]::before { content: "✗ "; color: var(--red); }30 .mr-state[data-state="closed"]::before { content: "✗ "; color: var(--red); }
@@ -112,11 +129,11 @@
112 & .d-or > summary:hover { color: var(--ink-hi); }129 & .d-or > summary:hover { color: var(--ink-hi); }
113 & .d-or[open] > .clone { margin-top: var(--s2); }130 & .d-or[open] > .clone { margin-top: var(--s2); }
114 & .clone code { white-space: pre-wrap; overflow-wrap: anywhere; }131 & .clone code { white-space: pre-wrap; overflow-wrap: anywhere; }
132+ & #mr-signing code { overflow-wrap: anywhere; }
115 }133 }
116 134
117 /* the rail of a merge request follows the review: it sticks under the135 /* the rail of a merge request follows the review: it sticks under the
118- header, one screen high, and scrolls on its own to its checks, commits136+ header, one screen high, and scrolls on its own to its verdicts. The list of files keeps its own scroll, under a height, so
119- and settings. The list of files keeps its own scroll, under a height, so
120 that the blocks below it stay in reach. Only on a two-column layout. */137 that the blocks below it stay in reach. Only on a two-column layout. */
121 @media (min-width: 1081px) {138 @media (min-width: 1081px) {
122 .rail:has(.r-files) {139 .rail:has(.r-files) {
A internal/adapters/web/static/css/85-mobile.css +53 -0
@@ -0,0 +1,53 @@
1+@layer components {
2+ .mr-touch-range { display: none; }
3+
4+ /* MR only: retain the shell's desktop layout and other pages' spacing. */
5+ @media (max-width: 720px) {
6+ body:has(#diffs[data-mr]) {
7+ --pad: 0px;
8+ --hdr-h: 97px;
9+ overflow-x: clip;
10+ }
11+ body:has(#diffs[data-mr]) .work { padding-inline: 0; margin-inline: 0; gap: var(--s3); }
12+ body:has(#diffs[data-mr]) main { min-width: 0; padding-inline: 0; }
13+ body:has(#diffs[data-mr]) :is(.card, .mr-card, .mr-desc, .dfile, .dscroll, .code, .rail section) {
14+ margin-inline: 0; border-inline: 0; border-radius: 0; min-width: 0; max-width: 100%;
15+ }
16+ body:has(#diffs[data-mr]) :is(.mr-h, .mr-desc.prose, .card-h, .mr-footer) { padding-inline: 4px; }
17+ body:has(#diffs[data-mr]) .mr-footer :is(th, td) { padding-inline: var(--s1); }
18+ body:has(#diffs[data-mr]) .mr-desc.prose > pre { margin-inline: -4px; padding-inline: 0; max-width: calc(100% + 8px); }
19+ #diffs[data-mr] .dfile > summary { padding-inline: 0; border-inline: 0; border-radius: 0; }
20+ #diffs[data-mr] :is(.dscroll, .code) { overflow-x: auto; overscroll-behavior-x: contain; padding-inline: 0; }
21+ #diffs[data-mr] .dt .ln { width: calc(var(--lnw) + .5ch); min-width: calc(var(--lnw) + .5ch); padding-inline: .25ch; }
22+ #diffs[data-mr] .dt .m { width: 1ch; }
23+ #diffs[data-mr][data-diff] .uni { display: table; }
24+ #diffs[data-mr][data-diff] .spl { display: none; }
25+ #diffs[data-mr] .fnote td { padding-inline: 0; }
26+ #diffs[data-mr] :is(.cform, .cmt) { width: min(65ch, calc(100vw - 5rem)); max-width: calc(100vw - 5rem); overflow-wrap: anywhere; }
27+ body:has(#diffs[data-mr]) :is(input, textarea, select) { font-size: 16px; }
28+ body:has(#diffs[data-mr]) .f-btns { flex-wrap: wrap; }
29+ body:has(#diffs[data-mr]) .menu .menu-pop {
30+ position: fixed; inset: auto 0 0; width: auto; max-width: 100%;
31+ max-height: 75dvh; overflow-y: auto; border-radius: var(--r) var(--r) 0 0;
32+ padding-bottom: max(var(--s4), env(safe-area-inset-bottom));
33+ }
34+ body:has(#diffs[data-mr]) .mr-bar { position: static; }
35+ /* A wrapping toolbar has no reliable fixed sticky height. */
36+ body:has(#diffs[data-mr]) { --bar-h: 0px; }
37+ }
38+
39+ @media (pointer: coarse), (hover: none) {
40+ .mr-touch-range { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2); }
41+ /* Real, disjoint cells: never expand invisible targets into other lines
42+ or into the neighbouring old/new gutter. */
43+ #diffs[data-mr] .dt { line-height: max(var(--lh-code), 40px); }
44+ #diffs[data-mr] .dt .ln { width: max(calc(var(--lnw) + .5ch), 40px); min-width: 40px; padding: 0; }
45+ #diffs[data-mr] .spl .c-ln { width: max(calc(var(--lnw) + .5ch), 40px); }
46+ #diffs[data-mr] .ln a { display: block; width: 100%; min-height: 40px; text-align: center; text-decoration: underline; }
47+ .mr-touch-range[hidden] { display: none; }
48+ #diffs[data-mr] .ln a[data-range-start] { outline: 2px solid var(--focus); background: var(--sel); }
49+ body:has(#diffs[data-mr]) :is(.cform .btn, .menu .btn, .mr-touch-range .btn, .c-act button) { min-height: 40px; height: auto; padding-block: var(--s2); }
50+ #diffs[data-mr] .cform { scroll-margin-block: calc(var(--hdr-h) + 12px); }
51+ .mr-footer :is(summary, [data-mr-tabs] a) { display: inline-flex; align-items: center; min-height: 40px; }
52+ }
53+}
@@ -0,0 +1,53 @@
1+@layer components {
2+ .mr-touch-range { display: none; }
3+
4+ /* MR only: retain the shell's desktop layout and other pages' spacing. */
5+ @media (max-width: 720px) {
6+ body:has(#diffs[data-mr]) {
7+ --pad: 0px;
8+ --hdr-h: 97px;
9+ overflow-x: clip;
10+ }
11+ body:has(#diffs[data-mr]) .work { padding-inline: 0; margin-inline: 0; gap: var(--s3); }
12+ body:has(#diffs[data-mr]) main { min-width: 0; padding-inline: 0; }
13+ body:has(#diffs[data-mr]) :is(.card, .mr-card, .mr-desc, .dfile, .dscroll, .code, .rail section) {
14+ margin-inline: 0; border-inline: 0; border-radius: 0; min-width: 0; max-width: 100%;
15+ }
16+ body:has(#diffs[data-mr]) :is(.mr-h, .mr-desc.prose, .card-h, .mr-footer) { padding-inline: 4px; }
17+ body:has(#diffs[data-mr]) .mr-footer :is(th, td) { padding-inline: var(--s1); }
18+ body:has(#diffs[data-mr]) .mr-desc.prose > pre { margin-inline: -4px; padding-inline: 0; max-width: calc(100% + 8px); }
19+ #diffs[data-mr] .dfile > summary { padding-inline: 0; border-inline: 0; border-radius: 0; }
20+ #diffs[data-mr] :is(.dscroll, .code) { overflow-x: auto; overscroll-behavior-x: contain; padding-inline: 0; }
21+ #diffs[data-mr] .dt .ln { width: calc(var(--lnw) + .5ch); min-width: calc(var(--lnw) + .5ch); padding-inline: .25ch; }
22+ #diffs[data-mr] .dt .m { width: 1ch; }
23+ #diffs[data-mr][data-diff] .uni { display: table; }
24+ #diffs[data-mr][data-diff] .spl { display: none; }
25+ #diffs[data-mr] .fnote td { padding-inline: 0; }
26+ #diffs[data-mr] :is(.cform, .cmt) { width: min(65ch, calc(100vw - 5rem)); max-width: calc(100vw - 5rem); overflow-wrap: anywhere; }
27+ body:has(#diffs[data-mr]) :is(input, textarea, select) { font-size: 16px; }
28+ body:has(#diffs[data-mr]) .f-btns { flex-wrap: wrap; }
29+ body:has(#diffs[data-mr]) .menu .menu-pop {
30+ position: fixed; inset: auto 0 0; width: auto; max-width: 100%;
31+ max-height: 75dvh; overflow-y: auto; border-radius: var(--r) var(--r) 0 0;
32+ padding-bottom: max(var(--s4), env(safe-area-inset-bottom));
33+ }
34+ body:has(#diffs[data-mr]) .mr-bar { position: static; }
35+ /* A wrapping toolbar has no reliable fixed sticky height. */
36+ body:has(#diffs[data-mr]) { --bar-h: 0px; }
37+ }
38+
39+ @media (pointer: coarse), (hover: none) {
40+ .mr-touch-range { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2); }
41+ /* Real, disjoint cells: never expand invisible targets into other lines
42+ or into the neighbouring old/new gutter. */
43+ #diffs[data-mr] .dt { line-height: max(var(--lh-code), 40px); }
44+ #diffs[data-mr] .dt .ln { width: max(calc(var(--lnw) + .5ch), 40px); min-width: 40px; padding: 0; }
45+ #diffs[data-mr] .spl .c-ln { width: max(calc(var(--lnw) + .5ch), 40px); }
46+ #diffs[data-mr] .ln a { display: block; width: 100%; min-height: 40px; text-align: center; text-decoration: underline; }
47+ .mr-touch-range[hidden] { display: none; }
48+ #diffs[data-mr] .ln a[data-range-start] { outline: 2px solid var(--focus); background: var(--sel); }
49+ body:has(#diffs[data-mr]) :is(.cform .btn, .menu .btn, .mr-touch-range .btn, .c-act button) { min-height: 40px; height: auto; padding-block: var(--s2); }
50+ #diffs[data-mr] .cform { scroll-margin-block: calc(var(--hdr-h) + 12px); }
51+ .mr-footer :is(summary, [data-mr-tabs] a) { display: inline-flex; align-items: center; min-height: 40px; }
52+ }
53+}
M internal/adapters/web/static/js/ermite.js +1 -0
@@ -183,6 +183,7 @@
183183 layout(mode) {
184184 const el = $('[data-diff]');
185185 if (!el) return;
186+ if (el.hasAttribute('data-mr') && el.dataset.mobile === 'true') return;
186187 el.dataset.diff = mode;
187188 try { sessionStorage.setItem('diff', mode); } catch { /* storage refused: the layout holds for this page */ }
188189 for (const d of $$('[data-file]')) if ($('.dt', d)) d.open = true;
@@ -183,6 +183,7 @@
183 layout(mode) {183 layout(mode) {
184 const el = $('[data-diff]');184 const el = $('[data-diff]');
185 if (!el) return;185 if (!el) return;
186+ if (el.hasAttribute('data-mr') && el.dataset.mobile === 'true') return;
186 el.dataset.diff = mode;187 el.dataset.diff = mode;
187 try { sessionStorage.setItem('diff', mode); } catch { /* storage refused: the layout holds for this page */ }188 try { sessionStorage.setItem('diff', mode); } catch { /* storage refused: the layout holds for this page */ }
188 for (const d of $$('[data-file]')) if ($('.dt', d)) d.open = true;189 for (const d of $$('[data-file]')) if ($('.dt', d)) d.open = true;
M internal/adapters/web/static/js/mr.js +133 -2
@@ -27,6 +27,20 @@ window.ermiteMR = (() => {
2727 b.searchParams.set('on', `${y[1]}:${nums[0]}-${nums[1]}:${y[3]}`);
2828 return b.href;
2929 },
30+ // Range mode is explicit: ordinary taps still open single-line forms.
31+ touchRange(previous, current, base) {
32+ if (!previous) return { start: current, url: null };
33+ const url = core.rangeURL(previous, current, base);
34+ if (url) return { start: null, url };
35+ if (previous === current) return { start: null, url: current };
36+ return { start: current, url: null }; // another file/side starts afresh
37+ },
38+ mobileURL(href, view, narrow) {
39+ if (!narrow || view !== 'split') return null;
40+ const url = new URL(href);
41+ url.searchParams.set('view', 'unified');
42+ return url.href;
43+ },
3044 quote(button) {
3145 const thread = button.closest('.cmt').closest('[data-thread]');
3246 const details = thread?.querySelector(':scope > details[data-reply]');
@@ -49,6 +63,13 @@ window.ermiteMR = (() => {
4963 if (/^[1-9]$/.test(key) && Number(key) <= modes) return { mode: Number(key) - 1 };
5064 return null;
5165 },
66+ tabIndex(key, index, count) {
67+ if (key === 'Home') return 0;
68+ if (key === 'End') return count - 1;
69+ if (key === 'ArrowRight') return (index + 1) % count;
70+ if (key === 'ArrowLeft') return (index + count - 1) % count;
71+ return null;
72+ },
5273 // step moves an index within [0, n).
5374 step(i, d, n) {
5475 if (n === 0) return -1;
@@ -60,6 +81,7 @@ window.ermiteMR = (() => {
6081 const $ = (sel, root = document) => root.querySelector(sel);
6182 const $$ = (sel, root = document) => [...root.querySelectorAll(sel)];
6283 const loading = new Map(); // src -> promise of the swap
84+ let refreshTouchComments = () => {};
6385 let moved = false;
6486 let lazyIO = null; // the observer of the placeholders (watch)
6587 let revealGen = 0; // the last reveal wins the scroll
@@ -108,6 +130,7 @@ window.ermiteMR = (() => {
108130 window.htmx?.process(f);
109131 window.ermite?.watchFile?.(f, old);
110132 }
133+ refreshTouchComments();
111134 }
112135
113136 // stale: the diff changed under the page. The placeholders say so; no file
@@ -130,7 +153,7 @@ window.ermiteMR = (() => {
130153 // A page with both layouts says which shows in data-diff; a large diff
131154 // rendered in one layout only says it in data-view.
132155 const diffs = $('#diffs')?.dataset;
133- if (/^c\d+$/.test(id) && (diffs?.diff || diffs?.view) === 'split') {
156+ if (/^c\d+$/.test(id) && !window.matchMedia?.('(max-width: 720px)').matches && (diffs?.diff || diffs?.view) === 'split') {
134157 const split = document.getElementById(id + '-s');
135158 if (split) return split;
136159 }
@@ -285,8 +308,116 @@ window.ermiteMR = (() => {
285308 reveal(id);
286309 }
287310
311+ // Enhance the ordinary anchor navigation only when scripts are available.
312+ function panels() {
313+ const footer = $('#mr-panels'), nav = $('[data-mr-tabs]');
314+ if (!footer || !nav) return;
315+ const tabs = $$('a', nav), panels = $$('[data-mr-panel]', footer);
316+ nav.setAttribute('role', 'tablist');
317+ function select(index, focus = false) {
318+ tabs.forEach((tab, i) => {
319+ tab.setAttribute('role', 'tab');
320+ tab.setAttribute('aria-controls', panels[i].id);
321+ tab.setAttribute('aria-selected', String(i === index));
322+ tab.tabIndex = i === index ? 0 : -1;
323+ panels[i].setAttribute('role', 'tabpanel');
324+ panels[i].tabIndex = 0;
325+ panels[i].hidden = i !== index;
326+ });
327+ if (focus) tabs[index].focus();
328+ }
329+ tabs.forEach((tab, i) => {
330+ tab.addEventListener('click', (e) => { e.preventDefault(); select(i); });
331+ tab.addEventListener('keydown', (e) => {
332+ const next = core.tabIndex(e.key, i, tabs.length);
333+ if (next === null) return;
334+ e.preventDefault(); select(next, true);
335+ });
336+ });
337+ function hash() {
338+ const index = location.hash === '#mr-checks' ? 1 : location.hash === '#mr-commits' ? 0 : -1;
339+ if (index < 0) return;
340+ footer.open = true; select(index);
341+ }
342+ // A repeated click on the same hash must also reopen a folded footer.
343+ document.addEventListener('click', (e) => {
344+ if (e.target.closest?.('#mr-ck')) { footer.open = true; select(1); }
345+ });
346+ const summary = $('#mr-ck');
347+ if (summary) {
348+ const sync = () => { $('[data-checks-label]', nav).textContent = $('#mr-ck')?.title || $('#mr-ck')?.textContent.trim() || 'no checks'; };
349+ new MutationObserver(sync).observe(summary.parentElement, { childList: true, subtree: true, characterData: true });
350+ sync();
351+ }
352+ select(0); hash();
353+ addEventListener('hashchange', hash);
354+ }
355+
356+ function touchComments() {
357+ const diffs = $('#diffs');
358+ const bar = document.createElement('div');
359+ bar.className = 'mr-touch-range';
360+ const button = document.createElement('button');
361+ button.type = 'button';
362+ button.className = 'btn';
363+ button.textContent = 'Select line range';
364+ button.setAttribute('aria-pressed', 'false');
365+ const status = document.createElement('span');
366+ status.setAttribute('role', 'status');
367+ bar.append(button, status);
368+ diffs.prepend(bar);
369+ refreshTouchComments = () => { bar.hidden = !$('.ln a[href*="on="]', diffs); };
370+ refreshTouchComments();
371+ let enabled = false, start = null, marker = null;
372+ const clear = () => { marker?.removeAttribute('data-range-start'); marker = null; start = null; };
373+ button.addEventListener('click', () => {
374+ enabled = !enabled;
375+ clear();
376+ button.setAttribute('aria-pressed', String(enabled));
377+ status.textContent = enabled ? 'Tap the first line number, then the last. Tap the same line for one line.' : '';
378+ });
379+ diffs.addEventListener('click', (e) => {
380+ const link = e.target.closest?.('.ln a[href*="on="]');
381+ if (!enabled || !link || e.shiftKey || e.ctrlKey || e.metaKey || e.altKey) return;
382+ e.preventDefault();
383+ e.stopPropagation(); // do not alter the desktop shift-click anchor
384+ const next = core.touchRange(start, link.href, location.href);
385+ clear();
386+ if (next.url) { location.assign(next.url); return; }
387+ start = next.start;
388+ marker = link;
389+ marker.setAttribute('data-range-start', '');
390+ status.textContent = `Range starts at line ${link.textContent.trim()}. Tap the last line number (same file and side).`;
391+ });
392+ // The server opens the line form. Scroll after layout without stealing
393+ // focus or forcing a mobile keyboard to appear.
394+ if (new URL(location.href).searchParams.has('on')) requestAnimationFrame(() => {
395+ const form = $$('.fnote .cform', diffs).find((f) => f.getClientRects().length);
396+ form?.scrollIntoView({ block: 'center' });
397+ });
398+ }
399+
288400 function start() {
289401 if (!$('#diffs[data-mr]')) return;
402+ panels();
403+ // Large diffs may contain only the split table. Ask the existing server
404+ // route for unified rather than writing the saved session preference.
405+ const narrow = window.matchMedia?.('(max-width: 720px)');
406+ const unify = () => {
407+ $('#diffs').dataset.mobile = String(!!narrow?.matches);
408+ const url = core.mobileURL(location.href, $('#diffs')?.dataset.view, narrow?.matches);
409+ if (url) { location.replace(url); return true; }
410+ return false;
411+ };
412+ if (unify()) return;
413+ narrow?.addEventListener('change', unify);
414+ addEventListener('click', (e) => {
415+ if (narrow?.matches && e.target.closest?.('.vbtn[data-view="split"]')) {
416+ e.preventDefault();
417+ e.stopImmediatePropagation();
418+ }
419+ }, true);
420+ touchComments();
290421 let folded = false;
291422 try { folded = localStorage.getItem('mr-files-folded') === '1'; } catch { /* no storage: open */ }
292423 if (folded) foldFiles(true);
@@ -316,7 +447,7 @@ window.ermiteMR = (() => {
316447 });
317448 }
318449
319- return { core, start, load, reveal, openMerge, menuKey, markRead, focusFiles, stepFiles, leaveFiles, foldFiles, openFile };
450+ return { core, panels, start, load, reveal, openMerge, menuKey, markRead, focusFiles, stepFiles, leaveFiles, foldFiles, openFile };
320451 })();
321452
322453 if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', () => window.ermiteMR.start());
@@ -27,6 +27,20 @@ window.ermiteMR = (() => {
27 b.searchParams.set('on', `${y[1]}:${nums[0]}-${nums[1]}:${y[3]}`);27 b.searchParams.set('on', `${y[1]}:${nums[0]}-${nums[1]}:${y[3]}`);
28 return b.href;28 return b.href;
29 },29 },
30+ // Range mode is explicit: ordinary taps still open single-line forms.
31+ touchRange(previous, current, base) {
32+ if (!previous) return { start: current, url: null };
33+ const url = core.rangeURL(previous, current, base);
34+ if (url) return { start: null, url };
35+ if (previous === current) return { start: null, url: current };
36+ return { start: current, url: null }; // another file/side starts afresh
37+ },
38+ mobileURL(href, view, narrow) {
39+ if (!narrow || view !== 'split') return null;
40+ const url = new URL(href);
41+ url.searchParams.set('view', 'unified');
42+ return url.href;
43+ },
30 quote(button) {44 quote(button) {
31 const thread = button.closest('.cmt').closest('[data-thread]');45 const thread = button.closest('.cmt').closest('[data-thread]');
32 const details = thread?.querySelector(':scope > details[data-reply]');46 const details = thread?.querySelector(':scope > details[data-reply]');
@@ -49,6 +63,13 @@ window.ermiteMR = (() => {
49 if (/^[1-9]$/.test(key) && Number(key) <= modes) return { mode: Number(key) - 1 };63 if (/^[1-9]$/.test(key) && Number(key) <= modes) return { mode: Number(key) - 1 };
50 return null;64 return null;
51 },65 },
66+ tabIndex(key, index, count) {
67+ if (key === 'Home') return 0;
68+ if (key === 'End') return count - 1;
69+ if (key === 'ArrowRight') return (index + 1) % count;
70+ if (key === 'ArrowLeft') return (index + count - 1) % count;
71+ return null;
72+ },
52 // step moves an index within [0, n).73 // step moves an index within [0, n).
53 step(i, d, n) {74 step(i, d, n) {
54 if (n === 0) return -1;75 if (n === 0) return -1;
@@ -60,6 +81,7 @@ window.ermiteMR = (() => {
60 const $ = (sel, root = document) => root.querySelector(sel);81 const $ = (sel, root = document) => root.querySelector(sel);
61 const $$ = (sel, root = document) => [...root.querySelectorAll(sel)];82 const $$ = (sel, root = document) => [...root.querySelectorAll(sel)];
62 const loading = new Map(); // src -> promise of the swap83 const loading = new Map(); // src -> promise of the swap
84+ let refreshTouchComments = () => {};
63 let moved = false;85 let moved = false;
64 let lazyIO = null; // the observer of the placeholders (watch)86 let lazyIO = null; // the observer of the placeholders (watch)
65 let revealGen = 0; // the last reveal wins the scroll87 let revealGen = 0; // the last reveal wins the scroll
@@ -108,6 +130,7 @@ window.ermiteMR = (() => {
108 window.htmx?.process(f);130 window.htmx?.process(f);
109 window.ermite?.watchFile?.(f, old);131 window.ermite?.watchFile?.(f, old);
110 }132 }
133+ refreshTouchComments();
111 }134 }
112 135
113 // stale: the diff changed under the page. The placeholders say so; no file136 // stale: the diff changed under the page. The placeholders say so; no file
@@ -130,7 +153,7 @@ window.ermiteMR = (() => {
130 // A page with both layouts says which shows in data-diff; a large diff153 // A page with both layouts says which shows in data-diff; a large diff
131 // rendered in one layout only says it in data-view.154 // rendered in one layout only says it in data-view.
132 const diffs = $('#diffs')?.dataset;155 const diffs = $('#diffs')?.dataset;
133- if (/^c\d+$/.test(id) && (diffs?.diff || diffs?.view) === 'split') {156+ if (/^c\d+$/.test(id) && !window.matchMedia?.('(max-width: 720px)').matches && (diffs?.diff || diffs?.view) === 'split') {
134 const split = document.getElementById(id + '-s');157 const split = document.getElementById(id + '-s');
135 if (split) return split;158 if (split) return split;
136 }159 }
@@ -285,8 +308,116 @@ window.ermiteMR = (() => {
285 reveal(id);308 reveal(id);
286 }309 }
287 310
311+ // Enhance the ordinary anchor navigation only when scripts are available.
312+ function panels() {
313+ const footer = $('#mr-panels'), nav = $('[data-mr-tabs]');
314+ if (!footer || !nav) return;
315+ const tabs = $$('a', nav), panels = $$('[data-mr-panel]', footer);
316+ nav.setAttribute('role', 'tablist');
317+ function select(index, focus = false) {
318+ tabs.forEach((tab, i) => {
319+ tab.setAttribute('role', 'tab');
320+ tab.setAttribute('aria-controls', panels[i].id);
321+ tab.setAttribute('aria-selected', String(i === index));
322+ tab.tabIndex = i === index ? 0 : -1;
323+ panels[i].setAttribute('role', 'tabpanel');
324+ panels[i].tabIndex = 0;
325+ panels[i].hidden = i !== index;
326+ });
327+ if (focus) tabs[index].focus();
328+ }
329+ tabs.forEach((tab, i) => {
330+ tab.addEventListener('click', (e) => { e.preventDefault(); select(i); });
331+ tab.addEventListener('keydown', (e) => {
332+ const next = core.tabIndex(e.key, i, tabs.length);
333+ if (next === null) return;
334+ e.preventDefault(); select(next, true);
335+ });
336+ });
337+ function hash() {
338+ const index = location.hash === '#mr-checks' ? 1 : location.hash === '#mr-commits' ? 0 : -1;
339+ if (index < 0) return;
340+ footer.open = true; select(index);
341+ }
342+ // A repeated click on the same hash must also reopen a folded footer.
343+ document.addEventListener('click', (e) => {
344+ if (e.target.closest?.('#mr-ck')) { footer.open = true; select(1); }
345+ });
346+ const summary = $('#mr-ck');
347+ if (summary) {
348+ const sync = () => { $('[data-checks-label]', nav).textContent = $('#mr-ck')?.title || $('#mr-ck')?.textContent.trim() || 'no checks'; };
349+ new MutationObserver(sync).observe(summary.parentElement, { childList: true, subtree: true, characterData: true });
350+ sync();
351+ }
352+ select(0); hash();
353+ addEventListener('hashchange', hash);
354+ }
355+
356+ function touchComments() {
357+ const diffs = $('#diffs');
358+ const bar = document.createElement('div');
359+ bar.className = 'mr-touch-range';
360+ const button = document.createElement('button');
361+ button.type = 'button';
362+ button.className = 'btn';
363+ button.textContent = 'Select line range';
364+ button.setAttribute('aria-pressed', 'false');
365+ const status = document.createElement('span');
366+ status.setAttribute('role', 'status');
367+ bar.append(button, status);
368+ diffs.prepend(bar);
369+ refreshTouchComments = () => { bar.hidden = !$('.ln a[href*="on="]', diffs); };
370+ refreshTouchComments();
371+ let enabled = false, start = null, marker = null;
372+ const clear = () => { marker?.removeAttribute('data-range-start'); marker = null; start = null; };
373+ button.addEventListener('click', () => {
374+ enabled = !enabled;
375+ clear();
376+ button.setAttribute('aria-pressed', String(enabled));
377+ status.textContent = enabled ? 'Tap the first line number, then the last. Tap the same line for one line.' : '';
378+ });
379+ diffs.addEventListener('click', (e) => {
380+ const link = e.target.closest?.('.ln a[href*="on="]');
381+ if (!enabled || !link || e.shiftKey || e.ctrlKey || e.metaKey || e.altKey) return;
382+ e.preventDefault();
383+ e.stopPropagation(); // do not alter the desktop shift-click anchor
384+ const next = core.touchRange(start, link.href, location.href);
385+ clear();
386+ if (next.url) { location.assign(next.url); return; }
387+ start = next.start;
388+ marker = link;
389+ marker.setAttribute('data-range-start', '');
390+ status.textContent = `Range starts at line ${link.textContent.trim()}. Tap the last line number (same file and side).`;
391+ });
392+ // The server opens the line form. Scroll after layout without stealing
393+ // focus or forcing a mobile keyboard to appear.
394+ if (new URL(location.href).searchParams.has('on')) requestAnimationFrame(() => {
395+ const form = $$('.fnote .cform', diffs).find((f) => f.getClientRects().length);
396+ form?.scrollIntoView({ block: 'center' });
397+ });
398+ }
399+
288 function start() {400 function start() {
289 if (!$('#diffs[data-mr]')) return;401 if (!$('#diffs[data-mr]')) return;
402+ panels();
403+ // Large diffs may contain only the split table. Ask the existing server
404+ // route for unified rather than writing the saved session preference.
405+ const narrow = window.matchMedia?.('(max-width: 720px)');
406+ const unify = () => {
407+ $('#diffs').dataset.mobile = String(!!narrow?.matches);
408+ const url = core.mobileURL(location.href, $('#diffs')?.dataset.view, narrow?.matches);
409+ if (url) { location.replace(url); return true; }
410+ return false;
411+ };
412+ if (unify()) return;
413+ narrow?.addEventListener('change', unify);
414+ addEventListener('click', (e) => {
415+ if (narrow?.matches && e.target.closest?.('.vbtn[data-view="split"]')) {
416+ e.preventDefault();
417+ e.stopImmediatePropagation();
418+ }
419+ }, true);
420+ touchComments();
290 let folded = false;421 let folded = false;
291 try { folded = localStorage.getItem('mr-files-folded') === '1'; } catch { /* no storage: open */ }422 try { folded = localStorage.getItem('mr-files-folded') === '1'; } catch { /* no storage: open */ }
292 if (folded) foldFiles(true);423 if (folded) foldFiles(true);
@@ -316,7 +447,7 @@ window.ermiteMR = (() => {
316 });447 });
317 }448 }
318 449
319- return { core, start, load, reveal, openMerge, menuKey, markRead, focusFiles, stepFiles, leaveFiles, foldFiles, openFile };450+ return { core, panels, start, load, reveal, openMerge, menuKey, markRead, focusFiles, stepFiles, leaveFiles, foldFiles, openFile };
320 })();451 })();
321 452
322 if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', () => window.ermiteMR.start());453 if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', () => window.ermiteMR.start());
M internal/app/testdata/web/commit-big.html +3 -3
@@ -127,12 +127,12 @@
127127 </span>
128128 <details class="menu vmenu">
129129 <summary class="btn" aria-label="Diff view">
130-<span hx-live="this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>
130+<span hx-live="this.textContent = q('#diffs').attr['data-mobile'] !== 'true' && q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>
131131 </summary>
132132 <div class="menu-pop" role="group" aria-label="Diff view">
133-<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
133+<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
134134 </a>
135-<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" data-fire="split" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
135+<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" :aria-disabled="q('#diffs').attr['data-mobile'] === 'true' ? 'true' : false" :title="q('#diffs').attr['data-mobile'] === 'true' ? 'Split view requires a wider screen' : 'Split view'" data-fire="split" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
136136 </a>
137137 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">
138138 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>
@@ -127,12 +127,12 @@
127 </span>127 </span>
128 <details class="menu vmenu">128 <details class="menu vmenu">
129 <summary class="btn" aria-label="Diff view">129 <summary class="btn" aria-label="Diff view">
130-<span hx-live="this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>130+<span hx-live="this.textContent = q('#diffs').attr['data-mobile'] !== 'true' && q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>
131 </summary>131 </summary>
132 <div class="menu-pop" role="group" aria-label="Diff view">132 <div class="menu-pop" role="group" aria-label="Diff view">
133-<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>133+<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
134 </a>134 </a>
135-<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" data-fire="split" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>135+<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" :aria-disabled="q('#diffs').attr['data-mobile'] === 'true' ? 'true' : false" :title="q('#diffs').attr['data-mobile'] === 'true' ? 'Split view requires a wider screen' : 'Split view'" data-fire="split" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
136 </a>136 </a>
137 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">137 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">
138 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>138 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>
M internal/app/testdata/web/commit-binary.html +3 -3
@@ -123,12 +123,12 @@
123123 </span>
124124 <details class="menu vmenu">
125125 <summary class="btn" aria-label="Diff view">
126-<span hx-live="this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>
126+<span hx-live="this.textContent = q('#diffs').attr['data-mobile'] !== 'true' && q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>
127127 </summary>
128128 <div class="menu-pop" role="group" aria-label="Diff view">
129-<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
129+<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
130130 </a>
131-<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" data-fire="split" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
131+<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" :aria-disabled="q('#diffs').attr['data-mobile'] === 'true' ? 'true' : false" :title="q('#diffs').attr['data-mobile'] === 'true' ? 'Split view requires a wider screen' : 'Split view'" data-fire="split" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
132132 </a>
133133 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">
134134 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>
@@ -123,12 +123,12 @@
123 </span>123 </span>
124 <details class="menu vmenu">124 <details class="menu vmenu">
125 <summary class="btn" aria-label="Diff view">125 <summary class="btn" aria-label="Diff view">
126-<span hx-live="this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>126+<span hx-live="this.textContent = q('#diffs').attr['data-mobile'] !== 'true' && q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>
127 </summary>127 </summary>
128 <div class="menu-pop" role="group" aria-label="Diff view">128 <div class="menu-pop" role="group" aria-label="Diff view">
129-<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>129+<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
130 </a>130 </a>
131-<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" data-fire="split" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>131+<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" :aria-disabled="q('#diffs').attr['data-mobile'] === 'true' ? 'true' : false" :title="q('#diffs').attr['data-mobile'] === 'true' ? 'Split view requires a wider screen' : 'Split view'" data-fire="split" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
132 </a>132 </a>
133 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">133 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">
134 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>134 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>
M internal/app/testdata/web/commit-merge.html +3 -3
@@ -122,12 +122,12 @@
122122 </span>
123123 <details class="menu vmenu">
124124 <summary class="btn" aria-label="Diff view">
125-<span hx-live="this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>
125+<span hx-live="this.textContent = q('#diffs').attr['data-mobile'] !== 'true' && q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>
126126 </summary>
127127 <div class="menu-pop" role="group" aria-label="Diff view">
128-<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
128+<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
129129 </a>
130-<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" data-fire="split" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
130+<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" :aria-disabled="q('#diffs').attr['data-mobile'] === 'true' ? 'true' : false" :title="q('#diffs').attr['data-mobile'] === 'true' ? 'Split view requires a wider screen' : 'Split view'" data-fire="split" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
131131 </a>
132132 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">
133133 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>
@@ -122,12 +122,12 @@
122 </span>122 </span>
123 <details class="menu vmenu">123 <details class="menu vmenu">
124 <summary class="btn" aria-label="Diff view">124 <summary class="btn" aria-label="Diff view">
125-<span hx-live="this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>125+<span hx-live="this.textContent = q('#diffs').attr['data-mobile'] !== 'true' && q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>
126 </summary>126 </summary>
127 <div class="menu-pop" role="group" aria-label="Diff view">127 <div class="menu-pop" role="group" aria-label="Diff view">
128-<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>128+<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
129 </a>129 </a>
130-<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" data-fire="split" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>130+<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" :aria-disabled="q('#diffs').attr['data-mobile'] === 'true' ? 'true' : false" :title="q('#diffs').attr['data-mobile'] === 'true' ? 'Split view requires a wider screen' : 'Split view'" data-fire="split" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
131 </a>131 </a>
132 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">132 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">
133 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>133 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>
M internal/app/testdata/web/commit-modify-split.html +3 -3
@@ -129,12 +129,12 @@ And &lt;b&gt;html&lt;/b&gt; &amp; &#34;quotes&#34;.</pre>
129129 </span>
130130 <details class="menu vmenu">
131131 <summary class="btn" aria-label="Diff view">
132-<span hx-live="this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Split</span>
132+<span hx-live="this.textContent = q('#diffs').attr['data-mobile'] !== 'true' && q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Split</span>
133133 </summary>
134134 <div class="menu-pop" role="group" aria-label="Diff view">
135-<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" data-fire="unified" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
135+<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" data-fire="unified" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
136136 </a>
137-<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" aria-current="true" data-fire="split" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
137+<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" :aria-disabled="q('#diffs').attr['data-mobile'] === 'true' ? 'true' : false" :title="q('#diffs').attr['data-mobile'] === 'true' ? 'Split view requires a wider screen' : 'Split view'" aria-current="true" data-fire="split" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
138138 </a>
139139 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">
140140 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>
@@ -129,12 +129,12 @@ And &lt;b&gt;html&lt;/b&gt; &amp; &#34;quotes&#34;.</pre>
129 </span>129 </span>
130 <details class="menu vmenu">130 <details class="menu vmenu">
131 <summary class="btn" aria-label="Diff view">131 <summary class="btn" aria-label="Diff view">
132-<span hx-live="this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Split</span>132+<span hx-live="this.textContent = q('#diffs').attr['data-mobile'] !== 'true' && q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Split</span>
133 </summary>133 </summary>
134 <div class="menu-pop" role="group" aria-label="Diff view">134 <div class="menu-pop" role="group" aria-label="Diff view">
135-<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" data-fire="unified" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>135+<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" data-fire="unified" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
136 </a>136 </a>
137-<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" aria-current="true" data-fire="split" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>137+<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" :aria-disabled="q('#diffs').attr['data-mobile'] === 'true' ? 'true' : false" :title="q('#diffs').attr['data-mobile'] === 'true' ? 'Split view requires a wider screen' : 'Split view'" aria-current="true" data-fire="split" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
138 </a>138 </a>
139 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">139 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">
140 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>140 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>
M internal/app/testdata/web/commit-modify.html +3 -3
@@ -129,12 +129,12 @@ And &lt;b&gt;html&lt;/b&gt; &amp; &#34;quotes&#34;.</pre>
129129 </span>
130130 <details class="menu vmenu">
131131 <summary class="btn" aria-label="Diff view">
132-<span hx-live="this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>
132+<span hx-live="this.textContent = q('#diffs').attr['data-mobile'] !== 'true' && q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>
133133 </summary>
134134 <div class="menu-pop" role="group" aria-label="Diff view">
135-<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
135+<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
136136 </a>
137-<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" data-fire="split" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
137+<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" :aria-disabled="q('#diffs').attr['data-mobile'] === 'true' ? 'true' : false" :title="q('#diffs').attr['data-mobile'] === 'true' ? 'Split view requires a wider screen' : 'Split view'" data-fire="split" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
138138 </a>
139139 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">
140140 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>
@@ -129,12 +129,12 @@ And &lt;b&gt;html&lt;/b&gt; &amp; &#34;quotes&#34;.</pre>
129 </span>129 </span>
130 <details class="menu vmenu">130 <details class="menu vmenu">
131 <summary class="btn" aria-label="Diff view">131 <summary class="btn" aria-label="Diff view">
132-<span hx-live="this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>132+<span hx-live="this.textContent = q('#diffs').attr['data-mobile'] !== 'true' && q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>
133 </summary>133 </summary>
134 <div class="menu-pop" role="group" aria-label="Diff view">134 <div class="menu-pop" role="group" aria-label="Diff view">
135-<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>135+<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
136 </a>136 </a>
137-<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" data-fire="split" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>137+<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" :aria-disabled="q('#diffs').attr['data-mobile'] === 'true' ? 'true' : false" :title="q('#diffs').attr['data-mobile'] === 'true' ? 'Split view requires a wider screen' : 'Split view'" data-fire="split" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
138 </a>138 </a>
139 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">139 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">
140 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>140 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>
M internal/app/testdata/web/commit-rename.html +3 -3
@@ -123,12 +123,12 @@
123123 </span>
124124 <details class="menu vmenu">
125125 <summary class="btn" aria-label="Diff view">
126-<span hx-live="this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>
126+<span hx-live="this.textContent = q('#diffs').attr['data-mobile'] !== 'true' && q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>
127127 </summary>
128128 <div class="menu-pop" role="group" aria-label="Diff view">
129-<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
129+<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
130130 </a>
131-<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" data-fire="split" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
131+<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" :aria-disabled="q('#diffs').attr['data-mobile'] === 'true' ? 'true' : false" :title="q('#diffs').attr['data-mobile'] === 'true' ? 'Split view requires a wider screen' : 'Split view'" data-fire="split" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
132132 </a>
133133 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">
134134 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>
@@ -123,12 +123,12 @@
123 </span>123 </span>
124 <details class="menu vmenu">124 <details class="menu vmenu">
125 <summary class="btn" aria-label="Diff view">125 <summary class="btn" aria-label="Diff view">
126-<span hx-live="this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>126+<span hx-live="this.textContent = q('#diffs').attr['data-mobile'] !== 'true' && q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>
127 </summary>127 </summary>
128 <div class="menu-pop" role="group" aria-label="Diff view">128 <div class="menu-pop" role="group" aria-label="Diff view">
129-<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>129+<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
130 </a>130 </a>
131-<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" data-fire="split" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>131+<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" :aria-disabled="q('#diffs').attr['data-mobile'] === 'true' ? 'true' : false" :title="q('#diffs').attr['data-mobile'] === 'true' ? 'Split view requires a wider screen' : 'Split view'" data-fire="split" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
132 </a>132 </a>
133 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">133 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">
134 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>134 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>
M internal/app/testdata/web/commit-root.html +3 -3
@@ -121,12 +121,12 @@
121121 </span>
122122 <details class="menu vmenu">
123123 <summary class="btn" aria-label="Diff view">
124-<span hx-live="this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>
124+<span hx-live="this.textContent = q('#diffs').attr['data-mobile'] !== 'true' && q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>
125125 </summary>
126126 <div class="menu-pop" role="group" aria-label="Diff view">
127-<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
127+<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
128128 </a>
129-<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" data-fire="split" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
129+<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" :aria-disabled="q('#diffs').attr['data-mobile'] === 'true' ? 'true' : false" :title="q('#diffs').attr['data-mobile'] === 'true' ? 'Split view requires a wider screen' : 'Split view'" data-fire="split" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
130130 </a>
131131 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">
132132 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>
@@ -121,12 +121,12 @@
121 </span>121 </span>
122 <details class="menu vmenu">122 <details class="menu vmenu">
123 <summary class="btn" aria-label="Diff view">123 <summary class="btn" aria-label="Diff view">
124-<span hx-live="this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>124+<span hx-live="this.textContent = q('#diffs').attr['data-mobile'] !== 'true' && q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>
125 </summary>125 </summary>
126 <div class="menu-pop" role="group" aria-label="Diff view">126 <div class="menu-pop" role="group" aria-label="Diff view">
127-<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>127+<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
128 </a>128 </a>
129-<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" data-fire="split" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>129+<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" :aria-disabled="q('#diffs').attr['data-mobile'] === 'true' ? 'true' : false" :title="q('#diffs').attr['data-mobile'] === 'true' ? 'Split view requires a wider screen' : 'Split view'" data-fire="split" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
130 </a>130 </a>
131 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">131 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">
132 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>132 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>
M internal/app/testdata/web/commit-trojan.html +3 -3
@@ -124,12 +124,12 @@
124124 </span>
125125 <details class="menu vmenu">
126126 <summary class="btn" aria-label="Diff view">
127-<span hx-live="this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>
127+<span hx-live="this.textContent = q('#diffs').attr['data-mobile'] !== 'true' && q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>
128128 </summary>
129129 <div class="menu-pop" role="group" aria-label="Diff view">
130-<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
130+<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
131131 </a>
132-<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" data-fire="split" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
132+<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" :aria-disabled="q('#diffs').attr['data-mobile'] === 'true' ? 'true' : false" :title="q('#diffs').attr['data-mobile'] === 'true' ? 'Split view requires a wider screen' : 'Split view'" data-fire="split" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
133133 </a>
134134 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">
135135 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>
@@ -124,12 +124,12 @@
124 </span>124 </span>
125 <details class="menu vmenu">125 <details class="menu vmenu">
126 <summary class="btn" aria-label="Diff view">126 <summary class="btn" aria-label="Diff view">
127-<span hx-live="this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>127+<span hx-live="this.textContent = q('#diffs').attr['data-mobile'] !== 'true' && q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">Unified</span>
128 </summary>128 </summary>
129 <div class="menu-pop" role="group" aria-label="Diff view">129 <div class="menu-pop" role="group" aria-label="Diff view">
130-<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>130+<a href="/diffs/commit/SHA40?view=unified" class="btn vbtn" data-view="unified" aria-keyshortcuts="u" aria-current="true" data-fire="unified" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Unified<kbd aria-hidden="true">u</kbd>
131 </a>131 </a>
132-<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" data-fire="split" :aria-current="q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>132+<a href="/diffs/commit/SHA40?view=split" class="btn vbtn" data-view="split" aria-keyshortcuts="d" :aria-disabled="q('#diffs').attr['data-mobile'] === 'true' ? 'true' : false" :title="q('#diffs').attr['data-mobile'] === 'true' ? 'Split view requires a wider screen' : 'Split view'" data-fire="split" :aria-current="(q('#diffs').attr['data-mobile'] === 'true' ? 'unified' : q('#diffs').attr['data-diff']) === this.dataset.view ? 'true' : false">Split<kbd aria-hidden="true">d</kbd>
133 </a>133 </a>
134 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">134 <button type="button" aria-keyshortcuts="x" data-js data-fire="collapse" class="btn">
135 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>135 <span hx-live="this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'">Collapse all</span>
M internal/app/web_mr_test.go +1 -1
@@ -335,7 +335,7 @@ func TestWebMergeRequestReviewAndFastForward(t *testing.T) {
335335 all := b.get(base, as(token))
336336 assert.Contains(t, all.body, `href="/proj/merge-requests/1/since"`)
337337 assert.Contains(t, all.body, "since your last read")
338- assert.Contains(t, all.body, "<li data-new>", "the commit pushed since is marked")
338+ assert.Contains(t, all.body, "<tr data-new>", "the commit pushed since is marked")
339339 assert.Contains(t, all.body, "data-read>Mark read")
340340 assert.Contains(t, all.body, "outdated", "the notes were written on the earlier head")
341341 since := b.get(base+"/since", as(token))
@@ -335,7 +335,7 @@ func TestWebMergeRequestReviewAndFastForward(t *testing.T) {
335 all := b.get(base, as(token))335 all := b.get(base, as(token))
336 assert.Contains(t, all.body, `href="/proj/merge-requests/1/since"`)336 assert.Contains(t, all.body, `href="/proj/merge-requests/1/since"`)
337 assert.Contains(t, all.body, "since your last read")337 assert.Contains(t, all.body, "since your last read")
338- assert.Contains(t, all.body, "<li data-new>", "the commit pushed since is marked")338+ assert.Contains(t, all.body, "<tr data-new>", "the commit pushed since is marked")
339 assert.Contains(t, all.body, "data-read>Mark read")339 assert.Contains(t, all.body, "data-read>Mark read")
340 assert.Contains(t, all.body, "outdated", "the notes were written on the earlier head")340 assert.Contains(t, all.body, "outdated", "the notes were written on the earlier head")
341 since := b.get(base+"/since", as(token))341 since := b.get(base+"/since", as(token))

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 44

↑↓ moveenter openesc close