mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
fix(tasks): preserve GitHub list scroll restoration (#17547)
This commit is contained in:
@@ -538,7 +538,10 @@ export default function TaskPage(): React.JSX.Element {
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const target = pendingGithubScrollRestoreRef.current
|
||||
if (target === null || !pages[currentPage]) {
|
||||
// Start observing as soon as the list mounts; its page rows may be committed
|
||||
// by a later render, and the restore helper will retry when they appear.
|
||||
// Keep the target armed while the detail route is transitioning and the list is still mounted.
|
||||
if (target === null || pageData.openGitHubWorkItem) {
|
||||
return
|
||||
}
|
||||
return startGitHubListScrollRestore({
|
||||
@@ -559,6 +562,7 @@ export default function TaskPage(): React.JSX.Element {
|
||||
currentPage,
|
||||
dialogWorkItem,
|
||||
githubResumeContextKey,
|
||||
pageData.openGitHubWorkItem,
|
||||
pages,
|
||||
githubListScrollTopRef,
|
||||
pendingGithubScrollRestoreRef,
|
||||
|
||||
@@ -106,6 +106,28 @@ describe('GitHub task list scroll restore', () => {
|
||||
expect(applied.at(-1)).toBe(360)
|
||||
})
|
||||
|
||||
it('retries when the rows mount after the restore starts', async () => {
|
||||
const list = createScrollList(0)
|
||||
list.element.removeChild(list.rows)
|
||||
const pendingRestoreRef = ref<number | null>(360)
|
||||
const restoreWriteRef = ref<GitHubListRestoreWrite | null>(null)
|
||||
|
||||
startGitHubListScrollRestore({
|
||||
target: 360,
|
||||
scrollElementRef: ref<HTMLElement | null>(list.element),
|
||||
pendingRestoreRef,
|
||||
restoreWriteRef,
|
||||
onScrollTopApplied: () => {}
|
||||
})
|
||||
|
||||
list.setMaxScrollTop(900)
|
||||
list.element.append(list.rows)
|
||||
await Promise.resolve()
|
||||
|
||||
expect(list.element.scrollTop).toBe(360)
|
||||
expect(pendingRestoreRef.current).toBeNull()
|
||||
})
|
||||
|
||||
it('keeps the remembered offset armed when the list never becomes tall enough', () => {
|
||||
const list = createScrollList(0)
|
||||
const pendingRestoreRef = ref<number | null>(360)
|
||||
|
||||
@@ -40,6 +40,7 @@ export function startGitHubListScrollRestore({
|
||||
restoreWriteRef.current = null
|
||||
let frame: number | null = null
|
||||
let observer: ResizeObserver | null = null
|
||||
let mutationObserver: MutationObserver | null = null
|
||||
const stop = (): void => {
|
||||
if (frame !== null) {
|
||||
window.cancelAnimationFrame(frame)
|
||||
@@ -47,6 +48,8 @@ export function startGitHubListScrollRestore({
|
||||
}
|
||||
observer?.disconnect()
|
||||
observer = null
|
||||
mutationObserver?.disconnect()
|
||||
mutationObserver = null
|
||||
}
|
||||
const restore = (): void => {
|
||||
const element = scrollElementRef.current
|
||||
@@ -72,6 +75,10 @@ export function startGitHubListScrollRestore({
|
||||
for (const child of scrollElement.children) {
|
||||
observer.observe(child)
|
||||
}
|
||||
// Rows can mount after this layout effect (for example when a cached page settles),
|
||||
// so observe child-list changes to cover elements that were not present initially.
|
||||
mutationObserver = new MutationObserver(restore)
|
||||
mutationObserver.observe(scrollElement, { childList: true, subtree: true })
|
||||
restore()
|
||||
if (pendingRestoreRef.current === target) {
|
||||
frame = window.requestAnimationFrame(restore)
|
||||
|
||||
Reference in New Issue
Block a user