mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
More Layering (#9139)
* move handling generated files to the serilization classes * remove unneeded methods * add more folders to strictire compile, add more strict compile options * update ci * wip * add more layering and fix issues * add more strictness * remove unnecessary assertion * add missing checks * fix indentation * wip * remove jsdoc * fix layering * fix compile * fix compile errors * wip * wip * finish layering * fix css * more layering * rip * reworking results serializer * move some files around * move capabilities to platform wip * implement capabilities register provider * fix capabilities service * fix usage of the regist4ry * add contribution * wip * wip * wip * remove no longer good parts * fix strict-nulls * fix issues with startup * another try * fix startup * fix imports * fix tests * fix tests * fix more tests * fix tests * fix more tests * fix broken test * fix tabbing * fix naming * wip * finished layering * fix imports * fix valid layers * fix layers
This commit is contained in:
@@ -0,0 +1,306 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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/firewallRuleDialog';
|
||||
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { localize } from 'vs/nls';
|
||||
import { buttonBackground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { attachInputBoxStyler } from 'vs/platform/theme/common/styler';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import { Button } from 'sql/base/browser/ui/button/button';
|
||||
import { Modal } from 'sql/workbench/browser/modal/modal';
|
||||
import { FirewallRuleViewModel } from 'sql/platform/accounts/common/firewallRuleViewModel';
|
||||
import { attachButtonStyler } from 'sql/platform/theme/common/styler';
|
||||
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox';
|
||||
import { IAccountPickerService } from 'sql/workbench/services/accountManagement/browser/accountPicker';
|
||||
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfigurationService';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
|
||||
import { attachModalDialogStyler } from 'sql/workbench/common/styler';
|
||||
|
||||
// TODO: Make the help link 1) extensible (01/08/2018, https://github.com/Microsoft/azuredatastudio/issues/450)
|
||||
// in case that other non-Azure sign in is to be used
|
||||
const firewallHelpUri = 'https://aka.ms/sqlopsfirewallhelp';
|
||||
|
||||
const LocalizedStrings = {
|
||||
FROM: localize('from', "From"),
|
||||
TO: localize('to', "To")
|
||||
};
|
||||
|
||||
export class FirewallRuleDialog extends Modal {
|
||||
public viewModel: FirewallRuleViewModel;
|
||||
private _createButton: Button;
|
||||
private _closeButton: Button;
|
||||
private _fromRangeinputBox: InputBox;
|
||||
private _toRangeinputBox: InputBox;
|
||||
|
||||
private _helpLink: HTMLElement;
|
||||
private _IPAddressInput: HTMLElement;
|
||||
private _subnetIPRangeInput: HTMLElement;
|
||||
private _IPAddressElement: HTMLElement;
|
||||
|
||||
// EVENTING ////////////////////////////////////////////////////////////
|
||||
private _onAddAccountErrorEmitter: Emitter<string>;
|
||||
public get onAddAccountErrorEvent(): Event<string> { return this._onAddAccountErrorEmitter.event; }
|
||||
|
||||
private _onCancel: Emitter<void>;
|
||||
public get onCancel(): Event<void> { return this._onCancel.event; }
|
||||
|
||||
private _onCreateFirewallRule: Emitter<void>;
|
||||
public get onCreateFirewallRule(): Event<void> { return this._onCreateFirewallRule.event; }
|
||||
|
||||
constructor(
|
||||
@IAccountPickerService private _accountPickerService: IAccountPickerService,
|
||||
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@IContextViewService private _contextViewService: IContextViewService,
|
||||
@IAdsTelemetryService telemetryService: IAdsTelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IClipboardService clipboardService: IClipboardService,
|
||||
@ILogService logService: ILogService,
|
||||
@ITextResourcePropertiesService textResourcePropertiesService: ITextResourcePropertiesService,
|
||||
@IOpenerService private readonly openerService: IOpenerService
|
||||
) {
|
||||
super(
|
||||
localize('createNewFirewallRule', "Create new firewall rule"),
|
||||
TelemetryKeys.FireWallRule,
|
||||
telemetryService,
|
||||
layoutService,
|
||||
clipboardService,
|
||||
themeService,
|
||||
logService,
|
||||
textResourcePropertiesService,
|
||||
contextKeyService,
|
||||
{
|
||||
isFlyout: true,
|
||||
hasBackButton: true,
|
||||
hasSpinner: true
|
||||
}
|
||||
);
|
||||
|
||||
// Setup event emitters
|
||||
this._onAddAccountErrorEmitter = new Emitter<string>();
|
||||
this._onCancel = new Emitter<void>();
|
||||
this._onCreateFirewallRule = new Emitter<void>();
|
||||
|
||||
this.viewModel = this._instantiationService.createInstance(FirewallRuleViewModel);
|
||||
}
|
||||
|
||||
public render() {
|
||||
super.render();
|
||||
attachModalDialogStyler(this, this._themeService);
|
||||
this.backButton.onDidClick(() => this.cancel());
|
||||
this._register(attachButtonStyler(this.backButton, this._themeService, { buttonBackground: SIDE_BAR_BACKGROUND, buttonHoverBackground: SIDE_BAR_BACKGROUND }));
|
||||
this._createButton = this.addFooterButton(localize('firewall.ok', "OK"), () => this.createFirewallRule());
|
||||
this._closeButton = this.addFooterButton(localize('firewall.cancel', "Cancel"), () => this.cancel());
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
protected renderBody(container: HTMLElement) {
|
||||
const body = DOM.append(container, DOM.$('.firewall-rule-dialog'));
|
||||
const descriptionSection = DOM.append(body, DOM.$('.firewall-rule-description-section.new-section'));
|
||||
|
||||
DOM.append(descriptionSection, DOM.$('div.firewall-rule-icon'));
|
||||
|
||||
const textDescriptionContainer = DOM.append(descriptionSection, DOM.$('div.firewall-rule-description'));
|
||||
const dialogDescription = localize('firewallRuleDialogDescription',
|
||||
"Your client IP address does not have access to the server. Sign in to an Azure account and create a new firewall rule to enable access.");
|
||||
this.createLabelElement(textDescriptionContainer, dialogDescription, false);
|
||||
|
||||
this._helpLink = DOM.append(textDescriptionContainer, DOM.$('a.help-link'));
|
||||
this._helpLink.setAttribute('href', firewallHelpUri);
|
||||
this._helpLink.innerHTML += localize('firewallRuleHelpDescription', "Learn more about firewall settings");
|
||||
this._helpLink.onclick = () => {
|
||||
this.openerService.open(URI.parse(firewallHelpUri));
|
||||
};
|
||||
|
||||
// Create account picker with event handling
|
||||
this._accountPickerService.addAccountCompleteEvent(() => this.spinner = false);
|
||||
this._accountPickerService.addAccountErrorEvent((msg) => {
|
||||
this.spinner = false;
|
||||
this._onAddAccountErrorEmitter.fire(msg);
|
||||
});
|
||||
this._accountPickerService.addAccountStartEvent(() => this.spinner = true);
|
||||
this._accountPickerService.onAccountSelectionChangeEvent((account) => this.onAccountSelectionChange(account));
|
||||
|
||||
const azureAccountSection = DOM.append(body, DOM.$('.azure-account-section.new-section'));
|
||||
const azureAccountLabel = localize('azureAccount', "Azure account");
|
||||
this.createLabelElement(azureAccountSection, azureAccountLabel, true);
|
||||
this._accountPickerService.renderAccountPicker(DOM.append(azureAccountSection, DOM.$('.dialog-input')));
|
||||
|
||||
const firewallRuleSection = DOM.append(body, DOM.$('.firewall-rule-section.new-section'));
|
||||
const firewallRuleLabel = localize('filewallRule', "Firewall rule");
|
||||
this.createLabelElement(firewallRuleSection, firewallRuleLabel, true);
|
||||
const radioContainer = DOM.append(firewallRuleSection, DOM.$('.radio-section'));
|
||||
const form = DOM.append(radioContainer, DOM.$('form.firewall-rule'));
|
||||
const IPAddressDiv = DOM.append(form, DOM.$('div.firewall-ip-address dialog-input'));
|
||||
const subnetIPRangeDiv = DOM.append(form, DOM.$('div.firewall-subnet-ip-range dialog-input'));
|
||||
|
||||
const IPAddressContainer = DOM.append(IPAddressDiv, DOM.$('div.option-container'));
|
||||
this._IPAddressInput = DOM.append(IPAddressContainer, DOM.$('input.option-input'));
|
||||
this._IPAddressInput.setAttribute('type', 'radio');
|
||||
this._IPAddressInput.setAttribute('name', 'firewallRuleChoice');
|
||||
this._IPAddressInput.setAttribute('value', 'ipAddress');
|
||||
const IPAddressDescription = DOM.append(IPAddressContainer, DOM.$('div.option-description'));
|
||||
IPAddressDescription.innerText = localize('addIPAddressLabel', "Add my client IP ");
|
||||
this._IPAddressElement = DOM.append(IPAddressContainer, DOM.$('div.option-ip-address'));
|
||||
|
||||
const subnetIpRangeContainer = DOM.append(subnetIPRangeDiv, DOM.$('div.option-container'));
|
||||
this._subnetIPRangeInput = DOM.append(subnetIpRangeContainer, DOM.$('input.option-input'));
|
||||
this._subnetIPRangeInput.setAttribute('type', 'radio');
|
||||
this._subnetIPRangeInput.setAttribute('name', 'firewallRuleChoice');
|
||||
this._subnetIPRangeInput.setAttribute('value', 'ipRange');
|
||||
const subnetIPRangeDescription = DOM.append(subnetIpRangeContainer, DOM.$('div.option-description'));
|
||||
subnetIPRangeDescription.innerText = localize('addIpRangeLabel', "Add my subnet IP range");
|
||||
const subnetIPRangeSection = DOM.append(subnetIPRangeDiv, DOM.$('.subnet-ip-range-input'));
|
||||
|
||||
const inputContainer = DOM.append(subnetIPRangeSection, DOM.$('.dialog-input-section'));
|
||||
|
||||
DOM.append(inputContainer, DOM.$('.dialog-label')).innerText = LocalizedStrings.FROM;
|
||||
|
||||
this._fromRangeinputBox = new InputBox(DOM.append(inputContainer, DOM.$('.dialog-input')), this._contextViewService, {
|
||||
ariaLabel: LocalizedStrings.FROM
|
||||
});
|
||||
|
||||
DOM.append(inputContainer, DOM.$('.dialog-label')).innerText = LocalizedStrings.TO;
|
||||
|
||||
this._toRangeinputBox = new InputBox(DOM.append(inputContainer, DOM.$('.dialog-input')), this._contextViewService, {
|
||||
ariaLabel: LocalizedStrings.TO
|
||||
});
|
||||
|
||||
this._register(this._themeService.onThemeChange(e => this.updateTheme(e)));
|
||||
this.updateTheme(this._themeService.getTheme());
|
||||
|
||||
this._register(DOM.addDisposableListener(this._IPAddressElement, DOM.EventType.CLICK, () => {
|
||||
this.onFirewallRuleOptionSelected(true);
|
||||
}));
|
||||
|
||||
this._register(DOM.addDisposableListener(this._subnetIPRangeInput, DOM.EventType.CLICK, () => {
|
||||
this.onFirewallRuleOptionSelected(false);
|
||||
}));
|
||||
}
|
||||
|
||||
private onFirewallRuleOptionSelected(isIPAddress: boolean) {
|
||||
this.viewModel.isIPAddressSelected = isIPAddress;
|
||||
if (this._fromRangeinputBox) {
|
||||
isIPAddress ? this._fromRangeinputBox.disable() : this._fromRangeinputBox.enable();
|
||||
}
|
||||
if (this._toRangeinputBox) {
|
||||
isIPAddress ? this._toRangeinputBox.disable() : this._toRangeinputBox.enable();
|
||||
}
|
||||
}
|
||||
|
||||
protected layout(height?: number): void {
|
||||
// Nothing currently laid out statically in this class
|
||||
}
|
||||
|
||||
private createLabelElement(container: HTMLElement, content: string, isHeader?: boolean) {
|
||||
let className = 'dialog-label';
|
||||
if (isHeader) {
|
||||
className += ' header';
|
||||
}
|
||||
DOM.append(container, DOM.$(`.${className}`)).innerText = content;
|
||||
}
|
||||
|
||||
// Update theming that is specific to firewall rule flyout body
|
||||
private updateTheme(theme: ITheme): void {
|
||||
const linkColor = theme.getColor(buttonBackground);
|
||||
const link = linkColor ? linkColor.toString() : null;
|
||||
if (this._helpLink) {
|
||||
this._helpLink.style.color = link;
|
||||
}
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
// Theme styler
|
||||
this._register(attachButtonStyler(this._createButton, this._themeService));
|
||||
this._register(attachButtonStyler(this._closeButton, this._themeService));
|
||||
this._register(attachInputBoxStyler(this._fromRangeinputBox, this._themeService));
|
||||
this._register(attachInputBoxStyler(this._toRangeinputBox, this._themeService));
|
||||
|
||||
// handler for from subnet ip range change events
|
||||
this._register(this._fromRangeinputBox.onDidChange(IPAddress => {
|
||||
this.fromRangeInputChanged(IPAddress);
|
||||
}));
|
||||
|
||||
// handler for to subnet ip range change events
|
||||
this._register(this._toRangeinputBox.onDidChange(IPAddress => {
|
||||
this.toRangeInputChanged(IPAddress);
|
||||
}));
|
||||
}
|
||||
|
||||
private fromRangeInputChanged(IPAddress: string) {
|
||||
this.viewModel.fromSubnetIPRange = IPAddress;
|
||||
}
|
||||
|
||||
private toRangeInputChanged(IPAddress: string) {
|
||||
this.viewModel.toSubnetIPRange = IPAddress;
|
||||
}
|
||||
|
||||
/* Overwrite esapce key behavior */
|
||||
protected onClose() {
|
||||
this.cancel();
|
||||
}
|
||||
|
||||
/* Overwrite enter key behavior */
|
||||
protected onAccept() {
|
||||
this.createFirewallRule();
|
||||
}
|
||||
|
||||
public cancel() {
|
||||
this._onCancel.fire();
|
||||
this.close();
|
||||
}
|
||||
|
||||
public close() {
|
||||
this.hide();
|
||||
}
|
||||
|
||||
public createFirewallRule() {
|
||||
if (this._createButton.enabled) {
|
||||
this._createButton.enabled = false;
|
||||
this.spinner = true;
|
||||
this._onCreateFirewallRule.fire();
|
||||
}
|
||||
}
|
||||
|
||||
public onAccountSelectionChange(account: azdata.Account | undefined): void {
|
||||
this.viewModel.selectedAccount = account;
|
||||
if (account && !account.isStale) {
|
||||
this._createButton.enabled = true;
|
||||
} else {
|
||||
this._createButton.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
public onServiceComplete() {
|
||||
this._createButton.enabled = true;
|
||||
this.spinner = false;
|
||||
}
|
||||
|
||||
public open() {
|
||||
this._IPAddressInput.click();
|
||||
this.onAccountSelectionChange(this._accountPickerService.selectedAccount);
|
||||
this._fromRangeinputBox.setPlaceHolder(this.viewModel.defaultFromSubnetIPRange);
|
||||
this._toRangeinputBox.setPlaceHolder(this.viewModel.defaultToSubnetIPRange);
|
||||
this._IPAddressElement.innerText = '(' + this.viewModel.defaultIPAddress + ')';
|
||||
|
||||
this.show();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { localize } from 'vs/nls';
|
||||
import * as azdata from 'azdata';
|
||||
|
||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||
import { FirewallRuleDialog } from 'sql/workbench/services/resourceProvider/browser/firewallRuleDialog';
|
||||
import { IAccountManagementService, AzureResource } from 'sql/platform/accounts/common/interfaces';
|
||||
import { IResourceProviderService } from 'sql/workbench/services/resourceProvider/common/resourceProviderService';
|
||||
import { Deferred } from 'sql/base/common/promise';
|
||||
import { IErrorMessageService } from 'sql/platform/errorMessage/common/errorMessageService';
|
||||
|
||||
export class FirewallRuleDialogController {
|
||||
|
||||
private _firewallRuleDialog: FirewallRuleDialog;
|
||||
private _connection: IConnectionProfile;
|
||||
private _resourceProviderId: string;
|
||||
|
||||
private _addAccountErrorTitle = localize('firewallDialog.addAccountErrorTitle', "Error adding account");
|
||||
private _firewallRuleErrorTitle = localize('firewallRuleError', "Firewall rule error");
|
||||
private _deferredPromise: Deferred<boolean>;
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@IResourceProviderService private _resourceProviderService: IResourceProviderService,
|
||||
@IAccountManagementService private _accountManagementService: IAccountManagementService,
|
||||
@IErrorMessageService private _errorMessageService: IErrorMessageService
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Open firewall rule dialog
|
||||
*/
|
||||
public openFirewallRuleDialog(connection: IConnectionProfile, ipAddress: string, resourceProviderId: string): Promise<boolean> {
|
||||
if (!this._firewallRuleDialog) {
|
||||
this._firewallRuleDialog = this._instantiationService.createInstance(FirewallRuleDialog);
|
||||
this._firewallRuleDialog.onCancel(this.handleOnCancel, this);
|
||||
this._firewallRuleDialog.onCreateFirewallRule(this.handleOnCreateFirewallRule, this);
|
||||
this._firewallRuleDialog.onAddAccountErrorEvent(this.handleOnAddAccountError, this);
|
||||
this._firewallRuleDialog.render();
|
||||
}
|
||||
this._connection = connection;
|
||||
this._resourceProviderId = resourceProviderId;
|
||||
this._firewallRuleDialog.viewModel.updateDefaultValues(ipAddress);
|
||||
this._firewallRuleDialog.open();
|
||||
this._deferredPromise = new Deferred();
|
||||
return this._deferredPromise.promise;
|
||||
}
|
||||
|
||||
// PRIVATE HELPERS /////////////////////////////////////////////////////
|
||||
private handleOnAddAccountError(message: string): void {
|
||||
this._errorMessageService.showDialog(Severity.Error, this._addAccountErrorTitle, message);
|
||||
}
|
||||
|
||||
private async handleOnCreateFirewallRule(): Promise<void> {
|
||||
const resourceProviderId = this._resourceProviderId;
|
||||
try {
|
||||
const securityTokenMappings = await this._accountManagementService.getSecurityToken(this._firewallRuleDialog.viewModel.selectedAccount!, AzureResource.ResourceManagement);
|
||||
const firewallRuleInfo: azdata.FirewallRuleInfo = {
|
||||
startIpAddress: this._firewallRuleDialog.viewModel.isIPAddressSelected ? this._firewallRuleDialog.viewModel.defaultIPAddress : this._firewallRuleDialog.viewModel.fromSubnetIPRange,
|
||||
endIpAddress: this._firewallRuleDialog.viewModel.isIPAddressSelected ? this._firewallRuleDialog.viewModel.defaultIPAddress : this._firewallRuleDialog.viewModel.toSubnetIPRange,
|
||||
serverName: this._connection.serverName,
|
||||
securityTokenMappings
|
||||
};
|
||||
|
||||
const response = await this._resourceProviderService.createFirewallRule(this._firewallRuleDialog.viewModel.selectedAccount!, firewallRuleInfo, resourceProviderId);
|
||||
if (response.result) {
|
||||
this._firewallRuleDialog.close();
|
||||
this._deferredPromise.resolve(true);
|
||||
} else {
|
||||
this._errorMessageService.showDialog(Severity.Error, this._firewallRuleErrorTitle, response.errorMessage);
|
||||
}
|
||||
this._firewallRuleDialog.onServiceComplete();
|
||||
} catch (e) {
|
||||
this.showError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private showError(error: any): void {
|
||||
this._errorMessageService.showDialog(Severity.Error, this._firewallRuleErrorTitle, error);
|
||||
this._firewallRuleDialog.onServiceComplete();
|
||||
// Note: intentionally not rejecting the promise as we want users to be able to choose a different account
|
||||
}
|
||||
|
||||
private handleOnCancel(): void {
|
||||
this._deferredPromise.resolve(false);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.firewall-rule-dialog {
|
||||
padding: 15px
|
||||
}
|
||||
|
||||
.modal .firewall-rule-dialog .dialog-label.header {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.modal .firewall-rule-dialog .new-section {
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
|
||||
.modal .firewall-rule-dialog .dialog-input {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.modal .firewall-rule-dialog .dialog-input-section {
|
||||
display: flex;
|
||||
padding-left: 30px;
|
||||
padding-right: 20px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.modal .firewall-rule-dialog .dialog-input-section .dialog-label {
|
||||
flex: 0 0 15px;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.modal .firewall-rule-dialog .dialog-input-section .dialog-input {
|
||||
flex: 0 0 100px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
.modal .firewall-rule-dialog .azure-account-section {
|
||||
height: 92px;
|
||||
}
|
||||
|
||||
/* Firewall rule description section */
|
||||
.modal .firewall-rule-dialog a:link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.modal .firewall-rule-dialog .firewall-rule-description-section {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.modal .firewall-rule-dialog .firewall-rule-description-section .firewall-rule-icon {
|
||||
background: url('secure.svg') center center no-repeat;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
flex: 0 0 50px;
|
||||
}
|
||||
|
||||
.modal .firewall-rule-dialog .firewall-rule-description-section .firewall-rule-description {
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
/* Radio button section*/
|
||||
.modal .firewall-rule-dialog .firewall-rule-section .radio-section .option-container {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.modal .firewall-rule-dialog .firewall-rule-section .radio-section .option-container .option-input {
|
||||
margin-top: 0px;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.modal .firewall-rule-dialog .firewall-rule-section .radio-section .option-container .option-description {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.modal .firewall-rule-dialog .firewall-rule-section .radio-section .option-container .option-ip-address {
|
||||
padding-left: 3px;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36.65 50"><defs><style>.cls-1{fill:#7fba00;}.cls-2{fill:#b8d432;opacity:0.4;isolation:isolate;}.cls-3{fill:#fff;}</style></defs><title>secure</title><path class="cls-1" d="M31.19,6h0c-11-1.22-12.86-6-12.86-6S15.85,6.24,0,6.24V31.85c0,3.1,1.72,6,4.1,8.53h0C9.51,46.13,18.33,50,18.33,50s18.33-8,18.33-18.15V6.24A49.77,49.77,0,0,1,31.19,6Z"/><path class="cls-2" d="M22.86,16.54,31.19,6c-11-1.22-12.86-6-12.86-6S15.85,6.24,0,6.24V31.85c0,3.1,1.72,6,4.1,8.53l6.15-7.82Z"/><path class="cls-3" d="M25.6,24.46H24.53V20.91a6.7,6.7,0,0,0-1.67-4.45h0l-.11-.13a6,6,0,0,0-8.84,0,6.7,6.7,0,0,0-1.78,4.58v3.55H11.06a.8.8,0,0,0-.8.8v7.22h0v2.17a.8.8,0,0,0,.8.8H25.6a.8.8,0,0,0,.8-.8V25.26A.8.8,0,0,0,25.6,24.46Zm-4,0H15.07V20.91a3.75,3.75,0,0,1,1-2.57,3,3,0,0,1,4.54,0,3.67,3.67,0,0,1,.39.5h0a3.8,3.8,0,0,1,.6,2.06Z"/></svg>
|
||||
|
After Width: | Height: | Size: 894 B |
@@ -8,7 +8,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||
import { IResourceProviderService, IHandleFirewallRuleResult } from 'sql/workbench/services/resourceProvider/common/resourceProviderService';
|
||||
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
|
||||
import { FirewallRuleDialogController } from 'sql/workbench/contrib/accounts/browser/firewallRuleDialogController';
|
||||
import { FirewallRuleDialogController } from 'sql/workbench/services/resourceProvider/browser/firewallRuleDialogController';
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import { invalidProvider } from 'sql/base/common/errors';
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||
import { FirewallRuleDialog } from 'sql/workbench/services/resourceProvider/browser/firewallRuleDialog';
|
||||
import { FirewallRuleViewModel } from 'sql/platform/accounts/common/firewallRuleViewModel';
|
||||
import { FirewallRuleDialogController } from 'sql/workbench/services/resourceProvider/browser/firewallRuleDialogController';
|
||||
import { TestAccountManagementService } from 'sql/platform/accounts/test/common/testAccountManagementService';
|
||||
import { TestResourceProvider } from 'sql/workbench/services/resourceProvider/test/common/testResourceProviderService';
|
||||
import { TestErrorMessageService } from 'sql/platform/errorMessage/test/common/testErrorMessageService';
|
||||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||
import { Deferred } from 'sql/base/common/promise';
|
||||
import { mssqlProviderName } from 'sql/platform/connection/common/constants';
|
||||
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
|
||||
|
||||
// TESTS ///////////////////////////////////////////////////////////////////
|
||||
suite('Firewall rule dialog controller tests', () => {
|
||||
let connectionProfile: IConnectionProfile;
|
||||
let account: azdata.Account;
|
||||
let IPAddress = '250.222.155.198';
|
||||
let mockOnAddAccountErrorEvent: Emitter<string>;
|
||||
let mockOnCreateFirewallRule: Emitter<void>;
|
||||
|
||||
let instantiationService: TypeMoq.Mock<InstantiationService>;
|
||||
let mockFirewallRuleViewModel: TypeMoq.Mock<FirewallRuleViewModel>;
|
||||
let mockFirewallRuleDialog: TypeMoq.Mock<FirewallRuleDialog>;
|
||||
|
||||
setup(() => {
|
||||
account = {
|
||||
key: { providerId: 'azure', accountId: 'account1' },
|
||||
displayInfo: {
|
||||
contextualDisplayName: 'Microsoft Account',
|
||||
accountType: 'microsoft',
|
||||
displayName: 'Account 1',
|
||||
userId: 'user@email.com'
|
||||
},
|
||||
properties: [],
|
||||
isStale: false
|
||||
};
|
||||
|
||||
mockOnAddAccountErrorEvent = new Emitter<string>();
|
||||
mockOnCreateFirewallRule = new Emitter<void>();
|
||||
|
||||
// Create a mock firewall rule view model
|
||||
let firewallRuleViewModel = new FirewallRuleViewModel();
|
||||
mockFirewallRuleViewModel = TypeMoq.Mock.ofInstance(firewallRuleViewModel);
|
||||
mockFirewallRuleViewModel.setup(x => x.updateDefaultValues(TypeMoq.It.isAny()))
|
||||
.returns((ipAddress) => undefined);
|
||||
mockFirewallRuleViewModel.object.selectedAccount = account;
|
||||
mockFirewallRuleViewModel.object.isIPAddressSelected = true;
|
||||
|
||||
// Create a mocked out instantiation service
|
||||
instantiationService = TypeMoq.Mock.ofType(InstantiationService, TypeMoq.MockBehavior.Strict);
|
||||
instantiationService.setup(x => x.createInstance(TypeMoq.It.isValue(FirewallRuleViewModel)))
|
||||
.returns(() => mockFirewallRuleViewModel.object);
|
||||
|
||||
// Create a mock account picker
|
||||
let firewallRuleDialog = new FirewallRuleDialog(undefined!, undefined!, undefined!, instantiationService.object, undefined!, undefined!, new MockContextKeyService(), undefined!, undefined!, undefined!, undefined!);
|
||||
mockFirewallRuleDialog = TypeMoq.Mock.ofInstance(firewallRuleDialog);
|
||||
|
||||
let mockEvent = new Emitter<any>();
|
||||
mockFirewallRuleDialog.setup(x => x.onCancel)
|
||||
.returns(() => mockEvent.event);
|
||||
mockFirewallRuleDialog.setup(x => x.onCreateFirewallRule)
|
||||
.returns(() => mockOnCreateFirewallRule.event);
|
||||
mockFirewallRuleDialog.setup(x => x.onAddAccountErrorEvent)
|
||||
.returns((msg) => mockOnAddAccountErrorEvent.event);
|
||||
mockFirewallRuleDialog.setup(x => x.render());
|
||||
mockFirewallRuleDialog.setup(x => x.open());
|
||||
mockFirewallRuleDialog.setup(x => x.close());
|
||||
|
||||
instantiationService.setup(x => x.createInstance(TypeMoq.It.isValue(FirewallRuleDialog)))
|
||||
.returns(() => mockFirewallRuleDialog.object);
|
||||
|
||||
connectionProfile = {
|
||||
connectionName: 'new name',
|
||||
serverName: 'new server',
|
||||
databaseName: 'database',
|
||||
userName: 'user',
|
||||
password: 'password',
|
||||
authenticationType: '',
|
||||
savePassword: true,
|
||||
groupFullName: 'g2/g2-2',
|
||||
groupId: 'group id',
|
||||
getOptionsKey: () => '',
|
||||
matches: () => false,
|
||||
providerName: mssqlProviderName,
|
||||
options: {},
|
||||
saveProfile: true,
|
||||
id: ''
|
||||
};
|
||||
});
|
||||
|
||||
test('Add Account Failure - Error Message Shown', () => {
|
||||
// ... Create a mock instance of the error message service
|
||||
let errorMessageServiceStub = new TestErrorMessageService();
|
||||
let mockErrorMessageService = TypeMoq.Mock.ofInstance(errorMessageServiceStub);
|
||||
mockErrorMessageService.setup(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()));
|
||||
|
||||
// ... Create instance of the controller with an opened dialog
|
||||
let controller = new FirewallRuleDialogController(instantiationService.object, undefined!, undefined!, mockErrorMessageService.object);
|
||||
controller.openFirewallRuleDialog(connectionProfile, IPAddress, 'resourceID');
|
||||
|
||||
// If: The firewall rule dialog reports a failure
|
||||
|
||||
mockOnAddAccountErrorEvent.fire('Error message');
|
||||
|
||||
// Then: An error dialog should have been opened
|
||||
mockErrorMessageService.verify(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||
});
|
||||
|
||||
test('create firewall rule success', async () => {
|
||||
let deferredPromise = new Deferred();
|
||||
|
||||
mockFirewallRuleDialog.setup(x => x.onServiceComplete())
|
||||
.callback(() => {
|
||||
deferredPromise.resolve(true);
|
||||
});
|
||||
|
||||
// ... Create a mock instance of the account management test service
|
||||
let mockAccountManagementService = getMockAccountManagementService(true);
|
||||
|
||||
// ... Create a mock instance of the resource provider
|
||||
let mockResourceProvider = getMockResourceProvider(true, { result: true, errorMessage: '' });
|
||||
|
||||
// ... Create instance of the controller with an opened dialog
|
||||
let controller = new FirewallRuleDialogController(instantiationService.object, mockResourceProvider.object, mockAccountManagementService.object, undefined!);
|
||||
controller.openFirewallRuleDialog(connectionProfile, IPAddress, 'resourceID');
|
||||
|
||||
// If: The firewall rule dialog's create firewall rule get fired
|
||||
mockOnCreateFirewallRule.fire();
|
||||
|
||||
// Then: it should get security token from account management service and call create firewall rule in resource provider
|
||||
await deferredPromise;
|
||||
mockAccountManagementService.verify(x => x.getSecurityToken(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||
mockResourceProvider.verify(x => x.createFirewallRule(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||
mockFirewallRuleDialog.verify(x => x.close(), TypeMoq.Times.once());
|
||||
mockFirewallRuleDialog.verify(x => x.onServiceComplete(), TypeMoq.Times.once());
|
||||
});
|
||||
|
||||
test('create firewall rule fails during getSecurity', async () => {
|
||||
let deferredPromise = new Deferred<{}>();
|
||||
|
||||
// ... Create a mock instance of the error message service
|
||||
let mockErrorMessageService = getMockErrorMessageService(deferredPromise);
|
||||
|
||||
// ... Create a mock instance of the account management test service
|
||||
let mockAccountManagementService = getMockAccountManagementService(false);
|
||||
|
||||
// ... Create a mock instance of the resource provider
|
||||
let mockResourceProvider = getMockResourceProvider(true, { result: true, errorMessage: '' });
|
||||
|
||||
// ... Create instance of the controller with an opened dialog
|
||||
let controller = new FirewallRuleDialogController(instantiationService.object, mockResourceProvider.object, mockAccountManagementService.object, mockErrorMessageService.object);
|
||||
controller.openFirewallRuleDialog(connectionProfile, IPAddress, 'resourceID');
|
||||
|
||||
// If: The firewall rule dialog's create firewall rule get fired
|
||||
mockOnCreateFirewallRule.fire();
|
||||
|
||||
// Then: it should get security token from account management service and an error dialog should have been opened
|
||||
await deferredPromise;
|
||||
mockAccountManagementService.verify(x => x.getSecurityToken(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||
mockErrorMessageService.verify(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||
mockResourceProvider.verify(x => x.createFirewallRule(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.never());
|
||||
});
|
||||
|
||||
test('create firewall rule fails during createFirewallRule in ResourceProvider - result is false', async () => {
|
||||
let deferredPromise = new Deferred<{}>();
|
||||
|
||||
// ... Create a mock instance of the error message service
|
||||
let mockErrorMessageService = getMockErrorMessageService(deferredPromise);
|
||||
|
||||
// ... Create a mock instance of the account management test service
|
||||
let mockAccountManagementService = getMockAccountManagementService(true);
|
||||
|
||||
// ... Create a mock instance of the resource provider
|
||||
let mockResourceProvider = getMockResourceProvider(true, { result: false, errorMessage: '' });
|
||||
|
||||
// ... Create instance of the controller with an opened dialog
|
||||
let controller = new FirewallRuleDialogController(instantiationService.object, mockResourceProvider.object, mockAccountManagementService.object, mockErrorMessageService.object);
|
||||
controller.openFirewallRuleDialog(connectionProfile, IPAddress, 'resourceID');
|
||||
|
||||
// If: The firewall rule dialog's create firewall rule get fired
|
||||
mockOnCreateFirewallRule.fire();
|
||||
|
||||
// Then: it should get security token from account management service and an error dialog should have been opened
|
||||
await deferredPromise;
|
||||
|
||||
mockAccountManagementService.verify(x => x.getSecurityToken(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||
mockResourceProvider.verify(x => x.createFirewallRule(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||
mockErrorMessageService.verify(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||
});
|
||||
|
||||
test('create firewall rule fails during createFirewallRule in ResourceProvider - reject promise', async () => {
|
||||
let deferredPromise = new Deferred<{}>();
|
||||
|
||||
// ... Create a mock instance of the error message service
|
||||
let mockErrorMessageService = getMockErrorMessageService(deferredPromise);
|
||||
|
||||
// ... Create a mock instance of the account management test service
|
||||
let mockAccountManagementService = getMockAccountManagementService(true);
|
||||
|
||||
// ... Create a mock instance of the resource provider
|
||||
let mockResourceProvider = getMockResourceProvider(false);
|
||||
|
||||
// ... Create instance of the controller with an opened dialog
|
||||
let controller = new FirewallRuleDialogController(instantiationService.object, mockResourceProvider.object, mockAccountManagementService.object, mockErrorMessageService.object);
|
||||
controller.openFirewallRuleDialog(connectionProfile, IPAddress, 'resourceID');
|
||||
|
||||
// If: The firewall rule dialog's create firewall rule get fired
|
||||
mockOnCreateFirewallRule.fire();
|
||||
|
||||
// Then: it should get security token from account management service and an error dialog should have been opened
|
||||
await deferredPromise;
|
||||
mockAccountManagementService.verify(x => x.getSecurityToken(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||
mockResourceProvider.verify(x => x.createFirewallRule(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||
mockErrorMessageService.verify(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||
});
|
||||
});
|
||||
|
||||
function getMockAccountManagementService(resolveSecurityToken: boolean): TypeMoq.Mock<TestAccountManagementService> {
|
||||
let accountManagementTestService = new TestAccountManagementService();
|
||||
let mockAccountManagementService = TypeMoq.Mock.ofInstance(accountManagementTestService);
|
||||
mockAccountManagementService.setup(x => x.getSecurityToken(TypeMoq.It.isAny(), TypeMoq.It.isAny()))
|
||||
.returns(() => resolveSecurityToken ? Promise.resolve({}) : Promise.reject(null));
|
||||
return mockAccountManagementService;
|
||||
}
|
||||
|
||||
function getMockResourceProvider(resolveCreateFirewallRule: boolean, response?: azdata.CreateFirewallRuleResponse): TypeMoq.Mock<TestResourceProvider> {
|
||||
let resourceProviderStub = new TestResourceProvider();
|
||||
let mockResourceProvider = TypeMoq.Mock.ofInstance(resourceProviderStub);
|
||||
mockResourceProvider.setup(x => x.createFirewallRule(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()))
|
||||
.returns(() => resolveCreateFirewallRule ? Promise.resolve(response) : Promise.reject(null));
|
||||
return mockResourceProvider;
|
||||
}
|
||||
|
||||
function getMockErrorMessageService(deferredPromise: Deferred<{}>): TypeMoq.Mock<TestErrorMessageService> {
|
||||
let errorMessageServiceStub = new TestErrorMessageService();
|
||||
let mockErrorMessageService = TypeMoq.Mock.ofInstance(errorMessageServiceStub);
|
||||
mockErrorMessageService.setup(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).callback(() => {
|
||||
deferredPromise.resolve(true);
|
||||
});
|
||||
return mockErrorMessageService;
|
||||
}
|
||||
Reference in New Issue
Block a user