fix(ui): only show the previous-question button when a previous question exists - #2355

Merged
jackwener merged 1 commit into
apache:mainfrom
cat0825:fix/askuserquestion-previous-button
Aug 7, 2026
Merged

fix(ui): only show the previous-question button when a previous question exists#2355
jackwener merged 1 commit into
apache:mainfrom
cat0825:fix/askuserquestion-previous-button

Conversation

@cat0825

Copy link
Copy Markdown
Contributor

Closes#2354

问题

AskUserQuestion 弹窗底部操作区始终渲染"上一题"按钮,只用 isDisabledquestionIndex === 0 时禁用:

  • 单问题模式:questionIndex 恒为 0,按钮永远禁用但一直占据 UI
  • 多问题模式第一题:同样显示一个禁用的"上一题",第一题没有可回的上一题

期望:第一题(含单问题场景)不显示"上一题";从第二题开始才显示。

修复

packages/ui/src/user-question-prompt.tsx:将无条件渲染 + isDisabled 改为按 questionIndex > 0条件渲染,并去掉冗余的 questionIndex === 0 禁用判断(渲染条件已保证"有题可回")。

测试

  • SSR 单测conversation-localization.test.tsx,+2):单问题不渲染 上一题/Previous;多问题首题不渲染
  • e2eask-user-question.spec.ts,扩展三题流程):首题按钮 toHaveCount(0);次题出现"上一题",点击回退后已选答案保留、按钮消失,再前进继续原流程
  • 本地验证:packages/ui 444/444 通过;ask-user-question.spec.ts 2/2 通过(Playwright + Electron);biome 干净

行为对照

场景修复前修复后
单个问题禁用"上一题"常驻不显示
多问题·第一题禁用"上一题"常驻不显示
多问题·第二题起可用"上一题"可用"上一题"(不变)

@jackwener
jackwener merged commit acc063b into apache:mainAug 7, 2026
12 checks passed

@Astro-HanAstro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks — the core condition is right (questionIndex > 0, and the array is dense so it always equals 'a previous question exists'), the request event is atomic so streaming can't half-populate it, and the e2e pins the Q1-hidden/Q2-shown contract including 'not a disabled one'. CI green.

Four optional nits:

  • One-frame dirty render on session switch: staying on index>0 then switching sessions renders one frame of the new request's question with the old draft + previous button, before the effect resets. Pure visual (the click gets reset anyway), but a key={requestId} remount or an effect-less derivation would kill it.
  • Narrow containers: the footer grid moves 下一题 from col2 to col3 on Q2, so a fast double-click on the first question lands on the newly-appeared 上一题 and pops back — looks broken on ≤460px. Desktop width is fine (col4 is pinned).
  • Back-navigation focus is unpinned: only the forward direction has a toBeFocused assertion; the return path drops focus to body (same as before this PR, just untested).
  • The reset effect itself has zero coverage: unit tests only render index 0; a future refactor that breaks the sync would pass everything. One component test (advance to index>0, swap props.request, assert reset) would pin it cheaply.

Merging.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(ui): AskUserQuestion footer always renders a disabled "上一题 / Previous" button on the first (or only) question

3 participants

@cat0825@Astro-Han@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(ui): only show the previous-question button when a previous question exists - #2355

Merged
jackwener merged 1 commit into
apache:mainfrom
cat0825:fix/askuserquestion-previous-button
Aug 7, 2026
Merged

fix(ui): only show the previous-question button when a previous question exists#2355
jackwener merged 1 commit into
apache:mainfrom
cat0825:fix/askuserquestion-previous-button

Conversation

@cat0825

Copy link
Copy Markdown
Contributor

Closes#2354

问题

AskUserQuestion 弹窗底部操作区始终渲染"上一题"按钮,只用 isDisabledquestionIndex === 0 时禁用:

  • 单问题模式:questionIndex 恒为 0,按钮永远禁用但一直占据 UI
  • 多问题模式第一题:同样显示一个禁用的"上一题",第一题没有可回的上一题

期望:第一题(含单问题场景)不显示"上一题";从第二题开始才显示。

修复

packages/ui/src/user-question-prompt.tsx:将无条件渲染 + isDisabled 改为按 questionIndex > 0条件渲染,并去掉冗余的 questionIndex === 0 禁用判断(渲染条件已保证"有题可回")。

