mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Add new file UI (#14773)
Adds a notebook or markdown file to a book's top level or a section by right click on Book Tree View
This commit is contained in:
@@ -25,7 +25,6 @@ export class BookModel {
|
||||
private _contentFolderPath: string;
|
||||
private _configPath: string;
|
||||
private _bookVersion: BookVersion;
|
||||
private _rootPath: string;
|
||||
private _errorMessage: string;
|
||||
private _activePromise: Deferred<void> | undefined = undefined;
|
||||
private _queuedPromises: Deferred<void>[] = [];
|
||||
@@ -104,11 +103,9 @@ export class BookModel {
|
||||
}
|
||||
this._bookVersion = BookVersion.v1;
|
||||
this._contentFolderPath = path.posix.join(this.bookPath, content, '');
|
||||
this._rootPath = path.dirname(path.dirname(this._tableOfContentsPath));
|
||||
} else {
|
||||
this._contentFolderPath = this.bookPath;
|
||||
this._tableOfContentsPath = path.posix.join(this.bookPath, '_toc.yml');
|
||||
this._rootPath = path.dirname(this._tableOfContentsPath);
|
||||
this._bookVersion = BookVersion.v2;
|
||||
}
|
||||
}
|
||||
@@ -190,7 +187,7 @@ export class BookModel {
|
||||
version: this._bookVersion,
|
||||
title: config.title,
|
||||
contentPath: this._tableOfContentsPath,
|
||||
root: this._rootPath,
|
||||
root: this.bookPath,
|
||||
tableOfContents: { sections: this.parseJupyterSections(this._bookVersion, tableOfContents) },
|
||||
page: tableOfContents,
|
||||
type: BookTreeItemType.Book,
|
||||
@@ -334,7 +331,7 @@ export class BookModel {
|
||||
return this._errorMessage;
|
||||
}
|
||||
|
||||
public get version(): string {
|
||||
public get version(): BookVersion {
|
||||
return this._bookVersion;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,12 +11,15 @@ import { BookVersion, convertTo } from './bookVersionHandler';
|
||||
import * as vscode from 'vscode';
|
||||
import * as loc from '../common/localizedConstants';
|
||||
import { BookModel } from './bookModel';
|
||||
import { TocEntryPathHandler } from './tocEntryPathHandler';
|
||||
import { FileExtension } from '../common/utils';
|
||||
|
||||
export interface IBookTocManager {
|
||||
updateBook(element: BookTreeItem, book: BookTreeItem, targetSection?: JupyterBookSection): Promise<void>;
|
||||
removeNotebook(element: BookTreeItem): Promise<void>;
|
||||
createBook(bookContentPath: string, contentFolder: string): Promise<void>;
|
||||
recovery(): Promise<void>
|
||||
addNewFile(pathDetails: TocEntryPathHandler, bookItem: BookTreeItem): Promise<void>;
|
||||
recovery(): Promise<void>;
|
||||
}
|
||||
|
||||
export interface quickPickResults {
|
||||
@@ -24,7 +27,7 @@ export interface quickPickResults {
|
||||
book?: BookTreeItem
|
||||
}
|
||||
|
||||
const allowedFileExtensions: string[] = ['.md', '.ipynb'];
|
||||
const allowedFileExtensions: string[] = [FileExtension.Markdown, FileExtension.Notebook];
|
||||
|
||||
export function hasSections(node: JupyterBookSection): boolean {
|
||||
return node.sections !== undefined && node.sections.length > 0;
|
||||
@@ -38,12 +41,12 @@ export class BookTocManager implements IBookTocManager {
|
||||
public tocFiles: Map<string, string> = new Map<string, string>();
|
||||
private sourceBookContentPath: string;
|
||||
private targetBookContentPath: string;
|
||||
private _sourceBook: BookModel;
|
||||
|
||||
constructor(targetBook?: BookModel, sourceBook?: BookModel) {
|
||||
this._sourceBook = sourceBook;
|
||||
this.sourceBookContentPath = sourceBook?.bookItems[0].rootContentPath;
|
||||
this.targetBookContentPath = targetBook?.bookItems[0].rootContentPath;
|
||||
constructor(private _sourceBook?: BookModel, private _targetBook?: BookModel) {
|
||||
this._targetBook?.unwatchTOC();
|
||||
this._sourceBook?.unwatchTOC();
|
||||
this.sourceBookContentPath = this._sourceBook?.bookItems[0].rootContentPath;
|
||||
this.targetBookContentPath = this._targetBook?.bookItems[0].rootContentPath;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,19 +183,25 @@ export class BookTocManager implements IBookTocManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads and modifies the table of contents file of the target book.
|
||||
* @param version the version of the target book
|
||||
* Reads and modifies the table of contents file of book.
|
||||
* @param version the version of book.
|
||||
* @param tocPath Path to the table of contents
|
||||
* @param findSection The section that will be modified.
|
||||
* @param findSection The section that will be modified. If findSection is undefined then the added section is added at the end of the toc file.
|
||||
* @param addSection The section that'll be added to the target section. If it's undefined then the target section (findSection) is removed from the table of contents.
|
||||
*/
|
||||
async updateTOC(version: BookVersion, tocPath: string, findSection: JupyterBookSection, addSection?: JupyterBookSection): Promise<void> {
|
||||
async updateTOC(version: BookVersion, tocPath: string, findSection?: JupyterBookSection, addSection?: JupyterBookSection): Promise<void> {
|
||||
const tocFile = await fs.readFile(tocPath, 'utf8');
|
||||
this.tableofContents = yaml.safeLoad(tocFile);
|
||||
if (!this.tocFiles.has(tocPath)) {
|
||||
this.tocFiles.set(tocPath, tocFile);
|
||||
}
|
||||
const isModified = this.modifyToc(version, this.tableofContents, findSection, addSection);
|
||||
let isModified = false;
|
||||
if (findSection) {
|
||||
isModified = this.modifyToc(version, this.tableofContents, findSection, addSection);
|
||||
} else if (addSection) {
|
||||
this.tableofContents.push(addSection);
|
||||
isModified = true;
|
||||
}
|
||||
if (isModified) {
|
||||
await fs.writeFile(tocPath, yaml.safeDump(this.tableofContents, { lineWidth: Infinity, noRefs: true, skipInvalid: true }));
|
||||
} else {
|
||||
@@ -307,7 +316,7 @@ export class BookTocManager implements IBookTocManager {
|
||||
* @param section The section that's been moved.
|
||||
* @param book The target book.
|
||||
*/
|
||||
async addSection(section: BookTreeItem, book: BookTreeItem): Promise<void> {
|
||||
async moveSectionFiles(section: BookTreeItem, book: BookTreeItem): Promise<void> {
|
||||
const uri = path.posix.join(path.posix.sep, path.relative(section.rootContentPath, section.book.contentPath));
|
||||
let moveFile = path.join(path.parse(uri).dir, path.parse(uri).name);
|
||||
let fileName = undefined;
|
||||
@@ -347,20 +356,20 @@ export class BookTocManager implements IBookTocManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a notebook to a book top level or a book's section. If there's a target section we add the the targetSection directory if it has one and append it to the
|
||||
* notebook's path. The overwrite option is set to false to prevent any issues with duplicated file names.
|
||||
* @param element Notebook, Markdown File, or section that will be added to the book.
|
||||
* Moves a file to a book top level or a book's section. If there's a target section we add the the targetSection directory if it has one and append it to the
|
||||
* files's path. The overwrite option is set to false to prevent any issues with duplicated file names.
|
||||
* @param element Notebook, Markdown File, or book's notebook that will be added to the book.
|
||||
* @param targetBook Book that will be modified.
|
||||
*/
|
||||
async addNotebook(notebook: BookTreeItem, book: BookTreeItem): Promise<void> {
|
||||
async moveFile(file: BookTreeItem, book: BookTreeItem): Promise<void> {
|
||||
const rootPath = book.rootContentPath;
|
||||
const notebookPath = path.parse(notebook.book.contentPath);
|
||||
const filePath = path.parse(file.book.contentPath);
|
||||
let fileName = undefined;
|
||||
try {
|
||||
await fs.move(notebook.book.contentPath, path.join(rootPath, notebookPath.base), { overwrite: false });
|
||||
await fs.move(file.book.contentPath, path.join(rootPath, filePath.base), { overwrite: false });
|
||||
} catch (error) {
|
||||
if (error.code === 'EEXIST') {
|
||||
fileName = await this.renameFile(notebook.book.contentPath, path.join(rootPath, notebookPath.base));
|
||||
fileName = await this.renameFile(file.book.contentPath, path.join(rootPath, filePath.base));
|
||||
}
|
||||
else {
|
||||
throw (error);
|
||||
@@ -368,14 +377,14 @@ export class BookTocManager implements IBookTocManager {
|
||||
}
|
||||
|
||||
if (this._sourceBook) {
|
||||
const sectionTOC = this._sourceBook.bookItems[0].findChildSection(notebook.uri);
|
||||
const sectionTOC = this._sourceBook.bookItems[0].findChildSection(file.uri);
|
||||
if (sectionTOC) {
|
||||
this.newSection = sectionTOC;
|
||||
}
|
||||
}
|
||||
fileName = fileName === undefined ? notebookPath.name : path.parse(fileName).name;
|
||||
fileName = fileName === undefined ? filePath.name : path.parse(fileName).name;
|
||||
this.newSection.file = path.posix.join(path.posix.sep, fileName);
|
||||
this.newSection.title = notebook.book.title;
|
||||
this.newSection.title = file.book.title;
|
||||
if (book.version === BookVersion.v1) {
|
||||
// here we only convert if is v1 because we are already using the v2 notation for every book that we read.
|
||||
this.newSection = convertTo(book.version, this.newSection);
|
||||
@@ -388,50 +397,76 @@ export class BookTocManager implements IBookTocManager {
|
||||
* @param targetBook Book that will be modified.
|
||||
* @param targetSection Book section that'll be modified.
|
||||
*/
|
||||
public async updateBook(element: BookTreeItem, targetBook: BookTreeItem, targetSection?: JupyterBookSection): Promise<void> {
|
||||
if (element.contextValue === 'section') {
|
||||
// modify the sourceBook toc and remove the section
|
||||
const findSection: JupyterBookSection = { file: element.book.page.file, title: element.book.page.title };
|
||||
await this.addSection(element, targetBook);
|
||||
await this.updateTOC(element.book.version, element.tableOfContentsPath, findSection, undefined);
|
||||
if (targetSection) {
|
||||
// adding new section to the target book toc file
|
||||
await this.updateTOC(targetBook.book.version, targetBook.tableOfContentsPath, targetSection, this.newSection);
|
||||
public async updateBook(element: BookTreeItem, targetItem: BookTreeItem, targetSection?: JupyterBookSection): Promise<void> {
|
||||
try {
|
||||
if (element.contextValue === 'section') {
|
||||
// modify the sourceBook toc and remove the section
|
||||
const findSection: JupyterBookSection = { file: element.book.page.file, title: element.book.page.title };
|
||||
await this.moveSectionFiles(element, targetItem);
|
||||
// remove section from book
|
||||
await this.updateTOC(element.book.version, element.tableOfContentsPath, findSection, undefined);
|
||||
// add section to book
|
||||
await this.updateTOC(targetItem.book.version, targetItem.tableOfContentsPath, targetSection, this.newSection);
|
||||
}
|
||||
else {
|
||||
//since there's not a target section, we just append the section at the end of the file
|
||||
if (this.targetBookContentPath !== this.sourceBookContentPath) {
|
||||
this.tableofContents = targetBook.sections.map(section => convertTo(targetBook.version, section));
|
||||
// the notebook is part of a book so we need to modify its toc as well
|
||||
const findSection = { file: element.book.page.file, title: element.book.page.title };
|
||||
await this.moveFile(element, targetItem);
|
||||
if (element.contextValue === 'savedBookNotebook' || element.contextValue === 'Markdown') {
|
||||
// remove notebook entry from book toc
|
||||
await this.updateTOC(element.book.version, element.tableOfContentsPath, findSection, undefined);
|
||||
} else {
|
||||
// close the standalone notebook, so it doesn't throw an error when we move the notebook to new location.
|
||||
await vscode.commands.executeCommand('notebook.command.closeNotebook', element);
|
||||
}
|
||||
await this.updateTOC(targetItem.book.version, targetItem.tableOfContentsPath, targetSection, this.newSection);
|
||||
}
|
||||
} catch (e) {
|
||||
await this.recovery();
|
||||
vscode.window.showErrorMessage(loc.editBookError(element.book.contentPath, e instanceof Error ? e.message : e));
|
||||
} finally {
|
||||
try {
|
||||
await this._targetBook.reinitializeContents();
|
||||
} finally {
|
||||
if (this._sourceBook && this._sourceBook.bookPath !== this._targetBook.bookPath) {
|
||||
// refresh source book model to pick up latest changes
|
||||
await this._sourceBook.reinitializeContents();
|
||||
}
|
||||
this.tableofContents.push(this.newSection);
|
||||
await fs.writeFile(targetBook.tableOfContentsPath, yaml.safeDump(this.tableofContents, { lineWidth: Infinity, noRefs: true, skipInvalid: true }));
|
||||
}
|
||||
}
|
||||
else if (element.contextValue === 'savedNotebook' || element.contextValue === 'savedBookNotebook') {
|
||||
// the notebook is part of a book so we need to modify its toc as well
|
||||
const findSection = { file: element.book.page.file, title: element.book.page.title };
|
||||
await this.addNotebook(element, targetBook);
|
||||
if (element.tableOfContentsPath) {
|
||||
await this.updateTOC(element.book.version, element.tableOfContentsPath, findSection, undefined);
|
||||
} else {
|
||||
// close the standalone notebook, so it doesn't throw an error when we move the notebook to new location.
|
||||
await vscode.commands.executeCommand('notebook.command.closeNotebook', element);
|
||||
}
|
||||
if (!targetSection) {
|
||||
if (this.targetBookContentPath !== this.sourceBookContentPath) {
|
||||
this.tableofContents = targetBook.sections.map(section => convertTo(targetBook.version, section));
|
||||
}
|
||||
this.tableofContents.push(this.newSection);
|
||||
await fs.writeFile(targetBook.tableOfContentsPath, yaml.safeDump(this.tableofContents, { lineWidth: Infinity, noRefs: true, skipInvalid: true }));
|
||||
} else {
|
||||
await this.updateTOC(targetBook.book.version, targetBook.tableOfContentsPath, targetSection, this.newSection);
|
||||
}
|
||||
}
|
||||
|
||||
public async addNewFile(pathDetails: TocEntryPathHandler, bookItem: BookTreeItem): Promise<void> {
|
||||
let findSection: JupyterBookSection | undefined = undefined;
|
||||
await fs.writeFile(pathDetails.filePath, '');
|
||||
if (bookItem.contextValue === 'section') {
|
||||
findSection = { file: bookItem.book.page.file, title: bookItem.book.page.title };
|
||||
}
|
||||
let fileEntryInToc: JupyterBookSection = {
|
||||
title: pathDetails.titleInTocEntry,
|
||||
file: pathDetails.fileInTocEntry
|
||||
};
|
||||
if (bookItem.book.version === BookVersion.v1) {
|
||||
fileEntryInToc = convertTo(BookVersion.v1, fileEntryInToc);
|
||||
}
|
||||
// book is already opened in notebooks view, so modifying the toc will add the new file automatically
|
||||
await this.updateTOC(bookItem.book.version, bookItem.tableOfContentsPath, findSection, fileEntryInToc);
|
||||
await this._sourceBook.reinitializeContents();
|
||||
await this.openResource(pathDetails);
|
||||
}
|
||||
|
||||
public async openResource(pathDetails: TocEntryPathHandler): Promise<void> {
|
||||
if (pathDetails.fileExtension === FileExtension.Notebook) {
|
||||
await vscode.commands.executeCommand('bookTreeView.openNotebook', pathDetails.filePath);
|
||||
} else {
|
||||
await vscode.commands.executeCommand('bookTreeView.openMarkdown', pathDetails.filePath);
|
||||
}
|
||||
}
|
||||
|
||||
public async removeNotebook(element: BookTreeItem): Promise<void> {
|
||||
const findSection = { file: element.book.page.file, title: element.book.page.title };
|
||||
await this.updateTOC(element.book.version, element.tableOfContentsPath, findSection, undefined);
|
||||
await this._sourceBook.reinitializeContents();
|
||||
}
|
||||
|
||||
public get modifiedDir(): Set<string> {
|
||||
|
||||
@@ -41,7 +41,7 @@ export class BookTreeItem extends vscode.TreeItem {
|
||||
private _uri: string | undefined;
|
||||
private _previousUri: string;
|
||||
private _nextUri: string;
|
||||
public readonly version: string;
|
||||
public readonly version: BookVersion;
|
||||
public command: vscode.Command;
|
||||
public resourceUri: vscode.Uri;
|
||||
private _rootContentPath: string;
|
||||
@@ -71,7 +71,7 @@ export class BookTreeItem extends vscode.TreeItem {
|
||||
this.contextValue = BookTreeItemType.ExternalLink;
|
||||
|
||||
} else {
|
||||
this.contextValue = book.type === BookTreeItemType.Notebook ? (isBookItemPinned(book.contentPath) ? BookTreeItemType.pinnedNotebook : getNotebookType(book)) : BookTreeItemType.section;
|
||||
this.contextValue = book.type === BookTreeItemType.Notebook ? (isBookItemPinned(book.contentPath) ? BookTreeItemType.pinnedNotebook : getNotebookType(book)) : BookTreeItemType.Markdown;
|
||||
}
|
||||
this.setPageVariables();
|
||||
this.setCommand();
|
||||
@@ -84,7 +84,7 @@ export class BookTreeItem extends vscode.TreeItem {
|
||||
}
|
||||
else {
|
||||
// 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 || (book.tableOfContents.sections && book.type === BookTreeItemType.Notebook)) {
|
||||
if (this.book.type === BookTreeItemType.Book || this.contextValue === BookTreeItemType.section || this.contextValue === BookTreeItemType.savedBookNotebook || book.tableOfContents.sections && book.type === BookTreeItemType.Markdown) {
|
||||
this._tableOfContentsPath = getTocPath(this.book.version, this.book.root);
|
||||
}
|
||||
this._rootContentPath = getContentPath(this.book.version, this.book.root, '');
|
||||
|
||||
@@ -16,10 +16,11 @@ import { Deferred } from '../common/promise';
|
||||
import { IBookTrustManager, BookTrustManager } from './bookTrustManager';
|
||||
import * as loc from '../common/localizedConstants';
|
||||
import * as glob from 'fast-glob';
|
||||
import { getPinnedNotebooks, confirmReplace, getNotebookType } from '../common/utils';
|
||||
import { getPinnedNotebooks, confirmMessageDialog, getNotebookType, FileExtension } from '../common/utils';
|
||||
import { IBookPinManager, BookPinManager } from './bookPinManager';
|
||||
import { BookTocManager, IBookTocManager, quickPickResults } from './bookTocManager';
|
||||
import { CreateBookDialog } from '../dialog/createBookDialog';
|
||||
import { AddFileDialog } from '../dialog/addFileDialog';
|
||||
import { getContentPath } from './bookVersionHandler';
|
||||
import { TelemetryReporter, BookTelemetryView, NbTelemetryActions } from '../telemetry';
|
||||
|
||||
@@ -197,37 +198,10 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
|
||||
const pickedSection = selectionResults.quickPickSection;
|
||||
const updateBook = selectionResults.book;
|
||||
const targetSection = pickedSection.detail !== undefined ? updateBook.findChildSection(pickedSection.detail) : undefined;
|
||||
if (movingElement.tableOfContents.sections) {
|
||||
if (movingElement.contextValue === 'savedNotebook' || movingElement.contextValue === 'savedBookNotebook') {
|
||||
let sourceBook = this.books.find(book => book.getNotebook(path.normalize(movingElement.book.contentPath)));
|
||||
movingElement.tableOfContents.sections = sourceBook?.bookItems[0].sections;
|
||||
}
|
||||
}
|
||||
const sourceBook = this.books.find(book => book.bookPath === movingElement.book.root);
|
||||
const targetBook = this.books.find(book => book.bookPath === updateBook.book.root);
|
||||
this.bookTocManager = new BookTocManager(targetBook, sourceBook);
|
||||
// remove watch on toc file from source book.
|
||||
if (sourceBook) {
|
||||
sourceBook.unwatchTOC();
|
||||
}
|
||||
try {
|
||||
await this.bookTocManager.updateBook(movingElement, updateBook, targetSection);
|
||||
} catch (e) {
|
||||
await this.bookTocManager.recovery();
|
||||
vscode.window.showErrorMessage(loc.editBookError(updateBook.book.contentPath, e instanceof Error ? e.message : e));
|
||||
} finally {
|
||||
try {
|
||||
await targetBook.reinitializeContents();
|
||||
} finally {
|
||||
if (sourceBook && sourceBook.bookPath !== targetBook.bookPath) {
|
||||
// refresh source book model to pick up latest changes
|
||||
await sourceBook.reinitializeContents();
|
||||
}
|
||||
if (sourceBook) {
|
||||
sourceBook.watchTOC();
|
||||
}
|
||||
}
|
||||
}
|
||||
this.bookTocManager = new BookTocManager(sourceBook, targetBook);
|
||||
await this.bookTocManager.updateBook(movingElement, updateBook, targetSection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,7 +250,23 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
|
||||
}
|
||||
}
|
||||
|
||||
async createMarkdownFile(bookItem: BookTreeItem): Promise<void> {
|
||||
const book = this.books.find(b => b.bookPath === bookItem.root);
|
||||
this.bookTocManager = new BookTocManager(book);
|
||||
const dialog = new AddFileDialog(this.bookTocManager, bookItem, FileExtension.Markdown);
|
||||
await dialog.createDialog();
|
||||
}
|
||||
|
||||
async createNotebook(bookItem: BookTreeItem): Promise<void> {
|
||||
const book = this.books.find(b => b.bookPath === bookItem.root);
|
||||
this.bookTocManager = new BookTocManager(book);
|
||||
const dialog = new AddFileDialog(this.bookTocManager, bookItem, FileExtension.Notebook);
|
||||
await dialog.createDialog();
|
||||
}
|
||||
|
||||
async removeNotebook(bookItem: BookTreeItem): Promise<void> {
|
||||
const book = this.books.find(b => b.bookPath === bookItem.root);
|
||||
this.bookTocManager = new BookTocManager(book);
|
||||
return this.bookTocManager.removeNotebook(bookItem);
|
||||
}
|
||||
|
||||
@@ -479,7 +469,7 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
|
||||
let destinationUri: vscode.Uri = vscode.Uri.file(path.join(pickedFolder.fsPath, path.basename(this.currentBook.bookPath)));
|
||||
if (destinationUri) {
|
||||
if (await fs.pathExists(destinationUri.fsPath)) {
|
||||
let doReplace = await confirmReplace(this.prompter);
|
||||
let doReplace = await confirmMessageDialog(this.prompter, loc.confirmReplace);
|
||||
if (!doReplace) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
20
extensions/notebook/src/book/tocEntryPathHandler.ts
Normal file
20
extensions/notebook/src/book/tocEntryPathHandler.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from 'path';
|
||||
import { FileExtension } from '../common/utils';
|
||||
|
||||
export class TocEntryPathHandler {
|
||||
public readonly fileInTocEntry: string;
|
||||
public readonly titleInTocEntry: string;
|
||||
public readonly fileExtension: FileExtension;
|
||||
constructor(public readonly filePath: string, public readonly bookRoot: string, title?: string) {
|
||||
const relativePath = path.relative(bookRoot, filePath);
|
||||
const pathDetails = path.parse(relativePath);
|
||||
this.fileInTocEntry = relativePath.replace(pathDetails.ext, '');
|
||||
this.titleInTocEntry = title ?? pathDetails.name;
|
||||
this.fileExtension = pathDetails.ext === FileExtension.Notebook ? FileExtension.Notebook : FileExtension.Markdown;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user