detached 16cdb71

Merge b46e8c113e6ca1da6e02aee22255c67f8729c736 into cc7ba64ee52412f41c3ce5207bac7e47b9f01f30

commit
16cdb716bf7d9f2729ce576567094090aef333f4
author
ermite · · 2026-10-20 05:18 UTC
merge of
cc7ba64 + b46e8c1 · diff against the first parent
signature
unsigned
26 files · +1484 -886
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 +208 -0
@@ -92,3 +92,211 @@ 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 oldHistory = globalThis.history;
101+ const listeners = {};
102+ const replaced = [];
103+ globalThis.history = { replaceState: (...args) => replaced.push(args) };
104+ const node = (id) => ({ id, attrs: {}, events: {}, hidden: false,
105+ setAttribute(k,v) { this.attrs[k]=v; },
106+ addEventListener(k,v) { this.events[k]=v; }, focus() { this.focused=true; } });
107+ const tabs = [node('mr-tab-commits'), node('mr-tab-checks')];
108+ const panels = [node('mr-commits'), node('mr-checks-panel')];
109+ const footer = node('mr-panels'); footer.open=false;
110+ const nav = node('tabs'); nav.querySelectorAll=()=>tabs;
111+ footer.querySelectorAll=()=>panels;
112+ globalThis.document = {querySelector: (s) => s === '#mr-panels' ? footer : s === '[data-mr-tabs]' ? nav : null,
113+ addEventListener(k,v) {listeners[k]=v;} };
114+ globalThis.location = {hash:''};
115+ globalThis.addEventListener = (k,v) => {listeners[k]=v;};
116+ try {
117+ window.ermiteMR.panels();
118+ assert.equal(footer.open,false);
119+ assert.equal(panels[0].hidden,false);
120+ assert.equal(panels[1].hidden,true);
121+ assert.deepEqual(replaced, [], 'initial selection leaves the URL alone');
122+ tabs[1].events.click({preventDefault(){}});
123+ assert.deepEqual(replaced, [[null, '', '#mr-checks-panel']]);
124+ assert.equal(panels[0].hidden,true);
125+ assert.equal(tabs[1].attrs['aria-selected'],'true');
126+ tabs[1].events.keydown({key:'ArrowRight',preventDefault(){}});
127+ assert.equal(tabs[0].focused,true);
128+ assert.equal(panels[0].hidden,false);
129+ assert.deepEqual(replaced.at(-1), [null, '', '#mr-commits']);
130+ location.hash='#mr-checks'; replaced.length = 0; listeners.hashchange();
131+ assert.deepEqual(replaced, [], 'hash navigation does not rewrite the URL');
132+ assert.equal(footer.open,true);
133+ assert.equal(panels[1].hidden,false);
134+ footer.open=false;
135+ listeners.click({target:{closest:()=>true}});
136+ assert.equal(footer.open,true);
137+ assert.equal(C.tabIndex('Home',1,2),0);
138+ assert.equal(C.tabIndex('End',0,2),1);
139+ assert.equal(C.tabIndex('ArrowLeft',0,2),1);
140+ assert.equal(C.tabIndex('Escape',0,2),null);
141+ } finally {
142+ globalThis.document=oldDocument; globalThis.location=oldLocation; globalThis.addEventListener=oldAdd;
143+ if (oldHistory === undefined) delete globalThis.history; else globalThis.history = oldHistory;
144+ }
145+});
146+
147+test('footer: #mr-ck syncs the checks label and a click opens the footer on Checks', () => {
148+ const saved = Object.fromEntries(['document', 'location', 'addEventListener', 'history', 'MutationObserver'].map((k) => [k, globalThis[k]]));
149+ const node = (id) => ({ id, attrs: {}, events: {}, hidden: false,
150+ setAttribute(k, v) { this.attrs[k] = v; }, addEventListener(k, v) { this.events[k] = v; }, focus() {} });
151+ const tabs = [node('t0'), node('t1')];
152+ const panels = [node('mr-commits'), node('mr-checks-panel')];
153+ const footer = node('mr-panels'); footer.open = false; footer.querySelectorAll = () => panels;
154+ const label = { textContent: '' };
155+ const nav = node('tabs'); nav.querySelectorAll = () => tabs;
156+ nav.querySelector = (s) => s === '[data-checks-label]' ? label : null;
157+ const summary = { title: '1/2 failed', textContent: ' 1/2 ', parentElement: {} };
158+ const listeners = {};
159+ let observed = null, callback = null;
160+ globalThis.MutationObserver = class { constructor(fn) { callback = fn; } observe(target, opts) { observed = [target, opts]; } };
161+ globalThis.document = { querySelector: (s) => s === '#mr-panels' ? footer : s === '[data-mr-tabs]' ? nav : s === '#mr-ck' ? summary : null,
162+ addEventListener(k, v) { listeners[k] = v; } };
163+ globalThis.location = { hash: '' };
164+ globalThis.addEventListener = () => {};
165+ globalThis.history = { replaceState() {} };
166+ try {
167+ window.ermiteMR.panels();
168+ assert.equal(label.textContent, '1/2 failed', 'initial label sync');
169+ assert.equal(observed[0], summary.parentElement);
170+ summary.title = ''; callback();
171+ assert.equal(label.textContent, '1/2', 'observer re-syncs from the text');
172+ summary.textContent = ' '; callback();
173+ assert.equal(label.textContent, 'no checks');
174+ listeners.click({ target: { closest: (s) => s === '#mr-ck' ? summary : null } });
175+ assert.equal(footer.open, true);
176+ assert.equal(panels[1].hidden, false);
177+ assert.equal(panels[0].hidden, true);
178+ assert.equal(tabs[1].attrs['aria-selected'], 'true');
179+ } finally {
180+ for (const [k, v] of Object.entries(saved)) { if (v === undefined) delete globalThis[k]; else globalThis[k] = v; }
181+ }
182+});
183+
184+test('touch range: first tap anchors, second tap opens the sorted range', () => {
185+ const base = 'https://forge.test/demo/merge-requests/1';
186+ const first = base + '?on=new:24:a.go#f1';
187+ const last = base + '?on=new:10:a.go#f1';
188+ assert.deepEqual(C.touchRange(null, first, base), { start: first, url: null });
189+ const result = C.touchRange(first, last, base);
190+ assert.equal(result.start, null);
191+ assert.equal(new URL(result.url).searchParams.get('on'), 'new:10-24:a.go');
192+ assert.deepEqual(C.touchRange(first, first, base), { start: null, url: first });
193+});
194+
195+test('touch range: a different file, side or request becomes a new anchor', () => {
196+ const base = 'https://forge.test/demo/merge-requests/1';
197+ const first = base + '?on=new:24:a.go#f1';
198+ for (const next of [first.replace('new:', 'old:'), first.replace('a.go', 'b.go'), first.replace('/1?', '/2?')]) {
199+ assert.deepEqual(C.touchRange(first, next, base), { start: next, url: null });
200+ }
201+});
202+
203+test('mobile unified fallback only redirects single-layout split pages and preserves query/hash', () => {
204+ const href = 'https://forge.test/demo/merge-requests/1?view=split&from=25&on=new:3:a.go#f26';
205+ assert.equal(C.mobileURL(href, 'split', false), null);
206+ assert.equal(C.mobileURL(href, undefined, true), null, 'both layouts are switched by CSS');
207+ assert.equal(C.mobileURL(href, 'unified', true), null, 'no redirect loop');
208+ const url = new URL(C.mobileURL(href, 'split', true));
209+ assert.equal(url.searchParams.get('view'), 'unified');
210+ assert.equal(url.searchParams.get('from'), '25');
211+ assert.equal(url.searchParams.get('on'), 'new:3:a.go');
212+ assert.equal(url.hash, '#f26');
213+});
214+
215+test('touch control: lazy links enable toolbar; ordinary taps pass through; ranges navigate and cancel', async () => {
216+ const saved = Object.fromEntries(['document', 'location', 'addEventListener', 'localStorage', 'sessionStorage', 'fetch', 'matchMedia'].map((k) => [k, globalThis[k]]));
217+ const make = () => ({
218+ attrs: {}, events: {}, children: [], textContent: '',
219+ setAttribute(k, v) { this.attrs[k] = v; },
220+ removeAttribute(k) { delete this.attrs[k]; },
221+ addEventListener(k, fn) { this.events[k] = fn; },
222+ append(...nodes) { this.children.push(...nodes); },
223+ prepend(node) { this.children.unshift(node); },
224+ querySelector() { return null; }, querySelectorAll() { return []; },
225+ });
226+ const diffs = make();
227+ diffs.dataset = { diff: 'split' };
228+ const base = 'https://forge.test/demo/merge-requests/1';
229+ const line = (n) => Object.assign(make(), { href: `${base}?on=new:${n}:a.go#f1`, textContent: String(n) });
230+ const a = line(20), b = line(10);
231+ let loaded = false;
232+ diffs.querySelector = () => loaded ? a : null;
233+ let assigned = null;
234+ globalThis.document = {
235+ querySelector: (sel) => sel === '#diffs[data-mr]' || sel === '#diffs' ? diffs : null,
236+ querySelectorAll: () => [], createElement: (tag) => tag === 'template' ? { content: { querySelectorAll: () => [] } } : make(),
237+ };
238+ globalThis.location = { href: base, pathname: '/demo/merge-requests/1', hash: '', assign(url) { assigned = url; } };
239+ globalThis.addEventListener = () => {};
240+ const changes = {};
241+ const medias = {};
242+ globalThis.matchMedia = (q) => medias[q] ??= { matches: true, addEventListener(type, fn) { changes[q] = fn; } };
243+ const media = globalThis.matchMedia('(max-width: 720px)');
244+ const touchQuery = '(pointer: coarse), (hover: none)';
245+ const resize = () => changes['(max-width: 720px)']();
246+ globalThis.fetch = async () => { loaded = true; return { ok: true, status: 200, text: async () => '' }; };
247+ globalThis.localStorage = globalThis.sessionStorage = { getItem: () => null };
248+ const click = (link, modifiers = {}) => {
249+ const e = { target: { closest: () => link }, prevented: false, stopped: false,
250+ preventDefault() { this.prevented = true; }, stopPropagation() { this.stopped = true; }, ...modifiers };
251+ diffs.events.click(e);
252+ return e;
253+ };
254+ try {
255+ window.ermiteMR.start();
256+ const bar = diffs.children[0];
257+ const [button, status] = bar.children;
258+ assert.equal(bar.hidden, true, 'no commentable links in the initial window');
259+ assert.equal(typeof diffs.events.click, 'function', 'delegation installed before lazy load');
260+ await window.ermiteMR.load({ dataset: { src: '/files?from=25' } });
261+ assert.equal(bar.hidden, false, 'lazy window refresh reveals range control');
262+ assert.equal(diffs.dataset.mobile, 'true');
263+ assert.equal(diffs.dataset.diff, 'split', 'preferred layout is retained');
264+ media.matches = false;
265+ resize();
266+ assert.equal(diffs.dataset.mobile, 'false', 'desktop menu returns to preferred layout');
267+ assert.equal(diffs.dataset.diff, 'split');
268+ assert.equal(click(a).prevented, false, 'normal single-line navigation is untouched');
269+ button.events.click();
270+ assert.equal(button.attrs['aria-pressed'], 'true');
271+ assert.equal(click(a, { shiftKey: true }).prevented, false, 'desktop range selection is untouched');
272+ const event = click(a);
273+ assert.equal(event.prevented, true);
274+ assert.equal(event.stopped, true);
275+ assert.ok('data-range-start' in a.attrs);
276+ assert.match(status.textContent, /20/);
277+ click(b);
278+ assert.equal(new URL(assigned).searchParams.get('on'), 'new:10-20:a.go');
279+ assert.equal('data-range-start' in a.attrs, false);
280+ click(a);
281+ button.events.click();
282+ assert.equal(button.attrs['aria-pressed'], 'false');
283+ assert.equal(status.textContent, '');
284+ assert.equal('data-range-start' in a.attrs, false);
285+ assert.equal(click(b).prevented, false);
286+ // The touch media query stops matching: range mode is switched off.
287+ button.events.click();
288+ click(a);
289+ assert.equal(button.attrs['aria-pressed'], 'true');
290+ assert.ok('data-range-start' in a.attrs);
291+ medias[touchQuery].matches = false;
292+ changes[touchQuery]();
293+ assert.equal(button.attrs['aria-pressed'], 'false');
294+ assert.equal(status.textContent, '');
295+ assert.equal('data-range-start' in a.attrs, false);
296+ assert.equal(click(b).prevented, false, 'clicks pass through once touch stops matching');
297+ } finally {
298+ for (const [k, v] of Object.entries(saved)) {
299+ if (v === undefined) delete globalThis[k]; else globalThis[k] = v;
300+ }
301+ }
302+});
@@ -92,3 +92,211 @@ 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 oldHistory = globalThis.history;
101+ const listeners = {};
102+ const replaced = [];
103+ globalThis.history = { replaceState: (...args) => replaced.push(args) };
104+ const node = (id) => ({ id, attrs: {}, events: {}, hidden: false,
105+ setAttribute(k,v) { this.attrs[k]=v; },
106+ addEventListener(k,v) { this.events[k]=v; }, focus() { this.focused=true; } });
107+ const tabs = [node('mr-tab-commits'), node('mr-tab-checks')];
108+ const panels = [node('mr-commits'), node('mr-checks-panel')];
109+ const footer = node('mr-panels'); footer.open=false;
110+ const nav = node('tabs'); nav.querySelectorAll=()=>tabs;
111+ footer.querySelectorAll=()=>panels;
112+ globalThis.document = {querySelector: (s) => s === '#mr-panels' ? footer : s === '[data-mr-tabs]' ? nav : null,
113+ addEventListener(k,v) {listeners[k]=v;} };
114+ globalThis.location = {hash:''};
115+ globalThis.addEventListener = (k,v) => {listeners[k]=v;};
116+ try {
117+ window.ermiteMR.panels();
118+ assert.equal(footer.open,false);
119+ assert.equal(panels[0].hidden,false);
120+ assert.equal(panels[1].hidden,true);
121+ assert.deepEqual(replaced, [], 'initial selection leaves the URL alone');
122+ tabs[1].events.click({preventDefault(){}});
123+ assert.deepEqual(replaced, [[null, '', '#mr-checks-panel']]);
124+ assert.equal(panels[0].hidden,true);
125+ assert.equal(tabs[1].attrs['aria-selected'],'true');
126+ tabs[1].events.keydown({key:'ArrowRight',preventDefault(){}});
127+ assert.equal(tabs[0].focused,true);
128+ assert.equal(panels[0].hidden,false);
129+ assert.deepEqual(replaced.at(-1), [null, '', '#mr-commits']);
130+ location.hash='#mr-checks'; replaced.length = 0; listeners.hashchange();
131+ assert.deepEqual(replaced, [], 'hash navigation does not rewrite the URL');
132+ assert.equal(footer.open,true);
133+ assert.equal(panels[1].hidden,false);
134+ footer.open=false;
135+ listeners.click({target:{closest:()=>true}});
136+ assert.equal(footer.open,true);
137+ assert.equal(C.tabIndex('Home',1,2),0);
138+ assert.equal(C.tabIndex('End',0,2),1);
139+ assert.equal(C.tabIndex('ArrowLeft',0,2),1);
140+ assert.equal(C.tabIndex('Escape',0,2),null);
141+ } finally {
142+ globalThis.document=oldDocument; globalThis.location=oldLocation; globalThis.addEventListener=oldAdd;
143+ if (oldHistory === undefined) delete globalThis.history; else globalThis.history = oldHistory;
144+ }
145+});
146+
147+test('footer: #mr-ck syncs the checks label and a click opens the footer on Checks', () => {
148+ const saved = Object.fromEntries(['document', 'location', 'addEventListener', 'history', 'MutationObserver'].map((k) => [k, globalThis[k]]));
149+ const node = (id) => ({ id, attrs: {}, events: {}, hidden: false,
150+ setAttribute(k, v) { this.attrs[k] = v; }, addEventListener(k, v) { this.events[k] = v; }, focus() {} });
151+ const tabs = [node('t0'), node('t1')];
152+ const panels = [node('mr-commits'), node('mr-checks-panel')];
153+ const footer = node('mr-panels'); footer.open = false; footer.querySelectorAll = () => panels;
154+ const label = { textContent: '' };
155+ const nav = node('tabs'); nav.querySelectorAll = () => tabs;
156+ nav.querySelector = (s) => s === '[data-checks-label]' ? label : null;
157+ const summary = { title: '1/2 failed', textContent: ' 1/2 ', parentElement: {} };
158+ const listeners = {};
159+ let observed = null, callback = null;
160+ globalThis.MutationObserver = class { constructor(fn) { callback = fn; } observe(target, opts) { observed = [target, opts]; } };
161+ globalThis.document = { querySelector: (s) => s === '#mr-panels' ? footer : s === '[data-mr-tabs]' ? nav : s === '#mr-ck' ? summary : null,
162+ addEventListener(k, v) { listeners[k] = v; } };
163+ globalThis.location = { hash: '' };
164+ globalThis.addEventListener = () => {};
165+ globalThis.history = { replaceState() {} };
166+ try {
167+ window.ermiteMR.panels();
168+ assert.equal(label.textContent, '1/2 failed', 'initial label sync');
169+ assert.equal(observed[0], summary.parentElement);
170+ summary.title = ''; callback();
171+ assert.equal(label.textContent, '1/2', 'observer re-syncs from the text');
172+ summary.textContent = ' '; callback();
173+ assert.equal(label.textContent, 'no checks');
174+ listeners.click({ target: { closest: (s) => s === '#mr-ck' ? summary : null } });
175+ assert.equal(footer.open, true);
176+ assert.equal(panels[1].hidden, false);
177+ assert.equal(panels[0].hidden, true);
178+ assert.equal(tabs[1].attrs['aria-selected'], 'true');
179+ } finally {
180+ for (const [k, v] of Object.entries(saved)) { if (v === undefined) delete globalThis[k]; else globalThis[k] = v; }
181+ }
182+});
183+
184+test('touch range: first tap anchors, second tap opens the sorted range', () => {
185+ const base = 'https://forge.test/demo/merge-requests/1';
186+ const first = base + '?on=new:24:a.go#f1';
187+ const last = base + '?on=new:10:a.go#f1';
188+ assert.deepEqual(C.touchRange(null, first, base), { start: first, url: null });
189+ const result = C.touchRange(first, last, base);
190+ assert.equal(result.start, null);
191+ assert.equal(new URL(result.url).searchParams.get('on'), 'new:10-24:a.go');
192+ assert.deepEqual(C.touchRange(first, first, base), { start: null, url: first });
193+});
194+
195+test('touch range: a different file, side or request becomes a new anchor', () => {
196+ const base = 'https://forge.test/demo/merge-requests/1';
197+ const first = base + '?on=new:24:a.go#f1';
198+ for (const next of [first.replace('new:', 'old:'), first.replace('a.go', 'b.go'), first.replace('/1?', '/2?')]) {
199+ assert.deepEqual(C.touchRange(first, next, base), { start: next, url: null });
200+ }
201+});
202+
203+test('mobile unified fallback only redirects single-layout split pages and preserves query/hash', () => {
204+ const href = 'https://forge.test/demo/merge-requests/1?view=split&from=25&on=new:3:a.go#f26';
205+ assert.equal(C.mobileURL(href, 'split', false), null);
206+ assert.equal(C.mobileURL(href, undefined, true), null, 'both layouts are switched by CSS');
207+ assert.equal(C.mobileURL(href, 'unified', true), null, 'no redirect loop');
208+ const url = new URL(C.mobileURL(href, 'split', true));
209+ assert.equal(url.searchParams.get('view'), 'unified');
210+ assert.equal(url.searchParams.get('from'), '25');
211+ assert.equal(url.searchParams.get('on'), 'new:3:a.go');
212+ assert.equal(url.hash, '#f26');
213+});
214+
215+test('touch control: lazy links enable toolbar; ordinary taps pass through; ranges navigate and cancel', async () => {
216+ const saved = Object.fromEntries(['document', 'location', 'addEventListener', 'localStorage', 'sessionStorage', 'fetch', 'matchMedia'].map((k) => [k, globalThis[k]]));
217+ const make = () => ({
218+ attrs: {}, events: {}, children: [], textContent: '',
219+ setAttribute(k, v) { this.attrs[k] = v; },
220+ removeAttribute(k) { delete this.attrs[k]; },
221+ addEventListener(k, fn) { this.events[k] = fn; },
222+ append(...nodes) { this.children.push(...nodes); },
223+ prepend(node) { this.children.unshift(node); },
224+ querySelector() { return null; }, querySelectorAll() { return []; },
225+ });
226+ const diffs = make();
227+ diffs.dataset = { diff: 'split' };
228+ const base = 'https://forge.test/demo/merge-requests/1';
229+ const line = (n) => Object.assign(make(), { href: `${base}?on=new:${n}:a.go#f1`, textContent: String(n) });
230+ const a = line(20), b = line(10);
231+ let loaded = false;
232+ diffs.querySelector = () => loaded ? a : null;
233+ let assigned = null;
234+ globalThis.document = {
235+ querySelector: (sel) => sel === '#diffs[data-mr]' || sel === '#diffs' ? diffs : null,
236+ querySelectorAll: () => [], createElement: (tag) => tag === 'template' ? { content: { querySelectorAll: () => [] } } : make(),
237+ };
238+ globalThis.location = { href: base, pathname: '/demo/merge-requests/1', hash: '', assign(url) { assigned = url; } };
239+ globalThis.addEventListener = () => {};
240+ const changes = {};
241+ const medias = {};
242+ globalThis.matchMedia = (q) => medias[q] ??= { matches: true, addEventListener(type, fn) { changes[q] = fn; } };
243+ const media = globalThis.matchMedia('(max-width: 720px)');
244+ const touchQuery = '(pointer: coarse), (hover: none)';
245+ const resize = () => changes['(max-width: 720px)']();
246+ globalThis.fetch = async () => { loaded = true; return { ok: true, status: 200, text: async () => '' }; };
247+ globalThis.localStorage = globalThis.sessionStorage = { getItem: () => null };
248+ const click = (link, modifiers = {}) => {
249+ const e = { target: { closest: () => link }, prevented: false, stopped: false,
250+ preventDefault() { this.prevented = true; }, stopPropagation() { this.stopped = true; }, ...modifiers };
251+ diffs.events.click(e);
252+ return e;
253+ };
254+ try {
255+ window.ermiteMR.start();
256+ const bar = diffs.children[0];
257+ const [button, status] = bar.children;
258+ assert.equal(bar.hidden, true, 'no commentable links in the initial window');
259+ assert.equal(typeof diffs.events.click, 'function', 'delegation installed before lazy load');
260+ await window.ermiteMR.load({ dataset: { src: '/files?from=25' } });
261+ assert.equal(bar.hidden, false, 'lazy window refresh reveals range control');
262+ assert.equal(diffs.dataset.mobile, 'true');
263+ assert.equal(diffs.dataset.diff, 'split', 'preferred layout is retained');
264+ media.matches = false;
265+ resize();
266+ assert.equal(diffs.dataset.mobile, 'false', 'desktop menu returns to preferred layout');
267+ assert.equal(diffs.dataset.diff, 'split');
268+ assert.equal(click(a).prevented, false, 'normal single-line navigation is untouched');
269+ button.events.click();
270+ assert.equal(button.attrs['aria-pressed'], 'true');
271+ assert.equal(click(a, { shiftKey: true }).prevented, false, 'desktop range selection is untouched');
272+ const event = click(a);
273+ assert.equal(event.prevented, true);
274+ assert.equal(event.stopped, true);
275+ assert.ok('data-range-start' in a.attrs);
276+ assert.match(status.textContent, /20/);
277+ click(b);
278+ assert.equal(new URL(assigned).searchParams.get('on'), 'new:10-20:a.go');
279+ assert.equal('data-range-start' in a.attrs, false);
280+ click(a);
281+ button.events.click();
282+ assert.equal(button.attrs['aria-pressed'], 'false');
283+ assert.equal(status.textContent, '');
284+ assert.equal('data-range-start' in a.attrs, false);
285+ assert.equal(click(b).prevented, false);
286+ // The touch media query stops matching: range mode is switched off.
287+ button.events.click();
288+ click(a);
289+ assert.equal(button.attrs['aria-pressed'], 'true');
290+ assert.ok('data-range-start' in a.attrs);
291+ medias[touchQuery].matches = false;
292+ changes[touchQuery]();
293+ assert.equal(button.attrs['aria-pressed'], 'false');
294+ assert.equal(status.textContent, '');
295+ assert.equal('data-range-start' in a.attrs, false);
296+ assert.equal(click(b).prevented, false, 'clicks pass through once touch stops matching');
297+ } finally {
298+ for (const [k, v] of Object.entries(saved)) {
299+ if (v === undefined) delete globalThis[k]; else globalThis[k] = v;
300+ }
301+ }
302+});
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 +108 -84
@@ -108,8 +108,9 @@ templ mrListRail(p MRListPage) {
108108 }
109109
110110 // MergeRequest is a merge request: its facts, its description, the diff with
111-// the notes under their lines, the general comments; and in the rail the merge
112-// form, the checks, the settings, the commits and the files.
111+// the notes under their lines, the general comments. The merge and More menus
112+// sit in the toolbar, the commits and checks in the card footer, and the rail
113+// holds the files and verdicts.
113114 templ MergeRequest(l Layout, p MRPage) {
114115 @Shell(l, mrRail(p)) {
115116 <section class="mr-card">
@@ -147,6 +148,7 @@ templ MergeRequest(l Layout, p MRPage) {
147148 @templ.Raw(string(p.Desc))
148149 </article>
149150 }
151+ @mrFooter(p)
150152 </section>
151153 if p.Deleting != "" {
152154 <p class="note" role="status">merged. the branch { p.Deleting } is being deleted.</p>
@@ -366,6 +368,65 @@ templ commentForm(f CommentForm, suffix string) {
366368 </form>
367369 }
368370
371+templ mrFooter(p MRPage) {
372+ <footer class="mr-footer">
373+ <details id="mr-panels">
374+ <summary>Commits <span class="count">{ p.CommitCount }</span> · Checks</summary>
375+ <nav data-mr-tabs aria-label="Branch details">
376+ <a id="mr-tab-commits" href="#mr-commits">Commits <span class="count">{ p.CommitCount }</span></a>
377+ <a id="mr-tab-checks" href="#mr-checks">
378+ { "Checks " }
379+ <span data-checks-label>
380+ if p.ChecksSum.Total > 0 {
381+ { p.ChecksSum.Title }
382+ } else {
383+ no checks
384+ }
385+ </span>
386+ </a>
387+ </nav>
388+ <div id="mr-commits" data-mr-panel aria-labelledby="mr-tab-commits">
389+ <table class="mr-commits">
390+ <thead><tr><th>Commit</th><th>Subject</th><th>Author</th><th>Date</th><th>Signature</th><th>Status</th></tr></thead>
391+ <tbody>
392+ for _, c := range p.Commits {
393+ <tr data-new?={ c.New }>
394+ <td><a href={ templ.SafeURL(c.Href) }>{ c.Short }</a></td>
395+ <td>{ c.Subject }</td>
396+ <td>{ c.Author }</td>
397+ <td>
398+ if c.WhenAt != "" {
399+ <time datetime={ c.WhenAt }>{ c.When }</time>
400+ }
401+ </td>
402+ <td>
403+ if c.Sig != nil {
404+ @signaturePill(c.Sig)
405+ }
406+ </td>
407+ <td>
408+ if c.New {
409+ <span>new</span>
410+ }
411+ </td>
412+ </tr>
413+ }
414+ </tbody>
415+ </table>
416+ if len(p.Commits) == 0 {
417+ <p class="dim">no commit to merge.</p>
418+ }
419+ if p.CommitsNote != "" {
420+ <p class="note">{ p.CommitsNote }</p>
421+ }
422+ </div>
423+ <div id="mr-checks-panel" data-mr-panel aria-labelledby="mr-tab-checks">
424+ @MRChecks(p.Checks)
425+ </div>
426+ </details>
427+ </footer>
428+}
429+
369430 templ mrRail(p MRPage) {
370431 <section aria-labelledby="r-files" class="r-files">
371432 <h2 id="r-files">
@@ -391,51 +452,6 @@ templ mrRail(p MRPage) {
391452 </ul>
392453 </section>
393454 }
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>
439455 }
440456
441457 // mrBar is the bar above the diff, which follows the review: the totals, the
@@ -450,8 +466,8 @@ templ mrBar(p MRPage) {
450466 @MRChecksSum(p.ChecksSum)
451467 if p.Box != nil {
452468 @mergeMenu(p)
453- @moreMenu(p)
454469 }
470+ @moreMenu(p)
455471 </div>
456472 }
457473
@@ -474,18 +490,9 @@ templ mergeMenu(p MRPage) {
474490 <kbd aria-hidden="true">M</kbd>
475491 </summary>
476492 <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>
493+ if p.Box.HeadGone {
494+ <p class="dim">the source branch was deleted</p>
495+ }
489496 if p.Box.Error != "" {
490497 <p class="d-err" role="alert">{ p.Box.Error }</p>
491498 }
@@ -519,15 +526,6 @@ templ mergeMenu(p MRPage) {
519526 </label>
520527 }
521528 </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- }
531529 if p.Box.CanDeleteBranch {
532530 <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>
533531 }
@@ -589,26 +587,52 @@ templ MRMergeabilityFragment(v MergeabilityView) {
589587 @mrMergeabilitySlot(v)
590588 }
591589
592-// moreMenu is what else the owner does with an open request: mark the head
593-// read, close it, merge it from a terminal.
590+// moreMenu shows read-only settings to every viewer, and keeps owner actions
591+// behind the same merge-box permission as before.
594592 templ moreMenu(p MRPage) {
595593 <details class="menu omenu">
596594 <summary class="btn icon" aria-label="More actions" title="more actions">⋯</summary>
597595 <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>
596+ <section class="merge-settings">
597+ <h2>Merge settings</h2>
598+ <dl class="kv">
599+ <dt>modes</dt>
600+ <dd>{ strings.Join(p.Modes, ", ") }</dd>
601+ <dt>checks</dt>
602+ <dd>
603+ if p.ChecksBlock {
604+ failing ones block the merge
605+ } else {
606+ do not block the merge
607+ }
608+ </dd>
609+ </dl>
610+ </section>
611+ if p.Box != nil {
612+ if p.Box.Signed {
613+ <p class="d-note" id="mr-signing">
614+ squash and merge commits are signed with ermite's own key (generated on first start).
615+ if p.Box.Fingerprint != "" {
616+ fingerprint <code>{ p.Box.Fingerprint }</code>
617+ }
618+ <code>ermite signing-key show</code> prints it.
619+ </p>
620+ }
621+ if p.Box.CanMarkRead {
622+ <form method="post" action={ templ.SafeURL(p.Box.ReadAction) }>
623+ <input type="hidden" name="head_id" value={ p.Box.Head }/>
624+ <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>
625+ </form>
626+ }
627+ <form method="post" action={ templ.SafeURL(p.Box.CloseAction) }>
628+ <button type="submit" title="close without merging; the branch is kept" class="btn danger">Close</button>
602629 </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>
630+ if !p.Box.HeadGone && p.Box.ReadyAction == "" {
631+ <details class="d-or">
632+ <summary class="mute">or from a terminal</summary>
633+ @CloneBlock(p.Box.CLI)
634+ </details>
635+ }
612636 }
613637 </div>
614638 </details>
@@ -108,8 +108,9 @@ templ mrListRail(p MRListPage) {
108 }108 }
109 109
110 // MergeRequest is a merge request: its facts, its description, the diff with110 // MergeRequest is a merge request: its facts, its description, the diff with
111-// the notes under their lines, the general comments; and in the rail the merge111+// the notes under their lines, the general comments. The merge and More menus
112-// form, the checks, the settings, the commits and the files.112+// sit in the toolbar, the commits and checks in the card footer, and the rail
113+// holds the files and verdicts.
113 templ MergeRequest(l Layout, p MRPage) {114 templ MergeRequest(l Layout, p MRPage) {
114 @Shell(l, mrRail(p)) {115 @Shell(l, mrRail(p)) {
115 <section class="mr-card">116 <section class="mr-card">
@@ -147,6 +148,7 @@ templ MergeRequest(l Layout, p MRPage) {
147 @templ.Raw(string(p.Desc))148 @templ.Raw(string(p.Desc))
148 </article>149 </article>
149 }150 }
151+ @mrFooter(p)
150 </section>152 </section>
151 if p.Deleting != "" {153 if p.Deleting != "" {
152 <p class="note" role="status">merged. the branch { p.Deleting } is being deleted.</p>154 <p class="note" role="status">merged. the branch { p.Deleting } is being deleted.</p>
@@ -366,6 +368,65 @@ templ commentForm(f CommentForm, suffix string) {
366 </form>368 </form>
367 }369 }
368 370
371+templ mrFooter(p MRPage) {
372+ <footer class="mr-footer">
373+ <details id="mr-panels">
374+ <summary>Commits <span class="count">{ p.CommitCount }</span> · Checks</summary>
375+ <nav data-mr-tabs aria-label="Branch details">
376+ <a id="mr-tab-commits" href="#mr-commits">Commits <span class="count">{ p.CommitCount }</span></a>
377+ <a id="mr-tab-checks" href="#mr-checks">
378+ { "Checks " }
379+ <span data-checks-label>
380+ if p.ChecksSum.Total > 0 {
381+ { p.ChecksSum.Title }
382+ } else {
383+ no checks
384+ }
385+ </span>
386+ </a>
387+ </nav>
388+ <div id="mr-commits" data-mr-panel aria-labelledby="mr-tab-commits">
389+ <table class="mr-commits">
390+ <thead><tr><th>Commit</th><th>Subject</th><th>Author</th><th>Date</th><th>Signature</th><th>Status</th></tr></thead>
391+ <tbody>
392+ for _, c := range p.Commits {
393+ <tr data-new?={ c.New }>
394+ <td><a href={ templ.SafeURL(c.Href) }>{ c.Short }</a></td>
395+ <td>{ c.Subject }</td>
396+ <td>{ c.Author }</td>
397+ <td>
398+ if c.WhenAt != "" {
399+ <time datetime={ c.WhenAt }>{ c.When }</time>
400+ }
401+ </td>
402+ <td>
403+ if c.Sig != nil {
404+ @signaturePill(c.Sig)
405+ }
406+ </td>
407+ <td>
408+ if c.New {
409+ <span>new</span>
410+ }
411+ </td>
412+ </tr>
413+ }
414+ </tbody>
415+ </table>
416+ if len(p.Commits) == 0 {
417+ <p class="dim">no commit to merge.</p>
418+ }
419+ if p.CommitsNote != "" {
420+ <p class="note">{ p.CommitsNote }</p>
421+ }
422+ </div>
423+ <div id="mr-checks-panel" data-mr-panel aria-labelledby="mr-tab-checks">
424+ @MRChecks(p.Checks)
425+ </div>
426+ </details>
427+ </footer>
428+}
429+
369 templ mrRail(p MRPage) {430 templ mrRail(p MRPage) {
370 <section aria-labelledby="r-files" class="r-files">431 <section aria-labelledby="r-files" class="r-files">
371 <h2 id="r-files">432 <h2 id="r-files">
@@ -391,51 +452,6 @@ templ mrRail(p MRPage) {
391 </ul>452 </ul>
392 </section>453 </section>
393 }454 }
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 }455 }
440 456
441 // mrBar is the bar above the diff, which follows the review: the totals, the457 // mrBar is the bar above the diff, which follows the review: the totals, the
@@ -450,8 +466,8 @@ templ mrBar(p MRPage) {
450 @MRChecksSum(p.ChecksSum)466 @MRChecksSum(p.ChecksSum)
451 if p.Box != nil {467 if p.Box != nil {
452 @mergeMenu(p)468 @mergeMenu(p)
453- @moreMenu(p)
454 }469 }
470+ @moreMenu(p)
455 </div>471 </div>
456 }472 }
457 473
@@ -474,18 +490,9 @@ templ mergeMenu(p MRPage) {
474 <kbd aria-hidden="true">M</kbd>490 <kbd aria-hidden="true">M</kbd>
475 </summary>491 </summary>
476 <div class="menu-pop" role="group" aria-label="Merge">492 <div class="menu-pop" role="group" aria-label="Merge">
477- <dl class="kv">493+ if p.Box.HeadGone {
478- <dt>head</dt>494+ <p class="dim">the source branch was deleted</p>
479- <dd>495+ }
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 != "" {496 if p.Box.Error != "" {
490 <p class="d-err" role="alert">{ p.Box.Error }</p>497 <p class="d-err" role="alert">{ p.Box.Error }</p>
491 }498 }
@@ -519,15 +526,6 @@ templ mergeMenu(p MRPage) {
519 </label>526 </label>
520 }527 }
521 </fieldset>528 </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 {529 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>530 <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 }531 }
@@ -589,26 +587,52 @@ templ MRMergeabilityFragment(v MergeabilityView) {
589 @mrMergeabilitySlot(v)587 @mrMergeabilitySlot(v)
590 }588 }
591 589
592-// moreMenu is what else the owner does with an open request: mark the head590+// moreMenu shows read-only settings to every viewer, and keeps owner actions
593-// read, close it, merge it from a terminal.591+// behind the same merge-box permission as before.
594 templ moreMenu(p MRPage) {592 templ moreMenu(p MRPage) {
595 <details class="menu omenu">593 <details class="menu omenu">
596 <summary class="btn icon" aria-label="More actions" title="more actions">⋯</summary>594 <summary class="btn icon" aria-label="More actions" title="more actions">⋯</summary>
597 <div class="menu-pop" role="group" aria-label="More actions">595 <div class="menu-pop" role="group" aria-label="More actions">
598- if p.Box.CanMarkRead {596+ <section class="merge-settings">
599- <form method="post" action={ templ.SafeURL(p.Box.ReadAction) }>597+ <h2>Merge settings</h2>
600- <input type="hidden" name="head_id" value={ p.Box.Head }/>598+ <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>599+ <dt>modes</dt>
600+ <dd>{ strings.Join(p.Modes, ", ") }</dd>
601+ <dt>checks</dt>
602+ <dd>
603+ if p.ChecksBlock {
604+ failing ones block the merge
605+ } else {
606+ do not block the merge
607+ }
608+ </dd>
609+ </dl>
610+ </section>
611+ if p.Box != nil {
612+ if p.Box.Signed {
613+ <p class="d-note" id="mr-signing">
614+ squash and merge commits are signed with ermite's own key (generated on first start).
615+ if p.Box.Fingerprint != "" {
616+ fingerprint <code>{ p.Box.Fingerprint }</code>
617+ }
618+ <code>ermite signing-key show</code> prints it.
619+ </p>
620+ }
621+ if p.Box.CanMarkRead {
622+ <form method="post" action={ templ.SafeURL(p.Box.ReadAction) }>
623+ <input type="hidden" name="head_id" value={ p.Box.Head }/>
624+ <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>
625+ </form>
626+ }
627+ <form method="post" action={ templ.SafeURL(p.Box.CloseAction) }>
628+ <button type="submit" title="close without merging; the branch is kept" class="btn danger">Close</button>
602 </form>629 </form>
603- }630+ if !p.Box.HeadGone && p.Box.ReadyAction == "" {
604- <form method="post" action={ templ.SafeURL(p.Box.CloseAction) }>631+ <details class="d-or">
605- <button type="submit" title="close without merging; the branch is kept" class="btn danger">Close</button>632+ <summary class="mute">or from a terminal</summary>
606- </form>633+ @CloneBlock(p.Box.CLI)
607- if !p.Box.HeadGone && p.Box.ReadyAction == "" {634+ </details>
608- <details class="d-or">635+ }
609- <summary class="mute">or from a terminal</summary>
610- @CloneBlock(p.Box.CLI)
611- </details>
612 }636 }
613 </div>637 </div>
614 </details>638 </details>
M internal/adapters/web/mr_templ.go +626 -581
@@ -521,8 +521,9 @@ func mrListRail(p MRListPage) templ.Component {
521521 }
522522
523523 // MergeRequest is a merge request: its facts, its description, the diff with
524-// the notes under their lines, the general comments; and in the rail the merge
525-// form, the checks, the settings, the commits and the files.
524+// the notes under their lines, the general comments. The merge and More menus
525+// sit in the toolbar, the commits and checks in the card footer, and the rail
526+// holds the files and verdicts.
526527 func MergeRequest(l Layout, p MRPage) templ.Component {
527528 return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
528529 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@@ -563,7 +564,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
563564 var templ_7745c5c3_Var26 string
564565 templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(p.Number)
565566 if templ_7745c5c3_Err != nil {
566- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 117, Col: 37}
567+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 118, Col: 37}
567568 }
568569 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26))
569570 if templ_7745c5c3_Err != nil {
@@ -576,7 +577,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
576577 var templ_7745c5c3_Var27 string
577578 templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(p.Title)
578579 if templ_7745c5c3_Err != nil {
579- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 117, Col: 56}
580+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 118, Col: 56}
580581 }
581582 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27))
582583 if templ_7745c5c3_Err != nil {
@@ -589,7 +590,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
589590 var templ_7745c5c3_Var28 string
590591 templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.State)
591592 if templ_7745c5c3_Err != nil {
592- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 120, Col: 46}
593+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 121, Col: 46}
593594 }
594595 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var28)
595596 if templ_7745c5c3_Err != nil {
@@ -602,7 +603,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
602603 var templ_7745c5c3_Var29 string
603604 templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(p.State)
604605 if templ_7745c5c3_Err != nil {
605- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 121, Col: 15}
606+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 122, Col: 15}
606607 }
607608 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29))
608609 if templ_7745c5c3_Err != nil {
@@ -616,7 +617,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
616617 var templ_7745c5c3_Var30 string
617618 templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")
618619 if templ_7745c5c3_Err != nil {
619- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 123, Col: 15}
620+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 124, Col: 15}
620621 }
621622 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30))
622623 if templ_7745c5c3_Err != nil {
@@ -629,7 +630,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
629630 var templ_7745c5c3_Var31 templ.SafeURL
630631 templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.MergedHref))
631632 if templ_7745c5c3_Err != nil {
632- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 123, Col: 54}
633+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 124, Col: 54}
633634 }
634635 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31))
635636 if templ_7745c5c3_Err != nil {
@@ -642,7 +643,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
642643 var templ_7745c5c3_Var32 string
643644 templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.JoinStringErrs(p.MergedShort)
644645 if templ_7745c5c3_Err != nil {
645- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 123, Col: 72}
646+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 124, Col: 72}
646647 }
647648 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var32))
648649 if templ_7745c5c3_Err != nil {
@@ -655,7 +656,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
655656 var templ_7745c5c3_Var33 string
656657 templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.JoinStringErrs(" · " + p.MergeMode)
657658 if templ_7745c5c3_Err != nil {
658- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 123, Col: 100}
659+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 124, Col: 100}
659660 }
660661 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var33))
661662 if templ_7745c5c3_Err != nil {
@@ -673,7 +674,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
673674 var templ_7745c5c3_Var34 string
674675 templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(" → ")
675676 if templ_7745c5c3_Err != nil {
676- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 129, Col: 15}
677+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 130, Col: 15}
677678 }
678679 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34))
679680 if templ_7745c5c3_Err != nil {
@@ -690,7 +691,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
690691 var templ_7745c5c3_Var35 string
691692 templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.JoinStringErrs(p.Opened.Name)
692693 if templ_7745c5c3_Err != nil {
693- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 134, Col: 21}
694+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 135, Col: 21}
694695 }
695696 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var35))
696697 if templ_7745c5c3_Err != nil {
@@ -704,7 +705,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
704705 var templ_7745c5c3_Var36 string
705706 templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")
706707 if templ_7745c5c3_Err != nil {
707- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 136, Col: 15}
708+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 137, Col: 15}
708709 }
709710 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var36))
710711 if templ_7745c5c3_Err != nil {
@@ -717,7 +718,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
717718 var templ_7745c5c3_Var37 string
718719 templ_7745c5c3_Var37, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Opened.WhenAt)
719720 if templ_7745c5c3_Err != nil {
720- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 136, Col: 49}
721+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 137, Col: 49}
721722 }
722723 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var37)
723724 if templ_7745c5c3_Err != nil {
@@ -730,7 +731,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
730731 var templ_7745c5c3_Var38 string
731732 templ_7745c5c3_Var38, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Opened.Abs)
732733 if templ_7745c5c3_Err != nil {
733- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 136, Col: 72}
734+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 137, Col: 72}
734735 }
735736 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var38)
736737 if templ_7745c5c3_Err != nil {
@@ -743,7 +744,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
743744 var templ_7745c5c3_Var39 string
744745 templ_7745c5c3_Var39, templ_7745c5c3_Err = templ.JoinStringErrs(p.Opened.When)
745746 if templ_7745c5c3_Err != nil {
746- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 136, Col: 90}
747+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 137, Col: 90}
747748 }
748749 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var39))
749750 if templ_7745c5c3_Err != nil {
@@ -766,7 +767,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
766767 var templ_7745c5c3_Var40 string
767768 templ_7745c5c3_Var40, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.UpdatedAt)
768769 if templ_7745c5c3_Err != nil {
769- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 141, Col: 38}
770+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 142, Col: 38}
770771 }
771772 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var40)
772773 if templ_7745c5c3_Err != nil {
@@ -779,7 +780,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
779780 var templ_7745c5c3_Var41 string
780781 templ_7745c5c3_Var41, templ_7745c5c3_Err = templ.JoinStringErrs(p.Updated)
781782 if templ_7745c5c3_Err != nil {
782- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 141, Col: 52}
783+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 142, Col: 52}
783784 }
784785 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var41))
785786 if templ_7745c5c3_Err != nil {
@@ -808,6 +809,10 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
808809 return templ_7745c5c3_Err
809810 }
810811 }
812+ templ_7745c5c3_Err = mrFooter(p).Render(ctx, templ_7745c5c3_Buffer)
813+ if templ_7745c5c3_Err != nil {
814+ return templ_7745c5c3_Err
815+ }
811816 templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "</section>")
812817 if templ_7745c5c3_Err != nil {
813818 return templ_7745c5c3_Err
@@ -820,7 +825,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
820825 var templ_7745c5c3_Var42 string
821826 templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.JoinStringErrs(p.Deleting)
822827 if templ_7745c5c3_Err != nil {
823- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 152, Col: 64}
828+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 154, Col: 64}
824829 }
825830 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var42))
826831 if templ_7745c5c3_Err != nil {
@@ -843,7 +848,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
843848 var templ_7745c5c3_Var43 string
844849 templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinStringErrs(p.MergeError)
845850 if templ_7745c5c3_Err != nil {
846- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 155, Col: 47}
851+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 157, Col: 47}
847852 }
848853 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43))
849854 if templ_7745c5c3_Err != nil {
@@ -874,7 +879,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
874879 var templ_7745c5c3_Var44 templ.SafeURL
875880 templ_7745c5c3_Var44, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Since.AllHref))
876881 if templ_7745c5c3_Err != nil {
877- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 161, Col: 42}
882+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 163, Col: 42}
878883 }
879884 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var44))
880885 if templ_7745c5c3_Err != nil {
@@ -897,7 +902,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
897902 var templ_7745c5c3_Var45 string
898903 templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
899904 if templ_7745c5c3_Err != nil {
900- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 165, Col: 49}
905+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 167, Col: 49}
901906 }
902907 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var45))
903908 if templ_7745c5c3_Err != nil {
@@ -910,7 +915,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
910915 var templ_7745c5c3_Var46 templ.SafeURL
911916 templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Since.SinceHref))
912917 if templ_7745c5c3_Err != nil {
913- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 167, Col: 44}
918+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 169, Col: 44}
914919 }
915920 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var46))
916921 if templ_7745c5c3_Err != nil {
@@ -933,7 +938,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
933938 var templ_7745c5c3_Var47 string
934939 templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.JoinStringErrs(p.Since.ReadShort)
935940 if templ_7745c5c3_Err != nil {
936- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 171, Col: 64}
941+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 173, Col: 64}
937942 }
938943 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var47))
939944 if templ_7745c5c3_Err != nil {
@@ -946,7 +951,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
946951 var templ_7745c5c3_Var48 string
947952 templ_7745c5c3_Var48, templ_7745c5c3_Err = templ.JoinStringErrs(p.Since.HeadShort)
948953 if templ_7745c5c3_Err != nil {
949- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 171, Col: 90}
954+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 173, Col: 90}
950955 }
951956 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var48))
952957 if templ_7745c5c3_Err != nil {
@@ -969,7 +974,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
969974 var templ_7745c5c3_Var49 string
970975 templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.JoinStringErrs(p.SinceNote)
971976 if templ_7745c5c3_Err != nil {
972- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 175, Col: 34}
977+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 177, Col: 34}
973978 }
974979 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var49))
975980 if templ_7745c5c3_Err != nil {
@@ -1010,7 +1015,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
10101015 var templ_7745c5c3_Var50 string
10111016 templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note)
10121017 if templ_7745c5c3_Err != nil {
1013- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 185, Col: 29}
1018+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 187, Col: 29}
10141019 }
10151020 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var50))
10161021 if templ_7745c5c3_Err != nil {
@@ -1033,7 +1038,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
10331038 var templ_7745c5c3_Var51 string
10341039 templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Canonical)
10351040 if templ_7745c5c3_Err != nil {
1036- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 191, Col: 32}
1041+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 193, Col: 32}
10371042 }
10381043 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var51)
10391044 if templ_7745c5c3_Err != nil {
@@ -1052,7 +1057,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
10521057 var templ_7745c5c3_Var52 string
10531058 templ_7745c5c3_Var52, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
10541059 if templ_7745c5c3_Err != nil {
1055- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 194, Col: 22}
1060+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 196, Col: 22}
10561061 }
10571062 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var52)
10581063 if templ_7745c5c3_Err != nil {
@@ -1070,7 +1075,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
10701075 var templ_7745c5c3_Var53 string
10711076 templ_7745c5c3_Var53, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
10721077 if templ_7745c5c3_Err != nil {
1073- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 196, Col: 22}
1078+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 198, Col: 22}
10741079 }
10751080 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var53)
10761081 if templ_7745c5c3_Err != nil {
@@ -1110,7 +1115,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
11101115 var templ_7745c5c3_Var54 string
11111116 templ_7745c5c3_Var54, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.NUnresolved))
11121117 if templ_7745c5c3_Err != nil {
1113- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 209, Col: 97}
1118+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 211, Col: 97}
11141119 }
11151120 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var54))
11161121 if templ_7745c5c3_Err != nil {
@@ -1123,7 +1128,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
11231128 var templ_7745c5c3_Var55 string
11241129 templ_7745c5c3_Var55, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.NComments))
11251130 if templ_7745c5c3_Err != nil {
1126- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 209, Col: 126}
1131+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 211, Col: 126}
11271132 }
11281133 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var55))
11291134 if templ_7745c5c3_Err != nil {
@@ -1204,7 +1209,7 @@ func branchLink(name, href string) templ.Component {
12041209 var templ_7745c5c3_Var57 templ.SafeURL
12051210 templ_7745c5c3_Var57, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))
12061211 if templ_7745c5c3_Err != nil {
1207- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 227, Col: 31}
1212+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 229, Col: 31}
12081213 }
12091214 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var57))
12101215 if templ_7745c5c3_Err != nil {
@@ -1217,7 +1222,7 @@ func branchLink(name, href string) templ.Component {
12171222 var templ_7745c5c3_Var58 string
12181223 templ_7745c5c3_Var58, templ_7745c5c3_Err = templ.JoinStringErrs(name)
12191224 if templ_7745c5c3_Err != nil {
1220- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 227, Col: 40}
1225+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 229, Col: 40}
12211226 }
12221227 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var58))
12231228 if templ_7745c5c3_Err != nil {
@@ -1231,7 +1236,7 @@ func branchLink(name, href string) templ.Component {
12311236 var templ_7745c5c3_Var59 string
12321237 templ_7745c5c3_Var59, templ_7745c5c3_Err = templ.JoinStringErrs(name)
12331238 if templ_7745c5c3_Err != nil {
1234- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 229, Col: 8}
1239+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 231, Col: 8}
12351240 }
12361241 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var59))
12371242 if templ_7745c5c3_Err != nil {
@@ -1312,7 +1317,7 @@ func commentView(c CommentView, suffix string) templ.Component {
13121317 var templ_7745c5c3_Var62 string
13131318 templ_7745c5c3_Var62, templ_7745c5c3_Err = templ.ResolveAttributeValue("c" + c.ID + suffix)
13141319 if templ_7745c5c3_Err != nil {
1315- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 248, Col: 42}
1320+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 250, Col: 42}
13161321 }
13171322 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var62)
13181323 if templ_7745c5c3_Err != nil {
@@ -1325,7 +1330,7 @@ func commentView(c CommentView, suffix string) templ.Component {
13251330 var templ_7745c5c3_Var63 string
13261331 templ_7745c5c3_Var63, templ_7745c5c3_Err = templ.ResolveAttributeValue(boolText(c.Resolved))
13271332 if templ_7745c5c3_Err != nil {
1328- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 248, Col: 81}
1333+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 250, Col: 81}
13291334 }
13301335 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var63)
13311336 if templ_7745c5c3_Err != nil {
@@ -1348,7 +1353,7 @@ func commentView(c CommentView, suffix string) templ.Component {
13481353 var templ_7745c5c3_Var64 string
13491354 templ_7745c5c3_Var64, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)
13501355 if templ_7745c5c3_Err != nil {
1351- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 250, Col: 33}
1356+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 252, Col: 33}
13521357 }
13531358 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var64))
13541359 if templ_7745c5c3_Err != nil {
@@ -1362,7 +1367,7 @@ func commentView(c CommentView, suffix string) templ.Component {
13621367 var templ_7745c5c3_Var65 string
13631368 templ_7745c5c3_Var65, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
13641369 if templ_7745c5c3_Err != nil {
1365- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 252, Col: 9}
1370+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 254, Col: 9}
13661371 }
13671372 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var65))
13681373 if templ_7745c5c3_Err != nil {
@@ -1375,7 +1380,7 @@ func commentView(c CommentView, suffix string) templ.Component {
13751380 var templ_7745c5c3_Var66 string
13761381 templ_7745c5c3_Var66, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)
13771382 if templ_7745c5c3_Err != nil {
1378- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 252, Col: 49}
1383+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 254, Col: 49}
13791384 }
13801385 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var66)
13811386 if templ_7745c5c3_Err != nil {
@@ -1388,7 +1393,7 @@ func commentView(c CommentView, suffix string) templ.Component {
13881393 var templ_7745c5c3_Var67 string
13891394 templ_7745c5c3_Var67, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.Abs)
13901395 if templ_7745c5c3_Err != nil {
1391- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 252, Col: 65}
1396+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 254, Col: 65}
13921397 }
13931398 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var67)
13941399 if templ_7745c5c3_Err != nil {
@@ -1401,7 +1406,7 @@ func commentView(c CommentView, suffix string) templ.Component {
14011406 var templ_7745c5c3_Var68 string
14021407 templ_7745c5c3_Var68, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)
14031408 if templ_7745c5c3_Err != nil {
1404- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 252, Col: 76}
1409+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 254, Col: 76}
14051410 }
14061411 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var68))
14071412 if templ_7745c5c3_Err != nil {
@@ -1416,7 +1421,7 @@ func commentView(c CommentView, suffix string) templ.Component {
14161421 var templ_7745c5c3_Var69 string
14171422 templ_7745c5c3_Var69, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
14181423 if templ_7745c5c3_Err != nil {
1419- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 255, Col: 9}
1424+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 257, Col: 9}
14201425 }
14211426 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var69))
14221427 if templ_7745c5c3_Err != nil {
@@ -1431,7 +1436,7 @@ func commentView(c CommentView, suffix string) templ.Component {
14311436 var templ_7745c5c3_Var70 string
14321437 templ_7745c5c3_Var70, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
14331438 if templ_7745c5c3_Err != nil {
1434- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 258, Col: 9}
1439+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 260, Col: 9}
14351440 }
14361441 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var70))
14371442 if templ_7745c5c3_Err != nil {
@@ -1446,7 +1451,7 @@ func commentView(c CommentView, suffix string) templ.Component {
14461451 var templ_7745c5c3_Var71 string
14471452 templ_7745c5c3_Var71, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
14481453 if templ_7745c5c3_Err != nil {
1449- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 261, Col: 9}
1454+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 263, Col: 9}
14501455 }
14511456 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var71))
14521457 if templ_7745c5c3_Err != nil {
@@ -1459,7 +1464,7 @@ func commentView(c CommentView, suffix string) templ.Component {
14591464 var templ_7745c5c3_Var72 string
14601465 templ_7745c5c3_Var72, templ_7745c5c3_Err = templ.JoinStringErrs(c.Where)
14611466 if templ_7745c5c3_Err != nil {
1462- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 261, Col: 47}
1467+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 263, Col: 47}
14631468 }
14641469 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var72))
14651470 if templ_7745c5c3_Err != nil {
@@ -1534,7 +1539,7 @@ func commentView(c CommentView, suffix string) templ.Component {
15341539 var templ_7745c5c3_Var73 string
15351540 templ_7745c5c3_Var73, templ_7745c5c3_Err = templ.JoinStringErrs(c.Verdict)
15361541 if templ_7745c5c3_Err != nil {
1537- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 285, Col: 36}
1542+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 287, Col: 36}
15381543 }
15391544 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var73))
15401545 if templ_7745c5c3_Err != nil {
@@ -1553,7 +1558,7 @@ func commentView(c CommentView, suffix string) templ.Component {
15531558 var templ_7745c5c3_Var74 string
15541559 templ_7745c5c3_Var74, templ_7745c5c3_Err = templ.JoinStringErrs(c.Range)
15551560 if templ_7745c5c3_Err != nil {
1556- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 288, Col: 31}
1561+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 290, Col: 31}
15571562 }
15581563 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var74))
15591564 if templ_7745c5c3_Err != nil {
@@ -1572,7 +1577,7 @@ func commentView(c CommentView, suffix string) templ.Component {
15721577 var templ_7745c5c3_Var75 string
15731578 templ_7745c5c3_Var75, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.Quote)
15741579 if templ_7745c5c3_Err != nil {
1575- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 291, Col: 65}
1580+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 293, Col: 65}
15761581 }
15771582 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var75)
15781583 if templ_7745c5c3_Err != nil {
@@ -1591,7 +1596,7 @@ func commentView(c CommentView, suffix string) templ.Component {
15911596 var templ_7745c5c3_Var76 templ.SafeURL
15921597 templ_7745c5c3_Var76, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Edit.Action))
15931598 if templ_7745c5c3_Err != nil {
1594- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 294, Col: 92}
1599+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 296, Col: 92}
15951600 }
15961601 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var76))
15971602 if templ_7745c5c3_Err != nil {
@@ -1604,7 +1609,7 @@ func commentView(c CommentView, suffix string) templ.Component {
16041609 var templ_7745c5c3_Var77 string
16051610 templ_7745c5c3_Var77, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(c.Edit.From))
16061611 if templ_7745c5c3_Err != nil {
1607- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 294, Col: 153}
1612+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 296, Col: 153}
16081613 }
16091614 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var77)
16101615 if templ_7745c5c3_Err != nil {
@@ -1617,7 +1622,7 @@ func commentView(c CommentView, suffix string) templ.Component {
16171622 var templ_7745c5c3_Var78 string
16181623 templ_7745c5c3_Var78, templ_7745c5c3_Err = templ.JoinStringErrs(c.Edit.Text)
16191624 if templ_7745c5c3_Err != nil {
1620- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 294, Col: 209}
1625+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 296, Col: 209}
16211626 }
16221627 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var78))
16231628 if templ_7745c5c3_Err != nil {
@@ -1636,7 +1641,7 @@ func commentView(c CommentView, suffix string) templ.Component {
16361641 var templ_7745c5c3_Var79 templ.SafeURL
16371642 templ_7745c5c3_Var79, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Delete.Action))
16381643 if templ_7745c5c3_Err != nil {
1639- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 297, Col: 96}
1644+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 299, Col: 96}
16401645 }
16411646 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var79))
16421647 if templ_7745c5c3_Err != nil {
@@ -1649,7 +1654,7 @@ func commentView(c CommentView, suffix string) templ.Component {
16491654 var templ_7745c5c3_Var80 string
16501655 templ_7745c5c3_Var80, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(c.Delete.From))
16511656 if templ_7745c5c3_Err != nil {
1652- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 297, Col: 159}
1657+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 299, Col: 159}
16531658 }
16541659 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var80)
16551660 if templ_7745c5c3_Err != nil {
@@ -1688,7 +1693,7 @@ func commentView(c CommentView, suffix string) templ.Component {
16881693 var templ_7745c5c3_Var81 templ.SafeURL
16891694 templ_7745c5c3_Var81, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Resolve.Action))
16901695 if templ_7745c5c3_Err != nil {
1691- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 308, Col: 77}
1696+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 310, Col: 77}
16921697 }
16931698 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var81))
16941699 if templ_7745c5c3_Err != nil {
@@ -1701,7 +1706,7 @@ func commentView(c CommentView, suffix string) templ.Component {
17011706 var templ_7745c5c3_Var82 string
17021707 templ_7745c5c3_Var82, templ_7745c5c3_Err = templ.ResolveAttributeValue(boolText(c.Resolve.Value))
17031708 if templ_7745c5c3_Err != nil {
1704- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 309, Col: 74}
1709+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 311, Col: 74}
17051710 }
17061711 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var82)
17071712 if templ_7745c5c3_Err != nil {
@@ -1719,7 +1724,7 @@ func commentView(c CommentView, suffix string) templ.Component {
17191724 var templ_7745c5c3_Var83 string
17201725 templ_7745c5c3_Var83, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(c.Resolve.From))
17211726 if templ_7745c5c3_Err != nil {
1722- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 311, Col: 66}
1727+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 313, Col: 66}
17231728 }
17241729 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var83)
17251730 if templ_7745c5c3_Err != nil {
@@ -1737,7 +1742,7 @@ func commentView(c CommentView, suffix string) templ.Component {
17371742 var templ_7745c5c3_Var84 string
17381743 templ_7745c5c3_Var84, templ_7745c5c3_Err = templ.JoinStringErrs(c.Resolve.Label)
17391744 if templ_7745c5c3_Err != nil {
1740- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 313, Col: 55}
1745+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 315, Col: 55}
17411746 }
17421747 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var84))
17431748 if templ_7745c5c3_Err != nil {
@@ -1792,7 +1797,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
17921797 var templ_7745c5c3_Var86 templ.SafeURL
17931798 templ_7745c5c3_Var86, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(f.Action))
17941799 if templ_7745c5c3_Err != nil {
1795- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 328, Col: 67}
1800+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 330, Col: 67}
17961801 }
17971802 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var86))
17981803 if templ_7745c5c3_Err != nil {
@@ -1805,7 +1810,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
18051810 var templ_7745c5c3_Var87 string
18061811 templ_7745c5c3_Var87, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID + suffix)
18071812 if templ_7745c5c3_Err != nil {
1808- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 329, Col: 28}
1813+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 331, Col: 28}
18091814 }
18101815 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var87)
18111816 if templ_7745c5c3_Err != nil {
@@ -1818,7 +1823,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
18181823 var templ_7745c5c3_Var88 string
18191824 templ_7745c5c3_Var88, templ_7745c5c3_Err = templ.JoinStringErrs(f.Title)
18201825 if templ_7745c5c3_Err != nil {
1821- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 329, Col: 40}
1826+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 331, Col: 40}
18221827 }
18231828 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var88))
18241829 if templ_7745c5c3_Err != nil {
@@ -1831,7 +1836,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
18311836 var templ_7745c5c3_Var89 string
18321837 templ_7745c5c3_Var89, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID + suffix)
18331838 if templ_7745c5c3_Err != nil {
1834- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 331, Col: 21}
1839+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 333, Col: 21}
18351840 }
18361841 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var89)
18371842 if templ_7745c5c3_Err != nil {
@@ -1870,7 +1875,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
18701875 var templ_7745c5c3_Var90 string
18711876 templ_7745c5c3_Var90, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Path)
18721877 if templ_7745c5c3_Err != nil {
1873- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 346, Col: 50}
1878+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 348, Col: 50}
18741879 }
18751880 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var90)
18761881 if templ_7745c5c3_Err != nil {
@@ -1883,7 +1888,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
18831888 var templ_7745c5c3_Var91 string
18841889 templ_7745c5c3_Var91, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Line)
18851890 if templ_7745c5c3_Err != nil {
1886- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 347, Col: 50}
1891+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 349, Col: 50}
18871892 }
18881893 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var91)
18891894 if templ_7745c5c3_Err != nil {
@@ -1896,7 +1901,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
18961901 var templ_7745c5c3_Var92 string
18971902 templ_7745c5c3_Var92, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Side)
18981903 if templ_7745c5c3_Err != nil {
1899- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 348, Col: 50}
1904+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 350, Col: 50}
19001905 }
19011906 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var92)
19021907 if templ_7745c5c3_Err != nil {
@@ -1909,7 +1914,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
19091914 var templ_7745c5c3_Var93 string
19101915 templ_7745c5c3_Var93, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.StartLine)
19111916 if templ_7745c5c3_Err != nil {
1912- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 349, Col: 86}
1917+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 351, Col: 86}
19131918 }
19141919 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var93)
19151920 if templ_7745c5c3_Err != nil {
@@ -1928,7 +1933,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
19281933 var templ_7745c5c3_Var94 string
19291934 templ_7745c5c3_Var94, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ReplyTo)
19301935 if templ_7745c5c3_Err != nil {
1931- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 352, Col: 57}
1936+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 354, Col: 57}
19321937 }
19331938 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var94)
19341939 if templ_7745c5c3_Err != nil {
@@ -1953,7 +1958,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
19531958 var templ_7745c5c3_Var95 string
19541959 templ_7745c5c3_Var95, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(f.From))
19551960 if templ_7745c5c3_Err != nil {
1956- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 358, Col: 56}
1961+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 360, Col: 56}
19571962 }
19581963 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var95)
19591964 if templ_7745c5c3_Err != nil {
@@ -1976,7 +1981,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
19761981 var templ_7745c5c3_Var96 templ.SafeURL
19771982 templ_7745c5c3_Var96, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(f.Cancel))
19781983 if templ_7745c5c3_Err != nil {
1979- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 363, Col: 49}
1984+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 365, Col: 49}
19801985 }
19811986 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var96))
19821987 if templ_7745c5c3_Err != nil {
@@ -1995,7 +2000,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
19952000 })
19962001 }
19972002
1998-func mrRail(p MRPage) templ.Component {
2003+func mrFooter(p MRPage) templ.Component {
19992004 return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
20002005 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
20012006 if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -2016,312 +2021,349 @@ func mrRail(p MRPage) templ.Component {
20162021 templ_7745c5c3_Var97 = templ.NopComponent
20172022 }
20182023 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\">")
2024+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 185, "<footer class=\"mr-footer\"><details id=\"mr-panels\"><summary>Commits <span class=\"count\">")
20202025 if templ_7745c5c3_Err != nil {
20212026 return templ_7745c5c3_Err
20222027 }
20232028 var templ_7745c5c3_Var98 string
2024- templ_7745c5c3_Var98, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))
2029+ templ_7745c5c3_Var98, templ_7745c5c3_Err = templ.JoinStringErrs(p.CommitCount)
20252030 if templ_7745c5c3_Err != nil {
2026- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 372, Col: 49}
2031+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 374, Col: 55}
20272032 }
20282033 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var98))
20292034 if templ_7745c5c3_Err != nil {
20302035 return templ_7745c5c3_Err
20312036 }
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>")
2037+ 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\">")
20332038 if templ_7745c5c3_Err != nil {
20342039 return templ_7745c5c3_Err
20352040 }
2036- templ_7745c5c3_Err = FileList(p.Files).Render(ctx, templ_7745c5c3_Buffer)
2041+ var templ_7745c5c3_Var99 string
2042+ templ_7745c5c3_Var99, templ_7745c5c3_Err = templ.JoinStringErrs(p.CommitCount)
20372043 if templ_7745c5c3_Err != nil {
2038- return templ_7745c5c3_Err
2044+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 376, Col: 89}
20392045 }
2040- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 187, "</section>")
2046+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var99))
20412047 if templ_7745c5c3_Err != nil {
20422048 return templ_7745c5c3_Err
20432049 }
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)
2050+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 187, "</span></a> <a id=\"mr-tab-checks\" href=\"#mr-checks\">")
21102051 if templ_7745c5c3_Err != nil {
21112052 return templ_7745c5c3_Err
21122053 }
2113- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 196, "<section aria-labelledby=\"r-commits\"><h2 id=\"r-commits\">Commits <span class=\"count\">")
2054+ var templ_7745c5c3_Var100 string
2055+ templ_7745c5c3_Var100, templ_7745c5c3_Err = templ.JoinStringErrs("Checks ")
21142056 if templ_7745c5c3_Err != nil {
2115- return templ_7745c5c3_Err
2057+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 378, Col: 16}
21162058 }
2117- var templ_7745c5c3_Var102 string
2118- templ_7745c5c3_Var102, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Commits)))
2059+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var100))
21192060 if templ_7745c5c3_Err != nil {
2120- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 396, Col: 71}
2061+ return templ_7745c5c3_Err
21212062 }
2122- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var102))
2063+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 188, " <span data-checks-label>")
21232064 if templ_7745c5c3_Err != nil {
21242065 return templ_7745c5c3_Err
21252066 }
2126- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 197, "</span></h2><ul class=\"pcommits\">")
2067+ if p.ChecksSum.Total > 0 {
2068+ var templ_7745c5c3_Var101 string
2069+ templ_7745c5c3_Var101, templ_7745c5c3_Err = templ.JoinStringErrs(p.ChecksSum.Title)
2070+ if templ_7745c5c3_Err != nil {
2071+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 381, Col: 26}
2072+ }
2073+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var101))
2074+ if templ_7745c5c3_Err != nil {
2075+ return templ_7745c5c3_Err
2076+ }
2077+ } else {
2078+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 189, "no checks")
2079+ if templ_7745c5c3_Err != nil {
2080+ return templ_7745c5c3_Err
2081+ }
2082+ }
2083+ 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>")
21272084 if templ_7745c5c3_Err != nil {
21282085 return templ_7745c5c3_Err
21292086 }
21302087 for _, c := range p.Commits {
2131- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 198, "<li")
2088+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 191, "<tr")
21322089 if templ_7745c5c3_Err != nil {
21332090 return templ_7745c5c3_Err
21342091 }
21352092 if c.New {
2136- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 199, " data-new")
2093+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 192, " data-new")
21372094 if templ_7745c5c3_Err != nil {
21382095 return templ_7745c5c3_Err
21392096 }
21402097 }
2141- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 200, "><a href=\"")
2098+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 193, "><td><a href=\"")
21422099 if templ_7745c5c3_Err != nil {
21432100 return templ_7745c5c3_Err
21442101 }
2145- var templ_7745c5c3_Var103 templ.SafeURL
2146- templ_7745c5c3_Var103, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Href))
2102+ var templ_7745c5c3_Var102 templ.SafeURL
2103+ templ_7745c5c3_Var102, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Href))
21472104 if templ_7745c5c3_Err != nil {
2148- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 400, Col: 36}
2105+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 394, Col: 43}
21492106 }
2150- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var103))
2107+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var102))
21512108 if templ_7745c5c3_Err != nil {
21522109 return templ_7745c5c3_Err
21532110 }
2154- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 201, "\">")
2111+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 194, "\">")
21552112 if templ_7745c5c3_Err != nil {
21562113 return templ_7745c5c3_Err
21572114 }
2158- var templ_7745c5c3_Var104 string
2159- templ_7745c5c3_Var104, templ_7745c5c3_Err = templ.JoinStringErrs(c.Short)
2115+ var templ_7745c5c3_Var103 string
2116+ templ_7745c5c3_Var103, templ_7745c5c3_Err = templ.JoinStringErrs(c.Short)
21602117 if templ_7745c5c3_Err != nil {
2161- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 400, Col: 48}
2118+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 394, Col: 55}
21622119 }
2163- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var104))
2120+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var103))
21642121 if templ_7745c5c3_Err != nil {
21652122 return templ_7745c5c3_Err
21662123 }
2167- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 202, "</a> <span class=\"s\">")
2124+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 195, "</a></td><td>")
21682125 if templ_7745c5c3_Err != nil {
21692126 return templ_7745c5c3_Err
21702127 }
2171- var templ_7745c5c3_Var105 string
2172- templ_7745c5c3_Var105, templ_7745c5c3_Err = templ.JoinStringErrs(c.Subject)
2128+ var templ_7745c5c3_Var104 string
2129+ templ_7745c5c3_Var104, templ_7745c5c3_Err = templ.JoinStringErrs(c.Subject)
21732130 if templ_7745c5c3_Err != nil {
2174- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 401, Col: 32}
2131+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 395, Col: 23}
21752132 }
2176- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var105))
2133+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var104))
21772134 if templ_7745c5c3_Err != nil {
21782135 return templ_7745c5c3_Err
21792136 }
2180- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 203, "</span> ")
2137+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 196, "</td><td>")
21812138 if templ_7745c5c3_Err != nil {
21822139 return templ_7745c5c3_Err
21832140 }
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)
2141+ var templ_7745c5c3_Var105 string
2142+ templ_7745c5c3_Var105, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)
21962143 if templ_7745c5c3_Err != nil {
2197- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 406, Col: 16}
2144+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 396, Col: 22}
21982145 }
2199- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var106))
2146+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var105))
22002147 if templ_7745c5c3_Err != nil {
22012148 return templ_7745c5c3_Err
22022149 }
2203- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 205, " ")
2150+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 197, "</td><td>")
22042151 if templ_7745c5c3_Err != nil {
22052152 return templ_7745c5c3_Err
22062153 }
22072154 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))
2155+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 198, "<time datetime=\"")
22142156 if templ_7745c5c3_Err != nil {
22152157 return templ_7745c5c3_Err
22162158 }
2217- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 206, "<time datetime=\"")
2159+ var templ_7745c5c3_Var106 string
2160+ templ_7745c5c3_Var106, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)
22182161 if templ_7745c5c3_Err != nil {
2219- return templ_7745c5c3_Err
2162+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 399, Col: 35}
22202163 }
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)
2164+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var106)
22272165 if templ_7745c5c3_Err != nil {
22282166 return templ_7745c5c3_Err
22292167 }
2230- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 207, "\">")
2168+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 199, "\">")
22312169 if templ_7745c5c3_Err != nil {
22322170 return templ_7745c5c3_Err
22332171 }
2234- var templ_7745c5c3_Var109 string
2235- templ_7745c5c3_Var109, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)
2172+ var templ_7745c5c3_Var107 string
2173+ templ_7745c5c3_Var107, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)
22362174 if templ_7745c5c3_Err != nil {
2237- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 408, Col: 53}
2175+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 399, Col: 46}
22382176 }
2239- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var109))
2177+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var107))
22402178 if templ_7745c5c3_Err != nil {
22412179 return templ_7745c5c3_Err
22422180 }
2243- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 208, "</time> ")
2181+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 200, "</time>")
22442182 if templ_7745c5c3_Err != nil {
22452183 return templ_7745c5c3_Err
22462184 }
22472185 }
2248- if c.New {
2249- var templ_7745c5c3_Var110 string
2250- templ_7745c5c3_Var110, templ_7745c5c3_Err = templ.JoinStringErrs(" · new")
2186+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 201, "</td><td>")
2187+ if templ_7745c5c3_Err != nil {
2188+ return templ_7745c5c3_Err
2189+ }
2190+ if c.Sig != nil {
2191+ templ_7745c5c3_Err = signaturePill(c.Sig).Render(ctx, templ_7745c5c3_Buffer)
22512192 if templ_7745c5c3_Err != nil {
2252- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 411, Col: 18}
2193+ return templ_7745c5c3_Err
22532194 }
2254- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var110))
2195+ }
2196+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 202, "</td><td>")
2197+ if templ_7745c5c3_Err != nil {
2198+ return templ_7745c5c3_Err
2199+ }
2200+ if c.New {
2201+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 203, "<span>new</span>")
22552202 if templ_7745c5c3_Err != nil {
22562203 return templ_7745c5c3_Err
22572204 }
22582205 }
2259- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 209, "</span></li>")
2206+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 204, "</td></tr>")
22602207 if templ_7745c5c3_Err != nil {
22612208 return templ_7745c5c3_Err
22622209 }
22632210 }
2264- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 210, "</ul>")
2211+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 205, "</tbody></table>")
22652212 if templ_7745c5c3_Err != nil {
22662213 return templ_7745c5c3_Err
22672214 }
22682215 if len(p.Commits) == 0 {
2269- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 211, "<p class=\"dim\">no commit to merge.</p>")
2216+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 206, "<p class=\"dim\">no commit to merge.</p>")
22702217 if templ_7745c5c3_Err != nil {
22712218 return templ_7745c5c3_Err
22722219 }
22732220 }
22742221 if p.CommitsNote != "" {
2275- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 212, "<p class=\"note\">")
2222+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 207, "<p class=\"note\">")
22762223 if templ_7745c5c3_Err != nil {
22772224 return templ_7745c5c3_Err
22782225 }
2279- var templ_7745c5c3_Var111 string
2280- templ_7745c5c3_Var111, templ_7745c5c3_Err = templ.JoinStringErrs(p.CommitsNote)
2226+ var templ_7745c5c3_Var108 string
2227+ templ_7745c5c3_Var108, templ_7745c5c3_Err = templ.JoinStringErrs(p.CommitsNote)
22812228 if templ_7745c5c3_Err != nil {
2282- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 421, Col: 34}
2229+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 420, Col: 36}
22832230 }
2284- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var111))
2231+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var108))
22852232 if templ_7745c5c3_Err != nil {
22862233 return templ_7745c5c3_Err
22872234 }
2288- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 213, "</p>")
2235+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 208, "</p>")
22892236 if templ_7745c5c3_Err != nil {
22902237 return templ_7745c5c3_Err
22912238 }
22922239 }
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>")
2240+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 209, "</div><div id=\"mr-checks-panel\" data-mr-panel aria-labelledby=\"mr-tab-checks\">")
22942241 if templ_7745c5c3_Err != nil {
22952242 return templ_7745c5c3_Err
22962243 }
2297- var templ_7745c5c3_Var112 string
2298- templ_7745c5c3_Var112, templ_7745c5c3_Err = templ.JoinStringErrs(strings.Join(p.Modes, ", "))
2244+ templ_7745c5c3_Err = MRChecks(p.Checks).Render(ctx, templ_7745c5c3_Buffer)
22992245 if templ_7745c5c3_Err != nil {
2300- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 428, Col: 36}
2246+ return templ_7745c5c3_Err
2247+ }
2248+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 210, "</div></details></footer>")
2249+ if templ_7745c5c3_Err != nil {
2250+ return templ_7745c5c3_Err
2251+ }
2252+ return nil
2253+ })
2254+}
2255+
2256+func mrRail(p MRPage) templ.Component {
2257+ return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
2258+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
2259+ if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
2260+ return templ_7745c5c3_CtxErr
23012261 }
2302- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var112))
2262+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
2263+ if !templ_7745c5c3_IsBuffer {
2264+ defer func() {
2265+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
2266+ if templ_7745c5c3_Err == nil {
2267+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
2268+ }
2269+ }()
2270+ }
2271+ ctx = templ.InitializeContext(ctx)
2272+ templ_7745c5c3_Var109 := templ.GetChildren(ctx)
2273+ if templ_7745c5c3_Var109 == nil {
2274+ templ_7745c5c3_Var109 = templ.NopComponent
2275+ }
2276+ ctx = templ.ClearChildren(ctx)
2277+ 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\">")
23032278 if templ_7745c5c3_Err != nil {
23042279 return templ_7745c5c3_Err
23052280 }
2306- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 215, "</dd><dt>checks</dt><dd>")
2281+ var templ_7745c5c3_Var110 string
2282+ templ_7745c5c3_Var110, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))
2283+ if templ_7745c5c3_Err != nil {
2284+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 433, Col: 49}
2285+ }
2286+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var110))
23072287 if templ_7745c5c3_Err != nil {
23082288 return templ_7745c5c3_Err
23092289 }
2310- if p.ChecksBlock {
2311- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 216, "failing ones block the merge")
2290+ 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>")
2291+ if templ_7745c5c3_Err != nil {
2292+ return templ_7745c5c3_Err
2293+ }
2294+ templ_7745c5c3_Err = FileList(p.Files).Render(ctx, templ_7745c5c3_Buffer)
2295+ if templ_7745c5c3_Err != nil {
2296+ return templ_7745c5c3_Err
2297+ }
2298+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 213, "</section>")
2299+ if templ_7745c5c3_Err != nil {
2300+ return templ_7745c5c3_Err
2301+ }
2302+ if len(p.Verdicts) > 0 {
2303+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 214, "<section><h2>Verdicts</h2><ul>")
23122304 if templ_7745c5c3_Err != nil {
23132305 return templ_7745c5c3_Err
23142306 }
2315- } else {
2316- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 217, "do not block the merge")
2307+ for _, v := range p.Verdicts {
2308+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 215, "<li><a href=\"")
2309+ if templ_7745c5c3_Err != nil {
2310+ return templ_7745c5c3_Err
2311+ }
2312+ var templ_7745c5c3_Var111 templ.SafeURL
2313+ templ_7745c5c3_Var111, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(v.Href))
2314+ if templ_7745c5c3_Err != nil {
2315+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 446, Col: 37}
2316+ }
2317+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var111))
2318+ if templ_7745c5c3_Err != nil {
2319+ return templ_7745c5c3_Err
2320+ }
2321+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 216, "\">")
2322+ if templ_7745c5c3_Err != nil {
2323+ return templ_7745c5c3_Err
2324+ }
2325+ var templ_7745c5c3_Var112 string
2326+ templ_7745c5c3_Var112, templ_7745c5c3_Err = templ.JoinStringErrs(v.Author)
2327+ if templ_7745c5c3_Err != nil {
2328+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 446, Col: 50}
2329+ }
2330+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var112))
2331+ if templ_7745c5c3_Err != nil {
2332+ return templ_7745c5c3_Err
2333+ }
2334+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 217, ": ")
2335+ if templ_7745c5c3_Err != nil {
2336+ return templ_7745c5c3_Err
2337+ }
2338+ var templ_7745c5c3_Var113 string
2339+ templ_7745c5c3_Var113, templ_7745c5c3_Err = templ.JoinStringErrs(v.Label)
2340+ if templ_7745c5c3_Err != nil {
2341+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 446, Col: 63}
2342+ }
2343+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var113))
2344+ if templ_7745c5c3_Err != nil {
2345+ return templ_7745c5c3_Err
2346+ }
2347+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 218, "</a> ")
2348+ if templ_7745c5c3_Err != nil {
2349+ return templ_7745c5c3_Err
2350+ }
2351+ if v.Stale {
2352+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 219, "<span class=\"mute\">(stale)</span>")
2353+ if templ_7745c5c3_Err != nil {
2354+ return templ_7745c5c3_Err
2355+ }
2356+ }
2357+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 220, "</li>")
2358+ if templ_7745c5c3_Err != nil {
2359+ return templ_7745c5c3_Err
2360+ }
2361+ }
2362+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 221, "</ul></section>")
23172363 if templ_7745c5c3_Err != nil {
23182364 return templ_7745c5c3_Err
23192365 }
23202366 }
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- }
23252367 return nil
23262368 })
23272369 }
@@ -2346,51 +2388,51 @@ func mrBar(p MRPage) templ.Component {
23462388 }()
23472389 }
23482390 ctx = templ.InitializeContext(ctx)
2349- templ_7745c5c3_Var113 := templ.GetChildren(ctx)
2350- if templ_7745c5c3_Var113 == nil {
2351- templ_7745c5c3_Var113 = templ.NopComponent
2391+ templ_7745c5c3_Var114 := templ.GetChildren(ctx)
2392+ if templ_7745c5c3_Var114 == nil {
2393+ templ_7745c5c3_Var114 = templ.NopComponent
23522394 }
23532395 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\">")
2396+ 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\">")
23552397 if templ_7745c5c3_Err != nil {
23562398 return templ_7745c5c3_Err
23572399 }
2358- var templ_7745c5c3_Var114 string
2359- templ_7745c5c3_Var114, templ_7745c5c3_Err = templ.JoinStringErrs(plural(p.NFiles, "file", "files"))
2400+ var templ_7745c5c3_Var115 string
2401+ templ_7745c5c3_Var115, templ_7745c5c3_Err = templ.JoinStringErrs(plural(p.NFiles, "file", "files"))
23602402 if templ_7745c5c3_Err != nil {
2361- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 447, Col: 55}
2403+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 463, Col: 55}
23622404 }
2363- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var114))
2405+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var115))
23642406 if templ_7745c5c3_Err != nil {
23652407 return templ_7745c5c3_Err
23662408 }
2367- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 220, " · <span class=\"plus\">+")
2409+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 223, " · <span class=\"plus\">+")
23682410 if templ_7745c5c3_Err != nil {
23692411 return templ_7745c5c3_Err
23702412 }
2371- var templ_7745c5c3_Var115 string
2372- templ_7745c5c3_Var115, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Adds))
2413+ var templ_7745c5c3_Var116 string
2414+ templ_7745c5c3_Var116, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Adds))
23732415 if templ_7745c5c3_Err != nil {
2374- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 447, Col: 95}
2416+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 463, Col: 95}
23752417 }
2376- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var115))
2418+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var116))
23772419 if templ_7745c5c3_Err != nil {
23782420 return templ_7745c5c3_Err
23792421 }
2380- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 221, "</span> <span class=\"minus\">-")
2422+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 224, "</span> <span class=\"minus\">-")
23812423 if templ_7745c5c3_Err != nil {
23822424 return templ_7745c5c3_Err
23832425 }
2384- var templ_7745c5c3_Var116 string
2385- templ_7745c5c3_Var116, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Dels))
2426+ var templ_7745c5c3_Var117 string
2427+ templ_7745c5c3_Var117, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Dels))
23862428 if templ_7745c5c3_Err != nil {
2387- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 447, Col: 140}
2429+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 463, Col: 140}
23882430 }
2389- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var116))
2431+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var117))
23902432 if templ_7745c5c3_Err != nil {
23912433 return templ_7745c5c3_Err
23922434 }
2393- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 222, "</span></span>")
2435+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 225, "</span></span>")
23942436 if templ_7745c5c3_Err != nil {
23952437 return templ_7745c5c3_Err
23962438 }
@@ -2398,7 +2440,7 @@ func mrBar(p MRPage) templ.Component {
23982440 if templ_7745c5c3_Err != nil {
23992441 return templ_7745c5c3_Err
24002442 }
2401- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 223, "<span class=\"grow\"></span>")
2443+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 226, "<span class=\"grow\"></span>")
24022444 if templ_7745c5c3_Err != nil {
24032445 return templ_7745c5c3_Err
24042446 }
@@ -2411,16 +2453,12 @@ func mrBar(p MRPage) templ.Component {
24112453 if templ_7745c5c3_Err != nil {
24122454 return templ_7745c5c3_Err
24132455 }
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- }
24222456 }
2423- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 225, "</div>")
2457+ templ_7745c5c3_Err = moreMenu(p).Render(ctx, templ_7745c5c3_Buffer)
2458+ if templ_7745c5c3_Err != nil {
2459+ return templ_7745c5c3_Err
2460+ }
2461+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 227, "</div>")
24242462 if templ_7745c5c3_Err != nil {
24252463 return templ_7745c5c3_Err
24262464 }
@@ -2452,84 +2490,57 @@ func mergeMenu(p MRPage) templ.Component {
24522490 }()
24532491 }
24542492 ctx = templ.InitializeContext(ctx)
2455- templ_7745c5c3_Var117 := templ.GetChildren(ctx)
2456- if templ_7745c5c3_Var117 == nil {
2457- templ_7745c5c3_Var117 = templ.NopComponent
2493+ templ_7745c5c3_Var118 := templ.GetChildren(ctx)
2494+ if templ_7745c5c3_Var118 == nil {
2495+ templ_7745c5c3_Var118 = templ.NopComponent
24582496 }
24592497 ctx = templ.ClearChildren(ctx)
2460- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 226, "<details class=\"menu mmenu\" id=\"merge-menu\" data-state=\"open\"")
2498+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 228, "<details class=\"menu mmenu\" id=\"merge-menu\" data-state=\"open\"")
24612499 if templ_7745c5c3_Err != nil {
24622500 return templ_7745c5c3_Err
24632501 }
24642502 if p.Box.Error != "" {
2465- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 227, " open")
2503+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 229, " open")
24662504 if templ_7745c5c3_Err != nil {
24672505 return templ_7745c5c3_Err
24682506 }
24692507 }
2470- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 228, "><summary class=\"btn primary\" aria-keyshortcuts=\"Shift+M\">")
2508+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 230, "><summary class=\"btn primary\" aria-keyshortcuts=\"Shift+M\">")
24712509 if templ_7745c5c3_Err != nil {
24722510 return templ_7745c5c3_Err
24732511 }
24742512 if p.Box.ReadyAction != "" {
2475- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 229, "Draft ")
2513+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 231, "Draft ")
24762514 if templ_7745c5c3_Err != nil {
24772515 return templ_7745c5c3_Err
24782516 }
24792517 } else {
2480- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 230, "Merge ")
2518+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 232, "Merge ")
24812519 if templ_7745c5c3_Err != nil {
24822520 return templ_7745c5c3_Err
24832521 }
24842522 }
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>")
2523+ 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\">")
24862524 if templ_7745c5c3_Err != nil {
24872525 return templ_7745c5c3_Err
24882526 }
24892527 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))
2528+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 234, "<p class=\"dim\">the source branch was deleted</p>")
25012529 if templ_7745c5c3_Err != nil {
25022530 return templ_7745c5c3_Err
25032531 }
25042532 }
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- }
25222533 if p.Box.Error != "" {
25232534 templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 235, "<p class=\"d-err\" role=\"alert\">")
25242535 if templ_7745c5c3_Err != nil {
25252536 return templ_7745c5c3_Err
25262537 }
2527- var templ_7745c5c3_Var120 string
2528- templ_7745c5c3_Var120, templ_7745c5c3_Err = templ.JoinStringErrs(p.Box.Error)
2538+ var templ_7745c5c3_Var119 string
2539+ templ_7745c5c3_Var119, templ_7745c5c3_Err = templ.JoinStringErrs(p.Box.Error)
25292540 if templ_7745c5c3_Err != nil {
2530- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 490, Col: 47}
2541+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 497, Col: 47}
25312542 }
2532- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var120))
2543+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var119))
25332544 if templ_7745c5c3_Err != nil {
25342545 return templ_7745c5c3_Err
25352546 }
@@ -2543,12 +2554,12 @@ func mergeMenu(p MRPage) templ.Component {
25432554 if templ_7745c5c3_Err != nil {
25442555 return templ_7745c5c3_Err
25452556 }
2546- var templ_7745c5c3_Var121 templ.SafeURL
2547- templ_7745c5c3_Var121, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.ReadyAction))
2557+ var templ_7745c5c3_Var120 templ.SafeURL
2558+ templ_7745c5c3_Var120, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.ReadyAction))
25482559 if templ_7745c5c3_Err != nil {
2549- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 494, Col: 80}
2560+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 501, Col: 80}
25502561 }
2551- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var121))
2562+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var120))
25522563 if templ_7745c5c3_Err != nil {
25532564 return templ_7745c5c3_Err
25542565 }
@@ -2565,12 +2576,12 @@ func mergeMenu(p MRPage) templ.Component {
25652576 if templ_7745c5c3_Err != nil {
25662577 return templ_7745c5c3_Err
25672578 }
2568- var templ_7745c5c3_Var122 templ.SafeURL
2569- templ_7745c5c3_Var122, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.MergeAction))
2579+ var templ_7745c5c3_Var121 templ.SafeURL
2580+ templ_7745c5c3_Var121, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.MergeAction))
25702581 if templ_7745c5c3_Err != nil {
2571- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 499, Col: 80}
2582+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 506, Col: 80}
25722583 }
2573- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var122))
2584+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var121))
25742585 if templ_7745c5c3_Err != nil {
25752586 return templ_7745c5c3_Err
25762587 }
@@ -2578,12 +2589,12 @@ func mergeMenu(p MRPage) templ.Component {
25782589 if templ_7745c5c3_Err != nil {
25792590 return templ_7745c5c3_Err
25802591 }
2581- var templ_7745c5c3_Var123 string
2582- templ_7745c5c3_Var123, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.Head)
2592+ var templ_7745c5c3_Var122 string
2593+ templ_7745c5c3_Var122, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.Head)
25832594 if templ_7745c5c3_Err != nil {
2584- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 500, Col: 59}
2595+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 507, Col: 59}
25852596 }
2586- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var123)
2597+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var122)
25872598 if templ_7745c5c3_Err != nil {
25882599 return templ_7745c5c3_Err
25892600 }
@@ -2596,12 +2607,12 @@ func mergeMenu(p MRPage) templ.Component {
25962607 if templ_7745c5c3_Err != nil {
25972608 return templ_7745c5c3_Err
25982609 }
2599- var templ_7745c5c3_Var124 string
2600- templ_7745c5c3_Var124, templ_7745c5c3_Err = templ.ResolveAttributeValue(m.Value)
2610+ var templ_7745c5c3_Var123 string
2611+ templ_7745c5c3_Var123, templ_7745c5c3_Err = templ.ResolveAttributeValue(m.Value)
26012612 if templ_7745c5c3_Err != nil {
2602- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 508, Col: 24}
2613+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 515, Col: 24}
26032614 }
2604- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var124)
2615+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var123)
26052616 if templ_7745c5c3_Err != nil {
26062617 return templ_7745c5c3_Err
26072618 }
@@ -2625,12 +2636,12 @@ func mergeMenu(p MRPage) templ.Component {
26252636 if templ_7745c5c3_Err != nil {
26262637 return templ_7745c5c3_Err
26272638 }
2628- var templ_7745c5c3_Var125 string
2629- templ_7745c5c3_Var125, templ_7745c5c3_Err = templ.ResolveAttributeValue(m.Reason)
2639+ var templ_7745c5c3_Var124 string
2640+ templ_7745c5c3_Var124, templ_7745c5c3_Err = templ.ResolveAttributeValue(m.Reason)
26302641 if templ_7745c5c3_Err != nil {
2631- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 511, Col: 25}
2642+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 518, Col: 25}
26322643 }
2633- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var125)
2644+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var124)
26342645 if templ_7745c5c3_Err != nil {
26352646 return templ_7745c5c3_Err
26362647 }
@@ -2638,12 +2649,12 @@ func mergeMenu(p MRPage) templ.Component {
26382649 if templ_7745c5c3_Err != nil {
26392650 return templ_7745c5c3_Err
26402651 }
2641- var templ_7745c5c3_Var126 string
2642- templ_7745c5c3_Var126, templ_7745c5c3_Err = templ.JoinStringErrs(m.Label)
2652+ var templ_7745c5c3_Var125 string
2653+ templ_7745c5c3_Var125, templ_7745c5c3_Err = templ.JoinStringErrs(m.Label)
26432654 if templ_7745c5c3_Err != nil {
2644- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 515, Col: 17}
2655+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 522, Col: 17}
26452656 }
2646- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var126))
2657+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var125))
26472658 if templ_7745c5c3_Err != nil {
26482659 return templ_7745c5c3_Err
26492660 }
@@ -2656,12 +2667,12 @@ func mergeMenu(p MRPage) templ.Component {
26562667 if templ_7745c5c3_Err != nil {
26572668 return templ_7745c5c3_Err
26582669 }
2659- var templ_7745c5c3_Var127 string
2660- templ_7745c5c3_Var127, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(i + 1))
2670+ var templ_7745c5c3_Var126 string
2671+ templ_7745c5c3_Var126, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(i + 1))
26612672 if templ_7745c5c3_Err != nil {
2662- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 517, Col: 46}
2673+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 524, Col: 46}
26632674 }
2664- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var127))
2675+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var126))
26652676 if templ_7745c5c3_Err != nil {
26662677 return templ_7745c5c3_Err
26672678 }
@@ -2679,96 +2690,67 @@ func mergeMenu(p MRPage) templ.Component {
26792690 if templ_7745c5c3_Err != nil {
26802691 return templ_7745c5c3_Err
26812692 }
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- }
27112693 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 ")
2694+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 253, "<label class=\"d-check\"><input type=\"checkbox\" name=\"delete_branch\" value=\"1\"> delete ")
27132695 if templ_7745c5c3_Err != nil {
27142696 return templ_7745c5c3_Err
27152697 }
2716- var templ_7745c5c3_Var129 string
2717- templ_7745c5c3_Var129, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)
2698+ var templ_7745c5c3_Var127 string
2699+ templ_7745c5c3_Var127, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)
27182700 if templ_7745c5c3_Err != nil {
2719- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 532, Col: 102}
2701+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 530, Col: 102}
27202702 }
2721- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var129))
2703+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var127))
27222704 if templ_7745c5c3_Err != nil {
27232705 return templ_7745c5c3_Err
27242706 }
2725- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 258, " after the merge <kbd aria-hidden=\"true\">D</kbd></label>")
2707+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 254, " after the merge <kbd aria-hidden=\"true\">D</kbd></label>")
27262708 if templ_7745c5c3_Err != nil {
27272709 return templ_7745c5c3_Err
27282710 }
27292711 }
2730- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 259, "<div class=\"d-btns\"><button type=\"submit\" class=\"btn primary\" data-default")
2712+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 255, "<div class=\"d-btns\"><button type=\"submit\" class=\"btn primary\" data-default")
27312713 if templ_7745c5c3_Err != nil {
27322714 return templ_7745c5c3_Err
27332715 }
27342716 if !p.Box.CanMerge() {
2735- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 260, " disabled")
2717+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 256, " disabled")
27362718 if templ_7745c5c3_Err != nil {
27372719 return templ_7745c5c3_Err
27382720 }
27392721 }
2740- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 261, " title=\"")
2722+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 257, " title=\"")
27412723 if templ_7745c5c3_Err != nil {
27422724 return templ_7745c5c3_Err
27432725 }
2744- var templ_7745c5c3_Var130 string
2745- templ_7745c5c3_Var130, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.MergeTitle())
2726+ var templ_7745c5c3_Var128 string
2727+ templ_7745c5c3_Var128, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.MergeTitle())
27462728 if templ_7745c5c3_Err != nil {
2747- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 540, Col: 33}
2729+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 538, Col: 33}
27482730 }
2749- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var130)
2731+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var128)
27502732 if templ_7745c5c3_Err != nil {
27512733 return templ_7745c5c3_Err
27522734 }
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 ")
2735+ 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 ")
27542736 if templ_7745c5c3_Err != nil {
27552737 return templ_7745c5c3_Err
27562738 }
2757- var templ_7745c5c3_Var131 string
2758- templ_7745c5c3_Var131, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
2739+ var templ_7745c5c3_Var129 string
2740+ templ_7745c5c3_Var129, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
27592741 if templ_7745c5c3_Err != nil {
2760- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 543, Col: 28}
2742+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 541, Col: 28}
27612743 }
2762- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var131))
2744+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var129))
27632745 if templ_7745c5c3_Err != nil {
27642746 return templ_7745c5c3_Err
27652747 }
2766- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 263, "</button></div></form>")
2748+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 259, "</button></div></form>")
27672749 if templ_7745c5c3_Err != nil {
27682750 return templ_7745c5c3_Err
27692751 }
27702752 }
2771- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 264, "</div></details>")
2753+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 260, "</div></details>")
27722754 if templ_7745c5c3_Err != nil {
27732755 return templ_7745c5c3_Err
27742756 }
@@ -2794,182 +2776,182 @@ func MRMergeability(v MergeabilityView) templ.Component {
27942776 }()
27952777 }
27962778 ctx = templ.InitializeContext(ctx)
2797- templ_7745c5c3_Var132 := templ.GetChildren(ctx)
2798- if templ_7745c5c3_Var132 == nil {
2799- templ_7745c5c3_Var132 = templ.NopComponent
2779+ templ_7745c5c3_Var130 := templ.GetChildren(ctx)
2780+ if templ_7745c5c3_Var130 == nil {
2781+ templ_7745c5c3_Var130 = templ.NopComponent
28002782 }
28012783 ctx = templ.ClearChildren(ctx)
2802- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 265, "<span data-mergeability data-state=\"")
2784+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 261, "<span data-mergeability data-state=\"")
28032785 if templ_7745c5c3_Err != nil {
28042786 return templ_7745c5c3_Err
28052787 }
2806- var templ_7745c5c3_Var133 string
2807- templ_7745c5c3_Var133, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.State)
2788+ var templ_7745c5c3_Var131 string
2789+ templ_7745c5c3_Var131, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.State)
28082790 if templ_7745c5c3_Err != nil {
2809- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 556, Col: 22}
2791+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 554, Col: 22}
28102792 }
2811- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var133)
2793+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var131)
28122794 if templ_7745c5c3_Err != nil {
28132795 return templ_7745c5c3_Err
28142796 }
2815- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 266, "\" data-ff-ok=\"")
2797+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 262, "\" data-ff-ok=\"")
28162798 if templ_7745c5c3_Err != nil {
28172799 return templ_7745c5c3_Err
28182800 }
2819- var templ_7745c5c3_Var134 string
2820- templ_7745c5c3_Var134, templ_7745c5c3_Err = templ.ResolveAttributeValue(strconv.FormatBool(v.FFOk))
2801+ var templ_7745c5c3_Var132 string
2802+ templ_7745c5c3_Var132, templ_7745c5c3_Err = templ.ResolveAttributeValue(strconv.FormatBool(v.FFOk))
28212803 if templ_7745c5c3_Err != nil {
2822- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 557, Col: 41}
2804+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 555, Col: 41}
28232805 }
2824- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var134)
2806+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var132)
28252807 if templ_7745c5c3_Err != nil {
28262808 return templ_7745c5c3_Err
28272809 }
2828- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 267, "\" data-merge-ok=\"")
2810+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 263, "\" data-merge-ok=\"")
28292811 if templ_7745c5c3_Err != nil {
28302812 return templ_7745c5c3_Err
28312813 }
2832- var templ_7745c5c3_Var135 string
2833- templ_7745c5c3_Var135, templ_7745c5c3_Err = templ.ResolveAttributeValue(strconv.FormatBool(v.MergeOk))
2814+ var templ_7745c5c3_Var133 string
2815+ templ_7745c5c3_Var133, templ_7745c5c3_Err = templ.ResolveAttributeValue(strconv.FormatBool(v.MergeOk))
28342816 if templ_7745c5c3_Err != nil {
2835- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 558, Col: 47}
2817+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 556, Col: 47}
28362818 }
2837- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var135)
2819+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var133)
28382820 if templ_7745c5c3_Err != nil {
28392821 return templ_7745c5c3_Err
28402822 }
2841- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 268, "\" data-ff-reason=\"")
2823+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 264, "\" data-ff-reason=\"")
28422824 if templ_7745c5c3_Err != nil {
28432825 return templ_7745c5c3_Err
28442826 }
2845- var templ_7745c5c3_Var136 string
2846- templ_7745c5c3_Var136, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.FFReason)
2827+ var templ_7745c5c3_Var134 string
2828+ templ_7745c5c3_Var134, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.FFReason)
28472829 if templ_7745c5c3_Err != nil {
2848- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 559, Col: 29}
2830+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 557, Col: 29}
28492831 }
2850- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var136)
2832+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var134)
28512833 if templ_7745c5c3_Err != nil {
28522834 return templ_7745c5c3_Err
28532835 }
2854- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 269, "\" data-merge-reason=\"")
2836+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 265, "\" data-merge-reason=\"")
28552837 if templ_7745c5c3_Err != nil {
28562838 return templ_7745c5c3_Err
28572839 }
2858- var templ_7745c5c3_Var137 string
2859- templ_7745c5c3_Var137, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.MergeReason)
2840+ var templ_7745c5c3_Var135 string
2841+ templ_7745c5c3_Var135, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.MergeReason)
28602842 if templ_7745c5c3_Err != nil {
2861- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 560, Col: 35}
2843+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 558, Col: 35}
28622844 }
2863- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var137)
2845+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var135)
28642846 if templ_7745c5c3_Err != nil {
28652847 return templ_7745c5c3_Err
28662848 }
2867- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 270, "\"><span class=\"badge\" data-state=\"")
2849+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 266, "\"><span class=\"badge\" data-state=\"")
28682850 if templ_7745c5c3_Err != nil {
28692851 return templ_7745c5c3_Err
28702852 }
2871- var templ_7745c5c3_Var138 string
2872- templ_7745c5c3_Var138, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.State)
2853+ var templ_7745c5c3_Var136 string
2854+ templ_7745c5c3_Var136, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.State)
28732855 if templ_7745c5c3_Err != nil {
2874- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 562, Col: 42}
2856+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 560, Col: 42}
28752857 }
2876- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var138)
2858+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var136)
28772859 if templ_7745c5c3_Err != nil {
28782860 return templ_7745c5c3_Err
28792861 }
2880- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 271, "\">")
2862+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 267, "\">")
28812863 if templ_7745c5c3_Err != nil {
28822864 return templ_7745c5c3_Err
28832865 }
2884- var templ_7745c5c3_Var139 string
2885- templ_7745c5c3_Var139, templ_7745c5c3_Err = templ.JoinStringErrs(v.Label)
2866+ var templ_7745c5c3_Var137 string
2867+ templ_7745c5c3_Var137, templ_7745c5c3_Err = templ.JoinStringErrs(v.Label)
28862868 if templ_7745c5c3_Err != nil {
2887- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 562, Col: 54}
2869+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 560, Col: 54}
28882870 }
2889- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var139))
2871+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var137))
28902872 if templ_7745c5c3_Err != nil {
28912873 return templ_7745c5c3_Err
28922874 }
2893- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 272, "</span> ")
2875+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 268, "</span> ")
28942876 if templ_7745c5c3_Err != nil {
28952877 return templ_7745c5c3_Err
28962878 }
28972879 if v.Detail != "" {
2898- var templ_7745c5c3_Var140 string
2899- templ_7745c5c3_Var140, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
2880+ var templ_7745c5c3_Var138 string
2881+ templ_7745c5c3_Var138, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
29002882 if templ_7745c5c3_Err != nil {
2901- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 564, Col: 8}
2883+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 562, Col: 8}
29022884 }
2903- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var140))
2885+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var138))
29042886 if templ_7745c5c3_Err != nil {
29052887 return templ_7745c5c3_Err
29062888 }
2907- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 273, "<span class=\"dim\">")
2889+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 269, "<span class=\"dim\">")
29082890 if templ_7745c5c3_Err != nil {
29092891 return templ_7745c5c3_Err
29102892 }
2911- var templ_7745c5c3_Var141 string
2912- templ_7745c5c3_Var141, templ_7745c5c3_Err = templ.JoinStringErrs(v.Detail)
2893+ var templ_7745c5c3_Var139 string
2894+ templ_7745c5c3_Var139, templ_7745c5c3_Err = templ.JoinStringErrs(v.Detail)
29132895 if templ_7745c5c3_Err != nil {
2914- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 564, Col: 38}
2896+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 562, Col: 38}
29152897 }
2916- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var141))
2898+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var139))
29172899 if templ_7745c5c3_Err != nil {
29182900 return templ_7745c5c3_Err
29192901 }
2920- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 274, "</span>")
2902+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 270, "</span>")
29212903 if templ_7745c5c3_Err != nil {
29222904 return templ_7745c5c3_Err
29232905 }
29242906 }
2925- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 275, "</span> ")
2907+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 271, "</span> ")
29262908 if templ_7745c5c3_Err != nil {
29272909 return templ_7745c5c3_Err
29282910 }
29292911 if len(v.Paths) > 0 {
2930- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 276, "<ul class=\"mg-paths\" aria-label=\"conflicting files\">")
2912+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 272, "<ul class=\"mg-paths\" aria-label=\"conflicting files\">")
29312913 if templ_7745c5c3_Err != nil {
29322914 return templ_7745c5c3_Err
29332915 }
29342916 for _, path := range v.Paths {
2935- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 277, "<li><code>")
2917+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 273, "<li><code>")
29362918 if templ_7745c5c3_Err != nil {
29372919 return templ_7745c5c3_Err
29382920 }
2939- var templ_7745c5c3_Var142 string
2940- templ_7745c5c3_Var142, templ_7745c5c3_Err = templ.JoinStringErrs(path)
2921+ var templ_7745c5c3_Var140 string
2922+ templ_7745c5c3_Var140, templ_7745c5c3_Err = templ.JoinStringErrs(path)
29412923 if templ_7745c5c3_Err != nil {
2942- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 570, Col: 20}
2924+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 568, Col: 20}
29432925 }
2944- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var142))
2926+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var140))
29452927 if templ_7745c5c3_Err != nil {
29462928 return templ_7745c5c3_Err
29472929 }
2948- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 278, "</code></li>")
2930+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 274, "</code></li>")
29492931 if templ_7745c5c3_Err != nil {
29502932 return templ_7745c5c3_Err
29512933 }
29522934 }
2953- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 279, "</ul>")
2935+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 275, "</ul>")
29542936 if templ_7745c5c3_Err != nil {
29552937 return templ_7745c5c3_Err
29562938 }
29572939 }
29582940 if v.PathsNote != "" {
2959- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 280, "<p class=\"dim\">")
2941+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 276, "<p class=\"dim\">")
29602942 if templ_7745c5c3_Err != nil {
29612943 return templ_7745c5c3_Err
29622944 }
2963- var templ_7745c5c3_Var143 string
2964- templ_7745c5c3_Var143, templ_7745c5c3_Err = templ.JoinStringErrs(v.PathsNote)
2945+ var templ_7745c5c3_Var141 string
2946+ templ_7745c5c3_Var141, templ_7745c5c3_Err = templ.JoinStringErrs(v.PathsNote)
29652947 if templ_7745c5c3_Err != nil {
2966- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 575, Col: 30}
2948+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 573, Col: 30}
29672949 }
2968- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var143))
2950+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var141))
29692951 if templ_7745c5c3_Err != nil {
29702952 return templ_7745c5c3_Err
29712953 }
2972- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 281, "</p>")
2954+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 277, "</p>")
29732955 if templ_7745c5c3_Err != nil {
29742956 return templ_7745c5c3_Err
29752957 }
@@ -2996,12 +2978,12 @@ func mrMergeabilitySlot(v MergeabilityView) templ.Component {
29962978 }()
29972979 }
29982980 ctx = templ.InitializeContext(ctx)
2999- templ_7745c5c3_Var144 := templ.GetChildren(ctx)
3000- if templ_7745c5c3_Var144 == nil {
3001- templ_7745c5c3_Var144 = templ.NopComponent
2981+ templ_7745c5c3_Var142 := templ.GetChildren(ctx)
2982+ if templ_7745c5c3_Var142 == nil {
2983+ templ_7745c5c3_Var142 = templ.NopComponent
30022984 }
30032985 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>")
2986+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 278, "<div id=\"mr-mergeability\" class=\"live-slot\" role=\"status\" data-slot>")
30052987 if templ_7745c5c3_Err != nil {
30062988 return templ_7745c5c3_Err
30072989 }
@@ -3009,7 +2991,7 @@ func mrMergeabilitySlot(v MergeabilityView) templ.Component {
30092991 if templ_7745c5c3_Err != nil {
30102992 return templ_7745c5c3_Err
30112993 }
3012- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 283, "</div>")
2994+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 279, "</div>")
30132995 if templ_7745c5c3_Err != nil {
30142996 return templ_7745c5c3_Err
30152997 }
@@ -3034,9 +3016,9 @@ func MRMergeabilityFragment(v MergeabilityView) templ.Component {
30343016 }()
30353017 }
30363018 ctx = templ.InitializeContext(ctx)
3037- templ_7745c5c3_Var145 := templ.GetChildren(ctx)
3038- if templ_7745c5c3_Var145 == nil {
3039- templ_7745c5c3_Var145 = templ.NopComponent
3019+ templ_7745c5c3_Var143 := templ.GetChildren(ctx)
3020+ if templ_7745c5c3_Var143 == nil {
3021+ templ_7745c5c3_Var143 = templ.NopComponent
30403022 }
30413023 ctx = templ.ClearChildren(ctx)
30423024 templ_7745c5c3_Err = mrMergeabilitySlot(v).Render(ctx, templ_7745c5c3_Buffer)
@@ -3047,8 +3029,8 @@ func MRMergeabilityFragment(v MergeabilityView) templ.Component {
30473029 })
30483030 }
30493031
3050-// moreMenu is what else the owner does with an open request: mark the head
3051-// read, close it, merge it from a terminal.
3032+// moreMenu shows read-only settings to every viewer, and keeps owner actions
3033+// behind the same merge-box permission as before.
30523034 func moreMenu(p MRPage) templ.Component {
30533035 return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
30543036 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@@ -3065,79 +3047,142 @@ func moreMenu(p MRPage) templ.Component {
30653047 }()
30663048 }
30673049 ctx = templ.InitializeContext(ctx)
3068- templ_7745c5c3_Var146 := templ.GetChildren(ctx)
3069- if templ_7745c5c3_Var146 == nil {
3070- templ_7745c5c3_Var146 = templ.NopComponent
3050+ templ_7745c5c3_Var144 := templ.GetChildren(ctx)
3051+ if templ_7745c5c3_Var144 == nil {
3052+ templ_7745c5c3_Var144 = templ.NopComponent
30713053 }
30723054 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\">")
3055+ 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>")
30743056 if templ_7745c5c3_Err != nil {
30753057 return templ_7745c5c3_Err
30763058 }
3077- if p.Box.CanMarkRead {
3078- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 285, "<form method=\"post\" action=\"")
3059+ var templ_7745c5c3_Var145 string
3060+ templ_7745c5c3_Var145, templ_7745c5c3_Err = templ.JoinStringErrs(strings.Join(p.Modes, ", "))
3061+ if templ_7745c5c3_Err != nil {
3062+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 600, Col: 38}
3063+ }
3064+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var145))
3065+ if templ_7745c5c3_Err != nil {
3066+ return templ_7745c5c3_Err
3067+ }
3068+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 281, "</dd><dt>checks</dt><dd>")
3069+ if templ_7745c5c3_Err != nil {
3070+ return templ_7745c5c3_Err
3071+ }
3072+ if p.ChecksBlock {
3073+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 282, "failing ones block the merge")
30793074 if templ_7745c5c3_Err != nil {
30803075 return templ_7745c5c3_Err
30813076 }
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))
3077+ } else {
3078+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 283, "do not block the merge")
30883079 if templ_7745c5c3_Err != nil {
30893080 return templ_7745c5c3_Err
30903081 }
3091- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 286, "\"><input type=\"hidden\" name=\"head_id\" value=\"")
3082+ }
3083+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 284, "</dd></dl></section>")
3084+ if templ_7745c5c3_Err != nil {
3085+ return templ_7745c5c3_Err
3086+ }
3087+ if p.Box != nil {
3088+ if p.Box.Signed {
3089+ 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). ")
3090+ if templ_7745c5c3_Err != nil {
3091+ return templ_7745c5c3_Err
3092+ }
3093+ if p.Box.Fingerprint != "" {
3094+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 286, "fingerprint <code>")
3095+ if templ_7745c5c3_Err != nil {
3096+ return templ_7745c5c3_Err
3097+ }
3098+ var templ_7745c5c3_Var146 string
3099+ templ_7745c5c3_Var146, templ_7745c5c3_Err = templ.JoinStringErrs(p.Box.Fingerprint)
3100+ if templ_7745c5c3_Err != nil {
3101+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 616, Col: 44}
3102+ }
3103+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var146))
3104+ if templ_7745c5c3_Err != nil {
3105+ return templ_7745c5c3_Err
3106+ }
3107+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 287, "</code> ")
3108+ if templ_7745c5c3_Err != nil {
3109+ return templ_7745c5c3_Err
3110+ }
3111+ }
3112+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 288, "<code>ermite signing-key show</code> prints it.</p>")
3113+ if templ_7745c5c3_Err != nil {
3114+ return templ_7745c5c3_Err
3115+ }
3116+ }
3117+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 289, " ")
30923118 if templ_7745c5c3_Err != nil {
30933119 return templ_7745c5c3_Err
30943120 }
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}
3121+ if p.Box.CanMarkRead {
3122+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 290, "<form method=\"post\" action=\"")
3123+ if templ_7745c5c3_Err != nil {
3124+ return templ_7745c5c3_Err
3125+ }
3126+ var templ_7745c5c3_Var147 templ.SafeURL
3127+ templ_7745c5c3_Var147, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.ReadAction))
3128+ if templ_7745c5c3_Err != nil {
3129+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 622, Col: 65}
3130+ }
3131+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var147))
3132+ if templ_7745c5c3_Err != nil {
3133+ return templ_7745c5c3_Err
3134+ }
3135+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 291, "\"><input type=\"hidden\" name=\"head_id\" value=\"")
3136+ if templ_7745c5c3_Err != nil {
3137+ return templ_7745c5c3_Err
3138+ }
3139+ var templ_7745c5c3_Var148 string
3140+ templ_7745c5c3_Var148, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.Head)
3141+ if templ_7745c5c3_Err != nil {
3142+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 623, Col: 60}
3143+ }
3144+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var148)
3145+ if templ_7745c5c3_Err != nil {
3146+ return templ_7745c5c3_Err
3147+ }
3148+ 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>")
3149+ if templ_7745c5c3_Err != nil {
3150+ return templ_7745c5c3_Err
3151+ }
30993152 }
3100- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var148)
3153+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 293, " <form method=\"post\" action=\"")
31013154 if templ_7745c5c3_Err != nil {
31023155 return templ_7745c5c3_Err
31033156 }
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>")
3157+ var templ_7745c5c3_Var149 templ.SafeURL
3158+ templ_7745c5c3_Var149, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.CloseAction))
31053159 if templ_7745c5c3_Err != nil {
3106- return templ_7745c5c3_Err
3160+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 627, Col: 65}
31073161 }
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>")
3162+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var149))
31283163 if templ_7745c5c3_Err != nil {
31293164 return templ_7745c5c3_Err
31303165 }
3131- templ_7745c5c3_Err = CloneBlock(p.Box.CLI).Render(ctx, templ_7745c5c3_Buffer)
3166+ 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>")
31323167 if templ_7745c5c3_Err != nil {
31333168 return templ_7745c5c3_Err
31343169 }
3135- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 291, "</details>")
3136- if templ_7745c5c3_Err != nil {
3137- return templ_7745c5c3_Err
3170+ if !p.Box.HeadGone && p.Box.ReadyAction == "" {
3171+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 295, "<details class=\"d-or\"><summary class=\"mute\">or from a terminal</summary>")
3172+ if templ_7745c5c3_Err != nil {
3173+ return templ_7745c5c3_Err
3174+ }
3175+ templ_7745c5c3_Err = CloneBlock(p.Box.CLI).Render(ctx, templ_7745c5c3_Buffer)
3176+ if templ_7745c5c3_Err != nil {
3177+ return templ_7745c5c3_Err
3178+ }
3179+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 296, "</details>")
3180+ if templ_7745c5c3_Err != nil {
3181+ return templ_7745c5c3_Err
3182+ }
31383183 }
31393184 }
3140- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 292, "</div></details>")
3185+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 297, "</div></details>")
31413186 if templ_7745c5c3_Err != nil {
31423187 return templ_7745c5c3_Err
31433188 }
@@ -3178,263 +3223,263 @@ func Compare(l Layout, p ComparePage) templ.Component {
31783223 }()
31793224 }
31803225 ctx = templ.InitializeContext(ctx)
3181- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 293, "<header class=\"show mr-h\"><h1>")
3226+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 298, "<header class=\"show mr-h\"><h1>")
31823227 if templ_7745c5c3_Err != nil {
31833228 return templ_7745c5c3_Err
31843229 }
31853230 var templ_7745c5c3_Var152 string
31863231 templ_7745c5c3_Var152, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)
31873232 if templ_7745c5c3_Err != nil {
3188- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 620, Col: 17}
3233+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 644, Col: 17}
31893234 }
31903235 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var152))
31913236 if templ_7745c5c3_Err != nil {
31923237 return templ_7745c5c3_Err
31933238 }
3194- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 294, " → ")
3239+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 299, " → ")
31953240 if templ_7745c5c3_Err != nil {
31963241 return templ_7745c5c3_Err
31973242 }
31983243 var templ_7745c5c3_Var153 string
31993244 templ_7745c5c3_Var153, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
32003245 if templ_7745c5c3_Err != nil {
3201- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 620, Col: 34}
3246+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 644, Col: 34}
32023247 }
32033248 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var153))
32043249 if templ_7745c5c3_Err != nil {
32053250 return templ_7745c5c3_Err
32063251 }
3207- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 295, "</h1><dl class=\"kv show-kv\"><dt>branch</dt><dd><a href=\"")
3252+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 300, "</h1><dl class=\"kv show-kv\"><dt>branch</dt><dd><a href=\"")
32083253 if templ_7745c5c3_Err != nil {
32093254 return templ_7745c5c3_Err
32103255 }
32113256 var templ_7745c5c3_Var154 templ.SafeURL
32123257 templ_7745c5c3_Var154, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.SourceHref))
32133258 if templ_7745c5c3_Err != nil {
3214- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 623, Col: 45}
3259+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 647, Col: 45}
32153260 }
32163261 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var154))
32173262 if templ_7745c5c3_Err != nil {
32183263 return templ_7745c5c3_Err
32193264 }
3220- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 296, "\">")
3265+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 301, "\">")
32213266 if templ_7745c5c3_Err != nil {
32223267 return templ_7745c5c3_Err
32233268 }
32243269 var templ_7745c5c3_Var155 string
32253270 templ_7745c5c3_Var155, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)
32263271 if templ_7745c5c3_Err != nil {
3227- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 623, Col: 58}
3272+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 647, Col: 58}
32283273 }
32293274 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var155))
32303275 if templ_7745c5c3_Err != nil {
32313276 return templ_7745c5c3_Err
32323277 }
3233- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 297, "</a></dd><dt>target</dt><dd><a href=\"")
3278+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 302, "</a></dd><dt>target</dt><dd><a href=\"")
32343279 if templ_7745c5c3_Err != nil {
32353280 return templ_7745c5c3_Err
32363281 }
32373282 var templ_7745c5c3_Var156 templ.SafeURL
32383283 templ_7745c5c3_Var156, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.TargetHref))
32393284 if templ_7745c5c3_Err != nil {
3240- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 625, Col: 45}
3285+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 649, Col: 45}
32413286 }
32423287 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var156))
32433288 if templ_7745c5c3_Err != nil {
32443289 return templ_7745c5c3_Err
32453290 }
3246- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 298, "\">")
3291+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 303, "\">")
32473292 if templ_7745c5c3_Err != nil {
32483293 return templ_7745c5c3_Err
32493294 }
32503295 var templ_7745c5c3_Var157 string
32513296 templ_7745c5c3_Var157, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
32523297 if templ_7745c5c3_Err != nil {
3253- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 625, Col: 58}
3298+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 649, Col: 58}
32543299 }
32553300 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var157))
32563301 if templ_7745c5c3_Err != nil {
32573302 return templ_7745c5c3_Err
32583303 }
3259- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 299, "</a></dd><dt>ahead</dt><dd>")
3304+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 304, "</a></dd><dt>ahead</dt><dd>")
32603305 if templ_7745c5c3_Err != nil {
32613306 return templ_7745c5c3_Err
32623307 }
32633308 var templ_7745c5c3_Var158 string
32643309 templ_7745c5c3_Var158, templ_7745c5c3_Err = templ.JoinStringErrs(p.AheadText)
32653310 if templ_7745c5c3_Err != nil {
3266- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 627, Col: 21}
3311+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 651, Col: 21}
32673312 }
32683313 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var158))
32693314 if templ_7745c5c3_Err != nil {
32703315 return templ_7745c5c3_Err
32713316 }
3272- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 300, "</dd></dl></header>")
3317+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 305, "</dd></dl></header>")
32733318 if templ_7745c5c3_Err != nil {
32743319 return templ_7745c5c3_Err
32753320 }
32763321 if p.Note != "" {
3277- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 301, "<p class=\"notice\">")
3322+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 306, "<p class=\"notice\">")
32783323 if templ_7745c5c3_Err != nil {
32793324 return templ_7745c5c3_Err
32803325 }
32813326 var templ_7745c5c3_Var159 string
32823327 templ_7745c5c3_Var159, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note)
32833328 if templ_7745c5c3_Err != nil {
3284- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 631, Col: 29}
3329+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 655, Col: 29}
32853330 }
32863331 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var159))
32873332 if templ_7745c5c3_Err != nil {
32883333 return templ_7745c5c3_Err
32893334 }
3290- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 302, "</p>")
3335+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 307, "</p>")
32913336 if templ_7745c5c3_Err != nil {
32923337 return templ_7745c5c3_Err
32933338 }
32943339 }
3295- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 303, " ")
3340+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 308, " ")
32963341 if templ_7745c5c3_Err != nil {
32973342 return templ_7745c5c3_Err
32983343 }
32993344 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=\"")
3345+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 309, "<p class=\"notice\">an open merge request already covers these branches: <a href=\"")
33013346 if templ_7745c5c3_Err != nil {
33023347 return templ_7745c5c3_Err
33033348 }
33043349 var templ_7745c5c3_Var160 templ.SafeURL
33053350 templ_7745c5c3_Var160, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Existing.Href))
33063351 if templ_7745c5c3_Err != nil {
3307- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 634, Col: 114}
3352+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 658, Col: 114}
33083353 }
33093354 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var160))
33103355 if templ_7745c5c3_Err != nil {
33113356 return templ_7745c5c3_Err
33123357 }
3313- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 305, "\">")
3358+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 310, "\">")
33143359 if templ_7745c5c3_Err != nil {
33153360 return templ_7745c5c3_Err
33163361 }
33173362 var templ_7745c5c3_Var161 string
33183363 templ_7745c5c3_Var161, templ_7745c5c3_Err = templ.JoinStringErrs(p.Existing.Label)
33193364 if templ_7745c5c3_Err != nil {
3320- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 634, Col: 135}
3365+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 658, Col: 135}
33213366 }
33223367 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var161))
33233368 if templ_7745c5c3_Err != nil {
33243369 return templ_7745c5c3_Err
33253370 }
3326- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 306, "</a></p>")
3371+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 311, "</a></p>")
33273372 if templ_7745c5c3_Err != nil {
33283373 return templ_7745c5c3_Err
33293374 }
33303375 }
3331- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 307, " ")
3376+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 312, " ")
33323377 if templ_7745c5c3_Err != nil {
33333378 return templ_7745c5c3_Err
33343379 }
33353380 if p.Create != nil {
3336- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 308, "<form class=\"cform create\" method=\"post\" action=\"")
3381+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 313, "<form class=\"cform create\" method=\"post\" action=\"")
33373382 if templ_7745c5c3_Err != nil {
33383383 return templ_7745c5c3_Err
33393384 }
33403385 var templ_7745c5c3_Var162 templ.SafeURL
33413386 templ_7745c5c3_Var162, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Create.Action))
33423387 if templ_7745c5c3_Err != nil {
3343- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 637, Col: 83}
3388+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 661, Col: 83}
33443389 }
33453390 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var162))
33463391 if templ_7745c5c3_Err != nil {
33473392 return templ_7745c5c3_Err
33483393 }
3349- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 309, "\"><input type=\"hidden\" name=\"source\" value=\"")
3394+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 314, "\"><input type=\"hidden\" name=\"source\" value=\"")
33503395 if templ_7745c5c3_Err != nil {
33513396 return templ_7745c5c3_Err
33523397 }
33533398 var templ_7745c5c3_Var163 string
33543399 templ_7745c5c3_Var163, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Source)
33553400 if templ_7745c5c3_Err != nil {
3356- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 638, Col: 62}
3401+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 662, Col: 62}
33573402 }
33583403 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var163)
33593404 if templ_7745c5c3_Err != nil {
33603405 return templ_7745c5c3_Err
33613406 }
3362- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 310, "\"> <input type=\"hidden\" name=\"target\" value=\"")
3407+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 315, "\"> <input type=\"hidden\" name=\"target\" value=\"")
33633408 if templ_7745c5c3_Err != nil {
33643409 return templ_7745c5c3_Err
33653410 }
33663411 var templ_7745c5c3_Var164 string
33673412 templ_7745c5c3_Var164, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Target)
33683413 if templ_7745c5c3_Err != nil {
3369- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 639, Col: 62}
3414+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 663, Col: 62}
33703415 }
33713416 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var164)
33723417 if templ_7745c5c3_Err != nil {
33733418 return templ_7745c5c3_Err
33743419 }
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=\"")
3420+ 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=\"")
33763421 if templ_7745c5c3_Err != nil {
33773422 return templ_7745c5c3_Err
33783423 }
33793424 var templ_7745c5c3_Var165 string
33803425 templ_7745c5c3_Var165, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Title)
33813426 if templ_7745c5c3_Err != nil {
3382- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 641, Col: 97}
3427+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 665, Col: 97}
33833428 }
33843429 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var165)
33853430 if templ_7745c5c3_Err != nil {
33863431 return templ_7745c5c3_Err
33873432 }
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>")
3433+ 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>")
33893434 if templ_7745c5c3_Err != nil {
33903435 return templ_7745c5c3_Err
33913436 }
33923437 }
3393- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 313, " ")
3438+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 318, " ")
33943439 if templ_7745c5c3_Err != nil {
33953440 return templ_7745c5c3_Err
33963441 }
33973442 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\">")
3443+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 319, "<div class=\"diff-tools\" role=\"group\" aria-label=\"Diff view\"><span class=\"dim\">")
33993444 if templ_7745c5c3_Err != nil {
34003445 return templ_7745c5c3_Err
34013446 }
34023447 var templ_7745c5c3_Var166 string
34033448 templ_7745c5c3_Var166, templ_7745c5c3_Err = templ.JoinStringErrs(plural(p.NFiles, "file", "files"))
34043449 if templ_7745c5c3_Err != nil {
3405- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 651, Col: 57}
3450+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 675, Col: 57}
34063451 }
34073452 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var166))
34083453 if templ_7745c5c3_Err != nil {
34093454 return templ_7745c5c3_Err
34103455 }
3411- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 315, " · <span class=\"plus\">+")
3456+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 320, " · <span class=\"plus\">+")
34123457 if templ_7745c5c3_Err != nil {
34133458 return templ_7745c5c3_Err
34143459 }
34153460 var templ_7745c5c3_Var167 string
34163461 templ_7745c5c3_Var167, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Adds))
34173462 if templ_7745c5c3_Err != nil {
3418- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 651, Col: 97}
3463+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 675, Col: 97}
34193464 }
34203465 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var167))
34213466 if templ_7745c5c3_Err != nil {
34223467 return templ_7745c5c3_Err
34233468 }
3424- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 316, "</span> <span class=\"minus\">-")
3469+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 321, "</span> <span class=\"minus\">-")
34253470 if templ_7745c5c3_Err != nil {
34263471 return templ_7745c5c3_Err
34273472 }
34283473 var templ_7745c5c3_Var168 string
34293474 templ_7745c5c3_Var168, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Dels))
34303475 if templ_7745c5c3_Err != nil {
3431- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 651, Col: 142}
3476+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 675, Col: 142}
34323477 }
34333478 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var168))
34343479 if templ_7745c5c3_Err != nil {
34353480 return templ_7745c5c3_Err
34363481 }
3437- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 317, "</span></span> <span class=\"grow\"></span>")
3482+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 322, "</span></span> <span class=\"grow\"></span>")
34383483 if templ_7745c5c3_Err != nil {
34393484 return templ_7745c5c3_Err
34403485 }
@@ -3442,64 +3487,64 @@ func Compare(l Layout, p ComparePage) templ.Component {
34423487 if templ_7745c5c3_Err != nil {
34433488 return templ_7745c5c3_Err
34443489 }
3445- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 318, "</div>")
3490+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 323, "</div>")
34463491 if templ_7745c5c3_Err != nil {
34473492 return templ_7745c5c3_Err
34483493 }
34493494 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>")
3495+ 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>")
34513496 if templ_7745c5c3_Err != nil {
34523497 return templ_7745c5c3_Err
34533498 }
34543499 }
3455- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 320, " <div id=\"diffs\"")
3500+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 325, " <div id=\"diffs\"")
34563501 if templ_7745c5c3_Err != nil {
34573502 return templ_7745c5c3_Err
34583503 }
34593504 if p.Both {
3460- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 321, " data-diff=\"")
3505+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 326, " data-diff=\"")
34613506 if templ_7745c5c3_Err != nil {
34623507 return templ_7745c5c3_Err
34633508 }
34643509 var templ_7745c5c3_Var169 string
34653510 templ_7745c5c3_Var169, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
34663511 if templ_7745c5c3_Err != nil {
3467- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 664, Col: 23}
3512+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 688, Col: 23}
34683513 }
34693514 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var169)
34703515 if templ_7745c5c3_Err != nil {
34713516 return templ_7745c5c3_Err
34723517 }
3473- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 322, "\"")
3518+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 327, "\"")
34743519 if templ_7745c5c3_Err != nil {
34753520 return templ_7745c5c3_Err
34763521 }
34773522 } else {
3478- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 323, " data-view=\"")
3523+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 328, " data-view=\"")
34793524 if templ_7745c5c3_Err != nil {
34803525 return templ_7745c5c3_Err
34813526 }
34823527 var templ_7745c5c3_Var170 string
34833528 templ_7745c5c3_Var170, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
34843529 if templ_7745c5c3_Err != nil {
3485- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 666, Col: 23}
3530+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 690, Col: 23}
34863531 }
34873532 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var170)
34883533 if templ_7745c5c3_Err != nil {
34893534 return templ_7745c5c3_Err
34903535 }
3491- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 324, "\"")
3536+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 329, "\"")
34923537 if templ_7745c5c3_Err != nil {
34933538 return templ_7745c5c3_Err
34943539 }
34953540 }
34963541 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\"")
3542+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 330, " hx-live=\"this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff\"")
34983543 if templ_7745c5c3_Err != nil {
34993544 return templ_7745c5c3_Err
35003545 }
35013546 }
3502- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 326, ">")
3547+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 331, ">")
35033548 if templ_7745c5c3_Err != nil {
35043549 return templ_7745c5c3_Err
35053550 }
@@ -3509,7 +3554,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
35093554 return templ_7745c5c3_Err
35103555 }
35113556 }
3512- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 327, "</div>")
3557+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 332, "</div>")
35133558 if templ_7745c5c3_Err != nil {
35143559 return templ_7745c5c3_Err
35153560 }
@@ -3545,77 +3590,77 @@ func compareRail(p ComparePage) templ.Component {
35453590 templ_7745c5c3_Var171 = templ.NopComponent
35463591 }
35473592 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\">")
3593+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 333, "<section aria-labelledby=\"r-ahead\"><h2 id=\"r-ahead\">Commits <span class=\"count\">")
35493594 if templ_7745c5c3_Err != nil {
35503595 return templ_7745c5c3_Err
35513596 }
35523597 var templ_7745c5c3_Var172 string
35533598 templ_7745c5c3_Var172, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Ahead)))
35543599 if templ_7745c5c3_Err != nil {
3555- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 682, Col: 67}
3600+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 706, Col: 67}
35563601 }
35573602 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var172))
35583603 if templ_7745c5c3_Err != nil {
35593604 return templ_7745c5c3_Err
35603605 }
3561- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 329, "</span></h2><ul class=\"pcommits\">")
3606+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 334, "</span></h2><ul class=\"pcommits\">")
35623607 if templ_7745c5c3_Err != nil {
35633608 return templ_7745c5c3_Err
35643609 }
35653610 for _, c := range p.Ahead {
3566- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 330, "<li><a href=\"")
3611+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 335, "<li><a href=\"")
35673612 if templ_7745c5c3_Err != nil {
35683613 return templ_7745c5c3_Err
35693614 }
35703615 var templ_7745c5c3_Var173 templ.SafeURL
35713616 templ_7745c5c3_Var173, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.CHref))
35723617 if templ_7745c5c3_Err != nil {
3573- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 686, Col: 37}
3618+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 710, Col: 37}
35743619 }
35753620 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var173))
35763621 if templ_7745c5c3_Err != nil {
35773622 return templ_7745c5c3_Err
35783623 }
3579- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 331, "\">")
3624+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 336, "\">")
35803625 if templ_7745c5c3_Err != nil {
35813626 return templ_7745c5c3_Err
35823627 }
35833628 var templ_7745c5c3_Var174 string
35843629 templ_7745c5c3_Var174, templ_7745c5c3_Err = templ.JoinStringErrs(c.Short)
35853630 if templ_7745c5c3_Err != nil {
3586- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 686, Col: 49}
3631+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 710, Col: 49}
35873632 }
35883633 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var174))
35893634 if templ_7745c5c3_Err != nil {
35903635 return templ_7745c5c3_Err
35913636 }
3592- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 332, "</a> <span class=\"s\">")
3637+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 337, "</a> <span class=\"s\">")
35933638 if templ_7745c5c3_Err != nil {
35943639 return templ_7745c5c3_Err
35953640 }
35963641 var templ_7745c5c3_Var175 string
35973642 templ_7745c5c3_Var175, templ_7745c5c3_Err = templ.JoinStringErrs(c.Subject)
35983643 if templ_7745c5c3_Err != nil {
3599- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 687, Col: 32}
3644+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 711, Col: 32}
36003645 }
36013646 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var175))
36023647 if templ_7745c5c3_Err != nil {
36033648 return templ_7745c5c3_Err
36043649 }
3605- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 333, "</span> <span class=\"mute\">")
3650+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 338, "</span> <span class=\"mute\">")
36063651 if templ_7745c5c3_Err != nil {
36073652 return templ_7745c5c3_Err
36083653 }
36093654 var templ_7745c5c3_Var176 string
36103655 templ_7745c5c3_Var176, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)
36113656 if templ_7745c5c3_Err != nil {
3612- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 689, Col: 16}
3657+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 713, Col: 16}
36133658 }
36143659 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var176))
36153660 if templ_7745c5c3_Err != nil {
36163661 return templ_7745c5c3_Err
36173662 }
3618- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 334, " ")
3663+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 339, " ")
36193664 if templ_7745c5c3_Err != nil {
36203665 return templ_7745c5c3_Err
36213666 }
@@ -3623,90 +3668,90 @@ func compareRail(p ComparePage) templ.Component {
36233668 var templ_7745c5c3_Var177 string
36243669 templ_7745c5c3_Var177, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")
36253670 if templ_7745c5c3_Err != nil {
3626- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 691, Col: 15}
3671+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 715, Col: 15}
36273672 }
36283673 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var177))
36293674 if templ_7745c5c3_Err != nil {
36303675 return templ_7745c5c3_Err
36313676 }
3632- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 335, "<time datetime=\"")
3677+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 340, "<time datetime=\"")
36333678 if templ_7745c5c3_Err != nil {
36343679 return templ_7745c5c3_Err
36353680 }
36363681 var templ_7745c5c3_Var178 string
36373682 templ_7745c5c3_Var178, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)
36383683 if templ_7745c5c3_Err != nil {
3639- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 691, Col: 42}
3684+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 715, Col: 42}
36403685 }
36413686 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var178)
36423687 if templ_7745c5c3_Err != nil {
36433688 return templ_7745c5c3_Err
36443689 }
3645- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 336, "\">")
3690+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 341, "\">")
36463691 if templ_7745c5c3_Err != nil {
36473692 return templ_7745c5c3_Err
36483693 }
36493694 var templ_7745c5c3_Var179 string
36503695 templ_7745c5c3_Var179, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)
36513696 if templ_7745c5c3_Err != nil {
3652- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 691, Col: 53}
3697+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 715, Col: 53}
36533698 }
36543699 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var179))
36553700 if templ_7745c5c3_Err != nil {
36563701 return templ_7745c5c3_Err
36573702 }
3658- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 337, "</time>")
3703+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 342, "</time>")
36593704 if templ_7745c5c3_Err != nil {
36603705 return templ_7745c5c3_Err
36613706 }
36623707 }
3663- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 338, "</span></li>")
3708+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 343, "</span></li>")
36643709 if templ_7745c5c3_Err != nil {
36653710 return templ_7745c5c3_Err
36663711 }
36673712 }
3668- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 339, "</ul>")
3713+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 344, "</ul>")
36693714 if templ_7745c5c3_Err != nil {
36703715 return templ_7745c5c3_Err
36713716 }
36723717 if len(p.Ahead) == 0 {
3673- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 340, "<p class=\"dim\">no commit ahead of ")
3718+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 345, "<p class=\"dim\">no commit ahead of ")
36743719 if templ_7745c5c3_Err != nil {
36753720 return templ_7745c5c3_Err
36763721 }
36773722 var templ_7745c5c3_Var180 string
36783723 templ_7745c5c3_Var180, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
36793724 if templ_7745c5c3_Err != nil {
3680- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 698, Col: 47}
3725+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 722, Col: 47}
36813726 }
36823727 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var180))
36833728 if templ_7745c5c3_Err != nil {
36843729 return templ_7745c5c3_Err
36853730 }
3686- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 341, ".</p>")
3731+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 346, ".</p>")
36873732 if templ_7745c5c3_Err != nil {
36883733 return templ_7745c5c3_Err
36893734 }
36903735 }
3691- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 342, "</section>")
3736+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 347, "</section>")
36923737 if templ_7745c5c3_Err != nil {
36933738 return templ_7745c5c3_Err
36943739 }
36953740 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\">")
3741+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 348, "<section aria-labelledby=\"r-files\"><h2 id=\"r-files\">Files <span class=\"count\">")
36973742 if templ_7745c5c3_Err != nil {
36983743 return templ_7745c5c3_Err
36993744 }
37003745 var templ_7745c5c3_Var181 string
37013746 templ_7745c5c3_Var181, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))
37023747 if templ_7745c5c3_Err != nil {
3703- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 703, Col: 66}
3748+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 727, Col: 66}
37043749 }
37053750 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var181))
37063751 if templ_7745c5c3_Err != nil {
37073752 return templ_7745c5c3_Err
37083753 }
3709- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 344, "</span></h2>")
3754+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 349, "</span></h2>")
37103755 if templ_7745c5c3_Err != nil {
37113756 return templ_7745c5c3_Err
37123757 }
@@ -3714,12 +3759,12 @@ func compareRail(p ComparePage) templ.Component {
37143759 if templ_7745c5c3_Err != nil {
37153760 return templ_7745c5c3_Err
37163761 }
3717- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 345, "</section>")
3762+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 350, "</section>")
37183763 if templ_7745c5c3_Err != nil {
37193764 return templ_7745c5c3_Err
37203765 }
37213766 }
3722- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 346, "<section aria-labelledby=\"r-cli\"><h2 id=\"r-cli\">From a terminal</h2>")
3767+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 351, "<section aria-labelledby=\"r-cli\"><h2 id=\"r-cli\">From a terminal</h2>")
37233768 if templ_7745c5c3_Err != nil {
37243769 return templ_7745c5c3_Err
37253770 }
@@ -3727,7 +3772,7 @@ func compareRail(p ComparePage) templ.Component {
37273772 if templ_7745c5c3_Err != nil {
37283773 return templ_7745c5c3_Err
37293774 }
3730- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 347, "</section>")
3775+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 352, "</section>")
37313776 if templ_7745c5c3_Err != nil {
37323777 return templ_7745c5c3_Err
37333778 }
@@ -521,8 +521,9 @@ func mrListRail(p MRListPage) templ.Component {
521 }521 }
522 522
523 // MergeRequest is a merge request: its facts, its description, the diff with523 // MergeRequest is a merge request: its facts, its description, the diff with
524-// the notes under their lines, the general comments; and in the rail the merge524+// the notes under their lines, the general comments. The merge and More menus
525-// form, the checks, the settings, the commits and the files.525+// sit in the toolbar, the commits and checks in the card footer, and the rail
526+// holds the files and verdicts.
526 func MergeRequest(l Layout, p MRPage) templ.Component {527 func MergeRequest(l Layout, p MRPage) templ.Component {
527 return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {528 return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
528 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context529 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@@ -563,7 +564,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
563 var templ_7745c5c3_Var26 string564 var templ_7745c5c3_Var26 string
564 templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(p.Number)565 templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(p.Number)
565 if templ_7745c5c3_Err != nil {566 if templ_7745c5c3_Err != nil {
566- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 117, Col: 37}567+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 118, Col: 37}
567 }568 }
568 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26))569 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26))
569 if templ_7745c5c3_Err != nil {570 if templ_7745c5c3_Err != nil {
@@ -576,7 +577,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
576 var templ_7745c5c3_Var27 string577 var templ_7745c5c3_Var27 string
577 templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(p.Title)578 templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(p.Title)
578 if templ_7745c5c3_Err != nil {579 if templ_7745c5c3_Err != nil {
579- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 117, Col: 56}580+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 118, Col: 56}
580 }581 }
581 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27))582 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27))
582 if templ_7745c5c3_Err != nil {583 if templ_7745c5c3_Err != nil {
@@ -589,7 +590,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
589 var templ_7745c5c3_Var28 string590 var templ_7745c5c3_Var28 string
590 templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.State)591 templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.State)
591 if templ_7745c5c3_Err != nil {592 if templ_7745c5c3_Err != nil {
592- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 120, Col: 46}593+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 121, Col: 46}
593 }594 }
594 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var28)595 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var28)
595 if templ_7745c5c3_Err != nil {596 if templ_7745c5c3_Err != nil {
@@ -602,7 +603,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
602 var templ_7745c5c3_Var29 string603 var templ_7745c5c3_Var29 string
603 templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(p.State)604 templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(p.State)
604 if templ_7745c5c3_Err != nil {605 if templ_7745c5c3_Err != nil {
605- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 121, Col: 15}606+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 122, Col: 15}
606 }607 }
607 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29))608 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29))
608 if templ_7745c5c3_Err != nil {609 if templ_7745c5c3_Err != nil {
@@ -616,7 +617,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
616 var templ_7745c5c3_Var30 string617 var templ_7745c5c3_Var30 string
617 templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")618 templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")
618 if templ_7745c5c3_Err != nil {619 if templ_7745c5c3_Err != nil {
619- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 123, Col: 15}620+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 124, Col: 15}
620 }621 }
621 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30))622 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30))
622 if templ_7745c5c3_Err != nil {623 if templ_7745c5c3_Err != nil {
@@ -629,7 +630,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
629 var templ_7745c5c3_Var31 templ.SafeURL630 var templ_7745c5c3_Var31 templ.SafeURL
630 templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.MergedHref))631 templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.MergedHref))
631 if templ_7745c5c3_Err != nil {632 if templ_7745c5c3_Err != nil {
632- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 123, Col: 54}633+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 124, Col: 54}
633 }634 }
634 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31))635 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31))
635 if templ_7745c5c3_Err != nil {636 if templ_7745c5c3_Err != nil {
@@ -642,7 +643,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
642 var templ_7745c5c3_Var32 string643 var templ_7745c5c3_Var32 string
643 templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.JoinStringErrs(p.MergedShort)644 templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.JoinStringErrs(p.MergedShort)
644 if templ_7745c5c3_Err != nil {645 if templ_7745c5c3_Err != nil {
645- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 123, Col: 72}646+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 124, Col: 72}
646 }647 }
647 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var32))648 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var32))
648 if templ_7745c5c3_Err != nil {649 if templ_7745c5c3_Err != nil {
@@ -655,7 +656,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
655 var templ_7745c5c3_Var33 string656 var templ_7745c5c3_Var33 string
656 templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.JoinStringErrs(" · " + p.MergeMode)657 templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.JoinStringErrs(" · " + p.MergeMode)
657 if templ_7745c5c3_Err != nil {658 if templ_7745c5c3_Err != nil {
658- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 123, Col: 100}659+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 124, Col: 100}
659 }660 }
660 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var33))661 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var33))
661 if templ_7745c5c3_Err != nil {662 if templ_7745c5c3_Err != nil {
@@ -673,7 +674,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
673 var templ_7745c5c3_Var34 string674 var templ_7745c5c3_Var34 string
674 templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(" → ")675 templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(" → ")
675 if templ_7745c5c3_Err != nil {676 if templ_7745c5c3_Err != nil {
676- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 129, Col: 15}677+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 130, Col: 15}
677 }678 }
678 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34))679 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34))
679 if templ_7745c5c3_Err != nil {680 if templ_7745c5c3_Err != nil {
@@ -690,7 +691,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
690 var templ_7745c5c3_Var35 string691 var templ_7745c5c3_Var35 string
691 templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.JoinStringErrs(p.Opened.Name)692 templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.JoinStringErrs(p.Opened.Name)
692 if templ_7745c5c3_Err != nil {693 if templ_7745c5c3_Err != nil {
693- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 134, Col: 21}694+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 135, Col: 21}
694 }695 }
695 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var35))696 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var35))
696 if templ_7745c5c3_Err != nil {697 if templ_7745c5c3_Err != nil {
@@ -704,7 +705,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
704 var templ_7745c5c3_Var36 string705 var templ_7745c5c3_Var36 string
705 templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")706 templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")
706 if templ_7745c5c3_Err != nil {707 if templ_7745c5c3_Err != nil {
707- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 136, Col: 15}708+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 137, Col: 15}
708 }709 }
709 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var36))710 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var36))
710 if templ_7745c5c3_Err != nil {711 if templ_7745c5c3_Err != nil {
@@ -717,7 +718,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
717 var templ_7745c5c3_Var37 string718 var templ_7745c5c3_Var37 string
718 templ_7745c5c3_Var37, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Opened.WhenAt)719 templ_7745c5c3_Var37, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Opened.WhenAt)
719 if templ_7745c5c3_Err != nil {720 if templ_7745c5c3_Err != nil {
720- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 136, Col: 49}721+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 137, Col: 49}
721 }722 }
722 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var37)723 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var37)
723 if templ_7745c5c3_Err != nil {724 if templ_7745c5c3_Err != nil {
@@ -730,7 +731,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
730 var templ_7745c5c3_Var38 string731 var templ_7745c5c3_Var38 string
731 templ_7745c5c3_Var38, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Opened.Abs)732 templ_7745c5c3_Var38, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Opened.Abs)
732 if templ_7745c5c3_Err != nil {733 if templ_7745c5c3_Err != nil {
733- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 136, Col: 72}734+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 137, Col: 72}
734 }735 }
735 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var38)736 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var38)
736 if templ_7745c5c3_Err != nil {737 if templ_7745c5c3_Err != nil {
@@ -743,7 +744,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
743 var templ_7745c5c3_Var39 string744 var templ_7745c5c3_Var39 string
744 templ_7745c5c3_Var39, templ_7745c5c3_Err = templ.JoinStringErrs(p.Opened.When)745 templ_7745c5c3_Var39, templ_7745c5c3_Err = templ.JoinStringErrs(p.Opened.When)
745 if templ_7745c5c3_Err != nil {746 if templ_7745c5c3_Err != nil {
746- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 136, Col: 90}747+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 137, Col: 90}
747 }748 }
748 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var39))749 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var39))
749 if templ_7745c5c3_Err != nil {750 if templ_7745c5c3_Err != nil {
@@ -766,7 +767,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
766 var templ_7745c5c3_Var40 string767 var templ_7745c5c3_Var40 string
767 templ_7745c5c3_Var40, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.UpdatedAt)768 templ_7745c5c3_Var40, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.UpdatedAt)
768 if templ_7745c5c3_Err != nil {769 if templ_7745c5c3_Err != nil {
769- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 141, Col: 38}770+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 142, Col: 38}
770 }771 }
771 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var40)772 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var40)
772 if templ_7745c5c3_Err != nil {773 if templ_7745c5c3_Err != nil {
@@ -779,7 +780,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
779 var templ_7745c5c3_Var41 string780 var templ_7745c5c3_Var41 string
780 templ_7745c5c3_Var41, templ_7745c5c3_Err = templ.JoinStringErrs(p.Updated)781 templ_7745c5c3_Var41, templ_7745c5c3_Err = templ.JoinStringErrs(p.Updated)
781 if templ_7745c5c3_Err != nil {782 if templ_7745c5c3_Err != nil {
782- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 141, Col: 52}783+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 142, Col: 52}
783 }784 }
784 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var41))785 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var41))
785 if templ_7745c5c3_Err != nil {786 if templ_7745c5c3_Err != nil {
@@ -808,6 +809,10 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
808 return templ_7745c5c3_Err809 return templ_7745c5c3_Err
809 }810 }
810 }811 }
812+ templ_7745c5c3_Err = mrFooter(p).Render(ctx, templ_7745c5c3_Buffer)
813+ if templ_7745c5c3_Err != nil {
814+ return templ_7745c5c3_Err
815+ }
811 templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "</section>")816 templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "</section>")
812 if templ_7745c5c3_Err != nil {817 if templ_7745c5c3_Err != nil {
813 return templ_7745c5c3_Err818 return templ_7745c5c3_Err
@@ -820,7 +825,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
820 var templ_7745c5c3_Var42 string825 var templ_7745c5c3_Var42 string
821 templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.JoinStringErrs(p.Deleting)826 templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.JoinStringErrs(p.Deleting)
822 if templ_7745c5c3_Err != nil {827 if templ_7745c5c3_Err != nil {
823- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 152, Col: 64}828+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 154, Col: 64}
824 }829 }
825 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var42))830 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var42))
826 if templ_7745c5c3_Err != nil {831 if templ_7745c5c3_Err != nil {
@@ -843,7 +848,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
843 var templ_7745c5c3_Var43 string848 var templ_7745c5c3_Var43 string
844 templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinStringErrs(p.MergeError)849 templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinStringErrs(p.MergeError)
845 if templ_7745c5c3_Err != nil {850 if templ_7745c5c3_Err != nil {
846- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 155, Col: 47}851+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 157, Col: 47}
847 }852 }
848 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43))853 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43))
849 if templ_7745c5c3_Err != nil {854 if templ_7745c5c3_Err != nil {
@@ -874,7 +879,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
874 var templ_7745c5c3_Var44 templ.SafeURL879 var templ_7745c5c3_Var44 templ.SafeURL
875 templ_7745c5c3_Var44, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Since.AllHref))880 templ_7745c5c3_Var44, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Since.AllHref))
876 if templ_7745c5c3_Err != nil {881 if templ_7745c5c3_Err != nil {
877- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 161, Col: 42}882+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 163, Col: 42}
878 }883 }
879 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var44))884 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var44))
880 if templ_7745c5c3_Err != nil {885 if templ_7745c5c3_Err != nil {
@@ -897,7 +902,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
897 var templ_7745c5c3_Var45 string902 var templ_7745c5c3_Var45 string
898 templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)903 templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
899 if templ_7745c5c3_Err != nil {904 if templ_7745c5c3_Err != nil {
900- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 165, Col: 49}905+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 167, Col: 49}
901 }906 }
902 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var45))907 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var45))
903 if templ_7745c5c3_Err != nil {908 if templ_7745c5c3_Err != nil {
@@ -910,7 +915,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
910 var templ_7745c5c3_Var46 templ.SafeURL915 var templ_7745c5c3_Var46 templ.SafeURL
911 templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Since.SinceHref))916 templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Since.SinceHref))
912 if templ_7745c5c3_Err != nil {917 if templ_7745c5c3_Err != nil {
913- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 167, Col: 44}918+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 169, Col: 44}
914 }919 }
915 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var46))920 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var46))
916 if templ_7745c5c3_Err != nil {921 if templ_7745c5c3_Err != nil {
@@ -933,7 +938,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
933 var templ_7745c5c3_Var47 string938 var templ_7745c5c3_Var47 string
934 templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.JoinStringErrs(p.Since.ReadShort)939 templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.JoinStringErrs(p.Since.ReadShort)
935 if templ_7745c5c3_Err != nil {940 if templ_7745c5c3_Err != nil {
936- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 171, Col: 64}941+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 173, Col: 64}
937 }942 }
938 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var47))943 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var47))
939 if templ_7745c5c3_Err != nil {944 if templ_7745c5c3_Err != nil {
@@ -946,7 +951,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
946 var templ_7745c5c3_Var48 string951 var templ_7745c5c3_Var48 string
947 templ_7745c5c3_Var48, templ_7745c5c3_Err = templ.JoinStringErrs(p.Since.HeadShort)952 templ_7745c5c3_Var48, templ_7745c5c3_Err = templ.JoinStringErrs(p.Since.HeadShort)
948 if templ_7745c5c3_Err != nil {953 if templ_7745c5c3_Err != nil {
949- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 171, Col: 90}954+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 173, Col: 90}
950 }955 }
951 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var48))956 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var48))
952 if templ_7745c5c3_Err != nil {957 if templ_7745c5c3_Err != nil {
@@ -969,7 +974,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
969 var templ_7745c5c3_Var49 string974 var templ_7745c5c3_Var49 string
970 templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.JoinStringErrs(p.SinceNote)975 templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.JoinStringErrs(p.SinceNote)
971 if templ_7745c5c3_Err != nil {976 if templ_7745c5c3_Err != nil {
972- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 175, Col: 34}977+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 177, Col: 34}
973 }978 }
974 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var49))979 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var49))
975 if templ_7745c5c3_Err != nil {980 if templ_7745c5c3_Err != nil {
@@ -1010,7 +1015,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
1010 var templ_7745c5c3_Var50 string1015 var templ_7745c5c3_Var50 string
1011 templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note)1016 templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note)
1012 if templ_7745c5c3_Err != nil {1017 if templ_7745c5c3_Err != nil {
1013- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 185, Col: 29}1018+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 187, Col: 29}
1014 }1019 }
1015 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var50))1020 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var50))
1016 if templ_7745c5c3_Err != nil {1021 if templ_7745c5c3_Err != nil {
@@ -1033,7 +1038,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
1033 var templ_7745c5c3_Var51 string1038 var templ_7745c5c3_Var51 string
1034 templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Canonical)1039 templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Canonical)
1035 if templ_7745c5c3_Err != nil {1040 if templ_7745c5c3_Err != nil {
1036- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 191, Col: 32}1041+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 193, Col: 32}
1037 }1042 }
1038 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var51)1043 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var51)
1039 if templ_7745c5c3_Err != nil {1044 if templ_7745c5c3_Err != nil {
@@ -1052,7 +1057,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
1052 var templ_7745c5c3_Var52 string1057 var templ_7745c5c3_Var52 string
1053 templ_7745c5c3_Var52, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)1058 templ_7745c5c3_Var52, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
1054 if templ_7745c5c3_Err != nil {1059 if templ_7745c5c3_Err != nil {
1055- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 194, Col: 22}1060+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 196, Col: 22}
1056 }1061 }
1057 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var52)1062 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var52)
1058 if templ_7745c5c3_Err != nil {1063 if templ_7745c5c3_Err != nil {
@@ -1070,7 +1075,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
1070 var templ_7745c5c3_Var53 string1075 var templ_7745c5c3_Var53 string
1071 templ_7745c5c3_Var53, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)1076 templ_7745c5c3_Var53, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
1072 if templ_7745c5c3_Err != nil {1077 if templ_7745c5c3_Err != nil {
1073- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 196, Col: 22}1078+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 198, Col: 22}
1074 }1079 }
1075 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var53)1080 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var53)
1076 if templ_7745c5c3_Err != nil {1081 if templ_7745c5c3_Err != nil {
@@ -1110,7 +1115,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
1110 var templ_7745c5c3_Var54 string1115 var templ_7745c5c3_Var54 string
1111 templ_7745c5c3_Var54, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.NUnresolved))1116 templ_7745c5c3_Var54, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.NUnresolved))
1112 if templ_7745c5c3_Err != nil {1117 if templ_7745c5c3_Err != nil {
1113- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 209, Col: 97}1118+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 211, Col: 97}
1114 }1119 }
1115 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var54))1120 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var54))
1116 if templ_7745c5c3_Err != nil {1121 if templ_7745c5c3_Err != nil {
@@ -1123,7 +1128,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
1123 var templ_7745c5c3_Var55 string1128 var templ_7745c5c3_Var55 string
1124 templ_7745c5c3_Var55, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.NComments))1129 templ_7745c5c3_Var55, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.NComments))
1125 if templ_7745c5c3_Err != nil {1130 if templ_7745c5c3_Err != nil {
1126- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 209, Col: 126}1131+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 211, Col: 126}
1127 }1132 }
1128 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var55))1133 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var55))
1129 if templ_7745c5c3_Err != nil {1134 if templ_7745c5c3_Err != nil {
@@ -1204,7 +1209,7 @@ func branchLink(name, href string) templ.Component {
1204 var templ_7745c5c3_Var57 templ.SafeURL1209 var templ_7745c5c3_Var57 templ.SafeURL
1205 templ_7745c5c3_Var57, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))1210 templ_7745c5c3_Var57, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))
1206 if templ_7745c5c3_Err != nil {1211 if templ_7745c5c3_Err != nil {
1207- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 227, Col: 31}1212+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 229, Col: 31}
1208 }1213 }
1209 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var57))1214 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var57))
1210 if templ_7745c5c3_Err != nil {1215 if templ_7745c5c3_Err != nil {
@@ -1217,7 +1222,7 @@ func branchLink(name, href string) templ.Component {
1217 var templ_7745c5c3_Var58 string1222 var templ_7745c5c3_Var58 string
1218 templ_7745c5c3_Var58, templ_7745c5c3_Err = templ.JoinStringErrs(name)1223 templ_7745c5c3_Var58, templ_7745c5c3_Err = templ.JoinStringErrs(name)
1219 if templ_7745c5c3_Err != nil {1224 if templ_7745c5c3_Err != nil {
1220- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 227, Col: 40}1225+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 229, Col: 40}
1221 }1226 }
1222 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var58))1227 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var58))
1223 if templ_7745c5c3_Err != nil {1228 if templ_7745c5c3_Err != nil {
@@ -1231,7 +1236,7 @@ func branchLink(name, href string) templ.Component {
1231 var templ_7745c5c3_Var59 string1236 var templ_7745c5c3_Var59 string
1232 templ_7745c5c3_Var59, templ_7745c5c3_Err = templ.JoinStringErrs(name)1237 templ_7745c5c3_Var59, templ_7745c5c3_Err = templ.JoinStringErrs(name)
1233 if templ_7745c5c3_Err != nil {1238 if templ_7745c5c3_Err != nil {
1234- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 229, Col: 8}1239+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 231, Col: 8}
1235 }1240 }
1236 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var59))1241 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var59))
1237 if templ_7745c5c3_Err != nil {1242 if templ_7745c5c3_Err != nil {
@@ -1312,7 +1317,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1312 var templ_7745c5c3_Var62 string1317 var templ_7745c5c3_Var62 string
1313 templ_7745c5c3_Var62, templ_7745c5c3_Err = templ.ResolveAttributeValue("c" + c.ID + suffix)1318 templ_7745c5c3_Var62, templ_7745c5c3_Err = templ.ResolveAttributeValue("c" + c.ID + suffix)
1314 if templ_7745c5c3_Err != nil {1319 if templ_7745c5c3_Err != nil {
1315- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 248, Col: 42}1320+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 250, Col: 42}
1316 }1321 }
1317 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var62)1322 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var62)
1318 if templ_7745c5c3_Err != nil {1323 if templ_7745c5c3_Err != nil {
@@ -1325,7 +1330,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1325 var templ_7745c5c3_Var63 string1330 var templ_7745c5c3_Var63 string
1326 templ_7745c5c3_Var63, templ_7745c5c3_Err = templ.ResolveAttributeValue(boolText(c.Resolved))1331 templ_7745c5c3_Var63, templ_7745c5c3_Err = templ.ResolveAttributeValue(boolText(c.Resolved))
1327 if templ_7745c5c3_Err != nil {1332 if templ_7745c5c3_Err != nil {
1328- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 248, Col: 81}1333+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 250, Col: 81}
1329 }1334 }
1330 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var63)1335 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var63)
1331 if templ_7745c5c3_Err != nil {1336 if templ_7745c5c3_Err != nil {
@@ -1348,7 +1353,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1348 var templ_7745c5c3_Var64 string1353 var templ_7745c5c3_Var64 string
1349 templ_7745c5c3_Var64, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)1354 templ_7745c5c3_Var64, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)
1350 if templ_7745c5c3_Err != nil {1355 if templ_7745c5c3_Err != nil {
1351- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 250, Col: 33}1356+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 252, Col: 33}
1352 }1357 }
1353 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var64))1358 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var64))
1354 if templ_7745c5c3_Err != nil {1359 if templ_7745c5c3_Err != nil {
@@ -1362,7 +1367,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1362 var templ_7745c5c3_Var65 string1367 var templ_7745c5c3_Var65 string
1363 templ_7745c5c3_Var65, templ_7745c5c3_Err = templ.JoinStringErrs(" ")1368 templ_7745c5c3_Var65, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
1364 if templ_7745c5c3_Err != nil {1369 if templ_7745c5c3_Err != nil {
1365- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 252, Col: 9}1370+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 254, Col: 9}
1366 }1371 }
1367 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var65))1372 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var65))
1368 if templ_7745c5c3_Err != nil {1373 if templ_7745c5c3_Err != nil {
@@ -1375,7 +1380,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1375 var templ_7745c5c3_Var66 string1380 var templ_7745c5c3_Var66 string
1376 templ_7745c5c3_Var66, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)1381 templ_7745c5c3_Var66, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)
1377 if templ_7745c5c3_Err != nil {1382 if templ_7745c5c3_Err != nil {
1378- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 252, Col: 49}1383+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 254, Col: 49}
1379 }1384 }
1380 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var66)1385 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var66)
1381 if templ_7745c5c3_Err != nil {1386 if templ_7745c5c3_Err != nil {
@@ -1388,7 +1393,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1388 var templ_7745c5c3_Var67 string1393 var templ_7745c5c3_Var67 string
1389 templ_7745c5c3_Var67, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.Abs)1394 templ_7745c5c3_Var67, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.Abs)
1390 if templ_7745c5c3_Err != nil {1395 if templ_7745c5c3_Err != nil {
1391- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 252, Col: 65}1396+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 254, Col: 65}
1392 }1397 }
1393 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var67)1398 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var67)
1394 if templ_7745c5c3_Err != nil {1399 if templ_7745c5c3_Err != nil {
@@ -1401,7 +1406,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1401 var templ_7745c5c3_Var68 string1406 var templ_7745c5c3_Var68 string
1402 templ_7745c5c3_Var68, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)1407 templ_7745c5c3_Var68, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)
1403 if templ_7745c5c3_Err != nil {1408 if templ_7745c5c3_Err != nil {
1404- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 252, Col: 76}1409+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 254, Col: 76}
1405 }1410 }
1406 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var68))1411 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var68))
1407 if templ_7745c5c3_Err != nil {1412 if templ_7745c5c3_Err != nil {
@@ -1416,7 +1421,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1416 var templ_7745c5c3_Var69 string1421 var templ_7745c5c3_Var69 string
1417 templ_7745c5c3_Var69, templ_7745c5c3_Err = templ.JoinStringErrs(" ")1422 templ_7745c5c3_Var69, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
1418 if templ_7745c5c3_Err != nil {1423 if templ_7745c5c3_Err != nil {
1419- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 255, Col: 9}1424+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 257, Col: 9}
1420 }1425 }
1421 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var69))1426 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var69))
1422 if templ_7745c5c3_Err != nil {1427 if templ_7745c5c3_Err != nil {
@@ -1431,7 +1436,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1431 var templ_7745c5c3_Var70 string1436 var templ_7745c5c3_Var70 string
1432 templ_7745c5c3_Var70, templ_7745c5c3_Err = templ.JoinStringErrs(" ")1437 templ_7745c5c3_Var70, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
1433 if templ_7745c5c3_Err != nil {1438 if templ_7745c5c3_Err != nil {
1434- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 258, Col: 9}1439+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 260, Col: 9}
1435 }1440 }
1436 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var70))1441 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var70))
1437 if templ_7745c5c3_Err != nil {1442 if templ_7745c5c3_Err != nil {
@@ -1446,7 +1451,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1446 var templ_7745c5c3_Var71 string1451 var templ_7745c5c3_Var71 string
1447 templ_7745c5c3_Var71, templ_7745c5c3_Err = templ.JoinStringErrs(" ")1452 templ_7745c5c3_Var71, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
1448 if templ_7745c5c3_Err != nil {1453 if templ_7745c5c3_Err != nil {
1449- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 261, Col: 9}1454+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 263, Col: 9}
1450 }1455 }
1451 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var71))1456 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var71))
1452 if templ_7745c5c3_Err != nil {1457 if templ_7745c5c3_Err != nil {
@@ -1459,7 +1464,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1459 var templ_7745c5c3_Var72 string1464 var templ_7745c5c3_Var72 string
1460 templ_7745c5c3_Var72, templ_7745c5c3_Err = templ.JoinStringErrs(c.Where)1465 templ_7745c5c3_Var72, templ_7745c5c3_Err = templ.JoinStringErrs(c.Where)
1461 if templ_7745c5c3_Err != nil {1466 if templ_7745c5c3_Err != nil {
1462- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 261, Col: 47}1467+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 263, Col: 47}
1463 }1468 }
1464 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var72))1469 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var72))
1465 if templ_7745c5c3_Err != nil {1470 if templ_7745c5c3_Err != nil {
@@ -1534,7 +1539,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1534 var templ_7745c5c3_Var73 string1539 var templ_7745c5c3_Var73 string
1535 templ_7745c5c3_Var73, templ_7745c5c3_Err = templ.JoinStringErrs(c.Verdict)1540 templ_7745c5c3_Var73, templ_7745c5c3_Err = templ.JoinStringErrs(c.Verdict)
1536 if templ_7745c5c3_Err != nil {1541 if templ_7745c5c3_Err != nil {
1537- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 285, Col: 36}1542+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 287, Col: 36}
1538 }1543 }
1539 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var73))1544 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var73))
1540 if templ_7745c5c3_Err != nil {1545 if templ_7745c5c3_Err != nil {
@@ -1553,7 +1558,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1553 var templ_7745c5c3_Var74 string1558 var templ_7745c5c3_Var74 string
1554 templ_7745c5c3_Var74, templ_7745c5c3_Err = templ.JoinStringErrs(c.Range)1559 templ_7745c5c3_Var74, templ_7745c5c3_Err = templ.JoinStringErrs(c.Range)
1555 if templ_7745c5c3_Err != nil {1560 if templ_7745c5c3_Err != nil {
1556- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 288, Col: 31}1561+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 290, Col: 31}
1557 }1562 }
1558 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var74))1563 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var74))
1559 if templ_7745c5c3_Err != nil {1564 if templ_7745c5c3_Err != nil {
@@ -1572,7 +1577,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1572 var templ_7745c5c3_Var75 string1577 var templ_7745c5c3_Var75 string
1573 templ_7745c5c3_Var75, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.Quote)1578 templ_7745c5c3_Var75, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.Quote)
1574 if templ_7745c5c3_Err != nil {1579 if templ_7745c5c3_Err != nil {
1575- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 291, Col: 65}1580+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 293, Col: 65}
1576 }1581 }
1577 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var75)1582 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var75)
1578 if templ_7745c5c3_Err != nil {1583 if templ_7745c5c3_Err != nil {
@@ -1591,7 +1596,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1591 var templ_7745c5c3_Var76 templ.SafeURL1596 var templ_7745c5c3_Var76 templ.SafeURL
1592 templ_7745c5c3_Var76, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Edit.Action))1597 templ_7745c5c3_Var76, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Edit.Action))
1593 if templ_7745c5c3_Err != nil {1598 if templ_7745c5c3_Err != nil {
1594- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 294, Col: 92}1599+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 296, Col: 92}
1595 }1600 }
1596 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var76))1601 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var76))
1597 if templ_7745c5c3_Err != nil {1602 if templ_7745c5c3_Err != nil {
@@ -1604,7 +1609,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1604 var templ_7745c5c3_Var77 string1609 var templ_7745c5c3_Var77 string
1605 templ_7745c5c3_Var77, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(c.Edit.From))1610 templ_7745c5c3_Var77, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(c.Edit.From))
1606 if templ_7745c5c3_Err != nil {1611 if templ_7745c5c3_Err != nil {
1607- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 294, Col: 153}1612+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 296, Col: 153}
1608 }1613 }
1609 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var77)1614 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var77)
1610 if templ_7745c5c3_Err != nil {1615 if templ_7745c5c3_Err != nil {
@@ -1617,7 +1622,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1617 var templ_7745c5c3_Var78 string1622 var templ_7745c5c3_Var78 string
1618 templ_7745c5c3_Var78, templ_7745c5c3_Err = templ.JoinStringErrs(c.Edit.Text)1623 templ_7745c5c3_Var78, templ_7745c5c3_Err = templ.JoinStringErrs(c.Edit.Text)
1619 if templ_7745c5c3_Err != nil {1624 if templ_7745c5c3_Err != nil {
1620- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 294, Col: 209}1625+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 296, Col: 209}
1621 }1626 }
1622 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var78))1627 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var78))
1623 if templ_7745c5c3_Err != nil {1628 if templ_7745c5c3_Err != nil {
@@ -1636,7 +1641,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1636 var templ_7745c5c3_Var79 templ.SafeURL1641 var templ_7745c5c3_Var79 templ.SafeURL
1637 templ_7745c5c3_Var79, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Delete.Action))1642 templ_7745c5c3_Var79, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Delete.Action))
1638 if templ_7745c5c3_Err != nil {1643 if templ_7745c5c3_Err != nil {
1639- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 297, Col: 96}1644+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 299, Col: 96}
1640 }1645 }
1641 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var79))1646 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var79))
1642 if templ_7745c5c3_Err != nil {1647 if templ_7745c5c3_Err != nil {
@@ -1649,7 +1654,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1649 var templ_7745c5c3_Var80 string1654 var templ_7745c5c3_Var80 string
1650 templ_7745c5c3_Var80, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(c.Delete.From))1655 templ_7745c5c3_Var80, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(c.Delete.From))
1651 if templ_7745c5c3_Err != nil {1656 if templ_7745c5c3_Err != nil {
1652- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 297, Col: 159}1657+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 299, Col: 159}
1653 }1658 }
1654 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var80)1659 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var80)
1655 if templ_7745c5c3_Err != nil {1660 if templ_7745c5c3_Err != nil {
@@ -1688,7 +1693,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1688 var templ_7745c5c3_Var81 templ.SafeURL1693 var templ_7745c5c3_Var81 templ.SafeURL
1689 templ_7745c5c3_Var81, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Resolve.Action))1694 templ_7745c5c3_Var81, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Resolve.Action))
1690 if templ_7745c5c3_Err != nil {1695 if templ_7745c5c3_Err != nil {
1691- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 308, Col: 77}1696+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 310, Col: 77}
1692 }1697 }
1693 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var81))1698 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var81))
1694 if templ_7745c5c3_Err != nil {1699 if templ_7745c5c3_Err != nil {
@@ -1701,7 +1706,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1701 var templ_7745c5c3_Var82 string1706 var templ_7745c5c3_Var82 string
1702 templ_7745c5c3_Var82, templ_7745c5c3_Err = templ.ResolveAttributeValue(boolText(c.Resolve.Value))1707 templ_7745c5c3_Var82, templ_7745c5c3_Err = templ.ResolveAttributeValue(boolText(c.Resolve.Value))
1703 if templ_7745c5c3_Err != nil {1708 if templ_7745c5c3_Err != nil {
1704- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 309, Col: 74}1709+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 311, Col: 74}
1705 }1710 }
1706 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var82)1711 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var82)
1707 if templ_7745c5c3_Err != nil {1712 if templ_7745c5c3_Err != nil {
@@ -1719,7 +1724,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1719 var templ_7745c5c3_Var83 string1724 var templ_7745c5c3_Var83 string
1720 templ_7745c5c3_Var83, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(c.Resolve.From))1725 templ_7745c5c3_Var83, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(c.Resolve.From))
1721 if templ_7745c5c3_Err != nil {1726 if templ_7745c5c3_Err != nil {
1722- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 311, Col: 66}1727+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 313, Col: 66}
1723 }1728 }
1724 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var83)1729 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var83)
1725 if templ_7745c5c3_Err != nil {1730 if templ_7745c5c3_Err != nil {
@@ -1737,7 +1742,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1737 var templ_7745c5c3_Var84 string1742 var templ_7745c5c3_Var84 string
1738 templ_7745c5c3_Var84, templ_7745c5c3_Err = templ.JoinStringErrs(c.Resolve.Label)1743 templ_7745c5c3_Var84, templ_7745c5c3_Err = templ.JoinStringErrs(c.Resolve.Label)
1739 if templ_7745c5c3_Err != nil {1744 if templ_7745c5c3_Err != nil {
1740- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 313, Col: 55}1745+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 315, Col: 55}
1741 }1746 }
1742 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var84))1747 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var84))
1743 if templ_7745c5c3_Err != nil {1748 if templ_7745c5c3_Err != nil {
@@ -1792,7 +1797,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1792 var templ_7745c5c3_Var86 templ.SafeURL1797 var templ_7745c5c3_Var86 templ.SafeURL
1793 templ_7745c5c3_Var86, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(f.Action))1798 templ_7745c5c3_Var86, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(f.Action))
1794 if templ_7745c5c3_Err != nil {1799 if templ_7745c5c3_Err != nil {
1795- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 328, Col: 67}1800+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 330, Col: 67}
1796 }1801 }
1797 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var86))1802 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var86))
1798 if templ_7745c5c3_Err != nil {1803 if templ_7745c5c3_Err != nil {
@@ -1805,7 +1810,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1805 var templ_7745c5c3_Var87 string1810 var templ_7745c5c3_Var87 string
1806 templ_7745c5c3_Var87, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID + suffix)1811 templ_7745c5c3_Var87, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID + suffix)
1807 if templ_7745c5c3_Err != nil {1812 if templ_7745c5c3_Err != nil {
1808- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 329, Col: 28}1813+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 331, Col: 28}
1809 }1814 }
1810 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var87)1815 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var87)
1811 if templ_7745c5c3_Err != nil {1816 if templ_7745c5c3_Err != nil {
@@ -1818,7 +1823,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1818 var templ_7745c5c3_Var88 string1823 var templ_7745c5c3_Var88 string
1819 templ_7745c5c3_Var88, templ_7745c5c3_Err = templ.JoinStringErrs(f.Title)1824 templ_7745c5c3_Var88, templ_7745c5c3_Err = templ.JoinStringErrs(f.Title)
1820 if templ_7745c5c3_Err != nil {1825 if templ_7745c5c3_Err != nil {
1821- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 329, Col: 40}1826+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 331, Col: 40}
1822 }1827 }
1823 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var88))1828 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var88))
1824 if templ_7745c5c3_Err != nil {1829 if templ_7745c5c3_Err != nil {
@@ -1831,7 +1836,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1831 var templ_7745c5c3_Var89 string1836 var templ_7745c5c3_Var89 string
1832 templ_7745c5c3_Var89, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID + suffix)1837 templ_7745c5c3_Var89, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID + suffix)
1833 if templ_7745c5c3_Err != nil {1838 if templ_7745c5c3_Err != nil {
1834- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 331, Col: 21}1839+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 333, Col: 21}
1835 }1840 }
1836 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var89)1841 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var89)
1837 if templ_7745c5c3_Err != nil {1842 if templ_7745c5c3_Err != nil {
@@ -1870,7 +1875,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1870 var templ_7745c5c3_Var90 string1875 var templ_7745c5c3_Var90 string
1871 templ_7745c5c3_Var90, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Path)1876 templ_7745c5c3_Var90, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Path)
1872 if templ_7745c5c3_Err != nil {1877 if templ_7745c5c3_Err != nil {
1873- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 346, Col: 50}1878+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 348, Col: 50}
1874 }1879 }
1875 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var90)1880 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var90)
1876 if templ_7745c5c3_Err != nil {1881 if templ_7745c5c3_Err != nil {
@@ -1883,7 +1888,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1883 var templ_7745c5c3_Var91 string1888 var templ_7745c5c3_Var91 string
1884 templ_7745c5c3_Var91, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Line)1889 templ_7745c5c3_Var91, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Line)
1885 if templ_7745c5c3_Err != nil {1890 if templ_7745c5c3_Err != nil {
1886- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 347, Col: 50}1891+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 349, Col: 50}
1887 }1892 }
1888 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var91)1893 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var91)
1889 if templ_7745c5c3_Err != nil {1894 if templ_7745c5c3_Err != nil {
@@ -1896,7 +1901,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1896 var templ_7745c5c3_Var92 string1901 var templ_7745c5c3_Var92 string
1897 templ_7745c5c3_Var92, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Side)1902 templ_7745c5c3_Var92, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Side)
1898 if templ_7745c5c3_Err != nil {1903 if templ_7745c5c3_Err != nil {
1899- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 348, Col: 50}1904+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 350, Col: 50}
1900 }1905 }
1901 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var92)1906 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var92)
1902 if templ_7745c5c3_Err != nil {1907 if templ_7745c5c3_Err != nil {
@@ -1909,7 +1914,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1909 var templ_7745c5c3_Var93 string1914 var templ_7745c5c3_Var93 string
1910 templ_7745c5c3_Var93, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.StartLine)1915 templ_7745c5c3_Var93, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.StartLine)
1911 if templ_7745c5c3_Err != nil {1916 if templ_7745c5c3_Err != nil {
1912- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 349, Col: 86}1917+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 351, Col: 86}
1913 }1918 }
1914 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var93)1919 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var93)
1915 if templ_7745c5c3_Err != nil {1920 if templ_7745c5c3_Err != nil {
@@ -1928,7 +1933,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1928 var templ_7745c5c3_Var94 string1933 var templ_7745c5c3_Var94 string
1929 templ_7745c5c3_Var94, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ReplyTo)1934 templ_7745c5c3_Var94, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ReplyTo)
1930 if templ_7745c5c3_Err != nil {1935 if templ_7745c5c3_Err != nil {
1931- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 352, Col: 57}1936+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 354, Col: 57}
1932 }1937 }
1933 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var94)1938 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var94)
1934 if templ_7745c5c3_Err != nil {1939 if templ_7745c5c3_Err != nil {
@@ -1953,7 +1958,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1953 var templ_7745c5c3_Var95 string1958 var templ_7745c5c3_Var95 string
1954 templ_7745c5c3_Var95, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(f.From))1959 templ_7745c5c3_Var95, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(f.From))
1955 if templ_7745c5c3_Err != nil {1960 if templ_7745c5c3_Err != nil {
1956- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 358, Col: 56}1961+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 360, Col: 56}
1957 }1962 }
1958 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var95)1963 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var95)
1959 if templ_7745c5c3_Err != nil {1964 if templ_7745c5c3_Err != nil {
@@ -1976,7 +1981,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1976 var templ_7745c5c3_Var96 templ.SafeURL1981 var templ_7745c5c3_Var96 templ.SafeURL
1977 templ_7745c5c3_Var96, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(f.Cancel))1982 templ_7745c5c3_Var96, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(f.Cancel))
1978 if templ_7745c5c3_Err != nil {1983 if templ_7745c5c3_Err != nil {
1979- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 363, Col: 49}1984+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 365, Col: 49}
1980 }1985 }
1981 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var96))1986 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var96))
1982 if templ_7745c5c3_Err != nil {1987 if templ_7745c5c3_Err != nil {
@@ -1995,7 +2000,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1995 })2000 })
1996 }2001 }
1997 2002
1998-func mrRail(p MRPage) templ.Component {2003+func mrFooter(p MRPage) templ.Component {
1999 return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {2004 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.Context2005 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
2001 if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {2006 if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -2016,312 +2021,349 @@ func mrRail(p MRPage) templ.Component {
2016 templ_7745c5c3_Var97 = templ.NopComponent2021 templ_7745c5c3_Var97 = templ.NopComponent
2017 }2022 }
2018 ctx = templ.ClearChildren(ctx)2023 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\">")2024+ 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 {2025 if templ_7745c5c3_Err != nil {
2021 return templ_7745c5c3_Err2026 return templ_7745c5c3_Err
2022 }2027 }
2023 var templ_7745c5c3_Var98 string2028 var templ_7745c5c3_Var98 string
2024- templ_7745c5c3_Var98, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))2029+ templ_7745c5c3_Var98, templ_7745c5c3_Err = templ.JoinStringErrs(p.CommitCount)
2025 if templ_7745c5c3_Err != nil {2030 if templ_7745c5c3_Err != nil {
2026- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 372, Col: 49}2031+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 374, Col: 55}
2027 }2032 }
2028 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var98))2033 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var98))
2029 if templ_7745c5c3_Err != nil {2034 if templ_7745c5c3_Err != nil {
2030 return templ_7745c5c3_Err2035 return templ_7745c5c3_Err
2031 }2036 }
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>")2037+ 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 {2038 if templ_7745c5c3_Err != nil {
2034 return templ_7745c5c3_Err2039 return templ_7745c5c3_Err
2035 }2040 }
2036- templ_7745c5c3_Err = FileList(p.Files).Render(ctx, templ_7745c5c3_Buffer)2041+ var templ_7745c5c3_Var99 string
2042+ templ_7745c5c3_Var99, templ_7745c5c3_Err = templ.JoinStringErrs(p.CommitCount)
2037 if templ_7745c5c3_Err != nil {2043 if templ_7745c5c3_Err != nil {
2038- return templ_7745c5c3_Err2044+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 376, Col: 89}
2039 }2045 }
2040- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 187, "</section>")2046+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var99))
2041 if templ_7745c5c3_Err != nil {2047 if templ_7745c5c3_Err != nil {
2042 return templ_7745c5c3_Err2048 return templ_7745c5c3_Err
2043 }2049 }
2044- if len(p.Verdicts) > 0 {2050+ 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 {2051 if templ_7745c5c3_Err != nil {
2111 return templ_7745c5c3_Err2052 return templ_7745c5c3_Err
2112 }2053 }
2113- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 196, "<section aria-labelledby=\"r-commits\"><h2 id=\"r-commits\">Commits <span class=\"count\">")2054+ var templ_7745c5c3_Var100 string
2055+ templ_7745c5c3_Var100, templ_7745c5c3_Err = templ.JoinStringErrs("Checks ")
2114 if templ_7745c5c3_Err != nil {2056 if templ_7745c5c3_Err != nil {
2115- return templ_7745c5c3_Err2057+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 378, Col: 16}
2116 }2058 }
2117- var templ_7745c5c3_Var102 string2059+ _, 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 {2060 if templ_7745c5c3_Err != nil {
2120- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 396, Col: 71}2061+ return templ_7745c5c3_Err
2121 }2062 }
2122- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var102))2063+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 188, " <span data-checks-label>")
2123 if templ_7745c5c3_Err != nil {2064 if templ_7745c5c3_Err != nil {
2124 return templ_7745c5c3_Err2065 return templ_7745c5c3_Err
2125 }2066 }
2126- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 197, "</span></h2><ul class=\"pcommits\">")2067+ if p.ChecksSum.Total > 0 {
2068+ var templ_7745c5c3_Var101 string
2069+ templ_7745c5c3_Var101, templ_7745c5c3_Err = templ.JoinStringErrs(p.ChecksSum.Title)
2070+ if templ_7745c5c3_Err != nil {
2071+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 381, Col: 26}
2072+ }
2073+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var101))
2074+ if templ_7745c5c3_Err != nil {
2075+ return templ_7745c5c3_Err
2076+ }
2077+ } else {
2078+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 189, "no checks")
2079+ if templ_7745c5c3_Err != nil {
2080+ return templ_7745c5c3_Err
2081+ }
2082+ }
2083+ 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 {2084 if templ_7745c5c3_Err != nil {
2128 return templ_7745c5c3_Err2085 return templ_7745c5c3_Err
2129 }2086 }
2130 for _, c := range p.Commits {2087 for _, c := range p.Commits {
2131- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 198, "<li")2088+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 191, "<tr")
2132 if templ_7745c5c3_Err != nil {2089 if templ_7745c5c3_Err != nil {
2133 return templ_7745c5c3_Err2090 return templ_7745c5c3_Err
2134 }2091 }
2135 if c.New {2092 if c.New {
2136- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 199, " data-new")2093+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 192, " data-new")
2137 if templ_7745c5c3_Err != nil {2094 if templ_7745c5c3_Err != nil {
2138 return templ_7745c5c3_Err2095 return templ_7745c5c3_Err
2139 }2096 }
2140 }2097 }
2141- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 200, "><a href=\"")2098+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 193, "><td><a href=\"")
2142 if templ_7745c5c3_Err != nil {2099 if templ_7745c5c3_Err != nil {
2143 return templ_7745c5c3_Err2100 return templ_7745c5c3_Err
2144 }2101 }
2145- var templ_7745c5c3_Var103 templ.SafeURL2102+ var templ_7745c5c3_Var102 templ.SafeURL
2146- templ_7745c5c3_Var103, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Href))2103+ templ_7745c5c3_Var102, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Href))
2147 if templ_7745c5c3_Err != nil {2104 if templ_7745c5c3_Err != nil {
2148- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 400, Col: 36}2105+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 394, Col: 43}
2149 }2106 }
2150- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var103))2107+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var102))
2151 if templ_7745c5c3_Err != nil {2108 if templ_7745c5c3_Err != nil {
2152 return templ_7745c5c3_Err2109 return templ_7745c5c3_Err
2153 }2110 }
2154- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 201, "\">")2111+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 194, "\">")
2155 if templ_7745c5c3_Err != nil {2112 if templ_7745c5c3_Err != nil {
2156 return templ_7745c5c3_Err2113 return templ_7745c5c3_Err
2157 }2114 }
2158- var templ_7745c5c3_Var104 string2115+ var templ_7745c5c3_Var103 string
2159- templ_7745c5c3_Var104, templ_7745c5c3_Err = templ.JoinStringErrs(c.Short)2116+ templ_7745c5c3_Var103, templ_7745c5c3_Err = templ.JoinStringErrs(c.Short)
2160 if templ_7745c5c3_Err != nil {2117 if templ_7745c5c3_Err != nil {
2161- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 400, Col: 48}2118+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 394, Col: 55}
2162 }2119 }
2163- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var104))2120+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var103))
2164 if templ_7745c5c3_Err != nil {2121 if templ_7745c5c3_Err != nil {
2165 return templ_7745c5c3_Err2122 return templ_7745c5c3_Err
2166 }2123 }
2167- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 202, "</a> <span class=\"s\">")2124+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 195, "</a></td><td>")
2168 if templ_7745c5c3_Err != nil {2125 if templ_7745c5c3_Err != nil {
2169 return templ_7745c5c3_Err2126 return templ_7745c5c3_Err
2170 }2127 }
2171- var templ_7745c5c3_Var105 string2128+ var templ_7745c5c3_Var104 string
2172- templ_7745c5c3_Var105, templ_7745c5c3_Err = templ.JoinStringErrs(c.Subject)2129+ templ_7745c5c3_Var104, templ_7745c5c3_Err = templ.JoinStringErrs(c.Subject)
2173 if templ_7745c5c3_Err != nil {2130 if templ_7745c5c3_Err != nil {
2174- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 401, Col: 32}2131+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 395, Col: 23}
2175 }2132 }
2176- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var105))2133+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var104))
2177 if templ_7745c5c3_Err != nil {2134 if templ_7745c5c3_Err != nil {
2178 return templ_7745c5c3_Err2135 return templ_7745c5c3_Err
2179 }2136 }
2180- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 203, "</span> ")2137+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 196, "</td><td>")
2181 if templ_7745c5c3_Err != nil {2138 if templ_7745c5c3_Err != nil {
2182 return templ_7745c5c3_Err2139 return templ_7745c5c3_Err
2183 }2140 }
2184- if c.Sig != nil {2141+ var templ_7745c5c3_Var105 string
2185- templ_7745c5c3_Err = signaturePill(c.Sig).Render(ctx, templ_7745c5c3_Buffer)2142+ 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 {2143 if templ_7745c5c3_Err != nil {
2197- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 406, Col: 16}2144+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 396, Col: 22}
2198 }2145 }
2199- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var106))2146+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var105))
2200 if templ_7745c5c3_Err != nil {2147 if templ_7745c5c3_Err != nil {
2201 return templ_7745c5c3_Err2148 return templ_7745c5c3_Err
2202 }2149 }
2203- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 205, " ")2150+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 197, "</td><td>")
2204 if templ_7745c5c3_Err != nil {2151 if templ_7745c5c3_Err != nil {
2205 return templ_7745c5c3_Err2152 return templ_7745c5c3_Err
2206 }2153 }
2207 if c.WhenAt != "" {2154 if c.WhenAt != "" {
2208- var templ_7745c5c3_Var107 string2155+ 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 {2156 if templ_7745c5c3_Err != nil {
2215 return templ_7745c5c3_Err2157 return templ_7745c5c3_Err
2216 }2158 }
2217- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 206, "<time datetime=\"")2159+ var templ_7745c5c3_Var106 string
2160+ templ_7745c5c3_Var106, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)
2218 if templ_7745c5c3_Err != nil {2161 if templ_7745c5c3_Err != nil {
2219- return templ_7745c5c3_Err2162+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 399, Col: 35}
2220 }2163 }
2221- var templ_7745c5c3_Var108 string2164+ _, 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 {2165 if templ_7745c5c3_Err != nil {
2228 return templ_7745c5c3_Err2166 return templ_7745c5c3_Err
2229 }2167 }
2230- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 207, "\">")2168+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 199, "\">")
2231 if templ_7745c5c3_Err != nil {2169 if templ_7745c5c3_Err != nil {
2232 return templ_7745c5c3_Err2170 return templ_7745c5c3_Err
2233 }2171 }
2234- var templ_7745c5c3_Var109 string2172+ var templ_7745c5c3_Var107 string
2235- templ_7745c5c3_Var109, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)2173+ templ_7745c5c3_Var107, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)
2236 if templ_7745c5c3_Err != nil {2174 if templ_7745c5c3_Err != nil {
2237- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 408, Col: 53}2175+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 399, Col: 46}
2238 }2176 }
2239- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var109))2177+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var107))
2240 if templ_7745c5c3_Err != nil {2178 if templ_7745c5c3_Err != nil {
2241 return templ_7745c5c3_Err2179 return templ_7745c5c3_Err
2242 }2180 }
2243- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 208, "</time> ")2181+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 200, "</time>")
2244 if templ_7745c5c3_Err != nil {2182 if templ_7745c5c3_Err != nil {
2245 return templ_7745c5c3_Err2183 return templ_7745c5c3_Err
2246 }2184 }
2247 }2185 }
2248- if c.New {2186+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 201, "</td><td>")
2249- var templ_7745c5c3_Var110 string2187+ if templ_7745c5c3_Err != nil {
2250- templ_7745c5c3_Var110, templ_7745c5c3_Err = templ.JoinStringErrs(" · new")2188+ return templ_7745c5c3_Err
2189+ }
2190+ if c.Sig != nil {
2191+ templ_7745c5c3_Err = signaturePill(c.Sig).Render(ctx, templ_7745c5c3_Buffer)
2251 if templ_7745c5c3_Err != nil {2192 if templ_7745c5c3_Err != nil {
2252- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 411, Col: 18}2193+ return templ_7745c5c3_Err
2253 }2194 }
2254- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var110))2195+ }
2196+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 202, "</td><td>")
2197+ if templ_7745c5c3_Err != nil {
2198+ return templ_7745c5c3_Err
2199+ }
2200+ if c.New {
2201+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 203, "<span>new</span>")
2255 if templ_7745c5c3_Err != nil {2202 if templ_7745c5c3_Err != nil {
2256 return templ_7745c5c3_Err2203 return templ_7745c5c3_Err
2257 }2204 }
2258 }2205 }
2259- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 209, "</span></li>")2206+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 204, "</td></tr>")
2260 if templ_7745c5c3_Err != nil {2207 if templ_7745c5c3_Err != nil {
2261 return templ_7745c5c3_Err2208 return templ_7745c5c3_Err
2262 }2209 }
2263 }2210 }
2264- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 210, "</ul>")2211+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 205, "</tbody></table>")
2265 if templ_7745c5c3_Err != nil {2212 if templ_7745c5c3_Err != nil {
2266 return templ_7745c5c3_Err2213 return templ_7745c5c3_Err
2267 }2214 }
2268 if len(p.Commits) == 0 {2215 if len(p.Commits) == 0 {
2269- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 211, "<p class=\"dim\">no commit to merge.</p>")2216+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 206, "<p class=\"dim\">no commit to merge.</p>")
2270 if templ_7745c5c3_Err != nil {2217 if templ_7745c5c3_Err != nil {
2271 return templ_7745c5c3_Err2218 return templ_7745c5c3_Err
2272 }2219 }
2273 }2220 }
2274 if p.CommitsNote != "" {2221 if p.CommitsNote != "" {
2275- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 212, "<p class=\"note\">")2222+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 207, "<p class=\"note\">")
2276 if templ_7745c5c3_Err != nil {2223 if templ_7745c5c3_Err != nil {
2277 return templ_7745c5c3_Err2224 return templ_7745c5c3_Err
2278 }2225 }
2279- var templ_7745c5c3_Var111 string2226+ var templ_7745c5c3_Var108 string
2280- templ_7745c5c3_Var111, templ_7745c5c3_Err = templ.JoinStringErrs(p.CommitsNote)2227+ templ_7745c5c3_Var108, templ_7745c5c3_Err = templ.JoinStringErrs(p.CommitsNote)
2281 if templ_7745c5c3_Err != nil {2228 if templ_7745c5c3_Err != nil {
2282- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 421, Col: 34}2229+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 420, Col: 36}
2283 }2230 }
2284- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var111))2231+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var108))
2285 if templ_7745c5c3_Err != nil {2232 if templ_7745c5c3_Err != nil {
2286 return templ_7745c5c3_Err2233 return templ_7745c5c3_Err
2287 }2234 }
2288- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 213, "</p>")2235+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 208, "</p>")
2289 if templ_7745c5c3_Err != nil {2236 if templ_7745c5c3_Err != nil {
2290 return templ_7745c5c3_Err2237 return templ_7745c5c3_Err
2291 }2238 }
2292 }2239 }
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>")2240+ 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 {2241 if templ_7745c5c3_Err != nil {
2295 return templ_7745c5c3_Err2242 return templ_7745c5c3_Err
2296 }2243 }
2297- var templ_7745c5c3_Var112 string2244+ 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 {2245 if templ_7745c5c3_Err != nil {
2300- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 428, Col: 36}2246+ return templ_7745c5c3_Err
2247+ }
2248+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 210, "</div></details></footer>")
2249+ if templ_7745c5c3_Err != nil {
2250+ return templ_7745c5c3_Err
2251+ }
2252+ return nil
2253+ })
2254+}
2255+
2256+func mrRail(p MRPage) templ.Component {
2257+ return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
2258+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
2259+ if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
2260+ return templ_7745c5c3_CtxErr
2301 }2261 }
2302- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var112))2262+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
2263+ if !templ_7745c5c3_IsBuffer {
2264+ defer func() {
2265+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
2266+ if templ_7745c5c3_Err == nil {
2267+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
2268+ }
2269+ }()
2270+ }
2271+ ctx = templ.InitializeContext(ctx)
2272+ templ_7745c5c3_Var109 := templ.GetChildren(ctx)
2273+ if templ_7745c5c3_Var109 == nil {
2274+ templ_7745c5c3_Var109 = templ.NopComponent
2275+ }
2276+ ctx = templ.ClearChildren(ctx)
2277+ 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 {2278 if templ_7745c5c3_Err != nil {
2304 return templ_7745c5c3_Err2279 return templ_7745c5c3_Err
2305 }2280 }
2306- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 215, "</dd><dt>checks</dt><dd>")2281+ var templ_7745c5c3_Var110 string
2282+ templ_7745c5c3_Var110, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))
2283+ if templ_7745c5c3_Err != nil {
2284+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 433, Col: 49}
2285+ }
2286+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var110))
2307 if templ_7745c5c3_Err != nil {2287 if templ_7745c5c3_Err != nil {
2308 return templ_7745c5c3_Err2288 return templ_7745c5c3_Err
2309 }2289 }
2310- if p.ChecksBlock {2290+ 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")2291+ if templ_7745c5c3_Err != nil {
2292+ return templ_7745c5c3_Err
2293+ }
2294+ templ_7745c5c3_Err = FileList(p.Files).Render(ctx, templ_7745c5c3_Buffer)
2295+ if templ_7745c5c3_Err != nil {
2296+ return templ_7745c5c3_Err
2297+ }
2298+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 213, "</section>")
2299+ if templ_7745c5c3_Err != nil {
2300+ return templ_7745c5c3_Err
2301+ }
2302+ if len(p.Verdicts) > 0 {
2303+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 214, "<section><h2>Verdicts</h2><ul>")
2312 if templ_7745c5c3_Err != nil {2304 if templ_7745c5c3_Err != nil {
2313 return templ_7745c5c3_Err2305 return templ_7745c5c3_Err
2314 }2306 }
2315- } else {2307+ for _, v := range p.Verdicts {
2316- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 217, "do not block the merge")2308+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 215, "<li><a href=\"")
2309+ if templ_7745c5c3_Err != nil {
2310+ return templ_7745c5c3_Err
2311+ }
2312+ var templ_7745c5c3_Var111 templ.SafeURL
2313+ templ_7745c5c3_Var111, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(v.Href))
2314+ if templ_7745c5c3_Err != nil {
2315+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 446, Col: 37}
2316+ }
2317+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var111))
2318+ if templ_7745c5c3_Err != nil {
2319+ return templ_7745c5c3_Err
2320+ }
2321+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 216, "\">")
2322+ if templ_7745c5c3_Err != nil {
2323+ return templ_7745c5c3_Err
2324+ }
2325+ var templ_7745c5c3_Var112 string
2326+ templ_7745c5c3_Var112, templ_7745c5c3_Err = templ.JoinStringErrs(v.Author)
2327+ if templ_7745c5c3_Err != nil {
2328+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 446, Col: 50}
2329+ }
2330+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var112))
2331+ if templ_7745c5c3_Err != nil {
2332+ return templ_7745c5c3_Err
2333+ }
2334+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 217, ": ")
2335+ if templ_7745c5c3_Err != nil {
2336+ return templ_7745c5c3_Err
2337+ }
2338+ var templ_7745c5c3_Var113 string
2339+ templ_7745c5c3_Var113, templ_7745c5c3_Err = templ.JoinStringErrs(v.Label)
2340+ if templ_7745c5c3_Err != nil {
2341+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 446, Col: 63}
2342+ }
2343+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var113))
2344+ if templ_7745c5c3_Err != nil {
2345+ return templ_7745c5c3_Err
2346+ }
2347+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 218, "</a> ")
2348+ if templ_7745c5c3_Err != nil {
2349+ return templ_7745c5c3_Err
2350+ }
2351+ if v.Stale {
2352+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 219, "<span class=\"mute\">(stale)</span>")
2353+ if templ_7745c5c3_Err != nil {
2354+ return templ_7745c5c3_Err
2355+ }
2356+ }
2357+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 220, "</li>")
2358+ if templ_7745c5c3_Err != nil {
2359+ return templ_7745c5c3_Err
2360+ }
2361+ }
2362+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 221, "</ul></section>")
2317 if templ_7745c5c3_Err != nil {2363 if templ_7745c5c3_Err != nil {
2318 return templ_7745c5c3_Err2364 return templ_7745c5c3_Err
2319 }2365 }
2320 }2366 }
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 nil2367 return nil
2326 })2368 })
2327 }2369 }
@@ -2346,51 +2388,51 @@ func mrBar(p MRPage) templ.Component {
2346 }()2388 }()
2347 }2389 }
2348 ctx = templ.InitializeContext(ctx)2390 ctx = templ.InitializeContext(ctx)
2349- templ_7745c5c3_Var113 := templ.GetChildren(ctx)2391+ templ_7745c5c3_Var114 := templ.GetChildren(ctx)
2350- if templ_7745c5c3_Var113 == nil {2392+ if templ_7745c5c3_Var114 == nil {
2351- templ_7745c5c3_Var113 = templ.NopComponent2393+ templ_7745c5c3_Var114 = templ.NopComponent
2352 }2394 }
2353 ctx = templ.ClearChildren(ctx)2395 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\">")2396+ 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 {2397 if templ_7745c5c3_Err != nil {
2356 return templ_7745c5c3_Err2398 return templ_7745c5c3_Err
2357 }2399 }
2358- var templ_7745c5c3_Var114 string2400+ var templ_7745c5c3_Var115 string
2359- templ_7745c5c3_Var114, templ_7745c5c3_Err = templ.JoinStringErrs(plural(p.NFiles, "file", "files"))2401+ templ_7745c5c3_Var115, templ_7745c5c3_Err = templ.JoinStringErrs(plural(p.NFiles, "file", "files"))
2360 if templ_7745c5c3_Err != nil {2402 if templ_7745c5c3_Err != nil {
2361- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 447, Col: 55}2403+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 463, Col: 55}
2362 }2404 }
2363- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var114))2405+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var115))
2364 if templ_7745c5c3_Err != nil {2406 if templ_7745c5c3_Err != nil {
2365 return templ_7745c5c3_Err2407 return templ_7745c5c3_Err
2366 }2408 }
2367- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 220, " · <span class=\"plus\">+")2409+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 223, " · <span class=\"plus\">+")
2368 if templ_7745c5c3_Err != nil {2410 if templ_7745c5c3_Err != nil {
2369 return templ_7745c5c3_Err2411 return templ_7745c5c3_Err
2370 }2412 }
2371- var templ_7745c5c3_Var115 string2413+ var templ_7745c5c3_Var116 string
2372- templ_7745c5c3_Var115, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Adds))2414+ templ_7745c5c3_Var116, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Adds))
2373 if templ_7745c5c3_Err != nil {2415 if templ_7745c5c3_Err != nil {
2374- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 447, Col: 95}2416+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 463, Col: 95}
2375 }2417 }
2376- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var115))2418+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var116))
2377 if templ_7745c5c3_Err != nil {2419 if templ_7745c5c3_Err != nil {
2378 return templ_7745c5c3_Err2420 return templ_7745c5c3_Err
2379 }2421 }
2380- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 221, "</span> <span class=\"minus\">-")2422+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 224, "</span> <span class=\"minus\">-")
2381 if templ_7745c5c3_Err != nil {2423 if templ_7745c5c3_Err != nil {
2382 return templ_7745c5c3_Err2424 return templ_7745c5c3_Err
2383 }2425 }
2384- var templ_7745c5c3_Var116 string2426+ var templ_7745c5c3_Var117 string
2385- templ_7745c5c3_Var116, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Dels))2427+ templ_7745c5c3_Var117, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Dels))
2386 if templ_7745c5c3_Err != nil {2428 if templ_7745c5c3_Err != nil {
2387- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 447, Col: 140}2429+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 463, Col: 140}
2388 }2430 }
2389- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var116))2431+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var117))
2390 if templ_7745c5c3_Err != nil {2432 if templ_7745c5c3_Err != nil {
2391 return templ_7745c5c3_Err2433 return templ_7745c5c3_Err
2392 }2434 }
2393- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 222, "</span></span>")2435+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 225, "</span></span>")
2394 if templ_7745c5c3_Err != nil {2436 if templ_7745c5c3_Err != nil {
2395 return templ_7745c5c3_Err2437 return templ_7745c5c3_Err
2396 }2438 }
@@ -2398,7 +2440,7 @@ func mrBar(p MRPage) templ.Component {
2398 if templ_7745c5c3_Err != nil {2440 if templ_7745c5c3_Err != nil {
2399 return templ_7745c5c3_Err2441 return templ_7745c5c3_Err
2400 }2442 }
2401- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 223, "<span class=\"grow\"></span>")2443+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 226, "<span class=\"grow\"></span>")
2402 if templ_7745c5c3_Err != nil {2444 if templ_7745c5c3_Err != nil {
2403 return templ_7745c5c3_Err2445 return templ_7745c5c3_Err
2404 }2446 }
@@ -2411,16 +2453,12 @@ func mrBar(p MRPage) templ.Component {
2411 if templ_7745c5c3_Err != nil {2453 if templ_7745c5c3_Err != nil {
2412 return templ_7745c5c3_Err2454 return templ_7745c5c3_Err
2413 }2455 }
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 }2456 }
2423- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 225, "</div>")2457+ templ_7745c5c3_Err = moreMenu(p).Render(ctx, templ_7745c5c3_Buffer)
2458+ if templ_7745c5c3_Err != nil {
2459+ return templ_7745c5c3_Err
2460+ }
2461+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 227, "</div>")
2424 if templ_7745c5c3_Err != nil {2462 if templ_7745c5c3_Err != nil {
2425 return templ_7745c5c3_Err2463 return templ_7745c5c3_Err
2426 }2464 }
@@ -2452,84 +2490,57 @@ func mergeMenu(p MRPage) templ.Component {
2452 }()2490 }()
2453 }2491 }
2454 ctx = templ.InitializeContext(ctx)2492 ctx = templ.InitializeContext(ctx)
2455- templ_7745c5c3_Var117 := templ.GetChildren(ctx)2493+ templ_7745c5c3_Var118 := templ.GetChildren(ctx)
2456- if templ_7745c5c3_Var117 == nil {2494+ if templ_7745c5c3_Var118 == nil {
2457- templ_7745c5c3_Var117 = templ.NopComponent2495+ templ_7745c5c3_Var118 = templ.NopComponent
2458 }2496 }
2459 ctx = templ.ClearChildren(ctx)2497 ctx = templ.ClearChildren(ctx)
2460- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 226, "<details class=\"menu mmenu\" id=\"merge-menu\" data-state=\"open\"")2498+ 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 {2499 if templ_7745c5c3_Err != nil {
2462 return templ_7745c5c3_Err2500 return templ_7745c5c3_Err
2463 }2501 }
2464 if p.Box.Error != "" {2502 if p.Box.Error != "" {
2465- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 227, " open")2503+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 229, " open")
2466 if templ_7745c5c3_Err != nil {2504 if templ_7745c5c3_Err != nil {
2467 return templ_7745c5c3_Err2505 return templ_7745c5c3_Err
2468 }2506 }
2469 }2507 }
2470- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 228, "><summary class=\"btn primary\" aria-keyshortcuts=\"Shift+M\">")2508+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 230, "><summary class=\"btn primary\" aria-keyshortcuts=\"Shift+M\">")
2471 if templ_7745c5c3_Err != nil {2509 if templ_7745c5c3_Err != nil {
2472 return templ_7745c5c3_Err2510 return templ_7745c5c3_Err
2473 }2511 }
2474 if p.Box.ReadyAction != "" {2512 if p.Box.ReadyAction != "" {
2475- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 229, "Draft ")2513+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 231, "Draft ")
2476 if templ_7745c5c3_Err != nil {2514 if templ_7745c5c3_Err != nil {
2477 return templ_7745c5c3_Err2515 return templ_7745c5c3_Err
2478 }2516 }
2479 } else {2517 } else {
2480- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 230, "Merge ")2518+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 232, "Merge ")
2481 if templ_7745c5c3_Err != nil {2519 if templ_7745c5c3_Err != nil {
2482 return templ_7745c5c3_Err2520 return templ_7745c5c3_Err
2483 }2521 }
2484 }2522 }
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>")2523+ 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 {2524 if templ_7745c5c3_Err != nil {
2487 return templ_7745c5c3_Err2525 return templ_7745c5c3_Err
2488 }2526 }
2489 if p.Box.HeadGone {2527 if p.Box.HeadGone {
2490- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 232, "gone: the source branch was deleted")2528+ 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 {2529 if templ_7745c5c3_Err != nil {
2502 return templ_7745c5c3_Err2530 return templ_7745c5c3_Err
2503 }2531 }
2504 }2532 }
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 != "" {2533 if p.Box.Error != "" {
2523 templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 235, "<p class=\"d-err\" role=\"alert\">")2534 templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 235, "<p class=\"d-err\" role=\"alert\">")
2524 if templ_7745c5c3_Err != nil {2535 if templ_7745c5c3_Err != nil {
2525 return templ_7745c5c3_Err2536 return templ_7745c5c3_Err
2526 }2537 }
2527- var templ_7745c5c3_Var120 string2538+ var templ_7745c5c3_Var119 string
2528- templ_7745c5c3_Var120, templ_7745c5c3_Err = templ.JoinStringErrs(p.Box.Error)2539+ templ_7745c5c3_Var119, templ_7745c5c3_Err = templ.JoinStringErrs(p.Box.Error)
2529 if templ_7745c5c3_Err != nil {2540 if templ_7745c5c3_Err != nil {
2530- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 490, Col: 47}2541+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 497, Col: 47}
2531 }2542 }
2532- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var120))2543+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var119))
2533 if templ_7745c5c3_Err != nil {2544 if templ_7745c5c3_Err != nil {
2534 return templ_7745c5c3_Err2545 return templ_7745c5c3_Err
2535 }2546 }
@@ -2543,12 +2554,12 @@ func mergeMenu(p MRPage) templ.Component {
2543 if templ_7745c5c3_Err != nil {2554 if templ_7745c5c3_Err != nil {
2544 return templ_7745c5c3_Err2555 return templ_7745c5c3_Err
2545 }2556 }
2546- var templ_7745c5c3_Var121 templ.SafeURL2557+ var templ_7745c5c3_Var120 templ.SafeURL
2547- templ_7745c5c3_Var121, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.ReadyAction))2558+ templ_7745c5c3_Var120, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.ReadyAction))
2548 if templ_7745c5c3_Err != nil {2559 if templ_7745c5c3_Err != nil {
2549- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 494, Col: 80}2560+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 501, Col: 80}
2550 }2561 }
2551- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var121))2562+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var120))
2552 if templ_7745c5c3_Err != nil {2563 if templ_7745c5c3_Err != nil {
2553 return templ_7745c5c3_Err2564 return templ_7745c5c3_Err
2554 }2565 }
@@ -2565,12 +2576,12 @@ func mergeMenu(p MRPage) templ.Component {
2565 if templ_7745c5c3_Err != nil {2576 if templ_7745c5c3_Err != nil {
2566 return templ_7745c5c3_Err2577 return templ_7745c5c3_Err
2567 }2578 }
2568- var templ_7745c5c3_Var122 templ.SafeURL2579+ var templ_7745c5c3_Var121 templ.SafeURL
2569- templ_7745c5c3_Var122, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.MergeAction))2580+ templ_7745c5c3_Var121, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.MergeAction))
2570 if templ_7745c5c3_Err != nil {2581 if templ_7745c5c3_Err != nil {
2571- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 499, Col: 80}2582+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 506, Col: 80}
2572 }2583 }
2573- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var122))2584+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var121))
2574 if templ_7745c5c3_Err != nil {2585 if templ_7745c5c3_Err != nil {
2575 return templ_7745c5c3_Err2586 return templ_7745c5c3_Err
2576 }2587 }
@@ -2578,12 +2589,12 @@ func mergeMenu(p MRPage) templ.Component {
2578 if templ_7745c5c3_Err != nil {2589 if templ_7745c5c3_Err != nil {
2579 return templ_7745c5c3_Err2590 return templ_7745c5c3_Err
2580 }2591 }
2581- var templ_7745c5c3_Var123 string2592+ var templ_7745c5c3_Var122 string
2582- templ_7745c5c3_Var123, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.Head)2593+ templ_7745c5c3_Var122, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.Head)
2583 if templ_7745c5c3_Err != nil {2594 if templ_7745c5c3_Err != nil {
2584- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 500, Col: 59}2595+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 507, Col: 59}
2585 }2596 }
2586- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var123)2597+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var122)
2587 if templ_7745c5c3_Err != nil {2598 if templ_7745c5c3_Err != nil {
2588 return templ_7745c5c3_Err2599 return templ_7745c5c3_Err
2589 }2600 }
@@ -2596,12 +2607,12 @@ func mergeMenu(p MRPage) templ.Component {
2596 if templ_7745c5c3_Err != nil {2607 if templ_7745c5c3_Err != nil {
2597 return templ_7745c5c3_Err2608 return templ_7745c5c3_Err
2598 }2609 }
2599- var templ_7745c5c3_Var124 string2610+ var templ_7745c5c3_Var123 string
2600- templ_7745c5c3_Var124, templ_7745c5c3_Err = templ.ResolveAttributeValue(m.Value)2611+ templ_7745c5c3_Var123, templ_7745c5c3_Err = templ.ResolveAttributeValue(m.Value)
2601 if templ_7745c5c3_Err != nil {2612 if templ_7745c5c3_Err != nil {
2602- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 508, Col: 24}2613+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 515, Col: 24}
2603 }2614 }
2604- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var124)2615+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var123)
2605 if templ_7745c5c3_Err != nil {2616 if templ_7745c5c3_Err != nil {
2606 return templ_7745c5c3_Err2617 return templ_7745c5c3_Err
2607 }2618 }
@@ -2625,12 +2636,12 @@ func mergeMenu(p MRPage) templ.Component {
2625 if templ_7745c5c3_Err != nil {2636 if templ_7745c5c3_Err != nil {
2626 return templ_7745c5c3_Err2637 return templ_7745c5c3_Err
2627 }2638 }
2628- var templ_7745c5c3_Var125 string2639+ var templ_7745c5c3_Var124 string
2629- templ_7745c5c3_Var125, templ_7745c5c3_Err = templ.ResolveAttributeValue(m.Reason)2640+ templ_7745c5c3_Var124, templ_7745c5c3_Err = templ.ResolveAttributeValue(m.Reason)
2630 if templ_7745c5c3_Err != nil {2641 if templ_7745c5c3_Err != nil {
2631- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 511, Col: 25}2642+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 518, Col: 25}
2632 }2643 }
2633- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var125)2644+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var124)
2634 if templ_7745c5c3_Err != nil {2645 if templ_7745c5c3_Err != nil {
2635 return templ_7745c5c3_Err2646 return templ_7745c5c3_Err
2636 }2647 }
@@ -2638,12 +2649,12 @@ func mergeMenu(p MRPage) templ.Component {
2638 if templ_7745c5c3_Err != nil {2649 if templ_7745c5c3_Err != nil {
2639 return templ_7745c5c3_Err2650 return templ_7745c5c3_Err
2640 }2651 }
2641- var templ_7745c5c3_Var126 string2652+ var templ_7745c5c3_Var125 string
2642- templ_7745c5c3_Var126, templ_7745c5c3_Err = templ.JoinStringErrs(m.Label)2653+ templ_7745c5c3_Var125, templ_7745c5c3_Err = templ.JoinStringErrs(m.Label)
2643 if templ_7745c5c3_Err != nil {2654 if templ_7745c5c3_Err != nil {
2644- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 515, Col: 17}2655+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 522, Col: 17}
2645 }2656 }
2646- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var126))2657+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var125))
2647 if templ_7745c5c3_Err != nil {2658 if templ_7745c5c3_Err != nil {
2648 return templ_7745c5c3_Err2659 return templ_7745c5c3_Err
2649 }2660 }
@@ -2656,12 +2667,12 @@ func mergeMenu(p MRPage) templ.Component {
2656 if templ_7745c5c3_Err != nil {2667 if templ_7745c5c3_Err != nil {
2657 return templ_7745c5c3_Err2668 return templ_7745c5c3_Err
2658 }2669 }
2659- var templ_7745c5c3_Var127 string2670+ var templ_7745c5c3_Var126 string
2660- templ_7745c5c3_Var127, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(i + 1))2671+ templ_7745c5c3_Var126, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(i + 1))
2661 if templ_7745c5c3_Err != nil {2672 if templ_7745c5c3_Err != nil {
2662- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 517, Col: 46}2673+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 524, Col: 46}
2663 }2674 }
2664- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var127))2675+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var126))
2665 if templ_7745c5c3_Err != nil {2676 if templ_7745c5c3_Err != nil {
2666 return templ_7745c5c3_Err2677 return templ_7745c5c3_Err
2667 }2678 }
@@ -2679,96 +2690,67 @@ func mergeMenu(p MRPage) templ.Component {
2679 if templ_7745c5c3_Err != nil {2690 if templ_7745c5c3_Err != nil {
2680 return templ_7745c5c3_Err2691 return templ_7745c5c3_Err
2681 }2692 }
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 {2693 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 ")2694+ 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 {2695 if templ_7745c5c3_Err != nil {
2714 return templ_7745c5c3_Err2696 return templ_7745c5c3_Err
2715 }2697 }
2716- var templ_7745c5c3_Var129 string2698+ var templ_7745c5c3_Var127 string
2717- templ_7745c5c3_Var129, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)2699+ templ_7745c5c3_Var127, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)
2718 if templ_7745c5c3_Err != nil {2700 if templ_7745c5c3_Err != nil {
2719- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 532, Col: 102}2701+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 530, Col: 102}
2720 }2702 }
2721- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var129))2703+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var127))
2722 if templ_7745c5c3_Err != nil {2704 if templ_7745c5c3_Err != nil {
2723 return templ_7745c5c3_Err2705 return templ_7745c5c3_Err
2724 }2706 }
2725- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 258, " after the merge <kbd aria-hidden=\"true\">D</kbd></label>")2707+ 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 {2708 if templ_7745c5c3_Err != nil {
2727 return templ_7745c5c3_Err2709 return templ_7745c5c3_Err
2728 }2710 }
2729 }2711 }
2730- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 259, "<div class=\"d-btns\"><button type=\"submit\" class=\"btn primary\" data-default")2712+ 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 {2713 if templ_7745c5c3_Err != nil {
2732 return templ_7745c5c3_Err2714 return templ_7745c5c3_Err
2733 }2715 }
2734 if !p.Box.CanMerge() {2716 if !p.Box.CanMerge() {
2735- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 260, " disabled")2717+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 256, " disabled")
2736 if templ_7745c5c3_Err != nil {2718 if templ_7745c5c3_Err != nil {
2737 return templ_7745c5c3_Err2719 return templ_7745c5c3_Err
2738 }2720 }
2739 }2721 }
2740- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 261, " title=\"")2722+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 257, " title=\"")
2741 if templ_7745c5c3_Err != nil {2723 if templ_7745c5c3_Err != nil {
2742 return templ_7745c5c3_Err2724 return templ_7745c5c3_Err
2743 }2725 }
2744- var templ_7745c5c3_Var130 string2726+ var templ_7745c5c3_Var128 string
2745- templ_7745c5c3_Var130, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.MergeTitle())2727+ templ_7745c5c3_Var128, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.MergeTitle())
2746 if templ_7745c5c3_Err != nil {2728 if templ_7745c5c3_Err != nil {
2747- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 540, Col: 33}2729+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 538, Col: 33}
2748 }2730 }
2749- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var130)2731+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var128)
2750 if templ_7745c5c3_Err != nil {2732 if templ_7745c5c3_Err != nil {
2751 return templ_7745c5c3_Err2733 return templ_7745c5c3_Err
2752 }2734 }
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 ")2735+ 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 {2736 if templ_7745c5c3_Err != nil {
2755 return templ_7745c5c3_Err2737 return templ_7745c5c3_Err
2756 }2738 }
2757- var templ_7745c5c3_Var131 string2739+ var templ_7745c5c3_Var129 string
2758- templ_7745c5c3_Var131, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)2740+ templ_7745c5c3_Var129, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
2759 if templ_7745c5c3_Err != nil {2741 if templ_7745c5c3_Err != nil {
2760- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 543, Col: 28}2742+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 541, Col: 28}
2761 }2743 }
2762- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var131))2744+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var129))
2763 if templ_7745c5c3_Err != nil {2745 if templ_7745c5c3_Err != nil {
2764 return templ_7745c5c3_Err2746 return templ_7745c5c3_Err
2765 }2747 }
2766- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 263, "</button></div></form>")2748+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 259, "</button></div></form>")
2767 if templ_7745c5c3_Err != nil {2749 if templ_7745c5c3_Err != nil {
2768 return templ_7745c5c3_Err2750 return templ_7745c5c3_Err
2769 }2751 }
2770 }2752 }
2771- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 264, "</div></details>")2753+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 260, "</div></details>")
2772 if templ_7745c5c3_Err != nil {2754 if templ_7745c5c3_Err != nil {
2773 return templ_7745c5c3_Err2755 return templ_7745c5c3_Err
2774 }2756 }
@@ -2794,182 +2776,182 @@ func MRMergeability(v MergeabilityView) templ.Component {
2794 }()2776 }()
2795 }2777 }
2796 ctx = templ.InitializeContext(ctx)2778 ctx = templ.InitializeContext(ctx)
2797- templ_7745c5c3_Var132 := templ.GetChildren(ctx)2779+ templ_7745c5c3_Var130 := templ.GetChildren(ctx)
2798- if templ_7745c5c3_Var132 == nil {2780+ if templ_7745c5c3_Var130 == nil {
2799- templ_7745c5c3_Var132 = templ.NopComponent2781+ templ_7745c5c3_Var130 = templ.NopComponent
2800 }2782 }
2801 ctx = templ.ClearChildren(ctx)2783 ctx = templ.ClearChildren(ctx)
2802- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 265, "<span data-mergeability data-state=\"")2784+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 261, "<span data-mergeability data-state=\"")
2803 if templ_7745c5c3_Err != nil {2785 if templ_7745c5c3_Err != nil {
2804 return templ_7745c5c3_Err2786 return templ_7745c5c3_Err
2805 }2787 }
2806- var templ_7745c5c3_Var133 string2788+ var templ_7745c5c3_Var131 string
2807- templ_7745c5c3_Var133, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.State)2789+ templ_7745c5c3_Var131, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.State)
2808 if templ_7745c5c3_Err != nil {2790 if templ_7745c5c3_Err != nil {
2809- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 556, Col: 22}2791+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 554, Col: 22}
2810 }2792 }
2811- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var133)2793+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var131)
2812 if templ_7745c5c3_Err != nil {2794 if templ_7745c5c3_Err != nil {
2813 return templ_7745c5c3_Err2795 return templ_7745c5c3_Err
2814 }2796 }
2815- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 266, "\" data-ff-ok=\"")2797+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 262, "\" data-ff-ok=\"")
2816 if templ_7745c5c3_Err != nil {2798 if templ_7745c5c3_Err != nil {
2817 return templ_7745c5c3_Err2799 return templ_7745c5c3_Err
2818 }2800 }
2819- var templ_7745c5c3_Var134 string2801+ var templ_7745c5c3_Var132 string
2820- templ_7745c5c3_Var134, templ_7745c5c3_Err = templ.ResolveAttributeValue(strconv.FormatBool(v.FFOk))2802+ templ_7745c5c3_Var132, templ_7745c5c3_Err = templ.ResolveAttributeValue(strconv.FormatBool(v.FFOk))
2821 if templ_7745c5c3_Err != nil {2803 if templ_7745c5c3_Err != nil {
2822- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 557, Col: 41}2804+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 555, Col: 41}
2823 }2805 }
2824- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var134)2806+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var132)
2825 if templ_7745c5c3_Err != nil {2807 if templ_7745c5c3_Err != nil {
2826 return templ_7745c5c3_Err2808 return templ_7745c5c3_Err
2827 }2809 }
2828- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 267, "\" data-merge-ok=\"")2810+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 263, "\" data-merge-ok=\"")
2829 if templ_7745c5c3_Err != nil {2811 if templ_7745c5c3_Err != nil {
2830 return templ_7745c5c3_Err2812 return templ_7745c5c3_Err
2831 }2813 }
2832- var templ_7745c5c3_Var135 string2814+ var templ_7745c5c3_Var133 string
2833- templ_7745c5c3_Var135, templ_7745c5c3_Err = templ.ResolveAttributeValue(strconv.FormatBool(v.MergeOk))2815+ templ_7745c5c3_Var133, templ_7745c5c3_Err = templ.ResolveAttributeValue(strconv.FormatBool(v.MergeOk))
2834 if templ_7745c5c3_Err != nil {2816 if templ_7745c5c3_Err != nil {
2835- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 558, Col: 47}2817+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 556, Col: 47}
2836 }2818 }
2837- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var135)2819+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var133)
2838 if templ_7745c5c3_Err != nil {2820 if templ_7745c5c3_Err != nil {
2839 return templ_7745c5c3_Err2821 return templ_7745c5c3_Err
2840 }2822 }
2841- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 268, "\" data-ff-reason=\"")2823+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 264, "\" data-ff-reason=\"")
2842 if templ_7745c5c3_Err != nil {2824 if templ_7745c5c3_Err != nil {
2843 return templ_7745c5c3_Err2825 return templ_7745c5c3_Err
2844 }2826 }
2845- var templ_7745c5c3_Var136 string2827+ var templ_7745c5c3_Var134 string
2846- templ_7745c5c3_Var136, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.FFReason)2828+ templ_7745c5c3_Var134, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.FFReason)
2847 if templ_7745c5c3_Err != nil {2829 if templ_7745c5c3_Err != nil {
2848- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 559, Col: 29}2830+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 557, Col: 29}
2849 }2831 }
2850- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var136)2832+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var134)
2851 if templ_7745c5c3_Err != nil {2833 if templ_7745c5c3_Err != nil {
2852 return templ_7745c5c3_Err2834 return templ_7745c5c3_Err
2853 }2835 }
2854- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 269, "\" data-merge-reason=\"")2836+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 265, "\" data-merge-reason=\"")
2855 if templ_7745c5c3_Err != nil {2837 if templ_7745c5c3_Err != nil {
2856 return templ_7745c5c3_Err2838 return templ_7745c5c3_Err
2857 }2839 }
2858- var templ_7745c5c3_Var137 string2840+ var templ_7745c5c3_Var135 string
2859- templ_7745c5c3_Var137, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.MergeReason)2841+ templ_7745c5c3_Var135, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.MergeReason)
2860 if templ_7745c5c3_Err != nil {2842 if templ_7745c5c3_Err != nil {
2861- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 560, Col: 35}2843+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 558, Col: 35}
2862 }2844 }
2863- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var137)2845+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var135)
2864 if templ_7745c5c3_Err != nil {2846 if templ_7745c5c3_Err != nil {
2865 return templ_7745c5c3_Err2847 return templ_7745c5c3_Err
2866 }2848 }
2867- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 270, "\"><span class=\"badge\" data-state=\"")2849+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 266, "\"><span class=\"badge\" data-state=\"")
2868 if templ_7745c5c3_Err != nil {2850 if templ_7745c5c3_Err != nil {
2869 return templ_7745c5c3_Err2851 return templ_7745c5c3_Err
2870 }2852 }
2871- var templ_7745c5c3_Var138 string2853+ var templ_7745c5c3_Var136 string
2872- templ_7745c5c3_Var138, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.State)2854+ templ_7745c5c3_Var136, templ_7745c5c3_Err = templ.ResolveAttributeValue(v.State)
2873 if templ_7745c5c3_Err != nil {2855 if templ_7745c5c3_Err != nil {
2874- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 562, Col: 42}2856+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 560, Col: 42}
2875 }2857 }
2876- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var138)2858+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var136)
2877 if templ_7745c5c3_Err != nil {2859 if templ_7745c5c3_Err != nil {
2878 return templ_7745c5c3_Err2860 return templ_7745c5c3_Err
2879 }2861 }
2880- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 271, "\">")2862+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 267, "\">")
2881 if templ_7745c5c3_Err != nil {2863 if templ_7745c5c3_Err != nil {
2882 return templ_7745c5c3_Err2864 return templ_7745c5c3_Err
2883 }2865 }
2884- var templ_7745c5c3_Var139 string2866+ var templ_7745c5c3_Var137 string
2885- templ_7745c5c3_Var139, templ_7745c5c3_Err = templ.JoinStringErrs(v.Label)2867+ templ_7745c5c3_Var137, templ_7745c5c3_Err = templ.JoinStringErrs(v.Label)
2886 if templ_7745c5c3_Err != nil {2868 if templ_7745c5c3_Err != nil {
2887- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 562, Col: 54}2869+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 560, Col: 54}
2888 }2870 }
2889- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var139))2871+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var137))
2890 if templ_7745c5c3_Err != nil {2872 if templ_7745c5c3_Err != nil {
2891 return templ_7745c5c3_Err2873 return templ_7745c5c3_Err
2892 }2874 }
2893- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 272, "</span> ")2875+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 268, "</span> ")
2894 if templ_7745c5c3_Err != nil {2876 if templ_7745c5c3_Err != nil {
2895 return templ_7745c5c3_Err2877 return templ_7745c5c3_Err
2896 }2878 }
2897 if v.Detail != "" {2879 if v.Detail != "" {
2898- var templ_7745c5c3_Var140 string2880+ var templ_7745c5c3_Var138 string
2899- templ_7745c5c3_Var140, templ_7745c5c3_Err = templ.JoinStringErrs(" ")2881+ templ_7745c5c3_Var138, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
2900 if templ_7745c5c3_Err != nil {2882 if templ_7745c5c3_Err != nil {
2901- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 564, Col: 8}2883+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 562, Col: 8}
2902 }2884 }
2903- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var140))2885+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var138))
2904 if templ_7745c5c3_Err != nil {2886 if templ_7745c5c3_Err != nil {
2905 return templ_7745c5c3_Err2887 return templ_7745c5c3_Err
2906 }2888 }
2907- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 273, "<span class=\"dim\">")2889+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 269, "<span class=\"dim\">")
2908 if templ_7745c5c3_Err != nil {2890 if templ_7745c5c3_Err != nil {
2909 return templ_7745c5c3_Err2891 return templ_7745c5c3_Err
2910 }2892 }
2911- var templ_7745c5c3_Var141 string2893+ var templ_7745c5c3_Var139 string
2912- templ_7745c5c3_Var141, templ_7745c5c3_Err = templ.JoinStringErrs(v.Detail)2894+ templ_7745c5c3_Var139, templ_7745c5c3_Err = templ.JoinStringErrs(v.Detail)
2913 if templ_7745c5c3_Err != nil {2895 if templ_7745c5c3_Err != nil {
2914- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 564, Col: 38}2896+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 562, Col: 38}
2915 }2897 }
2916- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var141))2898+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var139))
2917 if templ_7745c5c3_Err != nil {2899 if templ_7745c5c3_Err != nil {
2918 return templ_7745c5c3_Err2900 return templ_7745c5c3_Err
2919 }2901 }
2920- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 274, "</span>")2902+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 270, "</span>")
2921 if templ_7745c5c3_Err != nil {2903 if templ_7745c5c3_Err != nil {
2922 return templ_7745c5c3_Err2904 return templ_7745c5c3_Err
2923 }2905 }
2924 }2906 }
2925- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 275, "</span> ")2907+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 271, "</span> ")
2926 if templ_7745c5c3_Err != nil {2908 if templ_7745c5c3_Err != nil {
2927 return templ_7745c5c3_Err2909 return templ_7745c5c3_Err
2928 }2910 }
2929 if len(v.Paths) > 0 {2911 if len(v.Paths) > 0 {
2930- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 276, "<ul class=\"mg-paths\" aria-label=\"conflicting files\">")2912+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 272, "<ul class=\"mg-paths\" aria-label=\"conflicting files\">")
2931 if templ_7745c5c3_Err != nil {2913 if templ_7745c5c3_Err != nil {
2932 return templ_7745c5c3_Err2914 return templ_7745c5c3_Err
2933 }2915 }
2934 for _, path := range v.Paths {2916 for _, path := range v.Paths {
2935- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 277, "<li><code>")2917+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 273, "<li><code>")
2936 if templ_7745c5c3_Err != nil {2918 if templ_7745c5c3_Err != nil {
2937 return templ_7745c5c3_Err2919 return templ_7745c5c3_Err
2938 }2920 }
2939- var templ_7745c5c3_Var142 string2921+ var templ_7745c5c3_Var140 string
2940- templ_7745c5c3_Var142, templ_7745c5c3_Err = templ.JoinStringErrs(path)2922+ templ_7745c5c3_Var140, templ_7745c5c3_Err = templ.JoinStringErrs(path)
2941 if templ_7745c5c3_Err != nil {2923 if templ_7745c5c3_Err != nil {
2942- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 570, Col: 20}2924+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 568, Col: 20}
2943 }2925 }
2944- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var142))2926+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var140))
2945 if templ_7745c5c3_Err != nil {2927 if templ_7745c5c3_Err != nil {
2946 return templ_7745c5c3_Err2928 return templ_7745c5c3_Err
2947 }2929 }
2948- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 278, "</code></li>")2930+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 274, "</code></li>")
2949 if templ_7745c5c3_Err != nil {2931 if templ_7745c5c3_Err != nil {
2950 return templ_7745c5c3_Err2932 return templ_7745c5c3_Err
2951 }2933 }
2952 }2934 }
2953- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 279, "</ul>")2935+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 275, "</ul>")
2954 if templ_7745c5c3_Err != nil {2936 if templ_7745c5c3_Err != nil {
2955 return templ_7745c5c3_Err2937 return templ_7745c5c3_Err
2956 }2938 }
2957 }2939 }
2958 if v.PathsNote != "" {2940 if v.PathsNote != "" {
2959- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 280, "<p class=\"dim\">")2941+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 276, "<p class=\"dim\">")
2960 if templ_7745c5c3_Err != nil {2942 if templ_7745c5c3_Err != nil {
2961 return templ_7745c5c3_Err2943 return templ_7745c5c3_Err
2962 }2944 }
2963- var templ_7745c5c3_Var143 string2945+ var templ_7745c5c3_Var141 string
2964- templ_7745c5c3_Var143, templ_7745c5c3_Err = templ.JoinStringErrs(v.PathsNote)2946+ templ_7745c5c3_Var141, templ_7745c5c3_Err = templ.JoinStringErrs(v.PathsNote)
2965 if templ_7745c5c3_Err != nil {2947 if templ_7745c5c3_Err != nil {
2966- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 575, Col: 30}2948+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 573, Col: 30}
2967 }2949 }
2968- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var143))2950+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var141))
2969 if templ_7745c5c3_Err != nil {2951 if templ_7745c5c3_Err != nil {
2970 return templ_7745c5c3_Err2952 return templ_7745c5c3_Err
2971 }2953 }
2972- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 281, "</p>")2954+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 277, "</p>")
2973 if templ_7745c5c3_Err != nil {2955 if templ_7745c5c3_Err != nil {
2974 return templ_7745c5c3_Err2956 return templ_7745c5c3_Err
2975 }2957 }
@@ -2996,12 +2978,12 @@ func mrMergeabilitySlot(v MergeabilityView) templ.Component {
2996 }()2978 }()
2997 }2979 }
2998 ctx = templ.InitializeContext(ctx)2980 ctx = templ.InitializeContext(ctx)
2999- templ_7745c5c3_Var144 := templ.GetChildren(ctx)2981+ templ_7745c5c3_Var142 := templ.GetChildren(ctx)
3000- if templ_7745c5c3_Var144 == nil {2982+ if templ_7745c5c3_Var142 == nil {
3001- templ_7745c5c3_Var144 = templ.NopComponent2983+ templ_7745c5c3_Var142 = templ.NopComponent
3002 }2984 }
3003 ctx = templ.ClearChildren(ctx)2985 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>")2986+ 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 {2987 if templ_7745c5c3_Err != nil {
3006 return templ_7745c5c3_Err2988 return templ_7745c5c3_Err
3007 }2989 }
@@ -3009,7 +2991,7 @@ func mrMergeabilitySlot(v MergeabilityView) templ.Component {
3009 if templ_7745c5c3_Err != nil {2991 if templ_7745c5c3_Err != nil {
3010 return templ_7745c5c3_Err2992 return templ_7745c5c3_Err
3011 }2993 }
3012- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 283, "</div>")2994+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 279, "</div>")
3013 if templ_7745c5c3_Err != nil {2995 if templ_7745c5c3_Err != nil {
3014 return templ_7745c5c3_Err2996 return templ_7745c5c3_Err
3015 }2997 }
@@ -3034,9 +3016,9 @@ func MRMergeabilityFragment(v MergeabilityView) templ.Component {
3034 }()3016 }()
3035 }3017 }
3036 ctx = templ.InitializeContext(ctx)3018 ctx = templ.InitializeContext(ctx)
3037- templ_7745c5c3_Var145 := templ.GetChildren(ctx)3019+ templ_7745c5c3_Var143 := templ.GetChildren(ctx)
3038- if templ_7745c5c3_Var145 == nil {3020+ if templ_7745c5c3_Var143 == nil {
3039- templ_7745c5c3_Var145 = templ.NopComponent3021+ templ_7745c5c3_Var143 = templ.NopComponent
3040 }3022 }
3041 ctx = templ.ClearChildren(ctx)3023 ctx = templ.ClearChildren(ctx)
3042 templ_7745c5c3_Err = mrMergeabilitySlot(v).Render(ctx, templ_7745c5c3_Buffer)3024 templ_7745c5c3_Err = mrMergeabilitySlot(v).Render(ctx, templ_7745c5c3_Buffer)
@@ -3047,8 +3029,8 @@ func MRMergeabilityFragment(v MergeabilityView) templ.Component {
3047 })3029 })
3048 }3030 }
3049 3031
3050-// moreMenu is what else the owner does with an open request: mark the head3032+// moreMenu shows read-only settings to every viewer, and keeps owner actions
3051-// read, close it, merge it from a terminal.3033+// behind the same merge-box permission as before.
3052 func moreMenu(p MRPage) templ.Component {3034 func moreMenu(p MRPage) templ.Component {
3053 return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {3035 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.Context3036 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@@ -3065,79 +3047,142 @@ func moreMenu(p MRPage) templ.Component {
3065 }()3047 }()
3066 }3048 }
3067 ctx = templ.InitializeContext(ctx)3049 ctx = templ.InitializeContext(ctx)
3068- templ_7745c5c3_Var146 := templ.GetChildren(ctx)3050+ templ_7745c5c3_Var144 := templ.GetChildren(ctx)
3069- if templ_7745c5c3_Var146 == nil {3051+ if templ_7745c5c3_Var144 == nil {
3070- templ_7745c5c3_Var146 = templ.NopComponent3052+ templ_7745c5c3_Var144 = templ.NopComponent
3071 }3053 }
3072 ctx = templ.ClearChildren(ctx)3054 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\">")3055+ 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 {3056 if templ_7745c5c3_Err != nil {
3075 return templ_7745c5c3_Err3057 return templ_7745c5c3_Err
3076 }3058 }
3077- if p.Box.CanMarkRead {3059+ var templ_7745c5c3_Var145 string
3078- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 285, "<form method=\"post\" action=\"")3060+ templ_7745c5c3_Var145, templ_7745c5c3_Err = templ.JoinStringErrs(strings.Join(p.Modes, ", "))
3061+ if templ_7745c5c3_Err != nil {
3062+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 600, Col: 38}
3063+ }
3064+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var145))
3065+ if templ_7745c5c3_Err != nil {
3066+ return templ_7745c5c3_Err
3067+ }
3068+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 281, "</dd><dt>checks</dt><dd>")
3069+ if templ_7745c5c3_Err != nil {
3070+ return templ_7745c5c3_Err
3071+ }
3072+ if p.ChecksBlock {
3073+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 282, "failing ones block the merge")
3079 if templ_7745c5c3_Err != nil {3074 if templ_7745c5c3_Err != nil {
3080 return templ_7745c5c3_Err3075 return templ_7745c5c3_Err
3081 }3076 }
3082- var templ_7745c5c3_Var147 templ.SafeURL3077+ } else {
3083- templ_7745c5c3_Var147, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.ReadAction))3078+ 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 {3079 if templ_7745c5c3_Err != nil {
3089 return templ_7745c5c3_Err3080 return templ_7745c5c3_Err
3090 }3081 }
3091- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 286, "\"><input type=\"hidden\" name=\"head_id\" value=\"")3082+ }
3083+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 284, "</dd></dl></section>")
3084+ if templ_7745c5c3_Err != nil {
3085+ return templ_7745c5c3_Err
3086+ }
3087+ if p.Box != nil {
3088+ if p.Box.Signed {
3089+ 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). ")
3090+ if templ_7745c5c3_Err != nil {
3091+ return templ_7745c5c3_Err
3092+ }
3093+ if p.Box.Fingerprint != "" {
3094+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 286, "fingerprint <code>")
3095+ if templ_7745c5c3_Err != nil {
3096+ return templ_7745c5c3_Err
3097+ }
3098+ var templ_7745c5c3_Var146 string
3099+ templ_7745c5c3_Var146, templ_7745c5c3_Err = templ.JoinStringErrs(p.Box.Fingerprint)
3100+ if templ_7745c5c3_Err != nil {
3101+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 616, Col: 44}
3102+ }
3103+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var146))
3104+ if templ_7745c5c3_Err != nil {
3105+ return templ_7745c5c3_Err
3106+ }
3107+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 287, "</code> ")
3108+ if templ_7745c5c3_Err != nil {
3109+ return templ_7745c5c3_Err
3110+ }
3111+ }
3112+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 288, "<code>ermite signing-key show</code> prints it.</p>")
3113+ if templ_7745c5c3_Err != nil {
3114+ return templ_7745c5c3_Err
3115+ }
3116+ }
3117+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 289, " ")
3092 if templ_7745c5c3_Err != nil {3118 if templ_7745c5c3_Err != nil {
3093 return templ_7745c5c3_Err3119 return templ_7745c5c3_Err
3094 }3120 }
3095- var templ_7745c5c3_Var148 string3121+ if p.Box.CanMarkRead {
3096- templ_7745c5c3_Var148, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.Head)3122+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 290, "<form method=\"post\" action=\"")
3097- if templ_7745c5c3_Err != nil {3123+ if templ_7745c5c3_Err != nil {
3098- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 600, Col: 59}3124+ return templ_7745c5c3_Err
3125+ }
3126+ var templ_7745c5c3_Var147 templ.SafeURL
3127+ templ_7745c5c3_Var147, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.ReadAction))
3128+ if templ_7745c5c3_Err != nil {
3129+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 622, Col: 65}
3130+ }
3131+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var147))
3132+ if templ_7745c5c3_Err != nil {
3133+ return templ_7745c5c3_Err
3134+ }
3135+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 291, "\"><input type=\"hidden\" name=\"head_id\" value=\"")
3136+ if templ_7745c5c3_Err != nil {
3137+ return templ_7745c5c3_Err
3138+ }
3139+ var templ_7745c5c3_Var148 string
3140+ templ_7745c5c3_Var148, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.Head)
3141+ if templ_7745c5c3_Err != nil {
3142+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 623, Col: 60}
3143+ }
3144+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var148)
3145+ if templ_7745c5c3_Err != nil {
3146+ return templ_7745c5c3_Err
3147+ }
3148+ 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>")
3149+ if templ_7745c5c3_Err != nil {
3150+ return templ_7745c5c3_Err
3151+ }
3099 }3152 }
3100- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var148)3153+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 293, " <form method=\"post\" action=\"")
3101 if templ_7745c5c3_Err != nil {3154 if templ_7745c5c3_Err != nil {
3102 return templ_7745c5c3_Err3155 return templ_7745c5c3_Err
3103 }3156 }
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>")3157+ var templ_7745c5c3_Var149 templ.SafeURL
3158+ templ_7745c5c3_Var149, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.CloseAction))
3105 if templ_7745c5c3_Err != nil {3159 if templ_7745c5c3_Err != nil {
3106- return templ_7745c5c3_Err3160+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 627, Col: 65}
3107 }3161 }
3108- }3162+ _, 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 {3163 if templ_7745c5c3_Err != nil {
3129 return templ_7745c5c3_Err3164 return templ_7745c5c3_Err
3130 }3165 }
3131- templ_7745c5c3_Err = CloneBlock(p.Box.CLI).Render(ctx, templ_7745c5c3_Buffer)3166+ 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 {3167 if templ_7745c5c3_Err != nil {
3133 return templ_7745c5c3_Err3168 return templ_7745c5c3_Err
3134 }3169 }
3135- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 291, "</details>")3170+ if !p.Box.HeadGone && p.Box.ReadyAction == "" {
3136- if templ_7745c5c3_Err != nil {3171+ 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_Err3172+ if templ_7745c5c3_Err != nil {
3173+ return templ_7745c5c3_Err
3174+ }
3175+ templ_7745c5c3_Err = CloneBlock(p.Box.CLI).Render(ctx, templ_7745c5c3_Buffer)
3176+ if templ_7745c5c3_Err != nil {
3177+ return templ_7745c5c3_Err
3178+ }
3179+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 296, "</details>")
3180+ if templ_7745c5c3_Err != nil {
3181+ return templ_7745c5c3_Err
3182+ }
3138 }3183 }
3139 }3184 }
3140- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 292, "</div></details>")3185+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 297, "</div></details>")
3141 if templ_7745c5c3_Err != nil {3186 if templ_7745c5c3_Err != nil {
3142 return templ_7745c5c3_Err3187 return templ_7745c5c3_Err
3143 }3188 }
@@ -3178,263 +3223,263 @@ func Compare(l Layout, p ComparePage) templ.Component {
3178 }()3223 }()
3179 }3224 }
3180 ctx = templ.InitializeContext(ctx)3225 ctx = templ.InitializeContext(ctx)
3181- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 293, "<header class=\"show mr-h\"><h1>")3226+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 298, "<header class=\"show mr-h\"><h1>")
3182 if templ_7745c5c3_Err != nil {3227 if templ_7745c5c3_Err != nil {
3183 return templ_7745c5c3_Err3228 return templ_7745c5c3_Err
3184 }3229 }
3185 var templ_7745c5c3_Var152 string3230 var templ_7745c5c3_Var152 string
3186 templ_7745c5c3_Var152, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)3231 templ_7745c5c3_Var152, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)
3187 if templ_7745c5c3_Err != nil {3232 if templ_7745c5c3_Err != nil {
3188- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 620, Col: 17}3233+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 644, Col: 17}
3189 }3234 }
3190 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var152))3235 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var152))
3191 if templ_7745c5c3_Err != nil {3236 if templ_7745c5c3_Err != nil {
3192 return templ_7745c5c3_Err3237 return templ_7745c5c3_Err
3193 }3238 }
3194- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 294, " → ")3239+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 299, " → ")
3195 if templ_7745c5c3_Err != nil {3240 if templ_7745c5c3_Err != nil {
3196 return templ_7745c5c3_Err3241 return templ_7745c5c3_Err
3197 }3242 }
3198 var templ_7745c5c3_Var153 string3243 var templ_7745c5c3_Var153 string
3199 templ_7745c5c3_Var153, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)3244 templ_7745c5c3_Var153, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
3200 if templ_7745c5c3_Err != nil {3245 if templ_7745c5c3_Err != nil {
3201- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 620, Col: 34}3246+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 644, Col: 34}
3202 }3247 }
3203 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var153))3248 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var153))
3204 if templ_7745c5c3_Err != nil {3249 if templ_7745c5c3_Err != nil {
3205 return templ_7745c5c3_Err3250 return templ_7745c5c3_Err
3206 }3251 }
3207- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 295, "</h1><dl class=\"kv show-kv\"><dt>branch</dt><dd><a href=\"")3252+ 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 {3253 if templ_7745c5c3_Err != nil {
3209 return templ_7745c5c3_Err3254 return templ_7745c5c3_Err
3210 }3255 }
3211 var templ_7745c5c3_Var154 templ.SafeURL3256 var templ_7745c5c3_Var154 templ.SafeURL
3212 templ_7745c5c3_Var154, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.SourceHref))3257 templ_7745c5c3_Var154, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.SourceHref))
3213 if templ_7745c5c3_Err != nil {3258 if templ_7745c5c3_Err != nil {
3214- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 623, Col: 45}3259+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 647, Col: 45}
3215 }3260 }
3216 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var154))3261 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var154))
3217 if templ_7745c5c3_Err != nil {3262 if templ_7745c5c3_Err != nil {
3218 return templ_7745c5c3_Err3263 return templ_7745c5c3_Err
3219 }3264 }
3220- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 296, "\">")3265+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 301, "\">")
3221 if templ_7745c5c3_Err != nil {3266 if templ_7745c5c3_Err != nil {
3222 return templ_7745c5c3_Err3267 return templ_7745c5c3_Err
3223 }3268 }
3224 var templ_7745c5c3_Var155 string3269 var templ_7745c5c3_Var155 string
3225 templ_7745c5c3_Var155, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)3270 templ_7745c5c3_Var155, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)
3226 if templ_7745c5c3_Err != nil {3271 if templ_7745c5c3_Err != nil {
3227- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 623, Col: 58}3272+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 647, Col: 58}
3228 }3273 }
3229 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var155))3274 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var155))
3230 if templ_7745c5c3_Err != nil {3275 if templ_7745c5c3_Err != nil {
3231 return templ_7745c5c3_Err3276 return templ_7745c5c3_Err
3232 }3277 }
3233- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 297, "</a></dd><dt>target</dt><dd><a href=\"")3278+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 302, "</a></dd><dt>target</dt><dd><a href=\"")
3234 if templ_7745c5c3_Err != nil {3279 if templ_7745c5c3_Err != nil {
3235 return templ_7745c5c3_Err3280 return templ_7745c5c3_Err
3236 }3281 }
3237 var templ_7745c5c3_Var156 templ.SafeURL3282 var templ_7745c5c3_Var156 templ.SafeURL
3238 templ_7745c5c3_Var156, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.TargetHref))3283 templ_7745c5c3_Var156, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.TargetHref))
3239 if templ_7745c5c3_Err != nil {3284 if templ_7745c5c3_Err != nil {
3240- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 625, Col: 45}3285+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 649, Col: 45}
3241 }3286 }
3242 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var156))3287 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var156))
3243 if templ_7745c5c3_Err != nil {3288 if templ_7745c5c3_Err != nil {
3244 return templ_7745c5c3_Err3289 return templ_7745c5c3_Err
3245 }3290 }
3246- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 298, "\">")3291+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 303, "\">")
3247 if templ_7745c5c3_Err != nil {3292 if templ_7745c5c3_Err != nil {
3248 return templ_7745c5c3_Err3293 return templ_7745c5c3_Err
3249 }3294 }
3250 var templ_7745c5c3_Var157 string3295 var templ_7745c5c3_Var157 string
3251 templ_7745c5c3_Var157, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)3296 templ_7745c5c3_Var157, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
3252 if templ_7745c5c3_Err != nil {3297 if templ_7745c5c3_Err != nil {
3253- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 625, Col: 58}3298+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 649, Col: 58}
3254 }3299 }
3255 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var157))3300 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var157))
3256 if templ_7745c5c3_Err != nil {3301 if templ_7745c5c3_Err != nil {
3257 return templ_7745c5c3_Err3302 return templ_7745c5c3_Err
3258 }3303 }
3259- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 299, "</a></dd><dt>ahead</dt><dd>")3304+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 304, "</a></dd><dt>ahead</dt><dd>")
3260 if templ_7745c5c3_Err != nil {3305 if templ_7745c5c3_Err != nil {
3261 return templ_7745c5c3_Err3306 return templ_7745c5c3_Err
3262 }3307 }
3263 var templ_7745c5c3_Var158 string3308 var templ_7745c5c3_Var158 string
3264 templ_7745c5c3_Var158, templ_7745c5c3_Err = templ.JoinStringErrs(p.AheadText)3309 templ_7745c5c3_Var158, templ_7745c5c3_Err = templ.JoinStringErrs(p.AheadText)
3265 if templ_7745c5c3_Err != nil {3310 if templ_7745c5c3_Err != nil {
3266- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 627, Col: 21}3311+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 651, Col: 21}
3267 }3312 }
3268 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var158))3313 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var158))
3269 if templ_7745c5c3_Err != nil {3314 if templ_7745c5c3_Err != nil {
3270 return templ_7745c5c3_Err3315 return templ_7745c5c3_Err
3271 }3316 }
3272- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 300, "</dd></dl></header>")3317+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 305, "</dd></dl></header>")
3273 if templ_7745c5c3_Err != nil {3318 if templ_7745c5c3_Err != nil {
3274 return templ_7745c5c3_Err3319 return templ_7745c5c3_Err
3275 }3320 }
3276 if p.Note != "" {3321 if p.Note != "" {
3277- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 301, "<p class=\"notice\">")3322+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 306, "<p class=\"notice\">")
3278 if templ_7745c5c3_Err != nil {3323 if templ_7745c5c3_Err != nil {
3279 return templ_7745c5c3_Err3324 return templ_7745c5c3_Err
3280 }3325 }
3281 var templ_7745c5c3_Var159 string3326 var templ_7745c5c3_Var159 string
3282 templ_7745c5c3_Var159, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note)3327 templ_7745c5c3_Var159, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note)
3283 if templ_7745c5c3_Err != nil {3328 if templ_7745c5c3_Err != nil {
3284- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 631, Col: 29}3329+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 655, Col: 29}
3285 }3330 }
3286 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var159))3331 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var159))
3287 if templ_7745c5c3_Err != nil {3332 if templ_7745c5c3_Err != nil {
3288 return templ_7745c5c3_Err3333 return templ_7745c5c3_Err
3289 }3334 }
3290- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 302, "</p>")3335+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 307, "</p>")
3291 if templ_7745c5c3_Err != nil {3336 if templ_7745c5c3_Err != nil {
3292 return templ_7745c5c3_Err3337 return templ_7745c5c3_Err
3293 }3338 }
3294 }3339 }
3295- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 303, " ")3340+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 308, " ")
3296 if templ_7745c5c3_Err != nil {3341 if templ_7745c5c3_Err != nil {
3297 return templ_7745c5c3_Err3342 return templ_7745c5c3_Err
3298 }3343 }
3299 if p.Existing != nil {3344 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=\"")3345+ 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 {3346 if templ_7745c5c3_Err != nil {
3302 return templ_7745c5c3_Err3347 return templ_7745c5c3_Err
3303 }3348 }
3304 var templ_7745c5c3_Var160 templ.SafeURL3349 var templ_7745c5c3_Var160 templ.SafeURL
3305 templ_7745c5c3_Var160, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Existing.Href))3350 templ_7745c5c3_Var160, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Existing.Href))
3306 if templ_7745c5c3_Err != nil {3351 if templ_7745c5c3_Err != nil {
3307- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 634, Col: 114}3352+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 658, Col: 114}
3308 }3353 }
3309 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var160))3354 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var160))
3310 if templ_7745c5c3_Err != nil {3355 if templ_7745c5c3_Err != nil {
3311 return templ_7745c5c3_Err3356 return templ_7745c5c3_Err
3312 }3357 }
3313- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 305, "\">")3358+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 310, "\">")
3314 if templ_7745c5c3_Err != nil {3359 if templ_7745c5c3_Err != nil {
3315 return templ_7745c5c3_Err3360 return templ_7745c5c3_Err
3316 }3361 }
3317 var templ_7745c5c3_Var161 string3362 var templ_7745c5c3_Var161 string
3318 templ_7745c5c3_Var161, templ_7745c5c3_Err = templ.JoinStringErrs(p.Existing.Label)3363 templ_7745c5c3_Var161, templ_7745c5c3_Err = templ.JoinStringErrs(p.Existing.Label)
3319 if templ_7745c5c3_Err != nil {3364 if templ_7745c5c3_Err != nil {
3320- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 634, Col: 135}3365+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 658, Col: 135}
3321 }3366 }
3322 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var161))3367 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var161))
3323 if templ_7745c5c3_Err != nil {3368 if templ_7745c5c3_Err != nil {
3324 return templ_7745c5c3_Err3369 return templ_7745c5c3_Err
3325 }3370 }
3326- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 306, "</a></p>")3371+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 311, "</a></p>")
3327 if templ_7745c5c3_Err != nil {3372 if templ_7745c5c3_Err != nil {
3328 return templ_7745c5c3_Err3373 return templ_7745c5c3_Err
3329 }3374 }
3330 }3375 }
3331- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 307, " ")3376+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 312, " ")
3332 if templ_7745c5c3_Err != nil {3377 if templ_7745c5c3_Err != nil {
3333 return templ_7745c5c3_Err3378 return templ_7745c5c3_Err
3334 }3379 }
3335 if p.Create != nil {3380 if p.Create != nil {
3336- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 308, "<form class=\"cform create\" method=\"post\" action=\"")3381+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 313, "<form class=\"cform create\" method=\"post\" action=\"")
3337 if templ_7745c5c3_Err != nil {3382 if templ_7745c5c3_Err != nil {
3338 return templ_7745c5c3_Err3383 return templ_7745c5c3_Err
3339 }3384 }
3340 var templ_7745c5c3_Var162 templ.SafeURL3385 var templ_7745c5c3_Var162 templ.SafeURL
3341 templ_7745c5c3_Var162, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Create.Action))3386 templ_7745c5c3_Var162, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Create.Action))
3342 if templ_7745c5c3_Err != nil {3387 if templ_7745c5c3_Err != nil {
3343- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 637, Col: 83}3388+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 661, Col: 83}
3344 }3389 }
3345 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var162))3390 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var162))
3346 if templ_7745c5c3_Err != nil {3391 if templ_7745c5c3_Err != nil {
3347 return templ_7745c5c3_Err3392 return templ_7745c5c3_Err
3348 }3393 }
3349- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 309, "\"><input type=\"hidden\" name=\"source\" value=\"")3394+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 314, "\"><input type=\"hidden\" name=\"source\" value=\"")
3350 if templ_7745c5c3_Err != nil {3395 if templ_7745c5c3_Err != nil {
3351 return templ_7745c5c3_Err3396 return templ_7745c5c3_Err
3352 }3397 }
3353 var templ_7745c5c3_Var163 string3398 var templ_7745c5c3_Var163 string
3354 templ_7745c5c3_Var163, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Source)3399 templ_7745c5c3_Var163, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Source)
3355 if templ_7745c5c3_Err != nil {3400 if templ_7745c5c3_Err != nil {
3356- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 638, Col: 62}3401+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 662, Col: 62}
3357 }3402 }
3358 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var163)3403 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var163)
3359 if templ_7745c5c3_Err != nil {3404 if templ_7745c5c3_Err != nil {
3360 return templ_7745c5c3_Err3405 return templ_7745c5c3_Err
3361 }3406 }
3362- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 310, "\"> <input type=\"hidden\" name=\"target\" value=\"")3407+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 315, "\"> <input type=\"hidden\" name=\"target\" value=\"")
3363 if templ_7745c5c3_Err != nil {3408 if templ_7745c5c3_Err != nil {
3364 return templ_7745c5c3_Err3409 return templ_7745c5c3_Err
3365 }3410 }
3366 var templ_7745c5c3_Var164 string3411 var templ_7745c5c3_Var164 string
3367 templ_7745c5c3_Var164, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Target)3412 templ_7745c5c3_Var164, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Target)
3368 if templ_7745c5c3_Err != nil {3413 if templ_7745c5c3_Err != nil {
3369- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 639, Col: 62}3414+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 663, Col: 62}
3370 }3415 }
3371 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var164)3416 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var164)
3372 if templ_7745c5c3_Err != nil {3417 if templ_7745c5c3_Err != nil {
3373 return templ_7745c5c3_Err3418 return templ_7745c5c3_Err
3374 }3419 }
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=\"")3420+ 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 {3421 if templ_7745c5c3_Err != nil {
3377 return templ_7745c5c3_Err3422 return templ_7745c5c3_Err
3378 }3423 }
3379 var templ_7745c5c3_Var165 string3424 var templ_7745c5c3_Var165 string
3380 templ_7745c5c3_Var165, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Title)3425 templ_7745c5c3_Var165, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Title)
3381 if templ_7745c5c3_Err != nil {3426 if templ_7745c5c3_Err != nil {
3382- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 641, Col: 97}3427+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 665, Col: 97}
3383 }3428 }
3384 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var165)3429 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var165)
3385 if templ_7745c5c3_Err != nil {3430 if templ_7745c5c3_Err != nil {
3386 return templ_7745c5c3_Err3431 return templ_7745c5c3_Err
3387 }3432 }
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>")3433+ 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 {3434 if templ_7745c5c3_Err != nil {
3390 return templ_7745c5c3_Err3435 return templ_7745c5c3_Err
3391 }3436 }
3392 }3437 }
3393- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 313, " ")3438+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 318, " ")
3394 if templ_7745c5c3_Err != nil {3439 if templ_7745c5c3_Err != nil {
3395 return templ_7745c5c3_Err3440 return templ_7745c5c3_Err
3396 }3441 }
3397 if p.HasDiff {3442 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\">")3443+ 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 {3444 if templ_7745c5c3_Err != nil {
3400 return templ_7745c5c3_Err3445 return templ_7745c5c3_Err
3401 }3446 }
3402 var templ_7745c5c3_Var166 string3447 var templ_7745c5c3_Var166 string
3403 templ_7745c5c3_Var166, templ_7745c5c3_Err = templ.JoinStringErrs(plural(p.NFiles, "file", "files"))3448 templ_7745c5c3_Var166, templ_7745c5c3_Err = templ.JoinStringErrs(plural(p.NFiles, "file", "files"))
3404 if templ_7745c5c3_Err != nil {3449 if templ_7745c5c3_Err != nil {
3405- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 651, Col: 57}3450+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 675, Col: 57}
3406 }3451 }
3407 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var166))3452 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var166))
3408 if templ_7745c5c3_Err != nil {3453 if templ_7745c5c3_Err != nil {
3409 return templ_7745c5c3_Err3454 return templ_7745c5c3_Err
3410 }3455 }
3411- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 315, " · <span class=\"plus\">+")3456+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 320, " · <span class=\"plus\">+")
3412 if templ_7745c5c3_Err != nil {3457 if templ_7745c5c3_Err != nil {
3413 return templ_7745c5c3_Err3458 return templ_7745c5c3_Err
3414 }3459 }
3415 var templ_7745c5c3_Var167 string3460 var templ_7745c5c3_Var167 string
3416 templ_7745c5c3_Var167, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Adds))3461 templ_7745c5c3_Var167, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Adds))
3417 if templ_7745c5c3_Err != nil {3462 if templ_7745c5c3_Err != nil {
3418- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 651, Col: 97}3463+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 675, Col: 97}
3419 }3464 }
3420 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var167))3465 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var167))
3421 if templ_7745c5c3_Err != nil {3466 if templ_7745c5c3_Err != nil {
3422 return templ_7745c5c3_Err3467 return templ_7745c5c3_Err
3423 }3468 }
3424- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 316, "</span> <span class=\"minus\">-")3469+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 321, "</span> <span class=\"minus\">-")
3425 if templ_7745c5c3_Err != nil {3470 if templ_7745c5c3_Err != nil {
3426 return templ_7745c5c3_Err3471 return templ_7745c5c3_Err
3427 }3472 }
3428 var templ_7745c5c3_Var168 string3473 var templ_7745c5c3_Var168 string
3429 templ_7745c5c3_Var168, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Dels))3474 templ_7745c5c3_Var168, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Dels))
3430 if templ_7745c5c3_Err != nil {3475 if templ_7745c5c3_Err != nil {
3431- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 651, Col: 142}3476+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 675, Col: 142}
3432 }3477 }
3433 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var168))3478 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var168))
3434 if templ_7745c5c3_Err != nil {3479 if templ_7745c5c3_Err != nil {
3435 return templ_7745c5c3_Err3480 return templ_7745c5c3_Err
3436 }3481 }
3437- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 317, "</span></span> <span class=\"grow\"></span>")3482+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 322, "</span></span> <span class=\"grow\"></span>")
3438 if templ_7745c5c3_Err != nil {3483 if templ_7745c5c3_Err != nil {
3439 return templ_7745c5c3_Err3484 return templ_7745c5c3_Err
3440 }3485 }
@@ -3442,64 +3487,64 @@ func Compare(l Layout, p ComparePage) templ.Component {
3442 if templ_7745c5c3_Err != nil {3487 if templ_7745c5c3_Err != nil {
3443 return templ_7745c5c3_Err3488 return templ_7745c5c3_Err
3444 }3489 }
3445- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 318, "</div>")3490+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 323, "</div>")
3446 if templ_7745c5c3_Err != nil {3491 if templ_7745c5c3_Err != nil {
3447 return templ_7745c5c3_Err3492 return templ_7745c5c3_Err
3448 }3493 }
3449 if p.Invisible {3494 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>")3495+ 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 {3496 if templ_7745c5c3_Err != nil {
3452 return templ_7745c5c3_Err3497 return templ_7745c5c3_Err
3453 }3498 }
3454 }3499 }
3455- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 320, " <div id=\"diffs\"")3500+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 325, " <div id=\"diffs\"")
3456 if templ_7745c5c3_Err != nil {3501 if templ_7745c5c3_Err != nil {
3457 return templ_7745c5c3_Err3502 return templ_7745c5c3_Err
3458 }3503 }
3459 if p.Both {3504 if p.Both {
3460- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 321, " data-diff=\"")3505+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 326, " data-diff=\"")
3461 if templ_7745c5c3_Err != nil {3506 if templ_7745c5c3_Err != nil {
3462 return templ_7745c5c3_Err3507 return templ_7745c5c3_Err
3463 }3508 }
3464 var templ_7745c5c3_Var169 string3509 var templ_7745c5c3_Var169 string
3465 templ_7745c5c3_Var169, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)3510 templ_7745c5c3_Var169, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
3466 if templ_7745c5c3_Err != nil {3511 if templ_7745c5c3_Err != nil {
3467- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 664, Col: 23}3512+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 688, Col: 23}
3468 }3513 }
3469 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var169)3514 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var169)
3470 if templ_7745c5c3_Err != nil {3515 if templ_7745c5c3_Err != nil {
3471 return templ_7745c5c3_Err3516 return templ_7745c5c3_Err
3472 }3517 }
3473- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 322, "\"")3518+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 327, "\"")
3474 if templ_7745c5c3_Err != nil {3519 if templ_7745c5c3_Err != nil {
3475 return templ_7745c5c3_Err3520 return templ_7745c5c3_Err
3476 }3521 }
3477 } else {3522 } else {
3478- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 323, " data-view=\"")3523+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 328, " data-view=\"")
3479 if templ_7745c5c3_Err != nil {3524 if templ_7745c5c3_Err != nil {
3480 return templ_7745c5c3_Err3525 return templ_7745c5c3_Err
3481 }3526 }
3482 var templ_7745c5c3_Var170 string3527 var templ_7745c5c3_Var170 string
3483 templ_7745c5c3_Var170, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)3528 templ_7745c5c3_Var170, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
3484 if templ_7745c5c3_Err != nil {3529 if templ_7745c5c3_Err != nil {
3485- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 666, Col: 23}3530+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 690, Col: 23}
3486 }3531 }
3487 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var170)3532 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var170)
3488 if templ_7745c5c3_Err != nil {3533 if templ_7745c5c3_Err != nil {
3489 return templ_7745c5c3_Err3534 return templ_7745c5c3_Err
3490 }3535 }
3491- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 324, "\"")3536+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 329, "\"")
3492 if templ_7745c5c3_Err != nil {3537 if templ_7745c5c3_Err != nil {
3493 return templ_7745c5c3_Err3538 return templ_7745c5c3_Err
3494 }3539 }
3495 }3540 }
3496 if p.Both && !p.Pinned {3541 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\"")3542+ 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 {3543 if templ_7745c5c3_Err != nil {
3499 return templ_7745c5c3_Err3544 return templ_7745c5c3_Err
3500 }3545 }
3501 }3546 }
3502- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 326, ">")3547+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 331, ">")
3503 if templ_7745c5c3_Err != nil {3548 if templ_7745c5c3_Err != nil {
3504 return templ_7745c5c3_Err3549 return templ_7745c5c3_Err
3505 }3550 }
@@ -3509,7 +3554,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
3509 return templ_7745c5c3_Err3554 return templ_7745c5c3_Err
3510 }3555 }
3511 }3556 }
3512- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 327, "</div>")3557+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 332, "</div>")
3513 if templ_7745c5c3_Err != nil {3558 if templ_7745c5c3_Err != nil {
3514 return templ_7745c5c3_Err3559 return templ_7745c5c3_Err
3515 }3560 }
@@ -3545,77 +3590,77 @@ func compareRail(p ComparePage) templ.Component {
3545 templ_7745c5c3_Var171 = templ.NopComponent3590 templ_7745c5c3_Var171 = templ.NopComponent
3546 }3591 }
3547 ctx = templ.ClearChildren(ctx)3592 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\">")3593+ 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 {3594 if templ_7745c5c3_Err != nil {
3550 return templ_7745c5c3_Err3595 return templ_7745c5c3_Err
3551 }3596 }
3552 var templ_7745c5c3_Var172 string3597 var templ_7745c5c3_Var172 string
3553 templ_7745c5c3_Var172, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Ahead)))3598 templ_7745c5c3_Var172, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Ahead)))
3554 if templ_7745c5c3_Err != nil {3599 if templ_7745c5c3_Err != nil {
3555- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 682, Col: 67}3600+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 706, Col: 67}
3556 }3601 }
3557 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var172))3602 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var172))
3558 if templ_7745c5c3_Err != nil {3603 if templ_7745c5c3_Err != nil {
3559 return templ_7745c5c3_Err3604 return templ_7745c5c3_Err
3560 }3605 }
3561- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 329, "</span></h2><ul class=\"pcommits\">")3606+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 334, "</span></h2><ul class=\"pcommits\">")
3562 if templ_7745c5c3_Err != nil {3607 if templ_7745c5c3_Err != nil {
3563 return templ_7745c5c3_Err3608 return templ_7745c5c3_Err
3564 }3609 }
3565 for _, c := range p.Ahead {3610 for _, c := range p.Ahead {
3566- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 330, "<li><a href=\"")3611+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 335, "<li><a href=\"")
3567 if templ_7745c5c3_Err != nil {3612 if templ_7745c5c3_Err != nil {
3568 return templ_7745c5c3_Err3613 return templ_7745c5c3_Err
3569 }3614 }
3570 var templ_7745c5c3_Var173 templ.SafeURL3615 var templ_7745c5c3_Var173 templ.SafeURL
3571 templ_7745c5c3_Var173, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.CHref))3616 templ_7745c5c3_Var173, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.CHref))
3572 if templ_7745c5c3_Err != nil {3617 if templ_7745c5c3_Err != nil {
3573- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 686, Col: 37}3618+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 710, Col: 37}
3574 }3619 }
3575 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var173))3620 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var173))
3576 if templ_7745c5c3_Err != nil {3621 if templ_7745c5c3_Err != nil {
3577 return templ_7745c5c3_Err3622 return templ_7745c5c3_Err
3578 }3623 }
3579- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 331, "\">")3624+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 336, "\">")
3580 if templ_7745c5c3_Err != nil {3625 if templ_7745c5c3_Err != nil {
3581 return templ_7745c5c3_Err3626 return templ_7745c5c3_Err
3582 }3627 }
3583 var templ_7745c5c3_Var174 string3628 var templ_7745c5c3_Var174 string
3584 templ_7745c5c3_Var174, templ_7745c5c3_Err = templ.JoinStringErrs(c.Short)3629 templ_7745c5c3_Var174, templ_7745c5c3_Err = templ.JoinStringErrs(c.Short)
3585 if templ_7745c5c3_Err != nil {3630 if templ_7745c5c3_Err != nil {
3586- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 686, Col: 49}3631+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 710, Col: 49}
3587 }3632 }
3588 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var174))3633 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var174))
3589 if templ_7745c5c3_Err != nil {3634 if templ_7745c5c3_Err != nil {
3590 return templ_7745c5c3_Err3635 return templ_7745c5c3_Err
3591 }3636 }
3592- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 332, "</a> <span class=\"s\">")3637+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 337, "</a> <span class=\"s\">")
3593 if templ_7745c5c3_Err != nil {3638 if templ_7745c5c3_Err != nil {
3594 return templ_7745c5c3_Err3639 return templ_7745c5c3_Err
3595 }3640 }
3596 var templ_7745c5c3_Var175 string3641 var templ_7745c5c3_Var175 string
3597 templ_7745c5c3_Var175, templ_7745c5c3_Err = templ.JoinStringErrs(c.Subject)3642 templ_7745c5c3_Var175, templ_7745c5c3_Err = templ.JoinStringErrs(c.Subject)
3598 if templ_7745c5c3_Err != nil {3643 if templ_7745c5c3_Err != nil {
3599- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 687, Col: 32}3644+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 711, Col: 32}
3600 }3645 }
3601 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var175))3646 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var175))
3602 if templ_7745c5c3_Err != nil {3647 if templ_7745c5c3_Err != nil {
3603 return templ_7745c5c3_Err3648 return templ_7745c5c3_Err
3604 }3649 }
3605- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 333, "</span> <span class=\"mute\">")3650+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 338, "</span> <span class=\"mute\">")
3606 if templ_7745c5c3_Err != nil {3651 if templ_7745c5c3_Err != nil {
3607 return templ_7745c5c3_Err3652 return templ_7745c5c3_Err
3608 }3653 }
3609 var templ_7745c5c3_Var176 string3654 var templ_7745c5c3_Var176 string
3610 templ_7745c5c3_Var176, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)3655 templ_7745c5c3_Var176, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)
3611 if templ_7745c5c3_Err != nil {3656 if templ_7745c5c3_Err != nil {
3612- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 689, Col: 16}3657+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 713, Col: 16}
3613 }3658 }
3614 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var176))3659 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var176))
3615 if templ_7745c5c3_Err != nil {3660 if templ_7745c5c3_Err != nil {
3616 return templ_7745c5c3_Err3661 return templ_7745c5c3_Err
3617 }3662 }
3618- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 334, " ")3663+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 339, " ")
3619 if templ_7745c5c3_Err != nil {3664 if templ_7745c5c3_Err != nil {
3620 return templ_7745c5c3_Err3665 return templ_7745c5c3_Err
3621 }3666 }
@@ -3623,90 +3668,90 @@ func compareRail(p ComparePage) templ.Component {
3623 var templ_7745c5c3_Var177 string3668 var templ_7745c5c3_Var177 string
3624 templ_7745c5c3_Var177, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")3669 templ_7745c5c3_Var177, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")
3625 if templ_7745c5c3_Err != nil {3670 if templ_7745c5c3_Err != nil {
3626- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 691, Col: 15}3671+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 715, Col: 15}
3627 }3672 }
3628 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var177))3673 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var177))
3629 if templ_7745c5c3_Err != nil {3674 if templ_7745c5c3_Err != nil {
3630 return templ_7745c5c3_Err3675 return templ_7745c5c3_Err
3631 }3676 }
3632- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 335, "<time datetime=\"")3677+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 340, "<time datetime=\"")
3633 if templ_7745c5c3_Err != nil {3678 if templ_7745c5c3_Err != nil {
3634 return templ_7745c5c3_Err3679 return templ_7745c5c3_Err
3635 }3680 }
3636 var templ_7745c5c3_Var178 string3681 var templ_7745c5c3_Var178 string
3637 templ_7745c5c3_Var178, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)3682 templ_7745c5c3_Var178, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)
3638 if templ_7745c5c3_Err != nil {3683 if templ_7745c5c3_Err != nil {
3639- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 691, Col: 42}3684+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 715, Col: 42}
3640 }3685 }
3641 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var178)3686 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var178)
3642 if templ_7745c5c3_Err != nil {3687 if templ_7745c5c3_Err != nil {
3643 return templ_7745c5c3_Err3688 return templ_7745c5c3_Err
3644 }3689 }
3645- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 336, "\">")3690+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 341, "\">")
3646 if templ_7745c5c3_Err != nil {3691 if templ_7745c5c3_Err != nil {
3647 return templ_7745c5c3_Err3692 return templ_7745c5c3_Err
3648 }3693 }
3649 var templ_7745c5c3_Var179 string3694 var templ_7745c5c3_Var179 string
3650 templ_7745c5c3_Var179, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)3695 templ_7745c5c3_Var179, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)
3651 if templ_7745c5c3_Err != nil {3696 if templ_7745c5c3_Err != nil {
3652- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 691, Col: 53}3697+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 715, Col: 53}
3653 }3698 }
3654 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var179))3699 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var179))
3655 if templ_7745c5c3_Err != nil {3700 if templ_7745c5c3_Err != nil {
3656 return templ_7745c5c3_Err3701 return templ_7745c5c3_Err
3657 }3702 }
3658- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 337, "</time>")3703+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 342, "</time>")
3659 if templ_7745c5c3_Err != nil {3704 if templ_7745c5c3_Err != nil {
3660 return templ_7745c5c3_Err3705 return templ_7745c5c3_Err
3661 }3706 }
3662 }3707 }
3663- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 338, "</span></li>")3708+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 343, "</span></li>")
3664 if templ_7745c5c3_Err != nil {3709 if templ_7745c5c3_Err != nil {
3665 return templ_7745c5c3_Err3710 return templ_7745c5c3_Err
3666 }3711 }
3667 }3712 }
3668- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 339, "</ul>")3713+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 344, "</ul>")
3669 if templ_7745c5c3_Err != nil {3714 if templ_7745c5c3_Err != nil {
3670 return templ_7745c5c3_Err3715 return templ_7745c5c3_Err
3671 }3716 }
3672 if len(p.Ahead) == 0 {3717 if len(p.Ahead) == 0 {
3673- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 340, "<p class=\"dim\">no commit ahead of ")3718+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 345, "<p class=\"dim\">no commit ahead of ")
3674 if templ_7745c5c3_Err != nil {3719 if templ_7745c5c3_Err != nil {
3675 return templ_7745c5c3_Err3720 return templ_7745c5c3_Err
3676 }3721 }
3677 var templ_7745c5c3_Var180 string3722 var templ_7745c5c3_Var180 string
3678 templ_7745c5c3_Var180, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)3723 templ_7745c5c3_Var180, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
3679 if templ_7745c5c3_Err != nil {3724 if templ_7745c5c3_Err != nil {
3680- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 698, Col: 47}3725+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 722, Col: 47}
3681 }3726 }
3682 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var180))3727 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var180))
3683 if templ_7745c5c3_Err != nil {3728 if templ_7745c5c3_Err != nil {
3684 return templ_7745c5c3_Err3729 return templ_7745c5c3_Err
3685 }3730 }
3686- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 341, ".</p>")3731+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 346, ".</p>")
3687 if templ_7745c5c3_Err != nil {3732 if templ_7745c5c3_Err != nil {
3688 return templ_7745c5c3_Err3733 return templ_7745c5c3_Err
3689 }3734 }
3690 }3735 }
3691- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 342, "</section>")3736+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 347, "</section>")
3692 if templ_7745c5c3_Err != nil {3737 if templ_7745c5c3_Err != nil {
3693 return templ_7745c5c3_Err3738 return templ_7745c5c3_Err
3694 }3739 }
3695 if p.HasDiff {3740 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\">")3741+ 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 {3742 if templ_7745c5c3_Err != nil {
3698 return templ_7745c5c3_Err3743 return templ_7745c5c3_Err
3699 }3744 }
3700 var templ_7745c5c3_Var181 string3745 var templ_7745c5c3_Var181 string
3701 templ_7745c5c3_Var181, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))3746 templ_7745c5c3_Var181, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))
3702 if templ_7745c5c3_Err != nil {3747 if templ_7745c5c3_Err != nil {
3703- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 703, Col: 66}3748+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 727, Col: 66}
3704 }3749 }
3705 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var181))3750 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var181))
3706 if templ_7745c5c3_Err != nil {3751 if templ_7745c5c3_Err != nil {
3707 return templ_7745c5c3_Err3752 return templ_7745c5c3_Err
3708 }3753 }
3709- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 344, "</span></h2>")3754+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 349, "</span></h2>")
3710 if templ_7745c5c3_Err != nil {3755 if templ_7745c5c3_Err != nil {
3711 return templ_7745c5c3_Err3756 return templ_7745c5c3_Err
3712 }3757 }
@@ -3714,12 +3759,12 @@ func compareRail(p ComparePage) templ.Component {
3714 if templ_7745c5c3_Err != nil {3759 if templ_7745c5c3_Err != nil {
3715 return templ_7745c5c3_Err3760 return templ_7745c5c3_Err
3716 }3761 }
3717- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 345, "</section>")3762+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 350, "</section>")
3718 if templ_7745c5c3_Err != nil {3763 if templ_7745c5c3_Err != nil {
3719 return templ_7745c5c3_Err3764 return templ_7745c5c3_Err
3720 }3765 }
3721 }3766 }
3722- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 346, "<section aria-labelledby=\"r-cli\"><h2 id=\"r-cli\">From a terminal</h2>")3767+ 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 {3768 if templ_7745c5c3_Err != nil {
3724 return templ_7745c5c3_Err3769 return templ_7745c5c3_Err
3725 }3770 }
@@ -3727,7 +3772,7 @@ func compareRail(p ComparePage) templ.Component {
3727 if templ_7745c5c3_Err != nil {3772 if templ_7745c5c3_Err != nil {
3728 return templ_7745c5c3_Err3773 return templ_7745c5c3_Err
3729 }3774 }
3730- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 347, "</section>")3775+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 352, "</section>")
3731 if templ_7745c5c3_Err != nil {3776 if templ_7745c5c3_Err != nil {
3732 return templ_7745c5c3_Err3777 return templ_7745c5c3_Err
3733 }3778 }
M internal/adapters/web/mr_test.go +57 -0
@@ -4,6 +4,7 @@ package web
44
55 import (
66 "context"
7+ "time"
78 "testing"
89
910 "github.com/stretchr/testify/assert"
@@ -128,3 +129,59 @@ func TestMergeabilityLiveEvents(t *testing.T) {
128129 require.NoError(t, err)
129130 assert.Empty(t, fs)
130131 }
132+
133+func TestMRPanelsAndMenus(t *testing.T) {
134+ p := MRPage{CommitCount: "500+", CommitsNote: "more commits", Modes: []string{"squash", "merge"}, ChecksBlock: true,
135+ ChecksSum: ChecksSummary{Total: 2, Label: "1/2", Title: "1/2 failed"}, Box: &MergeBox{Signed: true, Fingerprint: "fingerprint", HeadGone: true}}
136+ footer := renderToString(t, mrFooter(p))
137+ assert.Contains(t, footer, `<footer class="mr-footer"><details id="mr-panels">`)
138+ assert.Contains(t, footer, `data-mr-tabs`)
139+ assert.Contains(t, footer, `id="mr-commits"`)
140+ assert.Contains(t, footer, `id="mr-checks"`)
141+ assert.Contains(t, footer, `<table class="mr-commits">`)
142+ assert.Contains(t, footer, "500+")
143+ assert.Contains(t, footer, "more commits")
144+ assert.Contains(t, footer, "1/2 failed")
145+ rail := renderToString(t, mrRail(p))
146+ assert.Contains(t, rail, "g f")
147+ for _, text := range []string{"Checks", "Commits", "Settings", "mr-checks"} {
148+ assert.NotContains(t, rail, text)
149+ }
150+ more := renderToString(t, moreMenu(p))
151+ for _, text := range []string{"Merge settings", "squash, merge", "failing ones block", `id="mr-signing"`, "fingerprint", "ermite signing-key show"} {
152+ assert.Contains(t, more, text)
153+ }
154+ merge := renderToString(t, mergeMenu(p))
155+ assert.NotContains(t, merge, `<dl`)
156+ assert.NotContains(t, merge, `mr-signing`)
157+ assert.Contains(t, merge, "the source branch was deleted")
158+ bar := renderToString(t, mrBar(MRPage{}))
159+ assert.Contains(t, bar, `id="mr-ck"`)
160+ assert.Contains(t, bar, `href="#mr-checks"`)
161+ assert.Contains(t, bar, "Merge settings")
162+ assert.NotContains(t, bar, ">Close</button>")
163+}
164+
165+func TestMRReadPresentationCommitCount(t *testing.T) {
166+ commits := func(n int) []domain.Commit { return make([]domain.Commit, n) }
167+ for _, tc := range []struct {
168+ name string
169+ commits []domain.Commit
170+ truncated bool
171+ count string
172+ note string
173+ }{
174+ {"empty", nil, false, "0", ""},
175+ {"complete", commits(2), false, "2", ""},
176+ {"truncated", commits(3), true, "3+", "the branch has more commits than the 3 listed."},
177+ } {
178+ t.Run(tc.name, func(t *testing.T) {
179+ s := &Server{cfg: Config{Now: time.Now}}
180+ p := &MRPage{}
181+ s.mrReadPresentation(p, "demo", 1, ports.MergeRequestDetail{Commits: tc.commits, CommitsTruncated: tc.truncated}, false, false)
182+ assert.Equal(t, tc.count, p.CommitCount)
183+ assert.Equal(t, tc.note, p.CommitsNote)
184+ assert.Len(t, p.Commits, len(tc.commits))
185+ })
186+ }
187+}
@@ -4,6 +4,7 @@ package web
4 4
5 import (5 import (
6 "context"6 "context"
7+ "time"
7 "testing"8 "testing"
8 9
9 "github.com/stretchr/testify/assert"10 "github.com/stretchr/testify/assert"
@@ -128,3 +129,59 @@ func TestMergeabilityLiveEvents(t *testing.T) {
128 require.NoError(t, err)129 require.NoError(t, err)
129 assert.Empty(t, fs)130 assert.Empty(t, fs)
130 }131 }
132+
133+func TestMRPanelsAndMenus(t *testing.T) {
134+ p := MRPage{CommitCount: "500+", CommitsNote: "more commits", Modes: []string{"squash", "merge"}, ChecksBlock: true,
135+ ChecksSum: ChecksSummary{Total: 2, Label: "1/2", Title: "1/2 failed"}, Box: &MergeBox{Signed: true, Fingerprint: "fingerprint", HeadGone: true}}
136+ footer := renderToString(t, mrFooter(p))
137+ assert.Contains(t, footer, `<footer class="mr-footer"><details id="mr-panels">`)
138+ assert.Contains(t, footer, `data-mr-tabs`)
139+ assert.Contains(t, footer, `id="mr-commits"`)
140+ assert.Contains(t, footer, `id="mr-checks"`)
141+ assert.Contains(t, footer, `<table class="mr-commits">`)
142+ assert.Contains(t, footer, "500+")
143+ assert.Contains(t, footer, "more commits")
144+ assert.Contains(t, footer, "1/2 failed")
145+ rail := renderToString(t, mrRail(p))
146+ assert.Contains(t, rail, "g f")
147+ for _, text := range []string{"Checks", "Commits", "Settings", "mr-checks"} {
148+ assert.NotContains(t, rail, text)
149+ }
150+ more := renderToString(t, moreMenu(p))
151+ for _, text := range []string{"Merge settings", "squash, merge", "failing ones block", `id="mr-signing"`, "fingerprint", "ermite signing-key show"} {
152+ assert.Contains(t, more, text)
153+ }
154+ merge := renderToString(t, mergeMenu(p))
155+ assert.NotContains(t, merge, `<dl`)
156+ assert.NotContains(t, merge, `mr-signing`)
157+ assert.Contains(t, merge, "the source branch was deleted")
158+ bar := renderToString(t, mrBar(MRPage{}))
159+ assert.Contains(t, bar, `id="mr-ck"`)
160+ assert.Contains(t, bar, `href="#mr-checks"`)
161+ assert.Contains(t, bar, "Merge settings")
162+ assert.NotContains(t, bar, ">Close</button>")
163+}
164+
165+func TestMRReadPresentationCommitCount(t *testing.T) {
166+ commits := func(n int) []domain.Commit { return make([]domain.Commit, n) }
167+ for _, tc := range []struct {
168+ name string
169+ commits []domain.Commit
170+ truncated bool
171+ count string
172+ note string
173+ }{
174+ {"empty", nil, false, "0", ""},
175+ {"complete", commits(2), false, "2", ""},
176+ {"truncated", commits(3), true, "3+", "the branch has more commits than the 3 listed."},
177+ } {
178+ t.Run(tc.name, func(t *testing.T) {
179+ s := &Server{cfg: Config{Now: time.Now}}
180+ p := &MRPage{}
181+ s.mrReadPresentation(p, "demo", 1, ports.MergeRequestDetail{Commits: tc.commits, CommitsTruncated: tc.truncated}, false, false)
182+ assert.Equal(t, tc.count, p.CommitCount)
183+ assert.Equal(t, tc.note, p.CommitsNote)
184+ assert.Len(t, p.Commits, len(tc.commits))
185+ })
186+ }
187+}
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 +55 -0
@@ -0,0 +1,55 @@
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 [data-mr-tabs] a { display: inline-flex; align-items: center; min-height: 40px; }
52+ /* No display change: the summary stays a list-item and keeps its marker. */
53+ .mr-footer summary { min-height: 40px; line-height: 40px; }
54+ }
55+}
@@ -0,0 +1,55 @@
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 [data-mr-tabs] a { display: inline-flex; align-items: center; min-height: 40px; }
52+ /* No display change: the summary stays a list-item and keeps its marker. */
53+ .mr-footer summary { min-height: 40px; line-height: 40px; }
54+ }
55+}
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 +143 -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,126 @@ 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, fromUser = 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+ if (fromUser && location.hash !== '#' + panels[index].id) history.replaceState(null, '', '#' + panels[index].id);
329+ }
330+ tabs.forEach((tab, i) => {
331+ tab.addEventListener('click', (e) => { e.preventDefault(); select(i, false, true); });
332+ tab.addEventListener('keydown', (e) => {
333+ const next = core.tabIndex(e.key, i, tabs.length);
334+ if (next === null) return;
335+ e.preventDefault(); select(next, true, true);
336+ });
337+ });
338+ function hash() {
339+ const h = location.hash;
340+ const index = h === '#mr-checks' || h === '#mr-checks-panel' ? 1 : h === '#mr-commits' ? 0 : -1;
341+ if (index < 0) return;
342+ footer.open = true; select(index);
343+ }
344+ // A repeated click on the same hash must also reopen a folded footer.
345+ document.addEventListener('click', (e) => {
346+ if (e.target.closest?.('#mr-ck')) { footer.open = true; select(1); }
347+ });
348+ const summary = $('#mr-ck');
349+ if (summary) {
350+ const sync = () => { $('[data-checks-label]', nav).textContent = $('#mr-ck')?.title || $('#mr-ck')?.textContent.trim() || 'no checks'; };
351+ new MutationObserver(sync).observe(summary.parentElement, { childList: true, subtree: true, characterData: true });
352+ sync();
353+ }
354+ select(0); hash();
355+ addEventListener('hashchange', hash);
356+ }
357+
358+ function touchComments() {
359+ const diffs = $('#diffs');
360+ const bar = document.createElement('div');
361+ bar.className = 'mr-touch-range';
362+ const button = document.createElement('button');
363+ button.type = 'button';
364+ button.className = 'btn';
365+ button.textContent = 'Select line range';
366+ button.setAttribute('aria-pressed', 'false');
367+ const status = document.createElement('span');
368+ status.setAttribute('role', 'status');
369+ bar.append(button, status);
370+ diffs.prepend(bar);
371+ refreshTouchComments = () => { bar.hidden = !$('.ln a[href*="on="]', diffs); };
372+ refreshTouchComments();
373+ const touch = window.matchMedia?.('(pointer: coarse), (hover: none)');
374+ let enabled = false, start = null, marker = null;
375+ const clear = () => { marker?.removeAttribute('data-range-start'); marker = null; start = null; };
376+ button.addEventListener('click', () => {
377+ enabled = !enabled;
378+ clear();
379+ button.setAttribute('aria-pressed', String(enabled));
380+ status.textContent = enabled ? 'Tap the first line number, then the last. Tap the same line for one line.' : '';
381+ });
382+ diffs.addEventListener('click', (e) => {
383+ const link = e.target.closest?.('.ln a[href*="on="]');
384+ if (!touch?.matches || !enabled || !link || e.shiftKey || e.ctrlKey || e.metaKey || e.altKey) return;
385+ e.preventDefault();
386+ e.stopPropagation(); // do not alter the desktop shift-click anchor
387+ const next = core.touchRange(start, link.href, location.href);
388+ clear();
389+ if (next.url) { location.assign(next.url); return; }
390+ start = next.start;
391+ marker = link;
392+ marker.setAttribute('data-range-start', '');
393+ status.textContent = `Range starts at line ${link.textContent.trim()}. Tap the last line number (same file and side).`;
394+ });
395+ touch?.addEventListener('change', () => {
396+ if (touch.matches) return;
397+ enabled = false;
398+ clear();
399+ button.setAttribute('aria-pressed', 'false');
400+ status.textContent = '';
401+ });
402+ // The server opens the line form. Scroll after layout without stealing
403+ // focus or forcing a mobile keyboard to appear.
404+ if (new URL(location.href).searchParams.has('on')) requestAnimationFrame(() => {
405+ const form = $$('.fnote .cform', diffs).find((f) => f.getClientRects().length);
406+ form?.scrollIntoView({ block: 'center' });
407+ });
408+ }
409+
288410 function start() {
289411 if (!$('#diffs[data-mr]')) return;
412+ panels();
413+ // Large diffs may contain only the split table. Ask the existing server
414+ // route for unified rather than writing the saved session preference.
415+ const narrow = window.matchMedia?.('(max-width: 720px)');
416+ const unify = () => {
417+ $('#diffs').dataset.mobile = String(!!narrow?.matches);
418+ const url = core.mobileURL(location.href, $('#diffs')?.dataset.view, narrow?.matches);
419+ if (url) { location.replace(url); return true; }
420+ return false;
421+ };
422+ if (unify()) return;
423+ narrow?.addEventListener('change', unify);
424+ addEventListener('click', (e) => {
425+ if (narrow?.matches && e.target.closest?.('.vbtn[data-view="split"]')) {
426+ e.preventDefault();
427+ e.stopImmediatePropagation();
428+ }
429+ }, true);
430+ touchComments();
290431 let folded = false;
291432 try { folded = localStorage.getItem('mr-files-folded') === '1'; } catch { /* no storage: open */ }
292433 if (folded) foldFiles(true);
@@ -316,7 +457,7 @@ window.ermiteMR = (() => {
316457 });
317458 }
318459
319- return { core, start, load, reveal, openMerge, menuKey, markRead, focusFiles, stepFiles, leaveFiles, foldFiles, openFile };
460+ return { core, panels, start, load, reveal, openMerge, menuKey, markRead, focusFiles, stepFiles, leaveFiles, foldFiles, openFile };
320461 })();
321462
322463 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,126 @@ 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, fromUser = 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+ if (fromUser && location.hash !== '#' + panels[index].id) history.replaceState(null, '', '#' + panels[index].id);
329+ }
330+ tabs.forEach((tab, i) => {
331+ tab.addEventListener('click', (e) => { e.preventDefault(); select(i, false, true); });
332+ tab.addEventListener('keydown', (e) => {
333+ const next = core.tabIndex(e.key, i, tabs.length);
334+ if (next === null) return;
335+ e.preventDefault(); select(next, true, true);
336+ });
337+ });
338+ function hash() {
339+ const h = location.hash;
340+ const index = h === '#mr-checks' || h === '#mr-checks-panel' ? 1 : h === '#mr-commits' ? 0 : -1;
341+ if (index < 0) return;
342+ footer.open = true; select(index);
343+ }
344+ // A repeated click on the same hash must also reopen a folded footer.
345+ document.addEventListener('click', (e) => {
346+ if (e.target.closest?.('#mr-ck')) { footer.open = true; select(1); }
347+ });
348+ const summary = $('#mr-ck');
349+ if (summary) {
350+ const sync = () => { $('[data-checks-label]', nav).textContent = $('#mr-ck')?.title || $('#mr-ck')?.textContent.trim() || 'no checks'; };
351+ new MutationObserver(sync).observe(summary.parentElement, { childList: true, subtree: true, characterData: true });
352+ sync();
353+ }
354+ select(0); hash();
355+ addEventListener('hashchange', hash);
356+ }
357+
358+ function touchComments() {
359+ const diffs = $('#diffs');
360+ const bar = document.createElement('div');
361+ bar.className = 'mr-touch-range';
362+ const button = document.createElement('button');
363+ button.type = 'button';
364+ button.className = 'btn';
365+ button.textContent = 'Select line range';
366+ button.setAttribute('aria-pressed', 'false');
367+ const status = document.createElement('span');
368+ status.setAttribute('role', 'status');
369+ bar.append(button, status);
370+ diffs.prepend(bar);
371+ refreshTouchComments = () => { bar.hidden = !$('.ln a[href*="on="]', diffs); };
372+ refreshTouchComments();
373+ const touch = window.matchMedia?.('(pointer: coarse), (hover: none)');
374+ let enabled = false, start = null, marker = null;
375+ const clear = () => { marker?.removeAttribute('data-range-start'); marker = null; start = null; };
376+ button.addEventListener('click', () => {
377+ enabled = !enabled;
378+ clear();
379+ button.setAttribute('aria-pressed', String(enabled));
380+ status.textContent = enabled ? 'Tap the first line number, then the last. Tap the same line for one line.' : '';
381+ });
382+ diffs.addEventListener('click', (e) => {
383+ const link = e.target.closest?.('.ln a[href*="on="]');
384+ if (!touch?.matches || !enabled || !link || e.shiftKey || e.ctrlKey || e.metaKey || e.altKey) return;
385+ e.preventDefault();
386+ e.stopPropagation(); // do not alter the desktop shift-click anchor
387+ const next = core.touchRange(start, link.href, location.href);
388+ clear();
389+ if (next.url) { location.assign(next.url); return; }
390+ start = next.start;
391+ marker = link;
392+ marker.setAttribute('data-range-start', '');
393+ status.textContent = `Range starts at line ${link.textContent.trim()}. Tap the last line number (same file and side).`;
394+ });
395+ touch?.addEventListener('change', () => {
396+ if (touch.matches) return;
397+ enabled = false;
398+ clear();
399+ button.setAttribute('aria-pressed', 'false');
400+ status.textContent = '';
401+ });
402+ // The server opens the line form. Scroll after layout without stealing
403+ // focus or forcing a mobile keyboard to appear.
404+ if (new URL(location.href).searchParams.has('on')) requestAnimationFrame(() => {
405+ const form = $$('.fnote .cform', diffs).find((f) => f.getClientRects().length);
406+ form?.scrollIntoView({ block: 'center' });
407+ });
408+ }
409+
288 function start() {410 function start() {
289 if (!$('#diffs[data-mr]')) return;411 if (!$('#diffs[data-mr]')) return;
412+ panels();
413+ // Large diffs may contain only the split table. Ask the existing server
414+ // route for unified rather than writing the saved session preference.
415+ const narrow = window.matchMedia?.('(max-width: 720px)');
416+ const unify = () => {
417+ $('#diffs').dataset.mobile = String(!!narrow?.matches);
418+ const url = core.mobileURL(location.href, $('#diffs')?.dataset.view, narrow?.matches);
419+ if (url) { location.replace(url); return true; }
420+ return false;
421+ };
422+ if (unify()) return;
423+ narrow?.addEventListener('change', unify);
424+ addEventListener('click', (e) => {
425+ if (narrow?.matches && e.target.closest?.('.vbtn[data-view="split"]')) {
426+ e.preventDefault();
427+ e.stopImmediatePropagation();
428+ }
429+ }, true);
430+ touchComments();
290 let folded = false;431 let folded = false;
291 try { folded = localStorage.getItem('mr-files-folded') === '1'; } catch { /* no storage: open */ }432 try { folded = localStorage.getItem('mr-files-folded') === '1'; } catch { /* no storage: open */ }
292 if (folded) foldFiles(true);433 if (folded) foldFiles(true);
@@ -316,7 +457,7 @@ window.ermiteMR = (() => {
316 });457 });
317 }458 }
318 459
319- return { core, start, load, reveal, openMerge, menuKey, markRead, focusFiles, stepFiles, leaveFiles, foldFiles, openFile };460+ return { core, panels, start, load, reveal, openMerge, menuKey, markRead, focusFiles, stepFiles, leaveFiles, foldFiles, openFile };
320 })();461 })();
321 462
322 if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', () => window.ermiteMR.start());463 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 45

↑↓ moveenter openesc close