fix(images): scroll to the rescan's discovery alert only when the toast band covers it
D42 scrolled the alert into view after every rescan, so a user scrolled down the grid was sent back to the top. It now scrolls only when the alert intersects the toast's band (its scroll-margin-block-end).
This commit is contained in:
@@ -1592,6 +1592,30 @@ for (const width of [1600, 390]) {
|
||||
});
|
||||
}
|
||||
|
||||
// Final review m3: D42 scrolls only when the alert meets the toast's band, never back up to one above the window.
|
||||
test('Rescan does not scroll back to a discovery alert above the window', async ({ page }) => {
|
||||
await page.setViewportSize({ width: 1600, height: 1100 });
|
||||
await page.route('**/prompt_manager/library/options*', route => route.abort('failed'));
|
||||
await page.goto(workspace);
|
||||
await expect(cards(page)).toHaveCount(2);
|
||||
const alert = page.getByRole('alert');
|
||||
await expect(alert).toHaveText('Categories could not be loaded. Rescan from Import to retry.');
|
||||
await page.setViewportSize({ width: 1600, height: 260 });
|
||||
// Import is at the top; the page is scrolled down to the last card while its dialog is open.
|
||||
await page.getByRole('button', { name: 'Import', exact: true }).click();
|
||||
await cards(page).last().evaluate(node => node.scrollIntoView({ block: 'end' }));
|
||||
expect((await boxOf(alert)).bottom).toBeLessThan(0);
|
||||
// The reload itself may move the page; what D42 must not do is scroll the alert back into view.
|
||||
await alert.evaluate(node => {
|
||||
window.alertScrolls = 0;
|
||||
node.scrollIntoView = (...args) => { window.alertScrolls += 1; Element.prototype.scrollIntoView.apply(node, args); };
|
||||
});
|
||||
await importDialog(page).getByRole('button', { name: 'Rescan', exact: true }).click();
|
||||
await expect(toast(page)).toHaveText(/^Rescan finished\. /);
|
||||
await expect(alert).toBeAttached();
|
||||
expect(await page.evaluate(() => window.alertScrolls)).toBe(0);
|
||||
});
|
||||
|
||||
// #249 final review m8: D36's alphabetical categories hold whatever order the server sends.
|
||||
test('toolbar categories are alphabetical regardless of server order', async ({ page }) => {
|
||||
await page.route('**/prompt_manager/library/options*', route => route.fulfill({
|
||||
|
||||
@@ -648,12 +648,15 @@ export function mountImages(main, api, parentScope, {embedded = false, fetchPage
|
||||
}
|
||||
}
|
||||
/**
|
||||
* D42: the concept's toast stays fixed at the bottom, so a discovery alert the rescan leaves is scrolled, only when
|
||||
* it must be, clear of the toast's band (its `scroll-margin-block-end`).
|
||||
* D42: the concept's toast stays fixed at the bottom, so a discovery alert the rescan leaves is scrolled clear of
|
||||
* the toast's band (its `scroll-margin-block-end`) only when it is in that band; elsewhere the page stays put.
|
||||
*/
|
||||
function announceRescan(message) {
|
||||
showWorkspaceToast(message);
|
||||
if (!optionsStatus.hidden) optionsStatus.scrollIntoView({block:'nearest', inline:'nearest'});
|
||||
if (optionsStatus.hidden) return;
|
||||
const {top, bottom} = optionsStatus.getBoundingClientRect();
|
||||
const band = parseFloat(getComputedStyle(optionsStatus).scrollMarginBlockEnd) || 0;
|
||||
if (bottom > innerHeight - band && top < innerHeight) optionsStatus.scrollIntoView({block:'nearest', inline:'nearest'});
|
||||
}
|
||||
async function refreshInspectionCollection() {
|
||||
if (scope.signal.aborted) return;
|
||||
|
||||
Reference in New Issue
Block a user