Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moving Restore functionality to the mssql extension #24757

Merged
merged 43 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
393cce8
initila commit: restore in menu, opens dialog with general tab
ssreerama Oct 19, 2023
2c3dec8
general tab UI with backup folder changes
ssreerama Oct 23, 2023
2566d30
Merge branch 'main' into sai/restore
ssreerama Oct 23, 2023
d3bd3ee
more updates
ssreerama Oct 24, 2023
a3e7c0f
Merge branch 'main' into sai/restore
ssreerama Oct 24, 2023
d11db76
adding other tabs and optiosn
ssreerama Oct 24, 2023
23d4899
Merge branch 'main' into sai/restore
ssreerama Oct 24, 2023
c40dcfe
UI elements are added mostly
ssreerama Oct 25, 2023
58f0b01
adding restore info interface
ssreerama Oct 26, 2023
7d81908
Merge branch 'main' into sai/restore
ssreerama Oct 26, 2023
72bade4
adding recovery options
ssreerama Oct 26, 2023
f538ad3
Merge branch 'main' into sai/restore
ssreerama Oct 26, 2023
acbf201
added all default options
ssreerama Oct 27, 2023
0a74338
Merge branch 'main' into sai/restore
ssreerama Oct 30, 2023
b206707
Merge branch 'main' into sai/restore
ssreerama Oct 30, 2023
4bac5fc
getting default values of restore dialog
ssreerama Oct 31, 2023
2a5132d
restorePlan table
ssreerama Nov 1, 2023
412e72a
Merge branch 'main' into sai/restore
ssreerama Nov 1, 2023
e313bdd
Merge branch 'main' into sai/restore
ssreerama Nov 2, 2023
0a41f1f
restore files table
ssreerama Nov 3, 2023
a84366f
Merge branch 'main' into sai/restore
ssreerama Nov 6, 2023
b8d0982
UI changes, fix for apply button required
ssreerama Nov 6, 2023
867d504
loading all done, restore/sccript buttons needed
ssreerama Nov 8, 2023
56f8f95
Reload new plan on source change, todo-loading symbol
ssreerama Nov 9, 2023
1964ee6
added loader, todo:script,restore
ssreerama Nov 9, 2023
14553b4
Merge branch 'main' into sai/restore
ssreerama Nov 9, 2023
ac65343
all UI completed
ssreerama Nov 9, 2023
d51a932
backup file path is working too, todo: increase dropdowns width, scri…
ssreerama Nov 9, 2023
38be192
restore done but fialing, todo-script,options
ssreerama Nov 13, 2023
22334a0
Merge branch 'main' into sai/restore
ssreerama Nov 13, 2023
2100945
restore succeeded
ssreerama Nov 13, 2023
f684e8a
finished restore plan checkboxes functionlaity as SSMS
ssreerama Nov 13, 2023
baaea3d
code review comment update
ssreerama Nov 13, 2023
9977041
Script button functionliaty added
ssreerama Nov 14, 2023
26a746c
Merge branch 'main' into sai/restore
ssreerama Nov 16, 2023
1b291d9
Merge branch 'main' into sai/restore
ssreerama Nov 20, 2023
65cc87b
Merge branch 'main' into sai/restore
ssreerama Nov 21, 2023
6219a72
Added button container to the data and log file paths
ssreerama Nov 21, 2023
4a5e1c3
Using the existing restore provider and removed the duplicate code
ssreerama Nov 21, 2023
4fa8e0f
removed unused code
ssreerama Nov 21, 2023
6803cf2
Merge branch 'main' into sai/restore
ssreerama Nov 27, 2023
013a555
void restore error message popup instead of awaiting
ssreerama Nov 27, 2023
c9d438f
Addressing code review comments
ssreerama Nov 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions extensions/mssql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@
"category": "MSSQL",
"title": "%title.attachDatabase%"
},
{
"command": "mssql.restoreDatabase",
"category": "MSSQL",
"title": "%title.restoreDatabase%"
},
{
"command": "mssql.backupDatabase",
"category": "MSSQL",
Expand Down Expand Up @@ -596,6 +601,10 @@
"command": "mssql.attachDatabase",
"when": "false"
},
{
"command": "mssql.restoreDatabase",
"when": "false"
},
{
"command": "mssql.backupDatabase",
"when": "false"
Expand Down Expand Up @@ -696,6 +705,11 @@
"when": "connectionProvider == MSSQL && nodeType == Folder && objectType == Databases && !isCloud && config.workbench.enablePreviewFeatures",
"group": "1_objectManagement@2"
},
{
"command": "mssql.restoreDatabase",
"when": "connectionProvider == MSSQL && !isCloud && mssql:engineedition != 11 && nodeType && nodeType == Database && (productQualityType =~ /^(insider|dev)$/ || isDevelopment)",
ssreerama marked this conversation as resolved.
Show resolved Hide resolved
"group": "1_objectManagement@3"
},
{
"command": "mssql.backupDatabase",
"when": "connectionProvider == MSSQL && nodeType == Database && !isCloud && engineEdition != 11 && config.workbench.enablePreviewFeatures && (productQualityType =~ /^(insider|dev)$/ || isDevelopment)",
Expand Down
3 changes: 2 additions & 1 deletion extensions/mssql/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -199,5 +199,6 @@
"title.renameObject": "Rename (Preview)",
"title.detachDatabase": "Detach Database (Preview)",
"title.attachDatabase": "Attach Database (Preview)",
"title.backupDatabase": "Backup Database (Preview)"
"title.backupDatabase": "Backup Database (Preview)",
"title.restoreDatabase": "Restore (Preview)"
ssreerama marked this conversation as resolved.
Show resolved Hide resolved
}
38 changes: 38 additions & 0 deletions extensions/mssql/src/objectManagement/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { ServerPropertiesDialog } from './ui/serverPropertiesDialog';
import { DetachDatabaseDialog } from './ui/detachDatabaseDialog';
import { DropDatabaseDialog } from './ui/dropDatabaseDialog';
import { AttachDatabaseDialog } from './ui/attachDatabaseDialog';
import { RestoreDatabaseDialog } from './ui/restoreDatabaseDialog';
import { BackupDatabaseDialog } from './ui/backupDatabaseDialog';