测试

  • SSR 单测conversation-localization.test.tsx,+2):单问题不渲染 上一题/Previous;多问题首题不渲染
  • e2eask-user-question.spec.ts,扩展三题流程):首题按钮 toHaveCount(0);次题出现"上一题",点击回退后已选答案保留、按钮消失,再前进继续原流程
  • 本地验证:packages/ui 444/444 通过;ask-user-question.spec.ts 2/2 通过(Playwright + Electron);biome 干净

行为对照

场景修复前修复后
单个问题禁用"上一题"常驻不显示
多问题·第一题禁用"上一题"常驻不显示
多问题·第二题起可用"上一题"可用"上一题"(不变)

@jackwener
jackwener merged commit acc063b into apache:mainAug 7, 2026
12 checks passed

@Astro-HanAstro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks — the core condition is right (questionIndex > 0, and the array is dense so it always equals 'a previous question exists'), the request event is atomic so streaming can't half-populate it, and the e2e pins the Q1-hidden/Q2-shown contract including 'not a disabled one'. CI green.

Four optional nits:

  • One-frame dirty render on session switch: staying on index>0 then switching sessions renders one frame of the new request's question with the old draft + previous button, before the effect resets. Pure visual (the click gets reset anyway), but a key={requestId} remount or an effect-less derivation would kill it.
  • Narrow containers: the footer grid moves 下一题 from col2 to col3 on Q2, so a fast double-click on the first question lands on the newly-appeared 上一题 and pops back — looks broken on ≤460px. Desktop width is fine (col4 is pinned).
  • Back-navigation focus is unpinned: only the forward direction has a toBeFocused assertion; the return path drops focus to body (same as before this PR, just untested).
  • The reset effect itself has zero coverage: unit tests only render index 0; a future refactor that breaks the sync would pass everything. One component test (advance to index>0, swap props.request, assert reset) would pin it cheaply.

Merging.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(ui): AskUserQuestion footer always renders a disabled "上一题 / Previous" button on the first (or only) question

3 participants

@cat0825@Astro-Han@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(ui): only show the previous-question button when a previous question exists - #2355

Merged
jackwener merged 1 commit into
apache:mainfrom
cat0825:fix/askuserquestion-previous-button
Aug 7, 2026
Merged

fix(ui): only show the previous-question button when a previous question exists#2355
jackwener merged 1 commit into
apache:mainfrom
cat0825:fix/askuserquestion-previous-button

Conversation

@cat0825

Copy link
Copy Markdown
Contributor

Closes#2354

问题

AskUserQuestion 弹窗底部操作区始终渲染"上一题"按钮,只用 isDisabledquestionIndex === 0 时禁用:

  • 单问题模式:questionIndex 恒为 0,按钮永远禁用但一直占据 UI
  • 多问题模式第一题:同样显示一个禁用的"上一题",第一题没有可回的上一题

期望:第一题(含单问题场景)不显示"上一题";从第二题开始才显示。

修复

packages/ui/src/user-question-prompt.tsx:将无条件渲染 + isDisabled 改为按 questionIndex > 0条件渲染,并去掉冗余的 questionIndex === 0 禁用判断(渲染条件已保证"有题可回")。

测试

  • SSR 单测conversation-localization.test.tsx,+2):单问题不渲染 上一题/Previous;多问题首题不渲染
  • e2eask-user-question.spec.ts,扩展三题流程):首题按钮 toHaveCount(0);次题出现"上一题",点击回退后已选答案保留、按钮消失,再前进继续原流程
  • 本地验证:packages/ui 444/444 通过;ask-user-question.spec.ts 2/2 通过(Playwright + Electron);biome 干净

行为对照

场景修复前修复后
单个问题禁用"上一题"常驻不显示
多问题·第一题禁用"上一题"常驻不显示
多问题·第二题起可用"上一题"可用"上一题"(不变)

@jackwener
jackwener merged commit acc063b into apache:mainAug 7, 2026
12 checks passed

@Astro-HanAstro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks — the core condition is right (questionIndex > 0, and the array is dense so it always equals 'a previous question exists'), the request event is atomic so streaming can't half-populate it, and the e2e pins the Q1-hidden/Q2-shown contract including 'not a disabled one'. CI green.

