mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -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:
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user