mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-07 17:23:56 -05:00
Sql DB project dashboard (#14899)
* First set of changes for workspace dashboard implementing the toolbar * Workspace dashboard container implementation (#14813) * First set of changes for workspace dashboard implementing the toolbar (#14160) * First set of changes for workspace dashboard implementing the toolbar * Addressed comments * Addressed one remaining comment * Removed an extra comma in interfaces file * Addressed comments * Addressed comments * Refactored a bit of code * Remove unnecessary await * Addressed comments * First set of changes for workspace dashboard container * Update targetPlatform icon+add Time column to deploy table * Addressed comments * Removed redundant class definition * Addressed comments * Addressed comments * Change enum to union type in dataworkspace typings * Fix tests * Addressed comments
This commit is contained in:
@@ -21,6 +21,8 @@ export const WorkspaceContainsNotAddedProjects = localize('dataworkspace.workspa
|
||||
export const LaunchOpenExisitingDialog = localize('dataworkspace.launchOpenExistingDialog', "Launch Open existing dialog");
|
||||
export const DoNotShowAgain = localize('dataworkspace.doNotShowAgain', "Do not show again");
|
||||
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");
|
||||
|
||||
// config settings
|
||||
export const projectsConfigurationKey = 'projects';
|
||||
@@ -72,3 +74,9 @@ export const LocalClonePathPlaceholder = localize('dataworkspace.localClonePathP
|
||||
// Workspace settings for saving new projects
|
||||
export const ProjectConfigurationKey = 'projects';
|
||||
export const ProjectSaveLocationKey = 'defaultProjectSaveLocation';
|
||||
|
||||
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' };
|
||||
export const tableRow = { 'border-top': 'solid 1px #ccc', 'border-bottom': 'solid 1px #ccc', 'border-left': 'none', 'border-right': 'none' };
|
||||
}
|
||||
|
||||
82
extensions/data-workspace/src/dataworkspace.d.ts
vendored
82
extensions/data-workspace/src/dataworkspace.d.ts
vendored
@@ -4,6 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
declare module 'dataworkspace' {
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
export const enum extension {
|
||||
name = 'Microsoft.data-workspace'
|
||||
@@ -37,8 +38,8 @@ declare module 'dataworkspace' {
|
||||
defaultProjectSaveLocation: vscode.Uri | undefined;
|
||||
|
||||
/**
|
||||
* Verifies that a workspace is open or if it should be automatically created
|
||||
*/
|
||||
* Verifies that a workspace is open or if it should be automatically created
|
||||
*/
|
||||
validateWorkspace(): Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -70,6 +71,16 @@ declare module 'dataworkspace' {
|
||||
* Gets the supported project types
|
||||
*/
|
||||
readonly supportedProjectTypes: IProjectType[];
|
||||
|
||||
/**
|
||||
* Gets the project actions to be placed on the dashboard toolbar
|
||||
*/
|
||||
readonly projectActions: (IProjectAction | IProjectActionGroup)[];
|
||||
|
||||
/**
|
||||
* Gets the project data to be placed in the dashboard container
|
||||
*/
|
||||
readonly dashboardComponents: IDashboardTable[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,4 +127,71 @@ declare module 'dataworkspace' {
|
||||
*/
|
||||
element: any;
|
||||
}
|
||||
|
||||
export interface IProjectAction {
|
||||
/**
|
||||
* id of the project action
|
||||
*/
|
||||
readonly id: string;
|
||||
|
||||
/**
|
||||
* icon path of the project action
|
||||
*/
|
||||
readonly icon?: azdata.IconPath;
|
||||
|
||||
/**
|
||||
* Run context for each project action
|
||||
* @param treeItem The treeItem in a project's hierarchy, to be used to obtain a Project
|
||||
*/
|
||||
run(treeItem: WorkspaceTreeItem): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of project actions that should be grouped and have a separator after the last action
|
||||
*/
|
||||
export interface IProjectActionGroup {
|
||||
actions: IProjectAction[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines table to be presented in the dashboard container
|
||||
*/
|
||||
export interface IDashboardTable {
|
||||
/**
|
||||
* name of the table
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* column definitions
|
||||
*/
|
||||
columns: IDashboardColumnInfo[];
|
||||
|
||||
/**
|
||||
* project data
|
||||
*/
|
||||
data: (string | IconCellValue)[][];
|
||||
}
|
||||
|
||||
/**
|
||||
* Project dashboard table's column information
|
||||
*/
|
||||
export interface IDashboardColumnInfo {
|
||||
displayName: string;
|
||||
width: number;
|
||||
type?: IDashboardColumnType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cell value of an icon for the table data
|
||||
*/
|
||||
export interface IconCellValue {
|
||||
text: string;
|
||||
icon: azdata.IconPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Union type representing data types in dashboard table
|
||||
*/
|
||||
export type IDashboardColumnType = 'string' | 'icon';
|
||||
}
|
||||
|
||||
188
extensions/data-workspace/src/dialogs/projectDashboard.ts
Normal file
188
extensions/data-workspace/src/dialogs/projectDashboard.ts
Normal file
@@ -0,0 +1,188 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import { IDashboardColumnInfo, IDashboardTable, IProjectAction, IProjectActionGroup, IProjectProvider, WorkspaceTreeItem } from 'dataworkspace';
|
||||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import * as constants from '../common/constants';
|
||||
import { IWorkspaceService } from '../common/interfaces';
|
||||
import { fileExist } from '../common/utils';
|
||||
|
||||
export class ProjectDashboard {
|
||||
|
||||
private dashboard: azdata.window.ModelViewDashboard | undefined;
|
||||
private modelView: azdata.ModelView | undefined;
|
||||
private projectProvider: IProjectProvider | undefined;
|
||||
private overviewTab: azdata.DashboardTab | undefined;
|
||||
|
||||
constructor(private _workspaceService: IWorkspaceService, private _treeItem: WorkspaceTreeItem) {
|
||||
}
|
||||
|
||||
public async showDashboard(): Promise<void> {
|
||||
const project = this._treeItem.element.project;
|
||||
|
||||
if (!(await fileExist(project.projectFilePath))) {
|
||||
throw new Error(constants.fileDoesNotExist(project.projectFilePath));
|
||||
}
|
||||
|
||||
if (!project.projectFileName) {
|
||||
throw new Error(constants.projectNameNull);
|
||||
}
|
||||
|
||||
this.projectProvider = await this._workspaceService.getProjectProvider(vscode.Uri.file(project.projectFilePath));
|
||||
if (!this.projectProvider) {
|
||||
throw new Error(constants.ProviderNotFoundForProjectTypeError(project.projectFilePath));
|
||||
}
|
||||
|
||||
await this.createDashboard(project.projectFileName, project.projectFilePath);
|
||||
await this.dashboard!.open();
|
||||
}
|
||||
|
||||
private async createDashboard(title: string, location: string): Promise<void> {
|
||||
this.dashboard = azdata.window.createModelViewDashboard(title, 'ProjectDashboard', { alwaysShowTabs: false });
|
||||
this.dashboard.registerTabs(async (modelView: azdata.ModelView) => {
|
||||
this.modelView = modelView;
|
||||
|
||||
this.overviewTab = {
|
||||
title: '',
|
||||
id: 'overview-tab',
|
||||
content: this.createContainer(title, location),
|
||||
toolbar: this.createToolbarContainer()
|
||||
};
|
||||
return [
|
||||
this.overviewTab
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
private createToolbarContainer(): azdata.ToolbarContainer {
|
||||
const projectActions: (IProjectAction | IProjectActionGroup)[] = this.projectProvider!.projectActions;
|
||||
|
||||
// Add actions as buttons
|
||||
const buttons: azdata.ToolbarComponent[] = [];
|
||||
|
||||
const projectActionsLength = projectActions.length;
|
||||
|
||||
projectActions.forEach((action, actionIndex) => {
|
||||
if (this.isProjectAction(action)) {
|
||||
const button = this.createButton(action);
|
||||
buttons.push({ component: button });
|
||||
} 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
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return this.modelView!.modelBuilder.toolbarContainer()
|
||||
.withToolbarItems(
|
||||
buttons
|
||||
).component();
|
||||
}
|
||||
|
||||
private isProjectAction(obj: any): obj is IProjectAction {
|
||||
return obj.id !== undefined;
|
||||
}
|
||||
|
||||
private createButton(projectAction: IProjectAction): azdata.ButtonComponent {
|
||||
let button = this.modelView!.modelBuilder.button()
|
||||
.withProperties<azdata.ButtonProperties>({
|
||||
label: projectAction.id,
|
||||
iconPath: projectAction.icon,
|
||||
height: '20px'
|
||||
}).component();
|
||||
|
||||
button.onDidClick(async () => {
|
||||
await projectAction.run(this._treeItem);
|
||||
});
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
private createContainer(title: string, location: string): azdata.FlexContainer {
|
||||
const dashboardData: IDashboardTable[] = this.projectProvider!.dashboardComponents;
|
||||
|
||||
const rootContainer = this.modelView!.modelBuilder.flexContainer().withLayout(
|
||||
{
|
||||
flexFlow: 'column',
|
||||
width: '100%',
|
||||
height: '100%'
|
||||
}).component();
|
||||
|
||||
const titleLabel = this.modelView!.modelBuilder.text()
|
||||
.withProperties<azdata.TextComponentProperties>({ 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' } });
|
||||
|
||||
const projectFolderPath = path.dirname(location);
|
||||
const locationLabel = this.modelView!.modelBuilder.text()
|
||||
.withProperties<azdata.TextComponentProperties>({ 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' } });
|
||||
|
||||
// Add all the tables to the container
|
||||
dashboardData.forEach(info => {
|
||||
const tableNameLabel = this.modelView!.modelBuilder.text()
|
||||
.withProperties<azdata.TextComponentProperties>({ 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 } });
|
||||
|
||||
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<azdata.ImageComponentProperties>({
|
||||
iconPath: val.icon,
|
||||
width: '15px',
|
||||
height: '15px',
|
||||
iconHeight: '15px',
|
||||
iconWidth: '15px'
|
||||
}).component();
|
||||
const stringComponent = this.modelView!.modelBuilder.text().withProperties<azdata.TextComponentProperties>({
|
||||
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 });
|
||||
}
|
||||
});
|
||||
data.push(columnValue);
|
||||
});
|
||||
|
||||
const table = this.modelView!.modelBuilder.declarativeTable()
|
||||
.withProperties<azdata.DeclarativeTableProperties>({ columns: columns, dataValues: data, ariaLabel: info.name, CSSStyles: { 'margin-left': '30px' } }).component();
|
||||
|
||||
rootContainer.addItem(table);
|
||||
});
|
||||
|
||||
return rootContainer;
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import { NewProjectDialog } from './dialogs/newProjectDialog';
|
||||
import { OpenExistingDialog } from './dialogs/openExistingDialog';
|
||||
import { IWorkspaceService } from './common/interfaces';
|
||||
import { IconPathHelper } from './common/iconHelper';
|
||||
import { ProjectDashboard } from './dialogs/projectDashboard';
|
||||
|
||||
export function activate(context: vscode.ExtensionContext): Promise<IExtension> {
|
||||
const workspaceService = new WorkspaceService(context);
|
||||
@@ -51,6 +52,10 @@ export function activate(context: vscode.ExtensionContext): Promise<IExtension>
|
||||
context.subscriptions.push(vscode.commands.registerCommand('projects.removeProject', async (treeItem: WorkspaceTreeItem) => {
|
||||
await workspaceService.removeProject(vscode.Uri.file(treeItem.element.project.projectFilePath));
|
||||
}));
|
||||
context.subscriptions.push(vscode.commands.registerCommand('projects.manageProject', async (treeItem: WorkspaceTreeItem) => {
|
||||
const dashboard = new ProjectDashboard(workspaceService, treeItem);
|
||||
await dashboard.showDashboard();
|
||||
}));
|
||||
|
||||
IconPathHelper.setExtensionContext(context);
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IDashboardTable, IProjectAction, IProjectProvider, IProjectType } from 'dataworkspace';
|
||||
import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import * as should from 'should';
|
||||
import * as vscode from 'vscode';
|
||||
import { ProjectProviderRegistry } from '../common/projectProviderRegistry';
|
||||
import { IProjectProvider, IProjectType } from 'dataworkspace';
|
||||
|
||||
export class MockTreeDataProvider implements vscode.TreeDataProvider<any>{
|
||||
onDidChangeTreeData?: vscode.Event<any> | undefined;
|
||||
@@ -19,7 +19,7 @@ export class MockTreeDataProvider implements vscode.TreeDataProvider<any>{
|
||||
}
|
||||
}
|
||||
|
||||
export function createProjectProvider(projectTypes: IProjectType[]): IProjectProvider {
|
||||
export function createProjectProvider(projectTypes: IProjectType[], projectActions: IProjectAction[], dashboardComponents: IDashboardTable[]): IProjectProvider {
|
||||
const treeDataProvider = new MockTreeDataProvider();
|
||||
const projectProvider: IProjectProvider = {
|
||||
supportedProjectTypes: projectTypes,
|
||||
@@ -31,7 +31,9 @@ export function createProjectProvider(projectTypes: IProjectType[]): IProjectPro
|
||||
},
|
||||
createProject: (name: string, location: vscode.Uri, projectTypeId: string): Promise<vscode.Uri> => {
|
||||
return Promise.resolve(location);
|
||||
}
|
||||
},
|
||||
projectActions: projectActions,
|
||||
dashboardComponents: dashboardComponents
|
||||
};
|
||||
return projectProvider;
|
||||
}
|
||||
@@ -52,7 +54,25 @@ suite('ProjectProviderRegistry Tests', function (): void {
|
||||
displayName: 'test project 1',
|
||||
description: ''
|
||||
}
|
||||
]);
|
||||
],
|
||||
[{
|
||||
id: 'testAction1',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
},
|
||||
{
|
||||
id: 'testAction2',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
}],
|
||||
[{
|
||||
name: 'tableInfo1',
|
||||
columns: [{ displayName: 'c1', width: 75, type: 'string' }],
|
||||
data: [['d1']]
|
||||
},
|
||||
{
|
||||
name: 'tableInfo2',
|
||||
columns: [{ displayName: 'c1', width: 75, type: 'string' }],
|
||||
data: [['d1']]
|
||||
}]);
|
||||
const provider2 = createProjectProvider([
|
||||
{
|
||||
id: 'sp1',
|
||||
@@ -61,7 +81,37 @@ suite('ProjectProviderRegistry Tests', function (): void {
|
||||
displayName: 'sql project',
|
||||
description: ''
|
||||
}
|
||||
]);
|
||||
],
|
||||
[{
|
||||
id: 'Add',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
},
|
||||
{
|
||||
id: 'Schema Compare',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
},
|
||||
{
|
||||
id: 'Build',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
},
|
||||
{
|
||||
id: 'Publish',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
},
|
||||
{
|
||||
id: 'Target Version',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
}],
|
||||
[{
|
||||
name: 'Deployments',
|
||||
columns: [{ displayName: 'c1', width: 75, type: 'string' }],
|
||||
data: [['d1']]
|
||||
},
|
||||
{
|
||||
name: 'Builds',
|
||||
columns: [{ displayName: 'c1', width: 75, type: 'string' }],
|
||||
data: [['d1']]
|
||||
}]);
|
||||
should.strictEqual(ProjectProviderRegistry.providers.length, 0, 'there should be no project provider at the beginning of the test');
|
||||
const disposable1 = ProjectProviderRegistry.registerProvider(provider1, 'test.testProvider');
|
||||
let providerResult = ProjectProviderRegistry.getProviderByProjectExtension('testproj');
|
||||
@@ -104,7 +154,16 @@ suite('ProjectProviderRegistry Tests', function (): void {
|
||||
displayName: 'test project',
|
||||
description: ''
|
||||
}
|
||||
]);
|
||||
],
|
||||
[{
|
||||
id: 'testAction1',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
}],
|
||||
[{
|
||||
name: 'tableInfo1',
|
||||
columns: [{ displayName: 'c1', width: 75, type: 'string' }],
|
||||
data: [['d1']]
|
||||
}]);
|
||||
should.strictEqual(ProjectProviderRegistry.providers.length, 0, 'there should be no project provider at the beginning of the test');
|
||||
ProjectProviderRegistry.registerProvider(provider, 'test.testProvider');
|
||||
should.strictEqual(ProjectProviderRegistry.providers.length, 1, 'there should be only one project provider at this time');
|
||||
|
||||
@@ -136,6 +136,28 @@ suite('WorkspaceService Tests', function (): void {
|
||||
icon: '',
|
||||
displayName: 'test project 1'
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
id: 'testAction1',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
},
|
||||
{
|
||||
id: 'testAction2',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
name: 'tableInfo1',
|
||||
columns: [{ displayName: 'c1', width: 75, type: 'string' }],
|
||||
data: [['d1']]
|
||||
},
|
||||
{
|
||||
name: 'tableInfo2',
|
||||
columns: [{ displayName: 'c1', width: 75, type: 'string' }],
|
||||
data: [['d1']]
|
||||
}
|
||||
]);
|
||||
const provider2 = createProjectProvider([
|
||||
{
|
||||
@@ -145,6 +167,40 @@ suite('WorkspaceService Tests', function (): void {
|
||||
icon: '',
|
||||
displayName: 'sql project'
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
id: 'Add',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
},
|
||||
{
|
||||
id: 'Schema Compare',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
},
|
||||
{
|
||||
id: 'Build',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
},
|
||||
{
|
||||
id: 'Publish',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
},
|
||||
{
|
||||
id: 'Target Version',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
name: 'Deployments',
|
||||
columns: [{ displayName: 'c1', width: 75, type: 'string' }],
|
||||
data: [['d1']]
|
||||
},
|
||||
{
|
||||
name: 'Builds',
|
||||
columns: [{ displayName: 'c1', width: 75, type: 'string' }],
|
||||
data: [['d1']]
|
||||
}
|
||||
]);
|
||||
sinon.stub(ProjectProviderRegistry, 'providers').value([provider1, provider2]);
|
||||
const consoleErrorStub = sinon.stub(console, 'error');
|
||||
@@ -178,7 +234,37 @@ suite('WorkspaceService Tests', function (): void {
|
||||
icon: '',
|
||||
displayName: 'test project'
|
||||
}
|
||||
]));
|
||||
],
|
||||
[{
|
||||
id: 'Add',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
},
|
||||
{
|
||||
id: 'Schema Compare',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
},
|
||||
{
|
||||
id: 'Build',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
},
|
||||
{
|
||||
id: 'Publish',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
},
|
||||
{
|
||||
id: 'Target Version',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
}],
|
||||
[{
|
||||
name: 'Deployments',
|
||||
columns: [{ displayName: 'c1', width: 75, type: 'string' }],
|
||||
data: [['d1']]
|
||||
},
|
||||
{
|
||||
name: 'Builds',
|
||||
columns: [{ displayName: 'c1', width: 75, type: 'string' }],
|
||||
data: [['d1']]
|
||||
}]));
|
||||
let provider = await service.getProjectProvider(vscode.Uri.file('abc.sqlproj'));
|
||||
should.notStrictEqual(provider, undefined, 'Provider should be returned for sqlproj');
|
||||
should.strictEqual(provider!.supportedProjectTypes[0].projectFileExtension, 'sqlproj');
|
||||
@@ -193,7 +279,16 @@ suite('WorkspaceService Tests', function (): void {
|
||||
projectFileExtension: 'csproj',
|
||||
icon: '',
|
||||
displayName: 'test cs project'
|
||||
}]));
|
||||
}],
|
||||
[{
|
||||
id: 'testAction2',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
}],
|
||||
[{
|
||||
name: 'tableInfo2',
|
||||
columns: [{ displayName: 'c1', width: 75, type: 'string' }],
|
||||
data: [['d1']]
|
||||
}]));
|
||||
provider = await service.getProjectProvider(vscode.Uri.file('abc.csproj'));
|
||||
should.notStrictEqual(provider, undefined, 'Provider should be returned for csproj');
|
||||
should.strictEqual(provider!.supportedProjectTypes[0].projectFileExtension, 'csproj');
|
||||
@@ -324,7 +419,7 @@ suite('WorkspaceService Tests', function (): void {
|
||||
await vscode.workspace.getConfiguration(constants.projectsConfigurationKey).update(constants.showNotAddedProjectsMessageKey, true, true);
|
||||
|
||||
sinon.stub(service, 'getProjectsInWorkspace').returns([vscode.Uri.file('abc.sqlproj'), vscode.Uri.file('folder1/abc1.sqlproj')]);
|
||||
sinon.stub(vscode.workspace, 'workspaceFolders').value([{uri: vscode.Uri.file('.')}]);
|
||||
sinon.stub(vscode.workspace, 'workspaceFolders').value([{ uri: vscode.Uri.file('.') }]);
|
||||
sinon.stub(service, 'getAllProjectTypes').resolves([{
|
||||
projectFileExtension: 'sqlproj',
|
||||
id: 'sql project',
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IProjectProvider, WorkspaceTreeItem } from 'dataworkspace';
|
||||
import 'mocha';
|
||||
import * as sinon from 'sinon';
|
||||
import * as vscode from 'vscode';
|
||||
import * as should from 'should';
|
||||
import * as sinon from 'sinon';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import * as vscode from 'vscode';
|
||||
import { WorkspaceTreeDataProvider } from '../common/workspaceTreeDataProvider';
|
||||
import { WorkspaceService } from '../services/workspaceService';
|
||||
import { IProjectProvider, WorkspaceTreeItem } from 'dataworkspace';
|
||||
import { MockTreeDataProvider } from './projectProviderRegistry.test';
|
||||
|
||||
interface ExtensionGlobalMemento extends vscode.Memento {
|
||||
@@ -90,7 +90,37 @@ suite('workspaceTreeDataProvider Tests', function (): void {
|
||||
},
|
||||
createProject: (name: string, location: vscode.Uri): Promise<vscode.Uri> => {
|
||||
return Promise.resolve(location);
|
||||
}
|
||||
},
|
||||
projectActions: [{
|
||||
id: 'Add',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
},
|
||||
{
|
||||
id: 'Schema Compare',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
},
|
||||
{
|
||||
id: 'Build',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
},
|
||||
{
|
||||
id: 'Publish',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
},
|
||||
{
|
||||
id: 'Target Version',
|
||||
run: async (): Promise<any> => { return Promise.resolve(); }
|
||||
}],
|
||||
dashboardComponents: [{
|
||||
name: 'Deployments',
|
||||
columns: [{ displayName: 'c1', width: 75, type: 'string' }],
|
||||
data: [['d1']]
|
||||
},
|
||||
{
|
||||
name: 'Builds',
|
||||
columns: [{ displayName: 'c1', width: 75, type: 'string' }],
|
||||
data: [['d1']]
|
||||
}]
|
||||
};
|
||||
const getProjectProviderStub = sinon.stub(workspaceService, 'getProjectProvider');
|
||||
getProjectProviderStub.onFirstCall().resolves(undefined);
|
||||
|
||||
Reference in New Issue
Block a user