mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-19 18:46:52 -05:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
efd809971f | ||
|
|
38ae14cc4d | ||
|
|
c7e33a90fe | ||
|
|
5add835750 | ||
|
|
734c614cba | ||
|
|
f6b347fa62 | ||
|
|
08d2f3125e | ||
|
|
385c48dcad |
@@ -91,17 +91,17 @@ Filename: "{app}\{#ExeBasename}.exe"; Description: "{cm:LaunchProgram,{#NameLong
|
||||
#else
|
||||
#define SoftwareClassesRootKey "HKLM"
|
||||
#endif
|
||||
Root: HKCR; Subkey: "{#RegValueName}SourceFile"; ValueType: string; ValueName: ""; ValueData: "{cm:SourceFile,{#NameLong}}"; Flags: uninsdeletekey
|
||||
Root: HKCR; Subkey: "{#RegValueName}SourceFile\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\resources\app\resources\win32\code_file.ico"
|
||||
Root: HKCR; Subkey: "{#RegValueName}SourceFile\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1"""
|
||||
Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\{#RegValueName}SourceFile"; ValueType: string; ValueName: ""; ValueData: "{cm:SourceFile,{#NameLong}}"; Flags: uninsdeletekey
|
||||
Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\{#RegValueName}SourceFile\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\resources\app\resources\win32\code_file.ico"
|
||||
Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\{#RegValueName}SourceFile\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1"""
|
||||
Root: HKCU; Subkey: "Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};{app}\bin"; Tasks: addtopath; Check: NeedsAddPath(ExpandConstant('{app}\bin'))
|
||||
|
||||
Root: HKCU; Subkey: "Software\Classes\.sql\OpenWithProgids"; ValueType: none; ValueName: "{#RegValueName}"; Flags: deletevalue uninsdeletevalue; Tasks: associatewithfiles
|
||||
Root: HKCU; Subkey: "Software\Classes\.sql\OpenWithProgids"; ValueType: string; ValueName: "{#RegValueName}.sql"; ValueData: ""; Flags: uninsdeletevalue; Tasks: associatewithfiles
|
||||
Root: HKCU; Subkey: "Software\Classes\{#RegValueName}.sql"; ValueType: string; ValueName: ""; ValueData: "{cm:SourceFile,SQL}"; Flags: uninsdeletekey; Tasks: associatewithfiles
|
||||
Root: HKCU; Subkey: "Software\Classes\{#RegValueName}.sql"; ValueType: string; ValueName: "AppUserModelID"; ValueData: "{#AppUserId}"; Flags: uninsdeletekey; Tasks: associatewithfiles
|
||||
Root: HKCU; Subkey: "Software\Classes\{#RegValueName}.sql\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\resources\app\resources\win32\code_file.ico"; Tasks: associatewithfiles
|
||||
Root: HKCU; Subkey: "Software\Classes\{#RegValueName}.sql\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1"""; Tasks: associatewithfiles
|
||||
Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\.sql\OpenWithProgids"; ValueType: none; ValueName: "{#RegValueName}"; Flags: deletevalue uninsdeletevalue; Tasks: associatewithfiles
|
||||
Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\.sql\OpenWithProgids"; ValueType: string; ValueName: "{#RegValueName}.sql"; ValueData: ""; Flags: uninsdeletevalue; Tasks: associatewithfiles
|
||||
Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\{#RegValueName}.sql"; ValueType: string; ValueName: ""; ValueData: "{cm:SourceFile,SQL}"; Flags: uninsdeletekey; Tasks: associatewithfiles
|
||||
Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\{#RegValueName}.sql"; ValueType: string; ValueName: "AppUserModelID"; ValueData: "{#AppUserId}"; Flags: uninsdeletekey; Tasks: associatewithfiles
|
||||
Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\{#RegValueName}.sql\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\resources\app\resources\win32\code_file.ico"; Tasks: associatewithfiles
|
||||
Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\{#RegValueName}.sql\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1"""; Tasks: associatewithfiles
|
||||
; Environment
|
||||
#if "user" == InstallTarget
|
||||
#define EnvironmentRootKey "HKCU"
|
||||
|
||||
@@ -223,22 +223,16 @@ export default class TokenCache implements adal.TokenCache {
|
||||
return this.getOrCreateEncryptionParams()
|
||||
.then(encryptionParams => {
|
||||
try {
|
||||
let cacheCipher = fs.readFileSync(self._cacheSerializationPath, TokenCache.FsOptions);
|
||||
|
||||
let decipher = crypto.createDecipheriv(TokenCache.CipherAlgorithm, encryptionParams.key, encryptionParams.initializationVector);
|
||||
let cacheJson = decipher.update(cacheCipher, 'hex', 'binary');
|
||||
cacheJson += decipher.final('binary');
|
||||
|
||||
// Deserialize the JSON into the array of tokens
|
||||
let cacheObj = <adal.TokenResponse[]>JSON.parse(cacheJson);
|
||||
for (let objIndex in cacheObj) {
|
||||
// Rehydrate Date objects since they will always serialize as a string
|
||||
cacheObj[objIndex].expiresOn = new Date(<string>cacheObj[objIndex].expiresOn);
|
||||
}
|
||||
|
||||
return cacheObj;
|
||||
return self.decryptCache('utf8', encryptionParams);
|
||||
} catch (e) {
|
||||
throw e;
|
||||
try {
|
||||
// try to parse using 'binary' encoding and rewrite cache as UTF8
|
||||
let response = self.decryptCache('binary', encryptionParams);
|
||||
self.writeCache(response);
|
||||
return response;
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
})
|
||||
.then(null, err => {
|
||||
@@ -248,6 +242,22 @@ export default class TokenCache implements adal.TokenCache {
|
||||
});
|
||||
}
|
||||
|
||||
private decryptCache(encoding: crypto.Utf8AsciiBinaryEncoding, encryptionParams: EncryptionParams): adal.TokenResponse[] {
|
||||
let cacheCipher = fs.readFileSync(this._cacheSerializationPath, TokenCache.FsOptions);
|
||||
let decipher = crypto.createDecipheriv(TokenCache.CipherAlgorithm, encryptionParams.key, encryptionParams.initializationVector);
|
||||
let cacheJson = decipher.update(cacheCipher, 'hex', encoding);
|
||||
cacheJson += decipher.final(encoding);
|
||||
|
||||
// Deserialize the JSON into the array of tokens
|
||||
let cacheObj = <adal.TokenResponse[]>JSON.parse(cacheJson);
|
||||
for (let objIndex in cacheObj) {
|
||||
// Rehydrate Date objects since they will always serialize as a string
|
||||
cacheObj[objIndex].expiresOn = new Date(<string>cacheObj[objIndex].expiresOn);
|
||||
}
|
||||
|
||||
return cacheObj;
|
||||
}
|
||||
|
||||
private removeFromCache(cache: adal.TokenResponse[], entries: adal.TokenResponse[]): adal.TokenResponse[] {
|
||||
entries.forEach((entry: adal.TokenResponse) => {
|
||||
// Check to see if the entry exists
|
||||
@@ -274,7 +284,7 @@ export default class TokenCache implements adal.TokenCache {
|
||||
let cacheJson = JSON.stringify(cache);
|
||||
|
||||
let cipher = crypto.createCipheriv(TokenCache.CipherAlgorithm, encryptionParams.key, encryptionParams.initializationVector);
|
||||
let cacheCipher = cipher.update(cacheJson, 'binary', 'hex');
|
||||
let cacheCipher = cipher.update(cacheJson, 'utf8', 'hex');
|
||||
cacheCipher += cipher.final('hex');
|
||||
|
||||
fs.writeFileSync(self._cacheSerializationPath, cacheCipher, TokenCache.FsOptions);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "azuredatastudio",
|
||||
"version": "1.3.5",
|
||||
"version": "1.3.6",
|
||||
"distro": "8c3e97e3425cc9814496472ab73e076de2ba99ee",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
|
||||
@@ -68,7 +68,7 @@ export class RowNumberColumn<T> implements Slick.Plugin<T> {
|
||||
width: this.currentColumnWidth,
|
||||
resizable: false,
|
||||
cssClass: this.options.cssClass,
|
||||
focusable: true,
|
||||
focusable: false,
|
||||
selectable: false,
|
||||
formatter: (r, c, v, cd, dc) => this.formatter(r, c, v, cd, dc)
|
||||
};
|
||||
|
||||
@@ -63,7 +63,7 @@ export class CommandLineService implements ICommandLineProcessing {
|
||||
// prompt the user for a new connection on startup if no profiles are registered
|
||||
this._connectionManagementService.showConnectionDialog();
|
||||
} else if (this._connectionProfile) {
|
||||
this._connectionManagementService.connectIfNotConnected(this._connectionProfile, 'connection')
|
||||
this._connectionManagementService.connectIfNotConnected(this._connectionProfile, 'connection', true)
|
||||
.then(result => TaskUtilities.newQuery(this._connectionProfile,
|
||||
this._connectionManagementService,
|
||||
this._queryEditorService,
|
||||
|
||||
@@ -121,7 +121,7 @@ export interface IConnectionManagementService {
|
||||
* otherwise tries to make a connection and returns the owner uri when connection is complete
|
||||
* The purpose is connection by default
|
||||
*/
|
||||
connectIfNotConnected(connection: IConnectionProfile, purpose?: 'dashboard' | 'insights' | 'connection'): Promise<string>;
|
||||
connectIfNotConnected(connection: IConnectionProfile, purpose?: 'dashboard' | 'insights' | 'connection', saveConnection?: boolean): Promise<string>;
|
||||
|
||||
/**
|
||||
* Adds the successful connection to MRU and send the connection error back to the connection handler for failed connections
|
||||
|
||||
@@ -380,14 +380,14 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
* otherwise tries to make a connection and returns the owner uri when connection is complete
|
||||
* The purpose is connection by default
|
||||
*/
|
||||
public connectIfNotConnected(connection: IConnectionProfile, purpose?: 'dashboard' | 'insights' | 'connection'): Promise<string> {
|
||||
public connectIfNotConnected(connection: IConnectionProfile, purpose?: 'dashboard' | 'insights' | 'connection', saveConnection: boolean = false): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
let ownerUri: string = Utils.generateUri(connection, purpose);
|
||||
if (this._connectionStatusManager.isConnected(ownerUri)) {
|
||||
resolve(this._connectionStatusManager.getOriginalOwnerUri(ownerUri));
|
||||
} else {
|
||||
const options: IConnectionCompletionOptions = {
|
||||
saveTheConnection: false,
|
||||
saveTheConnection: saveConnection,
|
||||
showConnectionDialogOnError: true,
|
||||
showDashboard: purpose === 'dashboard',
|
||||
params: undefined,
|
||||
|
||||
@@ -9,7 +9,6 @@ import { nb } from 'sqlops';
|
||||
|
||||
import { OnInit, Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild } from '@angular/core';
|
||||
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { IColorTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import * as themeColors from 'vs/workbench/common/theme';
|
||||
import { INotificationService, INotification } from 'vs/platform/notification/common/notification';
|
||||
@@ -18,12 +17,12 @@ import { localize } from 'vs/nls';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { AngularDisposable } from 'sql/base/common/lifecycle';
|
||||
|
||||
import { CellTypes, CellType, NotebookChangeType } from 'sql/parts/notebook/models/contracts';
|
||||
import { ICellModel, IModelFactory } from 'sql/parts/notebook/models/modelInterfaces';
|
||||
import { CellTypes, CellType } from 'sql/parts/notebook/models/contracts';
|
||||
import { ICellModel, IModelFactory, notebookConstants } from 'sql/parts/notebook/models/modelInterfaces';
|
||||
import { IConnectionManagementService, IConnectionDialogService } from 'sql/parts/connection/common/connectionManagement';
|
||||
import { INotebookService, INotebookParams, INotebookManager } from 'sql/services/notebook/notebookService';
|
||||
import { IBootstrapParams } from 'sql/services/bootstrap/bootstrapService';
|
||||
import { NotebookModel, ErrorInfo, MessageLevel, NotebookContentChange } from 'sql/parts/notebook/models/notebookModel';
|
||||
import { NotebookModel, NotebookContentChange } from 'sql/parts/notebook/models/notebookModel';
|
||||
import { ModelFactory } from 'sql/parts/notebook/models/modelFactory';
|
||||
import * as notebookUtils from './notebookUtils';
|
||||
import { Deferred } from 'sql/base/common/promise';
|
||||
@@ -33,6 +32,14 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { KernelsDropdown, AttachToDropdown, AddCellAction, TrustedAction, SaveNotebookAction } from 'sql/parts/notebook/notebookActions';
|
||||
import { attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
|
||||
import { MenuId, IMenuService, MenuItemAction } from 'vs/platform/actions/common/actions';
|
||||
import { IAction, Action, IActionItem } from 'vs/base/common/actions';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { fillInActions, LabeledMenuItemActionItem } from 'vs/platform/actions/browser/menuItemActionItem';
|
||||
import { IObjectExplorerService } from 'sql/parts/objectExplorer/common/objectExplorerService';
|
||||
import * as TaskUtilities from 'sql/workbench/common/taskUtilities';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
|
||||
export const NOTEBOOK_SELECTOR: string = 'notebook-component';
|
||||
|
||||
@@ -62,19 +69,42 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
||||
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
|
||||
@Inject(IConnectionManagementService) private connectionManagementService: IConnectionManagementService,
|
||||
@Inject(IObjectExplorerService) private objectExplorerService: IObjectExplorerService,
|
||||
@Inject(IEditorService) private editorService: IEditorService,
|
||||
@Inject(INotificationService) private notificationService: INotificationService,
|
||||
@Inject(INotebookService) private notebookService: INotebookService,
|
||||
@Inject(IBootstrapParams) private notebookParams: INotebookParams,
|
||||
@Inject(IInstantiationService) private instantiationService: IInstantiationService,
|
||||
@Inject(IContextMenuService) private contextMenuService: IContextMenuService,
|
||||
@Inject(IContextViewService) private contextViewService: IContextViewService,
|
||||
@Inject(IConnectionDialogService) private connectionDialogService: IConnectionDialogService
|
||||
@Inject(IConnectionDialogService) private connectionDialogService: IConnectionDialogService,
|
||||
@Inject(IContextKeyService) private contextKeyService: IContextKeyService,
|
||||
@Inject(IMenuService) private menuService: IMenuService,
|
||||
@Inject(IKeybindingService) private keybindingService: IKeybindingService
|
||||
) {
|
||||
super();
|
||||
this.profile = this.notebookParams!.profile;
|
||||
this.updateProfile();
|
||||
this.isLoading = true;
|
||||
}
|
||||
|
||||
private updateProfile(): void {
|
||||
this.profile = this.notebookParams!.profile;
|
||||
if (!this.profile) {
|
||||
// use global connection if possible
|
||||
let profile = TaskUtilities.getCurrentGlobalConnection(this.objectExplorerService, this.connectionManagementService, this.editorService);
|
||||
// TODO use generic method to match kernel with valid connection that's compatible. For now, we only have 1
|
||||
if (profile && profile.providerName === notebookConstants.hadoopKnoxProviderName) {
|
||||
this.profile = profile;
|
||||
} else {
|
||||
// if not, try 1st active connection that matches our filter
|
||||
let profiles = this.connectionManagementService.getActiveConnections([notebookConstants.hadoopKnoxProviderName]);
|
||||
if (profiles && profiles.length > 0) {
|
||||
this.profile = profiles[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this._register(this.themeService.onDidColorThemeChange(this.updateTheme, this));
|
||||
this.updateTheme(this.themeService.getColorTheme());
|
||||
@@ -251,8 +281,19 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
|
||||
|
||||
let saveNotebookButton = this.instantiationService.createInstance(SaveNotebookAction, 'notebook.SaveNotebook', localize('save', 'Save'), 'notebook-button icon-save');
|
||||
|
||||
// Get all of the menu contributions that use the ID 'notebook/toolbar'.
|
||||
// Then, find all groups (currently we don't leverage the contributed
|
||||
// groups functionality for the notebook toolbar), and fill in the 'primary'
|
||||
// array with items that don't list a group. Finally, add any actions from
|
||||
// the primary array to the end of the toolbar.
|
||||
const notebookBarMenu = this.menuService.createMenu(MenuId.NotebookToolbar, this.contextKeyService);
|
||||
let groups = notebookBarMenu.getActions({ arg: null, shouldForwardArgs: true });
|
||||
let primary: IAction[] = [];
|
||||
let secondary: IAction[] = [];
|
||||
fillInActions(groups, {primary, secondary}, false, (group: string) => group === undefined);
|
||||
|
||||
let taskbar = <HTMLElement>this.toolbar.nativeElement;
|
||||
this._actionBar = new Taskbar(taskbar, this.contextMenuService);
|
||||
this._actionBar = new Taskbar(taskbar, this.contextMenuService, { actionItemProvider: action => this.actionItemProvider(action as Action)});
|
||||
this._actionBar.context = this;
|
||||
this._actionBar.setContent([
|
||||
{ element: kernelContainer },
|
||||
@@ -262,6 +303,12 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
|
||||
{ action: saveNotebookButton },
|
||||
{ action: this._trustedAction }
|
||||
]);
|
||||
|
||||
// Primary actions are categorized as those that are added to the 'horizontal' group.
|
||||
// For the vertical toolbar, we can do the same thing and instead use the 'vertical' group.
|
||||
for (let action of primary) {
|
||||
this._actionBar.addAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
public async save(): Promise<boolean> {
|
||||
@@ -281,5 +328,13 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
|
||||
// }
|
||||
}
|
||||
|
||||
private actionItemProvider(action: Action): IActionItem {
|
||||
// Check extensions to create ActionItem; otherwise, return undefined
|
||||
// This is similar behavior that exists in MenuItemActionItem
|
||||
if (action instanceof MenuItemAction) {
|
||||
return new LabeledMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService, 'notebook-button');
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
'use strict';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as nls from 'vs/nls';
|
||||
import * as platform from 'vs/platform/registry/common/platform';
|
||||
import * as statusbar from 'vs/workbench/browser/parts/statusbar/statusbar';
|
||||
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { Memento, Scope as MementoScope } from 'vs/workbench/common/memento';
|
||||
@@ -20,8 +20,8 @@ import { AccountDialogController } from 'sql/parts/accountManagement/accountDial
|
||||
import { AutoOAuthDialogController } from 'sql/parts/accountManagement/autoOAuthDialog/autoOAuthDialogController';
|
||||
import { AccountListStatusbarItem } from 'sql/parts/accountManagement/accountListStatusbar/accountListStatusbarItem';
|
||||
import { AccountProviderAddedEventParams, UpdateAccountListEventParams } from 'sql/services/accountManagement/eventTypes';
|
||||
import { IAccountManagementService, AzureResource } from 'sql/services/accountManagement/interfaces';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { IAccountManagementService } from 'sql/services/accountManagement/interfaces';
|
||||
import { Deferred } from 'sql/base/common/promise';
|
||||
|
||||
export class AccountManagementService implements IAccountManagementService {
|
||||
// CONSTANTS ///////////////////////////////////////////////////////////
|
||||
@@ -198,11 +198,6 @@ export class AccountManagementService implements IAccountManagementService {
|
||||
public getAccountsForProvider(providerId: string): Thenable<sqlops.Account[]> {
|
||||
let self = this;
|
||||
|
||||
// Make sure the provider exists before attempting to retrieve accounts
|
||||
if (!this._providers[providerId]) {
|
||||
return Promise.reject(new Error(nls.localize('accountManagementNoProvider', 'Account provider does not exist'))).then();
|
||||
}
|
||||
|
||||
// 1) Get the accounts from the store
|
||||
// 2) Update our local cache of accounts
|
||||
return this.doWithProvider(providerId, provider => {
|
||||
@@ -217,7 +212,7 @@ export class AccountManagementService implements IAccountManagementService {
|
||||
/**
|
||||
* Generates a security token by asking the account's provider
|
||||
* @param {Account} account Account to generate security token for
|
||||
* @param {AzureResource} resource The resource to get the security token for
|
||||
* @param {sqlops.AzureResource} resource The resource to get the security token for
|
||||
* @return {Thenable<{}>} Promise to return the security token
|
||||
*/
|
||||
public getSecurityToken(account: sqlops.Account, resource: sqlops.AzureResource): Thenable<{}> {
|
||||
@@ -389,10 +384,17 @@ export class AccountManagementService implements IAccountManagementService {
|
||||
|
||||
// PRIVATE HELPERS /////////////////////////////////////////////////////
|
||||
private doWithProvider<T>(providerId: string, op: (provider: AccountProviderWithMetadata) => Thenable<T>): Thenable<T> {
|
||||
// Make sure the provider exists before attempting to retrieve accounts
|
||||
let provider = this._providers[providerId];
|
||||
if (!provider) {
|
||||
return Promise.reject(new Error(nls.localize('accountManagementNoProvider', 'Account provider does not exist'))).then();
|
||||
// If the provider doesn't already exist wait until it gets registered
|
||||
let deferredPromise = new Deferred<T>();
|
||||
let toDispose = this.addAccountProviderEvent(params => {
|
||||
if (params.addedProvider.id === providerId) {
|
||||
toDispose.dispose();
|
||||
deferredPromise.resolve(op(this._providers[providerId]));
|
||||
}
|
||||
});
|
||||
return deferredPromise;
|
||||
}
|
||||
|
||||
return op(provider);
|
||||
|
||||
@@ -164,7 +164,7 @@ suite('commandLineService tests', () => {
|
||||
environmentService.setup(e => e.args).returns(() => args).verifiable(TypeMoq.Times.atLeastOnce());
|
||||
connectionManagementService.setup((c) => c.showConnectionDialog()).verifiable(TypeMoq.Times.never());
|
||||
connectionManagementService.setup(c => c.hasRegisteredServers()).returns(() => true).verifiable(TypeMoq.Times.atMostOnce());
|
||||
connectionManagementService.setup(c => c.connectIfNotConnected(TypeMoq.It.isAny(), 'connection'))
|
||||
connectionManagementService.setup(c => c.connectIfNotConnected(TypeMoq.It.isAny(), 'connection', true))
|
||||
.returns(() => new Promise<string>((resolve, reject) => { reject('unused');}))
|
||||
.verifiable(TypeMoq.Times.once());
|
||||
let service = getCommandLineService(connectionManagementService.object, environmentService.object, capabilitiesService);
|
||||
|
||||
@@ -221,13 +221,13 @@ suite('Account Management Service Tests:', () => {
|
||||
let ams = getTestState().accountManagementService;
|
||||
|
||||
// If: I add an account when the provider doesn't exist
|
||||
// Then: It should be rejected
|
||||
ams.addAccount('doesNotExist')
|
||||
.then(
|
||||
() => done('Promise resolved when it should have rejected'),
|
||||
() => done()
|
||||
);
|
||||
|
||||
// Then: It should not resolve
|
||||
Promise.race([
|
||||
new Promise((resolve, reject) => setTimeout(() => resolve(), 100)),
|
||||
ams.addAccount('doesNotExist').then((
|
||||
() => done('Promise resolved when the provider did not exist')
|
||||
))
|
||||
]).then(() => done(), err => done(err));
|
||||
});
|
||||
|
||||
test('Add account - provider exists, provider fails', done => {
|
||||
@@ -305,12 +305,13 @@ suite('Account Management Service Tests:', () => {
|
||||
let ams = getTestState().accountManagementService;
|
||||
|
||||
// If: I get accounts when the provider doesn't exist
|
||||
// Then: It should be rejected
|
||||
ams.getAccountsForProvider('doesNotExist')
|
||||
.then(
|
||||
() => done('Promise resolved when it should have rejected'),
|
||||
() => done()
|
||||
);
|
||||
// Then: It should not resolve
|
||||
Promise.race([
|
||||
new Promise((resolve, reject) => setTimeout(() => resolve(), 100)),
|
||||
ams.getAccountsForProvider('doesNotExist').then((
|
||||
() => done('Promise resolved when the provider did not exist')
|
||||
))
|
||||
]).then(() => done(), err => done(err));
|
||||
});
|
||||
|
||||
test('Get accounts by provider - provider exists, no accounts', done => {
|
||||
|
||||
@@ -234,7 +234,7 @@ export class TestConnectionManagementService implements IConnectionManagementSer
|
||||
return [];
|
||||
}
|
||||
|
||||
connectIfNotConnected(connection: IConnectionProfile, purpose?: 'dashboard' | 'insights' | 'connection'): Promise<string> {
|
||||
connectIfNotConnected(connection: IConnectionProfile, purpose?: 'dashboard' | 'insights' | 'connection', saveConnection: boolean = false): Promise<string> {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -288,3 +288,63 @@ export class ContextAwareMenuItemActionItem extends MenuItemActionItem {
|
||||
.done(undefined, err => this._notificationService.error(err));
|
||||
}
|
||||
}
|
||||
|
||||
// Always show label for action items, instead of whether they don't have
|
||||
// an icon/CSS class. Useful for some toolbar scenarios in particular with
|
||||
// contributed actions from other extensions
|
||||
export class LabeledMenuItemActionItem extends MenuItemActionItem {
|
||||
private _labeledItemClassDispose: IDisposable;
|
||||
|
||||
constructor(
|
||||
public _action: MenuItemAction,
|
||||
@IKeybindingService private readonly _labeledkeybindingService: IKeybindingService,
|
||||
@INotificationService protected _notificationService: INotificationService,
|
||||
@IContextMenuService private readonly _labeledcontextMenuService: IContextMenuService,
|
||||
private readonly _defaultCSSClassToAdd: string = ''
|
||||
) {
|
||||
super(_action, _labeledkeybindingService, _notificationService, _labeledcontextMenuService);
|
||||
}
|
||||
_updateLabel(): void {
|
||||
this.$e.text(this._commandAction.label);
|
||||
}
|
||||
|
||||
// Overwrite item class to ensure that we can pass in a CSS class that other items use
|
||||
// Leverages the _defaultCSSClassToAdd property that's passed into the constructor
|
||||
_updateItemClass(item: ICommandAction): void {
|
||||
dispose(this._labeledItemClassDispose);
|
||||
this._labeledItemClassDispose = undefined;
|
||||
|
||||
if (item.iconLocation) {
|
||||
let iconClass: string;
|
||||
|
||||
const iconPathMapKey = item.iconLocation.dark.toString();
|
||||
|
||||
if (MenuItemActionItem.ICON_PATH_TO_CSS_RULES.has(iconPathMapKey)) {
|
||||
iconClass = MenuItemActionItem.ICON_PATH_TO_CSS_RULES.get(iconPathMapKey);
|
||||
} else {
|
||||
iconClass = ids.nextId();
|
||||
createCSSRule(`.icon.${iconClass}`, `background-image: url("${(item.iconLocation.light || item.iconLocation.dark).toString()}")`);
|
||||
createCSSRule(`.vs-dark .icon.${iconClass}, .hc-black .icon.${iconClass}`, `background-image: url("${item.iconLocation.dark.toString()}")`);
|
||||
MenuItemActionItem.ICON_PATH_TO_CSS_RULES.set(iconPathMapKey, iconClass);
|
||||
}
|
||||
|
||||
this.$e.getHTMLElement().classList.add('icon', iconClass);
|
||||
this.$e.getHTMLElement().classList.add(this._defaultCSSClassToAdd);
|
||||
this._labeledItemClassDispose = {
|
||||
dispose: () => {
|
||||
this.$e.getHTMLElement().classList.remove('icon', iconClass);
|
||||
this.$e.getHTMLElement().classList.remove(this._defaultCSSClassToAdd);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
if (this._labeledItemClassDispose) {
|
||||
dispose(this._labeledItemClassDispose);
|
||||
this._labeledItemClassDispose = undefined;
|
||||
}
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@ export class MenuId {
|
||||
static readonly MenubarHelpMenu = new MenuId();
|
||||
// {{SQL CARBON EDIT}}
|
||||
static readonly ObjectExplorerItemContext = new MenuId();
|
||||
static readonly NotebookToolbar = new MenuId();
|
||||
|
||||
|
||||
readonly id: string = String(MenuId.ID++);
|
||||
|
||||
@@ -43,6 +43,7 @@ namespace schema {
|
||||
case 'view/item/context': return MenuId.ViewItemContext;
|
||||
// {{SQL CARBON EDIT}}
|
||||
case 'objectExplorer/item/context': return MenuId.ObjectExplorerItemContext;
|
||||
case 'notebook/toolbar': return MenuId.NotebookToolbar;
|
||||
}
|
||||
|
||||
return void 0;
|
||||
|
||||
Reference in New Issue
Block a user