mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Add VS Code native New Project create flow (#15906)
* Add VS Code native New Project create flow * Update project name title * Ignore focus out * comments * ellipsis
This commit is contained in:
@@ -15,7 +15,7 @@ export const AllProjectTypes = localize('AllProjectTypes', "All Project Types");
|
||||
export const ProviderNotFoundForProjectTypeError = (projectType: string): string => { return localize('UnknownProjectTypeError', "No provider was found for project type with id: '{0}'", projectType); };
|
||||
export const WorkspaceRequiredMessage = localize('dataworkspace.workspaceRequiredMessage', "A workspace is required in order to use the project feature.");
|
||||
export const OpenWorkspace = localize('dataworkspace.openWorkspace', "Open Workspace…");
|
||||
export const CreateWorkspaceConfirmation = localize('dataworkspace.createWorkspaceConfirmation', "A workspace will be created and opened in order to open project. Azure Data Studio will restart and if there is a folder currently open, it will be closed.");
|
||||
export const CreateWorkspaceConfirmation = localize('dataworkspace.createWorkspaceConfirmation', "A workspace will be created and opened in order to open the project. Azure Data Studio will restart and if there is a folder currently open, it will be closed.");
|
||||
export const EnterWorkspaceConfirmation = localize('dataworkspace.enterWorkspaceConfirmation', "To open this workspace, Azure Data Studio will restart. If there is a workspace or folder currently open, it will be closed.");
|
||||
export const WorkspaceContainsNotAddedProjects = localize('dataworkspace.workspaceContainsNotAddedProjects', "The current workspace contains one or more projects that have not been added to the workspace. Use the 'Open existing' dialog to add projects to the projects pane.");
|
||||
export const LaunchOpenExisitingDialog = localize('dataworkspace.launchOpenExistingDialog', "Launch 'Open Existing' Dialog");
|
||||
@@ -35,8 +35,10 @@ export const showNotAddedProjectsMessageKey = 'showNotAddedProjectsInWorkspacePr
|
||||
export const OkButtonText = localize('dataworkspace.ok', "OK");
|
||||
export const CancelButtonText = localize('dataworkspace.cancel', "Cancel");
|
||||
export const BrowseButtonText = localize('dataworkspace.browse', "Browse");
|
||||
export const BrowseEllipsis = localize('dataworkspace.browseEllipsis', "Browse...");
|
||||
export const OpenButtonText = localize('dataworkspace.open', "Open");
|
||||
export const CreateButtonText = localize('dataworkspace.create', "Create");
|
||||
export const Select = localize('dataworkspace.select', "Select");
|
||||
export const WorkspaceFileExtension = '.code-workspace';
|
||||
export const DefaultInputWidth = '400px';
|
||||
export const DefaultButtonWidth = '80px';
|
||||
@@ -46,6 +48,7 @@ export const NewProjectDialogTitle = localize('dataworkspace.NewProjectDialogTit
|
||||
export const TypeTitle = localize('dataworkspace.Type', "Type");
|
||||
export const ProjectNameTitle = localize('dataworkspace.projectNameTitle', "Name");
|
||||
export const ProjectNamePlaceholder = localize('dataworkspace.projectNamePlaceholder', "Enter project name");
|
||||
export const EnterProjectName = localize('dataworkspace.enterProjectName', "Enter Project Name");
|
||||
export const ProjectLocationTitle = localize('dataworkspace.projectLocationTitle', "Location");
|
||||
export const ProjectLocationPlaceholder = localize('dataworkspace.projectLocationPlaceholder', "Select location to create project");
|
||||
export const AddProjectToCurrentWorkspace = localize('dataworkspace.AddProjectToCurrentWorkspace', "This project will be added to the current workspace.");
|
||||
@@ -53,10 +56,13 @@ export const NewWorkspaceWillBeCreated = localize('dataworkspace.NewWorkspaceWil
|
||||
export const WorkspaceLocationTitle = localize('dataworkspace.workspaceLocationTitle', "Workspace location");
|
||||
export const ProjectParentDirectoryNotExistError = (location: string): string => { return localize('dataworkspace.projectParentDirectoryNotExistError', "The selected project location '{0}' does not exist or is not a directory.", location); };
|
||||
export const ProjectDirectoryAlreadyExistError = (projectName: string, location: string): string => { return localize('dataworkspace.projectDirectoryAlreadyExistError', "There is already a directory named '{0}' in the selected location: '{1}'.", projectName, location); };
|
||||
export const ProjectDirectoryAlreadyExistErrorShort = (projectName: string) => { return localize('dataworkspace.projectDirectoryAlreadyExistErrorShort', "Directory '{0}' already exists in the selected location, please choose another", projectName); };
|
||||
export const WorkspaceFileInvalidError = (workspace: string): string => { return localize('dataworkspace.workspaceFileInvalidError', "The selected workspace file path '{0}' does not have the required file extension {1}.", workspace, WorkspaceFileExtension); };
|
||||
export const WorkspaceParentDirectoryNotExistError = (location: string): string => { return localize('dataworkspace.workspaceParentDirectoryNotExistError', "The selected workspace location '{0}' does not exist or is not a directory.", location); };
|
||||
export const WorkspaceFileAlreadyExistsError = (file: string): string => { return localize('dataworkspace.workspaceFileAlreadyExistsError', "The selected workspace file '{0}' already exists. To add the project to an existing workspace, use the Open Existing dialog to first open the workspace.", file); };
|
||||
|
||||
export const SelectProjectType = localize('dataworkspace.selectProjectType', "Select Project Type");
|
||||
export const SelectProjectLocation = localize('dataworkspace.selectProjectLocation', "Select Project Location");
|
||||
export const NameCannotBeEmpty = localize('dataworkspace.nameCannotBeEmpty', "Name cannot be empty");
|
||||
//Open Existing Dialog
|
||||
export const OpenExistingDialogTitle = localize('dataworkspace.openExistingDialogTitle', "Open existing");
|
||||
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); };
|
||||
|
||||
84
extensions/data-workspace/src/dialogs/newProjectQuickpick.ts
Normal file
84
extensions/data-workspace/src/dialogs/newProjectQuickpick.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import * as constants from '../common/constants';
|
||||
import { directoryExist } from '../common/utils';
|
||||
import { defaultProjectSaveLocation } from '../common/projectLocationHelper';
|
||||
import { WorkspaceService } from '../services/workspaceService';
|
||||
|
||||
/**
|
||||
* Create flow for a New Project using only VS Code-native APIs such as QuickPick
|
||||
*/
|
||||
export async function createNewProjectWithQuickpick(workspaceService: WorkspaceService): Promise<void> {
|
||||
// Refresh list of project types
|
||||
const projectTypes = (await workspaceService.getAllProjectTypes()).map(projType => {
|
||||
return {
|
||||
label: projType.displayName,
|
||||
description: projType.description,
|
||||
id: projType.id
|
||||
} as vscode.QuickPickItem & { id: string };
|
||||
});
|
||||
|
||||
// 1. Prompt for project type
|
||||
const projectType = await vscode.window.showQuickPick(projectTypes, { title: constants.SelectProjectType, ignoreFocusOut: true });
|
||||
if (!projectType) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Prompt for project name
|
||||
const projectName = await vscode.window.showInputBox(
|
||||
{
|
||||
title: constants.EnterProjectName,
|
||||
validateInput: (value) => {
|
||||
return value ? undefined : constants.NameCannotBeEmpty;
|
||||
},
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
if (!projectName) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Prompt for Project location
|
||||
// Show quick pick with just browse option to give user context about what the file dialog is for (since that doesn't always have a title)
|
||||
const browseProjectLocation = await vscode.window.showQuickPick(
|
||||
[constants.BrowseEllipsis],
|
||||
{ title: constants.SelectProjectLocation, ignoreFocusOut: true });
|
||||
if (!browseProjectLocation) {
|
||||
return;
|
||||
}
|
||||
// We validate that the folder doesn't already exist, and if it does keep prompting them to pick a new one
|
||||
let valid = false;
|
||||
let projectLocation = '';
|
||||
while (!valid) {
|
||||
const locations = await vscode.window.showOpenDialog({
|
||||
canSelectFiles: false,
|
||||
canSelectFolders: true,
|
||||
canSelectMany: false,
|
||||
openLabel: constants.Select,
|
||||
title: constants.SelectProjectLocation,
|
||||
defaultUri: defaultProjectSaveLocation()
|
||||
});
|
||||
if (!locations) {
|
||||
return;
|
||||
}
|
||||
projectLocation = locations[0].fsPath;
|
||||
const exists = await directoryExist(path.join(projectLocation, projectName));
|
||||
if (exists) {
|
||||
// Show the browse quick pick again with the title updated with the error
|
||||
const browseProjectLocation = await vscode.window.showQuickPick(
|
||||
[constants.BrowseEllipsis],
|
||||
{ title: constants.ProjectDirectoryAlreadyExistErrorShort(projectName), ignoreFocusOut: true });
|
||||
if (!browseProjectLocation) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
await workspaceService.createProject(projectName, vscode.Uri.file(projectLocation), projectType.id, undefined);
|
||||
}
|
||||
@@ -13,11 +13,13 @@ import { OpenExistingDialog } from './dialogs/openExistingDialog';
|
||||
import { IWorkspaceService } from './common/interfaces';
|
||||
import { IconPathHelper } from './common/iconHelper';
|
||||
import { ProjectDashboard } from './dialogs/projectDashboard';
|
||||
import { getAzdataApi } from './common/utils';
|
||||
import { createNewProjectWithQuickpick } from './dialogs/newProjectQuickpick';
|
||||
|
||||
export async function activate(context: vscode.ExtensionContext): Promise<IExtension> {
|
||||
const workspaceService = new WorkspaceService(context);
|
||||
await workspaceService.loadTempProjects();
|
||||
await workspaceService.checkForProjectsNotAddedToWorkspace();
|
||||
workspaceService.checkForProjectsNotAddedToWorkspace();
|
||||
context.subscriptions.push(vscode.workspace.onDidChangeWorkspaceFolders(async () => {
|
||||
await workspaceService.checkForProjectsNotAddedToWorkspace();
|
||||
}));
|
||||
@@ -31,8 +33,13 @@ export async function activate(context: vscode.ExtensionContext): Promise<IExten
|
||||
setProjectProviderContextValue(workspaceService);
|
||||
|
||||
context.subscriptions.push(vscode.commands.registerCommand('projects.new', async () => {
|
||||
if (getAzdataApi()) {
|
||||
const dialog = new NewProjectDialog(workspaceService);
|
||||
await dialog.open();
|
||||
} else {
|
||||
await createNewProjectWithQuickpick(workspaceService);
|
||||
}
|
||||
|
||||
}));
|
||||
|
||||
context.subscriptions.push(vscode.commands.registerCommand('projects.openExisting', async () => {
|
||||
|
||||
@@ -49,17 +49,23 @@ export class WorkspaceService implements IWorkspaceService {
|
||||
* @param projectFileFsPath project to add to the workspace
|
||||
*/
|
||||
async CreateNewWorkspaceForProject(projectFileFsPath: string, workspaceFile: vscode.Uri | undefined): Promise<void> {
|
||||
// save temp project
|
||||
await this._context.globalState.update(TempProject, [projectFileFsPath]);
|
||||
|
||||
// create workspace
|
||||
const projectFolder = vscode.Uri.file(path.dirname(projectFileFsPath));
|
||||
|
||||
const azdataApi = getAzdataApi();
|
||||
if (azdataApi) {
|
||||
// save temp project
|
||||
await this._context.globalState.update(TempProject, [projectFileFsPath]);
|
||||
if (isCurrentWorkspaceUntitled()) {
|
||||
vscode.workspace.updateWorkspaceFolders(vscode.workspace.workspaceFolders!.length, null, { uri: projectFolder });
|
||||
await getAzdataApi()?.workspace.saveAndEnterWorkspace(workspaceFile!);
|
||||
await azdataApi.workspace.saveAndEnterWorkspace(workspaceFile!);
|
||||
} else {
|
||||
await getAzdataApi()?.workspace.createAndEnterWorkspace(projectFolder, workspaceFile);
|
||||
await azdataApi.workspace.createAndEnterWorkspace(projectFolder, workspaceFile);
|
||||
}
|
||||
} else {
|
||||
// In VS Code we don't have access to the workspace APIs exposed by ADS and so can't actually create a new saved workspace.
|
||||
// Instead we'll just always call this, which will either add it to the existing untitled workspace or create a new
|
||||
// untitled workspace which the user can then save later on as they wish.
|
||||
vscode.workspace.updateWorkspaceFolders(vscode.workspace.workspaceFolders?.length || 0, null, { uri: projectFolder });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user