From 41bac47cbd6b11940781301f64e4718218ffebe0 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Thu, 1 Jul 2021 09:20:46 -0700 Subject: [PATCH] Add open existing project functionality for VS Code (#15958) --- .../data-workspace/src/common/constants.ts | 1 - .../src/dialogs/openExistingDialog.ts | 48 +++++++++---------- extensions/data-workspace/src/main.ts | 16 +++++-- .../src/services/workspaceService.ts | 2 +- .../test/dialogs/openExistingDialog.test.ts | 8 ++-- 5 files changed, 40 insertions(+), 35 deletions(-) diff --git a/extensions/data-workspace/src/common/constants.ts b/extensions/data-workspace/src/common/constants.ts index bb6b91d44a..1c7fb35f63 100644 --- a/extensions/data-workspace/src/common/constants.ts +++ b/extensions/data-workspace/src/common/constants.ts @@ -51,7 +51,6 @@ export const OpenExistingDialogTitle = localize('dataworkspace.openExistingDialo export const FileNotExistError = (fileType: string, filePath: string): string => { return localize('dataworkspace.fileNotExistError', "The selected {0} file '{1}' does not exist or is not a file.", fileType, filePath); }; export const CloneParentDirectoryNotExistError = (location: string): string => { return localize('dataworkspace.cloneParentDirectoryNotExistError', "The selected clone path '{0}' does not exist or is not a directory.", location); }; export const Project = localize('dataworkspace.project', "Project"); -export const Workspace = localize('dataworkspace.workspace', "Workspace"); export const LocationSelectorTitle = localize('dataworkspace.locationSelectorTitle', "Location"); export const ProjectFilePlaceholder = localize('dataworkspace.projectFilePlaceholder', "Select project file"); export const WorkspacePlaceholder = localize('dataworkspace.workspacePlaceholder', "Select workspace ({0}) file", WorkspaceFileExtension); diff --git a/extensions/data-workspace/src/dialogs/openExistingDialog.ts b/extensions/data-workspace/src/dialogs/openExistingDialog.ts index 401e3944b4..9c935817f6 100644 --- a/extensions/data-workspace/src/dialogs/openExistingDialog.ts +++ b/extensions/data-workspace/src/dialogs/openExistingDialog.ts @@ -207,9 +207,7 @@ export class OpenExistingDialog extends DialogBase { width: '18px', height: '16px' }).component(); - this.register(localProjectBrowseFolderButton.onDidClick(async () => { - await this.projectBrowse(); - })); + this.register(localProjectBrowseFolderButton.onDidClick(() => this.onBrowseButtonClick())); const flexContainer = this.createHorizontalContainer(view, [this.filePathTextBox, localProjectBrowseFolderButton]); flexContainer.updateCssStyles({ 'margin-top': '-10px' }); @@ -225,27 +223,29 @@ export class OpenExistingDialog extends DialogBase { this.initDialogComplete?.resolve(); } - public async projectBrowse(): Promise { - const filters: { [name: string]: string[] } = {}; - const projectTypes = await this.workspaceService.getAllProjectTypes(); - filters[constants.AllProjectTypes] = [...new Set(projectTypes.map(type => type.projectFileExtension))]; - projectTypes.forEach(type => { - filters[type.displayName] = [type.projectFileExtension]; - }); - - const fileUris = await vscode.window.showOpenDialog({ - canSelectFiles: true, - canSelectFolders: false, - canSelectMany: false, - openLabel: constants.SelectProjectFileActionName, - filters: filters - }); - - if (!fileUris || fileUris.length === 0) { - return; + public async onBrowseButtonClick(): Promise { + const projectFilePath = await browseForProject(this.workspaceService); + if (projectFilePath) { + this.filePathTextBox!.value = projectFilePath.fsPath; } - - const projectFilePath = fileUris[0].fsPath; - this.filePathTextBox!.value = projectFilePath; } } + +export async function browseForProject(workspaceService: IWorkspaceService): Promise { + const filters: { [name: string]: string[] } = {}; + const projectTypes = await workspaceService.getAllProjectTypes(); + filters[constants.AllProjectTypes] = [...new Set(projectTypes.map(type => type.projectFileExtension))]; + projectTypes.forEach(type => { + filters[type.displayName] = [type.projectFileExtension]; + }); + + const fileUris = await vscode.window.showOpenDialog({ + canSelectFiles: true, + canSelectFolders: false, + canSelectMany: false, + openLabel: constants.SelectProjectFileActionName, + filters: filters + }); + + return fileUris?.[0]; +} diff --git a/extensions/data-workspace/src/main.ts b/extensions/data-workspace/src/main.ts index 8e649d78fb..82ad3f71e8 100644 --- a/extensions/data-workspace/src/main.ts +++ b/extensions/data-workspace/src/main.ts @@ -9,7 +9,7 @@ import { WorkspaceService } from './services/workspaceService'; import { WorkspaceTreeItem, IExtension } from 'dataworkspace'; import { DataWorkspaceExtension } from './common/dataWorkspaceExtension'; import { NewProjectDialog } from './dialogs/newProjectDialog'; -import { OpenExistingDialog } from './dialogs/openExistingDialog'; +import { browseForProject, OpenExistingDialog } from './dialogs/openExistingDialog'; import { IWorkspaceService } from './common/interfaces'; import { IconPathHelper } from './common/iconHelper'; import { ProjectDashboard } from './dialogs/projectDashboard'; @@ -37,13 +37,19 @@ export async function activate(context: vscode.ExtensionContext): Promise { - const dialog = new OpenExistingDialog(workspaceService); - await dialog.open(); - + if (getAzdataApi()) { + const dialog = new OpenExistingDialog(workspaceService); + await dialog.open(); + } else { + const projectFileUri = await browseForProject(workspaceService); + if (!projectFileUri) { + return; + } + await workspaceService.addProjectsToWorkspace([projectFileUri]); + } })); context.subscriptions.push(vscode.commands.registerCommand('dataworkspace.refresh', () => { diff --git a/extensions/data-workspace/src/services/workspaceService.ts b/extensions/data-workspace/src/services/workspaceService.ts index a797862dda..90987640d2 100644 --- a/extensions/data-workspace/src/services/workspaceService.ts +++ b/extensions/data-workspace/src/services/workspaceService.ts @@ -143,7 +143,7 @@ export class WorkspaceService implements IWorkspaceService { const provider = ProjectProviderRegistry.getProviderByProjectType(projectTypeId); if (provider) { const projectFile = await provider.createProject(name, location, projectTypeId); - this.addProjectsToWorkspace([projectFile]); + await this.addProjectsToWorkspace([projectFile]); this._onDidWorkspaceProjectsChange.fire(); return projectFile; } else { diff --git a/extensions/data-workspace/src/test/dialogs/openExistingDialog.test.ts b/extensions/data-workspace/src/test/dialogs/openExistingDialog.test.ts index 1a7505fa88..1bdd2c9625 100644 --- a/extensions/data-workspace/src/test/dialogs/openExistingDialog.test.ts +++ b/extensions/data-workspace/src/test/dialogs/openExistingDialog.test.ts @@ -62,18 +62,18 @@ suite('Open Existing Dialog', function (): void { test('project browse', async function (): Promise { const workspaceServiceMock = TypeMoq.Mock.ofType(); workspaceServiceMock.setup(x => x.getAllProjectTypes()).returns(() => Promise.resolve([testProjectType])); - sinon.stub(vscode.window, 'showOpenDialog').returns(Promise.resolve([])); + const showOpenDialogStub = sinon.stub(vscode.window, 'showOpenDialog').returns(Promise.resolve([])); const dialog = new OpenExistingDialog(workspaceServiceMock.object); await dialog.open(); should.equal(dialog.filePathTextBox!.value ?? '', '', 'Project file should initially be empty'); - await dialog.projectBrowse(); + await dialog.onBrowseButtonClick(); should.equal(dialog.filePathTextBox!.value ?? '', '', 'Project file should not be set when no file is selected'); - sinon.restore(); + showOpenDialogStub.restore(); const projectFile = vscode.Uri.file(generateUniqueProjectFilePath('testproj')); sinon.stub(vscode.window, 'showOpenDialog').returns(Promise.resolve([projectFile])); - await dialog.projectBrowse(); + await dialog.onBrowseButtonClick(); should.equal(dialog.filePathTextBox!.value, projectFile.fsPath, 'Project file should be set'); }); });