mirror of
https://github.com/microsoft/vscode.git
synced 2026-09-28 16:39:00 +01:00
Allow comment threads to provide user info for comment replies (#246187)
Part of #246088
This commit is contained in:
@@ -2066,7 +2066,7 @@ export interface CommentThread<T = IRange> {
|
||||
onDidChangeInitialCollapsibleState: Event<CommentThreadCollapsibleState | undefined>;
|
||||
state?: CommentThreadState;
|
||||
applicability?: CommentThreadApplicability;
|
||||
canReply: boolean;
|
||||
canReply: boolean | CommentAuthorInformation;
|
||||
input?: CommentInput;
|
||||
onDidChangeInput: Event<CommentInput | undefined>;
|
||||
onDidChangeLabel: Event<string | undefined>;
|
||||
|
||||
@@ -62,6 +62,9 @@ const _allApiProposals = {
|
||||
commentReactor: {
|
||||
proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.commentReactor.d.ts',
|
||||
},
|
||||
commentReplyAuthor: {
|
||||
proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.commentReplyAuthor.d.ts',
|
||||
},
|
||||
commentReveal: {
|
||||
proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.commentReveal.d.ts',
|
||||
},
|
||||
|
||||
@@ -93,9 +93,9 @@ export class MainThreadCommentThread<T> implements languages.CommentThread<T> {
|
||||
|
||||
private readonly _onDidChangeCanReply = new Emitter<boolean>();
|
||||
get onDidChangeCanReply(): Event<boolean> { return this._onDidChangeCanReply.event; }
|
||||
set canReply(state: boolean) {
|
||||
set canReply(state: boolean | languages.CommentAuthorInformation) {
|
||||
this._canReply = state;
|
||||
this._onDidChangeCanReply.fire(this._canReply);
|
||||
this._onDidChangeCanReply.fire(!!this._canReply);
|
||||
}
|
||||
|
||||
get canReply() {
|
||||
@@ -182,7 +182,7 @@ export class MainThreadCommentThread<T> implements languages.CommentThread<T> {
|
||||
public resource: string,
|
||||
private _range: T | undefined,
|
||||
comments: languages.Comment[] | undefined,
|
||||
private _canReply: boolean,
|
||||
private _canReply: boolean | languages.CommentAuthorInformation,
|
||||
private _isTemplate: boolean,
|
||||
public editorId?: string
|
||||
) {
|
||||
|
||||
@@ -141,7 +141,7 @@ export type CommentThreadChanges<T = IRange> = Partial<{
|
||||
contextValue: string | null;
|
||||
comments: CommentChanges[];
|
||||
collapseState: languages.CommentThreadCollapsibleState;
|
||||
canReply: boolean;
|
||||
canReply: boolean | languages.CommentAuthorInformation;
|
||||
state: languages.CommentThreadState;
|
||||
applicability: languages.CommentThreadApplicability;
|
||||
isTemplate: boolean;
|
||||
|
||||
@@ -268,7 +268,7 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo
|
||||
contextValue: string | undefined;
|
||||
comments: vscode.Comment[];
|
||||
collapsibleState: vscode.CommentThreadCollapsibleState;
|
||||
canReply: boolean;
|
||||
canReply: boolean | vscode.CommentAuthorInformation;
|
||||
state: vscode.CommentThreadState;
|
||||
isTemplate: boolean;
|
||||
applicability: vscode.CommentThreadApplicability;
|
||||
@@ -316,9 +316,13 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo
|
||||
return this._range;
|
||||
}
|
||||
|
||||
private _canReply: boolean = true;
|
||||
private _canReply: boolean | vscode.CommentAuthorInformation = true;
|
||||
|
||||
set canReply(state: boolean | vscode.CommentAuthorInformation) {
|
||||
if (typeof state !== 'boolean') {
|
||||
checkProposedApiEnabled(this.extensionDescription, 'commentReplyAuthor');
|
||||
}
|
||||
|
||||
set canReply(state: boolean) {
|
||||
if (this._canReply !== state) {
|
||||
this._canReply = state;
|
||||
this.modifications.canReply = state;
|
||||
@@ -465,7 +469,7 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo
|
||||
get collapsibleState() { return that.collapsibleState; },
|
||||
set collapsibleState(value: vscode.CommentThreadCollapsibleState) { that.collapsibleState = value; },
|
||||
get canReply() { return that.canReply; },
|
||||
set canReply(state: boolean) { that.canReply = state; },
|
||||
set canReply(state: boolean | vscode.CommentAuthorInformation) { that.canReply = state; },
|
||||
get contextValue() { return that.contextValue; },
|
||||
set contextValue(value: string | undefined) { that.contextValue = value; },
|
||||
get label() { return that.label; },
|
||||
|
||||
@@ -223,7 +223,7 @@ export class CommentNode<T extends IRange | ICellRange> extends Disposable {
|
||||
private updateCommentUserIcon(userIconPath: UriComponents | undefined) {
|
||||
this._avatar.textContent = '';
|
||||
if (userIconPath) {
|
||||
const img = <HTMLImageElement>dom.append(this._avatar, dom.$('img.avatar'));
|
||||
const img = dom.append(this._avatar, dom.$('img.avatar')) as HTMLImageElement;
|
||||
img.src = FileAccess.uriToBrowserUri(URI.revive(userIconPath)).toString(true);
|
||||
img.onerror = _ => img.remove();
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { MOUSE_CURSOR_TEXT_CSS_CLASS_NAME } from '../../../../base/browser/ui/mo
|
||||
import { IAction } from '../../../../base/common/actions.js';
|
||||
import { Disposable, IDisposable, dispose } from '../../../../base/common/lifecycle.js';
|
||||
import { MarshalledId } from '../../../../base/common/marshallingIds.js';
|
||||
import { Schemas } from '../../../../base/common/network.js';
|
||||
import { FileAccess, Schemas } from '../../../../base/common/network.js';
|
||||
import { URI } from '../../../../base/common/uri.js';
|
||||
import { generateUuid } from '../../../../base/common/uuid.js';
|
||||
import { ICodeEditor } from '../../../../editor/browser/editorBrowser.js';
|
||||
@@ -38,8 +38,10 @@ export const COMMENTEDITOR_DECORATION_KEY = 'commenteditordecoration';
|
||||
|
||||
export class CommentReply<T extends IRange | ICellRange> extends Disposable {
|
||||
commentEditor: ICodeEditor;
|
||||
form: HTMLElement;
|
||||
private _container: HTMLElement;
|
||||
private _form: HTMLElement;
|
||||
commentEditorIsEmpty: IContextKey<boolean>;
|
||||
private avatar!: HTMLElement;
|
||||
private _error!: HTMLElement;
|
||||
private _formActions!: HTMLElement;
|
||||
private _editorActions!: HTMLElement;
|
||||
@@ -70,16 +72,18 @@ export class CommentReply<T extends IRange | ICellRange> extends Disposable {
|
||||
@ITextModelService private readonly textModelService: ITextModelService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.form = dom.append(container, dom.$('.comment-form'));
|
||||
this.commentEditor = this._register(this._scopedInstatiationService.createInstance(SimpleCommentEditor, this.form, SimpleCommentEditor.getEditorOptions(configurationService), _contextKeyService, this._parentThread));
|
||||
this._container = dom.append(container, dom.$('.comment-form-container'));
|
||||
this._form = dom.append(this._container, dom.$('.comment-form'));
|
||||
this.commentEditor = this._register(this._scopedInstatiationService.createInstance(SimpleCommentEditor, this._form, SimpleCommentEditor.getEditorOptions(configurationService), _contextKeyService, this._parentThread));
|
||||
this.commentEditorIsEmpty = CommentContextKeys.commentIsEmpty.bindTo(this._contextKeyService);
|
||||
this.commentEditorIsEmpty.set(!this._pendingComment);
|
||||
|
||||
this.initialize(focus);
|
||||
}
|
||||
|
||||
async initialize(focus: boolean) {
|
||||
private async initialize(focus: boolean) {
|
||||
this.avatar = dom.append(this._form, dom.$('.avatar-container'));
|
||||
this.updateAuthorInfo();
|
||||
const hasExistingComments = this._commentThread.comments && this._commentThread.comments.length > 0;
|
||||
const modeId = generateUuid() + '-' + (hasExistingComments ? this._commentThread.threadId : ++INMEM_MODEL_ID);
|
||||
const params = JSON.stringify({
|
||||
@@ -115,7 +119,7 @@ export class CommentReply<T extends IRange | ICellRange> extends Disposable {
|
||||
}
|
||||
}));
|
||||
|
||||
this.createTextModelListener(this.commentEditor, this.form);
|
||||
this.createTextModelListener(this.commentEditor, this._form);
|
||||
|
||||
this.setCommentEditorDecorations();
|
||||
|
||||
@@ -123,12 +127,12 @@ export class CommentReply<T extends IRange | ICellRange> extends Disposable {
|
||||
if (this._pendingComment) {
|
||||
this.expandReplyArea();
|
||||
} else if (hasExistingComments) {
|
||||
this.createReplyButton(this.commentEditor, this.form);
|
||||
this.createReplyButton(this.commentEditor, this._form);
|
||||
} else if (focus && (this._commentThread.comments && this._commentThread.comments.length === 0)) {
|
||||
this.expandReplyArea();
|
||||
}
|
||||
this._error = dom.append(this.form, dom.$('.validation-error.hidden'));
|
||||
const formActions = dom.append(this.form, dom.$('.form-actions'));
|
||||
this._error = dom.append(this._container, dom.$('.validation-error.hidden'));
|
||||
const formActions = dom.append(this._container, dom.$('.form-actions'));
|
||||
this._formActions = dom.append(formActions, dom.$('.other-actions'));
|
||||
this.createCommentWidgetFormActions(this._formActions, model.object.textEditorModel);
|
||||
this._editorActions = dom.append(formActions, dom.$('.editor-actions'));
|
||||
@@ -149,7 +153,7 @@ export class CommentReply<T extends IRange | ICellRange> extends Disposable {
|
||||
const oldAndNewBothEmpty = !this._commentThread.comments?.length && !commentThread.comments?.length;
|
||||
|
||||
if (!this._reviewThreadReplyButton) {
|
||||
this.createReplyButton(this.commentEditor, this.form);
|
||||
this.createReplyButton(this.commentEditor, this._form);
|
||||
}
|
||||
|
||||
if (this._commentThread.comments && this._commentThread.comments.length === 0 && !oldAndNewBothEmpty) {
|
||||
@@ -203,11 +207,23 @@ export class CommentReply<T extends IRange | ICellRange> extends Disposable {
|
||||
return this.commentEditor.hasWidgetFocus();
|
||||
}
|
||||
|
||||
public updateCanReply() {
|
||||
if (!this._commentThread.canReply) {
|
||||
this.form.style.display = 'none';
|
||||
private updateAuthorInfo() {
|
||||
this.avatar.textContent = '';
|
||||
if (typeof this._commentThread.canReply !== 'boolean' && this._commentThread.canReply.iconPath) {
|
||||
this.avatar.style.display = 'block';
|
||||
const img = dom.append(this.avatar, dom.$('img.avatar')) as HTMLImageElement;
|
||||
img.src = FileAccess.uriToBrowserUri(URI.revive(this._commentThread.canReply.iconPath)).toString(true);
|
||||
} else {
|
||||
this.form.style.display = 'block';
|
||||
this.avatar.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
public updateCanReply() {
|
||||
this.updateAuthorInfo();
|
||||
if (!this._commentThread.canReply) {
|
||||
this._container.style.display = 'none';
|
||||
} else {
|
||||
this._container.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,12 +336,12 @@ export class CommentReply<T extends IRange | ICellRange> extends Disposable {
|
||||
}
|
||||
|
||||
private get isReplyExpanded(): boolean {
|
||||
return this.form.classList.contains('expand');
|
||||
return this._container.classList.contains('expand');
|
||||
}
|
||||
|
||||
private expandReplyArea() {
|
||||
if (!this.isReplyExpanded) {
|
||||
this.form.classList.add('expand');
|
||||
this._container.classList.add('expand');
|
||||
this.commentEditor.focus();
|
||||
this.commentEditor.layout();
|
||||
}
|
||||
@@ -345,7 +361,7 @@ export class CommentReply<T extends IRange | ICellRange> extends Disposable {
|
||||
}
|
||||
this.commentEditor.setValue('');
|
||||
this._pendingComment = { body: '', cursor: new Position(1, 1) };
|
||||
this.form.classList.remove('expand');
|
||||
this._container.classList.remove('expand');
|
||||
this._error.textContent = '';
|
||||
this._error.classList.add('hidden');
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
margin-top: 4px !important;
|
||||
}
|
||||
|
||||
.review-widget .body .review-comment .avatar-container img.avatar {
|
||||
.review-widget .body .avatar-container img.avatar {
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
display: inline-block;
|
||||
@@ -246,7 +246,7 @@
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.review-widget .body .comment-form {
|
||||
.review-widget .body .comment-form-container {
|
||||
margin: 8px 20px;
|
||||
}
|
||||
|
||||
@@ -296,7 +296,6 @@
|
||||
padding: 4px 10px;
|
||||
}
|
||||
|
||||
|
||||
.review-widget .body .comment-additional-actions .codicon-drop-down-button {
|
||||
align-items: center;
|
||||
}
|
||||
@@ -304,17 +303,27 @@
|
||||
.review-widget .body .monaco-editor {
|
||||
color: var(--vscode-editor-foreground);
|
||||
}
|
||||
.review-widget .body .comment-form.expand .review-thread-reply-button {
|
||||
|
||||
.review-widget .body .comment-form-container .comment-form {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.review-widget .body .comment-form-container .comment-form .avatar-container {
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.review-widget .body .comment-form-container.expand .review-thread-reply-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.review-widget .body .comment-form.expand .monaco-editor,
|
||||
.review-widget .body .comment-form.expand .form-actions {
|
||||
.review-widget .body .comment-form-container.expand .monaco-editor,
|
||||
.review-widget .body .comment-form-container.expand .form-actions {
|
||||
display: block;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.review-widget .body .comment-form .review-thread-reply-button {
|
||||
.review-widget .body .comment-form-container .review-thread-reply-button {
|
||||
text-align: left;
|
||||
display: block;
|
||||
width: 100%;
|
||||
@@ -333,18 +342,18 @@
|
||||
font-family: var(--monaco-monospace-font);
|
||||
}
|
||||
|
||||
.review-widget .body .comment-form .review-thread-reply-button:focus {
|
||||
.review-widget .body .comment-form-container .review-thread-reply-button:focus {
|
||||
outline-style: solid;
|
||||
outline-width: 1px;
|
||||
}
|
||||
|
||||
.review-widget .body .comment-form .monaco-editor,
|
||||
.review-widget .body .comment-form .monaco-editor .monaco-editor-background,
|
||||
.review-widget .body .comment-form-container .monaco-editor,
|
||||
.review-widget .body .comment-form-container .monaco-editor .monaco-editor-background,
|
||||
.review-widget .body .edit-container .monaco-editor .monaco-editor-background {
|
||||
background-color: var(--vscode-editorCommentsWidget-replyInputBackground);
|
||||
}
|
||||
|
||||
.review-widget .body .comment-form .monaco-editor,
|
||||
.review-widget .body .comment-form-container .monaco-editor,
|
||||
.review-widget .body .edit-container .monaco-editor {
|
||||
width: 100%;
|
||||
min-height: 90px;
|
||||
@@ -355,12 +364,12 @@
|
||||
padding: 6px 0 6px 12px;
|
||||
}
|
||||
|
||||
.review-widget .body .comment-form .monaco-editor,
|
||||
.review-widget .body .comment-form .form-actions {
|
||||
.review-widget .body .comment-form-container .monaco-editor,
|
||||
.review-widget .body .comment-form-container .form-actions {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.review-widget .body .comment-form .form-actions,
|
||||
.review-widget .body .comment-form-container .form-actions,
|
||||
.review-widget .body .edit-container .form-actions {
|
||||
overflow: auto;
|
||||
margin: 10px 0;
|
||||
@@ -375,7 +384,7 @@
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.review-widget .body .comment-form .form-actions .monaco-text-button,
|
||||
.review-widget .body .comment-form-container .form-actions .monaco-text-button,
|
||||
.review-widget .body .edit-container .monaco-text-button {
|
||||
width: auto;
|
||||
padding: 4px 10px;
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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' {
|
||||
|
||||
// @alexr00 https://github.com/microsoft/vscode/issues/246088
|
||||
|
||||
export interface CommentThread2 {
|
||||
canReply: boolean | CommentAuthorInformation;
|
||||
|
||||
readonly uri: Uri;
|
||||
range: Range | undefined;
|
||||
comments: readonly Comment[];
|
||||
collapsibleState: CommentThreadCollapsibleState;
|
||||
contextValue?: string;
|
||||
label?: string;
|
||||
state?: CommentThreadState | { resolved?: CommentThreadState; applicability?: CommentThreadApplicability };
|
||||
dispose(): void;
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ declare module 'vscode' {
|
||||
range: Range | undefined;
|
||||
comments: readonly Comment[];
|
||||
collapsibleState: CommentThreadCollapsibleState;
|
||||
canReply: boolean;
|
||||
canReply: boolean | CommentAuthorInformation;
|
||||
contextValue?: string;
|
||||
label?: string;
|
||||
dispose(): void;
|
||||
|
||||
Reference in New Issue
Block a user