[web/document-updater] display preview for accepted/rejected tracked changes (#36240)

* [web] add preview payload to track-change notification types

* [doc-updater] pass accepted/rejected change data through to web for previews

* [web] snapshot change preview onto accepted/rejected notifications

* [web] render resolved change previews instead of accepted/rejected count lines

* [web] add unit coverage for accepted/rejected change preview flow

* fix: notification carries multiple previews per accept/reject batch; extract shared group helper

* fix: one preview per accept/reject action, drop adjacency grouping

* fix: move buildResolvedChangePreviews out of the email builder class

* fix: type error, make tests more explicit

* fix: render resolver below preview

* fix: overflow text, alignment

* fix: test error

* fix: resolved count

* [document-updater/web] send sparse change preview instead of full doc lines

* fix: store sparse preview, hydrate at render, drop CE gate

* fix: advance slice cursor past tracked-delete text in sparse preview

* fix: inline buildChangeGroupPreview

* fix: changePreviewBuilder -> sparseChangePreview

* fix: rm change_contributors

* fix: copilot flagged testing issues

* fix: hydrate and truncate change preview at write time

* fix: avoid materializing full doc text when slicing preview window

* fix: update reject preview test to hydrated shape

* fix: accepted delete removing context

* [document-updater/web] split resolved change previews into one per change cluster

* fix: narrow cluster userIds to string[] for typecheck

* feat: updating to use zod schema for previews

---------

Co-authored-by: Jimmy Domagala-Tang <jimmy.domagala-tang@overleaf.com>
GitOrigin-RevId: 0740713c715a61a220180f353e497b27da6a5b0f
This commit is contained in:
Kristina
2026-09-17 11:58:14 +00:00
committed by Copybot
co-authored by Jimmy Domagala-Tang
parent 3e0a54c917
commit 9c005e4e54
14 changed files with 699 additions and 41 deletions
@@ -92,6 +92,7 @@ describe('UpdateManager', function () {
},
}
this.buildSparseChangePreviews = sinon.stub().returns([])
this.UpdateManager = SandboxedModule.require(MODULE_PATH, {
requires: {
'./ProjectLockManager': this.ProjectLockManager,
@@ -107,6 +108,9 @@ describe('UpdateManager', function () {
'./WebApiManager': this.WebApiManager,
'./Profiler': this.Profiler,
'./ProjectHistoryRedisManager': this.ProjectHistoryRedisManager,
'./TrackedChangePreview': {
buildSparseChangePreviews: this.buildSparseChangePreviews,
},
},
})
})
@@ -610,6 +614,17 @@ describe('UpdateManager', function () {
historyUpdates: this.historyUpdates,
removedChangeIds: ['change-1', 'change-2'],
})
this.mockPreviews = [
{
sectionPath: ['Intro'],
startLine: 1,
changes: [{ d: 'x', p: 0 }],
slice: 'x',
sliceStart: 0,
userIds: ['author-1', 'author-2'],
},
]
this.buildSparseChangePreviews.returns(this.mockPreviews)
await this.UpdateManager.promises.applyUpdate(
this.project_id,
this.doc_id,
@@ -617,12 +632,23 @@ describe('UpdateManager', function () {
)
})
it('should notify web of the rejected tracked changes', function () {
it('should call buildSparseChangePreviews with the rejected changes and lines', function () {
this.buildSparseChangePreviews.should.have.been.calledWith({
changes: [
{ id: 'change-1', metadata: { user_id: 'author-1' } },
{ id: 'change-2', metadata: { user_id: 'author-2' } },
],
lines: this.lines,
})
})
it('should notify web of the rejected tracked changes with the previews', function () {
this.WebApiManager.promises.notifyTrackChangesRejected.should.have.been.calledWith(
this.project_id,
this.doc_id,
this.rejectedChangeAuthorIds,
this.updateMeta.user_id
this.updateMeta.user_id,
this.mockPreviews
)
})
})