From addef2d5848442c3aacace8e5eaae4cb4a686d39 Mon Sep 17 00:00:00 2001 From: Sakshi Sharma <57200045+SakshiS-harma@users.noreply.github.com> Date: Wed, 7 Apr 2021 00:42:11 -0700 Subject: [PATCH] Add message when no history exists on projects dashboard (#15002) * Add message when no history exists on projects dashboard * Bump version for sql db projects * Update text, add refresh button * Remove commented code --- extensions/data-workspace/images/refresh.svg | 3 + .../data-workspace/src/common/constants.ts | 4 + .../data-workspace/src/common/iconHelper.ts | 2 + .../src/dialogs/projectDashboard.ts | 130 +++++++++++------- extensions/sql-database-projects/package.json | 4 +- 5 files changed, 89 insertions(+), 54 deletions(-) create mode 100644 extensions/data-workspace/images/refresh.svg diff --git a/extensions/data-workspace/images/refresh.svg b/extensions/data-workspace/images/refresh.svg new file mode 100644 index 0000000000..f03579110b --- /dev/null +++ b/extensions/data-workspace/images/refresh.svg @@ -0,0 +1,3 @@ + + + diff --git a/extensions/data-workspace/src/common/constants.ts b/extensions/data-workspace/src/common/constants.ts index ebb2731836..fbddd579c7 100644 --- a/extensions/data-workspace/src/common/constants.ts +++ b/extensions/data-workspace/src/common/constants.ts @@ -23,6 +23,7 @@ export const DoNotShowAgain = localize('dataworkspace.doNotShowAgain', "Do not s export const ProjectsFailedToLoad = localize('dataworkspace.projectsFailedToLoad', "Some projects failed to load. Please open console for more information"); export const fileDoesNotExist = (name: string): string => { return localize('fileDoesNotExist', "File '{0}' doesn't exist", name); }; export const projectNameNull = localize('projectNameNull', "Project name is null"); +export const noPreviousData = (tableName: string): string => { return localize('noPreviousData', "Prior {0} will appear here, please run to see the results.", tableName); }; // config settings export const projectsConfigurationKey = 'projects'; @@ -75,6 +76,9 @@ export const LocalClonePathPlaceholder = localize('dataworkspace.localClonePathP export const ProjectConfigurationKey = 'projects'; export const ProjectSaveLocationKey = 'defaultProjectSaveLocation'; +// Dashboard dialog +export const Refresh = localize('dataworksapce.refresh', 'Refresh'); + export namespace cssStyles { export const title = { 'font-size': '18px', 'font-weight': '600' }; export const tableHeader = { 'text-align': 'left', 'font-weight': '500', 'font-size': '13px', 'user-select': 'text' }; diff --git a/extensions/data-workspace/src/common/iconHelper.ts b/extensions/data-workspace/src/common/iconHelper.ts index eef61bb913..1d3b22a48f 100644 --- a/extensions/data-workspace/src/common/iconHelper.ts +++ b/extensions/data-workspace/src/common/iconHelper.ts @@ -13,11 +13,13 @@ export interface IconPath { export class IconPathHelper { private static extensionContext: vscode.ExtensionContext; public static folder: IconPath; + public static refresh: IconPath; public static setExtensionContext(extensionContext: vscode.ExtensionContext) { IconPathHelper.extensionContext = extensionContext; IconPathHelper.folder = IconPathHelper.makeIcon('folder', true); + IconPathHelper.refresh = IconPathHelper.makeIcon('refresh', true); } private static makeIcon(name: string, sameIcon: boolean = false) { diff --git a/extensions/data-workspace/src/dialogs/projectDashboard.ts b/extensions/data-workspace/src/dialogs/projectDashboard.ts index a5fbda817a..9280d526bd 100644 --- a/extensions/data-workspace/src/dialogs/projectDashboard.ts +++ b/extensions/data-workspace/src/dialogs/projectDashboard.ts @@ -8,6 +8,7 @@ import { IDashboardColumnInfo, IDashboardTable, IProjectAction, IProjectActionGr import * as path from 'path'; import * as vscode from 'vscode'; import * as constants from '../common/constants'; +import { IconPathHelper } from '../common/iconHelper'; import { IWorkspaceService } from '../common/interfaces'; import { fileExist } from '../common/utils'; @@ -17,6 +18,8 @@ export class ProjectDashboard { private modelView: azdata.ModelView | undefined; private projectProvider: IProjectProvider | undefined; private overviewTab: azdata.DashboardTab | undefined; + private rootContainer: azdata.FlexContainer | undefined; + private tableContainer: azdata.Component | undefined; constructor(private _workspaceService: IWorkspaceService, private _treeItem: WorkspaceTreeItem) { } @@ -69,17 +72,32 @@ export class ProjectDashboard { projectActions.forEach((action, actionIndex) => { if (this.isProjectAction(action)) { const button = this.createButton(action); - buttons.push({ component: button }); + buttons.push({ component: button, toolbarSeparatorAfter: (projectActionsLength - 1 === actionIndex) }); } else { const groupLength = action.actions.length; action.actions.forEach((groupAction, index) => { const button = this.createButton(groupAction); - buttons.push({ component: button, toolbarSeparatorAfter: ((groupLength - 1 === index) && (projectActionsLength - 1 !== actionIndex)) }); // Add toolbar separator at the end of the group, if the group is not the last in the list + buttons.push({ component: button, toolbarSeparatorAfter: ((groupLength - 1 === index) || (projectActionsLength - 1 === actionIndex)) }); // Add toolbar separator at the end of the group }); } }); + const refreshButton = this.modelView!.modelBuilder.button() + .withProperties({ + label: constants.Refresh, + iconPath: IconPathHelper.refresh, + height: '20px' + }).component(); + + refreshButton.onDidClick(() => { + this.rootContainer?.removeItem(this.tableContainer!); + this.tableContainer = this.createTables(); + this.rootContainer?.addItem(this.tableContainer); + }); + + buttons.push({ component: refreshButton }); + return this.modelView!.modelBuilder.toolbarContainer() .withToolbarItems( buttons @@ -106,7 +124,7 @@ export class ProjectDashboard { } private createContainer(title: string, location: string): azdata.FlexContainer { - const rootContainer = this.modelView!.modelBuilder.flexContainer().withLayout( + this.rootContainer = this.modelView!.modelBuilder.flexContainer().withLayout( { flexFlow: 'column', width: '100%', @@ -114,12 +132,12 @@ export class ProjectDashboard { }).component(); const headerContainer = this.createHeader(title, location); - const tableContainer = this.createTables(); + this.tableContainer = this.createTables(); - rootContainer.addItem(headerContainer); - rootContainer.addItem(tableContainer); + this.rootContainer.addItem(headerContainer); + this.rootContainer.addItem(this.tableContainer); - return rootContainer; + return this.rootContainer; } /** @@ -186,54 +204,62 @@ export class ProjectDashboard { .component(); tableContainer.addItem(tableNameLabel, { CSSStyles: { 'padding-left': '25px', 'padding-bottom': '20px', ...constants.cssStyles.title } }); - const columns: azdata.DeclarativeTableColumn[] = []; - info.columns.forEach((column: IDashboardColumnInfo) => { - let col = { - displayName: column.displayName, - valueType: column.type === 'icon' ? azdata.DeclarativeDataType.component : azdata.DeclarativeDataType.string, - isReadOnly: true, - width: column.width, - headerCssStyles: { - 'border': 'none', - ...constants.cssStyles.tableHeader - }, - rowCssStyles: { - ...constants.cssStyles.tableRow - }, - }; - columns.push(col); - }); - - const data: azdata.DeclarativeTableCellValue[][] = []; - info.data.forEach(values => { - const columnValue: azdata.DeclarativeTableCellValue[] = []; - values.forEach(val => { - if (typeof val === 'string') { - columnValue.push({ value: val }); - } else { - const iconComponent = this.modelView!.modelBuilder.image().withProperties({ - iconPath: val.icon, - width: '15px', - height: '15px', - iconHeight: '15px', - iconWidth: '15px' - }).component(); - const stringComponent = this.modelView!.modelBuilder.text().withProperties({ - value: val.text, - CSSStyles: { 'margin-block-start': 'auto', 'block-size': 'auto', 'margin-block-end': '0px' } - }).component(); - - const columnData = this.modelView!.modelBuilder.flexContainer().withItems([iconComponent, stringComponent], { flex: '0 0 auto', CSSStyles: { 'margin-right': '10px' } }).withLayout({ flexFlow: 'row' }).component(); - columnValue.push({ value: columnData }); - } + if (info.data.length === 0) { + const noDataText = constants.noPreviousData(info.name.toLocaleLowerCase()); + const noDataLabel = this.modelView!.modelBuilder.text() + .withProperties({ value: noDataText }) + .component(); + tableContainer.addItem(noDataLabel, { CSSStyles: { 'padding-left': '25px', 'padding-bottom': '20px' } }); + } else { + const columns: azdata.DeclarativeTableColumn[] = []; + info.columns.forEach((column: IDashboardColumnInfo) => { + let col = { + displayName: column.displayName, + valueType: column.type === 'icon' ? azdata.DeclarativeDataType.component : azdata.DeclarativeDataType.string, + isReadOnly: true, + width: column.width, + headerCssStyles: { + 'border': 'none', + ...constants.cssStyles.tableHeader + }, + rowCssStyles: { + ...constants.cssStyles.tableRow + }, + }; + columns.push(col); }); - data.push(columnValue); - }); - const table = this.modelView!.modelBuilder.declarativeTable() - .withProperties({ columns: columns, dataValues: data, ariaLabel: info.name, CSSStyles: { 'margin-left': '30px' } }).component(); + const data: azdata.DeclarativeTableCellValue[][] = []; + info.data.forEach(values => { + const columnValue: azdata.DeclarativeTableCellValue[] = []; + values.forEach(val => { + if (typeof val === 'string') { + columnValue.push({ value: val }); + } else { + const iconComponent = this.modelView!.modelBuilder.image().withProperties({ + iconPath: val.icon, + width: '15px', + height: '15px', + iconHeight: '15px', + iconWidth: '15px' + }).component(); + const stringComponent = this.modelView!.modelBuilder.text().withProperties({ + value: val.text, + CSSStyles: { 'margin-block-start': 'auto', 'block-size': 'auto', 'margin-block-end': '0px' } + }).component(); - tableContainer.addItem(table); + const columnData = this.modelView!.modelBuilder.flexContainer().withItems([iconComponent, stringComponent], { flex: '0 0 auto', CSSStyles: { 'margin-right': '10px' } }).withLayout({ flexFlow: 'row' }).component(); + columnValue.push({ value: columnData }); + } + }); + data.push(columnValue); + }); + + const table = this.modelView!.modelBuilder.declarativeTable() + .withProperties({ columns: columns, dataValues: data, ariaLabel: info.name, CSSStyles: { 'margin-left': '30px' } }).component(); + + tableContainer.addItem(table); + } }); return tableContainer; } diff --git a/extensions/sql-database-projects/package.json b/extensions/sql-database-projects/package.json index 9c4c935ab5..1e9964d8d1 100644 --- a/extensions/sql-database-projects/package.json +++ b/extensions/sql-database-projects/package.json @@ -2,12 +2,12 @@ "name": "sql-database-projects", "displayName": "SQL Database Projects", "description": "The SQL Database Projects extension for Azure Data Studio allows users to develop and publish database schemas.", - "version": "0.8.0", + "version": "0.8.1", "publisher": "Microsoft", "preview": true, "engines": { "vscode": "^1.30.1", - "azdata": ">=1.27.0" + "azdata": ">=1.28.0" }, "license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt", "icon": "images/sqlDatabaseProjects.png",