mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-18 17:22:45 -05:00
Merge from vscode 2e5312cd61ff99c570299ecc122c52584265eda2
This commit is contained in:
committed by
Anthony Dresser
parent
3603f55d97
commit
7f1d8fc32f
@@ -27,7 +27,7 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { dirname, basename } from 'vs/base/common/resources';
|
||||
import { LIGHT, FileThemeIcon, FolderThemeIcon, registerThemingParticipant, IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { FileKind } from 'vs/platform/files/common/files';
|
||||
import { WorkbenchAsyncDataTree, ResourceNavigator } from 'vs/platform/list/browser/listService';
|
||||
import { WorkbenchAsyncDataTree, TreeResourceNavigator } from 'vs/platform/list/browser/listService';
|
||||
import { localize } from 'vs/nls';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { editorFindMatchHighlight, editorFindMatchHighlightBorder, textLinkForeground, textCodeBlockBackground, focusBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
@@ -416,9 +416,9 @@ export class CustomTreeView extends Disposable implements ITreeView {
|
||||
accessibilityProvider: {
|
||||
getAriaLabel(element: ITreeItem): string {
|
||||
return element.label ? element.label.label : '';
|
||||
}
|
||||
},
|
||||
getWidgetAriaLabel: () => this.title
|
||||
},
|
||||
ariaLabel: this.title,
|
||||
keyboardNavigationLabelProvider: {
|
||||
getKeyboardNavigationLabel: (item: ITreeItem) => {
|
||||
return item.label ? item.label.label : (item.resourceUri ? basename(URI.revive(item.resourceUri)) : undefined);
|
||||
@@ -451,7 +451,7 @@ export class CustomTreeView extends Disposable implements ITreeView {
|
||||
}));
|
||||
this.tree.setInput(this.root).then(() => this.updateContentAreas());
|
||||
|
||||
const customTreeNavigator = ResourceNavigator.createTreeResourceNavigator(this.tree, { openOnFocus: false, openOnSelection: false });
|
||||
const customTreeNavigator = new TreeResourceNavigator(this.tree, { openOnFocus: false, openOnSelection: false });
|
||||
this._register(customTreeNavigator);
|
||||
this._register(customTreeNavigator.onDidOpenResource(e => {
|
||||
if (!e.browserEvent) {
|
||||
|
||||
@@ -28,7 +28,8 @@ class AccountsStatusBarContributions extends Disposable implements IWorkbenchCon
|
||||
this._register(
|
||||
this.statusbarService.addEntry({
|
||||
command: 'workbench.actions.modal.linkedAccount',
|
||||
text: '$(person-filled)'
|
||||
text: '$(person-filled)',
|
||||
ariaLabel: 'Accounts'
|
||||
},
|
||||
'status.accountList',
|
||||
localize('status.problems', "Problems"),
|
||||
|
||||
@@ -30,6 +30,7 @@ export class ConnectionStatusbarItem extends Disposable implements IWorkbenchCon
|
||||
this.statusItem = this._register(
|
||||
this.statusbarService.addEntry({
|
||||
text: '',
|
||||
ariaLabel: ''
|
||||
},
|
||||
ConnectionStatusbarItem.ID,
|
||||
localize('status.connection.status', "Connection Status"),
|
||||
@@ -84,7 +85,7 @@ export class ConnectionStatusbarItem extends Disposable implements IWorkbenchCon
|
||||
}
|
||||
|
||||
this.statusItem.update({
|
||||
text, tooltip
|
||||
text, ariaLabel: text, tooltip
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ export class DataExplorerViewPaneContainer extends ViewPaneContainer {
|
||||
@IContextKeyService private contextKeyService: IContextKeyService,
|
||||
@IViewDescriptorService viewDescriptorService: IViewDescriptorService
|
||||
) {
|
||||
super(VIEWLET_ID, `${VIEWLET_ID}.state`, { mergeViewWithContainerWhenSingleView: true }, instantiationService, configurationService, layoutService, contextMenuService, telemetryService, extensionService, themeService, storageService, contextService, viewDescriptorService);
|
||||
super(VIEWLET_ID, { mergeViewWithContainerWhenSingleView: true }, instantiationService, configurationService, layoutService, contextMenuService, telemetryService, extensionService, themeService, storageService, contextService, viewDescriptorService);
|
||||
}
|
||||
|
||||
create(parent: HTMLElement): void {
|
||||
|
||||
@@ -88,11 +88,13 @@ export class EditDataEditor extends BaseEditor {
|
||||
}
|
||||
|
||||
if (_editorService) {
|
||||
_editorService.overrideOpenEditor((editor, options, group) => {
|
||||
if (this.isVisible() && (editor !== this.input || group !== this.group)) {
|
||||
this.saveEditorViewState();
|
||||
_editorService.overrideOpenEditor({
|
||||
open: (editor, options, group) => {
|
||||
if (this.isVisible() && (editor !== this.input || group !== this.group)) {
|
||||
this.saveEditorViewState();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,9 @@ export class EditorReplacementContribution implements IWorkbenchContribution {
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IModeService private readonly modeService: IModeService
|
||||
) {
|
||||
this.editorOpeningListener = this.editorService.overrideOpenEditor((editor, options, group) => this.onEditorOpening(editor, options, group));
|
||||
this.editorOpeningListener = this.editorService.overrideOpenEditor({
|
||||
open: (editor, options, group) => this.onEditorOpening(editor, options, group)
|
||||
});
|
||||
}
|
||||
|
||||
private onEditorOpening(editor: IEditorInput, options: IEditorOptions | ITextEditorOptions | undefined, group: IEditorGroup): IOpenEditorOverride | undefined {
|
||||
|
||||
@@ -194,7 +194,7 @@ class MockEditorService extends TestEditorService {
|
||||
fireOpenEditor(editor: IEditorInput, options: IEditorOptions | ITextEditorOptions | undefined, group: IEditorGroup) {
|
||||
for (const handler of this.overridenOpens) {
|
||||
let response: IOpenEditorOverride | undefined;
|
||||
if (response = handler(editor, options, group)) {
|
||||
if (response = handler.open(editor, options, group)) {
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ExtensionRecommendations, ExtensionRecommendation } from 'vs/workbench/contrib/extensions/browser/extensionRecommendations';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IExtensionRecommendation } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { visualizerExtensions } from 'sql/workbench/contrib/extensions/common/constants';
|
||||
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
|
||||
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
|
||||
import { InstallRecommendedExtensionsByScenarioAction, ShowRecommendedExtensionsByScenarioAction } from 'sql/workbench/contrib/extensions/browser/extensionsActions';
|
||||
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
|
||||
|
||||
const choiceNever = localize('neverShowAgain', "Don't Show Again");
|
||||
|
||||
export class ScenarioRecommendations extends ExtensionRecommendations {
|
||||
|
||||
readonly _recommendations: ExtensionRecommendation[] = [];
|
||||
get recommendations(): ReadonlyArray<ExtensionRecommendation> { return this._recommendations; }
|
||||
|
||||
constructor(
|
||||
isExtensionAllowedToBeRecommended: (extensionId: string) => boolean,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@INotificationService notificationService: INotificationService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
|
||||
@IAdsTelemetryService private readonly adsTelemetryService: IAdsTelemetryService,
|
||||
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService
|
||||
) {
|
||||
super(isExtensionAllowedToBeRecommended, instantiationService, configurationService, notificationService, telemetryService, storageService, storageKeysSyncRegistryService);
|
||||
|
||||
// this._recommendations = productService.recommendedExtensionsByScenario.map(r => ({ extensionId: r, reason: { reasonId: ExtensionRecommendationReason.Application, reasonText: localize('defaultRecommendations', "This extension is recommended by Azure Data Studio.") }, source: 'application' }));
|
||||
}
|
||||
|
||||
protected async doActivate(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
promptRecommendedExtensionsByScenario(scenarioType: string): void {
|
||||
const storageKey = 'extensionAssistant/RecommendationsIgnore/' + scenarioType;
|
||||
|
||||
if (this.storageService.getBoolean(storageKey, StorageScope.GLOBAL, false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const visualizerExtensionNotificationService = 'VisualizerExtensionNotificationService';
|
||||
|
||||
let recommendationMessage = localize('ExtensionsRecommended', "Azure Data Studio has extension recommendations.");
|
||||
if (scenarioType === visualizerExtensions) {
|
||||
recommendationMessage = localize('VisualizerExtensionsRecommended', "Azure Data Studio has extension recommendations for data visualization.\nOnce installed, you can select the Visualizer icon to visualize your query results.");
|
||||
}
|
||||
Promise.all([this.getRecommendedExtensionsByScenario(scenarioType), this.extensionManagementService.getInstalled(ExtensionType.User)]).then(([recommendations, localExtensions]) => {
|
||||
if (!recommendations.every(rec => { return localExtensions.findIndex(local => local.identifier.id.toLocaleLowerCase() === rec.extensionId.toLocaleLowerCase()) !== -1; })) {
|
||||
return new Promise<void>(c => {
|
||||
this.notificationService.prompt(
|
||||
Severity.Info,
|
||||
recommendationMessage,
|
||||
[{
|
||||
label: localize('installAll', "Install All"),
|
||||
run: () => {
|
||||
this.adsTelemetryService.sendActionEvent(
|
||||
TelemetryKeys.TelemetryView.ExtensionRecommendationDialog,
|
||||
TelemetryKeys.TelemetryAction.Click,
|
||||
'InstallButton',
|
||||
visualizerExtensionNotificationService
|
||||
);
|
||||
const installAllAction = this.instantiationService.createInstance(InstallRecommendedExtensionsByScenarioAction, scenarioType, recommendations);
|
||||
installAllAction.run();
|
||||
installAllAction.dispose();
|
||||
}
|
||||
}, {
|
||||
label: localize('showRecommendations', "Show Recommendations"),
|
||||
run: () => {
|
||||
this.adsTelemetryService.sendActionEvent(
|
||||
TelemetryKeys.TelemetryView.ExtensionRecommendationDialog,
|
||||
TelemetryKeys.TelemetryAction.Click,
|
||||
'ShowRecommendationsButton',
|
||||
visualizerExtensionNotificationService
|
||||
);
|
||||
const showAction = this.instantiationService.createInstance(ShowRecommendedExtensionsByScenarioAction, scenarioType);
|
||||
showAction.run();
|
||||
showAction.dispose();
|
||||
c(undefined);
|
||||
}
|
||||
}, {
|
||||
label: choiceNever,
|
||||
isSecondary: true,
|
||||
run: () => {
|
||||
this.adsTelemetryService.sendActionEvent(
|
||||
TelemetryKeys.TelemetryView.ExtensionRecommendationDialog,
|
||||
TelemetryKeys.TelemetryAction.Click,
|
||||
'NeverShowAgainButton',
|
||||
visualizerExtensionNotificationService
|
||||
);
|
||||
this.storageService.store(storageKey, true, StorageScope.GLOBAL);
|
||||
c(undefined);
|
||||
}
|
||||
}],
|
||||
{
|
||||
sticky: true,
|
||||
onCancel: () => {
|
||||
this.adsTelemetryService.sendActionEvent(
|
||||
TelemetryKeys.TelemetryView.ExtensionRecommendationDialog,
|
||||
TelemetryKeys.TelemetryAction.Click,
|
||||
'CancelButton',
|
||||
visualizerExtensionNotificationService
|
||||
);
|
||||
c(undefined);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getRecommendedExtensionsByScenario(scenarioType: string): Promise<IExtensionRecommendation[]> {
|
||||
if (!scenarioType) {
|
||||
return Promise.reject(new Error(localize('scenarioTypeUndefined', 'The scenario type for extension recommendations must be provided.')));
|
||||
}
|
||||
return Promise.resolve((this.productService.recommendedExtensionsByScenario[scenarioType] || [])
|
||||
.filter(extensionId => this.isExtensionAllowedToBeRecommended(extensionId))
|
||||
.map(extensionId => (<IExtensionRecommendation>{ extensionId, sources: ['application'] })));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ExtensionRecommendations, ExtensionRecommendation } from 'vs/workbench/contrib/extensions/browser/extensionRecommendations';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ExtensionRecommendationReason } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
|
||||
|
||||
export class StaticRecommendations extends ExtensionRecommendations {
|
||||
|
||||
readonly _recommendations: ExtensionRecommendation[] = [];
|
||||
get recommendations(): ReadonlyArray<ExtensionRecommendation> { return this._recommendations; }
|
||||
|
||||
constructor(
|
||||
isExtensionAllowedToBeRecommended: (extensionId: string) => boolean,
|
||||
@IProductService productService: IProductService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@INotificationService notificationService: INotificationService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService
|
||||
) {
|
||||
super(isExtensionAllowedToBeRecommended, instantiationService, configurationService, notificationService, telemetryService, storageService, storageKeysSyncRegistryService);
|
||||
|
||||
this._recommendations = productService.recommendedExtensions.map(r => ({ extensionId: r, reason: { reasonId: ExtensionRecommendationReason.Application, reasonText: localize('defaultRecommendations', "This extension is recommended by Azure Data Studio.") }, source: 'application' }));
|
||||
}
|
||||
|
||||
protected async doActivate(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -365,7 +365,8 @@ export class NotebookEditor extends BaseEditor implements IFindNotebookControlle
|
||||
searchScope: true,
|
||||
matchesPosition: false,
|
||||
matchesCount: false,
|
||||
currentMatch: false
|
||||
currentMatch: false,
|
||||
loop: true
|
||||
};
|
||||
this._notebookModel.cells.forEach(cell => {
|
||||
this._register(cell.onCellModeChanged((state) => {
|
||||
@@ -450,7 +451,8 @@ export class NotebookEditor extends BaseEditor implements IFindNotebookControlle
|
||||
searchScope: false,
|
||||
matchesPosition: false,
|
||||
matchesCount: false,
|
||||
currentMatch: false
|
||||
currentMatch: false,
|
||||
loop: true
|
||||
};
|
||||
this._onFindStateChange(changeEvent).catch(e => { onUnexpectedError(e); });
|
||||
}
|
||||
|
||||
@@ -172,11 +172,13 @@ export class ProfilerEditor extends BaseEditor {
|
||||
this._profilerEditorContextKey = CONTEXT_PROFILER_EDITOR.bindTo(this._contextKeyService);
|
||||
|
||||
if (editorService) {
|
||||
editorService.overrideOpenEditor((editor, options, group) => {
|
||||
if (this.isVisible() && (editor !== this.input || group !== this.group)) {
|
||||
this.saveEditorViewState();
|
||||
editorService.overrideOpenEditor({
|
||||
open: (editor, options, group) => {
|
||||
if (this.isVisible() && (editor !== this.input || group !== this.group)) {
|
||||
this.saveEditorViewState();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -502,7 +504,8 @@ export class ProfilerEditor extends BaseEditor {
|
||||
seedSearchStringFromSelection: (controller.getState().searchString.length === 0),
|
||||
shouldFocus: FindStartFocusAction.FocusFindInput,
|
||||
shouldAnimate: true,
|
||||
updateSearchScope: false
|
||||
updateSearchScope: false,
|
||||
loop: true
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -288,7 +288,7 @@ export class ProfilerTableEditor extends BaseEditor implements IProfilerControll
|
||||
: localize('ProfilerTableEditor.eventCount', "Events: {0}", this._input.data.getLength());
|
||||
|
||||
this._disposeStatusbarItem();
|
||||
this._statusbarItem = this._statusbarService.addEntry({ text: message }, 'status.eventCount', localize('status.eventCount', "Event Count"), StatusbarAlignment.RIGHT);
|
||||
this._statusbarItem = this._statusbarService.addEntry({ text: message, ariaLabel: message }, 'status.eventCount', localize('status.eventCount', "Event Count"), StatusbarAlignment.RIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -74,8 +74,8 @@ export class SqlFlavorStatusbarItem extends Disposable implements IWorkbenchCont
|
||||
this.statusItem = this._register(
|
||||
this.statusbarService.addEntry({
|
||||
text: nls.localize('changeProvider', "Change SQL language provider"),
|
||||
ariaLabel: nls.localize('changeProvider', "Change SQL language provider"),
|
||||
command: 'sql.action.editor.changeProvider'
|
||||
|
||||
},
|
||||
SqlFlavorStatusbarItem.ID,
|
||||
nls.localize('status.query.flavor', "SQL Language Flavor"),
|
||||
@@ -161,6 +161,7 @@ export class SqlFlavorStatusbarItem extends Disposable implements IWorkbenchCont
|
||||
private updateFlavorElement(text: string): void {
|
||||
const props: IStatusbarEntry = {
|
||||
text,
|
||||
ariaLabel: text,
|
||||
command: 'sql.action.editor.changeProvider'
|
||||
};
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ export class TimeElapsedStatusBarContributions extends Disposable implements IWo
|
||||
this.statusItem = this._register(
|
||||
this.statusbarService.addEntry({
|
||||
text: '',
|
||||
ariaLabel: ''
|
||||
},
|
||||
TimeElapsedStatusBarContributions.ID,
|
||||
localize('status.query.timeElapsed', "Time Elapsed"),
|
||||
@@ -89,20 +90,26 @@ export class TimeElapsedStatusBarContributions extends Disposable implements IWo
|
||||
if (runner.isExecuting) {
|
||||
this.intervalTimer.cancelAndSet(() => {
|
||||
const value = runner.queryStartTime ? Date.now() - runner.queryStartTime.getTime() : 0;
|
||||
const timeString = parseNumAsTimeString(value, false);
|
||||
this.statusItem.update({
|
||||
text: parseNumAsTimeString(value, false)
|
||||
text: timeString,
|
||||
ariaLabel: timeString
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
const value = runner.queryStartTime ? Date.now() - runner.queryStartTime.getTime() : 0;
|
||||
const timeString = parseNumAsTimeString(value, false);
|
||||
this.statusItem.update({
|
||||
text: parseNumAsTimeString(value, false)
|
||||
text: timeString,
|
||||
ariaLabel: timeString
|
||||
});
|
||||
} else {
|
||||
const value = runner.queryStartTime && runner.queryEndTime
|
||||
? runner.queryEndTime.getTime() - runner.queryStartTime.getTime() : 0;
|
||||
const timeString = parseNumAsTimeString(value, false);
|
||||
this.statusItem.update({
|
||||
text: parseNumAsTimeString(value, false)
|
||||
text: timeString,
|
||||
ariaLabel: timeString
|
||||
});
|
||||
}
|
||||
this.show();
|
||||
@@ -126,6 +133,7 @@ export class RowCountStatusBarContributions extends Disposable implements IWorkb
|
||||
this.statusItem = this._register(
|
||||
this.statusbarService.addEntry({
|
||||
text: '',
|
||||
ariaLabel: ''
|
||||
},
|
||||
RowCountStatusBarContributions.ID,
|
||||
localize('status.query.rowCount', "Row Count"),
|
||||
@@ -191,7 +199,7 @@ export class RowCountStatusBarContributions extends Disposable implements IWorkb
|
||||
}, 0);
|
||||
}, 0);
|
||||
const text = localize('rowCount', "{0} rows", rowCount.toLocaleString());
|
||||
this.statusItem.update({ text });
|
||||
this.statusItem.update({ text, ariaLabel: text });
|
||||
this.show();
|
||||
}
|
||||
}
|
||||
@@ -211,6 +219,7 @@ export class QueryStatusStatusBarContributions extends Disposable implements IWo
|
||||
this._register(
|
||||
this.statusbarService.addEntry({
|
||||
text: localize('query.status.executing', "Executing query..."),
|
||||
ariaLabel: localize('query.status.executing', "Executing query...")
|
||||
},
|
||||
QueryStatusStatusBarContributions.ID,
|
||||
localize('status.query.status', "Execution Status"),
|
||||
|
||||
Reference in New Issue
Block a user