Skip to content

feat(history): add per-task version history#37

Open
wuwangzhang1216 wants to merge 5 commits into
nexu-io:mainfrom
wuwangzhang1216:feat/history-versions
Open

feat(history): add per-task version history#37
wuwangzhang1216 wants to merge 5 commits into
nexu-io:mainfrom
wuwangzhang1216:feat/history-versions

Conversation

@wuwangzhang1216
Copy link
Copy Markdown
Contributor

@wuwangzhang1216 wuwangzhang1216 commented May 15, 2026

Why this branch

This branch is ready to pick because the risky parts were exercised in-browser against the real app shell and are now covered by repeatable unit tests: IndexedDB writes, per-task GC, task deletion cleanup, restore commits, visual iframe compare, and source diff rendering. It also fixes the React update loop found during smoke QA after Convert.

What changed

  • Added an IndexedDB-backed per-task HTML version store under html-anything-history/runs with a 20-version cap.
  • Added the History pane: current version markers, restore, side-by-side iframe compare, and line-based DOM/source diff.
  • Cleaned history rows when a task is deleted and isolated pane contents by active task.
  • Persisted historyPaneOpen across refreshes.
  • Fixed DeployControl's empty deployments selector so Convert does not trigger a React maximum-update-depth crash.
  • Added Vitest coverage for the History IndexedDB store.

Screenshots

v1 -> v2 visual compare

History visual compare

Empty state, English

History empty state English

Empty state, zh-CN

History empty state zh-CN

Large HTML visual compare, 250KB+ input

Large HTML visual compare

Automated coverage

pnpm test now covers src/lib/history/db.ts with fake-indexeddb:

Test area Assertion
Version writes Versions increment per task and listRuns returns newest first.
20-version GC A noisy task keeps exactly the newest 20 versions and prunes the oldest row.
Task isolation Task A and Task B histories stay separate.
Delete cleanup deleteTaskRuns removes only the selected task's rows.
Single-run delete deleteRun removes a historical version without disturbing newer rows.
IDB unavailable putRun, reads, deletes, and clearAll degrade without throwing.

Browser QA evidence

Scenario Result
First Convert runs had 1 row, versions [1], currentVersion=1, pane showed v1 current and 刚刚.
Second Convert runs had 2 rows, versions [2, 1], currentVersion=2, v1 no longer had the current marker.
Compare Visual mode rendered 2 iframes for old/new HTML.
Show DOM diff Source mode rendered 22 diff rows with both red removals and green additions.
Restore v1 Restore committed a new baseline: 3 rows, versions [3, 2, 1], currentVersion=3, preview returned to v1 content.
20-version GC After repeated Convert, the task retained exactly 20 rows: versions v5 through v24; earlier rows were trimmed.
Delete task cleanup Deleted task had remainingRowsForDeleted=0 in IndexedDB.
Multi-task isolation Task A showed 3 versions, task B showed 1; switching back reset compare mode to list.
Refresh persistence After reload, historyPaneOpen=true and the active task's history remained visible.
Private/quota failure path Convert completed with status=done, generated HTML, and no red error logs when IDB was unavailable.
Light theme + locales Empty states verified in en and zh-CN; captured above.
250KB+ HTML diff Two 250KB+ inputs rendered in iframe compare; source diff had + and - rows and the scroll container remained responsive.

Verification

  • pnpm test — 5 tests passed.
  • pnpm build — passed.
  • Full browser smoke run via pnpm dev, with Application -> IndexedDB inspection for html-anything-history.

Note: build still emits the existing Turbopack NFT tracing warning for next.config.ts -> src/app/api/draft/route.ts; no new build failure was introduced.

@lefarcen lefarcen requested a review from PerishCode May 15, 2026 19:52
@lefarcen lefarcen added size/XL PR size: 700-1499 changed lines risk/high High-risk PR: dependencies, infra, security-sensitive, or broad runtime impact type/feature Feature or new user-facing capability labels May 15, 2026
@lefarcen
Copy link
Copy Markdown

Heads-up: #33 is also open against the same DeployControl loop area. Both PRs touch src/components/deploy-control.tsx and stabilize the empty deployments selector fallback tied to #32; this PR also includes the broader per-task history feature work.

You and @cszhouwei may want to compare scope so the focused bugfix and the larger feature work do not step on each other. The maintainer team will decide which path lands.

@PerishCode
Copy link
Copy Markdown
Contributor

Adding one update now that the public harness PR has landed on main: the requested rebase should target the new workspace shape.

Please keep the earlier review guidance, but map the files like this:

  • src/app/page.tsx -> next/src/app/page.tsx
  • src/components/history-pane.tsx / toolbar.tsx -> next/src/components/...
  • src/lib/history/db.ts and its tests -> next/src/lib/history/...
  • i18n/store changes -> next/src/lib/...
  • root vitest.config.mts should not be reintroduced; Next-package tests now run through next/vitest.config.ts with pnpm -F @html-anything/next test
  • root package.json scripts/deps should stay out of the PR; package changes, if still needed, belong in next/package.json

Recommended validation after rebase:

  • pnpm install --frozen-lockfile
  • pnpm exec tsx scripts/guard.ts
  • pnpm -F @html-anything/next typecheck
  • pnpm -F @html-anything/next test
  • pnpm -F @html-anything/next build
  • pnpm -F @html-anything/e2e test if the History pane gets browser coverage

I am not pushing directly here because this is a larger feature branch and the existing review asks for scope cleanup before another code pass.

Resolve conflicts after the workspace move into next/:

- Move src/components/history-pane.tsx -> next/src/components/history-pane.tsx
- Move src/lib/history/{db,db.test}.ts -> next/src/lib/history/
- Keep both HistoryToggle and CommunityLinks in toolbar.tsx
- Merge history.* and community.* strings in both i18n locales
- Add `diff`, `idb`, and `fake-indexeddb` to next/package.json
- Drop top-level vitest.config.mts (next has its own)
- Regenerate pnpm-lock.yaml
@wuwangzhang1216
Copy link
Copy Markdown
Contributor Author

wuwangzhang1216 commented May 20, 2026

Resolved conflicts with main and pushed to feat/history-versions (c9d2618).

Conflict resolution

File Action
src/components/history-pane.tsx Moved to next/src/components/history-pane.tsx (directory rename on main)
src/lib/history/{db,db.test}.ts Moved to next/src/lib/history/
next/src/components/toolbar.tsx Kept both PR's HistoryToggle and main's CommunityLinks (both are rendered)
next/src/lib/i18n.ts Kept both history.* and community.* keys in the type union and the en / zh-CN tables
package.json Took main's root version; added diff@^9, idb@^8, fake-indexeddb@^6 to next/package.json
pnpm-lock.yaml Regenerated via pnpm install --lockfile-only
vitest.config.mts Removed (next/vitest.config.ts already exists)

Verification

  • pnpm exec tsx scripts/guard.ts
  • pnpm -F @html-anything/next typecheck
  • pnpm -F @html-anything/e2e typecheck
  • pnpm -F @html-anything/next test — 6 files / 64 tests ✓ (includes the 6 history IndexedDB store cases)
  • pnpm -F @html-anything/next build

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

Labels

risk/high High-risk PR: dependencies, infra, security-sensitive, or broad runtime impact size/XL PR size: 700-1499 changed lines type/feature Feature or new user-facing capability

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants