fix: place processing controls within the Console navigation box
This commit is contained in:
@@ -410,3 +410,65 @@ no document scroll at 1440x1000; the existing 1440x420 long-page checks remain.
|
||||
KS59 reverts processing.css to 0f8235277's bytes and must fail that same shell
|
||||
browser test. Total: 74 planned mutants. No test or mutant has run on this fix.
|
||||
Webby must statically review this delta before Sage opens the full no-carry gate.
|
||||
|
||||
|
||||
### Correction after Webby B1 (webby-0104, 2026-10-22 03:00Z)
|
||||
|
||||
The cause stated in the mos-1248/sage-2363 note above is withdrawn.
|
||||
processing.css loads after shell.css and already overrides the frame minimum.
|
||||
With the tree fixed and inspector hidden, the remaining floor is the Board's
|
||||
main content. The grid min-content row preserves that floor, so 5cd32f4c1
|
||||
is not an accepted layout fix. Its static review is CHANGES at Webby's
|
||||
REVIEW-layout.md, commit e2e7c60e5. No run established a new layout measurement.
|
||||
Next step requires a granted fixture probe for main/control heights and an
|
||||
owner layout ruling; no further product change or gate is authorized yet.
|
||||
Existing shell assertions remain unchanged.
|
||||
|
||||
|
||||
### Static nav placement: mos-1249/mos-1250, sage-2383/2385/2386, webby-0106/0108
|
||||
|
||||
Fast-forward on 5cd32f4c1; the rejected grid is removed. The unchanged labeled
|
||||
region is now the first child of nav.tree, before its Console h2. The banner
|
||||
stays at its original body location with every id, role, label and shipped
|
||||
string unchanged. No processing.js change and no runtime reparenting.
|
||||
At >=760 the tree is the same fixed box, with the same width breakpoints and
|
||||
ordinary overflow:auto. The controls are non-shrinking and non-sticky; they
|
||||
scroll with overflowing nav links (sage-2386 withdraws persistent visibility).
|
||||
Below760 the region takes a full flex line before Console/Projects. Its mobile
|
||||
location changes from before .frame to first in the static nav; the banner
|
||||
therefore precedes it in a halted mobile view. Banner behavior itself is unchanged.
|
||||
Specificity (0,3,0) resets .btn margin/order and .small margin/basis, leaving
|
||||
the shell rules unchanged. No content is shortened and no overflow is hidden.
|
||||
|
||||
Correct height arithmetic (Webby B1): page=max(innerHeight,86+C), where C is
|
||||
main content height. Controls consume space within the existing nav box, not
|
||||
another body row. The old failing layout was max(innerHeight,86+barHeight+C).
|
||||
The halted banner remains a body row; Sage tracks that separately.
|
||||
|
||||
Candidate-test design change at processing-ui.test.mjs:67 under mos-1250.
|
||||
Old assertion:
|
||||
```js
|
||||
assert.ok(html.indexOf('id="processing-controls"') < html.indexOf('<div class="frame">'));
|
||||
```
|
||||
New assertion text:
|
||||
```js
|
||||
const controlsAt = html.indexOf('id="processing-controls"');
|
||||
const mainAt = html.indexOf('<main id="main"'), inspectorAt = html.indexOf('<aside class="inspector"');
|
||||
assert.ok(controlsAt >= 0 && controlsAt < mainAt, 'controls are outside and before #main');
|
||||
assert.ok(!(inspectorAt < controlsAt && controlsAt < html.indexOf('</aside>', inspectorAt)),
|
||||
'controls are outside aside.inspector');
|
||||
```
|
||||
Reason: the bar moves into the frame's first column under mos-1249 while
|
||||
remaining outside route-specific #main and aside.inspector. This is a change
|
||||
to our unlanded candidate assertion, not a landed assertion.
|
||||
|
||||
All existing shell assertions stay unchanged. Added bar-inside-tree assertion
|
||||
and diagnostic height output. New processing browser coverage checks 400px
|
||||
Stop order=0, visibility, focus and position above Projects; also on-load
|
||||
visibility/focus at1440x1000,1440x420,800x420. Debug logs report controls/tree
|
||||
heights at those desktop sizes and main height; Sage judges controls over half
|
||||
the 334px nav at1440x420 before the window. No run yet.
|
||||
|
||||
Mutant delta: KS59 now reverts the complete layout (HTML and CSS together);
|
||||
KS60 hides the controls; KS61 moves them into #main; KS62 drops the (0,3,0)
|
||||
button reset. Total77. Every new site has its named killing test.
|
||||
|
||||
@@ -11,15 +11,15 @@
|
||||
<button type="button" class="cmdk" id="cmdk" aria-haspopup="dialog" aria-controls="cmdk-dialog"><svg class="i" aria-hidden="true"><use href="/icons.svg#i-search"/></svg><span>Go to a view, decision or task</span><kbd>Ctrl K</kbd></button>
|
||||
<p class="fresh" id="fresh"><span id="fresh-board"></span><span id="fresh-bus"></span></p>
|
||||
<div class="cmd-right"><label>Palette<select id="palette"></select></label><label>Appearance<select id="mode"><option value="system">system</option><option value="light">light</option><option value="dim">dim</option><option value="dark">dark</option></select></label><button class="btn" id="refresh" type="button">Refresh</button><button class="btn" id="pause" type="button" aria-pressed="false">Pause</button><form id="sign-out" method="post" action="/auth/logout" hidden><button class="btn" type="submit">Sign out</button></form></div></header>
|
||||
<div id="processing-controls" class="processing-controls" role="region" aria-label="Instance processing">
|
||||
<div id="processing-banner" class="processing-banner" role="alert" hidden></div>
|
||||
<div class="frame">
|
||||
<nav class="tree" aria-label="Console"><div id="processing-controls" class="processing-controls" role="region" aria-label="Instance processing">
|
||||
<strong>Processing</strong><p id="processing-state" role="status">Reading processing state.</p>
|
||||
<button id="processing-halt" type="button" class="btn" disabled>Stop processing</button>
|
||||
<button id="processing-resume" type="button" class="btn" disabled hidden>Resume processing</button>
|
||||
<p id="processing-unavailable" class="processing-note small muted">Processing controls are unavailable here. Use mosaic halt or mosaic resume from the instance CLI.</p>
|
||||
<p id="processing-receipt" class="processing-receipt small" aria-live="polite"></p></div>
|
||||
<div id="processing-banner" class="processing-banner" role="alert" hidden></div>
|
||||
<div class="frame">
|
||||
<nav class="tree" aria-label="Console"><h2 class="tree-title">Console</h2><ul class="s1-sections" id="sections"></ul><div id="board-tree"><h2 class="tree-title">Projects</h2><div id="projects"><p class="muted">Loading projects…</p></div><p class="small muted">Select a project to filter sessions. Waiting on you always shows all projects.</p></div></nav>
|
||||
<h2 class="tree-title">Console</h2><ul class="s1-sections" id="sections"></ul><div id="board-tree"><h2 class="tree-title">Projects</h2><div id="projects"><p class="muted">Loading projects…</p></div><p class="small muted">Select a project to filter sessions. Waiting on you always shows all projects.</p></div></nav>
|
||||
<main id="main" class="content" tabindex="-1"><div id="signed-out" class="banner ref" role="alert" tabindex="-1" hidden></div><div id="bus-down" class="banner err" role="alert" hidden></div><div class="page-head" id="board-head"><div><h1>Control board</h1><p id="status" class="small muted" role="status">Loading board…</p></div><div class="filters"><label><input id="show-machine" type="checkbox">Show machine sessions</label></div></div>
|
||||
<section id="held-section" aria-labelledby="held-title"><h2 id="held-title">Held roles <span id="held-count" class="count">–</span></h2><p class="small muted">The stack's seats: each role a run holds on the bus, from the bus <code>agents</code> read. Machine sessions are under Show machine sessions.</p><div id="held"><div class="skel-rows" aria-busy="true"><span class="sr-only">Reading the held roles.</span><span class="skel"></span><span class="skel"></span></div></div></section>
|
||||
<div id="error" class="banner err" role="alert" hidden></div>
|
||||
|
||||
@@ -5,26 +5,18 @@
|
||||
.processing-controls button:focus-visible { outline:3px solid currentColor; outline-offset:3px; }
|
||||
.processing-banner { padding:.75rem 1rem; font-weight:600; border-bottom:2px solid currentColor; }
|
||||
.processing-controls [hidden], .processing-banner[hidden] { display:none; }
|
||||
/* Keep the controls in normal flow. On desktop the frame fills the remaining
|
||||
viewport rather than adding a full viewport below the controls. Navigation
|
||||
retains the shell's command-bar/footer bounds independently of this bar. */
|
||||
/* The desktop controls share the nav's existing viewport box. They scroll with
|
||||
its contents: no sticky overlay may cover a focused navigation link. */
|
||||
.tree .processing-controls .btn { margin:0; order:0; }
|
||||
.tree .processing-controls .small { margin:0; flex-basis:100%; }
|
||||
@media (min-width:760px) {
|
||||
body {
|
||||
--processing-nav:240px;
|
||||
display:grid;
|
||||
grid-template-columns:minmax(0,1fr);
|
||||
grid-template-rows:auto auto auto minmax(min-content,1fr) auto;
|
||||
min-height:100vh;
|
||||
}
|
||||
.cmdbar { grid-row:1; }
|
||||
.processing-controls { grid-row:2; }
|
||||
.processing-banner { grid-row:3; }
|
||||
footer.foot { grid-row:5; }
|
||||
.processing-controls, .processing-banner { margin-left:var(--processing-nav); }
|
||||
.frame { grid-row:4; min-height:0; }
|
||||
body { --processing-nav:240px; }
|
||||
.processing-banner { margin-left:var(--processing-nav); }
|
||||
.tree > .processing-controls { flex:none; padding:.7rem .4rem; }
|
||||
.frame > .content { grid-column:2; }
|
||||
.frame > .tree { position:fixed; width:var(--processing-nav); }
|
||||
}
|
||||
@media (max-width:759px) { .tree > .processing-controls { flex-basis:100%; } }
|
||||
@media (min-width:760px) and (max-width:959px) { body { --processing-nav:200px; } }
|
||||
@media (min-width:1900px) { body { --processing-nav:280px; } }
|
||||
@media (min-width:2560px) { body { --processing-nav:320px; } }
|
||||
|
||||
@@ -93,3 +93,30 @@ for (const [name,path,kind] of [
|
||||
assert.equal(await b.evaluate('window.processingRequests.length'), count, 'no processing GET or POST after shared sign-out');
|
||||
if(kind==='signin') assert.equal(await b.evaluate(`!!document.querySelector('#signed-out a[href^="/auth/login"]')`), true);
|
||||
});
|
||||
|
||||
|
||||
test('processing browser: static nav controls keep Stop visible, ordered and keyboard reachable', async t => {
|
||||
const { b } = await setup(t);
|
||||
for (const [width, height] of [[400, 1000], [1440, 1000], [1440, 420], [800, 420]]) {
|
||||
await b.viewport(width, height);
|
||||
await b.evaluate('scrollTo(0,0);document.querySelector(".tree").scrollTop=0;true');
|
||||
const layout = await b.evaluate(`(() => {
|
||||
const controls = document.querySelector('#processing-controls'), stop = document.querySelector('#processing-halt');
|
||||
const c = controls.getBoundingClientRect(), n = document.querySelector('.tree').getBoundingClientRect();
|
||||
const s = stop.getBoundingClientRect(), bar = document.querySelector('.cmdbar').getBoundingClientRect();
|
||||
return { width: innerWidth, height: innerHeight, controls: c.height, tree: n.height,
|
||||
main: document.querySelector('#main').getBoundingClientRect().height,
|
||||
top: s.top, bottom: s.bottom, barBottom: bar.bottom,
|
||||
projectsTop: document.querySelector('#projects').getBoundingClientRect().top,
|
||||
order: getComputedStyle(stop).order, visible: stop.getClientRects().length > 0 &&
|
||||
getComputedStyle(stop).visibility === 'visible' && getComputedStyle(stop).display !== 'none' };
|
||||
})()`);
|
||||
console.log('ROW191_LAYOUT', JSON.stringify(layout));
|
||||
assert.ok(layout.visible && layout.top >= layout.barBottom && layout.bottom <= height,
|
||||
'Stop is visible below the command bar and inside the viewport on load');
|
||||
assert.equal(layout.order, '0', 'nav button rules do not reorder Stop');
|
||||
if (width === 400) assert.ok(layout.top < layout.projectsTop, 'Stop precedes Projects on mobile');
|
||||
await b.evaluate('document.querySelector("#processing-halt").focus();true');
|
||||
assert.equal(await b.evaluate('document.activeElement.id'), 'processing-halt');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -64,7 +64,11 @@ test('unknown writes are not retried or displayed as success and partial stops r
|
||||
});
|
||||
test('the persistent shell loads the control outside route-specific content with accessible status and native buttons', () => {
|
||||
const html = readFileSync(new URL('../src/public/index.html', import.meta.url), 'utf8');
|
||||
assert.ok(html.indexOf('id="processing-controls"') < html.indexOf('<div class="frame">'));
|
||||
const controlsAt = html.indexOf('id="processing-controls"');
|
||||
const mainAt = html.indexOf('<main id="main"'), inspectorAt = html.indexOf('<aside class="inspector"');
|
||||
assert.ok(controlsAt >= 0 && controlsAt < mainAt, 'controls are outside and before #main');
|
||||
assert.ok(!(inspectorAt < controlsAt && controlsAt < html.indexOf('</aside>', inspectorAt)),
|
||||
'controls are outside aside.inspector');
|
||||
assert.match(html, /src="\/processing.js"/); assert.match(html, /href="\/processing.css"/);
|
||||
assert.match(html, /id="processing-receipt"[^>]*aria-live="polite"/);
|
||||
assert.match(html, /<button[^>]*id="processing-halt"[^>]*type="button"/);
|
||||
|
||||
@@ -386,6 +386,17 @@ test('shell in a browser: System default, seeded states, 400px, focus and the Ct
|
||||
scroll: document.documentElement.scrollHeight };
|
||||
})())`));
|
||||
assert.ok(processingBar.visible && processingBar.height > 0, 'the processing bar is visible on the short Board');
|
||||
const treeRect = await b.evaluate(`(() => {
|
||||
const r = document.querySelector('.tree').getBoundingClientRect();
|
||||
return { top: r.top, bottom: r.bottom };
|
||||
})()`);
|
||||
assert.ok(processingBar.top >= treeRect.top && processingBar.bottom <= treeRect.bottom,
|
||||
'the processing bar sits inside the existing tree box');
|
||||
console.log('ROW191_LAYOUT', JSON.stringify(await b.evaluate(`(() => {
|
||||
const height = s => document.querySelector(s).getBoundingClientRect().height;
|
||||
return { width: innerWidth, height: innerHeight, controls: height('#processing-controls'),
|
||||
tree: height('.tree'), main: height('#main') };
|
||||
})()`)));
|
||||
assert.ok(processingBar.top >= bar[1] && processingBar.bottom <= processingBar.viewport,
|
||||
'the processing bar sits inside the viewport below the command bar');
|
||||
assert.equal(processingBar.scroll, processingBar.viewport, 'the visible processing bar adds no short-page scroll');
|
||||
|
||||
Reference in New Issue
Block a user