export function registerObjectManagementCommands(appContext: AppContext) {
Expand Down Expand Up @@ -73,6 +74,9 @@ export function registerObjectManagementCommands(appContext: AppContext) {
appContext.extensionContext.subscriptions.push(vscode.commands.registerCommand('mssql.dropDatabase', async (context: azdata.ObjectExplorerContext) => {
await handleDropDatabase(context, service);
}));
appContext.extensionContext.subscriptions.push(vscode.commands.registerCommand('mssql.restoreDatabase', async (context: azdata.ObjectExplorerContext) => {
await handleRestoreDatabase(context, service);
}));
}

function getObjectManagementService(appContext: AppContext, useTestService: boolean): IObjectManagementService {
Expand Down Expand Up @@ -455,6 +459,40 @@ async function handleDropDatabase(context: azdata.ObjectExplorerContext, service
}
}

async function handleRestoreDatabase(context: azdata.ObjectExplorerContext, service: IObjectManagementService): Promise<void> {
const connectionUri = await getConnectionUri(context);
if (!connectionUri) {
return;
}
try {
const parentUrn = await getParentUrn(context);
const options: ObjectManagementDialogOptions = {
connectionUri: connectionUri,
isNewObject: true,
database: context.connectionProfile!.databaseName!,
objectType: ObjectManagement.NodeType.Database,
objectName: '',
parentUrn: parentUrn,
objectExplorerContext: context
};
const dialog = new RestoreDatabaseDialog(service, options);
const startTime = Date.now();
await dialog.open();
TelemetryReporter.sendTelemetryEvent(TelemetryActions.OpenRestoreDatabaseDialog, {
objectType: ObjectManagement.NodeType.Database
}, {
elapsedTimeMs: Date.now() - startTime
});
}
catch (err) {
TelemetryReporter.createErrorEvent2(ObjectManagementViewName, TelemetryActions.OpenRestoreDatabaseDialog, err).withAdditionalProperties({
objectType: context.nodeInfo!.nodeType
}).send();
console.error(err);
await vscode.window.showErrorMessage(objectManagementLoc.OpenRestoreDatabaseDialogError(getErrorMessage(err)));
Charles-Gagnon marked this conversation as resolved.
Show resolved Hide resolved
}
}

function getDialog(service: IObjectManagementService, dialogOptions: ObjectManagementDialogOptions): ObjectManagementDialogBase<ObjectManagement.SqlObject, ObjectManagement.ObjectViewInfo<ObjectManagement.SqlObject>> {
const verticalTabsDialogWidth = '750px';
switch (dialogOptions.objectType) {
Expand Down
9 changes: 8 additions & 1 deletion extensions/mssql/src/objectManagement/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ export const QueryStorePropertiesDocUrl = 'https://learn.microsoft.com/sql/relat
export const DatabaseFilesPropertiesDocUrl = 'https://learn.microsoft.com/sql/relational-databases/databases/database-properties-files-page';
export const DatabaseFileGroupsPropertiesDocUrl = 'https://learn.microsoft.com/sql/relational-databases/databases/database-properties-filegroups-page';

// Restore database help links
export const RestoreDatabaseGeneralTabDocUrl = 'https://learn.microsoft.com/sql/relational-databases/backup-restore/restore-database-general-page'
export const RestoreDatabaseFilesTabDocUrl = 'https://learn.microsoft.com/sql/relational-databases/backup-restore/restore-database-files-page'
export const RestoreDatabaseOptionsTabDocUrl = 'https://learn.microsoft.com/sql/relational-databases/backup-restore/restore-database-options-page'

export const enum TelemetryActions {
CreateObject = 'CreateObject',
DropObject = 'DropObject',
Expand All @@ -58,7 +63,9 @@ export const enum TelemetryActions {
OpenBackupDatabaseDialog = 'OpenBackupDatabaseDialog',
OpenDropDatabaseDialog = 'OpenDropDatabaseDialog',
AttachDatabase = 'AttachDatabase',
DetachDatabase = 'DetachDatabase'
DetachDatabase = 'DetachDatabase',
OpenRestoreDatabaseDialog = 'OpenRestoreDatabaseDialog',
RestoreDatabase = 'RestoreDatabase'
}

export const ObjectManagementViewName = 'ObjectManagement';
15 changes: 15 additions & 0 deletions extensions/mssql/src/objectManagement/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as azdata from 'azdata';
import { ObjectManagement } from 'mssql';

/**
Expand Down Expand Up @@ -459,6 +461,7 @@ export interface Database extends ObjectManagement.SqlObject {
files?: DatabaseFile[];
filegroups?: FileGroup[];
queryStoreOptions?: QueryStoreOptions;
restorePlanResponse?: azdata.RestorePlanResponse;
backupEncryptors?: BackupEncryptor[];
}

Expand Down Expand Up @@ -489,6 +492,7 @@ export interface DatabaseViewInfo extends ObjectManagement.ObjectViewInfo<Databa
sizeBasedCleanupModeOptions?: string[];
staleThresholdOptions?: string[];
serverFilestreamAccessLevel?: FileStreamEffectiveLevel;
restoreDatabaseInfo?: RestoreDatabaseInfo;
}

export interface QueryStoreOptions {
Expand All @@ -505,6 +509,17 @@ export interface QueryStoreOptions {
currentStorageSizeInMB: number;
}

export interface RestoreDatabaseInfo {
sourceDatabaseNames: string[];
targetDatabaseNames: string[];
recoveryStateOptions: CategoryValue[];
}

export interface CategoryValue {
displayName: string;
name: string;
}

export interface QueryStoreCapturePolicyOptions {
executionCount: number;
staleThreshold: string;
Expand Down
61 changes: 61 additions & 0 deletions extensions/mssql/src/objectManagement/localizedConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,20 @@ export function BackupDatabaseOperationDisplayName(objectName: string): string {
}, "Backup database '{0}'", objectName);
}

export function OpenRestoreDatabaseDialogError(error: string): string {
return localize({
key: 'objectManagement.openRestoreDatabaseDialogError',
comment: ['{0}: error message.']
}, "An error occurred while opening the restore database dialog. {0}", error);
}

export function RestoreDatabaseOperationDisplayName(objectName: string): string {
return localize({
key: 'objectManagement.restoreDatabaseOperationName',
comment: ['{0}: object name.']
}, "Restore database '{0}'", objectName);
}

export function OpenObjectPropertiesDialogError(objectType: string, objectName: string, error: string): string {
return localize({
key: 'objectManagement.openObjectPropertiesDialogError',
Expand Down Expand Up @@ -221,6 +235,7 @@ export const EditionText = localize('objectManagement.editionLabel', "Edition");
export const MaxSizeText = localize('objectManagement.maxSizeLabel', "Max Size");
export const AzurePricingLinkText = localize('objectManagement.azurePricingLink', "Azure SQL Database pricing calculator");
export const DetachDatabaseDialogTitle = (dbName: string) => localize('objectManagement.detachDatabaseDialogTitle', "Detach Database - {0} (Preview)", dbName);
export const RestoreDatabaseDialogTitle = (dbName: string) => localize('objectManagement.restoreDatabaseDialogTitle', "Restore Database - {0} (Preview)", dbName);
export const DetachDropConnections = localize('objectManagement.detachDropConnections', "Drop connnections");
export const DetachUpdateStatistics = localize('objectManagement.detachUpdateStatistics', "Update statistics");
export const DatabaseFilesLabel = localize('objectManagement.databaseFiles', "Database Files");
Expand Down Expand Up @@ -314,6 +329,52 @@ export const SQLAuthenticationTypeDisplayText = localize('objectManagement.login
export const AADAuthenticationTypeDisplayText = localize('objectManagement.login.aadAuthenticationType', "Microsoft Entra ID Authentication");
export const OldPasswordCannotBeEmptyError = localize('objectManagement.login.oldPasswordCannotBeEmptyError', "Old password cannot be empty.");

//Restore Database
export const RestoreFromText = localize('objectManagement.restoreDatabase.restoreFromText', "Restore from");
export const BackupFilePathText = localize('objectManagement.restoreDatabase.backupFilePathText', "Backup file path");
export const DatabaseText = localize('objectManagement.restoreDatabase.databaseText', "Database");
export const TargetDatabaseText = localize('objectManagement.restoreDatabase.targetDatabaseText', "Target database");
export const RestoreToText = localize('objectManagement.restoreDatabase.restoreToText', "Restore to");
export const SourceSectionText = localize('objectManagement.restoreDatabase.SourceSectionText', "Source");
export const DestinationSectionText = localize('objectManagement.restoreDatabase.DestinationSectionText', "Destination");
export const RestorePlanSectionText = localize('objectManagement.restoreDatabase.RestorePlanSectionText', "Restore plan");
export const RestoreFromBackupFileOptionText = localize('objectManagement.restoreDatabase.restoreFromBackupFileOptionText', "Backup file");
export const RestoreFromDatabaseOptionText = localize('objectManagement.restoreDatabase.restoreFromDatabaseOptionText', "Database");
export const BackupFolderPathTitle = localize('objectManagement.restoreDatabase.backupFolderPathTitle', "Please enter one or more file paths separated by commas");
export const RestoreDatabaseFilesAsText = localize('objectManagement.restoreDatabase.restoreDatabaseFilesAsText', "Restore database files as");
export const RestoreDatabaseFileDetailsText = localize('objectManagement.restoreDatabase.restoreDatabaseFileDetailsText', "Restore database file Details");
export const RestoreOptionsText = localize('objectManagement.restoreDatabase.restoreOptionsText', "Restore Options");
export const RestoreTailLogBackupText = localize('objectManagement.restoreDatabase.restoreTailLogBackupOptionsText', "Tail-log backup");
export const RestoreServerConnectionsOptionsText = localize('objectManagement.restoreDatabase.restoreServerConnectionsOptionsText', "Server connections");
export const RelocateAllFilesText = localize('objectManagement.restoreDatabase.relocateAllFilesText', "Relocate All Files");
export const DataFileFolderText = localize('objectManagement.restoreDatabase.dataFileFolderText', "Data File Folder");
export const LogFileFolderText = localize('objectManagement.restoreDatabase.logFileFolderText', "Log File Folder");
export const OverwriteTheExistingDatabaseText = localize('objectManagement.restoreDatabase.overwriteTheExistingDatabaseText', "Overwrite the existing database (WITH REPLACE)");
export const PreserveReplicationSettingsText = localize('objectManagement.restoreDatabase.preserveReplicationSettingsText', "Preserve the replication settings (WITH KEEP_REPLICATION)");
export const RestrictAccessToRestoredDBText = localize('objectManagement.restoreDatabase.restrictAccessToRestoredDBText', "Restrict access to the restored database (WITH RESTRICTED_USER)");
export const RecoveryStateText = localize('objectManagement.restoreDatabase.recoveryStateText', "Recovery State");
export const StandbyFileText = localize('objectManagement.restoreDatabase.standbyFileText', "Standby file");
export const TakeTailLogBackupBeforeRestoreText = localize('objectManagement.restoreDatabase.takeTailLogBackupBeforeRestoreText', "Take tail-log backup before restore");
export const LeaveSourceDBText = localize('objectManagement.restoreDatabase.leaveSourceDBText', "Leave source database in the restoring state (WITH NORECOVERY)");
export const TailLogBackupFileText = localize('objectManagement.restoreDatabase.tailLogBackupFileText', "Tail Log Backup File");
export const CloseExistingConnectionText = localize('objectManagement.restoreDatabase.closeExistingConnectionText', "Close existing connections to destination database");
export const RestoreText = localize('objectManagement.restoreDatabase.restorePlan.restoreText', "Restore");
export const ComponentText = localize('objectManagement.restoreDatabase.restorePlan.componentText', "Component");
export const TypeText = localize('objectManagement.restoreDatabase.restorePlan.typeText', "Type");
export const ServerText = localize('objectManagement.restoreDatabase.restorePlan.serverText', "Server");
export const PositionText = localize('objectManagement.restoreDatabase.restorePlan.positionText', "Position");
export const FirstLSNText = localize('objectManagement.restoreDatabase.restorePlan.firstLSNText', "First LSN");
export const LastLSNText = localize('objectManagement.restoreDatabase.restorePlan.lastLSNText', "Last LSN");
export const CheckpointLSNText = localize('objectManagement.restoreDatabase.restorePlan.checkpointLSNText', "Checkpoint LSN");
export const FullLSNText = localize('objectManagement.restoreDatabase.restorePlan.FullLSNText', "Full LSN");
export const StartDateText = localize('objectManagement.restoreDatabase.restorePlan.startDateText', "Start Date");
export const FinishDateText = localize('objectManagement.restoreDatabase.restorePlan.FinishDateText', "Finish Date");
export const UserNameText = localize('objectManagement.restoreDatabase.restorePlan.userNameText', "User Name");
export const ExpirationText = localize('objectManagement.restoreDatabase.restorePlan.expirationText', "Expiration");
export const LogicalFileNameText = localize('objectManagement.restoreDatabase.restorePlan.logicalFileNameText', "Logical File Name");
export const OriginalFileNameText = localize('objectManagement.restoreDatabase.restorePlan.originalFileNameText', "Original File Name");
export const RestoreAsText = localize('objectManagement.restoreDatabase.restorePlan.restoreAsText', "Restore As");

// User
export const UserTypeText = localize('objectManagement.user.type', "Type");
export const UserType_LoginMapped = localize('objectManagement.user.loginMapped', "Mapped to a server login");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { ApplicationRoleViewInfo, AuthenticationType, DatabaseRoleViewInfo, Data
import * as Utils from '../utils';
import * as constants from '../constants';
import * as contracts from '../contracts';

import { BaseService, ISqlOpsFeature, SqlOpsDataClient } from 'dataprotocol-client';
import { ObjectManagement, IObjectManagementService, DatabaseFileData, BackupInfo } from 'mssql';
import { ClientCapabilities } from 'vscode-languageclient';
Expand Down
Loading
Loading