Remove circular reference from book tree item (#16579)

* Enable drag and drop and multiple selection in Book Tree View

* replace children for hasChildren to remove circular reference
This commit is contained in:
Barbara Valdez
2021-08-18 10:37:54 -07:00
committed by GitHub
parent 7b3aae7c88
commit 8aa0dffccf
3 changed files with 39 additions and 56 deletions

View File

@@ -186,12 +186,13 @@ export class BookModel {
const config = yaml.safeLoad(fileContents.toString()); const config = yaml.safeLoad(fileContents.toString());
fileContents = await fsPromises.readFile(this._tableOfContentsPath, 'utf-8'); fileContents = await fsPromises.readFile(this._tableOfContentsPath, 'utf-8');
let tableOfContents: any = yaml.safeLoad(fileContents.toString()); let tableOfContents: any = yaml.safeLoad(fileContents.toString());
const parsedTOC: IJupyterBookToc = { sections: this.parseJupyterSections(this._bookVersion, tableOfContents) };
let book: BookTreeItem = new BookTreeItem({ let book: BookTreeItem = new BookTreeItem({
version: this._bookVersion, version: this._bookVersion,
title: config.title, title: config.title,
contentPath: this._tableOfContentsPath, contentPath: this._tableOfContentsPath,
root: this.bookPath, root: this.bookPath,
tableOfContents: { sections: this.parseJupyterSections(this._bookVersion, tableOfContents) }, tableOfContents: parsedTOC,
page: tableOfContents, page: tableOfContents,
type: BookTreeItemType.Book, type: BookTreeItemType.Book,
treeItemCollapsibleState: collapsibleState, treeItemCollapsibleState: collapsibleState,
@@ -226,7 +227,6 @@ export class BookModel {
} }
public async getSections(element: BookTreeItem): Promise<BookTreeItem[]> { public async getSections(element: BookTreeItem): Promise<BookTreeItem[]> {
let tableOfContents: IJupyterBookToc = element.tableOfContents;
let sections: JupyterBookSection[] = element.sections; let sections: JupyterBookSection[] = element.sections;
let root: string = element.root; let root: string = element.root;
let book: BookTreeItemFormat = element.book; let book: BookTreeItemFormat = element.book;
@@ -237,7 +237,7 @@ export class BookModel {
title: sections[i].title, title: sections[i].title,
contentPath: undefined, contentPath: undefined,
root: root, root: root,
tableOfContents: tableOfContents, tableOfContents: element.tableOfContents,
page: sections[i], page: sections[i],
type: BookTreeItemType.ExternalLink, type: BookTreeItemType.ExternalLink,
treeItemCollapsibleState: vscode.TreeItemCollapsibleState.Collapsed, treeItemCollapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
@@ -263,7 +263,7 @@ export class BookModel {
title: sections[i].title ? sections[i].title : sections[i].file, title: sections[i].title ? sections[i].title : sections[i].file,
contentPath: pathToNotebook, contentPath: pathToNotebook,
root: root, root: root,
tableOfContents: tableOfContents, tableOfContents: element.tableOfContents,
page: sections[i], page: sections[i],
type: BookTreeItemType.Notebook, type: BookTreeItemType.Notebook,
treeItemCollapsibleState: vscode.TreeItemCollapsibleState.Collapsed, treeItemCollapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
@@ -295,7 +295,7 @@ export class BookModel {
title: sections[i].title ? sections[i].title : sections[i].file, title: sections[i].title ? sections[i].title : sections[i].file,
contentPath: pathToMarkdown, contentPath: pathToMarkdown,
root: root, root: root,
tableOfContents: tableOfContents, tableOfContents: element.tableOfContents,
page: sections[i], page: sections[i],
type: BookTreeItemType.Markdown, type: BookTreeItemType.Markdown,
treeItemCollapsibleState: vscode.TreeItemCollapsibleState.Collapsed, treeItemCollapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
@@ -326,7 +326,7 @@ export class BookModel {
} }
} }
} }
element.children = treeItems; element.hasChildren = treeItems.length > 0;
this.bookItems = treeItems; this.bookItems = treeItems;
return treeItems; return treeItems;
} }

View File

@@ -35,24 +35,24 @@ export interface BookTreeItemFormat {
isUntitled: boolean; isUntitled: boolean;
version?: BookVersion; version?: BookVersion;
parent?: BookTreeItem; parent?: BookTreeItem;
children?: BookTreeItem[]; hasChildren?: boolean;
} }
export class BookTreeItem extends vscode.TreeItem { export class BookTreeItem extends vscode.TreeItem {
private _sections: JupyterBookSection[] | undefined; public sections: JupyterBookSection[] | undefined;
private _uri: string | undefined; public uri: string | undefined;
private _previousUri: string; private _previousUri: string;
private _nextUri: string; private _nextUri: string;
public override command: vscode.Command; public override command: vscode.Command;
public override resourceUri: vscode.Uri; public override resourceUri: vscode.Uri;
private _rootContentPath: string; public rootContentPath: string;
private _tableOfContentsPath: string; public tableOfContentsPath: string;
constructor(public book: BookTreeItemFormat, icons: any) { constructor(public book: BookTreeItemFormat, icons: any) {
super(book.title, book.treeItemCollapsibleState); super(book.title, book.treeItemCollapsibleState);
if (book.type === BookTreeItemType.Book) { if (book.type === BookTreeItemType.Book) {
this.collapsibleState = book.treeItemCollapsibleState; this.collapsibleState = book.treeItemCollapsibleState;
this._sections = book.page; this.sections = book.page;
if (book.isUntitled) { if (book.isUntitled) {
this.contextValue = BookTreeItemType.providedBook; this.contextValue = BookTreeItemType.providedBook;
} else { } else {
@@ -77,18 +77,18 @@ export class BookTreeItem extends vscode.TreeItem {
this.setCommand(); this.setCommand();
} }
this.iconPath = icons; this.iconPath = icons;
this._tableOfContentsPath = undefined; this.tableOfContentsPath = undefined;
if (this.book.type === BookTreeItemType.ExternalLink) { if (this.book.type === BookTreeItemType.ExternalLink) {
this.tooltip = `${this._uri}`; this.tooltip = `${this.uri}`;
} }
else { else {
// if it's a section, book or a notebook's book then we set the table of contents path. // if it's a section, book or a notebook's book then we set the table of contents path.
if (this.book.type === BookTreeItemType.Book || this.contextValue === BookTreeItemType.section || this.contextValue === BookTreeItemType.savedBookNotebook || book.tableOfContents.sections && book.type === BookTreeItemType.Markdown) { if (this.book.type === BookTreeItemType.Book || this.contextValue === BookTreeItemType.section || this.contextValue === BookTreeItemType.savedBookNotebook || this.book.tableOfContents.sections && book.type === BookTreeItemType.Markdown) {
this._tableOfContentsPath = getTocPath(this.book.version, this.book.root); this.tableOfContentsPath = getTocPath(this.book.version, this.book.root);
} }
this._rootContentPath = getContentPath(this.book.version, this.book.root, ''); this.rootContentPath = getContentPath(this.book.version, this.book.root, '');
this.tooltip = this.book.type === BookTreeItemType.Book ? this._rootContentPath : this.book.contentPath; this.tooltip = this.book.type === BookTreeItemType.Book ? this.rootContentPath : this.book.contentPath;
this.resourceUri = this.book.type === BookTreeItemType.Book ? vscode.Uri.file(this.book.root) : vscode.Uri.file(this.book.contentPath); this.resourceUri = this.book.type === BookTreeItemType.Book ? vscode.Uri.file(this.book.root) : vscode.Uri.file(this.book.contentPath);
} }
} }
@@ -99,8 +99,8 @@ export class BookTreeItem extends vscode.TreeItem {
this.book.page.sections || this.book.page.subsections ? this.book.page.sections || this.book.page.subsections ?
vscode.TreeItemCollapsibleState.Collapsed : vscode.TreeItemCollapsibleState.Collapsed :
vscode.TreeItemCollapsibleState.None; vscode.TreeItemCollapsibleState.None;
this._sections = this.book.page.sections || this.book.page.subsections; this.sections = this.book.page.sections || this.book.page.subsections;
this._uri = this.book.page.file ? this.book.page.file?.replace(/\\/g, '/') : this.book.page.url?.replace(/\\/g, '/'); this.uri = this.book.page.file ? this.book.page.file?.replace(/\\/g, '/') : this.book.page.url?.replace(/\\/g, '/');
if (this.book.tableOfContents.sections) { if (this.book.tableOfContents.sections) {
let index = (this.book.tableOfContents.sections.indexOf(this.book.page)); let index = (this.book.tableOfContents.sections.indexOf(this.book.page));
@@ -116,7 +116,7 @@ export class BookTreeItem extends vscode.TreeItem {
} else if (this.book.type === BookTreeItemType.Markdown) { } else if (this.book.type === BookTreeItemType.Markdown) {
this.command = { command: 'bookTreeView.openMarkdown', title: loc.openMarkdownCommand, arguments: [this.book.contentPath], }; this.command = { command: 'bookTreeView.openMarkdown', title: loc.openMarkdownCommand, arguments: [this.book.contentPath], };
} else if (this.book.type === BookTreeItemType.ExternalLink) { } else if (this.book.type === BookTreeItemType.ExternalLink) {
this.command = { command: 'bookTreeView.openExternalLink', title: loc.openExternalLinkCommand, arguments: [this._uri], }; this.command = { command: 'bookTreeView.openExternalLink', title: loc.openExternalLinkCommand, arguments: [this.uri], };
} }
} }
@@ -160,30 +160,14 @@ export class BookTreeItem extends vscode.TreeItem {
return this.book.title; return this.book.title;
} }
public get uri(): string | undefined {
return this._uri;
}
public get root(): string { public get root(): string {
return this.book.root; return this.book.root;
} }
public get rootContentPath(): string {
return this._rootContentPath;
}
public get tableOfContentsPath(): string {
return this._tableOfContentsPath;
}
public get tableOfContents(): IJupyterBookToc { public get tableOfContents(): IJupyterBookToc {
return this.book.tableOfContents; return this.book.tableOfContents;
} }
public get sections(): JupyterBookSection[] {
return this._sections;
}
public get previousUri(): string { public get previousUri(): string {
return this._previousUri; return this._previousUri;
} }
@@ -194,24 +178,13 @@ export class BookTreeItem extends vscode.TreeItem {
public override readonly tooltip: string; public override readonly tooltip: string;
public set uri(uri: string) {
this._uri = uri; public get hasChildren(): boolean | undefined {
return this.book.hasChildren;
} }
public set sections(sections: JupyterBookSection[]) { public set hasChildren(hasChildren: boolean | undefined) {
this._sections = sections; this.book.hasChildren = hasChildren;
}
public set tableOfContentsPath(tocPath: string) {
this._tableOfContentsPath = tocPath;
}
public get children(): BookTreeItem[] | undefined {
return this.book.children;
}
public set children(children: BookTreeItem[] | undefined) {
this.book.children = children;
} }
public get parent(): BookTreeItem { public get parent(): BookTreeItem {

View File

@@ -29,7 +29,7 @@ interface BookSearchResults {
bookPaths: string[]; bookPaths: string[];
} }
export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeItem>, azdata.nb.NavigationProvider { export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeItem>, azdata.nb.NavigationProvider, vscode.DragAndDropController<BookTreeItem> {
private _onDidChangeTreeData: vscode.EventEmitter<BookTreeItem | undefined> = new vscode.EventEmitter<BookTreeItem | undefined>(); private _onDidChangeTreeData: vscode.EventEmitter<BookTreeItem | undefined> = new vscode.EventEmitter<BookTreeItem | undefined>();
readonly onDidChangeTreeData: vscode.Event<BookTreeItem | undefined> = this._onDidChangeTreeData.event; readonly onDidChangeTreeData: vscode.Event<BookTreeItem | undefined> = this._onDidChangeTreeData.event;
private _extensionContext: vscode.ExtensionContext; private _extensionContext: vscode.ExtensionContext;
@@ -44,6 +44,7 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
public viewId: string; public viewId: string;
public books: BookModel[] = []; public books: BookModel[] = [];
public currentBook: BookModel; public currentBook: BookModel;
supportedTypes = ['text/treeitems'];
constructor(workspaceFolders: vscode.WorkspaceFolder[], extensionContext: vscode.ExtensionContext, openAsUntitled: boolean, view: string, public providerId: string) { constructor(workspaceFolders: vscode.WorkspaceFolder[], extensionContext: vscode.ExtensionContext, openAsUntitled: boolean, view: string, public providerId: string) {
this._openAsUntitled = openAsUntitled; this._openAsUntitled = openAsUntitled;
@@ -54,7 +55,7 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
this.prompter = new CodeAdapter(); this.prompter = new CodeAdapter();
this._bookTrustManager = new BookTrustManager(this.books); this._bookTrustManager = new BookTrustManager(this.books);
this.bookTocManager = new BookTocManager(); this.bookTocManager = new BookTocManager();
this._bookViewer = vscode.window.createTreeView(this.viewId, { showCollapseAll: true, treeDataProvider: this }); this._bookViewer = vscode.window.createTreeView(this.viewId, { showCollapseAll: true, canSelectMany: true, treeDataProvider: this, dragAndDropController: this });
this._bookViewer.onDidChangeVisibility(async e => { this._bookViewer.onDidChangeVisibility(async e => {
await this.initialized; await this.initialized;
// Whenever the viewer changes visibility then try and reveal the currently active document // Whenever the viewer changes visibility then try and reveal the currently active document
@@ -470,7 +471,7 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
// increment to reset the depth since parent is in the same level // increment to reset the depth since parent is in the same level
depthOfNotebookInBook++; depthOfNotebookInBook++;
} }
if (!bookItemToExpand.children) { if (!bookItemToExpand.hasChildren) {
// We haven't loaded children of this node yet so do that now so we can // We haven't loaded children of this node yet so do that now so we can
// continue expanding and search its children // continue expanding and search its children
await this.getChildren(bookItemToExpand); await this.getChildren(bookItemToExpand);
@@ -715,4 +716,13 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
} }
return Promise.resolve(result); return Promise.resolve(result);
} }
async onDrop(sources: vscode.TreeDataTransfer, target: BookTreeItem): Promise<void> {
let treeItems = JSON.parse(await sources.items.get('text/treeitems')!.asString());
if (treeItems) {
}
}
dispose(): void { }
} }