diff --git a/extensions/sql-database-projects/package.json b/extensions/sql-database-projects/package.json index 84e339dcad..651724d1dd 100644 --- a/extensions/sql-database-projects/package.json +++ b/extensions/sql-database-projects/package.json @@ -206,6 +206,11 @@ "command": "sqlDatabaseProjects.addSqlCmdVariable", "title": "%sqlDatabaseProjects.addSqlCmdVariable%", "category": "%sqlDatabaseProjects.displayName%" + }, + { + "command": "sqlDatabaseProjects.rename", + "title": "%sqlDatabaseProjects.rename%", + "category": "%sqlDatabaseProjects.displayName%" } ], "menus": { @@ -333,6 +338,10 @@ { "command": "sqlDatabaseProjects.addSqlCmdVariable", "when": "false" + }, + { + "command": "sqlDatabaseProjects.rename", + "when": "false" } ], "view/item/context": [ @@ -426,6 +435,11 @@ "when": "view == dataworkspace.views.main && viewItem == databaseProject.itemType.folder || viewItem =~ /^databaseProject.itemType.file/ || viewItem == databaseProject.itemType.reference || viewItem == databaseProject.itemType.sqlcmdVariable", "group": "9_dbProjectsLast@2" }, + { + "command": "sqlDatabaseProjects.rename", + "when": "view == dataworkspace.views.main && viewItem =~ /^databaseProject.itemType.file/", + "group": "9_dbProjectsLast@3" + }, { "command": "sqlDatabaseProjects.changeTargetPlatform", "when": "view == dataworkspace.views.main && viewItem =~ /^(databaseProject.itemType.project|databaseProject.itemType.legacyProject)$/", diff --git a/extensions/sql-database-projects/package.nls.json b/extensions/sql-database-projects/package.nls.json index ff6edda831..4beced28f6 100644 --- a/extensions/sql-database-projects/package.nls.json +++ b/extensions/sql-database-projects/package.nls.json @@ -15,6 +15,7 @@ "sqlDatabaseProjects.delete": "Delete", "sqlDatabaseProjects.exclude": "Exclude from project", "sqlDatabaseProjects.edit": "Edit", + "sqlDatabaseProjects.rename": "Rename", "sqlDatabaseProjects.validateExternalStreamingJob": "Validate External Streaming Job", "sqlDatabaseProjects.newScript": "Add Script", diff --git a/extensions/sql-database-projects/src/common/constants.ts b/extensions/sql-database-projects/src/common/constants.ts index 9c4c7b4e5a..fa71a509b8 100644 --- a/extensions/sql-database-projects/src/common/constants.ts +++ b/extensions/sql-database-projects/src/common/constants.ts @@ -110,6 +110,7 @@ export function currentTargetPlatform(projectName: string, currentTargetPlatform export function projectUpdatedToSdkStyle(projectName: string) { return localize('projectUpdatedToSdkStyle', "The project {0} has been updated to be an SDK-style project. Click 'Learn More' for details on the Microsoft.Build.Sql SDK and ways to simplify the project file.", projectName); } export function convertToSdkStyleConfirmation(projectName: string) { return localize('convertToSdkStyleConfirmation', "The project '{0}' will not be fully compatible with SSDT after conversion. A backup copy of the project file will be created in the project folder prior to conversion. More information is available at https://aka.ms/sqlprojsdk. Continue with converting to SDK-style project?", projectName); } export function updatedToSdkStyleError(projectName: string) { return localize('updatedToSdkStyleError', "Converting the project {0} to SDK-style was unsuccessful. Changes to the .sqlproj have been rolled back.", projectName); } +export const enterNewName = localize('enterNewName', "Enter new name"); // Publish dialog strings export const publishDialogName = localize('publishDialogName', "Publish project"); diff --git a/extensions/sql-database-projects/src/controllers/mainController.ts b/extensions/sql-database-projects/src/controllers/mainController.ts index c68b038def..9dc7619d05 100644 --- a/extensions/sql-database-projects/src/controllers/mainController.ts +++ b/extensions/sql-database-projects/src/controllers/mainController.ts @@ -85,6 +85,7 @@ export default class MainController implements vscode.Disposable { this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.convertToSdkStyleProject', async (node: WorkspaceTreeItem) => { return this.projectsController.convertToSdkStyleProject(node); })); this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.delete', async (node: WorkspaceTreeItem) => { return this.projectsController.delete(node); })); this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.exclude', async (node: WorkspaceTreeItem) => { return this.projectsController.exclude(node); })); + this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.rename', async (node: WorkspaceTreeItem) => { return this.projectsController.rename(node); })); this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.editSqlCmdVariable', async (node: WorkspaceTreeItem) => { return this.projectsController.editSqlCmdVariable(node); })); this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.addSqlCmdVariable', async (node: WorkspaceTreeItem) => { return this.projectsController.addSqlCmdVariable(node); })); this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.changeTargetPlatform', async (node: WorkspaceTreeItem) => { return this.projectsController.changeTargetPlatform(node); })); diff --git a/extensions/sql-database-projects/src/controllers/projectController.ts b/extensions/sql-database-projects/src/controllers/projectController.ts index 5e51a76271..bc2df8638d 100644 --- a/extensions/sql-database-projects/src/controllers/projectController.ts +++ b/extensions/sql-database-projects/src/controllers/projectController.ts @@ -839,6 +839,41 @@ export class ProjectsController { } } + public async rename(context: dataworkspace.WorkspaceTreeItem): Promise { + const node = context.element as BaseProjectTreeItem; + const project = this.getProjectFromContext(node); + const file = this.getFileProjectEntry(project, node); + + // need to use quickpick because input box isn't supported in treeviews + // https://github.com/microsoft/vscode/issues/117502 and https://github.com/microsoft/vscode/issues/97190 + const newFileName = await vscode.window.showInputBox( + { + title: constants.enterNewName, + value: path.basename(node.friendlyName, constants.sqlFileExtension), + ignoreFocusOut: true, + validateInput: async (value) => { + return await this.fileAlreadyExists(value, file?.fsUri.fsPath!) ? constants.fileAlreadyExists(value) : undefined; + } + }); + + if (!newFileName) { + return; + } + + // TODO: swap this out and hookup to "Move" file/folder api + // rename the file + const newFilePath = path.join(path.dirname(file?.fsUri.fsPath!), `${newFileName}.sql`); + await fs.rename(file?.fsUri.fsPath!, newFilePath); + await project.exclude(file!); + await project.addExistingItem(newFilePath); + + this.refreshProjectsTree(context); + } + + private fileAlreadyExists(newFileName: string, previousFilePath: string): Promise { + return utils.exists(path.join(path.dirname(previousFilePath), `${newFileName}.sql`)); + } + /** * Opens a quickpick to edit the value of the SQLCMD variable launched from * @param context