fix(ui): preserve thinking detail scroll on rebuild
This commit is contained in:
parent
c5bb1fcaa0
commit
87ab74d1b9
2 changed files with 42 additions and 2 deletions
20
static/ui.js
20
static/ui.js
|
|
@ -8224,6 +8224,10 @@ function _worklogDetailBaseKey(el){
|
|||
function _worklogDetailDisclosureIsOpen(el){
|
||||
return !!(el&&el.classList&&el.classList.contains('open'));
|
||||
}
|
||||
function _worklogDetailScrollableBody(el){
|
||||
if(!el||!el.querySelector) return null;
|
||||
return el.querySelector('.thinking-card-body,.tool-card-detail');
|
||||
}
|
||||
function _setWorklogDetailDisclosureOpen(el, open){
|
||||
if(!el||!el.classList) return;
|
||||
el.classList.toggle('open', !!open);
|
||||
|
|
@ -8252,7 +8256,12 @@ function _captureWorklogDetailDisclosureState(root){
|
|||
const counts=Object.create(null);
|
||||
root.querySelectorAll(_worklogDetailDisclosureSelector).forEach(el=>{
|
||||
const key=_worklogDetailDisclosureKeyForElement(el, counts);
|
||||
if(key) state.set(key, _worklogDetailDisclosureIsOpen(el));
|
||||
if(!key) return;
|
||||
const body=_worklogDetailScrollableBody(el);
|
||||
state.set(key,{
|
||||
open:_worklogDetailDisclosureIsOpen(el),
|
||||
scrollTop:body?Math.max(0,Number(body.scrollTop)||0):0,
|
||||
});
|
||||
});
|
||||
return state;
|
||||
}
|
||||
|
|
@ -8264,7 +8273,14 @@ function _restoreWorklogDetailDisclosureState(root, state){
|
|||
root.querySelectorAll(_worklogDetailDisclosureSelector).forEach(el=>{
|
||||
const key=_worklogDetailDisclosureKeyForElement(el, counts);
|
||||
if(!key||!state.has(key)) return;
|
||||
_setWorklogDetailDisclosureOpen(el, state.get(key));
|
||||
const saved=state.get(key);
|
||||
const open=(saved&&typeof saved==='object'&&'open' in saved)?saved.open:saved;
|
||||
_setWorklogDetailDisclosureOpen(el, open);
|
||||
const scrollTop=(saved&&typeof saved==='object')?Number(saved.scrollTop):0;
|
||||
if(open&&Number.isFinite(scrollTop)&&scrollTop>0){
|
||||
const body=_worklogDetailScrollableBody(el);
|
||||
if(body) body.scrollTop=Math.min(scrollTop, Math.max(0, body.scrollHeight-body.clientHeight));
|
||||
}
|
||||
});
|
||||
}
|
||||
function _thinkingCardHtml(text, open){
|
||||
|
|
|
|||
|
|
@ -279,6 +279,30 @@ class TestToolCallGroupingStatic:
|
|||
"Restoring multi-tool groups must sync both CSS state and accessibility state."
|
||||
)
|
||||
|
||||
def test_render_rebuild_preserves_nested_worklog_detail_scroll_position(self):
|
||||
capture_fn = _function_body(UI_JS, "_captureWorklogDetailDisclosureState")
|
||||
restore_fn = _function_body(UI_JS, "_restoreWorklogDetailDisclosureState")
|
||||
body_fn = _function_body(UI_JS, "_worklogDetailScrollableBody")
|
||||
|
||||
assert ".thinking-card-body,.tool-card-detail" in body_fn, (
|
||||
"Nested scroll preservation must cover Thinking bodies and Tool details."
|
||||
)
|
||||
assert "_worklogDetailScrollableBody(el)" in capture_fn, (
|
||||
"The rebuild-state capture must inspect each detail's nested scroll container."
|
||||
)
|
||||
assert "scrollTop:body?Math.max(0,Number(body.scrollTop)||0):0" in capture_fn, (
|
||||
"The captured Worklog detail state must retain the nested scrollTop value."
|
||||
)
|
||||
assert "const saved=state.get(key)" in restore_fn, (
|
||||
"Restoration should read the structured state object for each detail."
|
||||
)
|
||||
assert "const open=(saved&&typeof saved==='object'&&'open' in saved)?saved.open:saved" in restore_fn, (
|
||||
"Restoration must remain backward-compatible with legacy boolean snapshots."
|
||||
)
|
||||
assert "body.scrollTop=Math.min(scrollTop, Math.max(0, body.scrollHeight-body.clientHeight))" in restore_fn, (
|
||||
"Restoration must reapply nested scrollTop after the rebuilt detail is opened."
|
||||
)
|
||||
|
||||
def test_worklog_detail_keys_stay_stable_while_streaming_content_grows(self):
|
||||
key_fn = _function_body(UI_JS, "_worklogDetailBaseKey")
|
||||
append_thinking_fn = _function_body(UI_JS, "appendThinking")
|
||||
|
|
|
|||
Loading…
Reference in a new issue