Skip to content

Commit

Permalink
Merge pull request #78532 from rebornix/rebornix/newtree-in-comments
Browse files Browse the repository at this point in the history
Re #69955. Adopt new tree in comments panel.
  • Loading branch information
rebornix authored Aug 6, 2019
2 parents 46b9778 + c17bb3e commit c02c6a9
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 109 deletions.
3 changes: 2 additions & 1 deletion src/vs/workbench/api/browser/mainThreadComments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { Extensions as PanelExtensions, PanelDescriptor, PanelRegistry } from 'vs/workbench/browser/panel';
import { ICommentInfo, ICommentService } from 'vs/workbench/contrib/comments/browser/commentService';
import { CommentsPanel, COMMENTS_PANEL_ID, COMMENTS_PANEL_TITLE } from 'vs/workbench/contrib/comments/browser/commentsPanel';
import { CommentsPanel } from 'vs/workbench/contrib/comments/browser/commentsPanel';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { CommentProviderFeatures, ExtHostCommentsShape, ExtHostContext, IExtHostContext, MainContext, MainThreadCommentsShape } from '../common/extHost.protocol';
import { COMMENTS_PANEL_ID, COMMENTS_PANEL_TITLE } from 'vs/workbench/contrib/comments/browser/commentsTreeViewer';


