mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
support rename for login, user and a few other types (#22331)
* rename object * add comment * use URN property * vbump STS * revert loc string change * fix name check * pr comments
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
|
||||
"version": "4.6.0.6",
|
||||
"version": "4.6.0.10",
|
||||
"downloadFileNames": {
|
||||
"Windows_86": "win-x86-net7.0.zip",
|
||||
"Windows_64": "win-x64-net7.0.zip",
|
||||
|
||||
@@ -92,6 +92,11 @@
|
||||
"category": "MSSQL",
|
||||
"title": "%title.deleteObject%"
|
||||
},
|
||||
{
|
||||
"command": "mssql.renameObject",
|
||||
"category": "MSSQL",
|
||||
"title": "%title.renameObject%"
|
||||
},
|
||||
{
|
||||
"command": "mssql.enableGroupBySchema",
|
||||
"category": "MSSQL",
|
||||
@@ -478,6 +483,10 @@
|
||||
{
|
||||
"command": "mssql.deleteObject",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "mssql.renameObject",
|
||||
"when": "false"
|
||||
}
|
||||
],
|
||||
"objectExplorer/item/context": [
|
||||
@@ -511,6 +520,16 @@
|
||||
"when": "connectionProvider == MSSQL && nodeType =~ /^(ServerLevelLogin|User)$/ && config.workbench.enablePreviewFeatures",
|
||||
"group": "0_query@2"
|
||||
},
|
||||
{
|
||||
"command": "mssql.renameObject",
|
||||
"when": "connectionProvider == MSSQL && nodeType =~ /^(Database|ServerLevelLogin|User|Table|View)$/ && config.workbench.enablePreviewFeatures",
|
||||
"group": "0_query@3"
|
||||
},
|
||||
{
|
||||
"command": "mssql.renameObject",
|
||||
"when": "connectionProvider == MSSQL && nodeType == Column && config.workbench.enablePreviewFeatures && nodePath =~ /^.*\/Tables\/.*\/Columns\/.*$",
|
||||
"group": "0_query@3"
|
||||
},
|
||||
{
|
||||
"command": "mssql.enableGroupBySchema",
|
||||
"when": "connectionProvider == MSSQL && nodeType && nodeType =~ /^(Server|Database)$/ && !config.mssql.objectExplorer.groupBySchema"
|
||||
@@ -551,6 +570,16 @@
|
||||
"when": "connectionProvider == MSSQL && nodeType =~ /^(ServerLevelLogin|User)$/ && config.workbench.enablePreviewFeatures",
|
||||
"group": "connection@2"
|
||||
},
|
||||
{
|
||||
"command": "mssql.renameObject",
|
||||
"when": "connectionProvider == MSSQL && nodeType =~ /^(Database|ServerLevelLogin|User|Table|View)$/ && config.workbench.enablePreviewFeatures",
|
||||
"group": "connection@3"
|
||||
},
|
||||
{
|
||||
"command": "mssql.renameObject",
|
||||
"when": "connectionProvider == MSSQL && nodeType == Column && config.workbench.enablePreviewFeatures && nodePath =~ /^.*\/Tables\/.*\/Columns\/.*$",
|
||||
"group": "connection@3"
|
||||
},
|
||||
{
|
||||
"command": "mssql.enableGroupBySchema",
|
||||
"when": "connectionProvider == MSSQL && nodeType && nodeType =~ /^(Server|Database)$/ && !config.mssql.objectExplorer.groupBySchema"
|
||||
|
||||
@@ -196,5 +196,6 @@
|
||||
"title.newApplicationRole": "New Application Role",
|
||||
"title.newUser": "New User",
|
||||
"title.objectProperties": "Properties (Preview)",
|
||||
"title.deleteObject": "Delete"
|
||||
"title.deleteObject": "Delete",
|
||||
"title.renameObject": "Rename"
|
||||
}
|
||||
|
||||
@@ -1604,4 +1604,14 @@ export namespace DisposeUserViewRequest {
|
||||
export const type = new RequestType<DisposeUserViewRequestParams, void, void, void>('objectManagement/disposeUserView');
|
||||
}
|
||||
|
||||
export interface RenameObjectRequestParams {
|
||||
connectionUri: string;
|
||||
newName: string;
|
||||
objectUrn: string;
|
||||
}
|
||||
|
||||
export namespace RenameObjectRequest {
|
||||
export const type = new RequestType<RenameObjectRequestParams, void, void, void>('objectManagement/rename');
|
||||
}
|
||||
|
||||
// ------------------------------- < Object Management > ------------------------------------
|
||||
|
||||
7
extensions/mssql/src/mssql.d.ts
vendored
7
extensions/mssql/src/mssql.d.ts
vendored
@@ -1235,6 +1235,13 @@ declare module 'mssql' {
|
||||
* @param contextId The id of the view.
|
||||
*/
|
||||
disposeUserView(contextId: string): Thenable<void>;
|
||||
/**
|
||||
* Rename an object.
|
||||
* @param connectionUri The URI of the server connection.
|
||||
* @param objectUrn Urn of the object to be renamed. More information: https://learn.microsoft.com/en-us/sql/relational-databases/server-management-objects-smo/overview-smo.
|
||||
* @param newName The new name of the object.
|
||||
*/
|
||||
rename(connectionUri: string, objectUrn: string, newName: string): Thenable<void>;
|
||||
}
|
||||
// Object Management - End.
|
||||
}
|
||||
|
||||
@@ -32,6 +32,9 @@ export function registerObjectManagementCommands(appContext: AppContext) {
|
||||
appContext.extensionContext.subscriptions.push(vscode.commands.registerCommand('mssql.deleteObject', async (context: azdata.ObjectExplorerContext) => {
|
||||
await handleDeleteObjectCommand(context, service);
|
||||
}));
|
||||
appContext.extensionContext.subscriptions.push(vscode.commands.registerCommand('mssql.renameObject', async (context: azdata.ObjectExplorerContext) => {
|
||||
await handleRenameObjectCommand(context, service);
|
||||
}));
|
||||
}
|
||||
|
||||
function getObjectManagementService(appContext: AppContext, useTestService: boolean): IObjectManagementService {
|
||||
@@ -159,8 +162,60 @@ async function handleDeleteObjectCommand(context: azdata.ObjectExplorerContext,
|
||||
}).send();
|
||||
return;
|
||||
}
|
||||
await refreshParentNode(context);
|
||||
operation.updateStatus(azdata.TaskStatus.Succeeded);
|
||||
await refreshParentNode(context);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function handleRenameObjectCommand(context: azdata.ObjectExplorerContext, service: IObjectManagementService): Promise<void> {
|
||||
const connectionUri = await getConnectionUri(context);
|
||||
if (!connectionUri) {
|
||||
return;
|
||||
}
|
||||
const nodeTypeDisplayName = getNodeTypeDisplayName(context.nodeInfo.nodeType);
|
||||
const originalName = context.nodeInfo.metadata.name;
|
||||
const newName = await vscode.window.showInputBox({
|
||||
title: localizedConstants.RenameObjectDialogTitle,
|
||||
value: originalName,
|
||||
validateInput: (value: string): string | undefined => {
|
||||
if (!value) {
|
||||
return localizedConstants.NameCannotBeEmptyError;
|
||||
} else {
|
||||
// valid
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// return if no change was made or the dialog was canceled.
|
||||
if (newName === originalName || !newName) {
|
||||
return;
|
||||
}
|
||||
|
||||
azdata.tasks.startBackgroundOperation({
|
||||
displayName: localizedConstants.RenameObjectOperationDisplayName(nodeTypeDisplayName, originalName, newName),
|
||||
description: '',
|
||||
isCancelable: false,
|
||||
operation: async (operation) => {
|
||||
try {
|
||||
const startTime = Date.now();
|
||||
await service.rename(connectionUri, context.nodeInfo.metadata.urn, newName);
|
||||
TelemetryReporter.sendTelemetryEvent(TelemetryActions.RenameObject, {
|
||||
objectType: context.nodeInfo.nodeType
|
||||
}, {
|
||||
elapsedTimeMs: Date.now() - startTime
|
||||
});
|
||||
}
|
||||
catch (err) {
|
||||
operation.updateStatus(azdata.TaskStatus.Failed, localizedConstants.RenameObjectError(nodeTypeDisplayName, originalName, newName, getErrorMessage(err)));
|
||||
TelemetryReporter.createErrorEvent2(TelemetryViews.ObjectManagement, TelemetryActions.RenameObject, err).withAdditionalProperties({
|
||||
objectType: context.nodeInfo.nodeType
|
||||
}).send();
|
||||
return;
|
||||
}
|
||||
operation.updateStatus(azdata.TaskStatus.Succeeded);
|
||||
await refreshParentNode(context);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,8 +7,12 @@
|
||||
* The object types in object explorer's node context.
|
||||
*/
|
||||
export enum NodeType {
|
||||
Column = 'Column',
|
||||
Database = 'Database',
|
||||
Login = 'ServerLevelLogin',
|
||||
User = 'User'
|
||||
Table = 'Table',
|
||||
User = 'User',
|
||||
View = 'View'
|
||||
}
|
||||
|
||||
export const PublicServerRoleName = 'public';
|
||||
@@ -51,10 +55,11 @@ export const AlterLoginDocUrl = 'https://learn.microsoft.com/en-us/sql/t-sql/sta
|
||||
|
||||
export enum TelemetryActions {
|
||||
CreateObject = 'CreateObject',
|
||||
UpdateObject = 'UpdateObject',
|
||||
DeleteObject = 'DeleteObject',
|
||||
OpenNewObjectDialog = 'OpenNewObjectDialog',
|
||||
OpenPropertiesDialog = 'OpenPropertiesDialog'
|
||||
OpenPropertiesDialog = 'OpenPropertiesDialog',
|
||||
RenameObject = 'RenameObject',
|
||||
UpdateObject = 'UpdateObject'
|
||||
}
|
||||
|
||||
export enum TelemetryViews {
|
||||
|
||||
@@ -11,6 +11,10 @@ export const LoginTypeDisplayName: string = localize('objectManagement.LoginType
|
||||
export const UserTypeDisplayName: string = localize('objectManagement.UserDisplayName', "user");
|
||||
export const LoginTypeDisplayNameInTitle: string = localize('objectManagement.LoginTypeDisplayNameInTitle', "Login");
|
||||
export const UserTypeDisplayNameInTitle: string = localize('objectManagement.UserTypeDisplayNameInTitle', "User");
|
||||
export const TableTypeDisplayName: string = localize('objectManagement.TableDisplayName', "table");
|
||||
export const ViewTypeDisplayName: string = localize('objectManagement.ViewDisplayName', "view");
|
||||
export const ColumnTypeDisplayName: string = localize('objectManagement.ColumnDisplayName', "column");
|
||||
export const DatabaseTypeDisplayName: string = localize('objectManagement.DatabaseDisplayName', "database");
|
||||
|
||||
// Shared Strings
|
||||
export const HelpText: string = localize('objectManagement.helpText', "Help");
|
||||
@@ -18,6 +22,7 @@ export const YesText: string = localize('objectManagement.yesText', "Yes");
|
||||
export const OkText: string = localize('objectManagement.OkText', "OK");
|
||||
export const LoadingDialogText: string = localize('objectManagement.loadingDialog', "Loading dialog...");
|
||||
export const FailedToRetrieveConnectionInfoErrorMessage: string = localize('objectManagement.noConnectionUriError', "Failed to retrieve the connection information, please reconnect and try again.")
|
||||
export const RenameObjectDialogTitle: string = localize('objectManagement.renameObjectDialogTitle', "Enter new name");
|
||||
|
||||
export function RefreshObjectExplorerError(error: string): string {
|
||||
return localize({
|
||||
@@ -89,6 +94,20 @@ export function ObjectPropertiesDialogTitle(objectType: string, objectName: stri
|
||||
}, '{0} - {1} (Preview)', objectType, objectName);
|
||||
}
|
||||
|
||||
export function RenameObjectOperationDisplayName(objectType: string, originalName: string, newName: string): string {
|
||||
return localize({
|
||||
key: 'objectManagement.renameObjectOperationName',
|
||||
comment: ['{0} object type, {1}: original name, {2}: new name']
|
||||
}, "Rename {0} '{1}' to '{2}'", objectType, originalName, newName);
|
||||
}
|
||||
|
||||
export function RenameObjectError(objectType: string, originalName: string, newName: string, error: string): string {
|
||||
return localize({
|
||||
key: 'objectManagement.renameObjectError',
|
||||
comment: ['{0} object type, {1}: original name, {2}: new name, {3}: error message.']
|
||||
}, "An error occurred while renaming {0} '{1}' to '{2}'. {3}", objectType, originalName, newName, error);
|
||||
}
|
||||
|
||||
export const NameText = localize('objectManagement.nameLabel', "Name");
|
||||
export const SelectedText = localize('objectManagement.selectedLabel', "Selected");
|
||||
export const GeneralSectionHeader = localize('objectManagement.generalSectionHeader', "General");
|
||||
|
||||
@@ -136,6 +136,16 @@ export class ObjectManagementService implements IObjectManagementService {
|
||||
}
|
||||
);
|
||||
}
|
||||
rename(connectionUri: string, objectUrn: string, newName: string): Thenable<void> {
|
||||
const params: contracts.RenameObjectRequestParams = { connectionUri, objectUrn, newName };
|
||||
return this.client.sendRequest(contracts.RenameObjectRequest.type, params).then(
|
||||
r => { },
|
||||
e => {
|
||||
this.client.logFailedRequest(contracts.RenameObjectRequest.type, e);
|
||||
return Promise.reject(new Error(e.message));
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class TestObjectManagementService implements IObjectManagementService {
|
||||
@@ -292,6 +302,9 @@ export class TestObjectManagementService implements IObjectManagementService {
|
||||
}
|
||||
async disposeUserView(contextId: string): Promise<void> {
|
||||
}
|
||||
async rename(connectionUri: string, objectUrn: string, newName: string): Promise<void> {
|
||||
return this.delayAndResolve();
|
||||
}
|
||||
|
||||
private delayAndResolve(): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
@@ -234,9 +234,9 @@ export abstract class ObjectManagementDialogBase<ObjectInfoType extends ObjectMa
|
||||
protected createGroup(header: string, items: azdata.Component[], collapsible: boolean = true, collapsed: boolean = false): azdata.GroupContainer {
|
||||
return this.modelView.modelBuilder.groupContainer().withLayout({
|
||||
header: header,
|
||||
collapsed: false,
|
||||
collapsible: collapsible
|
||||
}).withProps({ collapsed: collapsed }).withItems(items).component();
|
||||
collapsible: collapsible,
|
||||
collapsed: collapsed
|
||||
}).withItems(items).component();
|
||||
}
|
||||
|
||||
protected createFormContainer(items: azdata.Component[]): azdata.DivContainer {
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import { getErrorMessage } from '../utils';
|
||||
import { AuthenticationType, NodeType, UserType } from './constants';
|
||||
import { AADAuthenticationTypeDisplayText, ContainedUserText, LoginTypeDisplayName, LoginTypeDisplayNameInTitle, RefreshObjectExplorerError, SQLAuthenticationTypeDisplayText, UserTypeDisplayName, UserTypeDisplayNameInTitle, UserWithLoginText, UserWithNoConnectAccess, UserWithWindowsGroupLoginText, WindowsAuthenticationTypeDisplayText } from './localizedConstants';
|
||||
import { AADAuthenticationTypeDisplayText, ColumnTypeDisplayName, ContainedUserText, DatabaseTypeDisplayName, LoginTypeDisplayName, LoginTypeDisplayNameInTitle, RefreshObjectExplorerError, SQLAuthenticationTypeDisplayText, TableTypeDisplayName, UserTypeDisplayName, UserTypeDisplayNameInTitle, UserWithLoginText, UserWithNoConnectAccess, UserWithWindowsGroupLoginText, ViewTypeDisplayName, WindowsAuthenticationTypeDisplayText } from './localizedConstants';
|
||||
|
||||
export function deepClone<T>(obj: T): T {
|
||||
if (!obj || typeof obj !== 'object') {
|
||||
@@ -59,6 +59,14 @@ export function getNodeTypeDisplayName(type: string, inTitle: boolean = false):
|
||||
return inTitle ? LoginTypeDisplayNameInTitle : LoginTypeDisplayName;
|
||||
case NodeType.User:
|
||||
return inTitle ? UserTypeDisplayNameInTitle : UserTypeDisplayName;
|
||||
case NodeType.Table:
|
||||
return TableTypeDisplayName;
|
||||
case NodeType.View:
|
||||
return ViewTypeDisplayName;
|
||||
case NodeType.Column:
|
||||
return ColumnTypeDisplayName;
|
||||
case NodeType.Database:
|
||||
return DatabaseTypeDisplayName;
|
||||
default:
|
||||
throw new Error(`Unkown node type: ${type}`);
|
||||
}
|
||||
@@ -85,6 +93,7 @@ export function getAuthenticationTypeByDisplayName(displayValue: string): Authen
|
||||
return AuthenticationType.Sql;
|
||||
}
|
||||
}
|
||||
|
||||
export function getUserTypeDisplayName(userType: UserType): string {
|
||||
switch (userType) {
|
||||
case UserType.WithLogin:
|
||||
|
||||
@@ -44,6 +44,7 @@ export class MssqlNodeContext extends Disposable {
|
||||
static IsWindows = new RawContextKey<boolean>('isWindows', isWindows);
|
||||
static IsCloud = new RawContextKey<boolean>('isCloud', false);
|
||||
static NodeType = new RawContextKey<string>('nodeType', undefined);
|
||||
static NodePath = new RawContextKey<string>('nodePath', undefined);
|
||||
static ObjectType = new RawContextKey<string>('objectType', undefined);
|
||||
static NodeLabel = new RawContextKey<string>('nodeLabel', undefined);
|
||||
static EngineEdition = new RawContextKey<number>('engineEdition', DatabaseEngineEdition.Unknown);
|
||||
@@ -60,6 +61,7 @@ export class MssqlNodeContext extends Disposable {
|
||||
private nodeProviderKey!: IContextKey<string>;
|
||||
private isCloudKey!: IContextKey<boolean>;
|
||||
private nodeTypeKey!: IContextKey<string>;
|
||||
private nodePathKey!: IContextKey<string>;
|
||||
private objectTypeKey!: IContextKey<string>;
|
||||
private nodeLabelKey!: IContextKey<string>;
|
||||
private isDatabaseOrServerKey!: IContextKey<boolean>;
|
||||
@@ -99,6 +101,9 @@ export class MssqlNodeContext extends Disposable {
|
||||
this.setScriptingContextKeys();
|
||||
this.nodeTypeKey.set(node.contextValue);
|
||||
}
|
||||
if (node.nodeInfo?.nodePath) {
|
||||
this.nodePathKey.set(node.nodeInfo.nodePath);
|
||||
}
|
||||
this.setQueryEnabledKey();
|
||||
}
|
||||
if (node.label) {
|
||||
@@ -112,6 +117,7 @@ export class MssqlNodeContext extends Disposable {
|
||||
this.isCloudKey = MssqlNodeContext.IsCloud.bindTo(this.contextKeyService);
|
||||
this.engineEditionKey = MssqlNodeContext.EngineEdition.bindTo(this.contextKeyService);
|
||||
this.nodeTypeKey = MssqlNodeContext.NodeType.bindTo(this.contextKeyService);
|
||||
this.nodePathKey = MssqlNodeContext.NodePath.bindTo(this.contextKeyService);
|
||||
this.objectTypeKey = MssqlNodeContext.ObjectType.bindTo(this.contextKeyService);
|
||||
this.nodeLabelKey = MssqlNodeContext.NodeLabel.bindTo(this.contextKeyService);
|
||||
this.isDatabaseOrServerKey = MssqlNodeContext.IsDatabaseOrServer.bindTo(this.contextKeyService);
|
||||
|
||||
Reference in New Issue
Block a user