Four optional nits:

  • One-frame dirty render on session switch: staying on index>0 then switching sessions renders one frame of the new request's question with the old draft + previous button, before the effect resets. Pure visual (the click gets reset anyway), but a key={requestId} remount or an effect-less derivation would kill it.
  • Narrow containers: the footer grid moves 下一题 from col2 to col3 on Q2, so a fast double-click on the first question lands on the newly-appeared 上一题 and pops back — looks broken on ≤460px. Desktop width is fine (col4 is pinned).
  • Back-navigation focus is unpinned: only the forward direction has a toBeFocused assertion; the return path drops focus to body (same as before this PR, just untested).
  • The reset effect itself has zero coverage: unit tests only render index 0; a future refactor that breaks the sync would pass everything. One component test (advance to index>0, swap props.request, assert reset) would pin it cheaply.

Merging.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(ui): AskUserQuestion footer always renders a disabled "上一题 / Previous" button on the first (or only) question

3 participants

@cat0825@Astro-Han@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(ui): only show the previous-question button when a previous question exists - #2355

Merged
jackwener merged 1 commit into
apache:mainfrom
cat0825:fix/askuserquestion-previous-button
Aug 7, 2026
Merged

fix(ui): only show the previous-question button when a previous question exists#2355
jackwener merged 1 commit into
apache:mainfrom
cat0825:fix/askuserquestion-previous-button

Conversation

@cat0825

Copy link
Copy Markdown
Contributor

Closes#2354

问题

AskUserQuestion 弹窗底部操作区始终渲染"上一题"按钮,只用 isDisabledquestionIndex === 0 时禁用:

  • 单问题模式:questionIndex 恒为 0,按钮永远禁用但一直占据 UI
  • 多问题模式第一题:同样显示一个禁用的"上一题",第一题没有可回的上一题

期望:第一题(含单问题场景)不显示"上一题";从第二题开始才显示。

修复

packages/ui/src/user-question-prompt.tsx:将无条件渲染 + isDisabled 改为按 questionIndex > 0条件渲染,并去掉冗余的 questionIndex === 0 禁用判断(渲染条件已保证"有题可回")。

测试

  • SSR 单测conversation-localization.test.tsx,+2):单问题不渲染 上一题/Previous;多问题首题不渲染
  • e2eask-user-question.spec.ts,扩展三题流程):首题按钮 toHaveCount(0);次题出现"上一题",点击回退后已选答案保留、按钮消失,再前进继续原流程
  • 本地验证:packages/ui 444/444 通过;ask-user-question.spec.ts 2/2 通过(Playwright + Electron);biome 干净

行为对照

场景修复前修复后
单个问题禁用"上一题"常驻不显示
多问题·第一题禁用"上一题"常驻不显示
多问题·第二题起可用"上一题"可用"上一题"(不变)

@jackwener
jackwener merged commit acc063b into apache:mainAug 7, 2026
12 checks passed

@Astro-HanAstro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks — the core condition is right (questionIndex > 0, and the array is dense so it always equals 'a previous question exists'), the request event is atomic so streaming can't half-populate it, and the e2e pins the Q1-hidden/Q2-shown contract including 'not a disabled one'. CI green.

Four optional nits:

  • One-frame dirty render on session switch: staying on index>0 then switching sessions renders one frame of the new request's question with the old draft + previous button, before the effect resets. Pure visual (the click gets reset anyway), but a key={requestId} remount or an effect-less derivation would kill it.
  • Narrow containers: the footer grid moves 下一题 from col2 to col3 on Q2, so a fast double-click on the first question lands on the newly-appeared 上一题 and pops back — looks broken on ≤460px. Desktop width is fine (col4 is pinned).
  • Back-navigation focus is unpinned: only the forward direction has a toBeFocused assertion; the return path drops focus to body (same as before this PR, just untested).
  • The reset effect itself has zero coverage: unit tests only render index 0; a future refactor that breaks the sync would pass everything. One component test (advance to index>0, swap props.request, assert reset) would pin it cheaply.

Merging.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(ui): AskUserQuestion footer always renders a disabled "上一题 / Previous" button on the first (or only) question

3 participants