export class MainThreadCommentThread implements modes.CommentThread {
Expand Down
41 changes: 13 additions & 28 deletions src/vs/workbench/contrib/comments/browser/commentsPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,31 @@
*--------------------------------------------------------------------------------------------*/

import 'vs/css!./media/panel';
import * as nls from 'vs/nls';
import * as dom from 'vs/base/browser/dom';
import { IAction } from 'vs/base/common/actions';
import { Event } from 'vs/base/common/event';
import { CollapseAllAction, DefaultAccessibilityProvider, DefaultController, DefaultDragAndDrop } from 'vs/base/parts/tree/browser/treeDefaults';
import { IAction, Action } from 'vs/base/common/actions';
import { CollapseAllAction } from 'vs/base/browser/ui/tree/treeDefaults';
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { TreeResourceNavigator, WorkbenchTree } from 'vs/platform/list/browser/listService';
import { TreeResourceNavigator2 } from 'vs/platform/list/browser/listService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { Panel } from 'vs/workbench/browser/panel';
import { CommentNode, CommentsModel, ResourceWithCommentThreads, ICommentThreadChangedEvent } from 'vs/workbench/contrib/comments/common/commentModel';
import { ReviewController } from 'vs/workbench/contrib/comments/browser/commentsEditorContribution';
import { CommentsDataFilter, CommentsDataSource, CommentsModelRenderer } from 'vs/workbench/contrib/comments/browser/commentsTreeViewer';
import { ICommentService, IWorkspaceCommentThreadsEvent } from 'vs/workbench/contrib/comments/browser/commentService';
import { IEditorService, ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { textLinkForeground, textLinkActiveForeground, focusBorder, textPreformatForeground } from 'vs/platform/theme/common/colorRegistry';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { ResourceLabels } from 'vs/workbench/browser/labels';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { CommentsList, COMMENTS_PANEL_ID, COMMENTS_PANEL_TITLE } from 'vs/workbench/contrib/comments/browser/commentsTreeViewer';

export const COMMENTS_PANEL_ID = 'workbench.panel.comments';
export const COMMENTS_PANEL_TITLE = 'Comments';

export class CommentsPanel extends Panel {
private treeLabels: ResourceLabels;
private tree: WorkbenchTree;
private tree: CommentsList;
private treeContainer: HTMLElement;
private messageBoxContainer: HTMLElement;
private messageBox: HTMLElement;
Expand All @@ -42,7 +39,6 @@ export class CommentsPanel extends Panel {
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ICommentService private readonly commentService: ICommentService,
@IEditorService private readonly editorService: IEditorService,
@IOpenerService private readonly openerService: IOpenerService,
@ITelemetryService telemetryService: ITelemetryService,
@IThemeService themeService: IThemeService,
@IStorageService storageService: IStorageService
Expand Down Expand Up @@ -113,7 +109,7 @@ export class CommentsPanel extends Panel {

public getActions(): IAction[] {
if (!this.collapseAllAction) {
this.collapseAllAction = this.instantiationService.createInstance(CollapseAllAction, this.tree, this.commentsModel.hasCommentThreads());
this.collapseAllAction = new Action('vs.tree.collapse', nls.localize('collapseAll', "Collapse All"), 'monaco-tree-action collapse-all', true, () => this.tree ? new CollapseAllAction<any, any>(this.tree, true).run() : Promise.resolve());
this._register(this.collapseAllAction);
}

Expand Down Expand Up @@ -141,22 +137,11 @@ export class CommentsPanel extends Panel {

private createTree(): void {
this.treeLabels = this._register(this.instantiationService.createInstance(ResourceLabels, this));
this.tree = this._register(this.instantiationService.createInstance(CommentsList, this.treeLabels, this.treeContainer));

this.tree = this._register(this.instantiationService.createInstance(WorkbenchTree, this.treeContainer, {
dataSource: new CommentsDataSource(),
renderer: new CommentsModelRenderer(this.treeLabels, this.openerService),
accessibilityProvider: new DefaultAccessibilityProvider,
controller: new DefaultController(),
dnd: new DefaultDragAndDrop(),
filter: new CommentsDataFilter()
}, {
twistiePixels: 20,
ariaLabel: COMMENTS_PANEL_TITLE
}));

const commentsNavigator = this._register(new TreeResourceNavigator(this.tree, { openOnFocus: true }));
this._register(Event.debounce(commentsNavigator.openResource, (last, event) => event, 100, true)(options => {
this.openFile(options.element, options.editorOptions.pinned, options.editorOptions.preserveFocus, options.sideBySide);
const commentsNavigator = this._register(new TreeResourceNavigator2(this.tree, { openOnFocus: true }));
this._register(commentsNavigator.onDidOpenResource(e => {
this.openFile(e.element, e.editorOptions.pinned, e.editorOptions.preserveFocus, e.sideBySide);
}));
}

Expand Down Expand Up @@ -213,7 +198,7 @@ export class CommentsPanel extends Panel {
this.collapseAllAction.enabled = this.commentsModel.hasCommentThreads();

dom.toggleClass(this.treeContainer, 'hidden', !this.commentsModel.hasCommentThreads());
this.tree.refresh().then(() => {
this.tree.updateChildren().then(() => {
this.renderMessage();
}, (e) => {
console.log(e);
Expand Down Expand Up @@ -243,4 +228,4 @@ CommandsRegistry.registerCommand({
panelService.openPanel(COMMENTS_PANEL_ID, true);
}
}
});
});
192 changes: 112 additions & 80 deletions src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,28 @@ import { renderMarkdown } from 'vs/base/browser/htmlContentRenderer';
import { onUnexpectedError } from 'vs/base/common/errors';
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { IDataSource, IFilter, IRenderer as ITreeRenderer, ITree } from 'vs/base/parts/tree/browser/tree';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IResourceLabel, ResourceLabels } from 'vs/workbench/browser/labels';
import { CommentNode, CommentsModel, ResourceWithCommentThreads } from 'vs/workbench/contrib/comments/common/commentModel';

export class CommentsDataSource implements IDataSource {
public getId(tree: ITree, element: any): string {
if (element instanceof CommentsModel) {
return 'root';
}
if (element instanceof ResourceWithCommentThreads) {
return `${element.owner}-${element.id}`;
}
if (element instanceof CommentNode) {
return `${element.owner}-${element.resource.toString()}-${element.threadId}-${element.comment.uniqueIdInThread}` + (element.isRoot ? '-root' : '');
}
return '';
}

public hasChildren(tree: ITree, element: any): boolean {
import { IAsyncDataSource, ITreeNode } from 'vs/base/browser/ui/tree/tree';
import { IListVirtualDelegate, IListRenderer } from 'vs/base/browser/ui/list/list';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { WorkbenchAsyncDataTree, IListService } from 'vs/platform/list/browser/listService';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';

export const COMMENTS_PANEL_ID = 'workbench.panel.comments';
export const COMMENTS_PANEL_TITLE = 'Comments';

export class CommentsAsyncDataSource implements IAsyncDataSource<any, any> {
hasChildren(element: any): boolean {
return element instanceof CommentsModel || element instanceof ResourceWithCommentThreads || (element instanceof CommentNode && !!element.replies.length);
}

public getChildren(tree: ITree, element: any): Promise<ResourceWithCommentThreads[] | CommentNode[]> {
getChildren(element: any): any[] | Promise<any[]> {
if (element instanceof CommentsModel) {
return Promise.resolve(element.resourceCommentThreads);
}
Expand All @@ -44,14 +42,6 @@ export class CommentsDataSource implements IDataSource {
}
return Promise.resolve([]);
}

public getParent(tree: ITree, element: any): Promise<void> {
return Promise.resolve(undefined);
}

public shouldAutoexpand(tree: ITree, element: any): boolean {
return true;
}
}

interface IResourceTemplateData {
Expand All @@ -65,69 +55,60 @@ interface ICommentThreadTemplateData {
disposables: IDisposable[];
}

export class CommentsModelRenderer implements ITreeRenderer {
export class CommentsModelVirualDelegate implements IListVirtualDelegate<any> {
private static RESOURCE_ID = 'resource-with-comments';
private static COMMENT_ID = 'comment-node';

constructor(
private labels: ResourceLabels,
@IOpenerService private readonly openerService: IOpenerService
) {
}

public getHeight(tree: ITree, element: any): number {
getHeight(element: any): number {
return 22;
}

public getTemplateId(tree: ITree, element: any): string {
public getTemplateId(element: any): string {
if (element instanceof ResourceWithCommentThreads) {
return CommentsModelRenderer.RESOURCE_ID;
return CommentsModelVirualDelegate.RESOURCE_ID;
}
if (element instanceof CommentNode) {
return CommentsModelRenderer.COMMENT_ID;
return CommentsModelVirualDelegate.COMMENT_ID;
}

return '';
}
}

public renderTemplate(ITree: ITree, templateId: string, container: HTMLElement): any {
switch (templateId) {
case CommentsModelRenderer.RESOURCE_ID:
return this.renderResourceTemplate(container);
case CommentsModelRenderer.COMMENT_ID:
return this.renderCommentTemplate(container);
}
}

public disposeTemplate(tree: ITree, templateId: string, templateData: any): void {
switch (templateId) {
case CommentsModelRenderer.RESOURCE_ID:
(<IResourceTemplateData>templateData).resourceLabel.dispose();
break;
case CommentsModelRenderer.COMMENT_ID:
(<ICommentThreadTemplateData>templateData).disposables.forEach(disposeable => disposeable.dispose());
break;
}
}
export class ResourceWithCommentsRenderer implements IListRenderer<ITreeNode<ResourceWithCommentThreads>, IResourceTemplateData> {
templateId: string = 'resource-with-comments';

public renderElement(tree: ITree, element: any, templateId: string, templateData: any): void {
switch (templateId) {
case CommentsModelRenderer.RESOURCE_ID:
return this.renderResourceElement(tree, element, templateData);
case CommentsModelRenderer.COMMENT_ID:
return this.renderCommentElement(tree, element, templateData);
}
constructor(
private labels: ResourceLabels
) {
}

private renderResourceTemplate(container: HTMLElement): IResourceTemplateData {
renderTemplate(container: HTMLElement) {
const data = <IResourceTemplateData>Object.create(null);
const labelContainer = dom.append(container, dom.$('.resource-container'));
data.resourceLabel = this.labels.create(labelContainer);

return data;
}

private renderCommentTemplate(container: HTMLElement): ICommentThreadTemplateData {
renderElement(node: ITreeNode<ResourceWithCommentThreads>, index: number, templateData: IResourceTemplateData, height: number | undefined): void {
templateData.resourceLabel.setFile(node.element.resource);
}

disposeTemplate(templateData: IResourceTemplateData): void {
templateData.resourceLabel.dispose();
}
}

export class CommentNodeRenderer implements IListRenderer<ITreeNode<CommentNode>, ICommentThreadTemplateData> {
templateId: string = 'comment-node';

constructor(
@IOpenerService private readonly openerService: IOpenerService
) { }

renderTemplate(container: HTMLElement) {
const data = <ICommentThreadTemplateData>Object.create(null);
const labelContainer = dom.append(container, dom.$('.comment-container'));
data.userName = dom.append(labelContainer, dom.$('.user'));
Expand All @@ -137,16 +118,12 @@ export class CommentsModelRenderer implements ITreeRenderer {
return data;
}

private renderResourceElement(tree: ITree, element: ResourceWithCommentThreads, templateData: IResourceTemplateData) {
templateData.resourceLabel.setFile(element.resource);
}

private renderCommentElement(tree: ITree, element: CommentNode, templateData: ICommentThreadTemplateData) {
templateData.userName.textContent = element.comment.userName;
renderElement(node: ITreeNode<CommentNode>, index: number, templateData: ICommentThreadTemplateData, height: number | undefined): void {
templateData.userName.textContent = node.element.comment.userName;
templateData.commentText.innerHTML = '';
const disposables = new DisposableStore();
templateData.disposables.push(disposables);
const renderedComment = renderMarkdown(element.comment.body, {
const renderedComment = renderMarkdown(node.element.comment.body, {
inline: true,
actionHandler: {
callback: (content) => {
Expand All @@ -171,16 +148,71 @@ export class CommentsModelRenderer implements ITreeRenderer {

templateData.commentText.appendChild(renderedComment);
}

disposeTemplate(templateData: ICommentThreadTemplateData): void {
templateData.disposables.forEach(disposeable => disposeable.dispose());
}
}

export class CommentsDataFilter implements IFilter {
public isVisible(tree: ITree, element: any): boolean {
if (element instanceof CommentsModel) {
return element.resourceCommentThreads.length > 0;
}
if (element instanceof ResourceWithCommentThreads) {
return element.commentThreads.length > 0;
}
return true;
export class CommentsList extends WorkbenchAsyncDataTree<any, any> {
constructor(
labels: ResourceLabels,
container: HTMLElement,
@IContextKeyService contextKeyService: IContextKeyService,
@IListService listService: IListService,
@IThemeService themeService: IThemeService,
@IInstantiationService instantiationService: IInstantiationService,
@IConfigurationService configurationService: IConfigurationService,
@IKeybindingService keybindingService: IKeybindingService,
@IAccessibilityService accessibilityService: IAccessibilityService
) {
const delegate = new CommentsModelVirualDelegate();
const dataSource = new CommentsAsyncDataSource();

const renderers = [
instantiationService.createInstance(ResourceWithCommentsRenderer, labels),
instantiationService.createInstance(CommentNodeRenderer)
];

super(
container,
delegate,
renderers,
dataSource,
{
ariaLabel: COMMENTS_PANEL_TITLE,
keyboardSupport: true,
identityProvider: {
getId: (element: any) => {
if (element instanceof CommentsModel) {
return 'root';
}
if (element instanceof ResourceWithCommentThreads) {
return `${element.owner}-${element.id}`;
}
if (element instanceof CommentNode) {
return `${element.owner}-${element.resource.toString()}-${element.threadId}-${element.comment.uniqueIdInThread}` + (element.isRoot ? '-root' : '');
}
return '';
}
},
expandOnlyOnTwistieClick: (element: any) => {
if (element instanceof CommentsModel || element instanceof ResourceWithCommentThreads) {
return false;
}

return true;
},
collapseByDefault: () => {
return false;
}
},
contextKeyService,
listService,
themeService,
configurationService,
keybindingService,
accessibilityService
);
}
}

0 comments on commit c02c6a9

Please sign in to comment.