From f01e9e2fc02e2e33d0d1b7c222a94f0049e6fe33 Mon Sep 17 00:00:00 2001 From: Kim Santiago <31145923+kisantia@users.noreply.github.com> Date: Tue, 27 Jul 2021 10:03:44 -0700 Subject: [PATCH] add api to open new project dialog with only one project type with filtered target platforms (#16315) --- .../src/common/dataWorkspaceExtension.ts | 8 ++++- .../data-workspace/src/dataworkspace.d.ts | 7 +++++ .../data-workspace/src/dialogs/dialogBase.ts | 4 +-- .../src/dialogs/newProjectDialog.ts | 31 ++++++++++++++++--- .../src/projectProvider/projectProvider.ts | 21 +++++++++++++ .../sql-database-projects/src/sqldbproj.d.ts | 7 +++++ 6 files changed, 71 insertions(+), 7 deletions(-) diff --git a/extensions/data-workspace/src/common/dataWorkspaceExtension.ts b/extensions/data-workspace/src/common/dataWorkspaceExtension.ts index fe0ff2e2a6..a0b672cc81 100644 --- a/extensions/data-workspace/src/common/dataWorkspaceExtension.ts +++ b/extensions/data-workspace/src/common/dataWorkspaceExtension.ts @@ -4,9 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { IExtension } from 'dataworkspace'; +import { IExtension, IProjectType } from 'dataworkspace'; import { WorkspaceService } from '../services/workspaceService'; import { defaultProjectSaveLocation } from './projectLocationHelper'; +import { openSpecificProjectNewProjectDialog } from '../dialogs/newProjectDialog'; export class DataWorkspaceExtension implements IExtension { constructor(private workspaceService: WorkspaceService) { @@ -31,4 +32,9 @@ export class DataWorkspaceExtension implements IExtension { validateWorkspace(): Promise { return this.workspaceService.validateWorkspace(); } + + openSpecificProjectNewProjectDialog(projectType: IProjectType): Promise { + return openSpecificProjectNewProjectDialog(projectType, this.workspaceService); + } + } diff --git a/extensions/data-workspace/src/dataworkspace.d.ts b/extensions/data-workspace/src/dataworkspace.d.ts index fa169736a3..63d876bc01 100644 --- a/extensions/data-workspace/src/dataworkspace.d.ts +++ b/extensions/data-workspace/src/dataworkspace.d.ts @@ -40,6 +40,13 @@ declare module 'dataworkspace' { * Verifies that a workspace is open or if it should be automatically created */ validateWorkspace(): Promise; + + /** + * Opens the new project dialog with only the specified project type + * @param projectType project type to open the dialog for + * @returns the uri of the created the project or undefined if no project was created + */ + openSpecificProjectNewProjectDialog(projectType: IProjectType): Promise; } /** diff --git a/extensions/data-workspace/src/dialogs/dialogBase.ts b/extensions/data-workspace/src/dialogs/dialogBase.ts index f4c0b1fa13..12e9bd1d04 100644 --- a/extensions/data-workspace/src/dialogs/dialogBase.ts +++ b/extensions/data-workspace/src/dialogs/dialogBase.ts @@ -7,7 +7,7 @@ import type * as azdataType from 'azdata'; import * as vscode from 'vscode'; import { getAzdataApi } from '../common/utils'; -interface Deferred { +export interface Deferred { resolve: (result: T | Promise) => void; reject: (reason: any) => void; } @@ -42,7 +42,7 @@ export abstract class DialogBase { await this.initDialogPromise; } - private onCancelButtonClicked(): void { + protected onCancelButtonClicked(): void { this.dispose(); } diff --git a/extensions/data-workspace/src/dialogs/newProjectDialog.ts b/extensions/data-workspace/src/dialogs/newProjectDialog.ts index 7284fc60c4..98857083aa 100644 --- a/extensions/data-workspace/src/dialogs/newProjectDialog.ts +++ b/extensions/data-workspace/src/dialogs/newProjectDialog.ts @@ -6,7 +6,7 @@ import type * as azdataType from 'azdata'; import * as vscode from 'vscode'; import * as path from 'path'; -import { DialogBase } from './dialogBase'; +import { Deferred, DialogBase } from './dialogBase'; import { IWorkspaceService } from '../common/interfaces'; import * as constants from '../common/constants'; import { IProjectType } from 'dataworkspace'; @@ -14,6 +14,7 @@ import { directoryExist } from '../common/utils'; import { IconPathHelper } from '../common/iconHelper'; import { defaultProjectSaveLocation } from '../common/projectLocationHelper'; import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/telemetry'; +import { WorkspaceService } from '../services/workspaceService'; class NewProjectDialogModel { projectTypeId: string = ''; @@ -23,12 +24,22 @@ class NewProjectDialogModel { targetPlatform?: string; } +export async function openSpecificProjectNewProjectDialog(projectType: IProjectType, workspaceService: WorkspaceService): Promise { + const dialog = new NewProjectDialog(workspaceService, projectType); + await dialog.open(); + await dialog.newDialogPromise; + return dialog.projectUri; +} + export class NewProjectDialog extends DialogBase { public model: NewProjectDialogModel = new NewProjectDialogModel(); public formBuilder: azdataType.FormBuilder | undefined; public targetPlatformDropdownFormComponent: azdataType.FormComponent | undefined; + public newProjectDialogComplete: Deferred | undefined; + public newDialogPromise: Promise = new Promise((resolve, reject) => this.newProjectDialogComplete = { resolve, reject }); + public projectUri: vscode.Uri | undefined; - constructor(private workspaceService: IWorkspaceService) { + constructor(private workspaceService: IWorkspaceService, private specificProjectType?: IProjectType) { super(constants.NewProjectDialogTitle, 'NewProject', constants.CreateButtonText); // dialog launched from Welcome message button (only visible when no current workspace) vs. "add project" button @@ -64,6 +75,11 @@ export class NewProjectDialog extends DialogBase { } } + override onCancelButtonClicked(): void { + this.newProjectDialogComplete?.resolve(); + this.dispose(); + } + override async onComplete(): Promise { try { @@ -71,7 +87,8 @@ export class NewProjectDialog extends DialogBase { .withAdditionalProperties({ projectFileExtension: this.model.projectFileExtension, projectTemplateId: this.model.projectTypeId }) .send(); - await this.workspaceService.createProject(this.model.name, vscode.Uri.file(this.model.location), this.model.projectTypeId, this.model.targetPlatform); + this.projectUri = await this.workspaceService.createProject(this.model.name, vscode.Uri.file(this.model.location), this.model.projectTypeId, this.model.targetPlatform); + this.newProjectDialogComplete?.resolve(); } catch (err) { @@ -84,7 +101,13 @@ export class NewProjectDialog extends DialogBase { } protected async initialize(view: azdataType.ModelView): Promise { - const allProjectTypes = await this.workspaceService.getAllProjectTypes(); + let allProjectTypes = await this.workspaceService.getAllProjectTypes(); + + // if a specific project type is specified, only show that one + if (this.specificProjectType && allProjectTypes.find(p => p.id === this.specificProjectType?.id)) { + allProjectTypes = [this.specificProjectType]; + } + const projectTypeRadioCardGroup = view.modelBuilder.radioCardGroup().withProps({ cards: allProjectTypes.map((projectType: IProjectType) => { return { diff --git a/extensions/sql-database-projects/src/projectProvider/projectProvider.ts b/extensions/sql-database-projects/src/projectProvider/projectProvider.ts index ce603569c4..3734f0c8bd 100644 --- a/extensions/sql-database-projects/src/projectProvider/projectProvider.ts +++ b/extensions/sql-database-projects/src/projectProvider/projectProvider.ts @@ -9,6 +9,7 @@ import * as sqldbproj from 'sqldbproj'; import * as vscode from 'vscode'; import * as constants from '../common/constants'; import { IconPathHelper } from '../common/iconHelper'; +import { getDataWorkspaceExtensionApi } from '../common/utils'; import { SqlDatabaseProjectTreeViewProvider } from '../controllers/databaseProjectTreeViewProvider'; import { ProjectsController } from '../controllers/projectController'; import { Project } from '../models/project'; @@ -147,4 +148,24 @@ export class SqlDatabaseProjectProvider implements dataworkspace.IProjectProvide get image(): ThemedIconPath { return IconPathHelper.dashboardSqlProj; } + + async openSqlNewProjectDialog(allowedTargetPlatforms?: sqldbproj.SqlTargetPlatform[]): Promise { + let targetPlatforms = Array.from(constants.targetPlatformToVersion.keys()); + if (allowedTargetPlatforms) { + targetPlatforms = targetPlatforms.filter(p => allowedTargetPlatforms.toString().includes(p)); + } + + const projectType: dataworkspace.IProjectType = { + id: constants.emptySqlDatabaseProjectTypeId, + projectFileExtension: constants.sqlprojExtension.replace(/\./g, ''), + displayName: constants.emptyProjectTypeDisplayName, + description: constants.emptyProjectTypeDescription, + icon: IconPathHelper.colorfulSqlProject, + targetPlatforms: targetPlatforms, + defaultTargetPlatform: constants.defaultTargetPlatform + }; + + const projectUri = getDataWorkspaceExtensionApi().openSpecificProjectNewProjectDialog(projectType); + return projectUri; + } } diff --git a/extensions/sql-database-projects/src/sqldbproj.d.ts b/extensions/sql-database-projects/src/sqldbproj.d.ts index d4e6b62f24..2ce03198b4 100644 --- a/extensions/sql-database-projects/src/sqldbproj.d.ts +++ b/extensions/sql-database-projects/src/sqldbproj.d.ts @@ -27,6 +27,13 @@ declare module 'sqldbproj' { * Opens and loads a .sqlproj file */ openProject(projectFilePath: string): Promise; + + /** + * Opens the data workspace new project dialog with only the sql database template + * @param allowedTargetPlatforms specific target platforms to allow. If not specified, all target platforms for sql will be listed + * @returns uri of the created the project or undefined if no project was created + */ + openSqlNewProjectDialog(allowedTargetPlatforms?: SqlTargetPlatform[]): Promise; } export interface ISqlProject {