mirror of
https://github.com/nexu-io/open-design.git
synced 2026-09-20 06:15:06 +08:00
e19c057d8d
* fix(web): flip deck preview to a queued send's marked slide When several edits are queued against marked elements on different deck slides, the preview stayed parked on slide 1 while the agent drained the queue — the user couldn't see each edit land in context. The mark's slide index was already captured into the comment snapshot and target, but it was dropped when the snapshot became a ChatCommentAttachment, so nothing downstream knew which slide a queued send touched. Carry `slideIndex` through the contract and both attachment builders, then have ProjectView arm a `slideNavRequest` (mirroring `shareRequest`) the moment a queued send starts processing. FileWorkspace activates the deck tab if it is open and FileViewer consumes the nonce once to flip the preview via the existing `od:slide` go bridge, writing the cached slide state first so a freshly-mounted iframe restores to the same slide on load. No-op for plain prompts, free pins, or marks without a slide index. * fix(web): keep deck slide-nav consume-once across viewer remounts The consumed-nonce guard lived in a per-mount ref, so leaving the deck tab and returning remounted HtmlViewer, reset the ref, and replayed the still-live slideNavRequest — yanking the preview back to the queued slide and clobbering manual navigation. Move the guard into shouldConsumeSlideNav, keyed by preview state key outside the component, so "consume once" survives remounts. Add a unit spec covering first-handling, fresh-nonce, and per-file isolation. * fix(web): only flip a deck whose tab was open when the queued send started slideNavRequest stayed live in parent state, so a request for a deck that was closed at processing-start would resurface and jump the preview when the user opened that file by hand much later — not the follow-along behavior the feature promises. Decide deliverability once, at fire time: FileWorkspace marks the nonce deliverable only when the target deck is already an open tab, and the viewer is fed the request only for that deliverable nonce on the active file. A closed deck never becomes deliverable, so opening it later cannot jump. Pure helpers isSlideNavDeliverableNow / deliverableSlideNavForActiveFile carry the decision, with specs for the closed-deck-opened-later case.
63 lines
2.9 KiB
TypeScript
63 lines
2.9 KiB
TypeScript
import { beforeEach, describe, expect, it } from 'vitest';
|
|
|
|
import {
|
|
deliverableSlideNavForActiveFile,
|
|
isSlideNavDeliverableNow,
|
|
resetConsumedSlideNavForTests,
|
|
shouldConsumeSlideNav,
|
|
} from '../../src/runtime/slide-nav';
|
|
|
|
describe('shouldConsumeSlideNav', () => {
|
|
beforeEach(() => resetConsumedSlideNavForTests());
|
|
|
|
it('navigates only on the first handling of a request, even across remounts', () => {
|
|
const key = 'proj:deck.html';
|
|
// First mount handles the queued send's request → flip the preview.
|
|
expect(shouldConsumeSlideNav(key, 5)).toBe(true);
|
|
// The request stays live in parent state; leaving the deck tab and coming
|
|
// back remounts the viewer with the same nonce. It must NOT flip again —
|
|
// otherwise manual navigation after the queued send gets yanked back.
|
|
expect(shouldConsumeSlideNav(key, 5)).toBe(false);
|
|
expect(shouldConsumeSlideNav(key, 5)).toBe(false);
|
|
});
|
|
|
|
it('navigates again when a new queued send arms a fresh nonce', () => {
|
|
const key = 'proj:deck.html';
|
|
expect(shouldConsumeSlideNav(key, 5)).toBe(true);
|
|
expect(shouldConsumeSlideNav(key, 9)).toBe(true);
|
|
expect(shouldConsumeSlideNav(key, 9)).toBe(false);
|
|
});
|
|
|
|
it('tracks consumed nonces per file independently', () => {
|
|
expect(shouldConsumeSlideNav('proj:a.html', 5)).toBe(true);
|
|
expect(shouldConsumeSlideNav('proj:b.html', 5)).toBe(true);
|
|
expect(shouldConsumeSlideNav('proj:a.html', 5)).toBe(false);
|
|
expect(shouldConsumeSlideNav('proj:b.html', 5)).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('slide-nav deliverability (follow-along only)', () => {
|
|
it('is deliverable only when the target deck is already an open tab', () => {
|
|
expect(isSlideNavDeliverableNow({ name: 'deck.html' }, ['deck.html', 'index.html'])).toBe(true);
|
|
expect(isSlideNavDeliverableNow({ name: 'deck.html' }, ['index.html'])).toBe(false);
|
|
expect(isSlideNavDeliverableNow({ name: '' }, ['index.html'])).toBe(false);
|
|
expect(isSlideNavDeliverableNow(null, ['deck.html'])).toBe(false);
|
|
});
|
|
|
|
it('forwards a request to the active file once it is marked deliverable', () => {
|
|
const req = { name: 'deck.html', slideIndex: 3, nonce: 7 };
|
|
// Target was open at fire time → its nonce became deliverable.
|
|
expect(deliverableSlideNavForActiveFile(req, 'deck.html', 7)).toEqual({ slideIndex: 3, nonce: 7 });
|
|
});
|
|
|
|
it('does NOT jump a deck the user opens after a queued send started while it was closed', () => {
|
|
const req = { name: 'deck.html', slideIndex: 3, nonce: 7 };
|
|
// Deck was closed when the send started → nonce never became deliverable
|
|
// (deliverableNonce stays null). Later opening the deck makes it the active
|
|
// file, but the stale request must not resurface and flip the preview.
|
|
expect(deliverableSlideNavForActiveFile(req, 'deck.html', null)).toBeNull();
|
|
// A different deck being active never matches either.
|
|
expect(deliverableSlideNavForActiveFile(req, 'other.html', 7)).toBeNull();
|
|
});
|
|
});
|