diff --git a/extensions/sql-database-projects/src/controllers/databaseProjectTreeViewProvider.ts b/extensions/sql-database-projects/src/controllers/databaseProjectTreeViewProvider.ts index 3a89ecd079..46f9c8798f 100644 --- a/extensions/sql-database-projects/src/controllers/databaseProjectTreeViewProvider.ts +++ b/extensions/sql-database-projects/src/controllers/databaseProjectTreeViewProvider.ts @@ -5,7 +5,7 @@ import * as vscode from 'vscode'; -import { BaseProjectTreeItem, SpacerTreeItem } from '../models/tree/baseTreeItem'; +import { BaseProjectTreeItem } from '../models/tree/baseTreeItem'; import { ProjectRootTreeItem } from '../models/tree/projectTreeItem'; import { Project } from '../models/project'; @@ -52,11 +52,6 @@ export class SqlDatabaseProjectTreeViewProvider implements vscode.TreeDataProvid for (const proj of projects) { newRoots.push(new ProjectRootTreeItem(proj)); - newRoots.push(SpacerTreeItem); - } - - if (newRoots[newRoots.length - 1] === SpacerTreeItem) { - newRoots.pop(); // get rid of the trailing SpacerTreeItem } this.roots = newRoots; diff --git a/extensions/sql-database-projects/src/controllers/projectController.ts b/extensions/sql-database-projects/src/controllers/projectController.ts index bc2df8638d..24ad007cb9 100644 --- a/extensions/sql-database-projects/src/controllers/projectController.ts +++ b/extensions/sql-database-projects/src/controllers/projectController.ts @@ -777,7 +777,7 @@ export class ProjectsController { await project.exclude(fileEntry); } else { TelemetryReporter.sendErrorEvent(TelemetryViews.ProjectTree, TelemetryActions.excludeFromProject); - void vscode.window.showErrorMessage(constants.unableToPerformAction(constants.excludeAction, node.projectUri.path)); + void vscode.window.showErrorMessage(constants.unableToPerformAction(constants.excludeAction, node.relativeProjectUri.path)); } this.refreshProjectsTree(context); @@ -835,7 +835,7 @@ export class ProjectsController { .withAdditionalProperties({ objectType: node.constructor.name }) .send(); - void vscode.window.showErrorMessage(constants.unableToPerformAction(constants.deleteAction, node.projectUri.path)); + void vscode.window.showErrorMessage(constants.unableToPerformAction(constants.deleteAction, node.relativeProjectUri.path)); } } @@ -1454,7 +1454,7 @@ export class ProjectsController { const trimmedUri = utils.trimChars(utils.getPlatformSafeFileEntryPath(utils.trimUri(root.fileSystemUri, fileOrFolder.fileSystemUri)), '/'); return allFileEntries.find(x => utils.trimChars(utils.getPlatformSafeFileEntryPath(x.relativePath), '/') === trimmedUri); } - return project.files.find(x => utils.getPlatformSafeFileEntryPath(x.relativePath) === utils.getPlatformSafeFileEntryPath(utils.trimUri(context.root.projectUri, context.projectUri))); + return project.files.find(x => utils.getPlatformSafeFileEntryPath(x.relativePath) === utils.getPlatformSafeFileEntryPath(utils.trimUri(context.root.relativeProjectUri, context.relativeProjectUri))); } private getProjectFromContext(context: Project | BaseProjectTreeItem | dataworkspace.WorkspaceTreeItem): Project { @@ -1469,12 +1469,12 @@ export class ProjectsController { if (context.root instanceof ProjectRootTreeItem) { return (context.root).project; } else { - throw new Error(constants.unexpectedProjectContext(context.projectUri.path)); + throw new Error(constants.unexpectedProjectContext(context.relativeProjectUri.path)); } } private getRelativePath(treeNode: BaseProjectTreeItem): string { - return treeNode instanceof FolderNode ? utils.trimUri(treeNode.root.projectUri, treeNode.projectUri) : ''; + return treeNode instanceof FolderNode ? utils.trimUri(treeNode.root.relativeProjectUri, treeNode.relativeProjectUri) : ''; } private getConnectionProfileFromContext(context: azdataType.IConnectionProfile | mssqlVscode.ITreeNodeInfo | undefined): azdataType.IConnectionProfile | mssqlVscode.IConnectionInfo | undefined { diff --git a/extensions/sql-database-projects/src/models/tree/baseTreeItem.ts b/extensions/sql-database-projects/src/models/tree/baseTreeItem.ts index 1428695801..98d59d3066 100644 --- a/extensions/sql-database-projects/src/models/tree/baseTreeItem.ts +++ b/extensions/sql-database-projects/src/models/tree/baseTreeItem.ts @@ -10,21 +10,19 @@ import * as path from 'path'; * Base class for an item that appears in the ADS project tree */ export abstract class BaseProjectTreeItem { - /** Project-relative URI that's compatible with the project tree */ - projectUri: vscode.Uri; - parent?: BaseProjectTreeItem; - - constructor(uri: vscode.Uri, parent?: BaseProjectTreeItem) { - this.projectUri = uri; - this.parent = parent; - } + /** + * Constructor + * @param relativeProjectUri Project-relative URI that's compatible with the project tree + * @param parent parent tree item + */ + constructor(public relativeProjectUri: vscode.Uri, public parent?: BaseProjectTreeItem) { } abstract get children(): BaseProjectTreeItem[]; abstract get treeItem(): vscode.TreeItem; public get friendlyName(): string { - return path.parse(this.projectUri.path).base; + return path.parse(this.relativeProjectUri.path).base; } public get root() { @@ -37,25 +35,3 @@ export abstract class BaseProjectTreeItem { return node; } } - -/** - * Leaf tree item that just displays text for messaging purposes - */ -export class MessageTreeItem extends BaseProjectTreeItem { - private message: string; - - constructor(message: string, parent?: BaseProjectTreeItem) { - super(vscode.Uri.file(path.join(parent?.projectUri.path ?? 'Message', message)), parent); - this.message = message; - } - - public get children(): BaseProjectTreeItem[] { - return []; - } - - public get treeItem(): vscode.TreeItem { - return new vscode.TreeItem(this.message, vscode.TreeItemCollapsibleState.None); - } -} - -export const SpacerTreeItem = new MessageTreeItem(''); diff --git a/extensions/sql-database-projects/src/models/tree/databaseReferencesTreeItem.ts b/extensions/sql-database-projects/src/models/tree/databaseReferencesTreeItem.ts index 5ffca8d781..368b6bede5 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.projectUri.fsPath, constants.databaseReferencesNodeName)), project); + super(vscode.Uri.file(path.join(project.relativeProjectUri.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.projectUri, vscode.TreeItemCollapsibleState.Collapsed); + const refFolderItem = new vscode.TreeItem(this.relativeProjectUri, 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.projectUri.fsPath, reference.databaseName)), referencesTreeItem); + super(vscode.Uri.file(path.join(referencesTreeItem.relativeProjectUri.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.projectUri, vscode.TreeItemCollapsibleState.None); + const refItem = new vscode.TreeItem(this.relativeProjectUri, 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 996cda0ff9..4d9e363115 100644 --- a/extensions/sql-database-projects/src/models/tree/fileFolderTreeItem.ts +++ b/extensions/sql-database-projects/src/models/tree/fileFolderTreeItem.ts @@ -100,7 +100,7 @@ export function sortFileFolderNodes(a: (FolderNode | FileNode), b: (FolderNode | } else if (!(a instanceof FolderNode) && b instanceof FolderNode) { return 1; } else { - return a.projectUri.fsPath.localeCompare(b.projectUri.fsPath); + return a.relativeProjectUri.fsPath.localeCompare(b.relativeProjectUri.fsPath); } } @@ -120,5 +120,5 @@ function fsPathToProjectUri(fileSystemUri: vscode.Uri, projectNode: ProjectRootT localUri = parts[parts.length - 1]; } - return vscode.Uri.file(path.join(projectNode.projectUri.fsPath, localUri)); + return vscode.Uri.file(path.join(projectNode.relativeProjectUri.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 11f44c06f2..6bfec3fff4 100644 --- a/extensions/sql-database-projects/src/models/tree/projectTreeItem.ts +++ b/extensions/sql-database-projects/src/models/tree/projectTreeItem.ts @@ -50,7 +50,7 @@ export class ProjectRootTreeItem extends BaseProjectTreeItem { const projectItem = new vscode.TreeItem(this.fileSystemUri, collapsibleState); projectItem.contextValue = this.project.isSdkStyleProject ? DatabaseProjectItemType.project : DatabaseProjectItemType.legacyProject; projectItem.iconPath = IconPathHelper.databaseProject; - projectItem.label = path.basename(this.projectUri.fsPath, sqlprojExtension); + projectItem.label = path.basename(this.relativeProjectUri.fsPath, sqlprojExtension); return projectItem; } diff --git a/extensions/sql-database-projects/src/models/tree/sqlcmdVariableTreeItem.ts b/extensions/sql-database-projects/src/models/tree/sqlcmdVariableTreeItem.ts index ddaa53937d..cc368478fe 100644 --- a/extensions/sql-database-projects/src/models/tree/sqlcmdVariableTreeItem.ts +++ b/extensions/sql-database-projects/src/models/tree/sqlcmdVariableTreeItem.ts @@ -18,7 +18,7 @@ export class SqlCmdVariablesTreeItem extends BaseProjectTreeItem { private sqlcmdVariables: SqlCmdVariableTreeItem[] = []; constructor(project: ProjectRootTreeItem) { - super(vscode.Uri.file(path.join(project.projectUri.fsPath, constants.sqlcmdVariablesNodeName)), project); + super(vscode.Uri.file(path.join(project.relativeProjectUri.fsPath, constants.sqlcmdVariablesNodeName)), project); this.construct(); } @@ -42,7 +42,7 @@ export class SqlCmdVariablesTreeItem extends BaseProjectTreeItem { } public get treeItem(): vscode.TreeItem { - const sqlCmdVariableFolderItem = new vscode.TreeItem(this.projectUri, vscode.TreeItemCollapsibleState.Collapsed); + const sqlCmdVariableFolderItem = new vscode.TreeItem(this.relativeProjectUri, vscode.TreeItemCollapsibleState.Collapsed); sqlCmdVariableFolderItem.contextValue = constants.DatabaseProjectItemType.sqlcmdVariablesRoot; sqlCmdVariableFolderItem.iconPath = IconPathHelper.sqlCmdVariablesGroup; @@ -55,7 +55,7 @@ export class SqlCmdVariablesTreeItem extends BaseProjectTreeItem { */ export class SqlCmdVariableTreeItem extends BaseProjectTreeItem { constructor(private sqlcmdVar: string, sqlcmdVarsTreeItem: SqlCmdVariablesTreeItem) { - super(vscode.Uri.file(path.join(sqlcmdVarsTreeItem.projectUri.fsPath, sqlcmdVar)), sqlcmdVarsTreeItem); + super(vscode.Uri.file(path.join(sqlcmdVarsTreeItem.relativeProjectUri.fsPath, sqlcmdVar)), sqlcmdVarsTreeItem); } public get children(): BaseProjectTreeItem[] { @@ -63,7 +63,7 @@ export class SqlCmdVariableTreeItem extends BaseProjectTreeItem { } public get treeItem(): vscode.TreeItem { - const sqlcmdVariableItem = new vscode.TreeItem(this.projectUri, vscode.TreeItemCollapsibleState.None); + const sqlcmdVariableItem = new vscode.TreeItem(this.relativeProjectUri, vscode.TreeItemCollapsibleState.None); sqlcmdVariableItem.label = this.sqlcmdVar; sqlcmdVariableItem.contextValue = constants.DatabaseProjectItemType.sqlcmdVariable; sqlcmdVariableItem.iconPath = IconPathHelper.sqlCmdVariable; diff --git a/extensions/sql-database-projects/src/test/projectController.test.ts b/extensions/sql-database-projects/src/test/projectController.test.ts index 5899cac664..728d588d2c 100644 --- a/extensions/sql-database-projects/src/test/projectController.test.ts +++ b/extensions/sql-database-projects/src/test/projectController.test.ts @@ -343,8 +343,8 @@ describe('ProjectsController', function (): void { // Confirm result should(proj.files.some(x => x.relativePath === 'UpperFolder')).equal(false, 'UpperFolder should not be part of proj file any more'); should(await utils.exists(scriptEntry.fsUri.fsPath)).equal(false, 'script is supposed to be deleted from disk'); - should(await utils.exists(lowerFolder.projectUri.fsPath)).equal(false, 'LowerFolder is supposed to be deleted from disk'); - should(await utils.exists(upperFolder.projectUri.fsPath)).equal(false, 'UpperFolder is supposed to be deleted from disk'); + should(await utils.exists(lowerFolder.relativeProjectUri.fsPath)).equal(false, 'LowerFolder is supposed to be deleted from disk'); + should(await utils.exists(upperFolder.relativeProjectUri.fsPath)).equal(false, 'UpperFolder is supposed to be deleted from disk'); }); it('Should reload correctly after changing sqlproj file', async function (): Promise { diff --git a/extensions/sql-database-projects/src/test/projectTree.test.ts b/extensions/sql-database-projects/src/test/projectTree.test.ts index 4ac4cc2d7c..d56aa643bc 100644 --- a/extensions/sql-database-projects/src/test/projectTree.test.ts +++ b/extensions/sql-database-projects/src/test/projectTree.test.ts @@ -44,7 +44,7 @@ describe('Project Tree tests', function (): void { new FileNode(vscode.Uri.file(`${root}D`), parent) ]; - should(inputNodes.map(n => n.projectUri.path)).deepEqual(expectedNodes.map(n => n.projectUri.path)); + should(inputNodes.map(n => n.relativeProjectUri.path)).deepEqual(expectedNodes.map(n => n.relativeProjectUri.path)); }); it('Should build tree from Project file correctly', function (): void { @@ -68,14 +68,14 @@ 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.projectUri.path)).deepEqual([ + should(tree.children.map(x => x.relativeProjectUri.path)).deepEqual([ '/TestProj/Database References', '/TestProj/SQLCMD Variables', '/TestProj/duplicateFolder', '/TestProj/someFolder', '/TestProj/duplicate.sql']); - should(tree.children.find(x => x.projectUri.path === '/TestProj/someFolder')?.children.map(y => y.projectUri.path)).deepEqual([ + should(tree.children.find(x => x.relativeProjectUri.path === '/TestProj/someFolder')?.children.map(y => y.relativeProjectUri.path)).deepEqual([ '/TestProj/someFolder/aNestedFolder', '/TestProj/someFolder/bNestedFolder', '/TestProj/someFolder/aNestedTest.sql', @@ -88,7 +88,7 @@ describe('Project Tree tests', function (): void { DatabaseProjectItemType.folder, DatabaseProjectItemType.file]); - should(tree.children.find(x => x.projectUri.path === '/TestProj/someFolder')?.children.map(y => y.treeItem.contextValue)).deepEqual([ + should(tree.children.find(x => x.relativeProjectUri.path === '/TestProj/someFolder')?.children.map(y => y.treeItem.contextValue)).deepEqual([ DatabaseProjectItemType.folder, DatabaseProjectItemType.folder, DatabaseProjectItemType.file, @@ -106,12 +106,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.projectUri.path)).deepEqual([ + should(tree.children.map(x => x.relativeProjectUri.path)).deepEqual([ '/TestProj/Database References', '/TestProj/SQLCMD Variables', '/TestProj/someFolder1']); - should(tree.children.find(x => x.projectUri.path === '/TestProj/someFolder1')?.children.map(y => y.projectUri.path)).deepEqual([ + should(tree.children.find(x => x.relativeProjectUri.path === '/TestProj/someFolder1')?.children.map(y => y.relativeProjectUri.path)).deepEqual([ '/TestProj/someFolder1/MyNestedFolder1', '/TestProj/someFolder1/MyNestedFolder2', '/TestProj/someFolder1/MyFile2.sql']); @@ -128,7 +128,7 @@ 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.projectUri.path)).deepEqual([ + should(tree.children.map(x => x.relativeProjectUri.path)).deepEqual([ '/TestProj/Database References', '/TestProj/SQLCMD Variables', '/TestProj/MyFile1.sql',