diff --git a/extensions/sql-database-projects/package.json b/extensions/sql-database-projects/package.json index 6eefdc5b4b..84e339dcad 100644 --- a/extensions/sql-database-projects/package.json +++ b/extensions/sql-database-projects/package.json @@ -196,6 +196,16 @@ "command": "sqlDatabaseProjects.openInDesigner", "title": "%sqlDatabaseProjects.openInDesigner%", "category": "%sqlDatabaseProjects.displayName%" + }, + { + "command": "sqlDatabaseProjects.editSqlCmdVariable", + "title": "%sqlDatabaseProjects.edit%", + "category": "%sqlDatabaseProjects.displayName%" + }, + { + "command": "sqlDatabaseProjects.addSqlCmdVariable", + "title": "%sqlDatabaseProjects.addSqlCmdVariable%", + "category": "%sqlDatabaseProjects.displayName%" } ], "menus": { @@ -315,6 +325,14 @@ { "command": "sqlDatabaseProjects.generateProjectFromOpenApiSpec", "when": "config.workbench.enablePreviewFeatures || config.sqlDatabaseProjects.enablePreviewFeatures" + }, + { + "command": "sqlDatabaseProjects.editSqlCmdVariable", + "when": "false" + }, + { + "command": "sqlDatabaseProjects.addSqlCmdVariable", + "when": "false" } ], "view/item/context": [ @@ -405,7 +423,7 @@ }, { "command": "sqlDatabaseProjects.delete", - "when": "view == dataworkspace.views.main && viewItem == databaseProject.itemType.folder || viewItem =~ /^databaseProject.itemType.file/ || viewItem == databaseProject.itemType.reference", + "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" }, { @@ -427,6 +445,15 @@ "command": "sqlDatabaseProjects.createProjectFromDatabase", "when": "!azdataAvailable && view == objectExplorer && viewItem =~ /^(disconnectedServer|Server|Database)$/", "group": "sqldbproj@1" + }, + { + "command": "sqlDatabaseProjects.editSqlCmdVariable", + "when": "view == dataworkspace.views.main && viewItem == databaseProject.itemType.sqlcmdVariable", + "group": "9_dbProjectsLast@1" + }, + { + "command": "sqlDatabaseProjects.addSqlCmdVariable", + "when": "view == dataworkspace.views.main && viewItem == databaseProject.itemType.sqlcmdVariablesRoot" } ], "objectExplorer/item/context": [ diff --git a/extensions/sql-database-projects/package.nls.json b/extensions/sql-database-projects/package.nls.json index 2cbb49e9ba..ff6edda831 100644 --- a/extensions/sql-database-projects/package.nls.json +++ b/extensions/sql-database-projects/package.nls.json @@ -14,6 +14,7 @@ "sqlDatabaseProjects.schemaCompare": "Schema Compare", "sqlDatabaseProjects.delete": "Delete", "sqlDatabaseProjects.exclude": "Exclude from project", + "sqlDatabaseProjects.edit": "Edit", "sqlDatabaseProjects.validateExternalStreamingJob": "Validate External Streaming Job", "sqlDatabaseProjects.newScript": "Add Script", @@ -28,6 +29,7 @@ "sqlDatabaseProjects.newFolder": "Add Folder", "sqlDatabaseProjects.addDatabaseReference": "Add Database Reference", + "sqlDatabaseProjects.addSqlCmdVariable": "Add SQLCMD Variable", "sqlDatabaseProjects.openContainingFolder": "Open Containing Folder", "sqlDatabaseProjects.editProjectFile": "Edit .sqlproj File", "sqlDatabaseProjects.changeTargetPlatform": "Change Target Platform", diff --git a/extensions/sql-database-projects/src/common/constants.ts b/extensions/sql-database-projects/src/common/constants.ts index 7dfcda638d..a34e4f114e 100644 --- a/extensions/sql-database-projects/src/common/constants.ts +++ b/extensions/sql-database-projects/src/common/constants.ts @@ -105,6 +105,7 @@ export function newObjectNamePrompt(objectType: string) { return localize('newOb export function deleteConfirmation(toDelete: string) { return localize('deleteConfirmation', "Are you sure you want to delete {0}?", toDelete); } export function deleteConfirmationContents(toDelete: string) { return localize('deleteConfirmationContents', "Are you sure you want to delete {0} and all of its contents?", toDelete); } export function deleteReferenceConfirmation(toDelete: string) { return localize('deleteReferenceConfirmation', "Are you sure you want to delete the reference to {0}?", toDelete); } +export function deleteSqlCmdVariableConfirmation(toDelete: string) { return localize('deleteSqlCmdVariableConfirmation', "Are you sure you want to delete the SQLCMD Variable '{0}'?", toDelete); } export function selectTargetPlatform(currentTargetPlatform: string) { return localize('selectTargetPlatform', "Current target platform: {0}. Select new target platform", currentTargetPlatform); } export function currentTargetPlatform(projectName: string, currentTargetPlatform: string) { return localize('currentTargetPlatform', "Target platform of the project {0} is now {1}", projectName, 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); } @@ -139,6 +140,9 @@ export const browseForProfileWithIcon = `$(folder) ${localize('browseForProfile' export const chooseAction = localize('chooseAction', "Choose action"); export const chooseSqlcmdVarsToModify = localize('chooseSqlcmdVarsToModify', "Choose SQLCMD variables to modify"); export const enterNewValueForVar = (varName: string) => localize('enterNewValueForVar', "Enter new value for variable '{0}'", varName); +export const enterNewSqlCmdVariableName = localize('enterNewSqlCmdVariableName', "Enter new SQLCMD Variable name"); +export const enterNewSqlCmdVariableDefaultValue = (varName: string) => localize('enterNewSqlCmdVariableDefaultValue', "Enter default value for SQLCMD variable '{0}'", varName); +export const sqlcmdVariableAlreadyExists = localize('sqlcmdVariableAlreadyExists', "A SQLCMD Variable with the same name already exists in this project"); export const resetAllVars = localize('resetAllVars', "Reset all variables"); export const createNew = localize('createNew', "Create New"); export const enterNewDatabaseName = localize('enterNewDatabaseName', "Enter new database name"); diff --git a/extensions/sql-database-projects/src/controllers/mainController.ts b/extensions/sql-database-projects/src/controllers/mainController.ts index b5cc2b31ee..c68b038def 100644 --- a/extensions/sql-database-projects/src/controllers/mainController.ts +++ b/extensions/sql-database-projects/src/controllers/mainController.ts @@ -85,6 +85,8 @@ 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.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); })); this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.validateExternalStreamingJob', async (node: WorkspaceTreeItem) => { return this.projectsController.validateExternalStreamingJob(node); })); this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.openFileWithWatcher', async (fileSystemUri: vscode.Uri, node: FileNode) => { return this.projectsController.openFileWithWatcher(fileSystemUri, node); })); diff --git a/extensions/sql-database-projects/src/controllers/projectController.ts b/extensions/sql-database-projects/src/controllers/projectController.ts index 9f1aa259e2..b35f021100 100644 --- a/extensions/sql-database-projects/src/controllers/projectController.ts +++ b/extensions/sql-database-projects/src/controllers/projectController.ts @@ -48,6 +48,7 @@ import { UpdateProjectAction, UpdateProjectDataModel } from '../models/api/updat import { AzureSqlClient } from '../models/deploy/azureSqlClient'; import { ConnectionService } from '../models/connections/connectionService'; import { getPublishToDockerSettings } from '../dialogs/publishToDockerQuickpick'; +import { SqlCmdVariableTreeItem } from '../models/tree/sqlcmdVariableTreeItem'; const maxTableLength = 10; @@ -786,6 +787,8 @@ export class ProjectsController { let confirmationPrompt; if (node instanceof DatabaseReferenceTreeItem) { confirmationPrompt = constants.deleteReferenceConfirmation(node.friendlyName); + } else if (node instanceof SqlCmdVariableTreeItem) { + confirmationPrompt = constants.deleteSqlCmdVariableConfirmation(node.friendlyName); } else if (node instanceof FolderNode) { confirmationPrompt = constants.deleteConfirmationContents(node.friendlyName); } else { @@ -807,6 +810,8 @@ export class ProjectsController { await project.deleteDatabaseReference(databaseReference); success = true; } + } else if (node instanceof SqlCmdVariableTreeItem) { + // TODO: handle deleting sqlcmd var from project after swap } else if (node instanceof FileNode || FolderNode) { const fileEntry = this.getFileProjectEntry(project, node); @@ -831,6 +836,69 @@ export class ProjectsController { } } + /** + * Opens a quickpick to edit the value of the SQLCMD variable launched from + * @param context + */ + public async editSqlCmdVariable(context: dataworkspace.WorkspaceTreeItem): Promise { + const node = context.element as SqlCmdVariableTreeItem; + const project = this.getProjectFromContext(node); + const originalValue = project.sqlCmdVariables[node.friendlyName]; // TODO: update to hookup with however sqlcmd vars work after swap + + const newValue = await vscode.window.showInputBox( + { + title: constants.enterNewValueForVar(node.friendlyName), + value: originalValue, + ignoreFocusOut: true + }); + + if (!newValue) { + return; + } + + // TODO: update value in sqlcmd variables after swap + } + + /** + * Opens a quickpick to add a new SQLCMD variable to the project + * @param context + */ + public async addSqlCmdVariable(context: dataworkspace.WorkspaceTreeItem): Promise { + const project = this.getProjectFromContext(context); + + const variableName = await vscode.window.showInputBox( + { + title: constants.enterNewSqlCmdVariableName, + ignoreFocusOut: true, + validateInput: (value) => { + return this.sqlCmdVariableNameAlreadyExists(value, project) ? constants.sqlcmdVariableAlreadyExists : undefined; + } + }); + + if (!variableName) { + return; + } + + const defaultValue = await vscode.window.showInputBox( + { + title: constants.enterNewSqlCmdVariableDefaultValue(variableName), + ignoreFocusOut: true + }); + + if (!defaultValue) { + return; + } + + // TODO: update after swap + await project.addSqlCmdVariable(variableName, defaultValue); + + this.refreshProjectsTree(context); + } + + private sqlCmdVariableNameAlreadyExists(newVariableName: string, project: Project): boolean { + return Object.keys(project.sqlCmdVariables).findIndex(v => v === newVariableName) !== -1; + } + private getDatabaseReference(project: Project, context: BaseProjectTreeItem): IDatabaseReferenceProjectEntry | undefined { const root = context.root as ProjectRootTreeItem; const databaseReference = context as DatabaseReferenceTreeItem;