Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## group-documents #2753 +/- ##
====================================================
- Coverage 85.78% 66.19% -19.59%
====================================================
Files 820 815 -5
Lines 44039 44110 +71
Branches 11255 11272 +17
====================================================
- Hits 37778 29200 -8578
- Misses 6245 14875 +8630
- Partials 16 35 +19
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
collaborative-learning
|
||||||||||||||||||||||||||||||||||
| Project |
collaborative-learning
|
| Branch Review |
CLUE-341-group-doc-live
|
| Run status |
|
| Run duration | 04m 43s |
| Commit |
|
| Committer | Scott Cytacki |
| View all properties for this run ↗︎ | |
| Test results | |
|---|---|
|
|
1
|
|
|
0
|
|
|
0
|
|
|
0
|
|
|
3
|
| View all changes introduced in this branch ↗︎ | |
Tests for review
cypress/e2e/smoke/single_student_canvas_test.js • 1 failed test • Smoke tests
| Test | Artifacts | |
|---|---|---|
| single student functional test > can copy all tiles into workspace and other documents using toolbar helpers |
Test Replay
Screenshots
|
|
04d1f1d to
5f71b20
Compare
There was a problem hiding this comment.
Pull request overview
Adds support for collaborative “group documents” by extending Firestore history handling to support concurrent edits, and updates the history debug UI/docs to help reproduce race conditions.
Changes:
- Introduces
FirestoreHistoryManagerConcurrentwith queued transactional uploads, remote history syncing, and pause/resume upload controls. - Updates history viewer UI to show more Firestore metadata (index, previousEntryId) and adds controls for pausing/resuming uploads.
- Adds documentation on group document behavior/known issues and adjusts tests accordingly.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/models/mst.test.ts | Adds/organizes MST snapshot tests, including instance reuse in arrays. |
| src/models/history/tree-manager-history.test.ts | Removes tests related to setNumHistoryEntriesAppliedFromFirestore. |
| src/models/history/firestore-history-manager.test.ts | Updates history loading tests/types to use HistoryEntrySnapshot and refines status expectations. |
| src/models/history/firestore-history-manager-concurrent.ts | Implements concurrent Firestore history manager with queueing, transactions, remote sync, and pause/resume. |
| src/components/document/history-view-panel.tsx | Enhances remote history display and adds pause/resume controls for concurrent manager. |
| src/components/document/history-view-panel.scss | Styles new history manager control buttons. |
| src/components/document/history-entry-item.tsx | Displays Firestore metadata and improves timestamp precision formatting. |
| src/components/document/canvas.tsx | Minor import ordering change. |
| docs/group-documents.md | New documentation describing group documents, known issues, and TODOs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| resumeUploadsAfterDelay(delayMs: number) { | ||
| setTimeout(() => { | ||
| runInAction(() => { | ||
| this.paused = false; | ||
| }); | ||
| this.uploadQueuedHistoryEntries(); | ||
| }, delayMs); | ||
| } |
There was a problem hiding this comment.
resumeUploadsAfterDelay() doesn’t track/cancel outstanding timers. Multiple clicks can schedule multiple timeouts, potentially resuming earlier/later than intended and triggering redundant upload attempts. Consider storing the timeout id (e.g., this.resumeTimeoutId) and clearing it before scheduling a new one, and also handle/record errors from uploadQueuedHistoryEntries() (see unhandled promise risk).
most complex change is better error handling in uploadQueuedHistoryEntries. The approach doesn't fully fix the problem, but at least it prevents a messed up uploadInProgress state.
tealefristoe
left a comment
There was a problem hiding this comment.
Looks good 👍
I found one possible issue in firestore-history-manager-concurrent.ts, but otherwise just a few minor suggestions/questions.
docs/group-documents.md
Outdated
| - user B deletes the first object | ||
| - resume user A's uploads | ||
|
|
||
| The result of this is that user B will see different object colors than user B. |
There was a problem hiding this comment.
| The result of this is that user B will see different object colors than user B. | |
| The result of this is that user A will see different object colors than user B. |
|
|
||
| The result of this is that user B will see different object colors than user B. | ||
|
|
||
| This behavior should happen for any common drawing object properties: fill color, stroke width, position, rotation, flipping. If there is a property like "text" of a text object that doesn't exist on other objects, this seems to just be ignored. It doesn't show an error in the console. |
There was a problem hiding this comment.
What happens if you change a property of the last object/delete the last object?
There was a problem hiding this comment.
It should behave the same as when the tile is deleted above. If the delete happens first, then when the property change gets applied to the deleted object there will be a MST error about trying to apply a patch to something that doesn't exist. But everything will look OK in the UI.
| - user B deletes the 2nd column | ||
| - resume user A's uploads | ||
|
|
||
| The result of this is that user B will see the value in new 2nd column which used to be 3rd column. |
There was a problem hiding this comment.
What if you modify/delete the last row?
There was a problem hiding this comment.
Should be the same as above. The patch will try to be applied to an object that doesn't exist. I didn't spell these out because these are all the same class of issue: an array of objects.
| - resume User A's updates (with a delay) | ||
| - User B starts editing a different cell, but doesn't hit enter or tab. This has to happen before User A's updates are applied to User B's document | ||
|
|
||
| In this case User B's edits will be lost. This happens even though they are in a different cell. The cursor and focus of User B is lost when the table is updated to show User A's changes. |
There was a problem hiding this comment.
This is an issue we went through great lengths to avoid in the collaborative table codap plugin.
There was a problem hiding this comment.
Yup it will be hard to get this right.
| // If we made it here then the transaction succeeded so we can remove the entriesToUpload | ||
| // from the queue. | ||
| this.completedHistoryEntryQueue.splice(0, entriesToUpload.length); |
There was a problem hiding this comment.
If there are 2 entries to upload, and the first succeeds, but the second fails, we won't update completedHistoryEntryQueue and the first entry will stay in the queue. Then if we try to upload entries again, we'll upload the first one again. It seems like we want to update completeHistoryEntryQueue every time we upload an entry, not when a whole batch succeeds.
There was a problem hiding this comment.
Because tis is running in a transaction, if any of the writes fail then they all will be rolled back. So it will be all or nothing. This is the reason to not update the completedHistoryEntryQueue inside of the transaction. There are supposed to be no side effects in the transaction because it can be run multiple times.
CLUE-341
Finally this PR adds support for a group document which shows remotes edits as they are made by other users in the group.
To test group documents you have to use a unit with the
groupDocumentsEnabledconfig set. Currently this might only be on the qa unit:unit=unit=./demo/units/qa/content.json.The history viewer debugging tool, has been updated so it shows more information, and so it can pause the sending of history entries up to Firestore. This makes it possible to deterministically re-create "race condition" issues. The group-documents.md describes some of these issues.
The document content is only loaded once when the document is first opened. After this all changes from remote users come in via history events. Changes to the remote document content in the realtime database are ignored. This is "ignore of changes to remote document document" is the same way normal CLUE documents behave when they are opened for editing. So there is no special code needed to get this behavior when editing a group document.
Known issues with this code are in group-documents.md
The following PR merges in master: #2757
The test that failed in this PR should be fixed in that one. And I'll make sure the rest of the Cypress tests pass in that follow on PR.