Add Create Proj from DB to VS Code context menus (#16584)

* Add Create Proj from DB to VS Code context menus

* Fix error

* add comment

* use constant
This commit is contained in:
Charles Gagnon
2021-08-06 08:59:35 -07:00
committed by GitHub
parent e6f356accc
commit b8da94f9ef
5 changed files with 84 additions and 16 deletions

View File

@@ -351,6 +351,11 @@
"command": "sqlDatabaseProjects.openContainingFolder",
"when": "view == dataworkspace.views.main && viewItem == databaseProject.itemType.project",
"group": "9_dbProjectsLast@8"
},
{
"command": "sqlDatabaseProjects.createProjectFromDatabase",
"when": "!azdataAvailable && view == objectExplorer && viewItem =~ /^(disconnectedServer|Server|Database)$/",
"group": "sqldbproj@1"
}
],
"objectExplorer/item/context": [

View File

@@ -5,6 +5,7 @@
import type * as azdataType from 'azdata';
import * as vscode from 'vscode';
import * as vscodeMssql from 'vscode-mssql';
import * as templates from '../templates/templates';
import * as path from 'path';
@@ -50,7 +51,7 @@ export default class MainController implements vscode.Disposable {
vscode.commands.registerCommand('sqlDatabaseProjects.build', async (node: WorkspaceTreeItem) => { await this.projectsController.buildProject(node); });
vscode.commands.registerCommand('sqlDatabaseProjects.publish', async (node: WorkspaceTreeItem) => { this.projectsController.publishProject(node); });
vscode.commands.registerCommand('sqlDatabaseProjects.schemaCompare', async (node: WorkspaceTreeItem) => { await this.projectsController.schemaCompare(node); });
vscode.commands.registerCommand('sqlDatabaseProjects.createProjectFromDatabase', async (profile: azdataType.IConnectionProfile) => { await this.projectsController.createProjectFromDatabase(profile); });
vscode.commands.registerCommand('sqlDatabaseProjects.createProjectFromDatabase', async (context: azdataType.IConnectionProfile | vscodeMssql.ITreeNodeInfo | undefined) => { await this.projectsController.createProjectFromDatabase(context); });
vscode.commands.registerCommand('sqlDatabaseProjects.newScript', async (node: WorkspaceTreeItem) => { await this.projectsController.addItemPromptFromNode(node, templates.script); });
vscode.commands.registerCommand('sqlDatabaseProjects.newPreDeploymentScript', async (node: WorkspaceTreeItem) => { await this.projectsController.addItemPromptFromNode(node, templates.preDeployScript); });

View File

@@ -863,10 +863,10 @@ export class ProjectsController {
* 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: azdataType.IConnectionProfile | any): Promise<CreateProjectFromDatabaseDialog | undefined> {
public async createProjectFromDatabase(context: azdataType.IConnectionProfile | mssqlVscode.ITreeNodeInfo | undefined): Promise<CreateProjectFromDatabaseDialog | undefined> {
const profile = this.getConnectionProfileFromContext(context);
if (utils.getAzdataApi()) {
let createProjectFromDatabaseDialog = this.getCreateProjectFromDatabaseDialog(profile);
let createProjectFromDatabaseDialog = this.getCreateProjectFromDatabaseDialog(profile as azdataType.IConnectionProfile);
createProjectFromDatabaseDialog.createProjectFromDatabaseCallback = async (model) => await this.createProjectFromDatabaseCallback(model);
@@ -874,7 +874,15 @@ export class ProjectsController {
return createProjectFromDatabaseDialog;
} else {
const model = await createNewProjectFromDatabaseWithQuickpick();
if (context) {
// The profile we get from VS Code is for the overall server connection and isn't updated based on the database node
// the command was launched from like it is in ADS. So get the actual database name from the MSSQL extension and
// update the connection info here.
const treeNodeContext = context as mssqlVscode.ITreeNodeInfo;
const databaseName = (await utils.getVscodeMssqlApi()).getDatabaseNameFromTreeNode(treeNodeContext);
(profile as mssqlVscode.IConnectionInfo).database = databaseName;
}
const model = await createNewProjectFromDatabaseWithQuickpick(profile as mssqlVscode.IConnectionInfo);
if (model) {
await this.createProjectFromDatabaseCallback(model);
}
@@ -925,14 +933,14 @@ export class ProjectsController {
}
}
private getConnectionProfileFromContext(context: azdataType.IConnectionProfile | any): azdataType.IConnectionProfile | undefined {
private getConnectionProfileFromContext(context: azdataType.IConnectionProfile | mssqlVscode.ITreeNodeInfo | undefined): azdataType.IConnectionProfile | mssqlVscode.IConnectionInfo | undefined {
if (!context) {
return undefined;
}
// depending on where import new project is launched from, the connection profile could be passed as just
// the profile or it could be wrapped in another object
return (<any>context).connectionProfile ? (<any>context).connectionProfile : context;
return (<any>context)?.connectionProfile ?? (context as mssqlVscode.ITreeNodeInfo).connectionInfo ?? context;
}
public async createProjectFromDatabaseApiCall(model: ImportDataModel): Promise<void> {

View File

@@ -14,31 +14,48 @@ import { mapExtractTargetEnum } from './createProjectFromDatabaseDialog';
/**
* Create flow for a New Project using only VS Code-native APIs such as QuickPick
* @param connectionInfo Optional connection info to use instead of prompting the user for a connection
*/
export async function createNewProjectFromDatabaseWithQuickpick(): Promise<ImportDataModel | undefined> {
export async function createNewProjectFromDatabaseWithQuickpick(connectionInfo?: IConnectionInfo): Promise<ImportDataModel | undefined> {
const vscodeMssqlApi = await getVscodeMssqlApi();
// 1. Select connection
const vscodeMssqlApi = await getVscodeMssqlApi();
let connectionProfile: IConnectionInfo | undefined = undefined;
// Use passed in profile if we have one - otherwise prompt user to select one
let connectionProfile: IConnectionInfo | undefined = connectionInfo ?? await vscodeMssqlApi.promptForConnection(true);
if (!connectionProfile) {
// User cancelled
return undefined;
}
let connectionUri: string = '';
let dbs: string[] | undefined = undefined;
while (!dbs) {
connectionProfile = await vscodeMssqlApi.promptForConnection(true);
if (!connectionProfile) {
// User cancelled
return undefined;
}
// Get the list of databases now to validate that the connection is valid and re-prompt them if it isn't
try {
connectionUri = await vscodeMssqlApi.connect(connectionProfile);
dbs = (await vscodeMssqlApi.listDatabases(connectionUri))
.filter(db => !constants.systemDbs.includes(db)); // Filter out system dbs
} catch (err) {
// no-op, the mssql extension handles showing the error to the user. We'll just go
// back and prompt the user for a connection again
// The mssql extension handles showing the error to the user. Prompt the user
// for a new connection and then go and try getting the DBs again
connectionProfile = await vscodeMssqlApi.promptForConnection(true);
if (!connectionProfile) {
// User cancelled
return undefined;
}
}
}
// Move the database for the given connection up to the top
if (connectionProfile.database && connectionProfile.database !== constants.master) {
const index = dbs.indexOf(connectionProfile.database);
if (index >= 0) {
dbs.splice(index, 1);
}
dbs.unshift(connectionProfile.database);
}
// 2. Select database
const selectedDatabase = await vscode.window.showQuickPick(
dbs,

View File

@@ -4,6 +4,9 @@
*--------------------------------------------------------------------------------------------*/
declare module 'vscode-mssql' {
import * as vscode from 'vscode';
/**
* Covers defining what the vscode-mssql extension exports to other extensions
*
@@ -51,6 +54,15 @@ declare module 'vscode-mssql' {
* @returns The list of database names
*/
listDatabases(connectionUri: string): Promise<string[]>;
/**
* Gets the database name for the node - which is the database name of the connection for a server node, the database name
* for nodes at or under a database node or a default value if it's neither of those.
* @param node The node to get the database name of
* @returns The database name
*/
getDatabaseNameFromTreeNode(node: ITreeNodeInfo): string;
}
/**
@@ -490,4 +502,29 @@ declare module 'vscode-mssql' {
defaultDeploymentOptions: DeploymentOptions;
}
export interface ITreeNodeInfo extends vscode.TreeItem {
readonly connectionInfo: IConnectionInfo;
nodeType: string;
metadata: ObjectMetadata;
parentNode: ITreeNodeInfo;
}
export const enum MetadataType {
Table = 0,
View = 1,
SProc = 2,
Function = 3
}
export interface ObjectMetadata {
metadataType: MetadataType;
metadataTypeName: string;
urn: string;
name: string;
schema: string;
}
}