Skip to content

🐛 更新页不再倒计时自动关闭,记录失效改为自动重查续做 - #1720

Open
CodFrm wants to merge 1 commit into
mainfrom
fix/batchupdate-remove-autoclose
Open

🐛 更新页不再倒计时自动关闭,记录失效改为自动重查续做#1720
CodFrm wants to merge 1 commit into
mainfrom
fix/batchupdate-remove-autoclose

Conversation

@CodFrm

@CodFrm CodFrm commented Sep 3, 2026

Copy link
Copy Markdown
Member

Checklist / 检查清单

  • Fixes mentioned issues / 修复已提及的问题
  • Code reviewed by human / 代码通过人工检查
  • Changes tested / 已完成测试

背景

定时检查发现有更新后,用户导航到命中站点的域名时,SW 会抢焦点弹出批量更新页,并在 URL 上带 autoclose=30;页面倒计时归零直接 window.close()#1715 报的就是"认真读页面上每个字,没看完页面就没了",而 #1087 报过同一件事——当时的处理是把 8 秒延长到 30 秒,service_worker/index.ts 里也留了"关于 autoclose,日后再检讨 UI/UX 设计"的注释。

倒计时是在补偿"我们擅自弹出了一个你没要求的标签页",方向反了:更新页同时是打扰源和决策界面,给决策界面装秒表只会把打扰变成焦虑。而且页面上唯一不刹车的交互恰好是"点脚本名看差异"——该链路要先联网 fetch 脚本源码才开出安装页,这几秒里倒计时照走,列表页可能在用户读差异时于后台自行关闭。

本次改动

去掉自动关闭机制(不是调参、不是加开关):URL 参数两处产地、hooks.ts 的倒计时状态与两个 effect、AutoCloseChip 组件与两个 props、移动端的分支渲染、10 个语言包的 3 个 key,以及 e2e 冒烟用例里残留的 &autoclose=30 一并移除。更新页从此只在用户点关闭时才关。

记录失效改为自动重查续做:删掉倒计时后页面会长时间开着,这暴露了原本被 30 秒关窗掩盖的问题——批量更新记录(ScriptUpdateCheck.cacheFull)只存在 Service Worker 内存里,页面通过 chrome.runtime.sendMessage 广播订阅、不持有长连接,因此不给 SW 保活;SW 闲置回收后再点更新只会拿到 record_expired,用户面对的是"按钮点了没用,请重新检查"。现在首次失效自动重新检查一次并接着做完剩余条目,重查后已经是最新的条目静默出队(不计为失败、不弹汇总),二次失效才落回原来的 RecordExpiredNotice

实现考虑

  • runUpdates 从固定 for 改成可变队列 + 下标:失效时下标停在原地、队列换成重查后的剩余项,rechecked 保证每次调用只自动重查一次,避免死循环。批量进度的 total 随队列长度重算;整批都已是最新时不留汇总条也不弹 toast。
  • 重查走 checkScriptUpdate({ checkType: "user" }),不传 noUpdateCheck,因此不会命中 canSkipScriptUpdateCheck 的节流;SW 侧该调用会 await 完整检查后才返回,页面可以直接串行等待。重查期间 SW 广播 CHECKING_UPDATE,页面顶部进度条即为反馈,未新增 UI 或文案。
  • 出队判定用重查后记录里的 checkUpdate 字段,而不是 categorize().updates——后者会排除已忽略项,会让"全部恢复并更新"路径把待办条目误判成已完成。
  • 自动重查不设置 userCheckPendingRef,因此不会像手动"检查更新"那样弹"发现 N 个更新"的 toast。

已知限制

  • 更新页仍然是 chrome.tabs.create 默认 active: true 抢焦点弹出的,只是不再自己关。是否改成后台标签打开属于弹出策略,本 PR 不动。
  • 未在真实浏览器里驱动构建产物。删倒计时由单测直接证伪;record_expired 自动重查是在 hook 边界用打桩的 SW 响应验证的,真实 SW 被回收那一刻的行为没有实机观察。
  • 顺带发现但未处理(不在本 PR 范围):GM 权限确认页 src/pages/confirm/App.tsx 的 30 秒倒计时会自动按"忽略"并关窗,且不因 document.hidden 暂停、没有任何交互刹车。它有正当理由(脚本调用阻塞中,必须有结论),但那两条缺陷值得单独修。

建议审查重点

  • 批量更新中途失效后重新检查、队列重排与进度条 total 的一致性(runUpdates 的 while 循环)。
  • 单条更新在重查后条目消失时,行状态被清掉且不报错,是否符合预期。
  • 二次失效仍然落到 RecordExpiredNotice,没有把用户困在无限重试里。

关联

close #1715 —— 同一诉求此前在 #1087 出现过,当时只延长了倒计时。

验证

范围绑定:base 61164f69 → head 80c7dd26git diff 61164f69...80c7dd26 --stat = 18 文件 +159/−256,全部落在 batchupdate 页面、其两处 URL 产地、10 个语言包与一条 e2e 冒烟用例内,无其它清理。

  • pnpm run lint → exit 0(prettier + tsc --noEmit + check:i18n + check:issue-templates + eslint 全过)
  • npx vitest run src/pages/batchupdate src/pages/install/useInstallData.test.ts src/app/service/service_worker/script.test.ts src/locales/i18n-usage.test.ts → 6 文件 195/195 通过
  • TDD 红→绿:新增的 URL 仍带 autoclose 参数时也不会自行关闭 在实现前失败于 expected "bound close" to not be called at all, but actually been called 1 times;4 个改写的"更新数据过期"用例实现前全部超时失败。
  • pnpm test 全量在本机因并发超时(testTimeout 850ms)大面积假失败,与本改动无关:同一份 main 代码两次跑分别是 3 failed 和 443 failed / 129 文件,本分支两次是 38 failed 和 170 failed,失败集中在 scripts/check-i18n.test.mjssrc/pkg/utils/match.test.tspopconfirm.test.tsx 等与 diff 无关的文件。所有涉及文件单独跑均通过(见上一条)。

自动弹出的批量更新页带 autoclose=30,30 秒后 window.close(),用户还没读完
更新说明页面就自己没了(#1715)。倒计时是在补偿「抢焦点弹出一个没人要求的标签
页」,方向反了:整套机制连同 URL 参数、药丸组件与三个 i18n key 一并移除。

页面因此会长时间开着,这暴露了原本被 30 秒关窗掩盖的问题:批量更新记录只存在
Service Worker 内存里,SW 被回收后点更新只会拿到 record_expired。现在首次失效
自动重新检查一次并接着做完剩余条目,重查后已是最新的条目静默出队、不计为失败,
二次失效才提示用户重新检查。

close #1715
@cyfung1031

cyfung1031 commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

「 更新页不再倒计时自动关闭」暂时没意见。之后有需要再处理
或者你可以把自动关闭改到15分钟
否则有机会会重复弹 (例如长时间挂机)

Agent好像也发现这个设计是预设会关掉的
强制不关的话可能会有问题

或者你只改参数把 auto_close 设为 -1 会简单一点

Sign up for free to 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] 脚本更新确认倒计时设计不人性化

2 participants