@cat0825@Astro-Han@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(ui): only show the previous-question button when a previous question exists - #2355

Merged
jackwener merged 1 commit into
apache:mainfrom
cat0825:fix/askuserquestion-previous-button
Aug 7, 2026
Merged

fix(ui): only show the previous-question button when a previous question exists#2355
jackwener merged 1 commit into
apache:mainfrom
cat0825:fix/askuserquestion-previous-button

Conversation

@cat0825

Copy link
Copy Markdown
Contributor

Closes#2354

问题

AskUserQuestion 弹窗底部操作区始终渲染"上一题"按钮,只用 isDisabledquestionIndex === 0 时禁用:

  • 单问题模式:questionIndex 恒为 0,按钮永远禁用但一直占据 UI
  • 多问题模式第一题:同样显示一个禁用的"上一题",第一题没有可回的上一题

期望:第一题(含单问题场景)不显示"上一题";从第二题开始才显示。

修复

packages/ui/src/user-question-prompt.tsx:将无条件渲染 + isDisabled 改为按 questionIndex > 0条件渲染,并去掉冗余的 questionIndex === 0 禁用判断(渲染条件已保证"有题可回")。

测试

  • SSR 单测conversation-localization.test.tsx,+2):单问题不渲染 上一题/Previous;多问题首题不渲染
  • e2eask-user-question.spec.ts,扩展三题流程):首题按钮 toHaveCount(0);次题出现"上一题",点击回退后已选答案保留、按钮消失,再前进继续原流程
  • 本地验证:packages/ui 444/444 通过;ask-user-question.spec.ts 2/2 通过(Playwright + Electron);biome 干净

行为对照

场景修复前修复后
单个问题禁用"上一题"常驻不显示
多问题·第一题禁用"上一题"常驻不显示
多问题·第二题起可用"上一题"可用"上一题"(不变)

@jackwener
jackwener merged commit acc063b into apache:mainAug 7, 2026
12 checks passed

@Astro-HanAstro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks — the core condition is right (questionIndex > 0, and the array is dense so it always equals 'a previous question exists'), the request event is atomic so streaming can't half-populate it, and the e2e pins the Q1-hidden/Q2-shown contract including 'not a disabled one'. CI green.

Four optional nits:

  • One-frame dirty render on session switch: staying on index>0 then switching sessions renders one frame of the new request's question with the old draft + previous button, before the effect resets. Pure visual (the click gets reset anyway), but a key={requestId} remount or an effect-less derivation would kill it.
  • Narrow containers: the footer grid moves 下一题 from col2 to col3 on Q2, so a fast double-click on the first question lands on the newly-appeared 上一题 and pops back — looks broken on ≤460px. Desktop width is fine (col4 is pinned).
  • Back-navigation focus is unpinned: only the forward direction has a toBeFocused assertion; the return path drops focus to body (same as before this PR, just untested).
  • The reset effect itself has zero coverage: unit tests only render index 0; a future refactor that breaks the sync would pass everything. One component test (advance to index>0, swap props.request, assert reset) would pin it cheaply.

Merging.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(ui): AskUserQuestion footer always renders a disabled "上一题 / Previous" button on the first (or only) question

3 participants

@cat0825@Astro-Han@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(ui): only show the previous-question button when a previous question exists - #2355

Merged
jackwener merged 1 commit into
apache:mainfrom
cat0825:fix/askuserquestion-previous-button
Aug 7, 2026
Merged

fix(ui): only show the previous-question button when a previous question exists#2355
jackwener merged 1 commit into
apache:mainfrom
cat0825:fix/askuserquestion-previous-button

Conversation

@cat0825

Copy link
Copy Markdown
Contributor

Closes#2354

问题

AskUserQuestion 弹窗底部操作区始终渲染"上一题"按钮,只用 isDisabledquestionIndex === 0 时禁用:

  • 单问题模式:questionIndex 恒为 0,按钮永远禁用但一直占据 UI
  • 多问题模式第一题:同样显示一个禁用的"上一题",第一题没有可回的上一题

期望:第一题(含单问题场景)不显示"上一题";从第二题开始才显示。

修复

packages/ui/src/user-question-prompt.tsx:将无条件渲染 + isDisabled 改为按 questionIndex > 0条件渲染,并去掉冗余的 questionIndex === 0 禁用判断(渲染条件已保证"有题可回")。

