mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 11:01:37 -05:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e57eb999fc | ||
|
|
99af31fa1f | ||
|
|
e2990db33e | ||
|
|
b2238dc37b | ||
|
|
6770bf877e | ||
|
|
ba66305bb5 | ||
|
|
8e731c75c3 | ||
|
|
db0409569a | ||
|
|
fb4ab6b501 | ||
|
|
bd1d96a57a | ||
|
|
6fe49e8cef | ||
|
|
6da98ed439 | ||
|
|
5ef69f5133 | ||
|
|
ebf47df35e | ||
|
|
2a93d7c5e9 | ||
|
|
573c5b4470 | ||
|
|
41838b7720 | ||
|
|
ee1359fd7c | ||
|
|
189bcf703e |
@@ -5,11 +5,6 @@ REPO="$(pwd)"
|
||||
# ensure drop directories exist
|
||||
mkdir -p $REPO/.build/darwin/{archive,server}
|
||||
|
||||
# remove pkg from archive
|
||||
if [[ "$SIGNED" == "true" ]]; then
|
||||
zip -d $REPO/.build/darwin/archive/azuredatastudio-darwin.zip "*.pkg"
|
||||
fi
|
||||
|
||||
# package Remote Extension Host
|
||||
pushd .. && mv azuredatastudio-reh-darwin azuredatastudio-server-darwin && zip -Xry $REPO/.build/darwin/server/azuredatastudio-server-darwin.zip azuredatastudio-server-darwin && popd
|
||||
|
||||
|
||||
@@ -10,5 +10,13 @@
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<false/>
|
||||
<key>com.apple.security.automation.apple-events</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
steps:
|
||||
- task: InstallAppleCertificate@2
|
||||
displayName: 'Install developer certificate'
|
||||
inputs:
|
||||
certSecureFile: 'osx_signing_key.p12'
|
||||
|
||||
- script: |
|
||||
mkdir -p .build
|
||||
echo -n $BUILD_SOURCEVERSION > .build/commit
|
||||
@@ -107,12 +112,48 @@ steps:
|
||||
displayName: Run unit tests
|
||||
condition: and(succeeded(), eq(variables['RUN_TESTS'], 'true'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
pushd ../azuredatastudio-darwin
|
||||
ls
|
||||
|
||||
echo "Cleaning the application"
|
||||
xattr -cr *.app
|
||||
cd *.app
|
||||
find . -name '._*' -print0 | xargs -0 rm -rf --
|
||||
cd ..
|
||||
|
||||
echo "Signing the application with deep"
|
||||
codesign --deep --force --timestamp --options runtime --entitlements $(Build.SourcesDirectory)/build/azure-pipelines/darwin/entitlements.xml -s LPV3BJJYXS *.app
|
||||
|
||||
cd *.app
|
||||
ls
|
||||
echo "Signing specific components"
|
||||
find . -type f -print0 | xargs -0 file | grep ': *Mach-O' | sed 's/: *Mach-O.*//' | while read -r file; do codesign --options runtime --timestamp --entitlements $(Build.SourcesDirectory)/build/azure-pipelines/darwin/entitlements.xml -s LPV3BJJYXS --force "$file" || break; done
|
||||
|
||||
echo "Signing Electron again..."
|
||||
codesign --force --timestamp --options runtime --entitlements $(Build.SourcesDirectory)/build/azure-pipelines/darwin/entitlements.xml -s LPV3BJJYXS Contents/Frameworks/Electron\ Framework.framework
|
||||
cd ..
|
||||
|
||||
echo "Signing the entire application one more time"
|
||||
codesign --force --timestamp --options runtime --entitlements $(Build.SourcesDirectory)/build/azure-pipelines/darwin/entitlements.xml -s LPV3BJJYXS *.app
|
||||
popd
|
||||
displayName: 'Manual codesign'
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
mkdir -p .build/darwin/archive
|
||||
pushd ../azuredatastudio-darwin && zip -r -X -y $(Build.SourcesDirectory)/.build/darwin/archive/azuredatastudio-darwin.zip * && popd
|
||||
pushd ../azuredatastudio-darwin
|
||||
ditto -c -k --keepParent *.app $(Build.SourcesDirectory)/.build/darwin/archive/azuredatastudio-darwin.zip
|
||||
popd
|
||||
displayName: 'Archive'
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
displayName: 'Publish SelfSigned'
|
||||
inputs:
|
||||
artifactName: darwin-selfsigned
|
||||
targetPath: $(Build.SourcesDirectory)/.build/darwin/archive/azuredatastudio-darwin.zip
|
||||
|
||||
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
|
||||
displayName: 'ESRP CodeSigning'
|
||||
inputs:
|
||||
@@ -124,14 +165,57 @@ steps:
|
||||
[
|
||||
{
|
||||
"keyCode": "CP-401337-Apple",
|
||||
"operationSetCode": "MacAppDeveloperSign",
|
||||
"parameters": [],
|
||||
"operationCode": "MacAppDeveloperSign",
|
||||
"parameters": {
|
||||
"Hardening": "Enable"
|
||||
},
|
||||
"toolName": "sign",
|
||||
"toolVersion": "1.0"
|
||||
}
|
||||
]
|
||||
SessionTimeout: 125
|
||||
condition: and(succeeded(), eq(variables['signed'], true))
|
||||
SessionTimeout: 90
|
||||
condition: and(succeeded(), eq(variables['signtba'], true))
|
||||
|
||||
- script: |
|
||||
zip -d $(Build.SourcesDirectory)/.build/darwin/archive/azuredatastudio-darwin.zip "*.pkg"
|
||||
displayName: Clean Archive
|
||||
condition: and(succeeded(), eq(variables['signtba'], true))
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
displayName: 'Publish Signed'
|
||||
inputs:
|
||||
artifactName: darwin-signed
|
||||
targetPath: $(Build.SourcesDirectory)/.build/darwin/archive/azuredatastudio-darwin.zip
|
||||
condition: and(succeeded(), eq(variables['signtba'], true))
|
||||
|
||||
- task: EsrpCodeSigning@1
|
||||
displayName: 'ESRP Notarization'
|
||||
inputs:
|
||||
ConnectedServiceName: 'Code Signing'
|
||||
FolderPath: '$(Build.SourcesDirectory)/.build/darwin/archive'
|
||||
Pattern: 'azuredatastudio-darwin.zip'
|
||||
signConfigType: inlineSignParams
|
||||
inlineOperation: |
|
||||
[
|
||||
{
|
||||
"KeyCode": "CP-401337-Apple",
|
||||
"OperationCode": "MacAppNotarize",
|
||||
"Parameters": {
|
||||
"BundleId": "com.microsoft.azuredatastudio-$(VSCODE_QUALITY)"
|
||||
},
|
||||
"ToolName": "sign",
|
||||
"ToolVersion": "1.0"
|
||||
}
|
||||
]
|
||||
SessionTimeout: 120
|
||||
condition: and(succeeded(), eq(variables['signtba'], true))
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
displayName: 'Publish Notarized'
|
||||
inputs:
|
||||
artifactName: darwin-notarized
|
||||
targetPath: $(Build.SourcesDirectory)/.build/darwin/archive/azuredatastudio-darwin.zip
|
||||
condition: and(succeeded(), eq(variables['signtba'], true))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
|
||||
@@ -43,6 +43,7 @@ const nodeModules = [
|
||||
'electron',
|
||||
'original-fs',
|
||||
'rxjs/Observable',
|
||||
'rxjs/add/observable/fromPromise',
|
||||
'rxjs/Subject',
|
||||
'rxjs/Observer',
|
||||
'slickgrid/lib/jquery.event.drag-2.3.0',
|
||||
|
||||
@@ -116,7 +116,7 @@ function submitAllStats(productJson, commit) {
|
||||
}
|
||||
*/
|
||||
appInsights.defaultClient.trackEvent({
|
||||
name: `${productJson.quality !== 'stable' ? 'adsworkbench' : 'monacoworkbench'}/packagemetrics`,
|
||||
name: 'adsworkbench/packagemetrics',
|
||||
properties: { commit, size: JSON.stringify(sizes), count: JSON.stringify(counts) }
|
||||
});
|
||||
appInsights.defaultClient.flush({
|
||||
|
||||
@@ -126,7 +126,7 @@ export function submitAllStats(productJson: any, commit: string): Promise<boolea
|
||||
}
|
||||
*/
|
||||
appInsights.defaultClient.trackEvent({
|
||||
name: `${productJson.quality !== 'stable' ? 'adsworkbench' : 'monacoworkbench'}/packagemetrics`, // {{SQL CARBON EDIT}}
|
||||
name: 'adsworkbench/packagemetrics', // {{SQL CARBON EDIT}}
|
||||
properties: { commit, size: JSON.stringify(sizes), count: JSON.stringify(counts) }
|
||||
});
|
||||
|
||||
|
||||
@@ -39,6 +39,11 @@
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "%config.enablePublicCloudDescription%"
|
||||
},
|
||||
"accounts.azure.enableDeviceCodeLogin": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%config.enableDeviceCodeLogin%"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,5 +19,5 @@
|
||||
"config.enableUsGovCloudDescription": "Should US Government Azure cloud (Fairfax) integration be enabled",
|
||||
"config.enableChinaCloudDescription": "Should Azure China integration be enabled",
|
||||
"config.enableGermanyCloudDescription": "Should Azure Germany integration be enabled",
|
||||
"config.useNewSignInExperience": "Use the new Azure sign in experience"
|
||||
"config.enableDeviceCodeLogin": "Enable Azure Active Directory device code login mechanism"
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ export class AzureAccountProvider implements azdata.AccountProvider {
|
||||
private isInitialized: boolean = false;
|
||||
|
||||
|
||||
constructor(private metadata: AzureAccountProviderMetadata, private _tokenCache: TokenCache) {
|
||||
constructor(private metadata: AzureAccountProviderMetadata, private _tokenCache: TokenCache, private _context: vscode.ExtensionContext) {
|
||||
this.commonAuthorityUrl = url.resolve(this.metadata.settings.host, AzureAccountProvider.AadCommonTenant);
|
||||
}
|
||||
|
||||
@@ -79,7 +79,9 @@ export class AzureAccountProvider implements azdata.AccountProvider {
|
||||
|
||||
context.cache.add([response], (err, result) => {
|
||||
if (err || !result) {
|
||||
console.log(`Unexpected error adding token to cache ${err}`);
|
||||
const msg = localize('azure.tokenCacheFail', "Unexpected error adding token to cache: {0}", err.message);
|
||||
vscode.window.showErrorMessage(msg);
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -189,6 +191,8 @@ export class AzureAccountProvider implements azdata.AccountProvider {
|
||||
nonce: string,
|
||||
authUrl: string) {
|
||||
|
||||
const mediaPath = path.join(this._context.extensionPath, 'media');
|
||||
|
||||
// Utility function
|
||||
const sendFile = async (res: http.ServerResponse, filePath: string, contentType: string): Promise<void> => {
|
||||
let fileContents;
|
||||
@@ -240,12 +244,13 @@ export class AzureAccountProvider implements azdata.AccountProvider {
|
||||
return;
|
||||
}
|
||||
|
||||
sendFile(res, path.join(__dirname, 'media/landing.html'), 'text/html; charset=utf-8').catch(console.error);
|
||||
|
||||
sendFile(res, path.join(mediaPath, 'landing.html'), 'text/html; charset=utf-8').catch(console.error);
|
||||
this.handleAuthentication(code).catch((e) => console.error(e));
|
||||
};
|
||||
|
||||
const css = (req: http.IncomingMessage, res: http.ServerResponse, reqUrl: url.UrlWithParsedQuery) => {
|
||||
sendFile(res, path.join(__dirname, 'media/landing.css'), 'text/css; charset=utf-8').catch(console.error);
|
||||
sendFile(res, path.join(mediaPath, 'landing.css'), 'text/css; charset=utf-8').catch(console.error);
|
||||
};
|
||||
|
||||
pathMappings.set('/signin', initialSignIn);
|
||||
@@ -284,7 +289,9 @@ export class AzureAccountProvider implements azdata.AccountProvider {
|
||||
try {
|
||||
graphToken = await this.getToken(userId, value.tenantId, this.metadata.settings.graphResource.id);
|
||||
} catch (ex) {
|
||||
console.log(`Your authentication to the tenant ${value.tenantId} failed: ${ex}`);
|
||||
const msg = localize('azure.authFail', "Your authentication to the tenant {0} failed: {1}", value.tenantId, ex);
|
||||
vscode.window.showErrorMessage(msg);
|
||||
console.log(msg);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -305,7 +312,9 @@ export class AzureAccountProvider implements azdata.AccountProvider {
|
||||
|
||||
tenants = tenants.filter(t => t !== undefined);
|
||||
if (tenants.length === 0) {
|
||||
throw new Error(localize('azure.noTenants', "No azure tenants found. Failing..."));
|
||||
const msg = localize('azure.noTenants', "Failed to add account. No Azure tenants.");
|
||||
vscode.window.showErrorMessage(msg);
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
if (homeTenant) {
|
||||
|
||||
@@ -11,7 +11,8 @@ import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import CredentialServiceTokenCache from './tokenCache';
|
||||
import providerSettings from './providerSettings';
|
||||
import { AzureAccountProvider as AzureAccountProvider } from './azureAccountProvider2';
|
||||
import { AzureAccountProvider as OAuthAzureAccountProvider } from './azureAccountProvider2';
|
||||
import { AzureAccountProvider as DeviceCodeAzureAccountProvider } from './azureAccountProvider';
|
||||
import { AzureAccountProviderMetadata, ProviderSettings } from './interfaces';
|
||||
|
||||
let localize = nls.loadMessageBundle();
|
||||
@@ -133,12 +134,18 @@ export class AzureAccountProviderService implements vscode.Disposable {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
//let config = vscode.workspace.getConfiguration(AzureAccountProviderService.ConfigurationSection);
|
||||
let config = vscode.workspace.getConfiguration(AzureAccountProviderService.ConfigurationSection);
|
||||
|
||||
let tokenCacheKey = `azureTokenCache-${provider.metadata.id}`;
|
||||
let tokenCachePath = path.join(this._userStoragePath, tokenCacheKey);
|
||||
let tokenCache = new CredentialServiceTokenCache(self._credentialProvider, tokenCacheKey, tokenCachePath);
|
||||
let accountProvider = new AzureAccountProvider(provider.metadata as AzureAccountProviderMetadata, tokenCache);
|
||||
const enableDeviceCode = config.get('enableDeviceCodeLogin');
|
||||
let accountProvider: azdata.AccountProvider;
|
||||
if (enableDeviceCode === undefined || enableDeviceCode === false) {
|
||||
accountProvider = new OAuthAzureAccountProvider(provider.metadata as AzureAccountProviderMetadata, tokenCache, this._context);
|
||||
} else {
|
||||
accountProvider = new DeviceCodeAzureAccountProvider(provider.metadata as AzureAccountProviderMetadata, tokenCache);
|
||||
}
|
||||
self._accountProviders[provider.metadata.id] = accountProvider;
|
||||
self._accountDisposals[provider.metadata.id] = azdata.accounts.registerAccountProvider(provider.metadata, accountProvider);
|
||||
resolve();
|
||||
|
||||
@@ -71,13 +71,26 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
|
||||
};
|
||||
}).sort((a, b) => a.label.localeCompare(b.label));
|
||||
|
||||
const selectedSubscriptionQuickPickItems = await window.showQuickPick(subscriptionQuickPickItems, { canPickMany: true });
|
||||
if (selectedSubscriptionQuickPickItems && selectedSubscriptionQuickPickItems.length > 0) {
|
||||
await tree.refresh(node, false);
|
||||
const selectedQuickPickItems = subscriptionQuickPickItems.filter(s => s.picked);
|
||||
|
||||
selectedSubscriptions = selectedSubscriptionQuickPickItems.map((subscriptionItem) => subscriptionItem.subscription);
|
||||
await subscriptionFilterService.saveSelectedSubscriptions(accountNode.account, selectedSubscriptions);
|
||||
}
|
||||
const quickPick = window.createQuickPick<AzureResourceSubscriptionQuickPickItem>();
|
||||
quickPick.ok = true;
|
||||
quickPick.items = subscriptionQuickPickItems;
|
||||
quickPick.canSelectMany = true;
|
||||
quickPick.selectedItems = selectedQuickPickItems;
|
||||
|
||||
quickPick.show();
|
||||
|
||||
quickPick.onDidAccept(async event => {
|
||||
quickPick.hide();
|
||||
const selectedSubscriptionQuickPickItems = quickPick.selectedItems;
|
||||
if (selectedSubscriptionQuickPickItems && selectedSubscriptionQuickPickItems.length > 0) {
|
||||
await tree.refresh(node, false);
|
||||
|
||||
selectedSubscriptions = selectedSubscriptionQuickPickItems.map((subscriptionItem) => subscriptionItem.subscription);
|
||||
await subscriptionFilterService.saveSelectedSubscriptions(accountNode.account, selectedSubscriptions);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
appContext.apiWrapper.registerCommand('azure.resource.refreshall', () => tree.notifyNodeChanged(undefined));
|
||||
|
||||
@@ -54,19 +54,21 @@ export class AzureResourceSubscriptionFilterService implements IAzureResourceSub
|
||||
filters.push(...selectedSubscriptionsCache[accountId].map((subcription) => `${accountId}/${subcription.id}/${subcription.name}`));
|
||||
}
|
||||
|
||||
const resourceFilterConfig = this._config.inspect<string[]>(AzureResourceSubscriptionFilterService.filterConfigName);
|
||||
let configTarget = ConfigurationTarget.Global;
|
||||
if (resourceFilterConfig) {
|
||||
if (resourceFilterConfig.workspaceFolderValue) {
|
||||
configTarget = ConfigurationTarget.WorkspaceFolder;
|
||||
} else if (resourceFilterConfig.workspaceValue) {
|
||||
configTarget = ConfigurationTarget.Workspace;
|
||||
} else if (resourceFilterConfig.globalValue) {
|
||||
configTarget = ConfigurationTarget.Global;
|
||||
if (this._config) {
|
||||
const resourceFilterConfig = this._config.inspect<string[]>(AzureResourceSubscriptionFilterService.filterConfigName);
|
||||
let configTarget = ConfigurationTarget.Global;
|
||||
if (resourceFilterConfig) {
|
||||
if (resourceFilterConfig.workspaceFolderValue) {
|
||||
configTarget = ConfigurationTarget.WorkspaceFolder;
|
||||
} else if (resourceFilterConfig.workspaceValue) {
|
||||
configTarget = ConfigurationTarget.Workspace;
|
||||
} else if (resourceFilterConfig.globalValue) {
|
||||
configTarget = ConfigurationTarget.Global;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await this._config.update(AzureResourceSubscriptionFilterService.filterConfigName, filters, configTarget);
|
||||
await this._config.update(AzureResourceSubscriptionFilterService.filterConfigName, filters, configTarget);
|
||||
}
|
||||
}
|
||||
|
||||
private _config: WorkspaceConfiguration = undefined;
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
"onCommand:bigDataClusters.command.mount",
|
||||
"onCommand:bigDataClusters.command.refreshmount",
|
||||
"onCommand:bigDataClusters.command.deletemount",
|
||||
"onCommand:bigDataClusters.command.addController",
|
||||
"onCommand:bigDataClusters.command.deleteController",
|
||||
"onCommand:bigDataClusters.command.manageController",
|
||||
"onCommand:bigDataClusters.command.refreshController",
|
||||
"onView:sqlBigDataCluster"
|
||||
],
|
||||
"repository": {
|
||||
|
||||
@@ -32,9 +32,11 @@ export class ControllerTreeDataProvider implements vscode.TreeDataProvider<TreeN
|
||||
public readonly onDidChangeTreeData: vscode.Event<TreeNode> = this._onDidChangeTreeData.event;
|
||||
private root: ControllerRootNode;
|
||||
private credentialProvider: azdata.CredentialProvider;
|
||||
private initialized: boolean = false;
|
||||
|
||||
constructor(private memento: vscode.Memento) {
|
||||
this.root = new ControllerRootNode(this);
|
||||
this.root.addChild(new LoadingControllerNode());
|
||||
}
|
||||
|
||||
public async getChildren(element?: TreeNode): Promise<TreeNode[]> {
|
||||
@@ -42,14 +44,11 @@ export class ControllerTreeDataProvider implements vscode.TreeDataProvider<TreeN
|
||||
return element.getChildren();
|
||||
}
|
||||
|
||||
if (this.root.hasChildren) {
|
||||
return this.root.getChildren();
|
||||
if (!this.initialized) {
|
||||
this.loadSavedControllers().catch(err => { vscode.window.showErrorMessage(localize('bdc.controllerTreeDataProvider.error', "Unexpected error loading saved controllers: {0}", err)); });
|
||||
}
|
||||
|
||||
// Kick off loading the saved controllers but then immediately return the loading node so
|
||||
// the user isn't left with an empty tree while we load the nodes
|
||||
this.loadSavedControllers().catch(err => { vscode.window.showErrorMessage(localize('bdc.controllerTreeDataProvider.error', "Unexpected error loading saved controllers: {0}", err)); });
|
||||
return [new LoadingControllerNode()];
|
||||
return this.root.getChildren();
|
||||
}
|
||||
|
||||
public getTreeItem(element: TreeNode): vscode.TreeItem | Thenable<vscode.TreeItem> {
|
||||
@@ -89,12 +88,11 @@ export class ControllerTreeDataProvider implements vscode.TreeDataProvider<TreeN
|
||||
}
|
||||
|
||||
private removeNonControllerNodes(): void {
|
||||
this.removePlaceholderNodes();
|
||||
this.removeDefectiveControllerNodes();
|
||||
this.removePlaceholderNodes(this.root.children);
|
||||
this.removeDefectiveControllerNodes(this.root.children);
|
||||
}
|
||||
|
||||
private removePlaceholderNodes(): void {
|
||||
let nodes = this.root.children;
|
||||
private removePlaceholderNodes(nodes: TreeNode[]): void {
|
||||
if (nodes.length > 0) {
|
||||
for (let i = 0; i < nodes.length; ++i) {
|
||||
if (nodes[i] instanceof AddControllerNode ||
|
||||
@@ -106,8 +104,7 @@ export class ControllerTreeDataProvider implements vscode.TreeDataProvider<TreeN
|
||||
}
|
||||
}
|
||||
|
||||
private removeDefectiveControllerNodes(): void {
|
||||
let nodes = this.root.children;
|
||||
private removeDefectiveControllerNodes(nodes: TreeNode[]): void {
|
||||
if (nodes.length > 0) {
|
||||
for (let i = 0; i < nodes.length; ++i) {
|
||||
if (nodes[i] instanceof ControllerNode) {
|
||||
@@ -121,31 +118,42 @@ export class ControllerTreeDataProvider implements vscode.TreeDataProvider<TreeN
|
||||
}
|
||||
|
||||
private async loadSavedControllers(): Promise<void> {
|
||||
this.root.clearChildren();
|
||||
let controllers: IControllerInfoSlim[] = this.memento.get('controllers');
|
||||
if (controllers) {
|
||||
for (const c of controllers) {
|
||||
let password = undefined;
|
||||
if (c.rememberPassword) {
|
||||
password = await this.getPassword(c.url, c.username);
|
||||
// Optimistically set to true so we don't double-load the tree
|
||||
this.initialized = true;
|
||||
try {
|
||||
let controllers: IControllerInfoSlim[] = this.memento.get('controllers');
|
||||
let treeNodes: TreeNode[] = [];
|
||||
if (controllers) {
|
||||
for (const c of controllers) {
|
||||
let password = undefined;
|
||||
if (c.rememberPassword) {
|
||||
password = await this.getPassword(c.url, c.username);
|
||||
}
|
||||
if (!c.auth) {
|
||||
// Added before we had added authentication
|
||||
c.auth = 'basic';
|
||||
}
|
||||
treeNodes.push(new ControllerNode(
|
||||
c.url, c.auth, c.username, password, c.rememberPassword,
|
||||
undefined, this.root, this, undefined
|
||||
));
|
||||
}
|
||||
if (!c.auth) {
|
||||
// Added before we had added authentication
|
||||
c.auth = 'basic';
|
||||
}
|
||||
this.root.addChild(new ControllerNode(
|
||||
c.url, c.auth, c.username, password, c.rememberPassword,
|
||||
undefined, this.root, this, undefined
|
||||
));
|
||||
this.removeDefectiveControllerNodes(treeNodes);
|
||||
}
|
||||
this.removeDefectiveControllerNodes();
|
||||
|
||||
this.root.clearChildren();
|
||||
if (treeNodes.length === 0) {
|
||||
this.root.addChild(new AddControllerNode());
|
||||
} else {
|
||||
treeNodes.forEach(node => this.root.addChild(node));
|
||||
}
|
||||
this.notifyNodeChanged();
|
||||
} catch (err) {
|
||||
// Reset so we can try again if the tree refreshes
|
||||
this.initialized = false;
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (!this.root.hasChildren) {
|
||||
this.root.addChild(new AddControllerNode());
|
||||
}
|
||||
|
||||
this.notifyNodeChanged();
|
||||
}
|
||||
|
||||
public async saveControllers(): Promise<void> {
|
||||
|
||||
@@ -17,6 +17,7 @@ import { CmsResourceTreeNode } from './cmsResourceTreeNode';
|
||||
export class CmsResourceTreeProvider implements TreeDataProvider<TreeNode>, ICmsResourceTreeChangeHandler {
|
||||
|
||||
private _appContext: AppContext;
|
||||
private _children: TreeNode[] = [CmsResourceMessageTreeNode.create(CmsResourceTreeProvider.loadingLabel, undefined)];
|
||||
|
||||
public constructor(
|
||||
public readonly appContext: AppContext
|
||||
@@ -31,16 +32,14 @@ export class CmsResourceTreeProvider implements TreeDataProvider<TreeNode>, ICms
|
||||
}
|
||||
|
||||
if (!this.isSystemInitialized) {
|
||||
// Kick off loading the saved servers but then immediately return the loading node so
|
||||
// the user isn't left with an empty tree while we load the nodes
|
||||
this.loadSavedServers().catch(err => this._appContext.apiWrapper.showErrorMessage(localize('cms.resource.tree.treeProvider.loadError', "Unexpected error occured while loading saved servers {0}", err)));
|
||||
return [CmsResourceMessageTreeNode.create(CmsResourceTreeProvider.loadingLabel, undefined)];
|
||||
this.loadSavedServers().catch(err => this._appContext.apiWrapper.showErrorMessage(localize('cms.resource.tree.treeProvider.loadError', "Unexpected error occurred while loading saved servers {0}", err)));
|
||||
return this._children;
|
||||
}
|
||||
try {
|
||||
let registeredCmsServers = this.appContext.cmsUtils.registeredCmsServers;
|
||||
if (registeredCmsServers && registeredCmsServers.length > 0) {
|
||||
this.isSystemInitialized = true;
|
||||
return registeredCmsServers.map((server) => {
|
||||
this._children = registeredCmsServers.map((server) => {
|
||||
return new CmsResourceTreeNode(
|
||||
server.name,
|
||||
server.description,
|
||||
@@ -49,11 +48,12 @@ export class CmsResourceTreeProvider implements TreeDataProvider<TreeNode>, ICms
|
||||
this._appContext, this, null);
|
||||
}).sort((a, b) => a.name.localeCompare(b.name));
|
||||
} else {
|
||||
return [new CmsResourceEmptyTreeNode()];
|
||||
this._children = [new CmsResourceEmptyTreeNode()];
|
||||
}
|
||||
} catch (error) {
|
||||
return [new CmsResourceEmptyTreeNode()];
|
||||
this._children = [new CmsResourceEmptyTreeNode()];
|
||||
}
|
||||
return this._children;
|
||||
}
|
||||
|
||||
public get onDidChangeTreeData(): Event<TreeNode> {
|
||||
@@ -93,6 +93,10 @@ export class CmsResourceTreeProvider implements TreeDataProvider<TreeNode>, ICms
|
||||
await this.appContext.cmsUtils.cacheRegisteredCmsServer(server.name, server.description,
|
||||
server.ownerUri, server.connection);
|
||||
}
|
||||
this._children = servers;
|
||||
} else {
|
||||
// No saved servers so just show the Add Server node since we're done loading
|
||||
this._children = [new CmsResourceEmptyTreeNode()];
|
||||
}
|
||||
this._onDidChangeTreeData.fire(undefined);
|
||||
} catch (error) {
|
||||
|
||||
@@ -13,6 +13,7 @@ import { CmsResourceTreeProvider } from '../../../cmsResource/tree/treeProvider'
|
||||
import { CmsResourceMessageTreeNode } from '../../../cmsResource/messageTreeNode';
|
||||
import { CmsResourceEmptyTreeNode } from '../../../cmsResource/tree/cmsResourceEmptyTreeNode';
|
||||
import { CmsUtils } from '../../../cmsUtils';
|
||||
import { sleep } from '../../utils';
|
||||
|
||||
// Mock services
|
||||
let mockAppContext: AppContext;
|
||||
@@ -29,22 +30,42 @@ describe('CmsResourceTreeProvider.getChildren', function (): void {
|
||||
mockAppContext = new AppContext(mockExtensionContext.object, mockApiWrapper.object, mockCmsUtils.object);
|
||||
});
|
||||
|
||||
it('Should not be initialized.', async function (): Promise<void> {
|
||||
it('Should be loading while waiting for saved servers to load', async function (): Promise<void> {
|
||||
const treeProvider = new CmsResourceTreeProvider(mockAppContext);
|
||||
should.notEqual(treeProvider.isSystemInitialized, true);
|
||||
// We need to return at least one node so the async loading part is hit
|
||||
mockCmsUtils.setup(x => x.getSavedServers).returns(() => {
|
||||
return () => [{name: 'name',
|
||||
description: 'desc',
|
||||
ownerUri: 'uri',
|
||||
connection: undefined}];
|
||||
});
|
||||
// Set up so loading the servers doesn't return immediately - thus we'll still have the Loading node
|
||||
mockCmsUtils.setup(x => x.cacheRegisteredCmsServer).returns(() => {
|
||||
return async () => { await sleep(600000); return undefined; };
|
||||
});
|
||||
should.notEqual(treeProvider.isSystemInitialized, true, 'Expected isSystemInitialized not to be true');
|
||||
const children = await treeProvider.getChildren(undefined);
|
||||
should.equal(children.length, 1);
|
||||
should.equal(children[0].parent, undefined);
|
||||
should.equal(children[0] instanceof CmsResourceMessageTreeNode, true);
|
||||
should.equal(children.length, 1, 'Expected exactly one child node');
|
||||
should.equal(children[0].parent, undefined, 'Expected node to not have a parent');
|
||||
should.equal(children[0] instanceof CmsResourceMessageTreeNode, true, 'Expected node to be a CmsResourceMessageTreeNode');
|
||||
});
|
||||
|
||||
it('Should be empty resource node when no servers to load', async function (): Promise<void> {
|
||||
const treeProvider = new CmsResourceTreeProvider(mockAppContext);
|
||||
should.notEqual(treeProvider.isSystemInitialized, true, 'Expected isSystemInitialized not to be true');
|
||||
const children = await treeProvider.getChildren(undefined);
|
||||
should.equal(children.length, 1, 'Expected exactly one child node');
|
||||
should.equal(children[0].parent, undefined, 'Expected node to not have a parent');
|
||||
should.equal(children[0] instanceof CmsResourceEmptyTreeNode, true, 'Expected node to be a CmsResourceEmptyTreeNode');
|
||||
});
|
||||
|
||||
it('Should not be loading after initialized.', async function (): Promise<void> {
|
||||
const treeProvider = new CmsResourceTreeProvider(mockAppContext);
|
||||
treeProvider.isSystemInitialized = true;
|
||||
should.equal(true, treeProvider.isSystemInitialized);
|
||||
should.equal(true, treeProvider.isSystemInitialized, 'Expected isSystemInitialized to be true');
|
||||
mockCmsUtils.setup(x => x.registeredCmsServers).returns(() => []);
|
||||
const children = await treeProvider.getChildren(undefined);
|
||||
should.equal(children[0] instanceof CmsResourceEmptyTreeNode, true);
|
||||
should.equal(children[0] instanceof CmsResourceEmptyTreeNode, true, 'Expected child node to be CmsResourceEmptyTreeNode');
|
||||
});
|
||||
|
||||
it('Should show CMS nodes if there are cached servers', async function (): Promise<void> {
|
||||
@@ -59,6 +80,6 @@ describe('CmsResourceTreeProvider.getChildren', function (): void {
|
||||
}];
|
||||
});
|
||||
const children = await treeProvider.getChildren(undefined);
|
||||
should.equal(children[0] !== null, true);
|
||||
should.exist(children[0], 'Child node did not exist');
|
||||
});
|
||||
});
|
||||
|
||||
8
extensions/cms/src/test/utils.ts
Normal file
8
extensions/cms/src/test/utils.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export async function sleep(ms: number): Promise<{}> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
@@ -67,7 +67,8 @@ export class BookTreeItem extends vscode.TreeItem {
|
||||
|
||||
private setCommand() {
|
||||
if (this.book.type === BookTreeItemType.Notebook) {
|
||||
let pathToNotebook = path.join(this.book.root, 'content', this._uri.concat('.ipynb'));
|
||||
// The Notebook editor expects a posix path for the resource (it will still resolve to the correct fsPath based on OS)
|
||||
const pathToNotebook = path.posix.join(this.book.root, 'content', this._uri.concat('.ipynb'));
|
||||
this.command = { command: this.book.isUntitled ? 'bookTreeView.openUntitledNotebook' : 'bookTreeView.openNotebook', title: loc.openNotebookCommand, arguments: [pathToNotebook], };
|
||||
} else if (this.book.type === BookTreeItemType.Markdown) {
|
||||
let pathToMarkdown = path.join(this.book.root, 'content', this._uri.concat('.md'));
|
||||
@@ -81,8 +82,8 @@ export class BookTreeItem extends vscode.TreeItem {
|
||||
let i = --index;
|
||||
while (i > -1) {
|
||||
if (this.book.tableOfContents.sections[i].url) {
|
||||
// TODO: Currently only navigating to notebooks. Need to add logic for markdown.
|
||||
let pathToNotebook = path.join(this.book.root, 'content', this.book.tableOfContents.sections[i].url.concat('.ipynb'));
|
||||
// The Notebook editor expects a posix path for the resource (it will still resolve to the correct fsPath based on OS)
|
||||
let pathToNotebook = path.posix.join(this.book.root, 'content', this.book.tableOfContents.sections[i].url.concat('.ipynb'));
|
||||
// eslint-disable-next-line no-sync
|
||||
if (fs.existsSync(pathToNotebook)) {
|
||||
this._previousUri = pathToNotebook;
|
||||
@@ -97,8 +98,8 @@ export class BookTreeItem extends vscode.TreeItem {
|
||||
let i = ++index;
|
||||
while (i < this.book.tableOfContents.sections.length) {
|
||||
if (this.book.tableOfContents.sections[i].url) {
|
||||
// TODO: Currently only navigating to notebooks. Need to add logic for markdown.
|
||||
let pathToNotebook = path.join(this.book.root, 'content', this.book.tableOfContents.sections[i].url.concat('.ipynb'));
|
||||
// The Notebook editor expects a posix path for the resource (it will still resolve to the correct fsPath based on OS)
|
||||
let pathToNotebook = path.posix.join(this.book.root, 'content', this.book.tableOfContents.sections[i].url.concat('.ipynb'));
|
||||
// eslint-disable-next-line no-sync
|
||||
if (fs.existsSync(pathToNotebook)) {
|
||||
this._nextUri = pathToNotebook;
|
||||
|
||||
@@ -10,7 +10,6 @@ import * as fs from 'fs-extra';
|
||||
import { IPrompter, QuestionTypes, IQuestion } from '../prompts/question';
|
||||
import CodeAdapter from '../prompts/adapter';
|
||||
import { BookTreeItem } from './bookTreeItem';
|
||||
import { isEditorTitleFree } from '../common/utils';
|
||||
import { BookModel } from './bookModel';
|
||||
import { Deferred } from '../common/promise';
|
||||
import * as loc from '../common/localizedConstants';
|
||||
@@ -98,7 +97,8 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
|
||||
const sectionToOpen = bookRoot.findChildSection(urlToOpen);
|
||||
const urlPath = sectionToOpen ? sectionToOpen.url : bookRoot.tableOfContents.sections[0].url;
|
||||
const sectionToOpenMarkdown: string = path.join(this.currentBook.bookPath, 'content', urlPath.concat('.md'));
|
||||
const sectionToOpenNotebook: string = path.join(this.currentBook.bookPath, 'content', urlPath.concat('.ipynb'));
|
||||
// The Notebook editor expects a posix path for the resource (it will still resolve to the correct fsPath based on OS)
|
||||
const sectionToOpenNotebook: string = path.posix.join(this.currentBook.bookPath, 'content', urlPath.concat('.ipynb'));
|
||||
if (await fs.pathExists(sectionToOpenMarkdown)) {
|
||||
this.openMarkdown(sectionToOpenMarkdown);
|
||||
}
|
||||
@@ -297,9 +297,7 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
|
||||
}
|
||||
|
||||
getUntitledNotebookUri(resource: string): vscode.Uri {
|
||||
let untitledFileName: vscode.Uri;
|
||||
let nextTitle: string = this.findNextUntitledFileName(resource);
|
||||
untitledFileName = vscode.Uri.parse(`untitled:${nextTitle}`);
|
||||
let untitledFileName = vscode.Uri.parse(`untitled:${resource}`);
|
||||
if (!this.currentBook.getAllBooks().get(untitledFileName.fsPath) && !this.currentBook.getAllBooks().get(path.basename(untitledFileName.fsPath))) {
|
||||
let notebook = this.currentBook.getAllBooks().get(resource);
|
||||
this.currentBook.getAllBooks().set(path.basename(untitledFileName.fsPath), notebook);
|
||||
@@ -307,18 +305,6 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
|
||||
return untitledFileName;
|
||||
}
|
||||
|
||||
findNextUntitledFileName(filePath: string): string {
|
||||
const baseName = path.basename(filePath);
|
||||
let idx = 0;
|
||||
let title;
|
||||
do {
|
||||
const suffix = idx === 0 ? '' : `-${idx}`;
|
||||
title = `${baseName}${suffix}`;
|
||||
idx++;
|
||||
} while (!isEditorTitleFree(title));
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
//Confirmation message dialog
|
||||
private async confirmReplace(): Promise<boolean> {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
},
|
||||
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt",
|
||||
"icon": "images/sqlserver.png",
|
||||
"aiKey": "AIF-c5594e2d-38b5-4d3b-ab1b-ed5d4fe8ee40",
|
||||
"aiKey": "AIF-37eefaf0-8022-4671-a3fb-64752724682e",
|
||||
"activationEvents": [
|
||||
"onCommand:sqlDatabaseProjects.new",
|
||||
"onCommand:sqlDatabaseProjects.open",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "azuredatastudio",
|
||||
"version": "1.15.0",
|
||||
"distro": "b71b4af5016533d971958cc37e25b43b9c3754a5",
|
||||
"distro": "922d292f69c5d36ab6f0dbbd94a63c81219afaaf",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
},
|
||||
@@ -88,7 +88,7 @@
|
||||
"devDependencies": {
|
||||
"7zip": "0.0.6",
|
||||
"@types/applicationinsights": "0.20.0",
|
||||
"@types/chart.js": "^2.7.31",
|
||||
"@types/chart.js": "2.7.57",
|
||||
"@types/chokidar": "2.1.3",
|
||||
"@types/cookie": "^0.3.3",
|
||||
"@types/graceful-fs": "4.1.2",
|
||||
|
||||
1
src/bootstrap-window.js
vendored
1
src/bootstrap-window.js
vendored
@@ -111,6 +111,7 @@ exports.load = function (modulePaths, resultCallback, options) {
|
||||
'@angular/platform-browser-dynamic',
|
||||
'@angular/router',
|
||||
'rxjs/Observable',
|
||||
'rxjs/add/observable/fromPromise',
|
||||
'rxjs/Subject',
|
||||
'rxjs/Observer',
|
||||
'slickgrid/lib/jquery.event.drag-2.3.0',
|
||||
|
||||
@@ -458,8 +458,13 @@ export class MainThreadNotebookDocumentsAndEditors extends Disposable implements
|
||||
};
|
||||
let isUntitled: boolean = uri.scheme === Schemas.untitled;
|
||||
|
||||
const fileInput = isUntitled ? this._untitledEditorService.create({ untitledResource: uri, mode: 'notebook', initialValue: options.initialContent }) :
|
||||
this._editorService.createInput({ resource: uri, mode: 'notebook' });
|
||||
let fileInput;
|
||||
if (isUntitled && path.isAbsolute(uri.fsPath)) {
|
||||
fileInput = this._untitledEditorService.create({ associatedResource: uri, mode: 'notebook', initialValue: options.initialContent });
|
||||
} else {
|
||||
fileInput = isUntitled ? this._untitledEditorService.create({ untitledResource: uri, mode: 'notebook', initialValue: options.initialContent }) :
|
||||
this._editorService.createInput({ resource: uri, mode: 'notebook' });
|
||||
}
|
||||
let input: NotebookInput;
|
||||
if (isUntitled) {
|
||||
input = this._instantiationService.createInstance(UntitledNotebookInput, path.basename(uri.fsPath), uri, fileInput as UntitledTextEditorInput);
|
||||
@@ -720,7 +725,7 @@ export class MainThreadNotebookDocumentsAndEditors extends Disposable implements
|
||||
let result = await this._proxy.$getNavigation(handle, uri);
|
||||
if (result) {
|
||||
if (result.next.scheme === Schemas.untitled) {
|
||||
let untitledNbName: URI = URI.parse(`untitled:${path.basename(result.next.path)}`);
|
||||
let untitledNbName: URI = URI.parse(`untitled:${result.next.path}`);
|
||||
let content = await this._fileService.readFile(URI.file(result.next.path));
|
||||
await this.doOpenEditor(untitledNbName, { initialContent: content.value.toString(), initialDirtyState: false });
|
||||
}
|
||||
@@ -733,7 +738,7 @@ export class MainThreadNotebookDocumentsAndEditors extends Disposable implements
|
||||
let result = await this._proxy.$getNavigation(handle, uri);
|
||||
if (result) {
|
||||
if (result.previous.scheme === Schemas.untitled) {
|
||||
let untitledNbName: URI = URI.parse(`untitled:${path.basename(result.previous.path)}`);
|
||||
let untitledNbName: URI = URI.parse(`untitled:${result.previous.path}`);
|
||||
let content = await this._fileService.readFile(URI.file(result.previous.path));
|
||||
await this.doOpenEditor(untitledNbName, { initialContent: content.value.toString(), initialDirtyState: false });
|
||||
}
|
||||
|
||||
@@ -162,8 +162,8 @@ export class Graph implements IInsight {
|
||||
this.chartjs.config.type = this.options.type;
|
||||
// we don't want to include lables for timeSeries
|
||||
this.chartjs.data.labels = this.originalType === 'timeSeries' ? [] : labels;
|
||||
this.chartjs.config.options = this.transformOptions(this.options);
|
||||
this.chartjs.update(0);
|
||||
this.chartjs.options = this.transformOptions(this.options);
|
||||
this.chartjs.update({ duration: 0 });
|
||||
} else {
|
||||
this.chartjs = new chartjs.Chart(this.canvas.getContext('2d'), {
|
||||
data: {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
ComponentFactoryResolver, ViewChild, ChangeDetectorRef, Injector
|
||||
} from '@angular/core';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import 'rxjs/add/observable/fromPromise';
|
||||
|
||||
import { DashboardWidget, IDashboardWidget, WIDGET_CONFIG, WidgetConfig } from 'sql/workbench/contrib/dashboard/browser/core/dashboardWidget';
|
||||
import { CommonServiceInterface } from 'sql/workbench/services/bootstrap/browser/commonServiceInterface.service';
|
||||
|
||||
@@ -33,6 +33,7 @@ import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { deepClone, assign } from 'vs/base/common/objects';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { equals } from 'vs/base/common/arrays';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
|
||||
export class EditDataGridPanel extends GridParentComponent {
|
||||
// The time(in milliseconds) we wait before refreshing the grid.
|
||||
@@ -110,6 +111,7 @@ export class EditDataGridPanel extends GridParentComponent {
|
||||
onInit(): void {
|
||||
const self = this;
|
||||
this.baseInit();
|
||||
this._register(DOM.addDisposableListener(this.nativeElement, DOM.EventType.KEY_DOWN, e => this.tryHandleKeyEvent(new StandardKeyboardEvent(e))));
|
||||
|
||||
// Add the subscription to the list of things to be disposed on destroy, or else on a new component init
|
||||
// may get the "destroyed" object still getting called back.
|
||||
@@ -396,7 +398,6 @@ export class EditDataGridPanel extends GridParentComponent {
|
||||
|
||||
// Setup the state of the selected cell
|
||||
this.resetCurrentCell();
|
||||
this.currentEditCellValue = undefined;
|
||||
this.removingNewRow = false;
|
||||
this.newRowVisible = false;
|
||||
this.dirtyCells = [];
|
||||
@@ -522,7 +523,6 @@ export class EditDataGridPanel extends GridParentComponent {
|
||||
// so clear any existing client-side edit and refresh on-screen data
|
||||
// do not refresh the whole dataset as it will move the focus away to the first row.
|
||||
//
|
||||
this.currentEditCellValue = undefined;
|
||||
this.dirtyCells = [];
|
||||
let row = this.currentCell.row;
|
||||
this.resetCurrentCell();
|
||||
@@ -761,6 +761,7 @@ export class EditDataGridPanel extends GridParentComponent {
|
||||
isEditable: false,
|
||||
isDirty: false
|
||||
};
|
||||
this.currentEditCellValue = undefined;
|
||||
}
|
||||
|
||||
private setCurrentCell(row: number, column: number) {
|
||||
@@ -1066,7 +1067,7 @@ export class EditDataGridPanel extends GridParentComponent {
|
||||
cellClasses += ' missing-value';
|
||||
}
|
||||
else if (Services.DBCellValue.isDBCellValue(value)) {
|
||||
valueToDisplay = (value.displayValue + '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
valueToDisplay = (value.displayValue + '');
|
||||
valueToDisplay = escape(valueToDisplay.length > 250 ? valueToDisplay.slice(0, 250) + '...' : valueToDisplay);
|
||||
}
|
||||
else if (typeof value === 'string' || (value && value.text)) {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
/* Node Modules */
|
||||
import { Injectable, Inject } from '@angular/core';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import 'rxjs/add/observable/fromPromise';
|
||||
|
||||
/* SQL imports */
|
||||
import { IDefaultComponentParams, IBootstrapParams } from 'sql/workbench/services/bootstrap/common/bootstrapParams';
|
||||
|
||||
@@ -52,7 +52,7 @@ export class QueryEditorService implements IQueryEditorService {
|
||||
let docUri: URI = URI.from({ scheme: Schemas.untitled, path: filePath });
|
||||
|
||||
// Create a sql document pane with accoutrements
|
||||
const fileInput = this._untitledEditorService.create({ associatedResource: docUri, mode: 'sql' });
|
||||
const fileInput = this._untitledEditorService.create({ untitledResource: docUri, mode: 'sql' });
|
||||
let untitledEditorModel = await fileInput.resolve();
|
||||
if (sqlContent) {
|
||||
untitledEditorModel.textEditorModel.setValue(sqlContent);
|
||||
@@ -89,6 +89,8 @@ export class QueryEditorService implements IQueryEditorService {
|
||||
// Create a sql document pane with accoutrements
|
||||
const fileInput = this._untitledEditorService.create({ untitledResource: docUri, mode: 'sql' });
|
||||
const m = await fileInput.resolve();
|
||||
//when associatedResource editor is created it is dirty, this must be set to false to be able to detect changes to the editor.
|
||||
m.setDirty(false);
|
||||
// Create an EditDataInput for editing
|
||||
const resultsInput: EditDataResultsInput = this._instantiationService.createInstance(EditDataResultsInput, docUri.toString());
|
||||
let editDataInput: EditDataInput = this._instantiationService.createInstance(EditDataInput, docUri, schemaName, tableName, fileInput, sqlContent, resultsInput);
|
||||
|
||||
@@ -78,7 +78,7 @@ interface ISharedProcessInitData {
|
||||
logLevel: LogLevel;
|
||||
}
|
||||
|
||||
const eventPrefix = product.quality !== 'stable' ? 'adsworkbench' : 'monacoworkbench'; // {{ SQL CARBON EDIT }}
|
||||
const eventPrefix = 'adsworkbench'; // {{ SQL CARBON EDIT }}
|
||||
|
||||
class MainProcessService implements IMainProcessService {
|
||||
constructor(private server: Server, private mainRouter: StaticRouter) { }
|
||||
|
||||
@@ -292,7 +292,7 @@ export class Main {
|
||||
}
|
||||
}
|
||||
|
||||
const eventPrefix = product.quality !== 'stable' ? 'adsworkbench' : 'monacoworkbench'; // {{SQL CARBON EDIT}}
|
||||
const eventPrefix = 'adsworkbench'; // {{SQL CARBON EDIT}}
|
||||
|
||||
export async function main(argv: ParsedArgs): Promise<void> {
|
||||
const services = new ServiceCollection();
|
||||
|
||||
@@ -20,24 +20,12 @@ export async function resolveCommonProperties(
|
||||
product?: string
|
||||
): Promise<{ [name: string]: string | boolean | undefined; }> {
|
||||
const result: { [name: string]: string | boolean | undefined; } = Object.create(null);
|
||||
// {{SQL CARBON EDIT}} start
|
||||
if (productObject.quality !== 'stable') {
|
||||
// __GDPR__COMMON__ "common.machineId" : { "endPoint": "MacAddressHash", "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight" }
|
||||
result['common.machineId'] = machineId;
|
||||
// __GDPR__COMMON__ "sessionID" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
result['sessionID'] = uuid.generateUuid() + Date.now();
|
||||
// __GDPR__COMMON__ "commitHash" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
|
||||
result['commitHash'] = commit;
|
||||
} else {
|
||||
// __GDPR__COMMON__ "common.machineId" : { "endPoint": "MacAddressHash", "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight" }
|
||||
// result['common.machineId'] = machineId;
|
||||
result['common.machineId'] = '';
|
||||
// // __GDPR__COMMON__ "sessionID" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
// result['sessionID'] = uuid.generateUuid() + Date.now();
|
||||
result['sessionID'] = '';
|
||||
// __GDPR__COMMON__ "commitHash" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
result['commitHash'] = '';
|
||||
} // {{SQL CARBON EDIT}} end
|
||||
// __GDPR__COMMON__ "common.machineId" : { "endPoint": "MacAddressHash", "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight" }
|
||||
result['common.machineId'] = machineId;
|
||||
// __GDPR__COMMON__ "sessionID" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
result['sessionID'] = uuid.generateUuid() + Date.now();
|
||||
// __GDPR__COMMON__ "commitHash" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
|
||||
result['commitHash'] = commit;
|
||||
// __GDPR__COMMON__ "version" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
result['version'] = version;
|
||||
// __GDPR__COMMON__ "common.platformVersion" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
|
||||
@@ -24,39 +24,20 @@ export async function resolveWorkbenchCommonProperties(
|
||||
const firstSessionDate = storageService.get(firstSessionDateStorageKey, StorageScope.GLOBAL)!;
|
||||
const lastSessionDate = storageService.get(lastSessionDateStorageKey, StorageScope.GLOBAL)!;
|
||||
|
||||
if (product.quality !== 'stable') {
|
||||
// __GDPR__COMMON__ "common.version.shell" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
|
||||
result['common.version.shell'] = process.versions && process.versions['electron'];
|
||||
// __GDPR__COMMON__ "common.version.renderer" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
|
||||
result['common.version.renderer'] = process.versions && process.versions['chrome'];
|
||||
// __GDPR__COMMON__ "common.firstSessionDate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
result['common.firstSessionDate'] = firstSessionDate;
|
||||
// __GDPR__COMMON__ "common.lastSessionDate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
result['common.lastSessionDate'] = lastSessionDate || '';
|
||||
// __GDPR__COMMON__ "common.isNewSession" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
result['common.isNewSession'] = !lastSessionDate ? '1' : '0';
|
||||
// __GDPR__COMMON__ "common.instanceId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
result['common.instanceId'] = instanceId;
|
||||
// __GDPR__COMMON__ "common.remoteAuthority" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
|
||||
result['common.remoteAuthority'] = cleanRemoteAuthority(remoteAuthority);
|
||||
} else {
|
||||
// __GDPR__COMMON__ "common.version.shell" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
|
||||
// result['common.version.shell'] = process.versions && process.versions['electron'];
|
||||
// __GDPR__COMMON__ "common.version.renderer" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
|
||||
// result['common.version.renderer'] = process.versions && process.versions['chrome'];
|
||||
// __GDPR__COMMON__ "common.firstSessionDate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
// result['common.firstSessionDate'] = firstSessionDate;
|
||||
// __GDPR__COMMON__ "common.lastSessionDate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
// result['common.lastSessionDate'] = lastSessionDate || '';
|
||||
// __GDPR__COMMON__ "common.isNewSession" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
// result['common.isNewSession'] = !lastSessionDate ? '1' : '0';
|
||||
// __GDPR__COMMON__ "common.instanceId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
// result['common.instanceId'] = instanceId;
|
||||
// __GDPR__COMMON__ "common.remoteAuthority" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
|
||||
// result['common.remoteAuthority'] = cleanRemoteAuthority(remoteAuthority);
|
||||
|
||||
result['common.userId'] = ''; // {{SQL CARBON EDIT}}
|
||||
}
|
||||
// __GDPR__COMMON__ "common.version.shell" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
|
||||
result['common.version.shell'] = process.versions && process.versions['electron'];
|
||||
// __GDPR__COMMON__ "common.version.renderer" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
|
||||
result['common.version.renderer'] = process.versions && process.versions['chrome'];
|
||||
// __GDPR__COMMON__ "common.firstSessionDate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
result['common.firstSessionDate'] = firstSessionDate;
|
||||
// __GDPR__COMMON__ "common.lastSessionDate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
result['common.lastSessionDate'] = lastSessionDate || '';
|
||||
// __GDPR__COMMON__ "common.isNewSession" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
result['common.isNewSession'] = !lastSessionDate ? '1' : '0';
|
||||
// __GDPR__COMMON__ "common.instanceId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
result['common.instanceId'] = instanceId;
|
||||
// __GDPR__COMMON__ "common.remoteAuthority" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
|
||||
result['common.remoteAuthority'] = cleanRemoteAuthority(remoteAuthority);
|
||||
|
||||
result['common.application.name'] = product.nameLong; // {{SQL CARBON EDIT}}
|
||||
setUsageDates(storageService);
|
||||
|
||||
3
src/vs/vscode.d.ts
vendored
3
src/vs/vscode.d.ts
vendored
@@ -7940,6 +7940,9 @@ declare module 'vscode' {
|
||||
* An event signaling when the selected items have changed.
|
||||
*/
|
||||
readonly onDidChangeSelection: Event<T[]>;
|
||||
|
||||
// {SQL CARBON EDIT} Temporary change to allow setting the behavior of the QuickPick
|
||||
ok: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -261,9 +261,22 @@ class ExtHostQuickInput implements QuickInput {
|
||||
this._onDidChangeValueEmitter
|
||||
];
|
||||
|
||||
|
||||
constructor(protected _proxy: MainThreadQuickOpenShape, protected _extensionId: ExtensionIdentifier, private _onDidDispose: () => void) {
|
||||
}
|
||||
|
||||
// {SQL CARBON EDIT} START Temporary change for ok button visibility
|
||||
private _ok = false;
|
||||
get ok() {
|
||||
return this._ok;
|
||||
}
|
||||
|
||||
set ok(ok: boolean) {
|
||||
this._ok = ok;
|
||||
this.update({ ok });
|
||||
}
|
||||
// {SQL CARBON EDIT} END Temporary change for ok button visibility
|
||||
|
||||
get title() {
|
||||
return this._title;
|
||||
}
|
||||
|
||||
@@ -510,15 +510,15 @@ class ResourceLabelWidget extends IconLabel {
|
||||
}
|
||||
|
||||
let label = this.label.name || '';
|
||||
if (resource?.scheme === Schemas.untitled) {
|
||||
// Untitled labels are very dynamic because they may change
|
||||
// whenever the content changes. As such we always ask the
|
||||
// text file service for the name of the untitled editor
|
||||
const untitledName = this.textFileService.untitled.get(resource)?.getName();
|
||||
if (untitledName) {
|
||||
label = untitledName;
|
||||
}
|
||||
}
|
||||
// if (resource?.scheme === Schemas.untitled) { // {{SQL CARBON EDIT}} - For Query Editor, untitled editor query must use same label.
|
||||
// // Untitled labels are very dynamic because they may change
|
||||
// // whenever the content changes. As such we always ask the
|
||||
// // text file service for the name of the untitled editor
|
||||
// const untitledName = this.textFileService.untitled.get(resource)?.getName();
|
||||
// if (untitledName) {
|
||||
// label = untitledName;
|
||||
// }
|
||||
// }
|
||||
|
||||
this.setLabel(label, this.label.description, iconLabelOptions);
|
||||
|
||||
|
||||
@@ -426,10 +426,8 @@ registry.registerWorkbenchAction(SyncActionDescriptor.create(EditorLayoutTwoRows
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(EditorLayoutTwoColumnsBottomAction, EditorLayoutTwoColumnsBottomAction.ID, EditorLayoutTwoColumnsBottomAction.LABEL), 'View: Two Columns Bottom Editor Layout', category);
|
||||
|
||||
// Register Quick Editor Actions including built in quick navigate support for some
|
||||
const quickOpenNextRecentlyUsedEditorInGroupKeybinding = { primary: KeyMod.CtrlCmd | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyCode.Tab } };
|
||||
const quickOpenPreviousRecentlyUsedEditorInGroupKeybinding = { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Tab } };
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenPreviousRecentlyUsedEditorAction, QuickOpenPreviousRecentlyUsedEditorAction.ID, QuickOpenPreviousRecentlyUsedEditorAction.LABEL), 'View: Quick Open Previous Recently Used Editor', category);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenPreviousRecentlyUsedEditorInGroupAction, QuickOpenPreviousRecentlyUsedEditorInGroupAction.ID, QuickOpenPreviousRecentlyUsedEditorInGroupAction.LABEL, quickOpenPreviousRecentlyUsedEditorInGroupKeybinding), 'View: Quick Open Previous Recently Used Editor in Group', category);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenPreviousRecentlyUsedEditorInGroupAction, QuickOpenPreviousRecentlyUsedEditorInGroupAction.ID, QuickOpenPreviousRecentlyUsedEditorInGroupAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyCode.Tab } }), 'View: Quick Open Previous Recently Used Editor in Group', category);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenPreviousEditorFromHistoryAction, QuickOpenPreviousEditorFromHistoryAction.ID, QuickOpenPreviousEditorFromHistoryAction.LABEL), 'Quick Open Previous Editor from History');
|
||||
|
||||
const quickOpenNavigateNextInEditorPickerId = 'workbench.action.quickOpenNavigateNextInEditorPicker';
|
||||
@@ -438,8 +436,8 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
weight: KeybindingWeight.WorkbenchContrib + 50,
|
||||
handler: getQuickNavigateHandler(quickOpenNavigateNextInEditorPickerId, true),
|
||||
when: editorPickerContext,
|
||||
primary: quickOpenNextRecentlyUsedEditorInGroupKeybinding.primary,
|
||||
mac: quickOpenNextRecentlyUsedEditorInGroupKeybinding.mac
|
||||
primary: KeyMod.CtrlCmd | KeyCode.Tab,
|
||||
mac: { primary: KeyMod.WinCtrl | KeyCode.Tab }
|
||||
});
|
||||
|
||||
const quickOpenNavigatePreviousInEditorPickerId = 'workbench.action.quickOpenNavigatePreviousInEditorPicker';
|
||||
@@ -448,8 +446,8 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
weight: KeybindingWeight.WorkbenchContrib + 50,
|
||||
handler: getQuickNavigateHandler(quickOpenNavigatePreviousInEditorPickerId, false),
|
||||
when: editorPickerContext,
|
||||
primary: quickOpenPreviousRecentlyUsedEditorInGroupKeybinding.primary,
|
||||
mac: quickOpenPreviousRecentlyUsedEditorInGroupKeybinding.mac
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Tab,
|
||||
mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Tab }
|
||||
});
|
||||
|
||||
// Editor Commands
|
||||
|
||||
@@ -242,9 +242,9 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt
|
||||
}
|
||||
|
||||
private updateNameFromFirstLine(): void {
|
||||
if (this.hasAssociatedFilePath) {
|
||||
return; // not in case of an associated file path
|
||||
}
|
||||
// if (this.hasAssociatedFilePath) { {{SQL CARBON EDIT}} - For Query Editor, must not change name even without file path.
|
||||
return;
|
||||
// }
|
||||
|
||||
// Determine the first words of the model following these rules:
|
||||
// - cannot be only whitespace (so we trim())
|
||||
|
||||
@@ -572,7 +572,8 @@ export abstract class AbstractTextFileService extends Disposable implements ITex
|
||||
}
|
||||
|
||||
// Finally fallback to suggest just the file name
|
||||
return toLocalResource(resource.with({ path: suggestedFilename }), remoteAuthority);
|
||||
// {{SQL CARBON EDIT}} - Rationale: this seems to be a bug we picked up from a vscode merge. This should get fixed with a new merge in the future.
|
||||
return joinPath(this.fileDialogService.defaultFilePath() || URI.file(this.environmentService.userHome), suggestedFilename);
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
@@ -303,7 +303,7 @@ suite('Workbench untitled text editors', () => {
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('service#onDidChangeLabel', async () => {
|
||||
test.skip('service#onDidChangeLabel', async () => { // {{SQL CARBON EDIT}} - Disable as untitledTextEditorModel test is disabled.
|
||||
const service = accessor.untitledTextEditorService;
|
||||
const input = service.create();
|
||||
|
||||
@@ -383,7 +383,7 @@ suite('Workbench untitled text editors', () => {
|
||||
assert.ok(counter > 1);
|
||||
});
|
||||
|
||||
test('model#onDidChangeName and input name', async function () {
|
||||
test.skip('model#onDidChangeName and input name', async function () { // {{SQL CARBON EDIT}} - Disable as untitledTextEditorModel test is disabled.
|
||||
const service = accessor.untitledTextEditorService;
|
||||
const input = service.create();
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ function main() {
|
||||
'angular2-grid',
|
||||
'ng2-charts',
|
||||
'rxjs/add/observable/of',
|
||||
'rxjs/add/observable/fromPromise',
|
||||
'rxjs/Observable',
|
||||
'rxjs/Subject',
|
||||
'rxjs/Observer'
|
||||
|
||||
@@ -51,6 +51,7 @@ function initLoader(opts) {
|
||||
'angular2-grid',
|
||||
'ng2-charts',
|
||||
'rxjs/add/observable/of',
|
||||
'rxjs/add/observable/fromPromise',
|
||||
'rxjs/Observable',
|
||||
'rxjs/Subject',
|
||||
'rxjs/Observer'
|
||||
|
||||
@@ -192,10 +192,10 @@
|
||||
dependencies:
|
||||
applicationinsights "*"
|
||||
|
||||
"@types/chart.js@^2.7.31":
|
||||
version "2.7.48"
|
||||
resolved "https://registry.yarnpkg.com/@types/chart.js/-/chart.js-2.7.48.tgz#db7b6d6ed33659f97ee49181f22c980bb0790a7b"
|
||||
integrity sha512-U8paSPZGkW2WrHf8sgJj7s9MhfRgSz7wfU3CN73JVrcGJ13jGiqiXyr3Bg/4UFl4cbN3S8avHTsbtzYBrnWeVg==
|
||||
"@types/chart.js@2.7.57":
|
||||
version "2.7.57"
|
||||
resolved "https://registry.yarnpkg.com/@types/chart.js/-/chart.js-2.7.57.tgz#6f4f7a588de48c2f82e67608b8e1f01e91be38f7"
|
||||
integrity sha512-kVYcxX7PdTcUrmd2Q0UjN1U0YDO1FfZ8QCDvahGmI3gvwySZYwtcRANiduOI3st6Va2T/yBBLsoHt+Gl3O7Ztw==
|
||||
|
||||
"@types/chokidar@2.1.3":
|
||||
version "2.1.3"
|
||||
|
||||
Reference in New Issue
Block a user