Data workspace projects changes (#13466)

* Fix project context menu actions (#12541)

* delete works again

* make fewer changes

* update all sql db project commands

* cleanup

* Remove old projects view (#12563)

* remove old projects view from file explorer view

* fix tests failing

* remove projects in open folder opening up in old view

* Update db reference dialog to show projects in the workspace (#12580)

* update database reference dialog to show projects in the workspace in the project dropdown

* remove workspace stuff from sql projects extension

* undo change

* add class that implements IExtension

* undo a change

* update DataWorkspaceExtension to take workspaceService as a parameter

* add type

* Update sql database project commands (#12595)

* remove sql proj's open and create new project from comman palette

* hook up create project from database to data workspace

* rename the remaining import databases to create project from database

* remove open, new, and close commands

* expose addProjectsToWorkspace() in IExtension instead of calling command

* Addressing comments

* fix failing sql project tests (#12651)

* update SSDT projects opened in projects viewlet (#12669)

* fix action not refreshing the tree issue (#12692)

* fix adding project references in new projects viewlet (#12688)

* Remove old projects tree provider (#12702)

* Remove old projects tree provider and fix tests

* formatting

* update refreshProjectsTree() to accept workspaceTreeItem()

* Cleanup ProjectsController (#12718)

* remove openProject from ProjectController and some cleanup

* rename

* add project and open project dialogs (#12729)

* empty dialogs

* wip

* new project dialog implementation

* revert gitattributes

* open project dialog

* implement add project

* remove icon helper

* refactor

* revert script change

* adjust views

* more updates

* make data-workspace a builtin extension

* show the view only when project provider is detected (#12819)

* only show the view when proj provider is available

* update

* fix sql project tests after merge (#12793)

* Update dialogs to be closer to mockups (#12879)

* small UI changes to dialogs

* center radio card group text

* Create workspace if needed when opening/new project (#12930)

* empty dialogs

* wip

* new project dialog implementation

* revert gitattributes

* open project dialog

* implement add project

* remove icon helper

* refactor

* revert script change

* create workspace

* initial changes

* create new workspace working

* fix tests

* cleanup

* remove showWorkspaceRequiredNotification()

* Add test for no workspace open

* update blue buttons

* move loading temp project to activate() instead of workspaceService constructor

* move workspace creation warning message to before project is created

* pass uri to createWorkspace

* add tests

Co-authored-by: Alan Ren <alanren@microsoft.com>

* Additional create workspace changes (#13004)

* Dialogs workspace updates (#13010)

* adding workspace text boxes

* match new project dialog to mockups

* Add validation error message for workspace file

* add enterWorkspace api

* add warning message for opening workspace

* cleanup

* update commands to remove project so they're more generic

* remove 'empty' from string

* Move default project location setting to data workspace extension (#13022)

* remove project location setting and notification from sql database projects extension

* add default project location setting to data workspace extension

* fix typo

* Add back project name incrementing

* other merge fixes

* fix strings from other PR

* default to last opened directory instead of home directory if no specified default location

* A few small updates (#13092)

* fix build error

* update title for inputboxes

* add missing file

* Add tests for data workspace dialogs (#13324)

* add tests for dialogs

* create helper functions

* New project dialog workspace inputbox fixes (#13407)

* workspace inputbox fixes

* fix folder icons

* Update package.jsons and readme (#13451)

* update package.jsons

* update readme

* add workspace information to open existing dialog (#13455)

Co-authored-by: Alan Ren <alanren@microsoft.com>
This commit is contained in:
Kim Santiago
2020-11-18 16:13:43 -08:00
committed by GitHub
parent 34170e7741
commit ddc8c00090
63 changed files with 1835 additions and 931 deletions

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import * as constants from '../common/constants';
import * as dataSources from '../models/dataSources/dataSources';
import * as mssql from '../../../mssql';
import * as os from 'os';
import * as path from 'path';
@@ -14,12 +13,13 @@ import * as templates from '../templates/templates';
import * as newProjectTool from '../tools/newProjectTool';
import * as vscode from 'vscode';
import * as azdata from 'azdata';
import * as dataworkspace from 'dataworkspace';
import { promises as fs } from 'fs';
import { PublishDatabaseDialog } from '../dialogs/publishDatabaseDialog';
import { Project, reservedProjectFolders, FileProjectEntry, SqlProjectReferenceProjectEntry, IDatabaseReferenceProjectEntry } from '../models/project';
import { SqlDatabaseProjectTreeViewProvider } from './databaseProjectTreeViewProvider';
import { FolderNode, FileNode, ExternalStreamingJobFileNode } from '../models/tree/fileFolderTreeItem';
import { FolderNode, FileNode } from '../models/tree/fileFolderTreeItem';
import { IPublishSettings, IGenerateScriptSettings } from '../models/IPublishSettings';
import { BaseProjectTreeItem } from '../models/tree/baseTreeItem';
import { ProjectRootTreeItem } from '../models/tree/projectTreeItem';
@@ -30,97 +30,24 @@ import { PublishProfile, load } from '../models/publishProfile/publishProfile';
import { AddDatabaseReferenceDialog } from '../dialogs/addDatabaseReferenceDialog';
import { ISystemDatabaseReferenceSettings, IDacpacReferenceSettings, IProjectReferenceSettings } from '../models/IDatabaseReferenceSettings';
import { DatabaseReferenceTreeItem } from '../models/tree/databaseReferencesTreeItem';
import { WorkspaceTreeItem } from 'dataworkspace';
/**
* Controller for managing project lifecycle
*/
export class ProjectsController {
private projectTreeViewProvider: SqlDatabaseProjectTreeViewProvider;
private netCoreTool: NetCoreTool;
private buildHelper: BuildHelper;
projects: Project[] = [];
projFileWatchers = new Map<string, vscode.FileSystemWatcher>();
constructor(projTreeViewProvider: SqlDatabaseProjectTreeViewProvider) {
this.projectTreeViewProvider = projTreeViewProvider;
constructor() {
this.netCoreTool = new NetCoreTool();
this.buildHelper = new BuildHelper();
}
public refreshProjectsTree() {
this.projectTreeViewProvider.load(this.projects);
}
public async openProject(projectFile: vscode.Uri, focusProject: boolean = true, isReferencedProject: boolean = false): Promise<Project> {
for (const proj of this.projects) {
if (proj.projectFilePath === projectFile.fsPath) {
if (!isReferencedProject) {
vscode.window.showInformationMessage(constants.projectAlreadyOpened(projectFile.fsPath));
return proj;
} else {
throw new Error(constants.projectAlreadyOpened(projectFile.fsPath));
}
}
}
let newProject: Project;
try {
// Read project file
newProject = await Project.openProject(projectFile.fsPath);
this.projects.push(newProject);
// open any reference projects (don't need to worry about circular dependencies because those aren't allowed)
const referencedProjects = newProject.databaseReferences.filter(r => r instanceof SqlProjectReferenceProjectEntry);
for (const proj of referencedProjects) {
const projUri = vscode.Uri.file(path.join(newProject.projectFolderPath, proj.fsUri.fsPath));
try {
await this.openProject(projUri, false, true);
} catch (e) {
}
}
// Update for round tripping as needed
await this.updateProjectForRoundTrip(newProject);
// Read datasources.json (if present)
const dataSourcesFilePath = path.join(path.dirname(projectFile.fsPath), constants.dataSourcesFileName);
try {
newProject.dataSources = await dataSources.load(dataSourcesFilePath);
}
catch (err) {
if (err instanceof dataSources.NoDataSourcesFileError) {
// TODO: prompt to create new datasources.json; for now, swallow
}
else {
throw err;
}
}
this.refreshProjectsTree();
if (focusProject) {
await this.focusProject(newProject);
}
}
catch (err) {
// if the project didnt load - remove it from the list of open projects
this.projects = this.projects.filter((e) => { return e !== newProject; });
throw err;
}
return newProject!;
}
public async focusProject(project?: Project): Promise<void> {
if (project && this.projects.includes(project)) {
await this.projectTreeViewProvider.focus(project);
await vscode.commands.executeCommand(constants.sqlDatabaseProjectsViewFocusCommand);
}
public refreshProjectsTree(workspaceTreeItem: dataworkspace.WorkspaceTreeItem): void {
(workspaceTreeItem.treeDataProvider as SqlDatabaseProjectTreeViewProvider).notifyTreeDataChanged();
}
/**
@@ -166,31 +93,19 @@ export class ProjectsController {
return newProjFilePath;
}
public closeProject(treeNode: BaseProjectTreeItem) {
const project = this.getProjectFromContext(treeNode);
this.projects = this.projects.filter((e) => { return e !== project; });
if (this.projFileWatchers.has(project.projectFilePath)) {
this.projFileWatchers.get(project.projectFilePath)!.dispose();
this.projFileWatchers.delete(project.projectFilePath);
}
this.refreshProjectsTree();
}
/**
* Builds a project, producing a dacpac
* @param treeNode a treeItem in a project's hierarchy, to be used to obtain a Project
* @returns path of the built dacpac
*/
public async buildProject(treeNode: BaseProjectTreeItem): Promise<string>;
public async buildProject(treeNode: dataworkspace.WorkspaceTreeItem): Promise<string>;
/**
* Builds a project, producing a dacpac
* @param project Project to be built
* @returns path of the built dacpac
*/
public async buildProject(project: Project): Promise<string>;
public async buildProject(context: Project | BaseProjectTreeItem | WorkspaceTreeItem): Promise<string | undefined> {
public async buildProject(context: Project | dataworkspace.WorkspaceTreeItem): Promise<string> {
const project: Project = this.getProjectFromContext(context);
// Check mssql extension for project dlls (tracking issue #10273)
@@ -208,7 +123,7 @@ export class ProjectsController {
}
catch (err) {
vscode.window.showErrorMessage(constants.projBuildFailed(utils.getErrorMessage(err)));
return undefined;
return '';
}
}
@@ -216,18 +131,18 @@ export class ProjectsController {
* Builds and publishes a project
* @param treeNode a treeItem in a project's hierarchy, to be used to obtain a Project
*/
public publishProject(treeNode: BaseProjectTreeItem): PublishDatabaseDialog;
public publishProject(treeNode: dataworkspace.WorkspaceTreeItem): PublishDatabaseDialog;
/**
* Builds and publishes a project
* @param project Project to be built and published
*/
public publishProject(project: Project): PublishDatabaseDialog;
public publishProject(context: Project | BaseProjectTreeItem): PublishDatabaseDialog {
public publishProject(context: Project | dataworkspace.WorkspaceTreeItem): PublishDatabaseDialog {
const project: Project = this.getProjectFromContext(context);
let publishDatabaseDialog = this.getPublishDialog(project);
publishDatabaseDialog.publish = async (proj, prof) => await this.executionCallback(proj, prof);
publishDatabaseDialog.generateScript = async (proj, prof) => await this.executionCallback(proj, prof);
publishDatabaseDialog.publish = async (proj, prof) => await this.publishProjectCallback(proj, prof);
publishDatabaseDialog.generateScript = async (proj, prof) => await this.publishProjectCallback(proj, prof);
publishDatabaseDialog.readPublishProfile = async (profileUri) => await this.readPublishProfileCallback(profileUri);
publishDatabaseDialog.openDialog();
@@ -235,7 +150,7 @@ export class ProjectsController {
return publishDatabaseDialog;
}
public async executionCallback(project: Project, settings: IPublishSettings | IGenerateScriptSettings): Promise<mssql.DacFxResult | undefined> {
public async publishProjectCallback(project: Project, settings: IPublishSettings | IGenerateScriptSettings): Promise<mssql.DacFxResult | undefined> {
const dacpacPath = await this.buildProject(project);
if (!dacpacPath) {
@@ -268,7 +183,7 @@ export class ProjectsController {
}
}
public async schemaCompare(treeNode: BaseProjectTreeItem): Promise<void> {
public async schemaCompare(treeNode: dataworkspace.WorkspaceTreeItem): Promise<void> {
// check if schema compare extension is installed
if (vscode.extensions.getExtension(constants.schemaCompareExtensionId)) {
// build project
@@ -285,9 +200,9 @@ export class ProjectsController {
}
}
public async addFolderPrompt(treeNode: BaseProjectTreeItem) {
public async addFolderPrompt(treeNode: dataworkspace.WorkspaceTreeItem): Promise<void> {
const project = this.getProjectFromContext(treeNode);
const relativePathToParent = this.getRelativePath(treeNode);
const relativePathToParent = this.getRelativePath(treeNode.element);
const absolutePathToParent = path.join(project.projectFolderPath, relativePathToParent);
const newFolderName = await this.promptForNewObjectName(new templates.ProjectScriptType(templates.folder, constants.folderFriendlyName, ''),
project, absolutePathToParent);
@@ -308,7 +223,7 @@ export class ProjectsController {
}
await project.addFolderItem(relativeFolderPath);
this.refreshProjectsTree();
this.refreshProjectsTree(treeNode);
} catch (err) {
vscode.window.showErrorMessage(utils.getErrorMessage(err));
}
@@ -320,11 +235,11 @@ export class ProjectsController {
return sameName && sameLocation;
}
public async addItemPromptFromNode(treeNode: BaseProjectTreeItem, itemTypeName?: string) {
await this.addItemPrompt(this.getProjectFromContext(treeNode), this.getRelativePath(treeNode), itemTypeName);
public async addItemPromptFromNode(treeNode: dataworkspace.WorkspaceTreeItem, itemTypeName?: string): Promise<void> {
await this.addItemPrompt(this.getProjectFromContext(treeNode), this.getRelativePath(treeNode.element), itemTypeName, treeNode.treeDataProvider as SqlDatabaseProjectTreeViewProvider);
}
public async addItemPrompt(project: Project, relativePath: string, itemTypeName?: string) {
public async addItemPrompt(project: Project, relativePath: string, itemTypeName?: string, treeDataProvider?: SqlDatabaseProjectTreeViewProvider): Promise<void> {
if (!itemTypeName) {
const items: vscode.QuickPickItem[] = [];
@@ -366,37 +281,38 @@ export class ProjectsController {
const newEntry = await project.addScriptItem(relativeFilePath, newFileText, itemType.type);
await vscode.commands.executeCommand(constants.vscodeOpenCommand, newEntry.fsUri);
this.refreshProjectsTree();
treeDataProvider?.notifyTreeDataChanged();
} catch (err) {
vscode.window.showErrorMessage(utils.getErrorMessage(err));
}
}
public async exclude(context: FileNode | FolderNode): Promise<void> {
const project = this.getProjectFromContext(context);
public async exclude(context: dataworkspace.WorkspaceTreeItem): Promise<void> {
const node = context.element as BaseProjectTreeItem;
const project = this.getProjectFromContext(node);
const fileEntry = this.getFileProjectEntry(project, context);
const fileEntry = this.getFileProjectEntry(project, node);
if (fileEntry) {
await project.exclude(fileEntry);
} else {
vscode.window.showErrorMessage(constants.unableToPerformAction(constants.excludeAction, context.uri.path));
vscode.window.showErrorMessage(constants.unableToPerformAction(constants.excludeAction, node.uri.path));
}
this.refreshProjectsTree();
this.refreshProjectsTree(context);
}
public async delete(context: BaseProjectTreeItem): Promise<void> {
const project = this.getProjectFromContext(context);
public async delete(context: dataworkspace.WorkspaceTreeItem): Promise<void> {
const node = context.element as BaseProjectTreeItem;
const project = this.getProjectFromContext(node);
let confirmationPrompt;
if (context instanceof DatabaseReferenceTreeItem) {
confirmationPrompt = constants.deleteReferenceConfirmation(context.friendlyName);
} else if (context instanceof FolderNode) {
confirmationPrompt = constants.deleteConfirmationContents(context.friendlyName);
if (node instanceof DatabaseReferenceTreeItem) {
confirmationPrompt = constants.deleteReferenceConfirmation(node.friendlyName);
} else if (node instanceof FolderNode) {
confirmationPrompt = constants.deleteConfirmationContents(node.friendlyName);
} else {
confirmationPrompt = constants.deleteConfirmation(context.friendlyName);
confirmationPrompt = constants.deleteConfirmation(node.friendlyName);
}
const response = await vscode.window.showWarningMessage(confirmationPrompt, { modal: true }, constants.yesString);
@@ -407,15 +323,15 @@ export class ProjectsController {
let success = false;
if (context instanceof DatabaseReferenceTreeItem) {
const databaseReference = this.getDatabaseReference(project, context);
if (node instanceof DatabaseReferenceTreeItem) {
const databaseReference = this.getDatabaseReference(project, node);
if (databaseReference) {
await project.deleteDatabaseReference(databaseReference);
success = true;
}
} else if (context instanceof FileNode || FolderNode) {
const fileEntry = this.getFileProjectEntry(project, context);
} else if (node instanceof FileNode || FolderNode) {
const fileEntry = this.getFileProjectEntry(project, node);
if (fileEntry) {
await project.deleteFileFolder(fileEntry);
@@ -424,9 +340,9 @@ export class ProjectsController {
}
if (success) {
this.refreshProjectsTree();
this.refreshProjectsTree(context);
} else {
vscode.window.showErrorMessage(constants.unableToPerformAction(constants.deleteAction, context.uri.path));
vscode.window.showErrorMessage(constants.unableToPerformAction(constants.deleteAction, node.uri.path));
}
}
@@ -457,7 +373,7 @@ export class ProjectsController {
* Opens the folder containing the project
* @param context a treeItem in a project's hierarchy, to be used to obtain a Project
*/
public async openContainingFolder(context: BaseProjectTreeItem): Promise<void> {
public async openContainingFolder(context: dataworkspace.WorkspaceTreeItem): Promise<void> {
const project = this.getProjectFromContext(context);
await vscode.commands.executeCommand(constants.revealFileInOsCommand, vscode.Uri.file(project.projectFilePath));
}
@@ -467,7 +383,7 @@ export class ProjectsController {
* reload their project.
* @param context a treeItem in a project's hierarchy, to be used to obtain a Project
*/
public async editProjectFile(context: BaseProjectTreeItem): Promise<void> {
public async editProjectFile(context: dataworkspace.WorkspaceTreeItem): Promise<void> {
const project = this.getProjectFromContext(context);
try {
@@ -475,11 +391,11 @@ export class ProjectsController {
const projFileWatcher: vscode.FileSystemWatcher = vscode.workspace.createFileSystemWatcher(project.projectFilePath);
this.projFileWatchers.set(project.projectFilePath, projFileWatcher);
projFileWatcher.onDidChange(async (projectFileUri: vscode.Uri) => {
projFileWatcher.onDidChange(async () => {
const result = await vscode.window.showInformationMessage(constants.reloadProject, constants.yesString, constants.noString);
if (result === constants.yesString) {
this.reloadProject(projectFileUri);
this.reloadProject(context);
}
});
@@ -500,12 +416,12 @@ export class ProjectsController {
* Reloads the given project. Throws an error if given project is not a valid open project.
* @param projectFileUri the uri of the project to be reloaded
*/
public async reloadProject(projectFileUri: vscode.Uri) {
const project = this.projects.find((e) => e.projectFilePath === projectFileUri.fsPath);
public async reloadProject(context: dataworkspace.WorkspaceTreeItem): Promise<void> {
const project = this.getProjectFromContext(context);
if (project) {
// won't open any newly referenced projects, but otherwise matches the behavior of reopening the project
await project.readProjFile();
this.refreshProjectsTree();
this.refreshProjectsTree(context);
} else {
throw new Error(constants.invalidProjectReload);
}
@@ -515,7 +431,7 @@ export class ProjectsController {
* Changes the project's DSP to the selected target platform
* @param context a treeItem in a project's hierarchy, to be used to obtain a Project
*/
public async changeTargetPlatform(context: Project | BaseProjectTreeItem): Promise<void> {
public async changeTargetPlatform(context: Project | dataworkspace.WorkspaceTreeItem): Promise<void> {
const project = this.getProjectFromContext(context);
const selectedTargetPlatform = (await vscode.window.showQuickPick((Array.from(constants.targetPlatformToVersion.keys())).map(version => { return { label: version }; }),
{
@@ -533,23 +449,24 @@ export class ProjectsController {
* Adds a database reference to the project
* @param context a treeItem in a project's hierarchy, to be used to obtain a Project
*/
public async addDatabaseReference(context: Project | BaseProjectTreeItem): Promise<AddDatabaseReferenceDialog> {
public async addDatabaseReference(context: Project | dataworkspace.WorkspaceTreeItem): Promise<AddDatabaseReferenceDialog> {
const project = this.getProjectFromContext(context);
const addDatabaseReferenceDialog = this.getAddDatabaseReferenceDialog(project);
addDatabaseReferenceDialog.addReference = async (proj, prof) => await this.addDatabaseReferenceCallback(proj, prof);
addDatabaseReferenceDialog.addReference = async (proj, prof) => await this.addDatabaseReferenceCallback(proj, prof, context as dataworkspace.WorkspaceTreeItem);
addDatabaseReferenceDialog.openDialog();
return addDatabaseReferenceDialog;
}
public async addDatabaseReferenceCallback(project: Project, settings: ISystemDatabaseReferenceSettings | IDacpacReferenceSettings | IProjectReferenceSettings): Promise<void> {
public async addDatabaseReferenceCallback(project: Project, settings: ISystemDatabaseReferenceSettings | IDacpacReferenceSettings | IProjectReferenceSettings, context: dataworkspace.WorkspaceTreeItem): Promise<void> {
try {
if ((<IProjectReferenceSettings>settings).projectName !== undefined) {
// get project path and guid
const projectReferenceSettings = settings as IProjectReferenceSettings;
const referencedProject = this.projects.find(p => p.projectFileName === projectReferenceSettings.projectName);
const workspaceProjects = await utils.getSqlProjectsInWorkspace();
const referencedProject = await Project.openProject(workspaceProjects.filter(p => path.parse(p.fsPath).name === projectReferenceSettings.projectName)[0].fsPath);
const relativePath = path.relative(project.projectFolderPath, referencedProject?.projectFilePath!);
projectReferenceSettings.projectRelativePath = vscode.Uri.file(relativePath);
projectReferenceSettings.projectGuid = referencedProject?.projectGuid!;
@@ -571,23 +488,64 @@ export class ProjectsController {
await project.addDatabaseReference(<IDacpacReferenceSettings>settings);
}
this.refreshProjectsTree();
this.refreshProjectsTree(context);
} catch (err) {
vscode.window.showErrorMessage(utils.getErrorMessage(err));
}
}
/**
* Creates a new SQL database project from the existing database,
* prompting the user for a name, file path location and extract target
*/
public async createProjectFromDatabase(context: azdata.IConnectionProfile | any): Promise<void> {
public async validateExternalStreamingJob(node: ExternalStreamingJobFileNode): Promise<mssql.ValidateStreamingJobResult> {
// TODO: Refactor code
try {
const workspaceApi = utils.getDataWorkspaceExtensionApi();
const model: ImportDataModel | undefined = await this.getModelFromContext(context);
if (!model) {
return; // cancelled by user
}
model.projName = await this.getProjectName(model.database);
let newProjFolderUri = (await this.getFolderLocation()).fsPath;
model.extractTarget = await this.getExtractTarget();
model.version = '1.0.0.0';
const newProjFilePath = await this.createNewProject(model.projName, vscode.Uri.file(newProjFolderUri), true);
model.filePath = path.dirname(newProjFilePath);
if (model.extractTarget === mssql.ExtractTarget.file) {
model.filePath = path.join(model.filePath, model.projName + '.sql'); // File extractTarget specifies the exact file rather than the containing folder
}
const project = await Project.openProject(newProjFilePath);
await this.createProjectFromDatabaseApiCall(model); // Call ExtractAPI in DacFx Service
let fileFolderList: string[] = model.extractTarget === mssql.ExtractTarget.file ? [model.filePath] : await this.generateList(model.filePath); // Create a list of all the files and directories to be added to project
await project.addToProject(fileFolderList); // Add generated file structure to the project
// add project to workspace
workspaceApi.showProjectsView();
await workspaceApi.addProjectsToWorkspace([vscode.Uri.file(newProjFilePath)]);
}
catch (err) {
vscode.window.showErrorMessage(utils.getErrorMessage(err));
}
}
public async validateExternalStreamingJob(node: dataworkspace.WorkspaceTreeItem): Promise<mssql.ValidateStreamingJobResult> {
const project: Project = this.getProjectFromContext(node);
let dacpacPath: string = project.dacpacOutputPath;
if (!await utils.exists(dacpacPath)) {
dacpacPath = await this.buildProject(node);
dacpacPath = await this.buildProject(project);
}
const streamingJobDefinition: string = (await fs.readFile(node.fileSystemUri.fsPath)).toString();
const streamingJobDefinition: string = (await fs.readFile(node.element.fileSystemUri.fsPath)).toString();
const dacFxService = await this.getDaxFxService();
const result: mssql.ValidateStreamingJobResult = await dacFxService.validateStreamingJob(dacpacPath, streamingJobDefinition);
@@ -631,9 +589,9 @@ export class ProjectsController {
}
}
private getProjectFromContext(context: Project | BaseProjectTreeItem | WorkspaceTreeItem): Project {
private getProjectFromContext(context: Project | BaseProjectTreeItem | dataworkspace.WorkspaceTreeItem): Project {
if ('element' in context) {
return context.element.project;
return context.element.root.project;
}
if (context instanceof Project) {
@@ -642,8 +600,7 @@ export class ProjectsController {
if (context.root instanceof ProjectRootTreeItem) {
return (<ProjectRootTreeItem>context.root).project;
}
else {
} else {
throw new Error(constants.unexpectedProjectContext(context.uri.path));
}
}
@@ -692,45 +649,6 @@ export class ProjectsController {
return treeNode instanceof FolderNode ? utils.trimUri(treeNode.root.uri, treeNode.uri) : '';
}
/**
* Imports a new SQL database project from the existing database,
* prompting the user for a name, file path location and extract target
*/
public async importNewDatabaseProject(context: azdata.IConnectionProfile | any): Promise<void> {
// TODO: Refactor code
try {
const model: ImportDataModel | undefined = await this.getModelFromContext(context);
if (!model) {
return; // cancelled by user
}
model.projName = await this.getProjectName(model.database);
let newProjFolderUri = (await this.getFolderLocation()).fsPath;
model.extractTarget = await this.getExtractTarget();
model.version = '1.0.0.0';
newProjectTool.updateSaveLocationSetting();
const newProjFilePath = await this.createNewProject(model.projName, vscode.Uri.file(newProjFolderUri), true);
model.filePath = path.dirname(newProjFilePath);
if (model.extractTarget === mssql.ExtractTarget.file) {
model.filePath = path.join(model.filePath, model.projName + '.sql'); // File extractTarget specifies the exact file rather than the containing folder
}
const project = await Project.openProject(newProjFilePath);
await this.importApiCall(model); // Call ExtractAPI in DacFx Service
let fileFolderList: string[] = model.extractTarget === mssql.ExtractTarget.file ? [model.filePath] : await this.generateList(model.filePath); // Create a list of all the files and directories to be added to project
await project.addToProject(fileFolderList); // Add generated file structure to the project
await this.openProject(vscode.Uri.file(newProjFilePath));
}
catch (err) {
vscode.window.showErrorMessage(utils.getErrorMessage(err));
}
}
public async getModelFromContext(context: any): Promise<ImportDataModel | undefined> {
let model = <ImportDataModel>{};
@@ -861,13 +779,13 @@ export class ProjectsController {
return projUri;
}
public async importApiCall(model: ImportDataModel): Promise<void> {
public async createProjectFromDatabaseApiCall(model: ImportDataModel): Promise<void> {
let ext = vscode.extensions.getExtension(mssql.extension.name)!;
const service = (await ext.activate() as mssql.IExtension).dacFx;
const ownerUri = await azdata.connection.getUriForConnection(model.serverId);
await service.importDatabaseProject(model.database, model.filePath, model.projName, model.version, ownerUri, model.extractTarget, azdata.TaskExecutionMode.execute);
await service.createProjectFromDatabase(model.database, model.filePath, model.projName, model.version, ownerUri, model.extractTarget, azdata.TaskExecutionMode.execute);
// TODO: Check for success; throw error
}