mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
enable table designer for table script in sql database project (#19237)
* add 'open in designer' to context menu of tables in sql projects * fix tests * Address comments * enable table designer for sql database proj * update label and issues on init * vbump sts * use promisified fs * pr comments Co-authored-by: Alan Ren <alanren@microsoft.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
|
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
|
||||||
"version": "4.0.0.5",
|
"version": "4.0.0.9",
|
||||||
"downloadFileNames": {
|
"downloadFileNames": {
|
||||||
"Windows_86": "win-x86-net6.0.zip",
|
"Windows_86": "win-x86-net6.0.zip",
|
||||||
"Windows_64": "win-x64-net6.0.zip",
|
"Windows_64": "win-x64-net6.0.zip",
|
||||||
|
|||||||
@@ -9,13 +9,18 @@ import * as vscode from 'vscode';
|
|||||||
import { sqlProviderName } from '../constants';
|
import { sqlProviderName } from '../constants';
|
||||||
import { generateUuid } from 'vscode-languageclient/lib/utils/uuid';
|
import { generateUuid } from 'vscode-languageclient/lib/utils/uuid';
|
||||||
import { ITelemetryEventProperties, Telemetry } from '../telemetry';
|
import { ITelemetryEventProperties, Telemetry } from '../telemetry';
|
||||||
|
import * as nls from 'vscode-nls';
|
||||||
|
const localize = nls.loadMessageBundle();
|
||||||
|
|
||||||
|
const NewTableText = localize('tableDesigner.NewTable', "New Table");
|
||||||
export function registerTableDesignerCommands(appContext: AppContext) {
|
export function registerTableDesignerCommands(appContext: AppContext) {
|
||||||
appContext.extensionContext.subscriptions.push(vscode.commands.registerCommand('mssql.newTable', async (context: azdata.ObjectExplorerContext) => {
|
appContext.extensionContext.subscriptions.push(vscode.commands.registerCommand('mssql.newTable', async (context: azdata.ObjectExplorerContext) => {
|
||||||
const connectionString = await azdata.connection.getConnectionString(context.connectionProfile.id, true);
|
const connectionString = await azdata.connection.getConnectionString(context.connectionProfile.id, true);
|
||||||
const tableIcon = context.nodeInfo.nodeSubType as azdata.designers.TableIcon;
|
const tableIcon = context.nodeInfo.nodeSubType as azdata.designers.TableIcon;
|
||||||
const telemetryInfo = await getTelemetryInfo(context, tableIcon);
|
const telemetryInfo = await getTelemetryInfo(context, tableIcon);
|
||||||
await azdata.designers.openTableDesigner(sqlProviderName, {
|
await azdata.designers.openTableDesigner(sqlProviderName, {
|
||||||
|
title: NewTableText,
|
||||||
|
tooltip: `${context.connectionProfile.serverName} - ${context.connectionProfile.databaseName} - ${NewTableText}`,
|
||||||
server: context.connectionProfile.serverName,
|
server: context.connectionProfile.serverName,
|
||||||
database: context.connectionProfile.databaseName,
|
database: context.connectionProfile.databaseName,
|
||||||
isNewTable: true,
|
isNewTable: true,
|
||||||
@@ -35,6 +40,8 @@ export function registerTableDesignerCommands(appContext: AppContext) {
|
|||||||
const tableIcon = context.nodeInfo.nodeSubType as azdata.designers.TableIcon;
|
const tableIcon = context.nodeInfo.nodeSubType as azdata.designers.TableIcon;
|
||||||
const telemetryInfo = await getTelemetryInfo(context, tableIcon);
|
const telemetryInfo = await getTelemetryInfo(context, tableIcon);
|
||||||
await azdata.designers.openTableDesigner(sqlProviderName, {
|
await azdata.designers.openTableDesigner(sqlProviderName, {
|
||||||
|
title: `${schema}.${name}`,
|
||||||
|
tooltip: `${server} - ${database} - ${schema}.${name}`,
|
||||||
server: server,
|
server: server,
|
||||||
database: database,
|
database: database,
|
||||||
isNewTable: false,
|
isNewTable: false,
|
||||||
|
|||||||
@@ -190,6 +190,11 @@
|
|||||||
"command": "sqlDatabaseProjects.convertToSdkStyleProject",
|
"command": "sqlDatabaseProjects.convertToSdkStyleProject",
|
||||||
"title": "%sqlDatabaseProjects.convertToSdkStyleProject%",
|
"title": "%sqlDatabaseProjects.convertToSdkStyleProject%",
|
||||||
"category": "%sqlDatabaseProjects.displayName%"
|
"category": "%sqlDatabaseProjects.displayName%"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "sqlDatabaseProjects.openInDesigner",
|
||||||
|
"title": "%sqlDatabaseProjects.openInDesigner%",
|
||||||
|
"category": "%sqlDatabaseProjects.displayName%"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"menus": {
|
"menus": {
|
||||||
@@ -305,6 +310,10 @@
|
|||||||
{
|
{
|
||||||
"command": "sqlDatabaseProjects.convertToSdkStyleProject",
|
"command": "sqlDatabaseProjects.convertToSdkStyleProject",
|
||||||
"when": "false"
|
"when": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "sqlDatabaseProjects.openInDesigner",
|
||||||
|
"when": "false"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"view/item/context": [
|
"view/item/context": [
|
||||||
@@ -388,6 +397,11 @@
|
|||||||
"when": "view == dataworkspace.views.main && viewItem == databaseProject.itemType.file.externalStreamingJob",
|
"when": "view == dataworkspace.views.main && viewItem == databaseProject.itemType.file.externalStreamingJob",
|
||||||
"group": "5_dbProjects_streamingJob"
|
"group": "5_dbProjects_streamingJob"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "sqlDatabaseProjects.openInDesigner",
|
||||||
|
"when": "azdataAvailable && view == dataworkspace.views.main && viewItem == databaseProject.itemType.file.table && config.workbench.enablePreviewFeatures",
|
||||||
|
"group": "6_dbProjects_openInDesigner"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "sqlDatabaseProjects.exclude",
|
"command": "sqlDatabaseProjects.exclude",
|
||||||
"when": "view == dataworkspace.views.main && viewItem == databaseProject.itemType.folder || viewItem =~ /^databaseProject.itemType.file/",
|
"when": "view == dataworkspace.views.main && viewItem == databaseProject.itemType.folder || viewItem =~ /^databaseProject.itemType.file/",
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
"sqlDatabaseProjects.changeTargetPlatform": "Change Target Platform",
|
"sqlDatabaseProjects.changeTargetPlatform": "Change Target Platform",
|
||||||
"sqlDatabaseProjects.generateProjectFromOpenApiSpec": "Generate SQL Project from OpenAPI/Swagger spec",
|
"sqlDatabaseProjects.generateProjectFromOpenApiSpec": "Generate SQL Project from OpenAPI/Swagger spec",
|
||||||
"sqlDatabaseProjects.convertToSdkStyleProject": "Convert to SDK-style project",
|
"sqlDatabaseProjects.convertToSdkStyleProject": "Convert to SDK-style project",
|
||||||
|
"sqlDatabaseProjects.openInDesigner": "Open in Designer",
|
||||||
|
|
||||||
"sqlDatabaseProjects.Settings": "Database Projects",
|
"sqlDatabaseProjects.Settings": "Database Projects",
|
||||||
"sqlDatabaseProjects.dotnetInstallLocation": "Full path to .NET SDK on the machine.",
|
"sqlDatabaseProjects.dotnetInstallLocation": "Full path to .NET SDK on the machine.",
|
||||||
|
|||||||
@@ -529,6 +529,7 @@ export enum DatabaseProjectItemType {
|
|||||||
folder = 'databaseProject.itemType.folder',
|
folder = 'databaseProject.itemType.folder',
|
||||||
file = 'databaseProject.itemType.file',
|
file = 'databaseProject.itemType.file',
|
||||||
externalStreamingJob = 'databaseProject.itemType.file.externalStreamingJob',
|
externalStreamingJob = 'databaseProject.itemType.file.externalStreamingJob',
|
||||||
|
table = 'databaseProject.itemType.file.table',
|
||||||
referencesRoot = 'databaseProject.itemType.referencesRoot',
|
referencesRoot = 'databaseProject.itemType.referencesRoot',
|
||||||
reference = 'databaseProject.itemType.reference',
|
reference = 'databaseProject.itemType.reference',
|
||||||
dataSourceRoot = 'databaseProject.itemType.dataSourceRoot',
|
dataSourceRoot = 'databaseProject.itemType.dataSourceRoot',
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ import { WorkspaceTreeItem } from 'dataworkspace';
|
|||||||
import * as constants from '../common/constants';
|
import * as constants from '../common/constants';
|
||||||
import { SqlDatabaseProjectProvider } from '../projectProvider/projectProvider';
|
import { SqlDatabaseProjectProvider } from '../projectProvider/projectProvider';
|
||||||
import { GenerateProjectFromOpenApiSpecOptions, ItemType } from 'sqldbproj';
|
import { GenerateProjectFromOpenApiSpecOptions, ItemType } from 'sqldbproj';
|
||||||
|
import { TableFileNode } from '../models/tree/fileFolderTreeItem';
|
||||||
|
import { ProjectRootTreeItem } from '../models/tree/projectTreeItem';
|
||||||
|
import { getAzdataApi } from '../common/utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The main controller class that initializes the extension
|
* The main controller class that initializes the extension
|
||||||
@@ -56,35 +59,56 @@ export default class MainController implements vscode.Disposable {
|
|||||||
|
|
||||||
private async initializeDatabaseProjects(): Promise<void> {
|
private async initializeDatabaseProjects(): Promise<void> {
|
||||||
// init commands
|
// init commands
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.properties', async (node: WorkspaceTreeItem) => { return vscode.window.showErrorMessage(`Properties not yet implemented: ${node.element.uri.path}`); }); // TODO
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.properties', async (node: WorkspaceTreeItem) => { return vscode.window.showErrorMessage(`Properties not yet implemented: ${node.element.uri.path}`); })); // TODO
|
||||||
|
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.build', async (node: WorkspaceTreeItem) => { return this.projectsController.buildProject(node); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.build', async (node: WorkspaceTreeItem) => { return this.projectsController.buildProject(node); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.publish', async (node: WorkspaceTreeItem) => { return this.projectsController.publishProject(node); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.publish', async (node: WorkspaceTreeItem) => { return this.projectsController.publishProject(node); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.schemaCompare', async (node: WorkspaceTreeItem) => { return this.projectsController.schemaCompare(node); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.schemaCompare', async (node: WorkspaceTreeItem) => { return this.projectsController.schemaCompare(node); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.schemaComparePublishProjectChanges', async (operationId: string, projectFilePath: string, folderStructure: string): Promise<mssql.SchemaComparePublishProjectResult> => { return await this.projectsController.schemaComparePublishProjectChanges(operationId, projectFilePath, folderStructure); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.schemaComparePublishProjectChanges', async (operationId: string, projectFilePath: string, folderStructure: string): Promise<mssql.SchemaComparePublishProjectResult> => { return await this.projectsController.schemaComparePublishProjectChanges(operationId, projectFilePath, folderStructure); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.updateProjectFromDatabase', async (node: azdataType.IConnectionProfile | vscodeMssql.ITreeNodeInfo | WorkspaceTreeItem) => { await this.projectsController.updateProjectFromDatabase(node); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.updateProjectFromDatabase', async (node: azdataType.IConnectionProfile | vscodeMssql.ITreeNodeInfo | WorkspaceTreeItem) => { await this.projectsController.updateProjectFromDatabase(node); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.createProjectFromDatabase', async (context: azdataType.IConnectionProfile | vscodeMssql.ITreeNodeInfo | undefined) => { return this.projectsController.createProjectFromDatabase(context); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.createProjectFromDatabase', async (context: azdataType.IConnectionProfile | vscodeMssql.ITreeNodeInfo | undefined) => { return this.projectsController.createProjectFromDatabase(context); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.generateProjectFromOpenApiSpec', async (options?: GenerateProjectFromOpenApiSpecOptions) => { return this.projectsController.generateProjectFromOpenApiSpec(options); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.generateProjectFromOpenApiSpec', async (options?: GenerateProjectFromOpenApiSpecOptions) => { return this.projectsController.generateProjectFromOpenApiSpec(options); }));
|
||||||
|
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.newScript', async (node: WorkspaceTreeItem) => { return this.projectsController.addItemPromptFromNode(node, ItemType.script); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.newScript', async (node: WorkspaceTreeItem) => { return this.projectsController.addItemPromptFromNode(node, ItemType.script); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.newPreDeploymentScript', async (node: WorkspaceTreeItem) => { return this.projectsController.addItemPromptFromNode(node, ItemType.preDeployScript); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.newPreDeploymentScript', async (node: WorkspaceTreeItem) => { return this.projectsController.addItemPromptFromNode(node, ItemType.preDeployScript); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.newPostDeploymentScript', async (node: WorkspaceTreeItem) => { return this.projectsController.addItemPromptFromNode(node, ItemType.postDeployScript); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.newPostDeploymentScript', async (node: WorkspaceTreeItem) => { return this.projectsController.addItemPromptFromNode(node, ItemType.postDeployScript); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.newTable', async (node: WorkspaceTreeItem) => { return this.projectsController.addItemPromptFromNode(node, ItemType.table); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.newTable', async (node: WorkspaceTreeItem) => { return this.projectsController.addItemPromptFromNode(node, ItemType.table); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.newView', async (node: WorkspaceTreeItem) => { return this.projectsController.addItemPromptFromNode(node, ItemType.view); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.newView', async (node: WorkspaceTreeItem) => { return this.projectsController.addItemPromptFromNode(node, ItemType.view); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.newStoredProcedure', async (node: WorkspaceTreeItem) => { return this.projectsController.addItemPromptFromNode(node, ItemType.storedProcedure); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.newStoredProcedure', async (node: WorkspaceTreeItem) => { return this.projectsController.addItemPromptFromNode(node, ItemType.storedProcedure); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.newExternalStreamingJob', async (node: WorkspaceTreeItem) => { return this.projectsController.addItemPromptFromNode(node, ItemType.externalStreamingJob); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.newExternalStreamingJob', async (node: WorkspaceTreeItem) => { return this.projectsController.addItemPromptFromNode(node, ItemType.externalStreamingJob); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.newItem', async (node: WorkspaceTreeItem) => { return this.projectsController.addItemPromptFromNode(node); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.newItem', async (node: WorkspaceTreeItem) => { return this.projectsController.addItemPromptFromNode(node); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.addExistingItem', async (node: WorkspaceTreeItem) => { return this.projectsController.addExistingItemPrompt(node); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.addExistingItem', async (node: WorkspaceTreeItem) => { return this.projectsController.addExistingItemPrompt(node); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.newFolder', async (node: WorkspaceTreeItem) => { return this.projectsController.addFolderPrompt(node); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.newFolder', async (node: WorkspaceTreeItem) => { return this.projectsController.addFolderPrompt(node); }));
|
||||||
|
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.addDatabaseReference', async (node: WorkspaceTreeItem) => { return this.projectsController.addDatabaseReference(node); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.addDatabaseReference', async (node: WorkspaceTreeItem) => { return this.projectsController.addDatabaseReference(node); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.openContainingFolder', async (node: WorkspaceTreeItem) => { return this.projectsController.openContainingFolder(node); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.openContainingFolder', async (node: WorkspaceTreeItem) => { return this.projectsController.openContainingFolder(node); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.editProjectFile', async (node: WorkspaceTreeItem) => { return this.projectsController.editProjectFile(node); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.editProjectFile', async (node: WorkspaceTreeItem) => { return this.projectsController.editProjectFile(node); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.convertToSdkStyleProject', async (node: WorkspaceTreeItem) => { return this.projectsController.convertToSdkStyleProject(node); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.convertToSdkStyleProject', async (node: WorkspaceTreeItem) => { return this.projectsController.convertToSdkStyleProject(node); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.delete', async (node: WorkspaceTreeItem) => { return this.projectsController.delete(node); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.delete', async (node: WorkspaceTreeItem) => { return this.projectsController.delete(node); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.exclude', async (node: WorkspaceTreeItem) => { return this.projectsController.exclude(node); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.exclude', async (node: WorkspaceTreeItem) => { return this.projectsController.exclude(node); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.changeTargetPlatform', async (node: WorkspaceTreeItem) => { return this.projectsController.changeTargetPlatform(node); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.changeTargetPlatform', async (node: WorkspaceTreeItem) => { return this.projectsController.changeTargetPlatform(node); }));
|
||||||
vscode.commands.registerCommand('sqlDatabaseProjects.validateExternalStreamingJob', async (node: WorkspaceTreeItem) => { return this.projectsController.validateExternalStreamingJob(node); });
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.validateExternalStreamingJob', async (node: WorkspaceTreeItem) => { return this.projectsController.validateExternalStreamingJob(node); }));
|
||||||
|
this.context.subscriptions.push(vscode.commands.registerCommand('sqlDatabaseProjects.openInDesigner', async (node: WorkspaceTreeItem) => {
|
||||||
|
if (node?.element instanceof TableFileNode) {
|
||||||
|
const tableFileNode = node.element as TableFileNode;
|
||||||
|
const projectNode = tableFileNode.root as ProjectRootTreeItem;
|
||||||
|
const filePath = tableFileNode.fileSystemUri.fsPath;
|
||||||
|
const projectPath = projectNode.project.projectFilePath;
|
||||||
|
const targetVersion = projectNode.project.getProjectTargetVersion();
|
||||||
|
await getAzdataApi()!.designers.openTableDesigner('MSSQL', {
|
||||||
|
title: tableFileNode.friendlyName,
|
||||||
|
tooltip: `${projectPath} - ${tableFileNode.friendlyName}`,
|
||||||
|
id: filePath,
|
||||||
|
isNewTable: false,
|
||||||
|
tableScriptPath: filePath,
|
||||||
|
projectFilePath: projectPath,
|
||||||
|
allScripts: projectNode.project.files.map(entry => entry.fsUri.fsPath),
|
||||||
|
targetVersion: targetVersion
|
||||||
|
}, {
|
||||||
|
'ProjectTargetVersion': targetVersion
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
IconPathHelper.setExtensionContext(this.extensionContext);
|
IconPathHelper.setExtensionContext(this.extensionContext);
|
||||||
|
|
||||||
|
|||||||
@@ -245,10 +245,20 @@ export class Project implements ISqlProject {
|
|||||||
|
|
||||||
// create a FileProjectEntry for each file
|
// create a FileProjectEntry for each file
|
||||||
const fileEntries: FileProjectEntry[] = [];
|
const fileEntries: FileProjectEntry[] = [];
|
||||||
filesSet.forEach(f => {
|
for (let f of Array.from(filesSet.values())) {
|
||||||
const typeEntry = entriesWithType.find(e => e.relativePath === f);
|
const typeEntry = entriesWithType.find(e => e.relativePath === f);
|
||||||
fileEntries.push(this.createFileProjectEntry(f, EntryType.File, typeEntry ? typeEntry.typeAttribute : undefined));
|
let containsCreateTableStatement;
|
||||||
});
|
|
||||||
|
// read file to check if it has a "Create Table" statement
|
||||||
|
const fullPath = path.join(utils.getPlatformSafeFileEntryPath(this.projectFolderPath), utils.getPlatformSafeFileEntryPath(f));
|
||||||
|
|
||||||
|
if (await utils.exists(fullPath)) {
|
||||||
|
const fileContents = await fs.readFile(fullPath);
|
||||||
|
containsCreateTableStatement = fileContents.toString().toLowerCase().includes('create table');
|
||||||
|
}
|
||||||
|
|
||||||
|
fileEntries.push(this.createFileProjectEntry(f, EntryType.File, typeEntry ? typeEntry.typeAttribute : undefined, containsCreateTableStatement));
|
||||||
|
}
|
||||||
|
|
||||||
return fileEntries;
|
return fileEntries;
|
||||||
}
|
}
|
||||||
@@ -1078,13 +1088,14 @@ export class Project implements ISqlProject {
|
|||||||
return this.getCollectionProjectPropertyValue(constants.DatabaseSource);
|
return this.getCollectionProjectPropertyValue(constants.DatabaseSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
public createFileProjectEntry(relativePath: string, entryType: EntryType, sqlObjectType?: string): FileProjectEntry {
|
public createFileProjectEntry(relativePath: string, entryType: EntryType, sqlObjectType?: string, containsCreateTableStatement?: boolean): FileProjectEntry {
|
||||||
let platformSafeRelativePath = utils.getPlatformSafeFileEntryPath(relativePath);
|
let platformSafeRelativePath = utils.getPlatformSafeFileEntryPath(relativePath);
|
||||||
return new FileProjectEntry(
|
return new FileProjectEntry(
|
||||||
Uri.file(path.join(this.projectFolderPath, platformSafeRelativePath)),
|
Uri.file(path.join(this.projectFolderPath, platformSafeRelativePath)),
|
||||||
utils.convertSlashesForSqlProj(relativePath),
|
utils.convertSlashesForSqlProj(relativePath),
|
||||||
entryType,
|
entryType,
|
||||||
sqlObjectType);
|
sqlObjectType,
|
||||||
|
containsCreateTableStatement);
|
||||||
}
|
}
|
||||||
|
|
||||||
private findOrCreateItemGroup(containedTag?: string, prePostScriptExist?: { scriptExist: boolean; }): Element {
|
private findOrCreateItemGroup(containedTag?: string, prePostScriptExist?: { scriptExist: boolean; }): Element {
|
||||||
|
|||||||
@@ -27,12 +27,14 @@ export class FileProjectEntry extends ProjectEntry implements IFileProjectEntry
|
|||||||
fsUri: Uri;
|
fsUri: Uri;
|
||||||
relativePath: string;
|
relativePath: string;
|
||||||
sqlObjectType: string | undefined;
|
sqlObjectType: string | undefined;
|
||||||
|
containsCreateTableStatement: boolean | undefined;
|
||||||
|
|
||||||
constructor(uri: Uri, relativePath: string, entryType: EntryType, sqlObjectType?: string) {
|
constructor(uri: Uri, relativePath: string, entryType: EntryType, sqlObjectType?: string, containsCreateTableStatement?: boolean) {
|
||||||
super(entryType);
|
super(entryType);
|
||||||
this.fsUri = uri;
|
this.fsUri = uri;
|
||||||
this.relativePath = relativePath;
|
this.relativePath = relativePath;
|
||||||
this.sqlObjectType = sqlObjectType;
|
this.sqlObjectType = sqlObjectType;
|
||||||
|
this.containsCreateTableStatement = containsCreateTableStatement;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override toString(): string {
|
public override toString(): string {
|
||||||
|
|||||||
@@ -80,6 +80,15 @@ export class ExternalStreamingJobFileNode extends FileNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class TableFileNode extends FileNode {
|
||||||
|
public override get treeItem(): vscode.TreeItem {
|
||||||
|
const treeItem = super.treeItem;
|
||||||
|
treeItem.contextValue = DatabaseProjectItemType.table;
|
||||||
|
|
||||||
|
return treeItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares two folder/file tree nodes so that folders come before files, then alphabetically
|
* Compares two folder/file tree nodes so that folders come before files, then alphabetically
|
||||||
* @param a a folder or file tree node
|
* @param a a folder or file tree node
|
||||||
|
|||||||
@@ -80,6 +80,8 @@ export class ProjectRootTreeItem extends BaseProjectTreeItem {
|
|||||||
case EntryType.File:
|
case EntryType.File:
|
||||||
if (entry.sqlObjectType === ExternalStreamingJob) {
|
if (entry.sqlObjectType === ExternalStreamingJob) {
|
||||||
newNode = new fileTree.ExternalStreamingJobFileNode(entry.fsUri, parentNode);
|
newNode = new fileTree.ExternalStreamingJobFileNode(entry.fsUri, parentNode);
|
||||||
|
} else if (entry.containsCreateTableStatement) {
|
||||||
|
newNode = new fileTree.TableFileNode(entry.fsUri, parentNode);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
newNode = new fileTree.FileNode(entry.fsUri, parentNode);
|
newNode = new fileTree.FileNode(entry.fsUri, parentNode);
|
||||||
|
|||||||
66
src/sql/azdata.proposed.d.ts
vendored
66
src/sql/azdata.proposed.d.ts
vendored
@@ -735,29 +735,21 @@ declare module 'azdata' {
|
|||||||
*/
|
*/
|
||||||
export interface TableInfo {
|
export interface TableInfo {
|
||||||
/**
|
/**
|
||||||
* The server name.
|
* Used as the table designer editor's tab header text.
|
||||||
*/
|
*/
|
||||||
server: string;
|
title: string;
|
||||||
/**
|
/**
|
||||||
* The database name
|
* Used as the table designer editor's tab header hover text.
|
||||||
*/
|
*/
|
||||||
database: string;
|
tooltip: string;
|
||||||
/**
|
|
||||||
* The schema name, only required for existing table.
|
|
||||||
*/
|
|
||||||
schema?: string;
|
|
||||||
/**
|
|
||||||
* The table name, only required for existing table.
|
|
||||||
*/
|
|
||||||
name?: string;
|
|
||||||
/**
|
|
||||||
* A boolean value indicates whether a new table is being designed.
|
|
||||||
*/
|
|
||||||
isNewTable: boolean;
|
|
||||||
/**
|
/**
|
||||||
* Unique identifier of the table. Will be used to decide whether a designer is already opened for the table.
|
* Unique identifier of the table. Will be used to decide whether a designer is already opened for the table.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* A boolean value indicates whether a new table is being designed.
|
||||||
|
*/
|
||||||
|
isNewTable: boolean;
|
||||||
/**
|
/**
|
||||||
* Extension can store additional information that the provider needs to uniquely identify a table.
|
* Extension can store additional information that the provider needs to uniquely identify a table.
|
||||||
*/
|
*/
|
||||||
@@ -781,6 +773,14 @@ declare module 'azdata' {
|
|||||||
* The initial state of the designer.
|
* The initial state of the designer.
|
||||||
*/
|
*/
|
||||||
viewModel: DesignerViewModel;
|
viewModel: DesignerViewModel;
|
||||||
|
/**
|
||||||
|
* The new table info after initialization.
|
||||||
|
*/
|
||||||
|
tableInfo: TableInfo;
|
||||||
|
/**
|
||||||
|
* The issues.
|
||||||
|
*/
|
||||||
|
issues?: DesignerIssue[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -933,6 +933,10 @@ declare module 'azdata' {
|
|||||||
* Additional primary key properties. Common primary key properties: primaryKeyName, primaryKeyDescription.
|
* Additional primary key properties. Common primary key properties: primaryKeyName, primaryKeyDescription.
|
||||||
*/
|
*/
|
||||||
additionalPrimaryKeyProperties?: DesignerDataPropertyInfo[];
|
additionalPrimaryKeyProperties?: DesignerDataPropertyInfo[];
|
||||||
|
/**
|
||||||
|
* Whether to use advanced save mode. for advanced save mode, a publish changes dialog will be opened with preview of changes.
|
||||||
|
*/
|
||||||
|
useAdvancedSaveMode: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TableDesignerBuiltInTableViewOptions extends DesignerTablePropertiesBase {
|
export interface TableDesignerBuiltInTableViewOptions extends DesignerTablePropertiesBase {
|
||||||
@@ -1107,7 +1111,7 @@ declare module 'azdata' {
|
|||||||
/**
|
/**
|
||||||
* the path of the edit target.
|
* the path of the edit target.
|
||||||
*/
|
*/
|
||||||
path: DesignerEditPath;
|
path: DesignerPropertyPath;
|
||||||
/**
|
/**
|
||||||
* the new value.
|
* the new value.
|
||||||
*/
|
*/
|
||||||
@@ -1115,7 +1119,7 @@ declare module 'azdata' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The path of the edit target.
|
* The path of the property.
|
||||||
* Below are the 3 scenarios and their expected path.
|
* Below are the 3 scenarios and their expected path.
|
||||||
* Note: 'index-{x}' in the description below are numbers represent the index of the object in the list.
|
* Note: 'index-{x}' in the description below are numbers represent the index of the object in the list.
|
||||||
* 1. 'Add' scenario
|
* 1. 'Add' scenario
|
||||||
@@ -1129,7 +1133,7 @@ declare module 'azdata' {
|
|||||||
* a. ['propertyName1',index-1]. Example: remove a column from the columns property: ['columns',0'].
|
* a. ['propertyName1',index-1]. Example: remove a column from the columns property: ['columns',0'].
|
||||||
* b. ['propertyName1',index-1,'propertyName2',index-2]. Example: remove a column mapping from a foreign key's column mapping table: ['foreignKeys',0,'mappings',0].
|
* b. ['propertyName1',index-1,'propertyName2',index-2]. Example: remove a column mapping from a foreign key's column mapping table: ['foreignKeys',0,'mappings',0].
|
||||||
*/
|
*/
|
||||||
export type DesignerEditPath = (string | number)[];
|
export type DesignerPropertyPath = (string | number)[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Severity of the messages returned by the provider after processing an edit.
|
* Severity of the messages returned by the provider after processing an edit.
|
||||||
@@ -1139,6 +1143,28 @@ declare module 'azdata' {
|
|||||||
*/
|
*/
|
||||||
export type DesignerIssueSeverity = 'error' | 'warning' | 'information';
|
export type DesignerIssueSeverity = 'error' | 'warning' | 'information';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the issue in the designer
|
||||||
|
*/
|
||||||
|
export interface DesignerIssue {
|
||||||
|
/**
|
||||||
|
* Severity of the issue.
|
||||||
|
*/
|
||||||
|
severity: DesignerIssueSeverity,
|
||||||
|
/**
|
||||||
|
* Path of the property that is associated with the issue.
|
||||||
|
*/
|
||||||
|
propertyPath?: DesignerPropertyPath,
|
||||||
|
/**
|
||||||
|
* Description of the issue.
|
||||||
|
*/
|
||||||
|
description: string,
|
||||||
|
/**
|
||||||
|
* Url to a web page that has the explaination of the issue.
|
||||||
|
*/
|
||||||
|
moreInfoLink?: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The result returned by the table designer provider after handling an edit request.
|
* The result returned by the table designer provider after handling an edit request.
|
||||||
*/
|
*/
|
||||||
@@ -1158,7 +1184,7 @@ declare module 'azdata' {
|
|||||||
/**
|
/**
|
||||||
* Issues of current state.
|
* Issues of current state.
|
||||||
*/
|
*/
|
||||||
issues?: { severity: DesignerIssueSeverity, description: string, propertyPath?: DesignerEditPath }[];
|
issues?: DesignerIssue[];
|
||||||
/**
|
/**
|
||||||
* The input validation error.
|
* The input validation error.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export interface DesignerComponentInput {
|
|||||||
/**
|
/**
|
||||||
* Start initilizing the designer input object.
|
* Start initilizing the designer input object.
|
||||||
*/
|
*/
|
||||||
initialize(): void;
|
initialize(): Promise<void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start processing the edit made in the designer, the OnEditProcessed event will be fired when the processing is done.
|
* Start processing the edit made in the designer, the OnEditProcessed event will be fired when the processing is done.
|
||||||
|
|||||||
@@ -11,13 +11,10 @@ import { TableDesignerProvider } from 'sql/workbench/services/tableDesigner/comm
|
|||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import { GroupIdentifier, IEditorInput, IRevertOptions, ISaveOptions } from 'vs/workbench/common/editor';
|
import { GroupIdentifier, IEditorInput, IRevertOptions, ISaveOptions } from 'vs/workbench/common/editor';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
|
||||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||||
import { Schemas } from 'sql/base/common/schemas';
|
import { Schemas } from 'sql/base/common/schemas';
|
||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||||
|
|
||||||
const NewTable: string = localize('tableDesigner.newTable', "New Table");
|
|
||||||
|
|
||||||
enum TableIcon {
|
enum TableIcon {
|
||||||
Basic = 'Basic',
|
Basic = 'Basic',
|
||||||
Temporal = 'Temporal',
|
Temporal = 'Temporal',
|
||||||
@@ -43,19 +40,20 @@ export class TableDesignerInput extends EditorInput {
|
|||||||
tableInfo: azdata.designers.TableInfo,
|
tableInfo: azdata.designers.TableInfo,
|
||||||
telemetryInfo: { [key: string]: string },
|
telemetryInfo: { [key: string]: string },
|
||||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||||
@IEditorService private readonly _editorService: IEditorService,
|
|
||||||
@INotificationService private readonly _notificationService: INotificationService) {
|
@INotificationService private readonly _notificationService: INotificationService) {
|
||||||
super();
|
super();
|
||||||
this._designerComponentInput = this._instantiationService.createInstance(TableDesignerComponentInput, this._provider, tableInfo, telemetryInfo);
|
this._designerComponentInput = this._instantiationService.createInstance(TableDesignerComponentInput, this._provider, tableInfo, telemetryInfo);
|
||||||
this._register(this._designerComponentInput.onStateChange((e) => {
|
this._register(this._designerComponentInput.onStateChange((e) => {
|
||||||
if (e.previousState.pendingAction === 'publish') {
|
if (e.previousState.pendingAction === 'publish') {
|
||||||
this.setEditorLabel();
|
this.setEditorLabel();
|
||||||
this._onDidChangeLabel.fire();
|
|
||||||
}
|
}
|
||||||
if (e.currentState.dirty !== e.previousState.dirty) {
|
if (e.currentState.dirty !== e.previousState.dirty) {
|
||||||
this._onDidChangeDirty.fire();
|
this._onDidChangeDirty.fire();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
this._register(this._designerComponentInput.onInitialized(() => {
|
||||||
|
this.setEditorLabel();
|
||||||
|
}));
|
||||||
|
|
||||||
// default to basic if icon is null (new table) or no sub type
|
// default to basic if icon is null (new table) or no sub type
|
||||||
this._tableIcon = tableInfo.tableIcon ? tableInfo.tableIcon as TableIcon : TableIcon.Basic;
|
this._tableIcon = tableInfo.tableIcon ? tableInfo.tableIcon as TableIcon : TableIcon.Basic;
|
||||||
@@ -97,7 +95,7 @@ export class TableDesignerInput extends EditorInput {
|
|||||||
if (this._designerComponentInput.pendingAction) {
|
if (this._designerComponentInput.pendingAction) {
|
||||||
this._notificationService.warn(localize('tableDesigner.OperationInProgressWarning', "The operation cannot be performed while another operation is in progress."));
|
this._notificationService.warn(localize('tableDesigner.OperationInProgressWarning', "The operation cannot be performed while another operation is in progress."));
|
||||||
} else {
|
} else {
|
||||||
await this._designerComponentInput.openPublishDialog();
|
await this._designerComponentInput.save();
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -118,18 +116,8 @@ export class TableDesignerInput extends EditorInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private setEditorLabel(): void {
|
private setEditorLabel(): void {
|
||||||
const tableInfo = this._designerComponentInput.tableInfo;
|
this._name = this._designerComponentInput.tableInfo.title;
|
||||||
if (tableInfo.isNewTable) {
|
this._title = this._designerComponentInput.tableInfo.tooltip;
|
||||||
const existingNames = this._editorService.editors.map(editor => editor.getName());
|
this._onDidChangeLabel.fire();
|
||||||
// Find the next available unique name for the new table designer
|
|
||||||
let idx = 1;
|
|
||||||
do {
|
|
||||||
this._name = `${NewTable} ${idx}`;
|
|
||||||
idx++;
|
|
||||||
} while (existingNames.indexOf(this._name) !== -1);
|
|
||||||
} else {
|
|
||||||
this._name = `${tableInfo.schema}.${tableInfo.name}`;
|
|
||||||
}
|
|
||||||
this._title = `${tableInfo.server}.${tableInfo.database} - ${this._name}`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,57 +6,56 @@
|
|||||||
import { TableDesignerComponentInput } from 'sql/workbench/services/tableDesigner/browser/tableDesignerComponentInput';
|
import { TableDesignerComponentInput } from 'sql/workbench/services/tableDesigner/browser/tableDesignerComponentInput';
|
||||||
import { Action } from 'vs/base/common/actions';
|
import { Action } from 'vs/base/common/actions';
|
||||||
import { Codicon } from 'vs/base/common/codicons';
|
import { Codicon } from 'vs/base/common/codicons';
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
|
|
||||||
export abstract class TableChangesActionBase extends Action {
|
const PublishChangesLabel = localize('tableDesigner.publishTableChanges', "Publish Changes...");
|
||||||
protected _input: TableDesignerComponentInput;
|
const SaveChangesLabel = localize('tableDesigner.saveTableChanges', "Save");
|
||||||
private _onStateChangeDisposable: IDisposable;
|
|
||||||
|
|
||||||
constructor(id: string, label: string, iconClassNames: string) {
|
export class SaveTableChangesAction extends Action {
|
||||||
super(id, label, iconClassNames);
|
public static ID = 'tableDesigner.publishTableChanges';
|
||||||
|
protected _input: TableDesignerComponentInput;
|
||||||
|
protected _inputDisposableStore: DisposableStore;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(SaveTableChangesAction.ID);
|
||||||
|
this._inputDisposableStore = new DisposableStore();
|
||||||
}
|
}
|
||||||
|
|
||||||
public setContext(input: TableDesignerComponentInput): void {
|
public setContext(input: TableDesignerComponentInput): void {
|
||||||
this._input = input;
|
this._input = input;
|
||||||
this.updateState();
|
this.updateState();
|
||||||
this._onStateChangeDisposable?.dispose();
|
this.updateLabelAndIcon();
|
||||||
this._onStateChangeDisposable = input.onStateChange((e) => {
|
this._inputDisposableStore?.dispose();
|
||||||
|
this._inputDisposableStore = new DisposableStore();
|
||||||
|
this._inputDisposableStore.add(input.onStateChange((e) => {
|
||||||
this.updateState();
|
this.updateState();
|
||||||
});
|
}));
|
||||||
|
this._inputDisposableStore.add(input.onInitialized(() => {
|
||||||
|
this.updateLabelAndIcon();
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateState(): void {
|
private updateState(): void {
|
||||||
this.enabled = this._input.dirty && this._input.valid && this._input.pendingAction === undefined;
|
this.enabled = this._input.dirty && this._input.valid && this._input.pendingAction === undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updateLabelAndIcon(): void {
|
||||||
|
if (this._input?.tableDesignerView?.useAdvancedSaveMode) {
|
||||||
|
this.label = PublishChangesLabel;
|
||||||
|
this.class = Codicon.repoPush.classNames;
|
||||||
|
} else {
|
||||||
|
this.label = SaveChangesLabel;
|
||||||
|
this.class = Codicon.save.classNames;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async run(): Promise<void> {
|
||||||
|
await this._input.save();
|
||||||
|
}
|
||||||
|
|
||||||
override dispose() {
|
override dispose() {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
this._onStateChangeDisposable?.dispose();
|
this._inputDisposableStore?.dispose();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class PublishTableChangesAction extends TableChangesActionBase {
|
|
||||||
public static ID = 'tableDesigner.publishTableChanges';
|
|
||||||
public static LABEL = localize('tableDesigner.publishTableChanges', "Publish Changes...");
|
|
||||||
constructor() {
|
|
||||||
super(PublishTableChangesAction.ID, PublishTableChangesAction.LABEL, Codicon.repoPush.classNames);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async run(): Promise<void> {
|
|
||||||
await this._input.openPublishDialog();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class GenerateTableChangeScriptAction extends TableChangesActionBase {
|
|
||||||
public static ID = 'tableDesigner.generateScript';
|
|
||||||
public static LABEL = localize('tableDesigner.generateScript', "Generate Script");
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super(GenerateTableChangeScriptAction.ID, GenerateTableChangeScriptAction.LABEL, Codicon.output.classNames);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async run(): Promise<void> {
|
|
||||||
await this._input.generateScript();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
|||||||
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
|
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
|
||||||
import { IEditorOpenContext } from 'vs/workbench/common/editor';
|
import { IEditorOpenContext } from 'vs/workbench/common/editor';
|
||||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||||
import { PublishTableChangesAction } from 'sql/workbench/contrib/tableDesigner/browser/actions';
|
import { SaveTableChangesAction } from 'sql/workbench/contrib/tableDesigner/browser/actions';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IColorTheme, ICssStyleCollector, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
import { IColorTheme, ICssStyleCollector, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||||
import { DesignerPaneSeparator } from 'sql/platform/theme/common/colorRegistry';
|
import { DesignerPaneSeparator } from 'sql/platform/theme/common/colorRegistry';
|
||||||
@@ -26,7 +26,7 @@ export class TableDesignerEditor extends EditorPane {
|
|||||||
public static readonly ID: string = 'workbench.editor.tableDesigner';
|
public static readonly ID: string = 'workbench.editor.tableDesigner';
|
||||||
|
|
||||||
private _designer: Designer;
|
private _designer: Designer;
|
||||||
private _publishChangesAction: PublishTableChangesAction;
|
private _saveChangesAction: SaveTableChangesAction;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ITelemetryService telemetryService: ITelemetryService,
|
@ITelemetryService telemetryService: ITelemetryService,
|
||||||
@@ -45,7 +45,7 @@ export class TableDesignerEditor extends EditorPane {
|
|||||||
await super.setInput(input, options, context, token);
|
await super.setInput(input, options, context, token);
|
||||||
const designerInput = input.getComponentInput();
|
const designerInput = input.getComponentInput();
|
||||||
this._designer.setInput(designerInput);
|
this._designer.setInput(designerInput);
|
||||||
this._publishChangesAction.setContext(designerInput);
|
this._saveChangesAction.setContext(designerInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected createEditor(parent: HTMLElement): void {
|
protected createEditor(parent: HTMLElement): void {
|
||||||
@@ -58,9 +58,9 @@ export class TableDesignerEditor extends EditorPane {
|
|||||||
const designerContainer = container.appendChild(DOM.$('.designer-container'));
|
const designerContainer = container.appendChild(DOM.$('.designer-container'));
|
||||||
const actionbar = new ActionBar(actionbarContainer);
|
const actionbar = new ActionBar(actionbarContainer);
|
||||||
this._register(actionbar);
|
this._register(actionbar);
|
||||||
this._publishChangesAction = this._instantiationService.createInstance(PublishTableChangesAction);
|
this._saveChangesAction = this._instantiationService.createInstance(SaveTableChangesAction);
|
||||||
this._publishChangesAction.enabled = false;
|
this._saveChangesAction.enabled = false;
|
||||||
actionbar.push([this._publishChangesAction], { icon: true, label: false });
|
actionbar.push([this._saveChangesAction], { icon: true, label: false });
|
||||||
|
|
||||||
this._designer = this._instantiationService.createInstance(Designer, designerContainer);
|
this._designer = this._instantiationService.createInstance(Designer, designerContainer);
|
||||||
this._register(attachDesignerStyler(this._designer, this.themeService));
|
this._register(attachDesignerStyler(this._designer, this.themeService));
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ export class TableDesignerComponentInput implements DesignerComponentInput {
|
|||||||
private _onEditProcessed = new Emitter<DesignerEditProcessedEventArgs>();
|
private _onEditProcessed = new Emitter<DesignerEditProcessedEventArgs>();
|
||||||
private _onRefreshRequested = new Emitter<void>();
|
private _onRefreshRequested = new Emitter<void>();
|
||||||
private _originalViewModel: DesignerViewModel;
|
private _originalViewModel: DesignerViewModel;
|
||||||
|
private _tableDesignerView: azdata.designers.TableDesignerView;
|
||||||
|
|
||||||
public readonly onInitialized: Event<void> = this._onInitialized.event;
|
public readonly onInitialized: Event<void> = this._onInitialized.event;
|
||||||
public readonly onEditProcessed: Event<DesignerEditProcessedEventArgs> = this._onEditProcessed.event;
|
public readonly onEditProcessed: Event<DesignerEditProcessedEventArgs> = this._onEditProcessed.event;
|
||||||
@@ -81,6 +82,10 @@ export class TableDesignerComponentInput implements DesignerComponentInput {
|
|||||||
return this._issues;
|
return this._issues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get tableDesignerView(): azdata.designers.TableDesignerView {
|
||||||
|
return this._tableDesignerView;
|
||||||
|
}
|
||||||
|
|
||||||
processEdit(edit: DesignerEdit): void {
|
processEdit(edit: DesignerEdit): void {
|
||||||
const telemetryInfo = this.createTelemetryInfo();
|
const telemetryInfo = this.createTelemetryInfo();
|
||||||
telemetryInfo.tableObjectType = this.getObjectTypeFromPath(edit.path);
|
telemetryInfo.tableObjectType = this.getObjectTypeFromPath(edit.path);
|
||||||
@@ -177,6 +182,14 @@ export class TableDesignerComponentInput implements DesignerComponentInput {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async save(): Promise<void> {
|
||||||
|
if (this.tableDesignerView?.useAdvancedSaveMode) {
|
||||||
|
await this.openPublishDialog();
|
||||||
|
} else {
|
||||||
|
await this.publishChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async openPublishDialog(): Promise<void> {
|
async openPublishDialog(): Promise<void> {
|
||||||
const reportNotificationHandle = this._notificationService.notify({
|
const reportNotificationHandle = this._notificationService.notify({
|
||||||
severity: Severity.Info,
|
severity: Severity.Info,
|
||||||
@@ -243,24 +256,28 @@ export class TableDesignerComponentInput implements DesignerComponentInput {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize(): void {
|
async initialize(): Promise<void> {
|
||||||
if (this._view !== undefined || this.pendingAction === 'initialize') {
|
if (this._view !== undefined || this.pendingAction === 'initialize') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateState(this.valid, this.dirty, 'initialize');
|
this.updateState(this.valid, this.dirty, 'initialize');
|
||||||
this._provider.initializeTableDesigner(this.tableInfo).then(result => {
|
try {
|
||||||
|
const result = await this._provider.initializeTableDesigner(this.tableInfo);
|
||||||
this.doInitialization(result);
|
this.doInitialization(result);
|
||||||
this._onInitialized.fire();
|
this._onInitialized.fire();
|
||||||
}, error => {
|
} catch (error) {
|
||||||
this._errorMessageService.showDialog(Severity.Error, ErrorDialogTitle, localize('tableDesigner.errorInitializingTableDesigner', "An error occurred while initializing the table designer: {0}", error?.message ?? error));
|
this._errorMessageService.showDialog(Severity.Error, ErrorDialogTitle, localize('tableDesigner.errorInitializingTableDesigner', "An error occurred while initializing the table designer: {0}", error?.message ?? error));
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private doInitialization(designerInfo: azdata.designers.TableDesignerInfo): void {
|
private doInitialization(designerInfo: azdata.designers.TableDesignerInfo): void {
|
||||||
|
this.tableInfo = designerInfo.tableInfo;
|
||||||
this.updateState(true, this.tableInfo.isNewTable);
|
this.updateState(true, this.tableInfo.isNewTable);
|
||||||
this._viewModel = designerInfo.viewModel;
|
this._viewModel = designerInfo.viewModel;
|
||||||
this._originalViewModel = this.tableInfo.isNewTable ? undefined : deepClone(this._viewModel);
|
this._originalViewModel = this.tableInfo.isNewTable ? undefined : deepClone(this._viewModel);
|
||||||
|
this._tableDesignerView = designerInfo.view;
|
||||||
|
this._issues = designerInfo.issues;
|
||||||
this.setDesignerView(designerInfo.view);
|
this.setDesignerView(designerInfo.view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user