mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-14 01:25:37 -05:00
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:
@@ -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": [
|
||||
|
||||
@@ -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); });
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user