From 3b3df2c3fcc9d5aff7d67d6a161ed6c0df511a7e Mon Sep 17 00:00:00 2001 From: Sakshi Sharma <57200045+SakshiS-harma@users.noreply.github.com> Date: Wed, 5 May 2021 19:00:22 -0700 Subject: [PATCH] Fixes for sql db projects dashboard (#15100) * Fix ID assignment for sql db projects dashboard * Update with new fixes * Fix tests * Fix test --- .../src/common/constants.ts | 8 ++- .../src/controllers/projectController.ts | 66 +++++++++---------- .../src/dialogs/publishDatabaseDialog.ts | 9 +++ .../src/models/IPublishSettings.ts | 2 + .../src/models/dashboardData/dashboardData.ts | 11 ++++ .../models/publishProfile/publishProfile.ts | 9 ++- .../src/projectProvider/projectProvider.ts | 31 ++++----- .../dialogs/publishDatabaseDialog.test.ts | 3 + .../src/test/projectController.test.ts | 2 +- 9 files changed, 84 insertions(+), 57 deletions(-) diff --git a/extensions/sql-database-projects/src/common/constants.ts b/extensions/sql-database-projects/src/common/constants.ts index 393c826514..c116e7e85b 100644 --- a/extensions/sql-database-projects/src/common/constants.ts +++ b/extensions/sql-database-projects/src/common/constants.ts @@ -37,12 +37,14 @@ export const buildAction = localize('buildAction', "Build"); export const publishAction = localize('publishAction', "Publish"); export const changeTargetPlatformAction = localize('changeTargetPlatformAction', "Change Target Platform"); -export const ID = localize('ID', "ID"); export const Status = localize('Status', "Status"); export const Time = localize('Time', "Time"); export const Date = localize('Date', "Date"); -export const Builds = localize('Builds', "Builds"); -export const Deployments = localize('Deployments', "Deployments"); +export const TargetPlatform = localize('TargetPlatform', "Target Platform"); +export const TargetServer = localize('TargetServer', "Target Server"); +export const TargetDatabase = localize('TargetDatabase', "Target Database"); +export const BuildHistory = localize('BuildHistory', "Build History"); +export const PublishHistory = localize('PublishHistory', "Publish History"); export const Success = localize('Success', "Success"); export const Failed = localize('Failed', "Failed"); diff --git a/extensions/sql-database-projects/src/controllers/projectController.ts b/extensions/sql-database-projects/src/controllers/projectController.ts index 245839cde5..ae74697499 100644 --- a/extensions/sql-database-projects/src/controllers/projectController.ts +++ b/extensions/sql-database-projects/src/controllers/projectController.ts @@ -32,7 +32,7 @@ import { DatabaseReferenceTreeItem } from '../models/tree/databaseReferencesTree import { CreateProjectFromDatabaseDialog } from '../dialogs/createProjectFromDatabaseDialog'; import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/telemetry'; import { IconPathHelper } from '../common/iconHelper'; -import { DashboardData, Status } from '../models/dashboardData/dashboardData'; +import { DashboardData, PublishData, Status } from '../models/dashboardData/dashboardData'; const maxTableLength = 10; @@ -43,7 +43,7 @@ export class ProjectsController { private netCoreTool: NetCoreTool; private buildHelper: BuildHelper; private buildInfo: DashboardData[] = []; - private deployInfo: DashboardData[] = []; + private publishInfo: PublishData[] = []; projFileWatchers = new Map(); @@ -52,18 +52,17 @@ export class ProjectsController { this.buildHelper = new BuildHelper(); } - public getDashboardDeployData(projectFile: string): (string | dataworkspace.IconCellValue)[][] { + public getDashboardPublishData(projectFile: string): (string | dataworkspace.IconCellValue)[][] { const infoRows: (string | dataworkspace.IconCellValue)[][] = []; - let count = 0; - for (let i = this.deployInfo.length - 1; i >= 0; i--) { - if (this.deployInfo[i].projectFile === projectFile) { + for (let i = this.publishInfo.length - 1; i >= 0; i--) { + if (this.publishInfo[i].projectFile === projectFile) { let icon: azdata.IconPath; let text: string; - if (this.deployInfo[i].status === Status.success) { + if (this.publishInfo[i].status === Status.success) { icon = IconPathHelper.success; text = constants.Success; - } else if (this.deployInfo[i].status === Status.failed) { + } else if (this.publishInfo[i].status === Status.failed) { icon = IconPathHelper.error; text = constants.Failed; } else { @@ -71,13 +70,13 @@ export class ProjectsController { text = constants.InProgress; } - let infoRow: (string | dataworkspace.IconCellValue)[] = [count.toString(), - { text: text, icon: icon }, - this.deployInfo[i].target, - this.deployInfo[i].timeToCompleteAction, - this.deployInfo[i].startDate]; + let infoRow: (string | dataworkspace.IconCellValue)[] = [{ text: text, icon: icon }, + this.publishInfo[i].startDate, + this.publishInfo[i].timeToCompleteAction, + this.publishInfo[i].target, + this.publishInfo[i].targetServer, + this.publishInfo[i].targetDatabase]; infoRows.push(infoRow); - count++; } } @@ -86,7 +85,6 @@ export class ProjectsController { public getDashboardBuildData(projectFile: string): (string | dataworkspace.IconCellValue)[][] { const infoRows: (string | dataworkspace.IconCellValue)[][] = []; - let count = 0; for (let i = this.buildInfo.length - 1; i >= 0; i--) { if (this.buildInfo[i].projectFile === projectFile) { @@ -103,13 +101,11 @@ export class ProjectsController { text = constants.InProgress; } - let infoRow: (string | dataworkspace.IconCellValue)[] = [count.toString(), - { text: text, icon: icon }, - this.buildInfo[i].target, + let infoRow: (string | dataworkspace.IconCellValue)[] = [{ text: text, icon: icon }, + this.buildInfo[i].startDate, this.buildInfo[i].timeToCompleteAction, - this.buildInfo[i].startDate]; + this.buildInfo[i].target]; infoRows.push(infoRow); - count++; } } @@ -278,13 +274,13 @@ export class ProjectsController { telemetryProps.profileUsed = (settings.profileUsed ?? false).toString(); const currentDate = new Date(); const actionStartTime = currentDate.getTime(); - const currentDeployTimeInfo = `${currentDate.toLocaleDateString()} ${constants.at} ${currentDate.toLocaleTimeString()}`; + const currentPublishTimeInfo = `${currentDate.toLocaleDateString()} ${constants.at} ${currentDate.toLocaleTimeString()}`; - let deployInfoNew = new DashboardData(project.projectFilePath, Status.inProgress, project.getProjectTargetVersion(), currentDeployTimeInfo); - this.deployInfo.push(deployInfoNew); + let publishInfoNew = new PublishData(project.projectFilePath, Status.inProgress, project.getProjectTargetVersion(), currentPublishTimeInfo, settings.databaseName, settings.serverName); + this.publishInfo.push(publishInfoNew); - if (this.deployInfo.length - 1 === maxTableLength) { - this.deployInfo.shift(); // Remove the first element to maintain the length + if (this.publishInfo.length - 1 === maxTableLength) { + this.publishInfo.shift(); // Remove the first element to maintain the length } try { @@ -298,29 +294,29 @@ export class ProjectsController { } } catch (err) { const actionEndTime = new Date().getTime(); - const timeToFailureDeploy = actionEndTime - actionStartTime; - telemetryProps.actionDuration = timeToFailureDeploy.toString(); + const timeToFailurePublish = actionEndTime - actionStartTime; + telemetryProps.actionDuration = timeToFailurePublish.toString(); telemetryProps.totalDuration = (actionEndTime - buildStartTime).toString(); TelemetryReporter.createErrorEvent(TelemetryViews.ProjectController, TelemetryActions.publishProject) .withAdditionalProperties(telemetryProps) .send(); - const currentDeployIndex = this.deployInfo.findIndex(d => d.startDate === currentDeployTimeInfo); - this.deployInfo[currentDeployIndex].status = Status.failed; - this.deployInfo[currentDeployIndex].timeToCompleteAction = utils.timeConversion(timeToFailureDeploy); + const currentPublishIndex = this.publishInfo.findIndex(d => d.startDate === currentPublishTimeInfo); + this.publishInfo[currentPublishIndex].status = Status.failed; + this.publishInfo[currentPublishIndex].timeToCompleteAction = utils.timeConversion(timeToFailurePublish); throw err; } const actionEndTime = new Date().getTime(); - const timeToDeploy = actionEndTime - actionStartTime; - telemetryProps.actionDuration = timeToDeploy.toString(); + const timeToPublish = actionEndTime - actionStartTime; + telemetryProps.actionDuration = timeToPublish.toString(); telemetryProps.totalDuration = (actionEndTime - buildStartTime).toString(); - const currentDeployIndex = this.deployInfo.findIndex(d => d.startDate === currentDeployTimeInfo); - this.deployInfo[currentDeployIndex].status = result.success ? Status.success : Status.failed; - this.deployInfo[currentDeployIndex].timeToCompleteAction = utils.timeConversion(timeToDeploy); + const currentPublishIndex = this.publishInfo.findIndex(d => d.startDate === currentPublishTimeInfo); + this.publishInfo[currentPublishIndex].status = result.success ? Status.success : Status.failed; + this.publishInfo[currentPublishIndex].timeToCompleteAction = utils.timeConversion(timeToPublish); TelemetryReporter.createActionEvent(TelemetryViews.ProjectController, TelemetryActions.publishProject) .withAdditionalProperties(telemetryProps) diff --git a/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts b/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts index 417010585b..5dca9c8c0b 100644 --- a/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts +++ b/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts @@ -42,6 +42,7 @@ export class PublishDatabaseDialog { private sqlCmdVars: Record | undefined; private deploymentOptions: DeploymentOptions | undefined; private profileUsed: boolean = false; + private serverName: string | undefined; private toDispose: vscode.Disposable[] = []; @@ -183,6 +184,7 @@ export class PublishDatabaseDialog { public async publishClick(): Promise { const settings: IPublishSettings = { databaseName: this.getTargetDatabaseName(), + serverName: this.getServerName(), upgradeExisting: true, connectionUri: await this.getConnectionUri(), sqlCmdVariables: this.getSqlCmdVariablesForPublish(), @@ -202,6 +204,7 @@ export class PublishDatabaseDialog { const sqlCmdVars = this.getSqlCmdVariablesForPublish(); const settings: IGenerateScriptSettings = { databaseName: this.getTargetDatabaseName(), + serverName: this.getServerName(), connectionUri: await this.getConnectionUri(), sqlCmdVariables: sqlCmdVars, deploymentOptions: await this.getDeploymentOptions(), @@ -249,6 +252,10 @@ export class PublishDatabaseDialog { return this.project.projectFileName; } + public getServerName(): string { + return this.serverName!; + } + private createRadioButtons(view: azdata.ModelView): azdata.Component { this.connectionsRadioButton = view.modelBuilder.radioButton() .withProperties({ @@ -488,6 +495,7 @@ export class PublishDatabaseDialog { selectConnectionButton.onDidClick(async () => { let connection = await azdata.connection.openConnectionDialog(); this.connectionId = connection.connectionId; + this.serverName = connection.options['server']; let connectionTextboxValue: string = getConnectionName(connection); @@ -550,6 +558,7 @@ export class PublishDatabaseDialog { (this.targetDatabaseDropDown).values = []; this.connectionId = result.connectionId; + this.serverName = result.serverName; await this.updateConnectionComponents(result.connection, this.connectionId); if (result.databaseName) { diff --git a/extensions/sql-database-projects/src/models/IPublishSettings.ts b/extensions/sql-database-projects/src/models/IPublishSettings.ts index ec2a62cb0e..bb3e378960 100644 --- a/extensions/sql-database-projects/src/models/IPublishSettings.ts +++ b/extensions/sql-database-projects/src/models/IPublishSettings.ts @@ -7,6 +7,7 @@ import { DeploymentOptions } from '../../../mssql/src/mssql'; export interface IPublishSettings { databaseName: string; + serverName: string; connectionUri: string; upgradeExisting: boolean; sqlCmdVariables?: Record; @@ -16,6 +17,7 @@ export interface IPublishSettings { export interface IGenerateScriptSettings { databaseName: string; + serverName: string; connectionUri: string; sqlCmdVariables?: Record; deploymentOptions?: DeploymentOptions; diff --git a/extensions/sql-database-projects/src/models/dashboardData/dashboardData.ts b/extensions/sql-database-projects/src/models/dashboardData/dashboardData.ts index aaa52ce3ab..e802e50838 100644 --- a/extensions/sql-database-projects/src/models/dashboardData/dashboardData.ts +++ b/extensions/sql-database-projects/src/models/dashboardData/dashboardData.ts @@ -19,6 +19,17 @@ export class DashboardData { } } +export class PublishData extends DashboardData { + public targetServer: string; + public targetDatabase: string; + + constructor(projectFile: string, status: Status, target: string, startDate: string, targetDatabase: string, targetServer: string) { + super(projectFile, status, target, startDate); + this.targetDatabase = targetDatabase; + this.targetServer = targetServer; + } +} + export enum Status { success, failed, diff --git a/extensions/sql-database-projects/src/models/publishProfile/publishProfile.ts b/extensions/sql-database-projects/src/models/publishProfile/publishProfile.ts index d9a38589c0..5a4fd08dc6 100644 --- a/extensions/sql-database-projects/src/models/publishProfile/publishProfile.ts +++ b/extensions/sql-database-projects/src/models/publishProfile/publishProfile.ts @@ -16,6 +16,7 @@ import { SqlConnectionDataSource } from '../dataSources/sqlConnectionStringSourc // only reading db name, connection string, and SQLCMD vars from profile for now export interface PublishProfile { databaseName: string; + serverName: string; connectionId: string; connection: string; sqlCmdVariables: Record; @@ -45,6 +46,7 @@ export async function load(profileUri: Uri, dacfxService: mssql.IDacFxService): return { databaseName: targetDbName, + serverName: connectionInfo.server, connectionId: connectionInfo.connectionId, connection: connectionInfo.connection, sqlCmdVariables: sqlCmdVariables, @@ -52,14 +54,14 @@ export async function load(profileUri: Uri, dacfxService: mssql.IDacFxService): }; } -async function readConnectionString(xmlDoc: any): Promise<{ connectionId: string, connection: string }> { +async function readConnectionString(xmlDoc: any): Promise<{ connectionId: string, connection: string, server: string }> { let targetConnection: string = ''; let connId: string = ''; + let server: string = ''; if (xmlDoc.documentElement.getElementsByTagName(constants.targetConnectionString).length > 0) { const targetConnectionString = xmlDoc.documentElement.getElementsByTagName(constants.TargetConnectionString)[0].textContent; const dataSource = new SqlConnectionDataSource('', targetConnectionString); - let server: string = ''; let username: string = ''; const connectionProfile = dataSource.getConnectionProfile(); @@ -86,6 +88,7 @@ async function readConnectionString(xmlDoc: any): Promise<{ connectionId: string return { connectionId: connId, - connection: targetConnection + connection: targetConnection, + server: server }; } diff --git a/extensions/sql-database-projects/src/projectProvider/projectProvider.ts b/extensions/sql-database-projects/src/projectProvider/projectProvider.ts index 807de09aff..39a6f2ed24 100644 --- a/extensions/sql-database-projects/src/projectProvider/projectProvider.ts +++ b/extensions/sql-database-projects/src/projectProvider/projectProvider.ts @@ -127,27 +127,28 @@ export class SqlDatabaseProjectProvider implements dataworkspace.IProjectProvide * Gets the data to be displayed in the project dashboard */ getDashboardComponents(projectFile: string): dataworkspace.IDashboardTable[] { - const deployInfo: dataworkspace.IDashboardTable = { - name: constants.Deployments, - columns: [{ displayName: constants.ID, width: 100 }, - { displayName: constants.Status, width: 250, type: 'icon' }, - { displayName: constants.Target, width: 250 }, - { displayName: constants.Time, width: 250 }, - { displayName: constants.Date, width: 250 }], - data: this.projectController.getDashboardDeployData(projectFile) + const width = 200; + const publishInfo: dataworkspace.IDashboardTable = { + name: constants.PublishHistory, + columns: [{ displayName: constants.Status, width: width, type: 'icon' }, + { displayName: constants.Date, width: width }, + { displayName: constants.Time, width: width }, + { displayName: constants.TargetPlatform, width: width }, + { displayName: constants.TargetServer, width: width }, + { displayName: constants.TargetDatabase, width: width }], + data: this.projectController.getDashboardPublishData(projectFile) }; const buildInfo: dataworkspace.IDashboardTable = { - name: constants.Builds, - columns: [{ displayName: constants.ID, width: 100 }, - { displayName: constants.Status, width: 250, type: 'icon' }, - { displayName: constants.Target, width: 250 }, - { displayName: constants.Time, width: 250 }, - { displayName: constants.Date, width: 250 }], + name: constants.BuildHistory, + columns: [{ displayName: constants.Status, width: width, type: 'icon' }, + { displayName: constants.Date, width: width }, + { displayName: constants.Time, width: width }, + { displayName: constants.TargetPlatform, width: width }], data: this.projectController.getDashboardBuildData(projectFile) }; - return [deployInfo, buildInfo]; + return [publishInfo, buildInfo]; } get image(): ThemedIconPath { diff --git a/extensions/sql-database-projects/src/test/dialogs/publishDatabaseDialog.test.ts b/extensions/sql-database-projects/src/test/dialogs/publishDatabaseDialog.test.ts index 43544739c8..3f19c7149a 100644 --- a/extensions/sql-database-projects/src/test/dialogs/publishDatabaseDialog.test.ts +++ b/extensions/sql-database-projects/src/test/dialogs/publishDatabaseDialog.test.ts @@ -67,12 +67,14 @@ describe('Publish Database Dialog', () => { dialog.setup(x => x.getTargetDatabaseName()).returns(() => 'MockDatabaseName'); dialog.setup(x => x.getSqlCmdVariablesForPublish()).returns(() => proj.sqlCmdVariables); dialog.setup(x => x.getDeploymentOptions()).returns(() => { return Promise.resolve(mockDacFxOptionsResult.deploymentOptions); }); + dialog.setup(x => x.getServerName()).returns(() => 'MockServer'); dialog.callBase = true; let profile: IPublishSettings | IGenerateScriptSettings | undefined; const expectedPublish: IPublishSettings = { databaseName: 'MockDatabaseName', + serverName: 'MockServer', connectionUri: 'Mock|Connection|Uri', upgradeExisting: true, sqlCmdVariables: { @@ -90,6 +92,7 @@ describe('Publish Database Dialog', () => { const expectedGenScript: IGenerateScriptSettings = { databaseName: 'MockDatabaseName', + serverName: 'MockServer', connectionUri: 'Mock|Connection|Uri', sqlCmdVariables: { 'ProdDatabaseName': 'MyProdDatabase', diff --git a/extensions/sql-database-projects/src/test/projectController.test.ts b/extensions/sql-database-projects/src/test/projectController.test.ts index 026882b2ef..45866d752f 100644 --- a/extensions/sql-database-projects/src/test/projectController.test.ts +++ b/extensions/sql-database-projects/src/test/projectController.test.ts @@ -411,7 +411,7 @@ describe('ProjectsController', function (): void { const proj = await testUtils.createTestProject(baselines.openProjectFileBaseline); - await projController.object.publishProjectCallback(proj, { connectionUri: '', databaseName: '' }); + await projController.object.publishProjectCallback(proj, { connectionUri: '', databaseName: '' , serverName: ''}); should(builtDacpacPath).not.equal('', 'built dacpac path should be set'); should(publishedDacpacPath).not.equal('', 'published dacpac path should be set');