mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 02:14:01 +00:00
fix(panels): a collapsed window keeps its chosen height; handle early tile failures
- A floating portable panel saved its measured box, so dragging a collapsed window stored its 50 px header strip and a reload clamped it to the minimum. It now saves the inline size the user chose. A unit test and a collapse -> drag -> reload -> expand step in the panel gate pin it. - Coverage awaits the tile fetch and the one-time terrain table load together, so a tile that fails before the table loads is reported at once instead of surfacing as an unhandled rejection. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
1fa129ea8e
commit
f33cd54e2b
5 files changed
+136
-10
No files matched your search
@@ -356,6 +356,61 @@ async function main() {
|
||||
near(restored[key], record[key], 2, `restored ${key}`);
|
||||
console.log('PASS: reload restores position and size');
|
||||
|
||||
// A collapsed window keeps the height chosen for it, through a drag of
|
||||
// its header strip and a reload.
|
||||
const setCollapsed = async (collapsed) => {
|
||||
await page.evaluate(
|
||||
(id, want) => {
|
||||
const panel = document.getElementById(id);
|
||||
if (panel.classList.contains('collapsed') !== want)
|
||||
document
|
||||
.querySelector(
|
||||
`.panel-collapse-btn[data-collapse-target="${id}"]`,
|
||||
)
|
||||
.click();
|
||||
},
|
||||
PANEL_ID,
|
||||
collapsed,
|
||||
);
|
||||
await page.waitForFunction(
|
||||
(id, want) =>
|
||||
document.getElementById(id).classList.contains('collapsed') === want,
|
||||
{},
|
||||
PANEL_ID,
|
||||
collapsed,
|
||||
);
|
||||
await nextFrames(page);
|
||||
};
|
||||
await drag(handlePoint(await readPanel(), 'se'), 0, 200);
|
||||
const chosen = await readPanel();
|
||||
assert.ok(
|
||||
chosen.height > MIN_SIZE.height + 150,
|
||||
`the window grew to ${chosen.height}px`,
|
||||
);
|
||||
await setCollapsed(true);
|
||||
const strip = await readPanel();
|
||||
assert.ok(strip.height < chosen.height - 100, 'collapsed to its header');
|
||||
await drag(await headerPoint(), 40, 30);
|
||||
const movedStrip = await readPanel();
|
||||
assert.equal(movedStrip.floating, true, 'the strip stays a window');
|
||||
near(
|
||||
JSON.parse(movedStrip.stored).height,
|
||||
chosen.height,
|
||||
2,
|
||||
'stored height while collapsed',
|
||||
);
|
||||
await boot();
|
||||
await setCollapsed(false);
|
||||
near(
|
||||
(await readPanel()).height,
|
||||
chosen.height,
|
||||
2,
|
||||
'height after expanding',
|
||||
);
|
||||
console.log(
|
||||
'PASS: a collapsed window keeps its height through a drag and a reload',
|
||||
);
|
||||
|
||||
const dock = await dockPanelByDoubleClick(page, PANEL_ID);
|
||||
const snapped = await readPanel();
|
||||
assert.equal(
|
||||
|
||||
@@ -510,12 +510,14 @@ export function createCoverage({ state, source }) {
|
||||
state.coverage.pending.set(key, controller);
|
||||
notify();
|
||||
try {
|
||||
// Fetch and the one-time terrain-height table load run side by side.
|
||||
const fetching = source.getTile('coverage', tile.z, tile.x, tile.y, {
|
||||
signal: controller.signal,
|
||||
});
|
||||
if (kind === 'sequence') await ensureTerrainReady();
|
||||
const bytes = await fetching;
|
||||
// Fetch and the one-time terrain-height table load run side by side,
|
||||
// both handled from the start so an early tile failure is not unhandled.
|
||||
const [bytes] = await Promise.all([
|
||||
source.getTile('coverage', tile.z, tile.x, tile.y, {
|
||||
signal: controller.signal,
|
||||
}),
|
||||
kind === 'sequence' ? ensureTerrainReady() : null,
|
||||
]);
|
||||
// Only an abort, a retire, a clear or a newer request for this tile
|
||||
// discards the bytes; a refresh that still wants the tile keeps them.
|
||||
const current = () =>
|
||||
|
||||
@@ -906,3 +906,27 @@ test('a line across the date line from the camera is in mesh range', () => {
|
||||
const far = { west: -179.99, east: -179.97, south: -0.001, north: 0.001 };
|
||||
assert.equal(meshBoxInRange(far, camera), false);
|
||||
});
|
||||
|
||||
test('a tile that fails before the terrain table loads is reported at once, never unhandled', async () => {
|
||||
const { source, state, coverage, tileKey } = setup();
|
||||
let terrainLoaded;
|
||||
state.coverage.terrainReady = new Promise((resolve) => {
|
||||
terrainLoaded = resolve;
|
||||
});
|
||||
const unhandled = [];
|
||||
const onUnhandled = (reason) => unhandled.push(reason);
|
||||
process.on('unhandledRejection', onUnhandled);
|
||||
try {
|
||||
coverage.refresh();
|
||||
source.calls
|
||||
.find((call) => call.key === tileKey)
|
||||
.reject(new Error('Mapillary tiles HTTP 500'));
|
||||
await new Promise((resolve) => setTimeout(resolve, 20));
|
||||
assert.equal(state.coverage.lastError, 'Mapillary tiles HTTP 500');
|
||||
assert.deepEqual(unhandled, []);
|
||||
} finally {
|
||||
terrainLoaded();
|
||||
await settle();
|
||||
process.off('unhandledRejection', onUnhandled);
|
||||
}
|
||||
});
|
||||
@@ -540,3 +540,41 @@ test('a floating header never lands under the command dock or voice pill', () =>
|
||||
f.restore();
|
||||
}
|
||||
});
|
||||
|
||||
test('a collapsed floating window keeps its chosen height through a drag and a reload', () => {
|
||||
const f = fixture();
|
||||
try {
|
||||
const { panel, handle } = floatingPanel(f, 'cctv-panel');
|
||||
panel.style.height = '500px';
|
||||
panel.classList.add('collapsed');
|
||||
// Collapsed, the window measures only its header strip.
|
||||
panel.getBoundingClientRect = () => {
|
||||
const left = parseFloat(panel.style.left);
|
||||
const top = parseFloat(panel.style.top);
|
||||
return {
|
||||
left,
|
||||
top,
|
||||
width: 360,
|
||||
height: 50,
|
||||
right: left + 360,
|
||||
bottom: top + 50,
|
||||
};
|
||||
};
|
||||
pointer(handle, 'pointerdown', { x: 200, y: 90 });
|
||||
pointer(window, 'pointermove', { x: 260, y: 140 });
|
||||
pointer(window, 'pointerup', { x: 260, y: 140 });
|
||||
const record = JSON.parse(
|
||||
f.store.get('godsEyeView.v8.panelPos.cctv-panel'),
|
||||
);
|
||||
assert.equal(record.height, 500, 'the chosen height, not the strip');
|
||||
assert.equal(record.width, 360);
|
||||
|
||||
// Reload: a fresh panel restores the size it expands to.
|
||||
const reloaded = f.element();
|
||||
reloaded.id = 'cctv-panel';
|
||||
f.owner._restorePanelPosition('cctv-panel', reloaded);
|
||||
assert.equal(reloaded.style.height, '500px');
|
||||
} finally {
|
||||
f.restore();
|
||||
}
|
||||
});
|
||||
@@ -429,10 +429,17 @@ export class PanelPositionControls {
|
||||
top: Math.round(rect.top),
|
||||
};
|
||||
if (this._portablePanels.has(panelId)) {
|
||||
// Only an explicitly set size is remembered: freezing a collapsed
|
||||
// panel's measured height would stop it from ever expanding again.
|
||||
if (panelEl.style.width) record.width = Math.round(rect.width);
|
||||
if (panelEl.style.height) record.height = Math.round(rect.height);
|
||||
// Only an explicitly set size is remembered, and the inline value
|
||||
// rather than the measured box: a collapsed window measures only its
|
||||
// header but keeps the size the user chose for when it expands.
|
||||
const chosen = (inline, measured) => {
|
||||
const px = parseFloat(inline);
|
||||
return Math.round(Number.isFinite(px) ? px : measured);
|
||||
};
|
||||
if (panelEl.style.width)
|
||||
record.width = chosen(panelEl.style.width, rect.width);
|
||||
if (panelEl.style.height)
|
||||
record.height = chosen(panelEl.style.height, rect.height);
|
||||
record.floating = true;
|
||||
}
|
||||
try {
|
||||
|
||||
Reference in new issue
Block a user