diff --git a/extensions/data-workspace/package.json b/extensions/data-workspace/package.json index 0fc759fee4..195461d985 100644 --- a/extensions/data-workspace/package.json +++ b/extensions/data-workspace/package.json @@ -127,7 +127,7 @@ "view/item/context": [ { "command": "projects.manageProject", - "when": "view == dataworkspace.views.main", + "when": "view == dataworkspace.views.main && viewItem == databaseProject.itemType.project", "group": "0_projectsFirst@1" }, { diff --git a/extensions/data-workspace/src/dataworkspace.d.ts b/extensions/data-workspace/src/dataworkspace.d.ts index 34f324dc1a..78f2e11301 100644 --- a/extensions/data-workspace/src/dataworkspace.d.ts +++ b/extensions/data-workspace/src/dataworkspace.d.ts @@ -81,6 +81,11 @@ declare module 'dataworkspace' { * Gets the project data to be placed in the dashboard container */ readonly dashboardComponents: IDashboardTable[]; + + /** + * Gets the project image to be used as background in dashboard container + */ + readonly image?: azdata.ThemedIconPath; } /** @@ -110,7 +115,7 @@ declare module 'dataworkspace' { /** * Gets the icon path of the project type */ - readonly icon: string | vscode.Uri | { light: string | vscode.Uri, dark: string | vscode.Uri } + readonly icon: azdata.IconPath } /** @@ -178,7 +183,7 @@ declare module 'dataworkspace' { */ export interface IDashboardColumnInfo { displayName: string; - width: number; + width: number | string; type?: IDashboardColumnType; } diff --git a/extensions/data-workspace/src/dialogs/projectDashboard.ts b/extensions/data-workspace/src/dialogs/projectDashboard.ts index e4ad0924e1..a5fbda817a 100644 --- a/extensions/data-workspace/src/dialogs/projectDashboard.ts +++ b/extensions/data-workspace/src/dialogs/projectDashboard.ts @@ -106,8 +106,6 @@ export class ProjectDashboard { } private createContainer(title: string, location: string): azdata.FlexContainer { - const dashboardData: IDashboardTable[] = this.projectProvider!.dashboardComponents; - const rootContainer = this.modelView!.modelBuilder.flexContainer().withLayout( { flexFlow: 'column', @@ -115,23 +113,78 @@ export class ProjectDashboard { height: '100%' }).component(); + const headerContainer = this.createHeader(title, location); + const tableContainer = this.createTables(); + + rootContainer.addItem(headerContainer); + rootContainer.addItem(tableContainer); + + return rootContainer; + } + + /** + * Create header with title, location and background + */ + private createHeader(title: string, location: string): azdata.Component { + const headerContainer = this.modelView!.modelBuilder.flexContainer().withLayout( + { + flexFlow: 'column', + width: '100%', + height: '30%' + }).component(); + + const header = this.modelView!.modelBuilder.flexContainer().withLayout( + { + flexFlow: 'column', + width: '100%', + height: '30%' + }).component(); + const titleLabel = this.modelView!.modelBuilder.text() .withProperties({ value: title, CSSStyles: { 'margin-block-start': '20px', 'margin-block-end': '0px' } }) .component(); - rootContainer.addItem(titleLabel, { CSSStyles: { 'padding-left': '34px', 'padding-top': '15px', 'font-size': '36px', 'font-weight': '400' } }); + header.addItem(titleLabel, { CSSStyles: { 'padding-left': '34px', 'padding-top': '15px', 'font-size': '36px', 'font-weight': '400' } }); const projectFolderPath = path.dirname(location); const locationLabel = this.modelView!.modelBuilder.text() .withProperties({ value: projectFolderPath, CSSStyles: { 'margin-block-start': '20px', 'margin-block-end': '0px' } }) .component(); - rootContainer.addItem(locationLabel, { CSSStyles: { 'padding-left': '34px', 'padding-top': '15px', 'padding-bottom': '50px', 'font-size': '16px' } }); + header.addItem(locationLabel, { CSSStyles: { 'padding-left': '34px', 'padding-top': '15px', 'padding-bottom': '50px', 'font-size': '16px' } }); + + const image = this.projectProvider!.image; // background image added at the bottom right of the header + headerContainer.addItem(header, { + CSSStyles: { + 'background-image': `url(${vscode.Uri.file(image!.light.toString())})`, + 'background-repeat': 'no-repeat', + 'background-position': '85% bottom', + 'background-size': '10%', + 'border-bottom': 'solid 1px #ccc', + 'width': '100%', + 'height': '100%' + } + }); + + return headerContainer; + } + + /** + * Adds all the tables to the container + */ + private createTables(): azdata.Component { + const dashboardData: IDashboardTable[] = this.projectProvider!.dashboardComponents; + + const tableContainer = this.modelView!.modelBuilder.flexContainer().withLayout( + { + flexFlow: 'column', + width: '100%', + height: 'auto' + }).component(); - // Add all the tables to the container dashboardData.forEach(info => { const tableNameLabel = this.modelView!.modelBuilder.text() .withProperties({ value: info.name, CSSStyles: { 'margin-block-start': '30px', 'margin-block-end': '0px' } }) .component(); - rootContainer.addItem(tableNameLabel, { CSSStyles: { 'padding-left': '25px', 'padding-bottom': '20px', ...constants.cssStyles.title } }); + tableContainer.addItem(tableNameLabel, { CSSStyles: { 'padding-left': '25px', 'padding-bottom': '20px', ...constants.cssStyles.title } }); const columns: azdata.DeclarativeTableColumn[] = []; info.columns.forEach((column: IDashboardColumnInfo) => { @@ -180,9 +233,8 @@ export class ProjectDashboard { const table = this.modelView!.modelBuilder.declarativeTable() .withProperties({ columns: columns, dataValues: data, ariaLabel: info.name, CSSStyles: { 'margin-left': '30px' } }).component(); - rootContainer.addItem(table); + tableContainer.addItem(table); }); - - return rootContainer; + return tableContainer; } } diff --git a/extensions/sql-database-projects/images/dashboardSqlProj.svg b/extensions/sql-database-projects/images/dashboardSqlProj.svg new file mode 100644 index 0000000000..a79e1607ab --- /dev/null +++ b/extensions/sql-database-projects/images/dashboardSqlProj.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/sql-database-projects/src/common/iconHelper.ts b/extensions/sql-database-projects/src/common/iconHelper.ts index 456c76d7ca..6cd6585ac9 100644 --- a/extensions/sql-database-projects/src/common/iconHelper.ts +++ b/extensions/sql-database-projects/src/common/iconHelper.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; +import * as azdata from 'azdata'; export interface IconPath { dark: string; @@ -39,6 +40,8 @@ export class IconPathHelper { public static error: IconPath; public static inProgress: IconPath; + public static dashboardSqlProj: azdata.ThemedIconPath; + public static setExtensionContext(extensionContext: vscode.ExtensionContext) { IconPathHelper.extensionContext = extensionContext; @@ -68,6 +71,8 @@ export class IconPathHelper { IconPathHelper.success = IconPathHelper.makeIcon('success', true); IconPathHelper.error = IconPathHelper.makeIcon('error', true); IconPathHelper.inProgress = IconPathHelper.makeIcon('inProgress', true); + + IconPathHelper.dashboardSqlProj = IconPathHelper.makeIcon('dashboardSqlProj', true); } private static makeIcon(name: string, sameIcon: boolean = false) { diff --git a/extensions/sql-database-projects/src/projectProvider/projectProvider.ts b/extensions/sql-database-projects/src/projectProvider/projectProvider.ts index 0d5d517f29..78f40638e0 100644 --- a/extensions/sql-database-projects/src/projectProvider/projectProvider.ts +++ b/extensions/sql-database-projects/src/projectProvider/projectProvider.ts @@ -3,6 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { ThemedIconPath } from 'azdata'; import * as dataworkspace from 'dataworkspace'; import * as sqldbproj from 'sqldbproj'; import * as vscode from 'vscode'; @@ -130,24 +131,28 @@ export class SqlDatabaseProjectProvider implements dataworkspace.IProjectProvide get dashboardComponents(): dataworkspace.IDashboardTable[] { const deployInfo: dataworkspace.IDashboardTable = { name: constants.Deployments, - columns: [{ displayName: constants.ID, width: 75 }, - { displayName: constants.Status, width: 180, type: 'icon' }, - { displayName: constants.Target, width: 180 }, - { displayName: constants.Time, width: 180 }, - { displayName: constants.Date, width: 180 }], + 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.dashboardDeployData }; const buildInfo: dataworkspace.IDashboardTable = { name: constants.Builds, - columns: [{ displayName: constants.ID, width: 75 }, - { displayName: constants.Status, width: 180, type: 'icon' }, - { displayName: constants.Target, width: 180 }, - { displayName: constants.Time, width: 180 }, - { displayName: constants.Date, width: 180 }], + 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.dashboardBuildData }; return [deployInfo, buildInfo]; } + + get image(): ThemedIconPath { + return IconPathHelper.dashboardSqlProj; + } }