Merge pull request #17910 from overleaf/em-comment-ids

Include id in history Comment instances

GitOrigin-RevId: 25b897e8e9e8d7b19dfe2d90d7f0cafeb5e6e97f
This commit is contained in:
Eric Mc Sween
2024-04-17 08:04:41 +00:00
committed by Copybot
parent 46afce9e09
commit ca8e7975b7
20 changed files with 222 additions and 188 deletions
@@ -21,10 +21,12 @@ class Comment {
resolved = false
/**
* @param {string} id
* @param {ReadonlyArray<Range>} ranges
* @param {boolean} [resolved]
*/
constructor(ranges, resolved = false) {
constructor(id, ranges, resolved = false) {
this.id = id
this.resolved = resolved
this.ranges = this.mergeRanges(ranges)
}
@@ -87,7 +89,7 @@ class Comment {
newRanges.push(new Range(cursor, length))
}
return new Comment(newRanges, this.resolved)
return new Comment(this.id, newRanges, this.resolved)
}
/**
@@ -108,7 +110,7 @@ class Comment {
}
}
return new Comment(newRanges, this.resolved)
return new Comment(this.id, newRanges, this.resolved)
}
/**
@@ -148,6 +150,7 @@ class Comment {
*/
toRaw() {
return {
id: this.id,
resolved: this.resolved,
ranges: this.ranges.map(range => range.toRaw()),
}
@@ -189,6 +192,7 @@ class Comment {
*/
static fromRaw(rawComment) {
return new Comment(
rawComment.id,
rawComment.ranges.map(range => Range.fromRaw(range)),
rawComment.resolved
)
+2 -1
View File
@@ -15,6 +15,7 @@ const StringFileData = require('./file_data/string_file_data')
* @typedef {import("./types").ReadonlyBlobStore} ReadonlyBlobStore
* @typedef {import("./types").StringFileRawData} StringFileRawData
* @typedef {import("./types").CommentRawData} CommentRawData
* @typedef {import("./file_data/comment_list")} CommentList
* @typedef {import("./operation/text_operation")} TextOperation
* @typedef {{filterTrackedDeletes?: boolean}} FileGetContentOptions
*/
@@ -203,7 +204,7 @@ class File {
/**
* Get the comments for this file.
*
* @return {CommentRawData[]}
* @return {CommentList}
*/
getComments() {
return this.data.getComments()
@@ -2,28 +2,45 @@
const Comment = require('../comment')
/**
* @typedef {import("../types").CommentsListRawData} CommentsListRawData
* @typedef {import("../types").CommentRawData} CommentRawData
* @typedef {import("../range")} Range
*/
class CommentList {
/**
* @param {Map<string, Comment>} comments
* @param {Comment[]} comments
*/
constructor(comments) {
this.comments = comments
this.comments = new Map(comments.map(comment => [comment.id, comment]))
}
/**
* @returns {CommentsListRawData}
* @returns {IterableIterator<Comment>}
*/
getComments() {
return Array.from(this.comments).map(([commentId, comment]) => {
return {
id: commentId,
...comment.toRaw(),
}
})
[Symbol.iterator]() {
return this.comments.values()
}
/**
* Return the length of the comment list
*
* @returns {number}
*/
get length() {
return this.comments.size
}
/**
* Return the raw version of the comment list
*
* @returns {CommentRawData[]}
*/
toRaw() {
const raw = []
for (const comment of this.comments.values()) {
raw.push(comment.toRaw())
}
return raw
}
/**
@@ -35,11 +52,10 @@ class CommentList {
}
/**
* @param {string} id
* @param {Comment} newComment
*/
add(id, newComment) {
this.comments.set(id, newComment)
add(newComment) {
this.comments.set(newComment.id, newComment)
}
/**
@@ -50,14 +66,10 @@ class CommentList {
}
/**
* @param {CommentsListRawData} rawComments
* @param {CommentRawData[]} rawComments
*/
static fromRaw(rawComments) {
const comments = new Map()
for (const rawComment of rawComments) {
comments.set(rawComment.id, Comment.fromRaw(rawComment))
}
return new CommentList(comments)
return new CommentList(rawComments.map(Comment.fromRaw))
}
/**
@@ -1,3 +1,5 @@
// @ts-check
'use strict'
const assert = require('check-types').assert
@@ -17,6 +19,7 @@ let StringFileData = null
* @typedef {import("../types").BlobStore} BlobStore
* @typedef {import("../types").ReadonlyBlobStore} ReadonlyBlobStore
* @typedef {import("../operation/edit_operation")} EditOperation
* @typedef {import("../file_data/comment_list")} CommentList
* @typedef {import("../types").CommentRawData} CommentRawData
*/
@@ -190,7 +193,7 @@ class FileData {
/**
* @see File#getComments
* @function
* @return {CommentRawData[]}
* @return {CommentList}
* @abstract
*/
getComments() {
@@ -11,7 +11,7 @@ const TrackedChangeList = require('./tracked_change_list')
* @typedef {import("../types").StringFileRawData} StringFileRawData
* @typedef {import("../operation/edit_operation")} EditOperation
* @typedef {import("../types").BlobStore} BlobStore
* @typedef {import("../types").CommentsListRawData} CommentsListRawData
* @typedef {import("../types").CommentRawData} CommentRawData
* @typedef {import("../types").TrackedChangeRawData} TrackedChangeRawData
* @typedef {import('../types').RangesBlob} RangesBlob
*/
@@ -19,7 +19,7 @@ const TrackedChangeList = require('./tracked_change_list')
class StringFileData extends FileData {
/**
* @param {string} content
* @param {CommentsListRawData} [rawComments]
* @param {CommentRawData[]} [rawComments]
* @param {TrackedChangeRawData[]} [rawTrackedChanges]
*/
constructor(content, rawComments = [], rawTrackedChanges = []) {
@@ -49,9 +49,8 @@ class StringFileData extends FileData {
toRaw() {
const raw = { content: this.content }
const comments = this.getComments()
if (comments.length) {
raw.comments = comments
if (this.comments.length) {
raw.comments = this.comments.toRaw()
}
if (this.trackedChanges.length) {
@@ -110,7 +109,7 @@ class StringFileData extends FileData {
/** @inheritdoc */
getComments() {
return this.comments.getComments()
return this.comments
}
/**
@@ -135,7 +134,7 @@ class StringFileData extends FileData {
if (this.comments.comments.size || this.trackedChanges.length) {
/** @type {RangesBlob} */
const ranges = {
comments: this.getComments(),
comments: this.getComments().toRaw(),
trackedChanges: this.trackedChanges.toRaw(),
}
const rangesBlob = await blobStore.putObject(ranges)
@@ -1,6 +1,7 @@
// @ts-check
const core = require('../../index')
const Comment = require('../comment')
const Range = require('../range')
const EditOperation = require('./edit_operation')
/**
@@ -16,12 +17,20 @@ const EditOperation = require('./edit_operation')
class AddCommentOperation extends EditOperation {
/**
* @param {string} commentId
* @param {Comment} comment
* @param {ReadonlyArray<Range>} ranges
* @param {boolean} resolved
*/
constructor(commentId, comment) {
constructor(commentId, ranges, resolved = false) {
super()
/** @readonly */
this.commentId = commentId
this.comment = comment
/** @readonly */
this.ranges = ranges
/** @readonly */
this.resolved = resolved
}
/**
@@ -30,8 +39,9 @@ class AddCommentOperation extends EditOperation {
*/
toJSON() {
return {
...this.comment.toRaw(),
commentId: this.commentId,
ranges: this.ranges.map(range => range.toRaw()),
resolved: this.resolved,
}
}
@@ -39,7 +49,9 @@ class AddCommentOperation extends EditOperation {
* @param {StringFileData} fileData
*/
apply(fileData) {
fileData.comments.add(this.commentId, this.comment)
fileData.comments.add(
new Comment(this.commentId, this.ranges, this.resolved)
)
}
/**
@@ -90,8 +102,11 @@ class AddCommentOperation extends EditOperation {
other instanceof core.SetCommentStateOperation &&
other.commentId === this.commentId
) {
const comment = new Comment(this.comment.ranges, other.resolved)
return new AddCommentOperation(this.commentId, comment)
return new AddCommentOperation(
this.commentId,
this.ranges,
other.resolved
)
}
throw new Error(
@@ -105,7 +120,11 @@ class AddCommentOperation extends EditOperation {
* @returns {AddCommentOperation}
*/
static fromJSON(raw) {
return new AddCommentOperation(raw.commentId, Comment.fromRaw(raw))
return new AddCommentOperation(
raw.commentId,
raw.ranges.map(Range.fromRaw),
raw.resolved ?? false
)
}
}
@@ -50,7 +50,11 @@ class DeleteCommentOperation extends EditOperation {
return new EditNoOperation()
}
return new core.AddCommentOperation(this.commentId, comment)
return new core.AddCommentOperation(
comment.id,
comment.ranges.slice(),
comment.resolved
)
}
/**
@@ -29,8 +29,16 @@ class EditOperationTransformer {
createTransformer(TextOperation, SetCommentStateOperation, noConflict),
createTransformer(TextOperation, AddCommentOperation, (a, b) => {
// apply the text operation to the comment
const movedComment = b.comment.applyTextOperation(a, b.commentId)
return [a, new AddCommentOperation(b.commentId, movedComment)]
const originalComment = new Comment(b.commentId, b.ranges, b.resolved)
const movedComment = originalComment.applyTextOperation(a, b.commentId)
return [
a,
new AddCommentOperation(
movedComment.id,
movedComment.ranges,
movedComment.resolved
),
]
}),
createTransformer(AddCommentOperation, AddCommentOperation, (a, b) => {
if (a.commentId === b.commentId) {
@@ -50,8 +58,11 @@ class EditOperationTransformer {
SetCommentStateOperation,
(a, b) => {
if (a.commentId === b.commentId) {
const mergedComment = new Comment(a.comment.ranges, b.resolved)
const newA = new AddCommentOperation(a.commentId, mergedComment)
const newA = new AddCommentOperation(
a.commentId,
a.ranges,
b.resolved
)
return [newA, b]
}
return [a, b]
@@ -42,8 +42,8 @@ class SetCommentStateOperation extends EditOperation {
apply(fileData) {
const comment = fileData.comments.getComment(this.commentId)
if (comment) {
const newComment = new Comment(comment.ranges, this.resolved)
fileData.comments.add(this.commentId, newComment)
const newComment = new Comment(comment.id, comment.ranges, this.resolved)
fileData.comments.add(newComment)
}
}
+12 -6
View File
@@ -11,7 +11,7 @@ export type BlobStore = {
export type ReadonlyBlobStore = Pick<BlobStore, 'getString' | 'getObject'>
export type RangesBlob = {
comments: CommentsListRawData
comments: CommentRawData[]
trackedChanges: TrackedChangeRawData[]
}
@@ -21,6 +21,7 @@ type Range = {
}
export type CommentRawData = {
id: string
ranges: Range[]
resolved?: boolean
}
@@ -36,11 +37,9 @@ export type TrackingPropsRawData = {
ts: string
}
export type CommentsListRawData = Array<{ id: string } & CommentRawData>
export type StringFileRawData = {
content: string
comments?: CommentsListRawData
comments?: CommentRawData[]
trackedChanges?: TrackedChangeRawData[]
}
@@ -69,11 +68,18 @@ export type RawTextOperation = {
textOperation: RawScanOp[]
}
export type RawAddCommentOperation = CommentRawData & { commentId: string }
export type RawAddCommentOperation = {
commentId: string
ranges: Range[]
resolved?: boolean
}
export type RawDeleteCommentOperation = { deleteComment: string }
export type RawSetCommentStateOperation = { commentId: string; resolved: boolean }
export type RawSetCommentStateOperation = {
commentId: string
resolved: boolean
}
export type RawEditOperation =
| RawTextOperation