测试

  • SSR 单测conversation-localization.test.tsx,+2):单问题不渲染 上一题/Previous;多问题首题不渲染
  • e2eask-user-question.spec.ts,扩展三题流程):首题按钮 toHaveCount(0);次题出现"上一题",点击回退后已选答案保留、按钮消失,再前进继续原流程
  • 本地验证:packages/ui 444/444 通过;ask-user-question.spec.ts 2/2 通过(Playwright + Electron);biome 干净

行为对照

场景修复前修复后
单个问题禁用"上一题"常驻不显示
多问题·第一题禁用"上一题"常驻不显示
多问题·第二题起可用"上一题"可用"上一题"(不变)

@jackwener
jackwener merged commit acc063b into apache:mainAug 7, 2026
12 checks passed

@Astro-HanAstro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks — the core condition is right (questionIndex > 0, and the array is dense so it always equals 'a previous question exists'), the request event is atomic so streaming can't half-populate it, and the e2e pins the Q1-hidden/Q2-shown contract including 'not a disabled one'. CI green.

Four optional nits:

  • One-frame dirty render on session switch: staying on index>0 then switching sessions renders one frame of the new request's question with the old draft + previous button, before the effect resets. Pure visual (the click gets reset anyway), but a key={requestId} remount or an effect-less derivation would kill it.
  • Narrow containers: the footer grid moves 下一题 from col2 to col3 on Q2, so a fast double-click on the first question lands on the newly-appeared 上一题 and pops back — looks broken on ≤460px. Desktop width is fine (col4 is pinned).
  • Back-navigation focus is unpinned: only the forward direction has a toBeFocused assertion; the return path drops focus to body (same as before this PR, just untested).
  • The reset effect itself has zero coverage: unit tests only render index 0; a future refactor that breaks the sync would pass everything. One component test (advance to index>0, swap props.request, assert reset) would pin it cheaply.

Merging.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(ui): AskUserQuestion footer always renders a disabled "上一题 / Previous" button on the first (or only) question

3 participants

@cat0825@Astro-Han@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(ui): only show the previous-question button when a previous question exists - #2355

Merged
jackwener merged 1 commit into
apache:mainfrom
cat0825:fix/askuserquestion-previous-button
Aug 7, 2026
Merged

fix(ui): only show the previous-question button when a previous question exists#2355
jackwener merged 1 commit into
apache:mainfrom
cat0825:fix/askuserquestion-previous-button

Conversation

@cat0825

Copy link
Copy Markdown
Contributor

Closes#2354

问题

AskUserQuestion 弹窗底部操作区始终渲染"上一题"按钮,只用 isDisabledquestionIndex === 0 时禁用:

  • 单问题模式:questionIndex 恒为 0,按钮永远禁用但一直占据 UI
  • 多问题模式第一题:同样显示一个禁用的"上一题",第一题没有可回的上一题

期望:第一题(含单问题场景)不显示"上一题";从第二题开始才显示。

修复

packages/ui/src/user-question-prompt.tsx:将无条件渲染 + isDisabled 改为按 questionIndex > 0条件渲染,并去掉冗余的 questionIndex === 0 禁用判断(渲染条件已保证"有题可回")。

测试

  • SSR 单测conversation-localization.test.tsx,+2):单问题不渲染 上一题/Previous;多问题首题不渲染
  • e2eask-user-question.spec.ts,扩展三题流程):首题按钮 toHaveCount(0);次题出现"上一题",点击回退后已选答案保留、按钮消失,再前进继续原流程
  • 本地验证:packages/ui 444/444 通过;ask-user-question.spec.ts 2/2 通过(Playwright + Electron);biome 干净

行为对照

场景修复前修复后
单个问题禁用"上一题"常驻不显示
多问题·第一题禁用"上一题"常驻不显示
多问题·第二题起可用"上一题"可用"上一题"(不变)

@jackwener
jackwener merged commit acc063b into apache:mainAug 7, 2026
12 checks passed

@Astro-HanAstro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks — the core condition is right (questionIndex > 0, and the array is dense so it always equals 'a previous question exists'), the request event is atomic so streaming can't half-populate it, and the e2e pins the Q1-hidden/Q2-shown contract including 'not a disabled one'. CI green.

