Path: blob/main/src/vs/workbench/contrib/comments/common/commentModel.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { URI } from '../../../../base/common/uri.js';6import { IRange } from '../../../../editor/common/core/range.js';7import { Comment, CommentThread, CommentThreadChangedEvent, CommentThreadApplicability, CommentThreadState } from '../../../../editor/common/languages.js';89export interface ICommentThreadChangedEvent extends CommentThreadChangedEvent<IRange> {10uniqueOwner: string;11owner: string;12ownerLabel: string;13}1415export class CommentNode {16isRoot: boolean = false;17replies: CommentNode[] = [];18public readonly threadId: string;19public readonly range: IRange | undefined;20public readonly threadState: CommentThreadState | undefined;21public readonly threadRelevance: CommentThreadApplicability | undefined;22public readonly contextValue: string | undefined;23public readonly controllerHandle: number;24public readonly threadHandle: number;2526constructor(27public readonly uniqueOwner: string,28public readonly owner: string,29public readonly resource: URI,30public readonly comment: Comment,31public readonly thread: CommentThread) {32this.threadId = thread.threadId;33this.range = thread.range;34this.threadState = thread.state;35this.threadRelevance = thread.applicability;36this.contextValue = thread.contextValue;37this.controllerHandle = thread.controllerHandle;38this.threadHandle = thread.commentThreadHandle;39}4041hasReply(): boolean {42return this.replies && this.replies.length !== 0;43}4445private _lastUpdatedAt: string | undefined;4647get lastUpdatedAt(): string {48if (this._lastUpdatedAt === undefined) {49let updatedAt = this.comment.timestamp || '';50if (this.replies.length) {51const reply = this.replies[this.replies.length - 1];52const replyUpdatedAt = reply.lastUpdatedAt;53if (replyUpdatedAt > updatedAt) {54updatedAt = replyUpdatedAt;55}56}57this._lastUpdatedAt = updatedAt;58}59return this._lastUpdatedAt;60}61}6263export class ResourceWithCommentThreads {64id: string;65uniqueOwner: string;66owner: string;67ownerLabel: string | undefined;68commentThreads: CommentNode[]; // The top level comments on the file. Replys are nested under each node.69resource: URI;7071constructor(uniqueOwner: string, owner: string, resource: URI, commentThreads: CommentThread[]) {72this.uniqueOwner = uniqueOwner;73this.owner = owner;74this.id = resource.toString();75this.resource = resource;76this.commentThreads = commentThreads.filter(thread => thread.comments && thread.comments.length).map(thread => ResourceWithCommentThreads.createCommentNode(uniqueOwner, owner, resource, thread));77}7879public static createCommentNode(uniqueOwner: string, owner: string, resource: URI, commentThread: CommentThread): CommentNode {80const { comments } = commentThread;81const commentNodes: CommentNode[] = comments!.map(comment => new CommentNode(uniqueOwner, owner, resource, comment, commentThread));82if (commentNodes.length > 1) {83commentNodes[0].replies = commentNodes.slice(1, commentNodes.length);84}8586commentNodes[0].isRoot = true;8788return commentNodes[0];89}9091private _lastUpdatedAt: string | undefined;9293get lastUpdatedAt() {94if (this._lastUpdatedAt === undefined) {95let updatedAt = '';96// Return result without cahcing as we expect data to arrive later97if (!this.commentThreads.length) {98return updatedAt;99}100for (const thread of this.commentThreads) {101const threadUpdatedAt = thread.lastUpdatedAt;102if (threadUpdatedAt && threadUpdatedAt > updatedAt) {103updatedAt = threadUpdatedAt;104}105}106this._lastUpdatedAt = updatedAt;107}108return this._lastUpdatedAt;109}110}111112113114