diff --git a/extensions/sql-database-projects/src/controllers/projectController.ts b/extensions/sql-database-projects/src/controllers/projectController.ts index 85ab0ee224..d1ca86706a 100644 --- a/extensions/sql-database-projects/src/controllers/projectController.ts +++ b/extensions/sql-database-projects/src/controllers/projectController.ts @@ -374,7 +374,7 @@ export class ProjectsController { await project.exclude(fileEntry); } else { TelemetryReporter.sendErrorEvent(TelemetryViews.ProjectTree, TelemetryActions.excludeFromProject); - vscode.window.showErrorMessage(constants.unableToPerformAction(constants.excludeAction, node.uri.path)); + vscode.window.showErrorMessage(constants.unableToPerformAction(constants.excludeAction, node.projectUri.path)); } this.refreshProjectsTree(context); @@ -428,7 +428,7 @@ export class ProjectsController { .withAdditionalProperties({ objectType: node.constructor.name }) .send(); - vscode.window.showErrorMessage(constants.unableToPerformAction(constants.deleteAction, node.uri.path)); + vscode.window.showErrorMessage(constants.unableToPerformAction(constants.deleteAction, node.projectUri.path)); } } @@ -441,7 +441,7 @@ export class ProjectsController { const allFileEntries = project.files.concat(project.preDeployScripts).concat(project.postDeployScripts).concat(project.noneDeployScripts); return allFileEntries.find(x => utils.getPlatformSafeFileEntryPath(x.relativePath) === utils.getPlatformSafeFileEntryPath(utils.trimUri(root.fileSystemUri, fileOrFolder.fileSystemUri))); } - return project.files.find(x => utils.getPlatformSafeFileEntryPath(x.relativePath) === utils.getPlatformSafeFileEntryPath(utils.trimUri(context.root.uri, context.uri))); + return project.files.find(x => utils.getPlatformSafeFileEntryPath(x.relativePath) === utils.getPlatformSafeFileEntryPath(utils.trimUri(context.root.projectUri, context.projectUri))); } private getDatabaseReference(project: Project, context: BaseProjectTreeItem): IDatabaseReferenceProjectEntry | undefined { @@ -696,7 +696,7 @@ export class ProjectsController { if (context.root instanceof ProjectRootTreeItem) { return (context.root).project; } else { - throw new Error(constants.unexpectedProjectContext(context.uri.path)); + throw new Error(constants.unexpectedProjectContext(context.projectUri.path)); } } @@ -728,7 +728,7 @@ export class ProjectsController { } private getRelativePath(treeNode: BaseProjectTreeItem): string { - return treeNode instanceof FolderNode ? utils.trimUri(treeNode.root.uri, treeNode.uri) : ''; + return treeNode instanceof FolderNode ? utils.trimUri(treeNode.root.projectUri, treeNode.projectUri) : ''; } /** diff --git a/extensions/sql-database-projects/src/models/tree/baseTreeItem.ts b/extensions/sql-database-projects/src/models/tree/baseTreeItem.ts index 23567aa2f4..1428695801 100644 --- a/extensions/sql-database-projects/src/models/tree/baseTreeItem.ts +++ b/extensions/sql-database-projects/src/models/tree/baseTreeItem.ts @@ -10,11 +10,12 @@ import * as path from 'path'; * Base class for an item that appears in the ADS project tree */ export abstract class BaseProjectTreeItem { - uri: vscode.Uri; + /** Project-relative URI that's compatible with the project tree */ + projectUri: vscode.Uri; parent?: BaseProjectTreeItem; constructor(uri: vscode.Uri, parent?: BaseProjectTreeItem) { - this.uri = uri; + this.projectUri = uri; this.parent = parent; } @@ -23,7 +24,7 @@ export abstract class BaseProjectTreeItem { abstract get treeItem(): vscode.TreeItem; public get friendlyName(): string { - return path.parse(this.uri.path).base; + return path.parse(this.projectUri.path).base; } public get root() { @@ -44,7 +45,7 @@ export class MessageTreeItem extends BaseProjectTreeItem { private message: string; constructor(message: string, parent?: BaseProjectTreeItem) { - super(vscode.Uri.file(path.join(parent?.uri.path ?? 'Message', message)), parent); + super(vscode.Uri.file(path.join(parent?.projectUri.path ?? 'Message', message)), parent); this.message = message; } diff --git a/extensions/sql-database-projects/src/models/tree/dataSourceTreeItem.ts b/extensions/sql-database-projects/src/models/tree/dataSourceTreeItem.ts index 32da15ea40..6c1ceaaa0b 100644 --- a/extensions/sql-database-projects/src/models/tree/dataSourceTreeItem.ts +++ b/extensions/sql-database-projects/src/models/tree/dataSourceTreeItem.ts @@ -19,7 +19,7 @@ export class DataSourcesTreeItem extends BaseProjectTreeItem { private dataSources: DataSourceTreeItem[] = []; constructor(project: ProjectRootTreeItem) { - super(vscode.Uri.file(path.join(project.uri.path, constants.dataSourcesNodeName)), project); + super(vscode.Uri.file(path.join(project.projectUri.path, constants.dataSourcesNodeName)), project); this.construct(); } @@ -35,7 +35,7 @@ export class DataSourcesTreeItem extends BaseProjectTreeItem { } public get treeItem(): vscode.TreeItem { - const dataSources = new vscode.TreeItem(this.uri, vscode.TreeItemCollapsibleState.Collapsed); + const dataSources = new vscode.TreeItem(this.projectUri, vscode.TreeItemCollapsibleState.Collapsed); dataSources.contextValue = constants.DatabaseProjectItemType.dataSourceRoot; dataSources.iconPath = IconPathHelper.dataSourceGroup; @@ -50,11 +50,11 @@ abstract class DataSourceTreeItem extends BaseProjectTreeItem { } */ export class SqlConnectionDataSourceTreeItem extends DataSourceTreeItem { constructor(private dataSource: SqlConnectionDataSource, dataSourcesNode: DataSourcesTreeItem) { - super(vscode.Uri.file(path.join(dataSourcesNode.uri.path, dataSource.name)), dataSourcesNode); + super(vscode.Uri.file(path.join(dataSourcesNode.projectUri.path, dataSource.name)), dataSourcesNode); } public get treeItem(): vscode.TreeItem { - let item = new vscode.TreeItem(this.uri, vscode.TreeItemCollapsibleState.Collapsed); + let item = new vscode.TreeItem(this.projectUri, vscode.TreeItemCollapsibleState.Collapsed); item.label = `${this.dataSource.name} (${this.dataSource.typeFriendlyName})`; item.iconPath = IconPathHelper.dataSourceSql; diff --git a/extensions/sql-database-projects/src/models/tree/databaseReferencesTreeItem.ts b/extensions/sql-database-projects/src/models/tree/databaseReferencesTreeItem.ts index b85ef9797e..d81abd4c68 100644 --- a/extensions/sql-database-projects/src/models/tree/databaseReferencesTreeItem.ts +++ b/extensions/sql-database-projects/src/models/tree/databaseReferencesTreeItem.ts @@ -19,7 +19,7 @@ export class DatabaseReferencesTreeItem extends BaseProjectTreeItem { private references: DatabaseReferenceTreeItem[] = []; constructor(project: ProjectRootTreeItem) { - super(vscode.Uri.file(path.join(project.uri.path, constants.databaseReferencesNodeName)), project); + super(vscode.Uri.file(path.join(project.projectUri.fsPath, constants.databaseReferencesNodeName)), project); this.construct(); } @@ -35,7 +35,7 @@ export class DatabaseReferencesTreeItem extends BaseProjectTreeItem { } public get treeItem(): vscode.TreeItem { - const refFolderItem = new vscode.TreeItem(this.uri, vscode.TreeItemCollapsibleState.Collapsed); + const refFolderItem = new vscode.TreeItem(this.projectUri, vscode.TreeItemCollapsibleState.Collapsed); refFolderItem.contextValue = constants.DatabaseProjectItemType.referencesRoot; refFolderItem.iconPath = IconPathHelper.referenceGroup; @@ -45,7 +45,7 @@ export class DatabaseReferencesTreeItem extends BaseProjectTreeItem { export class DatabaseReferenceTreeItem extends BaseProjectTreeItem { constructor(private reference: IDatabaseReferenceProjectEntry, referencesTreeItem: DatabaseReferencesTreeItem) { - super(vscode.Uri.file(path.join(referencesTreeItem.uri.path, reference.databaseName)), referencesTreeItem); + super(vscode.Uri.file(path.join(referencesTreeItem.projectUri.fsPath, reference.databaseName)), referencesTreeItem); } public get children(): BaseProjectTreeItem[] { @@ -53,7 +53,7 @@ export class DatabaseReferenceTreeItem extends BaseProjectTreeItem { } public get treeItem(): vscode.TreeItem { - const refItem = new vscode.TreeItem(this.uri, vscode.TreeItemCollapsibleState.None); + const refItem = new vscode.TreeItem(this.projectUri, vscode.TreeItemCollapsibleState.None); refItem.label = this.reference.databaseName; refItem.contextValue = constants.DatabaseProjectItemType.reference; refItem.iconPath = IconPathHelper.referenceDatabase; diff --git a/extensions/sql-database-projects/src/models/tree/fileFolderTreeItem.ts b/extensions/sql-database-projects/src/models/tree/fileFolderTreeItem.ts index a00b0e5d12..24ed5054de 100644 --- a/extensions/sql-database-projects/src/models/tree/fileFolderTreeItem.ts +++ b/extensions/sql-database-projects/src/models/tree/fileFolderTreeItem.ts @@ -88,12 +88,10 @@ export class ExternalStreamingJobFileNode extends FileNode { export function sortFileFolderNodes(a: (FolderNode | FileNode), b: (FolderNode | FileNode)): number { if (a instanceof FolderNode && !(b instanceof FolderNode)) { return -1; - } - else if (!(a instanceof FolderNode) && b instanceof FolderNode) { + } else if (!(a instanceof FolderNode) && b instanceof FolderNode) { return 1; - } - else { - return a.uri.fsPath.localeCompare(b.uri.fsPath); + } else { + return a.projectUri.fsPath.localeCompare(b.projectUri.fsPath); } } @@ -106,13 +104,12 @@ function fsPathToProjectUri(fileSystemUri: vscode.Uri, projectNode: ProjectRootT if (fileSystemUri.fsPath.startsWith(projBaseDir)) { localUri = fileSystemUri.fsPath.substring(projBaseDir.length); - } - else if (isFile) { + } else if (isFile) { // if file is outside the folder add add at top level in tree // this is not true for folders otherwise the outside files will not be directly inside the top level - let parts = utils.getPlatformSafeFileEntryPath(fileSystemUri.fsPath).split('/'); + const parts = utils.getPlatformSafeFileEntryPath(fileSystemUri.fsPath).split('/'); localUri = parts[parts.length - 1]; } - return vscode.Uri.file(path.join(projectNode.uri.path, localUri)); + return vscode.Uri.file(path.join(projectNode.projectUri.fsPath, localUri)); } diff --git a/extensions/sql-database-projects/src/models/tree/projectTreeItem.ts b/extensions/sql-database-projects/src/models/tree/projectTreeItem.ts index 332d635a82..76269eade5 100644 --- a/extensions/sql-database-projects/src/models/tree/projectTreeItem.ts +++ b/extensions/sql-database-projects/src/models/tree/projectTreeItem.ts @@ -25,7 +25,7 @@ export class ProjectRootTreeItem extends BaseProjectTreeItem { fileSystemUri: vscode.Uri; constructor(project: Project) { - super(vscode.Uri.file(project.projectFilePath), undefined); + super(vscode.Uri.parse(path.basename(project.projectFilePath, sqlprojExtension)), undefined); this.project = project; this.fileSystemUri = vscode.Uri.file(project.projectFilePath); @@ -45,10 +45,10 @@ export class ProjectRootTreeItem extends BaseProjectTreeItem { } public get treeItem(): vscode.TreeItem { - const projectItem = new vscode.TreeItem(this.uri, vscode.TreeItemCollapsibleState.Expanded); + const projectItem = new vscode.TreeItem(this.fileSystemUri, vscode.TreeItemCollapsibleState.Expanded); projectItem.contextValue = DatabaseProjectItemType.project; projectItem.iconPath = IconPathHelper.databaseProject; - projectItem.label = path.basename(this.uri.fsPath, sqlprojExtension); + projectItem.label = path.basename(this.projectUri.fsPath, sqlprojExtension); return projectItem; } diff --git a/extensions/sql-database-projects/src/test/projectTree.test.ts b/extensions/sql-database-projects/src/test/projectTree.test.ts index 4272e50e0a..119f565eb9 100644 --- a/extensions/sql-database-projects/src/test/projectTree.test.ts +++ b/extensions/sql-database-projects/src/test/projectTree.test.ts @@ -43,7 +43,7 @@ describe('Project Tree tests', function (): void { new FileNode(vscode.Uri.file(`${root}D`), parent) ]; - should(inputNodes.map(n => n.uri.path)).deepEqual(expectedNodes.map(n => n.uri.path)); + should(inputNodes.map(n => n.projectUri.path)).deepEqual(expectedNodes.map(n => n.projectUri.path)); }); it('Should build tree from Project file correctly', function (): void { @@ -67,17 +67,17 @@ describe('Project Tree tests', function (): void { proj.files.push(proj.createFileProjectEntry('duplicateFolder', EntryType.Folder)); const tree = new ProjectRootTreeItem(proj); - should(tree.children.map(x => x.uri.path)).deepEqual([ - '/TestProj.sqlproj/Database References', - '/TestProj.sqlproj/duplicateFolder', - '/TestProj.sqlproj/someFolder', - '/TestProj.sqlproj/duplicate.sql']); + should(tree.children.map(x => x.projectUri.path)).deepEqual([ + '/TestProj/Database References', + '/TestProj/duplicateFolder', + '/TestProj/someFolder', + '/TestProj/duplicate.sql']); - should(tree.children.find(x => x.uri.path === '/TestProj.sqlproj/someFolder')?.children.map(y => y.uri.path)).deepEqual([ - '/TestProj.sqlproj/someFolder/aNestedFolder', - '/TestProj.sqlproj/someFolder/bNestedFolder', - '/TestProj.sqlproj/someFolder/aNestedTest.sql', - '/TestProj.sqlproj/someFolder/bNestedTest.sql']); + should(tree.children.find(x => x.projectUri.path === '/TestProj/someFolder')?.children.map(y => y.projectUri.path)).deepEqual([ + '/TestProj/someFolder/aNestedFolder', + '/TestProj/someFolder/bNestedFolder', + '/TestProj/someFolder/aNestedTest.sql', + '/TestProj/someFolder/bNestedTest.sql']); should(tree.children.map(x => x.treeItem.contextValue)).deepEqual([ DatabaseProjectItemType.referencesRoot, @@ -85,7 +85,7 @@ describe('Project Tree tests', function (): void { DatabaseProjectItemType.folder, DatabaseProjectItemType.file]); - should(tree.children.find(x => x.uri.path === '/TestProj.sqlproj/someFolder')?.children.map(y => y.treeItem.contextValue)).deepEqual([ + should(tree.children.find(x => x.projectUri.path === '/TestProj/someFolder')?.children.map(y => y.treeItem.contextValue)).deepEqual([ DatabaseProjectItemType.folder, DatabaseProjectItemType.folder, DatabaseProjectItemType.file, @@ -103,12 +103,12 @@ describe('Project Tree tests', function (): void { proj.files.push(proj.createFileProjectEntry('someFolder1\\MyFile2.sql', EntryType.File)); const tree = new ProjectRootTreeItem(proj); - should(tree.children.map(x => x.uri.path)).deepEqual([ - '/TestProj.sqlproj/Database References', - '/TestProj.sqlproj/someFolder1']); + should(tree.children.map(x => x.projectUri.path)).deepEqual([ + '/TestProj/Database References', + '/TestProj/someFolder1']); // Why are we only matching names - https://github.com/microsoft/azuredatastudio/issues/11026 - should(tree.children.find(x => x.uri.path === '/TestProj.sqlproj/someFolder1')?.children.map(y => path.basename(y.uri.path))).deepEqual([ + should(tree.children.find(x => x.projectUri.path === '/TestProj/someFolder1')?.children.map(y => path.basename(y.projectUri.path))).deepEqual([ 'MyNestedFolder1', 'MyNestedFolder2', 'MyFile2.sql']); @@ -125,9 +125,9 @@ describe('Project Tree tests', function (): void { proj.files.push(proj.createFileProjectEntry('..\\..\\someFolder3', EntryType.Folder)); // folder should not be counted (same as SSDT) const tree = new ProjectRootTreeItem(proj); - should(tree.children.map(x => x.uri.path)).deepEqual([ - '/Root/Level1/Level2/TestProj.sqlproj/Database References', - '/Root/Level1/Level2/TestProj.sqlproj/MyFile1.sql', - '/Root/Level1/Level2/TestProj.sqlproj/MyFile2.sql']); + should(tree.children.map(x => x.projectUri.path)).deepEqual([ + '/TestProj/Database References', + '/TestProj/MyFile1.sql', + '/TestProj/MyFile2.sql']); }); });