mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-02 17:23:40 -05:00
move code from parts to contrib (#8319)
This commit is contained in:
176
src/sql/workbench/contrib/backup/browser/backup.component.html
Normal file
176
src/sql/workbench/contrib/backup/browser/backup.component.html
Normal file
@@ -0,0 +1,176 @@
|
||||
<!--
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
-->
|
||||
<form class="angular-form" #myForm="ngForm" (ngSubmit)="onSubmit(f)">
|
||||
<div class="angular-modal-body" style="display: flex; flex-direction: column;">
|
||||
<div class="angular-modal-body-content">
|
||||
<div class="dialog-label">
|
||||
{{localizedStrings.BACKUP_NAME}}
|
||||
</div>
|
||||
<div class="input-divider" #backupsetName>
|
||||
</div>
|
||||
<div class="dialog-label">
|
||||
{{localizedStrings.RECOVERY_MODEL}}
|
||||
</div>
|
||||
<div class="input-divider" #recoveryModelContainer>
|
||||
</div>
|
||||
<div class="dialog-label">
|
||||
{{localizedStrings.BACKUP_TYPE}}
|
||||
</div>
|
||||
<div class="input-divider" #backupTypeContainer>
|
||||
</div>
|
||||
<div class="input-divider check" #copyOnlyContainer>
|
||||
</div>
|
||||
<div class="dialog-label">
|
||||
{{localizedStrings.BACKUP_DEVICE}}
|
||||
</div>
|
||||
<div class="backup-path-list">
|
||||
<div #pathContainer>
|
||||
</div>
|
||||
</div>
|
||||
<table class="backup-path-table">
|
||||
<tr>
|
||||
<td style="padding-left: 0px; padding-right: 0px;">
|
||||
<div class="backup-path-button" #addPathContainer></div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="backup-path-button" #removePathContainer></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<div class="advanced-main-header" #advancedOptionContainer>
|
||||
<div class="advanced-main-body" #advancedOptionBodyContainer>
|
||||
<!-- Compression -->
|
||||
<div class="dialog-label advanced-header">
|
||||
{{localizedStrings.COMPRESSION}}
|
||||
</div>
|
||||
<div class="indent">
|
||||
<div class="dialog-label">
|
||||
{{localizedStrings.SET_BACKUP_COMPRESSION}}
|
||||
</div>
|
||||
<div class="dialog-label" #compressionContainer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Encryption -->
|
||||
<div class="dialog-label advanced-header">
|
||||
{{localizedStrings.ENCRYPTION}}
|
||||
</div>
|
||||
<div class="indent">
|
||||
<div class="option check" #encryptCheckContainer>
|
||||
</div>
|
||||
<div class="option" #encryptWarningContainer>
|
||||
<div class="sql icon warning">
|
||||
</div>
|
||||
<div class="warning-message">
|
||||
{{localizedStrings.NO_ENCRYPTOR_WARNING}}
|
||||
</div>
|
||||
</div>
|
||||
<div #encryptContainer>
|
||||
<div class="dialog-label">
|
||||
{{localizedStrings.ALGORITHM}}
|
||||
</div>
|
||||
<div class="dialog-label" #algorithmContainer>
|
||||
</div>
|
||||
<div class="dialog-label">
|
||||
{{localizedStrings.CERTIFICATE_OR_ASYMMETRIC_KEY}}
|
||||
</div>
|
||||
<div class="dialog-label" #encryptorContainer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Overwrite media -->
|
||||
<div id="media" class="dialog-label advanced-header">
|
||||
{{localizedStrings.MEDIA}}
|
||||
</div>
|
||||
<div role="radiogroup" aria-labelledby="media" class="radio-indent">
|
||||
<div class="option">
|
||||
<input role="radio" type="radio" name="media-option" value="no_format" [checked]="!isFormatChecked" (change)="onChangeMediaFormat()" [disabled]="isEncryptChecked" aria-labelledby="mediaOption"><span id="mediaOption">{{localizedStrings.MEDIA_OPTION}}</span>
|
||||
</div>
|
||||
<div role="radiogroup" aria-labelledby="mediaOption" style="margin-left:15px">
|
||||
<div class="option">
|
||||
<input role="radio" type="radio" name="existing-media" value="append" [(ngModel)]="selectedInitOption" [disabled]="isFormatChecked" aria-labelledby="existingMediaAppend"><span id="existingMediaAppend">{{localizedStrings.EXISTING_MEDIA_APPEND}}</span>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input role="radio" type="radio" name="existing-media" value="overwrite" [(ngModel)]="selectedInitOption" [disabled]="isFormatChecked" aria-labelledby="existingMediaOverwrite"><span id="existingMediaOverwrite">{{localizedStrings.EXISTING_MEDIA_OVERWRITE}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="option">
|
||||
<input role="radio" type="radio" name="media-option" value="format" [checked]="isFormatChecked" (change)="onChangeMediaFormat()" aria-labelledby="mediaOptionFormat"><span id="mediaOptionFormat">{{localizedStrings.MEDIA_OPTION_FORMAT}}</span>
|
||||
</div>
|
||||
<div style="margin-left: 22px">
|
||||
<div class="dialog-label">
|
||||
{{localizedStrings.NEW_MEDIA_SET_NAME}}
|
||||
</div>
|
||||
<div class="dialog-label" #mediaName>
|
||||
</div>
|
||||
<div class="dialog-label">
|
||||
{{localizedStrings.NEW_MEDIA_SET_DESCRIPTION}}
|
||||
</div>
|
||||
<div class="dialog-label" #mediaDescription>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Transaction log -->
|
||||
<div id="transactionLog" class="dialog-label advanced-header">
|
||||
{{localizedStrings.TRANSACTION_LOG}}
|
||||
</div>
|
||||
<div role="radiogroup" aria-labelledby="transactionLog" class="radio-indent">
|
||||
<div class="option">
|
||||
<input role="radio" type="radio" name="t-log" value="truncate" [checked]="isTruncateChecked" (change)="onChangeTlog()" [disabled]="disableTlog" aria-labelledby="truncateTransaction"><span id="truncateTransaction">{{localizedStrings.TRUNCATE_TRANSACTION_LOG}}</span>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input role="radio" type="radio" name="t-log" value="taillog" [checked]="isTaillogChecked" (change)="onChangeTlog()" [disabled]="disableTlog" aria-labelledby="backupTail"><span id="backupTail">{{localizedStrings.BACKUP_TAIL}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Reliability -->
|
||||
<div class="dialog-label advanced-header">
|
||||
{{localizedStrings.RELIABILITY}}
|
||||
</div>
|
||||
<div class="indent">
|
||||
<div class="option check" #checksumContainer>
|
||||
</div>
|
||||
<div class="option check" #verifyContainer>
|
||||
</div>
|
||||
<div class="option check" #continueOnErrorContainer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Backup expiration -->
|
||||
<div class="dialog-label advanced-header">
|
||||
{{localizedStrings.EXPIRATION}}
|
||||
</div>
|
||||
<div class="indent">
|
||||
<div class="dialog-label">
|
||||
{{localizedStrings.SET_BACKUP_RETAIN_DAYS}}
|
||||
</div>
|
||||
<div class="dialog-label">
|
||||
<div #backupDaysContainer></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer" #modalFooterContainer>
|
||||
<div class="codicon in-progress" #inProgressContainer></div>
|
||||
<div class="right-footer">
|
||||
<div class="footer-button" #scriptButtonContainer>
|
||||
</div>
|
||||
<div class="footer-button" #backupButtonContainer>
|
||||
</div>
|
||||
<div class="footer-button" #cancelButtonContainer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
914
src/sql/workbench/contrib/backup/browser/backup.component.ts
Normal file
914
src/sql/workbench/contrib/backup/browser/backup.component.ts
Normal file
@@ -0,0 +1,914 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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/backupDialog';
|
||||
|
||||
import { ElementRef, Component, Inject, forwardRef, ViewChild, ChangeDetectorRef } from '@angular/core';
|
||||
import { Button } from 'sql/base/browser/ui/button/button';
|
||||
import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox';
|
||||
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox';
|
||||
import { ListBox } from 'sql/base/browser/ui/listBox/listBox';
|
||||
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox';
|
||||
import { attachButtonStyler, attachListBoxStyler, attachInputBoxStyler, attachSelectBoxStyler, attachCheckboxStyler } from 'sql/platform/theme/common/styler';
|
||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||
import * as BackupConstants from 'sql/workbench/contrib/backup/common/constants';
|
||||
import { IBackupService, TaskExecutionMode } from 'sql/platform/backup/common/backupService';
|
||||
import * as FileValidationConstants from 'sql/workbench/services/fileBrowser/common/fileValidationServiceConstants';
|
||||
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
||||
import { IFileBrowserDialogController } from 'sql/workbench/services/fileBrowser/common/fileBrowserDialogController';
|
||||
import { IBackupUiService } from 'sql/workbench/services/backup/common/backupUiService';
|
||||
import * as cr from 'vs/platform/theme/common/colorRegistry';
|
||||
|
||||
import { MessageType } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
import { localize } from 'vs/nls';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { ITheme } from 'vs/platform/theme/common/themeService';
|
||||
import { AngularDisposable } from 'sql/base/browser/lifecycle';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
|
||||
export const BACKUP_SELECTOR: string = 'backup-component';
|
||||
|
||||
export class RestoreItemSource {
|
||||
restoreItemLocation: string;
|
||||
restoreItemDeviceType: number;
|
||||
isLogicalDevice: boolean;
|
||||
|
||||
constructor(location: any) {
|
||||
this.restoreItemDeviceType = location.restoreItemDeviceType;
|
||||
this.restoreItemLocation = location.restoreItemLocation;
|
||||
this.isLogicalDevice = location.isLogicalDevice;
|
||||
}
|
||||
}
|
||||
|
||||
interface MssqlBackupInfo {
|
||||
ownerUri: string;
|
||||
databaseName: string;
|
||||
backupType: number;
|
||||
backupComponent: number;
|
||||
backupDeviceType: number;
|
||||
selectedFiles: string;
|
||||
backupsetName: string;
|
||||
selectedFileGroup: { [path: string]: string };
|
||||
|
||||
// List of {key: backup path, value: device type}
|
||||
backupPathDevices: { [path: string]: number };
|
||||
backupPathList: [string];
|
||||
isCopyOnly: boolean;
|
||||
formatMedia: boolean;
|
||||
initialize: boolean;
|
||||
skipTapeHeader: boolean;
|
||||
mediaName: string;
|
||||
mediaDescription: string;
|
||||
checksum: boolean;
|
||||
continueAfterError: boolean;
|
||||
logTruncation: boolean;
|
||||
tailLogBackup: boolean;
|
||||
retainDays: number;
|
||||
compressionOption: number;
|
||||
verifyBackupRequired: boolean;
|
||||
encryptionAlgorithm: number;
|
||||
encryptorType: number;
|
||||
encryptorName: string;
|
||||
}
|
||||
|
||||
const LocalizedStrings = {
|
||||
BACKUP_NAME: localize('backup.backupName', "Backup name"),
|
||||
RECOVERY_MODEL: localize('backup.recoveryModel', "Recovery model"),
|
||||
BACKUP_TYPE: localize('backup.backupType', "Backup type"),
|
||||
BACKUP_DEVICE: localize('backup.backupDevice', "Backup files"),
|
||||
ALGORITHM: localize('backup.algorithm', "Algorithm"),
|
||||
CERTIFICATE_OR_ASYMMETRIC_KEY: localize('backup.certificateOrAsymmetricKey', "Certificate or Asymmetric key"),
|
||||
MEDIA: localize('backup.media', "Media"),
|
||||
MEDIA_OPTION: localize('backup.mediaOption', "Backup to the existing media set"),
|
||||
MEDIA_OPTION_FORMAT: localize('backup.mediaOptionFormat', "Backup to a new media set"),
|
||||
EXISTING_MEDIA_APPEND: localize('backup.existingMediaAppend', "Append to the existing backup set"),
|
||||
EXISTING_MEDIA_OVERWRITE: localize('backup.existingMediaOverwrite', "Overwrite all existing backup sets"),
|
||||
NEW_MEDIA_SET_NAME: localize('backup.newMediaSetName', "New media set name"),
|
||||
NEW_MEDIA_SET_DESCRIPTION: localize('backup.newMediaSetDescription', "New media set description"),
|
||||
CHECKSUM_CONTAINER: localize('backup.checksumContainer', "Perform checksum before writing to media"),
|
||||
VERIFY_CONTAINER: localize('backup.verifyContainer', "Verify backup when finished"),
|
||||
CONTINUE_ON_ERROR_CONTAINER: localize('backup.continueOnErrorContainer', "Continue on error"),
|
||||
EXPIRATION: localize('backup.expiration', "Expiration"),
|
||||
SET_BACKUP_RETAIN_DAYS: localize('backup.setBackupRetainDays', "Set backup retain days"),
|
||||
COPY_ONLY: localize('backup.copyOnly', "Copy-only backup"),
|
||||
ADVANCED_CONFIGURATION: localize('backup.advancedConfiguration', "Advanced Configuration"),
|
||||
COMPRESSION: localize('backup.compression', "Compression"),
|
||||
SET_BACKUP_COMPRESSION: localize('backup.setBackupCompression', "Set backup compression"),
|
||||
ENCRYPTION: localize('backup.encryption', "Encryption"),
|
||||
TRANSACTION_LOG: localize('backup.transactionLog', "Transaction log"),
|
||||
TRUNCATE_TRANSACTION_LOG: localize('backup.truncateTransactionLog', "Truncate the transaction log"),
|
||||
BACKUP_TAIL: localize('backup.backupTail', "Backup the tail of the log"),
|
||||
RELIABILITY: localize('backup.reliability', "Reliability"),
|
||||
MEDIA_NAME_REQUIRED_ERROR: localize('backup.mediaNameRequired', "Media name is required"),
|
||||
NO_ENCRYPTOR_WARNING: localize('backup.noEncryptorWarning', "No certificate or asymmetric key is available")
|
||||
};
|
||||
|
||||
@Component({
|
||||
selector: BACKUP_SELECTOR,
|
||||
templateUrl: decodeURI(require.toUrl('./backup.component.html'))
|
||||
})
|
||||
export class BackupComponent extends AngularDisposable {
|
||||
@ViewChild('pathContainer', { read: ElementRef }) pathElement;
|
||||
@ViewChild('backupTypeContainer', { read: ElementRef }) backupTypeElement;
|
||||
@ViewChild('backupsetName', { read: ElementRef }) backupNameElement;
|
||||
@ViewChild('compressionContainer', { read: ElementRef }) compressionElement;
|
||||
@ViewChild('tlogOption', { read: ElementRef }) tlogOptionElement;
|
||||
@ViewChild('algorithmContainer', { read: ElementRef }) encryptionAlgorithmElement;
|
||||
@ViewChild('encryptorContainer', { read: ElementRef }) encryptorElement;
|
||||
@ViewChild('mediaName', { read: ElementRef }) mediaNameElement;
|
||||
@ViewChild('mediaDescription', { read: ElementRef }) mediaDescriptionElement;
|
||||
@ViewChild('recoveryModelContainer', { read: ElementRef }) recoveryModelElement;
|
||||
@ViewChild('backupDaysContainer', { read: ElementRef }) backupDaysElement;
|
||||
@ViewChild('backupButtonContainer', { read: ElementRef }) backupButtonElement;
|
||||
@ViewChild('cancelButtonContainer', { read: ElementRef }) cancelButtonElement;
|
||||
@ViewChild('addPathContainer', { read: ElementRef }) addPathElement;
|
||||
@ViewChild('removePathContainer', { read: ElementRef }) removePathElement;
|
||||
@ViewChild('copyOnlyContainer', { read: ElementRef }) copyOnlyElement;
|
||||
@ViewChild('encryptCheckContainer', { read: ElementRef }) encryptElement;
|
||||
@ViewChild('encryptContainer', { read: ElementRef }) encryptContainerElement;
|
||||
@ViewChild('verifyContainer', { read: ElementRef }) verifyElement;
|
||||
@ViewChild('checksumContainer', { read: ElementRef }) checksumElement;
|
||||
@ViewChild('continueOnErrorContainer', { read: ElementRef }) continueOnErrorElement;
|
||||
@ViewChild('encryptWarningContainer', { read: ElementRef }) encryptWarningElement;
|
||||
@ViewChild('inProgressContainer', { read: ElementRef }) inProgressElement;
|
||||
@ViewChild('modalFooterContainer', { read: ElementRef }) modalFooterElement;
|
||||
@ViewChild('scriptButtonContainer', { read: ElementRef }) scriptButtonElement;
|
||||
@ViewChild('advancedOptionContainer', { read: ElementRef }) advancedOptionElement;
|
||||
@ViewChild('advancedOptionBodyContainer', { read: ElementRef }) advancedOptionBodyElement;
|
||||
|
||||
private localizedStrings = LocalizedStrings;
|
||||
|
||||
private _uri: string;
|
||||
|
||||
private connection: IConnectionProfile;
|
||||
private databaseName: string;
|
||||
private defaultNewBackupFolder: string;
|
||||
private recoveryModel: string;
|
||||
private backupEncryptors;
|
||||
private containsBackupToUrl: boolean;
|
||||
|
||||
// UI element disable flag
|
||||
public disableTlog: boolean;
|
||||
|
||||
public selectedBackupComponent: string;
|
||||
private selectedFilesText: string;
|
||||
private selectedInitOption: string;
|
||||
private isTruncateChecked: boolean;
|
||||
private isTaillogChecked: boolean;
|
||||
private isFormatChecked: boolean;
|
||||
public isEncryptChecked: boolean;
|
||||
// Key: backup path, Value: device type
|
||||
private backupPathTypePairs: { [path: string]: number };
|
||||
|
||||
private compressionOptions = [BackupConstants.defaultCompression, BackupConstants.compressionOn, BackupConstants.compressionOff];
|
||||
private encryptionAlgorithms = [BackupConstants.aes128, BackupConstants.aes192, BackupConstants.aes256, BackupConstants.tripleDES];
|
||||
private existingMediaOptions = ['append', 'overwrite'];
|
||||
private backupTypeOptions: string[];
|
||||
|
||||
private backupTypeSelectBox: SelectBox;
|
||||
private backupNameBox: InputBox;
|
||||
private recoveryBox: InputBox;
|
||||
private backupRetainDaysBox: InputBox;
|
||||
private backupButton: Button;
|
||||
private cancelButton: Button;
|
||||
private scriptButton: Button;
|
||||
private addPathButton: Button;
|
||||
private removePathButton: Button;
|
||||
private pathListBox: ListBox;
|
||||
private compressionSelectBox: SelectBox;
|
||||
private algorithmSelectBox: SelectBox;
|
||||
private encryptorSelectBox: SelectBox;
|
||||
private mediaNameBox: InputBox;
|
||||
private mediaDescriptionBox: InputBox;
|
||||
private copyOnlyCheckBox: Checkbox;
|
||||
private encryptCheckBox: Checkbox;
|
||||
private verifyCheckBox: Checkbox;
|
||||
private checksumCheckBox: Checkbox;
|
||||
private continueOnErrorCheckBox: Checkbox;
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeDetectorRef: ChangeDetectorRef,
|
||||
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
|
||||
@Inject(IContextViewService) private contextViewService: IContextViewService,
|
||||
@Inject(IFileBrowserDialogController) private fileBrowserDialogService: IFileBrowserDialogController,
|
||||
@Inject(IBackupUiService) private _backupUiService: IBackupUiService,
|
||||
@Inject(IBackupService) private _backupService: IBackupService,
|
||||
@Inject(IClipboardService) private clipboardService: IClipboardService,
|
||||
@Inject(IConnectionManagementService) private connectionManagementService: IConnectionManagementService,
|
||||
) {
|
||||
super();
|
||||
this._backupUiService.onShowBackupEvent((param) => this.onGetBackupConfigInfo(param));
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
let self = this;
|
||||
this.addFooterButtons();
|
||||
|
||||
this.recoveryBox = new InputBox(this.recoveryModelElement.nativeElement, this.contextViewService, {
|
||||
placeholder: this.recoveryModel,
|
||||
ariaLabel: LocalizedStrings.RECOVERY_MODEL
|
||||
});
|
||||
// Set backup type
|
||||
this.backupTypeSelectBox = new SelectBox([], '', this.contextViewService, undefined, { ariaLabel: this.localizedStrings.BACKUP_TYPE });
|
||||
this.backupTypeSelectBox.render(this.backupTypeElement.nativeElement);
|
||||
|
||||
// Set copy-only check box
|
||||
this.copyOnlyCheckBox = new Checkbox(this.copyOnlyElement.nativeElement, {
|
||||
label: LocalizedStrings.COPY_ONLY,
|
||||
checked: false,
|
||||
onChange: (viaKeyboard) => { },
|
||||
ariaLabel: LocalizedStrings.COPY_ONLY
|
||||
});
|
||||
|
||||
// Encryption checkbox
|
||||
this.encryptCheckBox = new Checkbox(this.encryptElement.nativeElement, {
|
||||
label: LocalizedStrings.ENCRYPTION,
|
||||
checked: false,
|
||||
onChange: (viaKeyboard) => self.onChangeEncrypt(),
|
||||
ariaLabel: LocalizedStrings.ENCRYPTION
|
||||
});
|
||||
|
||||
// Verify backup checkbox
|
||||
this.verifyCheckBox = new Checkbox(this.verifyElement.nativeElement, {
|
||||
label: LocalizedStrings.VERIFY_CONTAINER,
|
||||
checked: false,
|
||||
onChange: (viaKeyboard) => { },
|
||||
ariaLabel: LocalizedStrings.VERIFY_CONTAINER
|
||||
});
|
||||
|
||||
// Perform checksum checkbox
|
||||
this.checksumCheckBox = new Checkbox(this.checksumElement.nativeElement, {
|
||||
label: LocalizedStrings.CHECKSUM_CONTAINER,
|
||||
checked: false,
|
||||
onChange: (viaKeyboard) => { },
|
||||
ariaLabel: LocalizedStrings.CHECKSUM_CONTAINER
|
||||
});
|
||||
|
||||
// Continue on error checkbox
|
||||
this.continueOnErrorCheckBox = new Checkbox(this.continueOnErrorElement.nativeElement, {
|
||||
label: LocalizedStrings.CONTINUE_ON_ERROR_CONTAINER,
|
||||
checked: false,
|
||||
onChange: (viaKeyboard) => { },
|
||||
ariaLabel: LocalizedStrings.CONTINUE_ON_ERROR_CONTAINER
|
||||
});
|
||||
|
||||
// Set backup name
|
||||
this.backupNameBox = new InputBox(this.backupNameElement.nativeElement, this.contextViewService, {
|
||||
ariaLabel: LocalizedStrings.BACKUP_NAME
|
||||
});
|
||||
|
||||
// Set backup path list
|
||||
this.pathListBox = new ListBox([], this.contextViewService);
|
||||
this.pathListBox.setAriaLabel(LocalizedStrings.BACKUP_DEVICE);
|
||||
this.pathListBox.onKeyDown(e => {
|
||||
if (this.pathListBox.selectedOptions.length > 0) {
|
||||
const key = e.keyCode;
|
||||
const ctrlOrCmd = e.ctrlKey || e.metaKey;
|
||||
|
||||
if (ctrlOrCmd && key === KeyCode.KEY_C) {
|
||||
let textToCopy = this.pathListBox.selectedOptions[0];
|
||||
for (let i = 1; i < this.pathListBox.selectedOptions.length; i++) {
|
||||
textToCopy = textToCopy + ', ' + this.pathListBox.selectedOptions[i];
|
||||
}
|
||||
|
||||
// Copy to clipboard
|
||||
this.clipboardService.writeText(textToCopy);
|
||||
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
});
|
||||
this.pathListBox.render(this.pathElement.nativeElement);
|
||||
|
||||
// Set backup path add/remove buttons
|
||||
this.addPathButton = this._register(new Button(this.addPathElement.nativeElement));
|
||||
this.addPathButton.label = '+';
|
||||
this.addPathButton.title = localize('addFile', "Add a file");
|
||||
|
||||
this.removePathButton = this._register(new Button(this.removePathElement.nativeElement));
|
||||
this.removePathButton.label = '-';
|
||||
this.removePathButton.title = localize('removeFile', "Remove files");
|
||||
|
||||
// Set compression
|
||||
this.compressionSelectBox = this._register(new SelectBox(this.compressionOptions, this.compressionOptions[0], this.contextViewService, undefined, { ariaLabel: this.localizedStrings.SET_BACKUP_COMPRESSION }));
|
||||
this.compressionSelectBox.render(this.compressionElement.nativeElement);
|
||||
|
||||
// Set encryption
|
||||
this.algorithmSelectBox = this._register(new SelectBox(this.encryptionAlgorithms, this.encryptionAlgorithms[0], this.contextViewService, undefined, { ariaLabel: this.localizedStrings.ALGORITHM }));
|
||||
this.algorithmSelectBox.render(this.encryptionAlgorithmElement.nativeElement);
|
||||
this.encryptorSelectBox = this._register(new SelectBox([], '', this.contextViewService, undefined, { ariaLabel: this.localizedStrings.CERTIFICATE_OR_ASYMMETRIC_KEY }));
|
||||
this.encryptorSelectBox.render(this.encryptorElement.nativeElement);
|
||||
|
||||
// Set media
|
||||
this.mediaNameBox = this._register(new InputBox(this.mediaNameElement.nativeElement,
|
||||
this.contextViewService,
|
||||
{
|
||||
validationOptions: {
|
||||
validation: (value: string) => !value ? ({ type: MessageType.ERROR, content: LocalizedStrings.MEDIA_NAME_REQUIRED_ERROR }) : null
|
||||
},
|
||||
ariaLabel: LocalizedStrings.NEW_MEDIA_SET_NAME
|
||||
}
|
||||
));
|
||||
|
||||
this.mediaDescriptionBox = this._register(new InputBox(this.mediaDescriptionElement.nativeElement, this.contextViewService, {
|
||||
ariaLabel: LocalizedStrings.NEW_MEDIA_SET_DESCRIPTION
|
||||
}));
|
||||
|
||||
// Set backup retain days
|
||||
let invalidInputMessage = localize('backupComponent.invalidInput', "Invalid input. Value must be greater than or equal 0.");
|
||||
this.backupRetainDaysBox = this._register(new InputBox(this.backupDaysElement.nativeElement,
|
||||
this.contextViewService,
|
||||
{
|
||||
placeholder: '0',
|
||||
type: 'number',
|
||||
min: '0',
|
||||
validationOptions: {
|
||||
validation: (value: string) => {
|
||||
if (types.isNumber(Number(value)) && Number(value) < 0) {
|
||||
return { type: MessageType.ERROR, content: invalidInputMessage };
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
},
|
||||
ariaLabel: LocalizedStrings.SET_BACKUP_RETAIN_DAYS
|
||||
}));
|
||||
|
||||
// Disable elements
|
||||
this.recoveryBox.disable();
|
||||
this.mediaNameBox.disable();
|
||||
this.mediaDescriptionBox.disable();
|
||||
|
||||
this.registerListeners();
|
||||
this.updateTheme(this.themeService.getTheme());
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this._backupUiService.onShowBackupDialog();
|
||||
}
|
||||
|
||||
private onGetBackupConfigInfo(param: { connection: IConnectionProfile, ownerUri: string }) {
|
||||
// Show spinner
|
||||
this.showSpinner();
|
||||
this.backupEnabled = false;
|
||||
|
||||
// Reset backup values
|
||||
this.backupNameBox.value = '';
|
||||
this.pathListBox.setOptions([], 0);
|
||||
|
||||
this.connection = param.connection;
|
||||
this._uri = param.ownerUri;
|
||||
|
||||
// Get backup configuration info
|
||||
this._backupService.getBackupConfigInfo(this._uri).then(configInfo => {
|
||||
if (configInfo) {
|
||||
this.defaultNewBackupFolder = configInfo.defaultBackupFolder;
|
||||
this.recoveryModel = configInfo.recoveryModel;
|
||||
this.backupEncryptors = configInfo.backupEncryptors;
|
||||
this.initialize(true);
|
||||
} else {
|
||||
this.initialize(false);
|
||||
}
|
||||
// Hide spinner
|
||||
this.hideSpinner();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show spinner in the backup dialog
|
||||
*/
|
||||
private showSpinner(): void {
|
||||
this.inProgressElement.nativeElement.style.visibility = 'visible';
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide spinner in the backup dialog
|
||||
*/
|
||||
private hideSpinner(): void {
|
||||
this.inProgressElement.nativeElement.style.visibility = 'hidden';
|
||||
}
|
||||
|
||||
private addFooterButtons(): void {
|
||||
// Set script footer button
|
||||
this.scriptButton = this._register(new Button(this.scriptButtonElement.nativeElement));
|
||||
this.scriptButton.label = localize('backupComponent.script', "Script");
|
||||
this.addButtonClickHandler(this.scriptButton, () => this.onScript());
|
||||
this._register(attachButtonStyler(this.scriptButton, this.themeService));
|
||||
this.scriptButton.enabled = false;
|
||||
|
||||
// Set backup footer button
|
||||
this.backupButton = this._register(new Button(this.backupButtonElement.nativeElement));
|
||||
this.backupButton.label = localize('backupComponent.backup', "Backup");
|
||||
this.addButtonClickHandler(this.backupButton, () => this.onOk());
|
||||
this._register(attachButtonStyler(this.backupButton, this.themeService));
|
||||
this.backupEnabled = false;
|
||||
|
||||
// Set cancel footer button
|
||||
this.cancelButton = this._register(new Button(this.cancelButtonElement.nativeElement));
|
||||
this.cancelButton.label = localize('backupComponent.cancel', "Cancel");
|
||||
this.addButtonClickHandler(this.cancelButton, () => this.onCancel());
|
||||
this._register(attachButtonStyler(this.cancelButton, this.themeService));
|
||||
}
|
||||
|
||||
private initialize(isMetadataPopulated: boolean): void {
|
||||
|
||||
this.databaseName = this.connection.databaseName;
|
||||
this.selectedBackupComponent = BackupConstants.labelDatabase;
|
||||
this.backupPathTypePairs = {};
|
||||
this.isFormatChecked = false;
|
||||
this.isEncryptChecked = false;
|
||||
this.selectedInitOption = this.existingMediaOptions[0];
|
||||
this.backupTypeOptions = [];
|
||||
|
||||
if (isMetadataPopulated) {
|
||||
this.backupEnabled = true;
|
||||
|
||||
// Set recovery model
|
||||
this.setControlsForRecoveryModel();
|
||||
|
||||
// Set backup type
|
||||
this.backupTypeSelectBox.setOptions(this.backupTypeOptions, 0);
|
||||
|
||||
this.setDefaultBackupName();
|
||||
this.backupNameBox.focus();
|
||||
|
||||
// Set backup path list
|
||||
this.setDefaultBackupPaths();
|
||||
let pathlist: ISelectOptionItem[] = [];
|
||||
for (let i in this.backupPathTypePairs) {
|
||||
pathlist.push({ text: i });
|
||||
}
|
||||
this.pathListBox.setOptions(pathlist, 0);
|
||||
|
||||
// Set encryption
|
||||
let encryptorItems = this.populateEncryptorCombo();
|
||||
this.encryptorSelectBox.setOptions(encryptorItems, 0);
|
||||
|
||||
if (encryptorItems.length === 0) {
|
||||
// Disable encryption checkbox
|
||||
this.encryptCheckBox.disable();
|
||||
|
||||
// Show warning instead of algorithm select boxes
|
||||
(<HTMLElement>this.encryptWarningElement.nativeElement).style.display = 'inline';
|
||||
(<HTMLElement>this.encryptContainerElement.nativeElement).style.display = 'none';
|
||||
}
|
||||
else {
|
||||
// Show algorithm select boxes instead of warning
|
||||
(<HTMLElement>this.encryptWarningElement.nativeElement).style.display = 'none';
|
||||
(<HTMLElement>this.encryptContainerElement.nativeElement).style.display = 'inline';
|
||||
|
||||
// Disable the algorithm select boxes since encryption is not checked by default
|
||||
this.setEncryptOptionsEnabled(false);
|
||||
}
|
||||
|
||||
this.setTLogOptions();
|
||||
|
||||
// disable elements
|
||||
this.recoveryBox.disable();
|
||||
this.mediaNameBox.disable();
|
||||
this.mediaDescriptionBox.disable();
|
||||
this.recoveryBox.value = this.recoveryModel;
|
||||
|
||||
// show warning message if latest backup file path contains url
|
||||
if (this.containsBackupToUrl) {
|
||||
this.pathListBox.setValidation(false, { content: localize('backup.containsBackupToUrlError', "Only backup to file is supported"), type: MessageType.WARNING });
|
||||
this.pathListBox.focus();
|
||||
}
|
||||
}
|
||||
|
||||
this._changeDetectorRef.detectChanges();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset dialog controls to their initial state.
|
||||
*/
|
||||
private resetDialog(): void {
|
||||
this.isFormatChecked = false;
|
||||
this.isEncryptChecked = false;
|
||||
|
||||
this.copyOnlyCheckBox.checked = false;
|
||||
this.copyOnlyCheckBox.enable();
|
||||
this.compressionSelectBox.setOptions(this.compressionOptions, 0);
|
||||
this.encryptCheckBox.checked = false;
|
||||
this.encryptCheckBox.enable();
|
||||
this.onChangeEncrypt();
|
||||
|
||||
this.mediaNameBox.value = '';
|
||||
this.mediaDescriptionBox.value = '';
|
||||
this.checksumCheckBox.checked = false;
|
||||
this.verifyCheckBox.checked = false;
|
||||
this.continueOnErrorCheckBox.checked = false;
|
||||
this.backupRetainDaysBox.value = '0';
|
||||
this.algorithmSelectBox.setOptions(this.encryptionAlgorithms, 0);
|
||||
this.selectedInitOption = this.existingMediaOptions[0];
|
||||
this.containsBackupToUrl = false;
|
||||
this.pathListBox.setValidation(true);
|
||||
|
||||
this.cancelButton.applyStyles();
|
||||
this.scriptButton.applyStyles();
|
||||
this.backupButton.applyStyles();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
// Theme styler
|
||||
this._register(attachInputBoxStyler(this.backupNameBox, this.themeService));
|
||||
this._register(attachInputBoxStyler(this.recoveryBox, this.themeService));
|
||||
this._register(attachSelectBoxStyler(this.backupTypeSelectBox, this.themeService));
|
||||
this._register(attachListBoxStyler(this.pathListBox, this.themeService));
|
||||
this._register(attachButtonStyler(this.addPathButton, this.themeService));
|
||||
this._register(attachButtonStyler(this.removePathButton, this.themeService));
|
||||
this._register(attachSelectBoxStyler(this.compressionSelectBox, this.themeService));
|
||||
this._register(attachSelectBoxStyler(this.algorithmSelectBox, this.themeService));
|
||||
this._register(attachSelectBoxStyler(this.encryptorSelectBox, this.themeService));
|
||||
this._register(attachInputBoxStyler(this.mediaNameBox, this.themeService));
|
||||
this._register(attachInputBoxStyler(this.mediaDescriptionBox, this.themeService));
|
||||
this._register(attachInputBoxStyler(this.backupRetainDaysBox, this.themeService));
|
||||
this._register(attachCheckboxStyler(this.copyOnlyCheckBox, this.themeService));
|
||||
this._register(attachCheckboxStyler(this.encryptCheckBox, this.themeService));
|
||||
this._register(attachCheckboxStyler(this.verifyCheckBox, this.themeService));
|
||||
this._register(attachCheckboxStyler(this.checksumCheckBox, this.themeService));
|
||||
this._register(attachCheckboxStyler(this.continueOnErrorCheckBox, this.themeService));
|
||||
|
||||
this._register(this.backupTypeSelectBox.onDidSelect(selected => this.onBackupTypeChanged()));
|
||||
this.addButtonClickHandler(this.addPathButton, () => this.onAddClick());
|
||||
this.addButtonClickHandler(this.removePathButton, () => this.onRemoveClick());
|
||||
this._register(this.mediaNameBox.onDidChange(mediaName => {
|
||||
this.mediaNameChanged(mediaName);
|
||||
}));
|
||||
this._register(this.backupRetainDaysBox.onDidChange(days => {
|
||||
this.backupRetainDaysChanged(days);
|
||||
}));
|
||||
|
||||
this._register(this.themeService.onDidColorThemeChange(e => this.updateTheme(e)));
|
||||
}
|
||||
|
||||
// Update theming that is specific to backup dialog
|
||||
private updateTheme(theme: ITheme): void {
|
||||
// set modal footer style
|
||||
let footerHtmlElement: HTMLElement = <HTMLElement>this.modalFooterElement.nativeElement;
|
||||
const backgroundColor = theme.getColor(SIDE_BAR_BACKGROUND);
|
||||
const border = theme.getColor(cr.contrastBorder) ? theme.getColor(cr.contrastBorder).toString() : null;
|
||||
const footerBorderTopWidth = border ? '1px' : null;
|
||||
const footerBorderTopStyle = border ? 'solid' : null;
|
||||
footerHtmlElement.style.backgroundColor = backgroundColor ? backgroundColor.toString() : null;
|
||||
footerHtmlElement.style.borderTopWidth = footerBorderTopWidth;
|
||||
footerHtmlElement.style.borderTopStyle = footerBorderTopStyle;
|
||||
footerHtmlElement.style.borderTopColor = border;
|
||||
}
|
||||
|
||||
private addButtonClickHandler(button: Button, handler: () => void) {
|
||||
if (button && handler) {
|
||||
button.onDidClick(() => {
|
||||
if (button.enabled) {
|
||||
handler();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* UI event handlers
|
||||
*/
|
||||
private onScript(): void {
|
||||
this._backupService.backup(this._uri, this.createBackupInfo(), TaskExecutionMode.script);
|
||||
this.close();
|
||||
}
|
||||
|
||||
private onOk(): void {
|
||||
this._backupService.backup(this._uri, this.createBackupInfo(), TaskExecutionMode.executeAndScript);
|
||||
this.close();
|
||||
}
|
||||
|
||||
private onCancel(): void {
|
||||
this.close();
|
||||
this.connectionManagementService.disconnect(this._uri);
|
||||
}
|
||||
|
||||
private close(): void {
|
||||
this._backupUiService.closeBackup();
|
||||
this.resetDialog();
|
||||
}
|
||||
|
||||
public onChangeTlog(): void {
|
||||
this.isTruncateChecked = !this.isTruncateChecked;
|
||||
this.isTaillogChecked = !this.isTaillogChecked;
|
||||
this.detectChange();
|
||||
}
|
||||
|
||||
private onChangeEncrypt(): void {
|
||||
if (this.encryptCheckBox.checked) {
|
||||
this.setEncryptOptionsEnabled(true);
|
||||
|
||||
// Force to choose format media option since otherwise encryption cannot be done
|
||||
if (!this.isFormatChecked) {
|
||||
this.onChangeMediaFormat();
|
||||
}
|
||||
} else {
|
||||
this.setEncryptOptionsEnabled(false);
|
||||
}
|
||||
this.isEncryptChecked = this.encryptCheckBox.checked;
|
||||
this.detectChange();
|
||||
}
|
||||
|
||||
private onChangeMediaFormat(): void {
|
||||
this.isFormatChecked = !this.isFormatChecked;
|
||||
this.enableMediaInput(this.isFormatChecked);
|
||||
if (this.isFormatChecked) {
|
||||
if (strings.isFalsyOrWhitespace(this.mediaNameBox.value)) {
|
||||
this.backupEnabled = false;
|
||||
this.backupButton.enabled = false;
|
||||
this.mediaNameBox.showMessage({ type: MessageType.ERROR, content: LocalizedStrings.MEDIA_NAME_REQUIRED_ERROR });
|
||||
}
|
||||
} else {
|
||||
this.enableBackupButton();
|
||||
}
|
||||
this.detectChange();
|
||||
}
|
||||
|
||||
private set backupEnabled(value: boolean) {
|
||||
this.backupButton.enabled = value;
|
||||
this.scriptButton.enabled = value;
|
||||
}
|
||||
|
||||
private onBackupTypeChanged(): void {
|
||||
if (this.getSelectedBackupType() === BackupConstants.labelDifferential) {
|
||||
this.copyOnlyCheckBox.checked = false;
|
||||
this.copyOnlyCheckBox.disable();
|
||||
} else {
|
||||
this.copyOnlyCheckBox.enable();
|
||||
}
|
||||
|
||||
this.setTLogOptions();
|
||||
this.setDefaultBackupName();
|
||||
this._changeDetectorRef.detectChanges();
|
||||
}
|
||||
|
||||
private onAddClick(): void {
|
||||
this.fileBrowserDialogService.showDialog(this._uri,
|
||||
this.defaultNewBackupFolder,
|
||||
BackupConstants.fileFiltersSet,
|
||||
FileValidationConstants.backup,
|
||||
false,
|
||||
(filepath => this.handlePathAdded(filepath)));
|
||||
}
|
||||
|
||||
private handlePathAdded(filepath: string) {
|
||||
if (filepath && !this.backupPathTypePairs[filepath]) {
|
||||
if ((this.getBackupPathCount() < BackupConstants.maxDevices)) {
|
||||
this.backupPathTypePairs[filepath] = BackupConstants.deviceTypeFile;
|
||||
this.pathListBox.add(filepath);
|
||||
this.enableBackupButton();
|
||||
this.enableAddRemoveButtons();
|
||||
|
||||
// stop showing error message if the list content was invalid due to no file path
|
||||
if (!this.pathListBox.isContentValid && this.pathListBox.count === 1) {
|
||||
this.pathListBox.setValidation(true);
|
||||
}
|
||||
|
||||
this._changeDetectorRef.detectChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private onRemoveClick(): void {
|
||||
let self = this;
|
||||
this.pathListBox.selectedOptions.forEach(selected => {
|
||||
if (self.backupPathTypePairs[selected]) {
|
||||
if (self.backupPathTypePairs[selected] === BackupConstants.deviceTypeURL) {
|
||||
// stop showing warning message since url path is getting removed
|
||||
this.pathListBox.setValidation(true);
|
||||
this.containsBackupToUrl = false;
|
||||
}
|
||||
|
||||
delete self.backupPathTypePairs[selected];
|
||||
}
|
||||
});
|
||||
|
||||
this.pathListBox.remove();
|
||||
if (this.pathListBox.count === 0) {
|
||||
this.backupEnabled = false;
|
||||
|
||||
// show input validation error
|
||||
this.pathListBox.setValidation(false, { content: localize('backup.backupFileRequired', "Backup file path is required"), type: MessageType.ERROR });
|
||||
this.pathListBox.focus();
|
||||
}
|
||||
|
||||
this.enableAddRemoveButtons();
|
||||
this._changeDetectorRef.detectChanges();
|
||||
}
|
||||
|
||||
private enableAddRemoveButtons(): void {
|
||||
if (this.pathListBox.count === 0) {
|
||||
this.removePathButton.enabled = false;
|
||||
} else if (this.pathListBox.count === BackupConstants.maxDevices) {
|
||||
this.addPathButton.enabled = false;
|
||||
} else {
|
||||
this.removePathButton.enabled = true;
|
||||
this.addPathButton.enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper methods
|
||||
*/
|
||||
private setControlsForRecoveryModel(): void {
|
||||
if (this.recoveryModel === BackupConstants.recoveryModelSimple) {
|
||||
this.selectedBackupComponent = BackupConstants.labelDatabase;
|
||||
}
|
||||
|
||||
this.populateBackupTypes();
|
||||
}
|
||||
|
||||
private populateBackupTypes(): void {
|
||||
this.backupTypeOptions.push(BackupConstants.labelFull);
|
||||
if (this.databaseName !== 'master') {
|
||||
this.backupTypeOptions.push(BackupConstants.labelDifferential);
|
||||
if (this.recoveryModel !== BackupConstants.recoveryModelSimple) {
|
||||
this.backupTypeOptions.push(BackupConstants.labelLog);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private populateEncryptorCombo(): string[] {
|
||||
let encryptorCombo = [];
|
||||
this.backupEncryptors.forEach((encryptor) => {
|
||||
let encryptorTypeStr = (encryptor.encryptorType === 0 ? BackupConstants.serverCertificate : BackupConstants.asymmetricKey);
|
||||
encryptorCombo.push(encryptor.encryptorName + '(' + encryptorTypeStr + ')');
|
||||
});
|
||||
return encryptorCombo;
|
||||
}
|
||||
|
||||
private setDefaultBackupName(): void {
|
||||
if (this.backupNameBox && (!this.backupNameBox.value || this.backupNameBox.value.trim().length === 0)) {
|
||||
let utc = new Date().toJSON().slice(0, 19);
|
||||
this.backupNameBox.value = this.databaseName + '-' + this.getSelectedBackupType() + '-' + utc;
|
||||
}
|
||||
}
|
||||
|
||||
private setDefaultBackupPaths(): void {
|
||||
if (this.defaultNewBackupFolder && this.defaultNewBackupFolder.length > 0) {
|
||||
|
||||
// TEMPORARY WORKAROUND: karlb 5/27 - try to guess path separator on server based on first character in path
|
||||
let serverPathSeparator: string = '\\';
|
||||
if (this.defaultNewBackupFolder[0] === '/') {
|
||||
serverPathSeparator = '/';
|
||||
}
|
||||
let d: Date = new Date();
|
||||
let formattedDateTime: string = `-${d.getFullYear()}${d.getMonth() + 1}${d.getDate()}-${d.getHours()}-${d.getMinutes()}-${d.getSeconds()}`;
|
||||
let defaultNewBackupLocation = this.defaultNewBackupFolder + serverPathSeparator + this.databaseName + formattedDateTime + '.bak';
|
||||
|
||||
// Add a default new backup location
|
||||
this.backupPathTypePairs[defaultNewBackupLocation] = BackupConstants.deviceTypeFile;
|
||||
}
|
||||
}
|
||||
|
||||
private enableMediaInput(enable: boolean): void {
|
||||
if (enable) {
|
||||
this.mediaNameBox.enable();
|
||||
this.mediaDescriptionBox.enable();
|
||||
} else {
|
||||
this.mediaNameBox.disable();
|
||||
this.mediaDescriptionBox.disable();
|
||||
}
|
||||
}
|
||||
|
||||
private detectChange(): void {
|
||||
this._changeDetectorRef.detectChanges();
|
||||
}
|
||||
|
||||
private setTLogOptions(): void {
|
||||
if (this.getSelectedBackupType() === BackupConstants.labelLog) {
|
||||
// Enable log options
|
||||
this.disableTlog = false;
|
||||
// Choose the default option
|
||||
this.isTruncateChecked = true;
|
||||
} else {
|
||||
// Unselect log options
|
||||
this.isTruncateChecked = false;
|
||||
this.isTaillogChecked = false;
|
||||
// Disable log options
|
||||
this.disableTlog = true;
|
||||
}
|
||||
}
|
||||
|
||||
private getBackupTypeNumber(): number {
|
||||
let backupType;
|
||||
switch (this.getSelectedBackupType()) {
|
||||
case BackupConstants.labelFull:
|
||||
backupType = 0;
|
||||
break;
|
||||
case BackupConstants.labelDifferential:
|
||||
backupType = 1;
|
||||
break;
|
||||
case BackupConstants.labelLog:
|
||||
backupType = 2;
|
||||
break;
|
||||
}
|
||||
return backupType;
|
||||
}
|
||||
|
||||
private getBackupPathCount(): number {
|
||||
return this.pathListBox.count;
|
||||
}
|
||||
|
||||
private getSelectedBackupType(): string {
|
||||
let backupType = '';
|
||||
if (this.backupTypeSelectBox) {
|
||||
backupType = this.backupTypeSelectBox.value;
|
||||
}
|
||||
return backupType;
|
||||
}
|
||||
|
||||
private enableBackupButton(): void {
|
||||
if (!this.backupButton.enabled) {
|
||||
if (this.pathListBox.count > 0 && (!this.isFormatChecked || this.mediaNameBox.value) && this.backupRetainDaysBox.validate()) {
|
||||
this.backupEnabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private setEncryptOptionsEnabled(enabled: boolean): void {
|
||||
if (enabled) {
|
||||
this.algorithmSelectBox.enable();
|
||||
this.encryptorSelectBox.enable();
|
||||
} else {
|
||||
this.algorithmSelectBox.disable();
|
||||
this.encryptorSelectBox.disable();
|
||||
}
|
||||
}
|
||||
|
||||
private mediaNameChanged(mediaName: string): void {
|
||||
if (!mediaName) {
|
||||
this.backupEnabled = false;
|
||||
} else {
|
||||
this.enableBackupButton();
|
||||
}
|
||||
}
|
||||
|
||||
private backupRetainDaysChanged(days: string): void {
|
||||
if (!this.backupRetainDaysBox.validate()) {
|
||||
this.backupEnabled = false;
|
||||
} else {
|
||||
this.enableBackupButton();
|
||||
}
|
||||
}
|
||||
|
||||
private createBackupInfo(): MssqlBackupInfo {
|
||||
let backupPathArray = [];
|
||||
for (let i in this.backupPathTypePairs) {
|
||||
backupPathArray.push(i);
|
||||
}
|
||||
|
||||
// get encryptor type and name
|
||||
let encryptorName = '';
|
||||
let encryptorType;
|
||||
|
||||
if (this.encryptCheckBox.checked && this.encryptorSelectBox.value !== '') {
|
||||
let selectedEncryptor = this.encryptorSelectBox.value;
|
||||
let encryptorTypeStr = selectedEncryptor.substring(selectedEncryptor.lastIndexOf('(') + 1, selectedEncryptor.lastIndexOf(')'));
|
||||
encryptorType = (encryptorTypeStr === BackupConstants.serverCertificate ? 0 : 1);
|
||||
encryptorName = selectedEncryptor.substring(0, selectedEncryptor.lastIndexOf('('));
|
||||
}
|
||||
|
||||
let backupInfo = <MssqlBackupInfo>{
|
||||
ownerUri: this._uri,
|
||||
databaseName: this.databaseName,
|
||||
backupType: this.getBackupTypeNumber(),
|
||||
backupComponent: 0,
|
||||
backupDeviceType: BackupConstants.backupDeviceTypeDisk,
|
||||
backupPathList: backupPathArray,
|
||||
selectedFiles: this.selectedFilesText,
|
||||
backupsetName: this.backupNameBox.value,
|
||||
selectedFileGroup: undefined,
|
||||
backupPathDevices: this.backupPathTypePairs,
|
||||
isCopyOnly: this.copyOnlyCheckBox.checked,
|
||||
|
||||
// Get advanced options
|
||||
formatMedia: this.isFormatChecked,
|
||||
initialize: (this.isFormatChecked ? true : (this.selectedInitOption === this.existingMediaOptions[1])),
|
||||
skipTapeHeader: this.isFormatChecked,
|
||||
mediaName: (this.isFormatChecked ? this.mediaNameBox.value : ''),
|
||||
mediaDescription: (this.isFormatChecked ? this.mediaDescriptionBox.value : ''),
|
||||
checksum: this.checksumCheckBox.checked,
|
||||
continueAfterError: this.continueOnErrorCheckBox.checked,
|
||||
logTruncation: this.isTruncateChecked,
|
||||
tailLogBackup: this.isTaillogChecked,
|
||||
retainDays: strings.isFalsyOrWhitespace(this.backupRetainDaysBox.value) ? 0 : this.backupRetainDaysBox.value,
|
||||
compressionOption: this.compressionOptions.indexOf(this.compressionSelectBox.value),
|
||||
verifyBackupRequired: this.verifyCheckBox.checked,
|
||||
encryptionAlgorithm: (this.encryptCheckBox.checked ? this.encryptionAlgorithms.indexOf(this.algorithmSelectBox.value) : 0),
|
||||
encryptorType: encryptorType,
|
||||
encryptorName: encryptorName
|
||||
};
|
||||
|
||||
return backupInfo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { TreeViewItemHandleArg } from 'sql/workbench/common/views';
|
||||
import { BackupAction } from 'sql/workbench/contrib/backup/browser/backupActions';
|
||||
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { ManageActionContext } from 'sql/workbench/browser/actions';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ItemContextKey } from 'sql/workbench/contrib/dashboard/browser/widgets/explorer/explorerTreeContext';
|
||||
import { MssqlNodeContext } from 'sql/workbench/contrib/dataExplorer/browser/mssqlNodeContext';
|
||||
import { NodeType } from 'sql/workbench/contrib/objectExplorer/common/nodeType';
|
||||
import { mssqlProviderName } from 'sql/platform/connection/common/constants';
|
||||
import { localize } from 'vs/nls';
|
||||
import { OEAction } from 'sql/workbench/contrib/objectExplorer/browser/objectExplorerActions';
|
||||
import { TreeNodeContextKey } from 'sql/workbench/contrib/objectExplorer/common/treeNodeContextKey';
|
||||
import { ConnectionContextKey } from 'sql/workbench/contrib/connection/common/connectionContextKey';
|
||||
import { ServerInfoContextKey } from 'sql/workbench/contrib/connection/common/serverInfoContextKey';
|
||||
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { DatabaseEngineEdition } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
|
||||
new BackupAction().registerTask();
|
||||
|
||||
// data explorer
|
||||
const DE_BACKUP_COMMAND_ID = 'dataExplorer.backup';
|
||||
CommandsRegistry.registerCommand({
|
||||
id: DE_BACKUP_COMMAND_ID,
|
||||
handler: (accessor, args: TreeViewItemHandleArg) => {
|
||||
const commandService = accessor.get(ICommandService);
|
||||
return commandService.executeCommand(BackupAction.ID, args.$treeItem.payload);
|
||||
}
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.DataExplorerContext, {
|
||||
group: 'connection',
|
||||
order: 4,
|
||||
command: {
|
||||
id: DE_BACKUP_COMMAND_ID,
|
||||
title: localize('backup', "Backup")
|
||||
},
|
||||
when: ContextKeyExpr.and(MssqlNodeContext.NodeProvider.isEqualTo(mssqlProviderName),
|
||||
MssqlNodeContext.NodeType.isEqualTo(NodeType.Database), MssqlNodeContext.IsCloud.toNegated(), MssqlNodeContext.EngineEdition.notEqualsTo(DatabaseEngineEdition.SqlOnDemand.toString()))
|
||||
});
|
||||
|
||||
// oe
|
||||
const OE_BACKUP_COMMAND_ID = 'objectExplorer.backup';
|
||||
CommandsRegistry.registerCommand({
|
||||
id: OE_BACKUP_COMMAND_ID,
|
||||
handler: (accessor: ServicesAccessor, actionContext: any) => {
|
||||
const instantiationService = accessor.get(IInstantiationService);
|
||||
return instantiationService.createInstance(OEAction, BackupAction.ID, BackupAction.LABEL).run(actionContext);
|
||||
}
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.ObjectExplorerItemContext, {
|
||||
group: 'connection',
|
||||
order: 4,
|
||||
command: {
|
||||
id: OE_BACKUP_COMMAND_ID,
|
||||
title: localize('backup', "Backup")
|
||||
},
|
||||
when: ContextKeyExpr.and(TreeNodeContextKey.NodeType.isEqualTo(NodeType.Database), ConnectionContextKey.Provider.isEqualTo(mssqlProviderName),
|
||||
ServerInfoContextKey.IsCloud.toNegated(), ServerInfoContextKey.EngineEdition.notEqualsTo(DatabaseEngineEdition.SqlOnDemand.toString()))
|
||||
});
|
||||
|
||||
// dashboard explorer
|
||||
const ExplorerBackUpActionID = 'explorer.backup';
|
||||
CommandsRegistry.registerCommand(ExplorerBackUpActionID, (accessor, context: ManageActionContext) => {
|
||||
const commandService = accessor.get(ICommandService);
|
||||
return commandService.executeCommand(BackupAction.ID, context.profile);
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.ExplorerWidgetContext, {
|
||||
command: {
|
||||
id: ExplorerBackUpActionID,
|
||||
title: BackupAction.LABEL
|
||||
},
|
||||
when: ContextKeyExpr.and(ItemContextKey.ItemType.isEqualTo('database'), ItemContextKey.ConnectionProvider.isEqualTo('mssql'),
|
||||
ItemContextKey.IsCloud.toNegated(), ItemContextKey.EngineEdition.notEqualsTo(DatabaseEngineEdition.SqlOnDemand.toString())),
|
||||
order: 2
|
||||
});
|
||||
55
src/sql/workbench/contrib/backup/browser/backup.module.ts
Normal file
55
src/sql/workbench/contrib/backup/browser/backup.module.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import {
|
||||
ApplicationRef, ComponentFactoryResolver, NgModule,
|
||||
Inject, forwardRef, Type
|
||||
} from '@angular/core';
|
||||
import { APP_BASE_HREF, CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
import { providerIterator } from 'sql/workbench/services/bootstrap/browser/bootstrapService';
|
||||
import { BackupComponent } from 'sql/workbench/contrib/backup/browser/backup.component';
|
||||
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IBootstrapParams, ISelector } from 'sql/workbench/services/bootstrap/common/bootstrapParams';
|
||||
|
||||
// Backup wizard main angular module
|
||||
export const BackupModule = (params: IBootstrapParams, selector: string, instantiationService: IInstantiationService): Type<any> => {
|
||||
@NgModule({
|
||||
declarations: [
|
||||
BackupComponent
|
||||
],
|
||||
entryComponents: [BackupComponent],
|
||||
imports: [
|
||||
FormsModule,
|
||||
CommonModule,
|
||||
BrowserModule
|
||||
],
|
||||
providers: [
|
||||
{ provide: APP_BASE_HREF, useValue: '/' },
|
||||
{ provide: IBootstrapParams, useValue: params },
|
||||
{ provide: ISelector, useValue: selector },
|
||||
...providerIterator(instantiationService)
|
||||
]
|
||||
})
|
||||
class ModuleClass {
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ComponentFactoryResolver)) private _resolver: ComponentFactoryResolver,
|
||||
@Inject(ISelector) private selector: string
|
||||
) {
|
||||
}
|
||||
|
||||
ngDoBootstrap(appRef: ApplicationRef) {
|
||||
const factory = this._resolver.resolveComponentFactory(BackupComponent);
|
||||
(<any>factory).factory.selector = this.selector;
|
||||
appRef.bootstrap(factory);
|
||||
}
|
||||
}
|
||||
|
||||
return ModuleClass;
|
||||
};
|
||||
71
src/sql/workbench/contrib/backup/browser/backupActions.ts
Normal file
71
src/sql/workbench/contrib/backup/browser/backupActions.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
||||
import { IObjectExplorerService } from 'sql/workbench/services/objectExplorer/browser/objectExplorerService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { getCurrentGlobalConnection } from 'sql/workbench/browser/taskUtilities';
|
||||
import { mssqlProviderName } from 'sql/platform/connection/common/constants';
|
||||
import { IBackupUiService } from 'sql/workbench/services/backup/common/backupUiService';
|
||||
import { Task } from 'sql/platform/tasks/browser/tasksRegistry';
|
||||
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
|
||||
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
||||
|
||||
export const BackupFeatureName = 'backup';
|
||||
|
||||
export function showBackup(accessor: ServicesAccessor, connection: IConnectionProfile): Promise<void> {
|
||||
const backupUiService = accessor.get(IBackupUiService);
|
||||
return backupUiService.showBackup(connection).then();
|
||||
}
|
||||
|
||||
export class BackupAction extends Task {
|
||||
public static readonly ID = BackupFeatureName;
|
||||
public static readonly LABEL = localize('backupAction.backup', "Backup");
|
||||
public static readonly ICON = BackupFeatureName;
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: BackupAction.ID,
|
||||
title: BackupAction.LABEL,
|
||||
iconPath: undefined,
|
||||
iconClass: BackupAction.ICON
|
||||
});
|
||||
}
|
||||
|
||||
runTask(accessor: ServicesAccessor, profile: IConnectionProfile): void | Promise<void> {
|
||||
const configurationService = accessor.get<IConfigurationService>(IConfigurationService);
|
||||
const previewFeaturesEnabled: boolean = configurationService.getValue('workbench')['enablePreviewFeatures'];
|
||||
if (!previewFeaturesEnabled) {
|
||||
return accessor.get<INotificationService>(INotificationService).info(localize('backup.isPreviewFeature', "You must enable preview features in order to use backup"));
|
||||
}
|
||||
|
||||
const connectionManagementService = accessor.get<IConnectionManagementService>(IConnectionManagementService);
|
||||
if (!profile) {
|
||||
const objectExplorerService = accessor.get<IObjectExplorerService>(IObjectExplorerService);
|
||||
const workbenchEditorService = accessor.get<IEditorService>(IEditorService);
|
||||
profile = getCurrentGlobalConnection(objectExplorerService, connectionManagementService, workbenchEditorService);
|
||||
}
|
||||
if (profile) {
|
||||
const serverInfo = connectionManagementService.getServerInfo(profile.id);
|
||||
if (serverInfo && serverInfo.isCloud && profile.providerName === mssqlProviderName) {
|
||||
return accessor.get<INotificationService>(INotificationService).info(localize('backup.commandNotSupported', "Backup command is not supported for Azure SQL databases."));
|
||||
}
|
||||
|
||||
if (!profile.databaseName && profile.providerName === mssqlProviderName) {
|
||||
return accessor.get<INotificationService>(INotificationService).info(localize('backup.commandNotSupportedForServer', "Backup command is not supported in Server Context. Please select a Database and try again."));
|
||||
}
|
||||
}
|
||||
|
||||
const capabilitiesService = accessor.get(ICapabilitiesService);
|
||||
const instantiationService = accessor.get(IInstantiationService);
|
||||
profile = profile ? profile : new ConnectionProfile(capabilitiesService, profile);
|
||||
return instantiationService.invokeFunction(showBackup, profile);
|
||||
}
|
||||
}
|
||||
107
src/sql/workbench/contrib/backup/browser/backupDialog.ts
Normal file
107
src/sql/workbench/contrib/backup/browser/backupDialog.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Modal } from 'sql/workbench/browser/modal/modal';
|
||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||
import { BackupModule } from 'sql/workbench/contrib/backup/browser/backup.module';
|
||||
import { BACKUP_SELECTOR } from 'sql/workbench/contrib/backup/browser/backup.component';
|
||||
import { attachModalDialogStyler } from 'sql/platform/theme/common/styler';
|
||||
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
|
||||
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { bootstrapAngular } from 'sql/workbench/services/bootstrap/browser/bootstrapService';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { append, $ } from 'vs/base/browser/dom';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration';
|
||||
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
|
||||
|
||||
export class BackupDialog extends Modal {
|
||||
private _body: HTMLElement;
|
||||
private _backupTitle: string;
|
||||
private _moduleRef: any;
|
||||
|
||||
constructor(
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
|
||||
@IAdsTelemetryService telemetryService: IAdsTelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@IClipboardService clipboardService: IClipboardService,
|
||||
@ILogService logService: ILogService,
|
||||
@ITextResourcePropertiesService textResourcePropertiesService: ITextResourcePropertiesService
|
||||
) {
|
||||
super('', TelemetryKeys.Backup, telemetryService, layoutService, clipboardService, themeService, logService, textResourcePropertiesService, contextKeyService, { isAngular: true, hasErrors: true });
|
||||
}
|
||||
|
||||
protected renderBody(container: HTMLElement) {
|
||||
this._body = append(container, $('.backup-dialog'));
|
||||
}
|
||||
|
||||
public render() {
|
||||
super.render();
|
||||
attachModalDialogStyler(this, this._themeService);
|
||||
|
||||
// Add angular component template to dialog body
|
||||
this.bootstrapAngular(this._body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bootstrap params and perform the bootstrap
|
||||
*/
|
||||
private bootstrapAngular(bodyContainer: HTMLElement) {
|
||||
bootstrapAngular(this._instantiationService,
|
||||
BackupModule,
|
||||
bodyContainer,
|
||||
BACKUP_SELECTOR,
|
||||
undefined,
|
||||
undefined,
|
||||
(moduleRef) => this._moduleRef = moduleRef);
|
||||
}
|
||||
|
||||
public hideError() {
|
||||
this.showError('');
|
||||
}
|
||||
|
||||
public showError(err: string) {
|
||||
this.showError(err);
|
||||
}
|
||||
|
||||
/* Overwrite escape key behavior */
|
||||
protected onClose() {
|
||||
this.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up the module and DOM element and close the dialog
|
||||
*/
|
||||
public close() {
|
||||
this.hide();
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
super.dispose();
|
||||
if (this._moduleRef) {
|
||||
this._moduleRef.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the dialog
|
||||
*/
|
||||
public open(connection: IConnectionProfile) {
|
||||
this._backupTitle = 'Backup database - ' + connection.serverName + ':' + connection.databaseName;
|
||||
this.title = this._backupTitle;
|
||||
this.show();
|
||||
}
|
||||
|
||||
protected layout(height?: number): void {
|
||||
// Nothing currently laid out in this class
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.backup-path-list {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.backup-path-table {
|
||||
border: 0px;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0px;
|
||||
}
|
||||
|
||||
.backup-path-button {
|
||||
width: 22px;
|
||||
}
|
||||
|
||||
.backup-dialog {
|
||||
height: 100%
|
||||
}
|
||||
|
||||
.backup-dialog .advanced-main-header {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.backup-dialog .advanced-header {
|
||||
padding-top: 15px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.backup-dialog input[type="checkbox"] {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.backup-dialog input[type="radio"] {
|
||||
margin-top: -2px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.backup-dialog .indent {
|
||||
margin-left: 7px;
|
||||
}
|
||||
|
||||
.backup-dialog .radio-indent {
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.backup-dialog .option {
|
||||
width: 100%;
|
||||
padding-bottom: 7px;
|
||||
}
|
||||
|
||||
.backup-dialog .option.check {
|
||||
display: flex;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.backup-dialog .check {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.backup-dialog .icon.warning {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.backup-dialog .warning-message{
|
||||
padding-left: 20px;
|
||||
}
|
||||
49
src/sql/workbench/contrib/backup/common/constants.ts
Normal file
49
src/sql/workbench/contrib/backup/common/constants.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
// Constants
|
||||
export const maxDevices: number = 64;
|
||||
|
||||
// Constants for backup physical device type
|
||||
export const backupDeviceTypeDisk = 2;
|
||||
export const backupDeviceTypeTape = 5;
|
||||
export const backupDeviceTypeURL = 9;
|
||||
|
||||
// Constants for backup media device type
|
||||
export const deviceTypeLogicalDevice = 0;
|
||||
export const deviceTypeTape = 1;
|
||||
export const deviceTypeFile = 2;
|
||||
export const deviceTypeURL = 5;
|
||||
|
||||
export const recoveryModelSimple = 'Simple';
|
||||
export const recoveryModelFull = 'Full';
|
||||
|
||||
// Constants for UI strings
|
||||
export const labelDatabase = localize('backup.labelDatabase', "Database");
|
||||
export const labelFilegroup = localize('backup.labelFilegroup', "Files and filegroups");
|
||||
export const labelFull = localize('backup.labelFull', "Full");
|
||||
export const labelDifferential = localize('backup.labelDifferential', "Differential");
|
||||
export const labelLog = localize('backup.labelLog', "Transaction Log");
|
||||
export const labelDisk = localize('backup.labelDisk', "Disk");
|
||||
export const labelUrl = localize('backup.labelUrl', "Url");
|
||||
|
||||
export const defaultCompression = localize('backup.defaultCompression', "Use the default server setting");
|
||||
export const compressionOn = localize('backup.compressBackup', "Compress backup");
|
||||
export const compressionOff = localize('backup.doNotCompress', "Do not compress backup");
|
||||
|
||||
export const aes128 = 'AES 128';
|
||||
export const aes192 = 'AES 192';
|
||||
export const aes256 = 'AES 256';
|
||||
export const tripleDES = 'Triple DES';
|
||||
|
||||
export const serverCertificate = localize('backup.serverCertificate', "Server Certificate");
|
||||
export const asymmetricKey = localize('backup.asymmetricKey', "Asymmetric Key");
|
||||
|
||||
export const fileFiltersSet: { label: string, filters: string[] }[] = [
|
||||
{ label: localize('backup.filterBackupFiles', "Backup Files"), filters: ['*.bak', '*.trn', '*.log'] },
|
||||
{ label: localize('backup.allFiles', "All Files"), filters: ['*'] }
|
||||
];
|
||||
Reference in New Issue
Block a user