UI for the Backup/Restore Managed Instance Feature (#19244)

* Rebase from main branch

* Made mssql a module

* remove rpc specific stuff

* Added create sas RPC call

* Backup to url works now

* Moved createSas RPC to the BlobService

* Relocated createSas RPC from sql-dataprotocolclient to the mssql

* After rebase

* Removed duplicate symbol

* Renamed Blob to AzureBlob and relocated CreateSasResponse to mssql extension

* Removed AzureBlobProvider, removed AzureBlobService feature

* renamed blob to azureblob, converted thenable to promise

* Simplify API

* fixes

* docs update, blob to azureblob update

* UI design first commit

* Detected Managed Instance, trying to script backup to url

* azure subscription api added, but ADS crashes

* Created url dialog component and added link account

* Changed backup component UI logic

* Changed b/r UI, added restore from URL, detected MI from restore component

* Removed mocked and added real Azure API, changed RestoreDialog UI

* Added file fetching API

* added create sas RPC call

* Backup to url works now

* Fixed some bugs

* Moved createSas RPC to the BlobService

* Relocated createSas RPC from sql-dataprotocolclient to the mssql

* Rebase createSas changed to the backupRestoreManagedInstance

* PR comments fix

* Enabled backup to url for gov clouds

* Replaced anchor element with Link class

* Fixed pick azure account logic

* Removed duplicates from eslintrc

* Fixed url browser dialog

* Fixed restore UI, disabled url empty url browser dropdowns, fixed backup OK button

* bumped sts version

* bumped sts version

* Fix config

* Fixed URL browser dialog UX

* Backup and restore dialog fix

* Referencing azure resource types directly

* Scoped url browser dialog css classes

* Made the url browser dialog field a local variable

* moved url browser files from fileBrowser to the urlBrowser folder

* Changed deviceType from number to enum

* Added all device type options

* Moved mssql

* Added MI backup button comment

* Removed unhelpful comment

* Revert differential copy only backup mistake

* Renamed azurebrowser to urlBrowserDialog

* Localize create sas button label

* Removed unnecessary spinner

* Use UTC date instead of locale date

* Removed * and added required flag

* Use async instead of nested thens

* Added target database tooltip

* Using deferred promise instead of event emitter

* Added error handling to the url browser dialog

* Registered backup component elements

* Register backup component listeners

* Removed redundant setDefaultBackupPaths call

* Added setBackupPathList docs

* Add return types

* Remove code from comment

* Register restore dialog elements

* Register restore dialog listeners

* Pass engine edition enum instead of boolean

* Capitalize enum values

* DatabaseEngineEdition fix

* Use DeviceType instead of number

* Use deferred pointer

* Add new ModalDialogName

* Use constructor fields

* Register URL browser dialog components

* Remove unnecessary helper function

* nextYear function doc and move

* split registerListeners method

* showDialog returns promise

* Backup device type comment

* Pass aria label through constructor

* Fix backup button

* Remove comment

* Comment unsupported MI backup options

* Remove one liner helper function

* Restore dialog methods return types

* Remove comment

* JS doc format

* Renamed UrlBrowserDialog to BackupRestoreUrlBrowserDialog

* Moved MediaDeviceType, added PhisicalDeviceType

* Reorder and rename physical device type

* remove extra spaces

Co-authored-by: chgagnon <chgagnon@microsoft.com>
This commit is contained in:
Nemanja Milovančević
2022-05-11 20:01:06 +02:00
committed by GitHub
parent d38dcc853d
commit 65ef41d53d
24 changed files with 1154 additions and 162 deletions

View File

@@ -0,0 +1,32 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.url-browser-dialog {
height: 100%;
padding-top: 12px;
padding-left: 12px;
padding-right: 12px;
box-sizing: border-box;
}
.url-browser-dialog .url-table-content {
width: 100%;
}
.url-browser-dialog .option-section {
padding-top: 10px;
height: 90px;
box-sizing: border-box;
}
.url-browser-dialog .url-input-label {
width: 50px;
padding-bottom: 5px;
}
.url-browser-dialog .url-input-box {
width: 200px;
padding-bottom: 5px;
}

View File

@@ -0,0 +1,450 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/urlBrowserDialog';
import { Button } from 'sql/base/browser/ui/button/button';
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox';
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox';
import * as DialogHelper from 'sql/workbench/browser/modal/dialogHelper';
import { HideReason, Modal } from 'sql/workbench/browser/modal/modal';
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { localize } from 'vs/nls';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { attachButtonStyler, attachInputBoxStyler, attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
import * as DOM from 'vs/base/browser/dom';
import * as strings from 'vs/base/common/strings';
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { ILogService } from 'vs/platform/log/common/log';
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfigurationService';
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
import { attachModalDialogStyler } from 'sql/workbench/common/styler';
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
import { Account } from 'azdata';
import { IAccountManagementService } from 'sql/platform/accounts/common/interfaces';
import { IAzureAccountService } from 'sql/platform/azureAccount/common/azureAccountService';
import { azureResource } from 'azurecore';
import { IAzureBlobService } from 'sql/platform/azureBlob/common/azureBlobService';
import { Link } from 'vs/platform/opener/browser/link';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Deferred } from 'sql/base/common/promise';
/**
* This function adds one year to the current date and returns it in the UTC format.
* It's used to pass an expiration date argument to the create shared access signature RPC.
* It returns the date in the UTC format for locale time zone independence.
* @returns next year's UTC date
*/
function nextYear(): string {
const today = new Date();
const nextYear = new Date(today.getFullYear() + 1, today.getMonth(), today.getDate());
return nextYear.toUTCString();
}
export class BackupRestoreUrlBrowserDialog extends Modal {
private _accounts: Account[];
private _selectedAccount: Account;
private _subscriptions: azureResource.AzureResourceSubscription[];
private _selectedSubscription: azureResource.AzureResourceSubscription;
private _storageAccounts: azureResource.AzureGraphResource[];
private _selectedStorageAccount: azureResource.AzureGraphResource;
private _blobContainers: azureResource.BlobContainer[];
private _selectedBlobContainer: azureResource.BlobContainer;
private _backupFiles: azureResource.Blob[];
private _ownerUri: string;
private _body: HTMLElement;
private _accountSelectorBox: SelectBox;
private _tenantSelectorBox: SelectBox;
private _subscriptionSelectorBox: SelectBox;
private _storageAccountSelectorBox: SelectBox;
private _blobContainerSelectorBox: SelectBox;
private _sasInputBox: InputBox;
private _sasButton: Button;
private _backupFileInputBox: InputBox;
private _backupFileSelectorBox: SelectBox;
private _okButton: Button;
private _cancelButton: Button;
public onOk: Deferred<string> | undefined = new Deferred();
constructor(title: string,
private _restoreDialog: boolean,
private _defaultBackupName: string,
@ILayoutService layoutService: ILayoutService,
@IThemeService themeService: IThemeService,
@IContextViewService private _contextViewService: IContextViewService,
@IAdsTelemetryService telemetryService: IAdsTelemetryService,
@IContextKeyService contextKeyService: IContextKeyService,
@IClipboardService clipboardService: IClipboardService,
@ILogService logService: ILogService,
@ITextResourcePropertiesService textResourcePropertiesService: ITextResourcePropertiesService,
@IAccountManagementService private _accountManagementService: IAccountManagementService,
@IAzureAccountService private _azureAccountService: IAzureAccountService,
@IAzureBlobService private _blobService: IAzureBlobService,
@IInstantiationService private _instantiationService: IInstantiationService
) {
super(title, TelemetryKeys.ModalDialogName.UrlBrowser, telemetryService, layoutService, clipboardService, themeService, logService, textResourcePropertiesService, contextKeyService, { dialogStyle: 'flyout', hasTitleIcon: false, hasBackButton: true, hasSpinner: true });
}
protected layout(height?: number): void {
}
protected renderBody(container: HTMLElement) {
this._body = DOM.append(container, DOM.$('.url-browser-dialog'));
}
public override render() {
super.render();
attachModalDialogStyler(this, this._themeService);
if (this.backButton) {
this._register(this.backButton.onDidClick(() => {
this.close();
}));
this._register(attachButtonStyler(this.backButton, this._themeService, { buttonBackground: SIDE_BAR_BACKGROUND, buttonHoverBackground: SIDE_BAR_BACKGROUND }));
}
let tableContainer: HTMLElement = DOM.append(DOM.append(this._body, DOM.$('.option-section')), DOM.$('table.url-table-content'));
tableContainer.setAttribute('role', 'presentation');
let azureAccountLabel = localize('backupRestoreUrlBrowserDialog.account', "Azure Account");
this._accountSelectorBox = this._register(new SelectBox([''], '', this._contextViewService, null, { ariaLabel: azureAccountLabel }));
this._accountSelectorBox.disable();
let accountSelector = DialogHelper.appendRow(tableContainer, azureAccountLabel, 'url-input-label', 'url-input-box', null, true);
DialogHelper.appendInputSelectBox(accountSelector, this._accountSelectorBox);
this._accountManagementService.getAccounts().then((accounts) => this.setAccountSelectorBoxOptions(accounts)).catch((err) => {
this.setAccountSelectorBoxOptions([]);
onUnexpectedError(err);
});
let linkAccountText = localize('backupRestoreUrlBrowserDialog.linkAccount', "Link account");
let linkAccountButton = DialogHelper.appendRow(tableContainer, '', 'url-input-label', 'url-input-box');
const linkAccount: Link = this._register(this._instantiationService.createInstance(Link,
{
label: linkAccountText,
title: linkAccountText,
href: ''
},
{
opener: async (href: string) => {
await this._accountManagementService.openAccountListDialog();
this._accountManagementService.getAccounts().then((accounts) => this.setAccountSelectorBoxOptions(accounts)).catch((err) => {
this.setAccountSelectorBoxOptions([]);
onUnexpectedError(err);
});
}
}
));
linkAccountButton.appendChild(linkAccount.el);
let tenantLabel = localize('backupRestoreUrlBrowserDialog.tenant', "Azure AD Tenant");
this._tenantSelectorBox = this._register(new SelectBox([], '', this._contextViewService, null, { ariaLabel: tenantLabel }));
this._tenantSelectorBox.disable();
let tenantSelector = DialogHelper.appendRow(tableContainer, tenantLabel, 'url-input-label', 'url-input-box', null, true);
DialogHelper.appendInputSelectBox(tenantSelector, this._tenantSelectorBox);
let subscriptionLabel = localize('backupRestoreUrlBrowserDialog.subscription', "Azure subscription");
this._subscriptionSelectorBox = this._register(new SelectBox([], '', this._contextViewService, null, { ariaLabel: subscriptionLabel }));
this._subscriptionSelectorBox.disable();
let subscriptionSelector = DialogHelper.appendRow(tableContainer, subscriptionLabel, 'url-input-label', 'url-input-box', null, true);
DialogHelper.appendInputSelectBox(subscriptionSelector, this._subscriptionSelectorBox);
let storageAccountLabel = localize('backupRestoreUrlBrowserDialog.storageAccount', "Storage account");
this._storageAccountSelectorBox = this._register(new SelectBox([], '', this._contextViewService, null, { ariaLabel: storageAccountLabel }));
this._storageAccountSelectorBox.disable();
let storageAccountSelector = DialogHelper.appendRow(tableContainer, storageAccountLabel, 'url-input-label', 'url-input-box', null, true);
DialogHelper.appendInputSelectBox(storageAccountSelector, this._storageAccountSelectorBox);
let blobContainerLabel = localize('backupRestoreUrlBrowserDialog.blobContainer', "Blob container");
this._blobContainerSelectorBox = this._register(new SelectBox([], '', this._contextViewService, null, { ariaLabel: blobContainerLabel }));
this._blobContainerSelectorBox.disable();
let blobContainerSelector = DialogHelper.appendRow(tableContainer, blobContainerLabel, 'url-input-label', 'url-input-box', null, true);
DialogHelper.appendInputSelectBox(blobContainerSelector, this._blobContainerSelectorBox);
let sharedAccessSignatureLabel = localize('backupRestoreUrlBrowserDialog.sharedAccessSignature', "Shared access signature generated");
let sasInput = DialogHelper.appendRow(tableContainer, sharedAccessSignatureLabel, 'url-input-label', 'url-input-box', null, true);
this._sasInputBox = this._register(new InputBox(sasInput, this._contextViewService, { flexibleHeight: true }));
this._sasInputBox.disable();
this._register(this._sasInputBox.onDidChange(() => this.enableOkButton()));
let sasButtonContainer = DialogHelper.appendRow(tableContainer, '', 'url-input-label', 'url-input-box');
let sasButtonLabel = localize('backupRestoreUrlBrowserDialog.sharedAccessSignatureButton', "Create Credentials");
this._sasButton = this._register(new Button(sasButtonContainer, { title: sasButtonLabel }));
this._sasButton.label = sasButtonLabel;
this._sasButton.title = sasButtonLabel;
this._register(this._sasButton.onDidClick(e => this.generateSharedAccessSignature()));
let backupFileLabel = localize('backupRestoreUrlBrowserDialog.backupFile', "Backup file");
if (this._restoreDialog) {
this._backupFileSelectorBox = this._register(new SelectBox([], '', this._contextViewService, null, { ariaLabel: backupFileLabel }));
let backupFileSelector = DialogHelper.appendRow(tableContainer, backupFileLabel, 'url-input-label', 'url-input-box', null, true);
DialogHelper.appendInputSelectBox(backupFileSelector, this._backupFileSelectorBox);
this._backupFileSelectorBox.setOptions([]);
this._backupFileSelectorBox.disable();
} else {
let fileInput = DialogHelper.appendRow(tableContainer, backupFileLabel, 'url-input-label', 'url-input-box', null, true);
this._backupFileInputBox = this._register(new InputBox(fileInput, this._contextViewService, { flexibleHeight: true }));
this._backupFileInputBox.value = this._defaultBackupName;
}
this._okButton = this.addFooterButton(localize('fileBrowser.ok', "OK"), () => this.ok());
this._okButton.enabled = false;
this._cancelButton = this.addFooterButton(localize('fileBrowser.discard', "Discard"), () => this.close(), 'right', true);
this.registerListeners();
this.registerThemeStylers();
}
private setAccountSelectorBoxOptions(accounts: Account[]) {
this._accounts = accounts.filter(account => !account.isStale);
const accountDisplayNames: string[] = this._accounts.map(account => account.displayInfo.displayName);
this._accountSelectorBox.setOptions(accountDisplayNames);
this._accountSelectorBox.select(0);
if (this._accounts.length === 0) {
this._accountSelectorBox.disable();
this.onTenantSelectorBoxChanged(0);
} else {
this._accountSelectorBox.enable();
}
}
private onAccountSelectorBoxChanged(checkedAccount: number) {
if (this._accounts.length !== 0) {
this._selectedAccount = this._accounts[checkedAccount];
const tenants = this._selectedAccount.properties.tenants;
const tenantsDisplayNames = tenants.map(tenant => tenant.displayName);
this._tenantSelectorBox.setOptions(tenantsDisplayNames);
this._tenantSelectorBox.select(0);
if (tenantsDisplayNames.length === 0) {
this._tenantSelectorBox.disable();
} else {
this._tenantSelectorBox.enable();
}
} else {
this._tenantSelectorBox.setOptions([]);
this._tenantSelectorBox.select(0);
this._tenantSelectorBox.disable();
}
}
private onTenantSelectorBoxChanged(checkedTenant: number) {
if (this._accounts.length !== 0) {
this._azureAccountService.getSubscriptions(this._selectedAccount)
.then(getSubscriptionResult => this.setSubscriptionsSelectorBoxOptions(getSubscriptionResult.subscriptions))
.catch(getSubscriptionResult => {
this.setSubscriptionsSelectorBoxOptions([]);
onUnexpectedError(getSubscriptionResult.errors);
});
} else {
this._tenantSelectorBox.setOptions([]);
this._tenantSelectorBox.disable();
this.setSubscriptionsSelectorBoxOptions([]);
}
}
private setSubscriptionsSelectorBoxOptions(subscriptions: azureResource.AzureResourceSubscription[]) {
this._subscriptions = subscriptions;
const subscriptionDisplayNames: string[] = subscriptions.map(subscription => subscription.name);
this._subscriptionSelectorBox.setOptions(subscriptionDisplayNames);
this._subscriptionSelectorBox.select(0);
if (this._subscriptions.length === 0) {
this._subscriptionSelectorBox.disable();
} else {
this._subscriptionSelectorBox.enable();
}
}
private onSubscriptionSelectorBoxChanged(checkedSubscription: number) {
if (this._subscriptions.length !== 0) {
this._selectedSubscription = this._subscriptions[checkedSubscription];
this._azureAccountService.getStorageAccounts(this._selectedAccount, [this._selectedSubscription])
.then(getStorageAccountsResult => this.setStorageAccountSelectorBoxOptions(getStorageAccountsResult.resources))
.catch(getStorageAccountsResult => {
this.setStorageAccountSelectorBoxOptions([]);
onUnexpectedError(getStorageAccountsResult.errors);
});
} else {
this.setStorageAccountSelectorBoxOptions([]);
}
}
private setStorageAccountSelectorBoxOptions(storageAccounts: azureResource.AzureGraphResource[]) {
this._storageAccounts = storageAccounts;
const storageAccountDisplayNames: string[] = this._storageAccounts.map(storageAccount => storageAccount.name);
this._storageAccountSelectorBox.setOptions(storageAccountDisplayNames);
this._storageAccountSelectorBox.select(0);
if (storageAccounts.length === 0) {
this._storageAccountSelectorBox.disable();
} else {
this._storageAccountSelectorBox.enable();
}
}
private onStorageAccountSelectorBoxChanged(checkedStorageAccount: number) {
if (this._storageAccounts.length !== 0) {
this._selectedStorageAccount = this._storageAccounts[checkedStorageAccount];
this._azureAccountService.getBlobContainers(this._selectedAccount, this._selectedSubscription, this._selectedStorageAccount)
.then(getBlobContainersResult => this.setBlobContainersSelectorBoxOptions(getBlobContainersResult.blobContainers))
.catch(getBlobContainersResult => {
this.setBlobContainersSelectorBoxOptions([]);
onUnexpectedError(getBlobContainersResult.errors);
});
} else {
this.setBlobContainersSelectorBoxOptions([]);
}
}
private setBlobContainersSelectorBoxOptions(blobContainers: azureResource.BlobContainer[]) {
this._blobContainers = blobContainers;
const blobContainersDisplayNames: string[] = this._blobContainers.map(blobContainer => blobContainer.name);
this._blobContainerSelectorBox.setOptions(blobContainersDisplayNames);
this._blobContainerSelectorBox.select(0);
if (this._blobContainers.length === 0) {
this._blobContainerSelectorBox.disable();
} else {
this._blobContainerSelectorBox.enable();
}
}
private onBlobContainersSelectorBoxChanged(checkedBlobContainer: number) {
this._sasInputBox.value = '';
if (this._restoreDialog) {
if (this._blobContainers.length !== 0) {
this._selectedBlobContainer = this._blobContainers[checkedBlobContainer];
this._azureAccountService.getBlobs(this._selectedAccount, this._selectedSubscription, this._selectedStorageAccount, this._selectedBlobContainer.name, true)
.then(getBlobsResult => this.setBackupFilesOptions(getBlobsResult.blobs))
.catch(getBlobsResult => {
this.setBackupFilesOptions([]);
onUnexpectedError(getBlobsResult.errors);
});
} else {
this.setBackupFilesOptions([]);
}
}
this.enableCreateCredentialsButton();
}
private setBackupFilesOptions(blobs: azureResource.Blob[]) {
this._backupFiles = blobs;
const backupFilesDisplayNames: string[] = this._backupFiles.map(backupFile => backupFile.name);
this._backupFileSelectorBox.setOptions(backupFilesDisplayNames);
this._backupFileSelectorBox.select(0);
if (this._backupFiles.length === 0) {
this._backupFileSelectorBox.disable();
} else {
this._backupFileSelectorBox.enable();
}
}
public open(ownerUri: string,
expandPath: string,
fileFilters: [{ label: string, filters: string[] }],
fileValidationServiceType: string,
): void {
this._ownerUri = ownerUri;
this.enableOkButton();
this.enableCreateCredentialsButton();
this.show();
}
/* enter key */
protected override onAccept() {
let selectedValue = this._sasInputBox.value;
if (this._okButton.enabled === true && selectedValue !== '') {
this.ok();
}
}
private enableOkButton() {
if (strings.isFalsyOrWhitespace(this._blobContainerSelectorBox.value) || strings.isFalsyOrWhitespace(this._sasInputBox.value) || (this._restoreDialog && strings.isFalsyOrWhitespace(this._blobContainerSelectorBox.value)) || (!this._restoreDialog && strings.isFalsyOrWhitespace(this._backupFileInputBox.value))) {
this._okButton.enabled = false;
} else {
this._okButton.enabled = true;
}
}
private enableCreateCredentialsButton() {
if (strings.isFalsyOrWhitespace(this._blobContainerSelectorBox.label)) {
this._sasButton.enabled = false;
} else {
this._sasButton.enabled = true;
}
}
private ok() {
let returnValue = '';
if (this._restoreDialog) {
returnValue = `https://${this._storageAccountSelectorBox.value}.blob${this._selectedAccount.properties.providerSettings.settings.azureStorageResource.endpointSuffix}/${this._blobContainerSelectorBox.value}/${this._backupFileSelectorBox.value}`;
} else {
returnValue = `https://${this._storageAccountSelectorBox.value}.blob${this._selectedAccount.properties.providerSettings.settings.azureStorageResource.endpointSuffix}/${this._blobContainerSelectorBox.value}/${this._backupFileInputBox.value}`;
}
this.onOk.resolve(returnValue);
this.close('ok');
}
private close(hideReason: HideReason = 'close'): void {
this.hide(hideReason);
}
private async generateSharedAccessSignature() {
this.spinner = true;
const blobContainerUri = `https://${this._storageAccountSelectorBox.value}.blob${this._selectedAccount.properties.providerSettings.settings.azureStorageResource.endpointSuffix}/${this._blobContainerSelectorBox.value}`;
const getStorageAccountAccessKeyResult = await this._azureAccountService.getStorageAccountAccessKey(this._selectedAccount, this._selectedSubscription, this._selectedStorageAccount);
const key1 = getStorageAccountAccessKeyResult.keyName1;
const createSasResult = await this._blobService.createSas(this._ownerUri, blobContainerUri, key1, this._selectedStorageAccount.name, nextYear());
const sas = createSasResult.sharedAccessSignature;
this._sasInputBox.value = sas;
this.spinner = false;
}
private registerListeners(): void {
this._register(this._accountSelectorBox.onDidSelect(e => this.onAccountSelectorBoxChanged(e.index)));
this._register(this._tenantSelectorBox.onDidSelect(selectedTenant => this.onTenantSelectorBoxChanged(selectedTenant.index)));
this._register(this._subscriptionSelectorBox.onDidSelect(selectedSubscription => this.onSubscriptionSelectorBoxChanged(selectedSubscription.index)));
this._register(this._storageAccountSelectorBox.onDidSelect(selectedStorageAccount => this.onStorageAccountSelectorBoxChanged(selectedStorageAccount.index)));
this._register(this._blobContainerSelectorBox.onDidSelect(selectedBlobContainer => {
this.onBlobContainersSelectorBoxChanged(selectedBlobContainer.index);
this.enableOkButton();
}));
if (this._backupFileInputBox) {
this._register(this._backupFileInputBox.onDidChange(e => this.enableOkButton()));
}
if (this._backupFileSelectorBox) {
this._register(this._backupFileSelectorBox.onDidSelect(e => this.enableOkButton()));
}
}
private registerThemeStylers(): void {
this._register(attachSelectBoxStyler(this._tenantSelectorBox, this._themeService));
this._register(attachSelectBoxStyler(this._accountSelectorBox, this._themeService));
this._register(attachSelectBoxStyler(this._subscriptionSelectorBox, this._themeService));
this._register(attachSelectBoxStyler(this._storageAccountSelectorBox, this._themeService));
this._register(attachSelectBoxStyler(this._blobContainerSelectorBox, this._themeService));
this._register(attachInputBoxStyler(this._sasInputBox, this._themeService));
if (this._backupFileInputBox) {
this._register(attachInputBoxStyler(this._backupFileInputBox, this._themeService));
}
if (this._backupFileSelectorBox) {
this._register(attachSelectBoxStyler(this._backupFileSelectorBox, this._themeService));
}
this._register(attachButtonStyler(this._sasButton, this._themeService));
this._register(attachButtonStyler(this._okButton, this._themeService));
this._register(attachButtonStyler(this._cancelButton, this._themeService));
}
}

View File

@@ -0,0 +1,37 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { BackupRestoreUrlBrowserDialog } from 'sql/workbench/services/backupRestoreUrlBrowser/browser/urlBrowserDialog';
import { IBackupRestoreUrlBrowserDialogService } from 'sql/workbench/services/backupRestoreUrlBrowser/common/urlBrowserDialogService';
import { localize } from 'vs/nls';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
/**
* Url browser dialog service
*/
export class BackupRestoreUrlBrowserDialogService implements IBackupRestoreUrlBrowserDialogService {
_serviceBrand: undefined;
constructor(
@IInstantiationService private _instantiationService: IInstantiationService
) {
}
public showDialog(ownerUri: string,
expandPath: string,
fileFilters: [{ label: string, filters: string[] }],
fileValidationServiceType: string,
isWide: boolean,
isRestoreDialog: boolean,
defaultBackupName: string
): Promise<string> {
const backupRestoreUrlBrowserDialog = this._instantiationService.createInstance(BackupRestoreUrlBrowserDialog, localize('filebrowser.selectBlob', "Select a blob"), isRestoreDialog, defaultBackupName);
backupRestoreUrlBrowserDialog.render();
backupRestoreUrlBrowserDialog.setWide(isWide);
backupRestoreUrlBrowserDialog.open(ownerUri, expandPath, fileFilters, fileValidationServiceType);
return backupRestoreUrlBrowserDialog.onOk;
}
}

View File

@@ -0,0 +1,21 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
export const IBackupRestoreUrlBrowserDialogService = createDecorator<IBackupRestoreUrlBrowserDialogService>('backupRestoreUrlBrowserDialogService');
export interface IBackupRestoreUrlBrowserDialogService {
_serviceBrand: undefined;
/**
* Show url browser dialog
*/
showDialog(ownerUri: string,
expandPath: string,
fileFilters: { label: string, filters: string[] }[],
fileValidationServiceType: string,
isWide: boolean,
isRestoreDialog: boolean,
defaultBackupName: string): Promise<string>;
}