Four optional nits:

  • One-frame dirty render on session switch: staying on index>0 then switching sessions renders one frame of the new request's question with the old draft + previous button, before the effect resets. Pure visual (the click gets reset anyway), but a key={requestId} remount or an effect-less derivation would kill it.
  • Narrow containers: the footer grid moves 下一题 from col2 to col3 on Q2, so a fast double-click on the first question lands on the newly-appeared 上一题 and pops back — looks broken on ≤460px. Desktop width is fine (col4 is pinned).
  • Back-navigation focus is unpinned: only the forward direction has a toBeFocused assertion; the return path drops focus to body (same as before this PR, just untested).
  • The reset effect itself has zero coverage: unit tests only render index 0; a future refactor that breaks the sync would pass everything. One component test (advance to index>0, swap props.request, assert reset) would pin it cheaply.

Merging.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(ui): AskUserQuestion footer always renders a disabled "上一题 / Previous" button on the first (or only) question

3 participants

@cat0825@Astro-Han@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(ui): only show the previous-question button when a previous question exists - #2355

Merged
jackwener merged 1 commit into
apache:mainfrom
cat0825:fix/askuserquestion-previous-button
Aug 7, 2026
Merged

fix(ui): only show the previous-question button when a previous question exists#2355
jackwener merged 1 commit into
apache:mainfrom
cat0825:fix/askuserquestion-previous-button

Conversation

@cat0825

Copy link
Copy Markdown
Contributor

Closes#2354

问题

AskUserQuestion 弹窗底部操作区始终渲染"上一题"按钮,只用 isDisabledquestionIndex === 0 时禁用:

  • 单问题模式:questionIndex 恒为 0,按钮永远禁用但一直占据 UI
  • 多问题模式第一题:同样显示一个禁用的"上一题",第一题没有可回的上一题

期望:第一题(含单问题场景)不显示"上一题";从第二题开始才显示。

修复

packages/ui/src/user-question-prompt.tsx:将无条件渲染 + isDisabled 改为按 questionIndex > 0条件渲染,并去掉冗余的 questionIndex === 0 禁用判断(渲染条件已保证"有题可回")。

测试

  • SSR 单测conversation-localization.test.tsx,+2):单问题不渲染 上一题/Previous;多问题首题不渲染
  • e2eask-user-question.spec.ts,扩展三题流程):首题按钮 toHaveCount(0);次题出现"上一题",点击回退后已选答案保留、按钮消失,再前进继续原流程
  • 本地验证:packages/ui 444/444 通过;ask-user-question.spec.ts 2/2 通过(Playwright + Electron);biome 干净

行为对照

场景修复前修复后
单个问题禁用"上一题"常驻不显示
多问题·第一题禁用"上一题"常驻不显示
多问题·第二题起可用"上一题"可用"上一题"(不变)

@jackwener
jackwener merged commit acc063b into apache:mainAug 7, 2026
12 checks passed

@Astro-HanAstro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks — the core condition is right (questionIndex > 0, and the array is dense so it always equals 'a previous question exists'), the request event is atomic so streaming can't half-populate it, and the e2e pins the Q1-hidden/Q2-shown contract including 'not a disabled one'. CI green.

Four optional nits:

  • One-frame dirty render on session switch: staying on index>0 then switching sessions renders one frame of the new request's question with the old draft + previous button, before the effect resets. Pure visual (the click gets reset anyway), but a key={requestId} remount or an effect-less derivation would kill it.
  • Narrow containers: the footer grid moves 下一题 from col2 to col3 on Q2, so a fast double-click on the first question lands on the newly-appeared 上一题 and pops back — looks broken on ≤460px. Desktop width is fine (col4 is pinned).
  • Back-navigation focus is unpinned: only the forward direction has a toBeFocused assertion; the return path drops focus to body (same as before this PR, just untested).
  • The reset effect itself has zero coverage: unit tests only render index 0; a future refactor that breaks the sync would pass everything. One component test (advance to index>0, swap props.request, assert reset) would pin it cheaply.

Merging.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(ui): AskUserQuestion footer always renders a disabled "上一题 / Previous" button on the first (or only) question

3 participants

@cat0825@Astro-Han@jackwener