Skip to content

Commit

Permalink
Provide a way to add a timestamp or detail to a comment
Browse files Browse the repository at this point in the history
WIP for #139524
  • Loading branch information
alexr00 committed Jan 7, 2022
1 parent 0c93312 commit 60afb84
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 7 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"@vscode/sudo-prompt": "9.3.1",
"@vscode/vscode-languagedetection": "1.0.21",
"applicationinsights": "1.4.2",
"dayjs": "^1.10.7",
"graceful-fs": "4.2.8",
"http-proxy-agent": "^2.1.0",
"https-proxy-agent": "^2.2.3",
Expand Down
10 changes: 10 additions & 0 deletions src/vs/editor/common/languages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1663,6 +1663,15 @@ export enum CommentMode {
Preview = 1
}

/**
* @internal
*/
export interface Timestamp {
date: Date;
useRelativeTime?: boolean;
label?: string;
}

/**
* @internal
*/
Expand All @@ -1675,6 +1684,7 @@ export interface Comment {
readonly commentReactions?: CommentReaction[];
readonly label?: string;
readonly mode?: CommentMode;
readonly timestamp?: Timestamp;
}

/**
Expand Down
19 changes: 13 additions & 6 deletions src/vs/workbench/api/common/extHostComments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensio
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
import * as extHostTypeConverter from 'vs/workbench/api/common/extHostTypeConverters';
import * as types from 'vs/workbench/api/common/extHostTypes';
import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
import type * as vscode from 'vscode';
import { ExtHostCommentsShape, IMainContext, MainContext, CommentThreadChanges } from './extHost.protocol';
import { ExtHostCommands } from './extHostCommands';
Expand Down Expand Up @@ -346,7 +347,7 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo
private _uri: vscode.Uri,
private _range: vscode.Range,
private _comments: vscode.Comment[],
extensionId: ExtensionIdentifier
public readonly extensionDescription: IExtensionDescription
) {
this._acceptInputDisposables.value = new DisposableStore();

Expand All @@ -360,7 +361,7 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo
this._id,
this._uri,
extHostTypeConverter.Range.from(this._range),
extensionId
extensionDescription.identifier
);

this._localDisposables = [];
Expand Down Expand Up @@ -561,18 +562,18 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo
createCommentThread(resource: vscode.Uri, range: vscode.Range, comments: vscode.Comment[]): ExtHostCommentThread;
createCommentThread(arg0: vscode.Uri | string, arg1: vscode.Uri | vscode.Range, arg2: vscode.Range | vscode.Comment[], arg3?: vscode.Comment[]): vscode.CommentThread {
if (typeof arg0 === 'string') {
const commentThread = new ExtHostCommentThread(this.id, this.handle, arg0, arg1 as vscode.Uri, arg2 as vscode.Range, arg3 as vscode.Comment[], this._extension.identifier);
const commentThread = new ExtHostCommentThread(this.id, this.handle, arg0, arg1 as vscode.Uri, arg2 as vscode.Range, arg3 as vscode.Comment[], this._extension);
this._threads.set(commentThread.handle, commentThread);
return commentThread;
} else {
const commentThread = new ExtHostCommentThread(this.id, this.handle, undefined, arg0 as vscode.Uri, arg1 as vscode.Range, arg2 as vscode.Comment[], this._extension.identifier);
const commentThread = new ExtHostCommentThread(this.id, this.handle, undefined, arg0 as vscode.Uri, arg1 as vscode.Range, arg2 as vscode.Comment[], this._extension);
this._threads.set(commentThread.handle, commentThread);
return commentThread;
}
}

$createCommentThreadTemplate(uriComponents: UriComponents, range: IRange): ExtHostCommentThread {
const commentThread = new ExtHostCommentThread(this.id, this.handle, undefined, URI.revive(uriComponents), extHostTypeConverter.Range.to(range), [], this._extension.identifier);
const commentThread = new ExtHostCommentThread(this.id, this.handle, undefined, URI.revive(uriComponents), extHostTypeConverter.Range.to(range), [], this._extension);
commentThread.collapsibleState = modes.CommentThreadCollapsibleState.Expanded;
this._threads.set(commentThread.handle, commentThread);
return commentThread;
Expand Down Expand Up @@ -617,6 +618,10 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo

const iconPath = vscodeComment.author && vscodeComment.author.iconPath ? vscodeComment.author.iconPath.toString() : undefined;

if (vscodeComment.timestamp) {
checkProposedApiEnabled(thread.extensionDescription, 'commentTimestamp');
}

return {
mode: vscodeComment.mode,
contextValue: vscodeComment.contextValue,
Expand All @@ -625,7 +630,8 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo
userName: vscodeComment.author.name,
userIconPath: iconPath,
label: vscodeComment.label,
commentReactions: vscodeComment.reactions ? vscodeComment.reactions.map(reaction => convertToReaction(reaction)) : undefined
commentReactions: vscodeComment.reactions ? vscodeComment.reactions.map(reaction => convertToReaction(reaction)) : undefined,
timestamp: vscodeComment.timestamp
};
}

Expand Down Expand Up @@ -661,3 +667,4 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo

return new ExtHostCommentsImpl();
}

9 changes: 8 additions & 1 deletion src/vs/workbench/contrib/comments/browser/commentNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem';
import { Codicon } from 'vs/base/common/codicons';
import { MarshalledId } from 'vs/base/common/marshalling';
import { TimestampWidget } from 'vs/workbench/contrib/comments/browser/timestamp';

export class CommentNode extends Disposable {
private _domNode: HTMLElement;
Expand All @@ -53,6 +54,7 @@ export class CommentNode extends Disposable {
private _commentEditorDisposables: IDisposable[] = [];
private _commentEditorModel: ITextModel | null = null;
private _isPendingLabel!: HTMLElement;
private _timestamp: TimestampWidget | undefined;
private _contextKeyService: IContextKeyService;
private _commentContextValue: IContextKey<string>;

Expand Down Expand Up @@ -125,7 +127,8 @@ export class CommentNode extends Disposable {
const header = dom.append(commentDetailsContainer, dom.$(`div.comment-title.${MOUSE_CURSOR_TEXT_CSS_CLASS_NAME}`));
const author = dom.append(header, dom.$('strong.author'));
author.innerText = this.comment.userName;

this._timestamp = new TimestampWidget(header, this.comment.timestamp);
this._register(this._timestamp);
this._isPendingLabel = dom.append(header, dom.$('span.isPending'));

if (this.comment.label) {
Expand Down Expand Up @@ -516,6 +519,10 @@ export class CommentNode extends Disposable {
} else {
this._commentContextValue.reset();
}

if (this.comment.timestamp) {
this._timestamp?.setTimestamp(this.comment.timestamp);
}
}

focus() {
Expand Down
6 changes: 6 additions & 0 deletions src/vs/workbench/contrib/comments/browser/media/review.css
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@
font-style: italic;
}

.monaco-editor .review-widget .body .review-comment .review-comment-contents .timestamp {
line-height: 22px;
margin: 0 5px 0 5px;
padding: 0 2px 0 2px;
}

.monaco-editor .review-widget .body .review-comment .review-comment-contents .comment-body {
padding-top: 4px;
}
Expand Down
106 changes: 106 additions & 0 deletions src/vs/workbench/contrib/comments/browser/timestamp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as dom from 'vs/base/browser/dom';
import { Disposable } from 'vs/base/common/lifecycle';
import { Timestamp } from 'vs/editor/common/modes';
import * as dayjs from 'dayjs';
import * as relativeTime from 'dayjs/plugin/relativeTime';
import * as updateLocale from 'dayjs/plugin/updateLocale';
import * as localizedFormat from 'dayjs/plugin/localizedFormat'

dayjs.extend(relativeTime, {
thresholds: [
{ l: 's', r: 44, d: 'second' },
{ l: 'm', r: 89 },
{ l: 'mm', r: 44, d: 'minute' },
{ l: 'h', r: 89 },
{ l: 'hh', r: 21, d: 'hour' },
{ l: 'd', r: 35 },
{ l: 'dd', r: 6, d: 'day' },
{ l: 'w', r: 7 },
{ l: 'ww', r: 3, d: 'week' },
{ l: 'M', r: 4 },
{ l: 'MM', r: 10, d: 'month' },
{ l: 'y', r: 17 },
{ l: 'yy', d: 'year' },
],
});

dayjs.extend(updateLocale);
dayjs.updateLocale('en', {
relativeTime: {
past: '%s ago',
s: 'seconds',
m: 'a minute',
mm: '%d minutes',
h: 'an hour',
hh: '%d hours',
d: 'a day',
dd: '%d days',
w: 'a week',
ww: '%d weeks',
M: 'a month',
MM: '%d months',
y: 'a year',
yy: '%d years',
},
});
dayjs.extend(localizedFormat);

export class TimestampWidget extends Disposable {
private _date: HTMLElement;
private _timestamp: Timestamp | undefined;

constructor(container: HTMLElement, timeStamp?: Timestamp) {
super();
this._date = dom.append(container, dom.$('span.timestamp'));
this.setTimestamp(timeStamp);
}

public async setTimestamp(timestamp: Timestamp | undefined) {
if ((timestamp?.date !== this._timestamp?.date) || (timestamp?.useRelativeTime !== this._timestamp?.useRelativeTime)) {
this.updateDate(timestamp);
}
this._timestamp = timestamp;
}

private updateDate(timestamp?: Timestamp) {
if (!timestamp) {
this._date.textContent = '';
} else if ((timestamp.date !== this._timestamp?.date)
|| (timestamp.useRelativeTime !== this._timestamp.useRelativeTime)) {

let textContent: string;
let tooltip: string | undefined;
if (timestamp.useRelativeTime) {
textContent = this.getRelative(timestamp.date);
tooltip = timestamp.label ?? this.getDateString(timestamp.date);
} else {
textContent = timestamp.label ?? this.getDateString(timestamp.date);
}

this._date.textContent = textContent;
if (tooltip) {
this._date.title = tooltip;
}
}
}

private getRelative(date: Date): string {
const djs = dayjs(date);
const now = Date.now();
const diff = djs.diff(now, 'month');
if ((diff < 1) && (diff > -11)) {
return djs.fromNow();
}
return this.getDateString(date);
}

private getDateString(date: Date): string {
const djs = dayjs(date);
return djs.format('lll');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

export const allApiProposals = Object.freeze({
authSession: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.authSession.d.ts',
commentTimestamp: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.commentTimestamp.d.ts',
contribIconFonts: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribIconFonts.d.ts',
contribIcons: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribIcons.d.ts',
contribLabelFormatterWorkspaceTooltip: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribLabelFormatterWorkspaceTooltip.d.ts',
Expand Down
14 changes: 14 additions & 0 deletions src/vscode-dts/vscode.proposed.commentTimestamp.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

declare module 'vscode' {
export interface Comment {
timestamp?: {
date: Date,
label?: string,
useRelativeTime?: boolean
}
}
}
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3015,6 +3015,11 @@ data-uri-to-buffer@3:
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636"
integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==

dayjs@^1.10.7:
version "1.10.7"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.7.tgz#2cf5f91add28116748440866a0a1d26f3a6ce468"
integrity sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==

debounce@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.1.0.tgz#6a1a4ee2a9dc4b7c24bb012558dbcdb05b37f408"
Expand Down

0 comments on commit 60afb84

Please sign in to comment.