Refresh master with initial release/0.24 snapshot (#332)

* Initial port of release/0.24 source code

* Fix additional headers

* Fix a typo in launch.json
This commit is contained in:
Karl Burtram
2017-12-15 15:38:57 -08:00
committed by GitHub
parent 271b3a0b82
commit 6ad0df0e3e
7118 changed files with 107999 additions and 56466 deletions

View File

@@ -8,15 +8,14 @@
import 'vs/css!./media/accountDialog';
import 'vs/css!sql/parts/accountManagement/common/media/accountActions';
import * as DOM from 'vs/base/browser/dom';
import { SplitView } from 'vs/base/browser/ui/splitview/splitview';
import { SplitView } from 'sql/base/browser/ui/splitview/splitview';
import { List } from 'vs/base/browser/ui/list/listWidget';
import { IListService } from 'vs/platform/list/browser/listService';
import { Button } from 'vs/base/browser/ui/button/button';
import { IPartService } from 'vs/workbench/services/part/common/partService';
import Event, { Emitter } from 'vs/base/common/event';
import { localize } from 'vs/nls';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { attachListStyler, attachButtonStyler } from 'vs/platform/theme/common/styler';
import { attachListStyler } from 'vs/platform/theme/common/styler';
import { ActionRunner } from 'vs/base/common/actions';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -25,8 +24,9 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import * as TelemetryKeys from 'sql/common/telemetryKeys';
import * as data from 'data';
import { Button } from 'sql/base/browser/ui/button/button';
import { Modal } from 'sql/base/browser/ui/modal/modal';
import { attachModalDialogStyler } from 'sql/common/theme/styler';
import { attachModalDialogStyler, attachButtonStyler } from 'sql/common/theme/styler';
import { AccountViewModel } from 'sql/parts/accountManagement/accountDialog/accountViewModel';
import { AddAccountAction } from 'sql/parts/accountManagement/common/accountActions';
import { AccountListRenderer, AccountListDelegate } from 'sql/parts/accountManagement/common/accountListRenderer';
@@ -67,7 +67,7 @@ export class AccountDialog extends Modal {
@IContextKeyService contextKeyService: IContextKeyService
) {
super(
localize('linkedAccounts', 'Linked Accounts'),
localize('linkedAccounts', 'Linked accounts'),
TelemetryKeys.Accounts,
partService,
telemetryService,
@@ -81,7 +81,7 @@ export class AccountDialog extends Modal {
this._actionRunner = new ActionRunner();
// Setup the event emitters
this._onAddAccountErrorEmitter = new Emitter<string>();
this._onAddAccountErrorEmitter = new Emitter<string>();
this._onCloseEmitter = new Emitter<void>();
// Create the view model and wire up the events

View File

@@ -18,8 +18,6 @@ import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar';
import { IAccountManagementService } from 'sql/services/accountManagement/interfaces';
export class AccountListStatusbarItem implements IStatusbarItem {
private _rootElement: HTMLElement;
private _iconElement: HTMLElement;
private _toDispose: IDisposable[];
private _manageLinkedAccountAction: IAction;
@@ -32,11 +30,11 @@ export class AccountListStatusbarItem implements IStatusbarItem {
public render(container: HTMLElement): IDisposable {
// Create root element for account list
this._rootElement = append(container, $('.linked-account-staus'));
this._rootElement.title = ManageLinkedAccountAction.LABEL;
this._rootElement.onclick = () => this._onClick();
this._iconElement = append(this._rootElement, $('a.linked-account-status-selection'));
const rootElement = append(container, $('.linked-account-staus'));
const accountElement = append(rootElement, $('a.linked-account-status-selection'));
accountElement.title = ManageLinkedAccountAction.LABEL;
accountElement.onclick = () => this._onClick();
append(accountElement, $('.linked-account-icon'));
return combinedDisposable(this._toDispose);
}

View File

@@ -3,9 +3,14 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.statusbar-item .linked-account-staus a.linked-account-status-selection {
background: url('accounts_statusbar_inverse.svg') center center no-repeat;
background-size: 12px;
height: 12px !important;
.statusbar-item .linked-account-staus a.linked-account-status-selection .linked-account-icon {
-webkit-mask: url('accounts_statusbar_inverse.svg') no-repeat 50% 50%;
-webkit-mask-size: 12px;
background-color: rgb(255, 255, 255);
width: 12px;
height: 22px;
}
.statusbar-item .linked-account-staus a.linked-account-status-selection {
padding: 0 5px 0 5px;
}

View File

@@ -34,6 +34,7 @@ export class AccountPicker extends Disposable {
private _refreshContainer: HTMLElement;
private _listContainer: HTMLElement;
private _dropdown: DropdownList;
private _refreshAccountAction: RefreshAccountAction;
// EVENTING ////////////////////////////////////////////////////////////
private _addAccountCompleteEmitter: Emitter<void>;
@@ -62,13 +63,6 @@ export class AccountPicker extends Disposable {
this._addAccountStartEmitter = new Emitter<void>();
this._onAccountSelectionChangeEvent = new Emitter<data.Account>();
// Create an account list
let delegate = new AccountListDelegate(AccountPicker.ACCOUNTPICKERLIST_HEIGHT);
let accountRenderer = new AccountPickerListRenderer();
this._listContainer = DOM.$('div.account-list-container');
this._accountList = new List<data.Account>(this._listContainer, delegate, [accountRenderer]);
this._register(attachListStyler(this._accountList, this._themeService));
// Create the view model, wire up the events, and initialize with baseline data
this.viewModel = this._instantiationService.createInstance(AccountPickerViewModel, this._providerId);
this.viewModel.updateAccountListEvent(arg => {
@@ -76,8 +70,6 @@ export class AccountPicker extends Disposable {
this.updateAccountList(arg.accountList);
}
});
this.createAccountPickerComponent();
}
// PUBLIC METHODS //////////////////////////////////////////////////////
@@ -88,7 +80,18 @@ export class AccountPicker extends Disposable {
DOM.append(container, this._rootElement);
}
private createAccountPickerComponent() {
// PUBLIC METHODS //////////////////////////////////////////////////////
/**
* Create account picker component
*/
public createAccountPickerComponent() {
// Create an account list
let delegate = new AccountListDelegate(AccountPicker.ACCOUNTPICKERLIST_HEIGHT);
let accountRenderer = new AccountPickerListRenderer();
this._listContainer = DOM.$('div.account-list-container');
this._accountList = new List<data.Account>(this._listContainer, delegate, [accountRenderer]);
this._register(attachListStyler(this._accountList, this._themeService));
this._rootElement = DOM.$('div.account-picker-container');
// Create a dropdown for account picker
@@ -116,7 +119,8 @@ export class AccountPicker extends Disposable {
this._refreshContainer = DOM.append(this._rootElement, DOM.$('div.refresh-container'));
DOM.append(this._refreshContainer, DOM.$('div.icon warning'));
let actionBar = new ActionBar(this._refreshContainer, { animated: false });
actionBar.push(new RefreshAccountAction(RefreshAccountAction.ID, RefreshAccountAction.LABEL), { icon: false, label: true });
this._refreshAccountAction = this._instantiationService.createInstance(RefreshAccountAction);
actionBar.push(this._refreshAccountAction, { icon: false, label: true });
if (this._accountList.length > 0) {
this._accountList.setSelection([0]);
@@ -146,10 +150,12 @@ export class AccountPicker extends Disposable {
private onAccountSelectionChange(account: data.Account) {
this.viewModel.selectedAccount = account;
if (account && account.isStale) {
this._refreshAccountAction.account = account;
new Builder(this._refreshContainer).show();
} else {
new Builder(this._refreshContainer).hide();
}
this._onAccountSelectionChangeEvent.fire(account);
}
@@ -170,9 +176,9 @@ export class AccountPicker extends Disposable {
const badgeContent = DOM.append(badge, DOM.$('div.badge-content'));
const label = DOM.append(row, DOM.$('div.label'));
icon.className = 'icon';
// Set the account icon
icon.style.background = `url('data:${account.displayInfo.contextualLogo.light}')`;
icon.classList.add('icon', account.displayInfo.accountType);
// TODO: Pick between the light and dark logo
label.innerText = account.displayInfo.displayName + ' (' + account.displayInfo.contextualDisplayName + ')';

View File

@@ -54,6 +54,7 @@ export class AccountPickerService implements IAccountPickerService {
// TODO: expand support to multiple providers
const providerId: string = 'azurePublicCloud';
this._accountPicker = this._instantiationService.createInstance(AccountPicker, providerId);
this._accountPicker.createAccountPickerComponent();
}
this._accountPicker.addAccountCompleteEvent(() => this._addAccountCompleteEmitter.fire());

View File

@@ -0,0 +1,160 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import 'vs/css!./media/autoOAuthDialog';
import { Builder, $ } from 'vs/base/browser/builder';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { attachInputBoxStyler } from 'vs/platform/theme/common/styler';
import { IPartService } from 'vs/workbench/services/part/common/partService';
import Event, { Emitter } from 'vs/base/common/event';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { localize } from 'vs/nls';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
import { Button } from 'sql/base/browser/ui/button/button';
import { Modal } from 'sql/base/browser/ui/modal/modal';
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox';
import { attachModalDialogStyler, attachButtonStyler } from 'sql/common/theme/styler';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import * as TelemetryKeys from 'sql/common/telemetryKeys';
export class AutoOAuthDialog extends Modal {
private _copyAndOpenButton: Button;
private _closeButton: Button;
private _userCodeInputBox: InputBox;
private _websiteInputBox: InputBox;
private _descriptionElement: HTMLElement;
// EVENTING ////////////////////////////////////////////////////////////
private _onHandleAddAccount = new Emitter<void>();
public get onHandleAddAccount(): Event<void> { return this._onHandleAddAccount.event; }
private _onCancel = new Emitter<void>();
public get onCancel(): Event<void> { return this._onCancel.event; }
private _onCloseEvent = new Emitter<void>();
public get onCloseEvent(): Event<void> { return this._onCloseEvent.event; }
constructor(
@IPartService partService: IPartService,
@IThemeService private _themeService: IThemeService,
@IContextViewService private _contextViewService: IContextViewService,
@ITelemetryService telemetryService: ITelemetryService,
@IContextKeyService contextKeyService: IContextKeyService
) {
super(
'',
TelemetryKeys.AutoOAuth,
partService,
telemetryService,
contextKeyService,
{
isFlyout: true,
hasBackButton: true,
hasSpinner: true
}
);
}
public render() {
super.render();
attachModalDialogStyler(this, this._themeService);
this.backButton.addListener('click', () => this.cancel());
this._register(attachButtonStyler(this.backButton, this._themeService, { buttonBackground: SIDE_BAR_BACKGROUND, buttonHoverBackground: SIDE_BAR_BACKGROUND }));
this._copyAndOpenButton = this.addFooterButton(localize('copyAndOpen', 'Copy & Open'), () => this.addAccount());
this._closeButton = this.addFooterButton(localize('cancel', 'Cancel'), () => this.cancel());
this.registerListeners();
this._userCodeInputBox.disable();
this._websiteInputBox.disable();
}
protected layout(height?: number): void {
// NO OP
}
protected renderBody(container: HTMLElement) {
$().div({ class: 'auto-oauth-description-section new-section' }, (descriptionContainer) => {
this._descriptionElement = descriptionContainer.getHTMLElement();
});
let addAccountSection;
$().div({ class: 'auto-oauth-info-section new-section' }, (addAccountContainer) => {
addAccountSection = addAccountContainer.getHTMLElement();
this._userCodeInputBox = this.createInputBoxHelper(addAccountContainer, localize('userCode', 'User code'));
this._websiteInputBox = this.createInputBoxHelper(addAccountContainer, localize('website', 'Website'));
});
new Builder(container).div({ class: 'auto-oauth-dialog' }, (builder) => {
builder.append(this._descriptionElement);
builder.append(addAccountSection);
});
}
private createInputBoxHelper(container: Builder, label: string): InputBox {
let inputBox: InputBox;
container.div({ class: 'dialog-input-section' }, (inputContainer) => {
inputContainer.div({ class: 'dialog-label' }, (labelContainer) => {
labelContainer.innerHtml(label);
});
inputContainer.div({ class: 'dialog-input' }, (inputCellContainer) => {
inputBox = new InputBox(inputCellContainer.getHTMLElement(), this._contextViewService);
});
});
return inputBox;
}
private registerListeners(): void {
// Theme styler
this._register(attachButtonStyler(this._copyAndOpenButton, this._themeService));
this._register(attachButtonStyler(this._closeButton, this._themeService));
this._register(attachInputBoxStyler(this._userCodeInputBox, this._themeService));
this._register(attachInputBoxStyler(this._websiteInputBox, this._themeService));
}
/* Overwrite escape key behavior */
protected onClose() {
this.cancel();
}
/* Overwrite enter key behavior */
protected onAccept() {
this.addAccount();
}
private addAccount() {
if (this._copyAndOpenButton.enabled) {
this._copyAndOpenButton.enabled = false;
this.showSpinner();
this._onHandleAddAccount.fire();
}
}
public cancel() {
this._onCancel.fire();
}
public close() {
this._copyAndOpenButton.enabled = true;
this._onCloseEvent.fire();
this.hideSpinner();
this.hide();
}
public open(title: string, message: string, userCode: string, uri: string) {
// Update dialog
this.title = title;
this._descriptionElement.innerText = message;
this._userCodeInputBox.value = userCode;
this._websiteInputBox.value = uri;
this.show();
this._copyAndOpenButton.focus();
}
}

View File

@@ -0,0 +1,79 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import Severity from 'vs/base/common/severity';
import { localize } from 'vs/nls';
import { IErrorMessageService } from 'sql/parts/connection/common/connectionManagement';
import { AutoOAuthDialog } from 'sql/parts/accountManagement/autoOAuthDialog/autoOAuthDialog';
import { IAccountManagementService } from 'sql/services/accountManagement/interfaces';
export class AutoOAuthDialogController {
// MEMBER VARIABLES ////////////////////////////////////////////////////
private _autoOAuthDialog: AutoOAuthDialog;
private _providerId: string;
private _userCode: string;
private _uri: string;
constructor(
@IInstantiationService private _instantiationService: IInstantiationService,
@IAccountManagementService private _accountManagementService: IAccountManagementService,
@IErrorMessageService private _errorMessageService: IErrorMessageService
) {
this._providerId = null;
}
/**
* Open auto OAuth dialog
*/
public openAutoOAuthDialog(providerId: string, title: string, message: string, userCode: string, uri: string): Thenable<void> {
if (this._providerId !== null) {
// If a oauth flyout is already open, return an error
let errorMessage = localize('oauthFlyoutIsAlreadyOpen', 'Cannot start auto OAuth. An auto OAuth is already in progress.');
this._errorMessageService.showDialog(Severity.Error, '', errorMessage);
return Promise.reject(new Error('Auto OAuth dialog already open'));
}
// Create a new dialog if one doesn't exist
if (!this._autoOAuthDialog) {
this._autoOAuthDialog = this._instantiationService.createInstance(AutoOAuthDialog);
this._autoOAuthDialog.onHandleAddAccount(this.handleOnAddAccount, this);
this._autoOAuthDialog.onCancel(this.handleOnCancel, this);
this._autoOAuthDialog.onCloseEvent(this.handleOnClose, this);
this._autoOAuthDialog.render();
}
this._userCode = userCode;
this._uri = uri;
// Open the dialog
this._autoOAuthDialog.open(title, message, userCode, uri);
this._providerId = providerId;
return Promise.resolve();
}
/**
* Close auto OAuth dialog
*/
public closeAutoOAuthDialog(): void {
this._autoOAuthDialog.close();
this._providerId = null;
}
// PRIVATE HELPERS /////////////////////////////////////////////////////
private handleOnCancel(): void {
this._accountManagementService.cancelAutoOAuthDeviceCode(this._providerId);
}
private handleOnClose(): void {
this._providerId = null;
}
private handleOnAddAccount(): void {
this._accountManagementService.copyUserCodeAndOpenBrowser(this._userCode, this._uri);
}
}

View File

@@ -0,0 +1,29 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.auto-oauth-dialog {
padding: 15px
}
.modal .auto-oauth-dialog .new-section {
padding-bottom: 30px;
}
.modal .auto-oauth-dialog .dialog-input-section {
display: flex;
padding-left: 15px;
padding-right: 15px;
padding-top: 10px;
padding-bottom: 10px;
}
.modal .auto-oauth-dialog .dialog-input-section .dialog-label {
flex: 0 0 100px;
align-self: center;
}
.modal .auto-oauth-dialog .dialog-input-section .dialog-input {
flex: 1 1 auto;
}

View File

@@ -36,8 +36,6 @@ export class AddAccountAction extends Action {
constructor(
private _providerId: string,
@IMessageService private _messageService: IMessageService,
@IErrorMessageService private _errorMessageService: IErrorMessageService,
@IAccountManagementService private _accountManagementService: IAccountManagementService
) {
super(AddAccountAction.ID, AddAccountAction.LABEL);
@@ -99,21 +97,25 @@ export class RemoveAccountAction extends Action {
type: 'question'
};
if (!this._messageService.confirm(confirm)) {
return TPromise.as(false);
}
let confirmPromise = this._messageService.confirm(confirm);
return new TPromise((resolve, reject) => {
self._accountManagementService.removeAccount(self._account.key)
.then(
(result) => { resolve(result); },
(err) => {
// Must handle here as this is an independent action
self._errorMessageService.showDialog(Severity.Error,
localize('removeAccountFailed', 'Failed to remove account'), err);
resolve(false);
}
);
return confirmPromise.then(confirmation => {
if (!confirmation.confirmed) {
return TPromise.as(false);
} else {
return new TPromise((resolve, reject) => {
self._accountManagementService.removeAccount(self._account.key)
.then(
(result) => { resolve(result); },
(err) => {
// Must handle here as this is an independent action
self._errorMessageService.showDialog(Severity.Error,
localize('removeAccountFailed', 'Failed to remove account'), err);
resolve(false);
}
);
});
}
});
}
}
@@ -144,15 +146,31 @@ export class ApplyFilterAction extends Action {
export class RefreshAccountAction extends Action {
public static ID = 'account.refresh';
public static LABEL = localize('refreshAccount', 'Reenter your credentials');
public account: data.Account;
constructor(
id: string,
label: string
@IAccountManagementService private _accountManagementService: IAccountManagementService
) {
super(id, label, 'refresh-account-action icon refresh');
super(RefreshAccountAction.ID, RefreshAccountAction.LABEL, 'refresh-account-action icon refresh');
}
public run(): TPromise<boolean> {
// Todo: refresh the account
return TPromise.as(true);
let self = this;
return new TPromise((resolve, reject) => {
if (self.account) {
self._accountManagementService.refreshAccount(self.account)
.then(
() => {
resolve(true);
},
err => {
error(`Error while refreshing account: ${err}`);
reject(err);
}
);
} else {
let errorMessage = localize('NoAccountToRefresh', 'There is no account to refresh');
reject(errorMessage);
}
});
}
}

View File

@@ -13,7 +13,7 @@ import { ActionBar, IActionOptions } from 'vs/base/browser/ui/actionbar/actionba
import { localize } from 'vs/nls';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { RemoveAccountAction, ApplyFilterAction, RefreshAccountAction } from 'sql/parts/accountManagement/common/accountActions';
import { RemoveAccountAction, RefreshAccountAction } from 'sql/parts/accountManagement/common/accountActions';
import * as data from 'data';
@@ -66,9 +66,7 @@ export class AccountPickerListRenderer implements IRenderer<data.Account, Accoun
public renderElement(account: data.Account, index: number, templateData: AccountListTemplate): void {
// Set the account icon
templateData.icon.classList.add('account-logo');
templateData.icon.style.background = `url('data:${account.displayInfo.contextualLogo.light}')`;
// TODO: Pick between the light and dark logo
templateData.icon.classList.add('account-logo', account.displayInfo.accountType);
templateData.contextualDisplayName.innerText = account.displayInfo.contextualDisplayName;
templateData.displayName.innerText = account.displayInfo.displayName;
@@ -114,9 +112,12 @@ export class AccountListRenderer extends AccountPickerListRenderer {
let actionOptions: IActionOptions = { icon: true, label: false };
if (account.isStale) {
templateData.actions.push(new RefreshAccountAction(RefreshAccountAction.ID, RefreshAccountAction.LABEL), actionOptions);
let refreshAction = this._instantiationService.createInstance(RefreshAccountAction);
refreshAction.account = account;
templateData.actions.push(refreshAction, actionOptions);
} else {
templateData.actions.push(new ApplyFilterAction(ApplyFilterAction.ID, ApplyFilterAction.LABEL), actionOptions);
// Todo: Will show filter action when API/GUI for filtering is implemented (#3022, #3024)
// templateData.actions.push(new ApplyFilterAction(ApplyFilterAction.ID, ApplyFilterAction.LABEL), actionOptions);
}
let removeAction = this._instantiationService.createInstance(RemoveAccountAction, account);

View File

@@ -0,0 +1,109 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { Registry } from 'vs/platform/registry/common/platform';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { IExtensionPointUser, ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { localize } from 'vs/nls';
import { join } from 'path';
import { createCSSRule } from 'vs/base/browser/dom';
import URI from 'vs/base/common/uri';
import { ManageLinkedAccountAction } from 'sql/parts/accountManagement/accountListStatusbar/accountListStatusbarItem';
let actionRegistry = <IWorkbenchActionRegistry>Registry.as(Extensions.WorkbenchActions);
actionRegistry.registerWorkbenchAction(
new SyncActionDescriptor(
ManageLinkedAccountAction,
ManageLinkedAccountAction.ID,
ManageLinkedAccountAction.LABEL
),
ManageLinkedAccountAction.LABEL
);
export interface IAccountContrib {
id: string;
icon?: IUserFriendlyIcon;
}
export type IUserFriendlyIcon = string | { light: string; dark: string; };
const account: IJSONSchema = {
type: 'object',
properties: {
id: {
description: localize('carbon.extension.contributes.account.id', 'Identifier of the account type'),
type: 'string'
},
icon: {
description: localize('carbon.extension.contributes.account.icon', '(Optional) Icon which is used to represent the accpunt in the UI. Either a file path or a themable configuration'),
anyOf: [{
type: 'string'
},
{
type: 'object',
properties: {
light: {
description: localize('carbon.extension.contributes.account.icon.light', 'Icon path when a light theme is used'),
type: 'string'
},
dark: {
description: localize('carbon.extension.contributes.account.icon.dark', 'Icon path when a dark theme is used'),
type: 'string'
}
}
}]
}
}
};
export const accountsContribution: IJSONSchema = {
description: localize('carbon.extension.contributes.account', "Contributes icons to account provider."),
oneOf: [
account,
{
type: 'array',
items: account
}
]
};
ExtensionsRegistry.registerExtensionPoint<IAccountContrib | IAccountContrib[]>('account-type', [], accountsContribution).setHandler(extensions => {
function handleCommand(account: IAccountContrib, extension: IExtensionPointUser<any>) {
let { icon, id } = account;
let iconClass: string;
if (icon) {
iconClass = id;
if (typeof icon === 'string') {
const path = join(extension.description.extensionFolderPath, icon);
createCSSRule(`.icon.${iconClass}`, `background-image: url("${URI.file(path).toString()}")`);
} else {
const light = join(extension.description.extensionFolderPath, icon.light);
const dark = join(extension.description.extensionFolderPath, icon.dark);
createCSSRule(`.icon.${iconClass}`, `background-image: url("${URI.file(light).toString()}")`);
createCSSRule(`.vs-dark .icon.${iconClass}, .hc-black .icon.${iconClass}`, `background-image: url("${URI.file(dark).toString()}")`);
}
}
}
for (let extension of extensions) {
const { value } = extension;
if (Array.isArray<IAccountContrib>(value)) {
for (let command of value) {
handleCommand(command, extension);
}
} else {
handleCommand(value, extension);
}
}
});

View File

@@ -6,7 +6,6 @@
'use strict';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import { IResourceProviderService, IHandleFirewallRuleResult } from 'sql/parts/accountManagement/common/interfaces';
@@ -26,7 +25,6 @@ export class ResourceProviderService implements IResourceProviderService {
constructor(
@ITelemetryService private _telemetryService: ITelemetryService,
@IInstantiationService private _instantiationService: IInstantiationService,
@IEnvironmentService private _environmentService: IEnvironmentService
) {
}
@@ -66,39 +64,33 @@ export class ResourceProviderService implements IResourceProviderService {
* Handle a firewall rule
*/
public handleFirewallRule(errorCode: number, errorMessage: string, connectionTypeId: string): Promise<IHandleFirewallRuleResult> {
if (!this._environmentService.isBuilt) {
let self = this;
return new Promise<IHandleFirewallRuleResult>((resolve, reject) => {
let handleFirewallRuleResult: IHandleFirewallRuleResult;
let promises = [];
if (self._providers) {
for (let key in self._providers) {
let provider = self._providers[key];
promises.push(provider.handleFirewallRule(errorCode, errorMessage, connectionTypeId)
.then(response => {
if (response.result) {
handleFirewallRuleResult = { canHandleFirewallRule: response.result, ipAddress: response.ipAddress, resourceProviderId: key };
}
},
() => { /* Swallow failures at getting accounts, we'll just hide that provider */
}));
}
let self = this;
return new Promise<IHandleFirewallRuleResult>((resolve, reject) => {
let handleFirewallRuleResult: IHandleFirewallRuleResult;
let promises = [];
if (self._providers) {
for (let key in self._providers) {
let provider = self._providers[key];
promises.push(provider.handleFirewallRule(errorCode, errorMessage, connectionTypeId)
.then(response => {
if (response.result) {
handleFirewallRuleResult = { canHandleFirewallRule: response.result, ipAddress: response.ipAddress, resourceProviderId: key };
}
},
() => { /* Swallow failures at getting accounts, we'll just hide that provider */
}));
}
}
Promise.all(promises).then(() => {
if (handleFirewallRuleResult) {
resolve(handleFirewallRuleResult);
} else {
handleFirewallRuleResult = { canHandleFirewallRule: false, ipAddress: undefined, resourceProviderId: undefined };
resolve(handleFirewallRuleResult);
}
});
Promise.all(promises).then(() => {
if (handleFirewallRuleResult) {
resolve(handleFirewallRuleResult);
} else {
handleFirewallRuleResult = { canHandleFirewallRule: false, ipAddress: undefined, resourceProviderId: undefined };
resolve(handleFirewallRuleResult);
}
});
} else {
return new Promise<IHandleFirewallRuleResult>((resolve, reject) => {
resolve({ canHandleFirewallRule: false, ipAddress: undefined, resourceProviderId: undefined });
});
}
});
}
/**

View File

@@ -8,24 +8,23 @@
import 'vs/css!./media/firewallRuleDialog';
import { Builder, $ } from 'vs/base/browser/builder';
import * as DOM from 'vs/base/browser/dom';
import { Button } from 'vs/base/browser/ui/button/button';
import { IPartService } from 'vs/workbench/services/part/common/partService';
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 { IWorkbenchThemeService, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { attachButtonStyler, attachInputBoxStyler } from 'vs/platform/theme/common/styler';
import { attachInputBoxStyler } from 'vs/platform/theme/common/styler';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import * as data from 'data';
import { Button } from 'sql/base/browser/ui/button/button';
import { Modal } from 'sql/base/browser/ui/modal/modal';
import { FirewallRuleViewModel } from 'sql/parts/accountManagement/firewallRuleDialog/firewallRuleViewModel';
import { attachModalDialogStyler } from 'sql/common/theme/styler';
import { attachModalDialogStyler, attachButtonStyler } from 'sql/common/theme/styler';
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox';
import { IAccountPickerService } from 'sql/parts/accountManagement/common/interfaces';
import * as TelemetryKeys from 'sql/common/telemetryKeys';

View File

@@ -10,7 +10,7 @@ import { localize } from 'vs/nls';
import * as data from 'data';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import { IConnectionManagementService, IErrorMessageService } from 'sql/parts/connection/common/connectionManagement';
import { IErrorMessageService } from 'sql/parts/connection/common/connectionManagement';
import { FirewallRuleDialog } from 'sql/parts/accountManagement/firewallRuleDialog/firewallRuleDialog';
import { IAccountManagementService } from 'sql/services/accountManagement/interfaces';
import { IResourceProviderService } from 'sql/parts/accountManagement/common/interfaces';
@@ -29,7 +29,6 @@ export class FirewallRuleDialogController {
constructor(
@IInstantiationService private _instantiationService: IInstantiationService,
@IResourceProviderService private _resourceProviderService: IResourceProviderService,
@IConnectionManagementService private _connectionService: IConnectionManagementService,
@IAccountManagementService private _accountManagementService: IAccountManagementService,
@IErrorMessageService private _errorMessageService: IErrorMessageService
) {