Query Editor Refactor (#5528)

* query editor changes

* query editor changes

* finish converting query editor

* fix merge issue

* remove unused code

* fix tests

* fix tests

* remove editor context key class

* edit tests to test input state
This commit is contained in:
Anthony Dresser
2019-05-23 11:43:59 -07:00
committed by GitHub
parent cf8f8907ee
commit 5e8a52bcc0
18 changed files with 537 additions and 1183 deletions

View File

@@ -10,9 +10,9 @@ import { IConnectionManagementService, IConnectionCompletionOptions, ConnectionT
import { QueryEditor } from 'sql/workbench/parts/query/browser/queryEditor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { IQueryModelService, IQueryEvent } from 'sql/platform/query/common/queryModel';
import { IQueryManagementService } from 'sql/platform/query/common/queryManagement';
import { IQueryModelService } from 'sql/platform/query/common/queryModel';
import * as azdata from 'azdata';
import { IQueryManagementService } from 'sql/platform/query/common/queryManagement';
@extHostNamedCustomer(SqlMainContext.MainThreadQueryEditor)
export class MainThreadQueryEditor implements MainThreadQueryEditorShape {
@@ -23,9 +23,9 @@ export class MainThreadQueryEditor implements MainThreadQueryEditorShape {
constructor(
extHostContext: IExtHostContext,
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
@IQueryManagementService private _queryManagementService: IQueryManagementService,
@IQueryModelService private _queryModelService: IQueryModelService,
@IEditorService private _editorService: IEditorService
@IEditorService private _editorService: IEditorService,
@IQueryManagementService private _queryManagementService: IQueryManagementService
) {
if (extHostContext) {
this._proxy = extHostContext.getProxy(SqlExtHostContext.ExtHostQueryEditor);

View File

@@ -5,7 +5,6 @@
import { IInsightOptions, IInsight } from './interfaces';
import { Graph } from './graphInsight';
import { QueryEditor } from 'sql/workbench/parts/query/browser/queryEditor';
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
import { IInsightsConfig } from 'sql/workbench/parts/dashboard/widgets/insights/interfaces';
import { resolveCurrentDirectory, getRootPath } from 'sql/platform/node/pathUtilities';
@@ -20,6 +19,7 @@ import { URI } from 'vs/base/common/uri';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { QueryInput } from 'sql/workbench/parts/query/common/queryInput';
export interface IChartActionContext {
options: IInsightOptions;
@@ -87,10 +87,9 @@ export class CreateInsightAction extends Action {
}
private getActiveUriString(): string {
let editor = this.editorService.activeControl;
if (editor && editor instanceof QueryEditor) {
let queryEditor: QueryEditor = editor;
return queryEditor.uri;
let editor = this.editorService.activeEditor;
if (editor instanceof QueryInput) {
return editor.uri;
}
return undefined;
}
@@ -203,10 +202,9 @@ export class SaveImageAction extends Action {
}
private getActiveUriString(): string {
let editor = this.editorService.activeControl;
if (editor && editor instanceof QueryEditor) {
let queryEditor: QueryEditor = editor;
return queryEditor.uri;
let editor = this.editorService.activeEditor;
if (editor instanceof QueryInput) {
return editor.uri;
}
return undefined;
}

View File

@@ -205,12 +205,8 @@ export class ChartDataAction extends Action {
}
public run(context: IGridActionContext): Promise<boolean> {
let activeEditor = this.editorService.activeControl;
if (activeEditor instanceof QueryEditor) {
activeEditor.resultsEditor.chart({ batchId: context.batchId, resultId: context.resultId });
return Promise.resolve(true);
} else {
return Promise.resolve(false);
}
const activeEditor = this.editorService.activeControl as QueryEditor;
activeEditor.chart({ batchId: context.batchId, resultId: context.resultId });
return Promise.resolve(true);
}
}

View File

@@ -7,7 +7,7 @@ import { Dimension } from 'vs/base/browser/dom';
import { Disposable } from 'vs/base/common/lifecycle';
import { Event, Emitter } from 'vs/base/common/event';
import {
IHorizontalSashLayoutProvider, IVerticalSashLayoutProvider,
IHorizontalSashLayoutProvider,
ISashEvent, Orientation, Sash
} from 'vs/base/browser/ui/sash/sash';
// There is no need to import the sash CSS - 'vs/base/browser/ui/sash/sash' already includes it
@@ -40,121 +40,6 @@ export interface IFlexibleSash {
onPositionChange: Event<number>;
}
/**
* A simple Vertical Sash that computes the position of the sash when it is moved between the given dimension.
* Triggers onPositionChange event when the position is changed. Implements IFlexibleSash to enable classes to be
* agnostic of the fact that this sash is vertical.
*/
export class VerticalFlexibleSash extends Disposable implements IVerticalSashLayoutProvider, IFlexibleSash {
private sash: Sash;
private ratio: number;
private startPosition: number;
private position: number;
private dimension: Dimension;
private top: number;
private _onPositionChange: Emitter<number> = new Emitter<number>();
public get onPositionChange(): Event<number> { return this._onPositionChange.event; }
constructor(container: HTMLElement, private minWidth: number) {
super();
this.ratio = 0.5;
this.top = 0;
this.sash = new Sash(container, this);
this._register(this.sash.onDidStart(() => this.onSashDragStart()));
this._register(this.sash.onDidChange((e: ISashEvent) => this.onSashDrag(e)));
this._register(this.sash.onDidEnd(() => this.onSashDragEnd()));
this._register(this.sash.onDidReset(() => this.onSashReset()));
}
public getSplitPoint(): number {
return this.getVerticalSashLeft();
}
public layout(): void {
this.sash.layout();
}
public show(): void {
this.sash.show();
}
public hide(): void {
this.sash.hide();
}
public getVerticalSashTop(): number {
return this.top;
}
public getVerticalSashLeft(): number {
return this.position;
}
public getVerticalSashHeight(): number {
return this.dimension.height;
}
public setDimenesion(dimension: Dimension) {
this.dimension = dimension;
this.compute(this.ratio);
}
public setEdge(edge: number) {
this.top = edge;
}
private onSashDragStart(): void {
this.startPosition = this.position;
}
private onSashDrag(e: ISashEvent): void {
this.compute((this.startPosition + (e.currentX - e.startX)) / this.dimension.width);
}
private compute(ratio: number) {
this.computeSashPosition(ratio);
this.ratio = this.position / this.dimension.width;
this._onPositionChange.fire(this.position);
}
private onSashDragEnd(): void {
this.sash.layout();
}
private onSashReset(): void {
this.ratio = 0.5;
this._onPositionChange.fire(this.position);
this.sash.layout();
}
private computeSashPosition(sashRatio: number = this.ratio) {
let contentWidth = this.dimension.width;
let sashPosition = Math.floor((sashRatio || 0.5) * contentWidth);
let midPoint = Math.floor(0.5 * contentWidth);
if (contentWidth > this.minWidth * 2) {
if (sashPosition < this.minWidth) {
sashPosition = this.minWidth;
}
if (sashPosition > contentWidth - this.minWidth) {
sashPosition = contentWidth - this.minWidth;
}
} else {
sashPosition = midPoint;
}
if (this.position !== sashPosition) {
this.position = sashPosition;
this.sash.layout();
}
}
}
/**
* A simple Horizontal Sash that computes the position of the sash when it is moved between the given dimension.
* Triggers onPositionChange event when the position is changed. Implements IFlexibleSash to enable classes to be
@@ -269,4 +154,4 @@ export class HorizontalFlexibleSash extends Disposable implements IHorizontalSas
this.sash.layout();
}
}
}
}

View File

@@ -20,14 +20,15 @@ import * as ConnectionConstants from 'sql/platform/connection/common/constants';
import { EditDataEditor } from 'sql/workbench/parts/editData/browser/editDataEditor';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { QueryInput } from 'sql/workbench/parts/query/common/queryInput';
const singleQuote = '\'';
function isConnected(editor: QueryEditor, connectionManagementService: IConnectionManagementService): boolean {
if (!editor || !editor.currentQueryInput) {
if (!editor || !editor.input) {
return false;
}
return connectionManagementService.isConnected(editor.currentQueryInput.uri);
return connectionManagementService.isConnected(editor.input.uri);
}
function runActionOnActiveQueryEditor(editorService: IEditorService, action: (QueryEditor) => void): void {
@@ -71,10 +72,9 @@ export class FocusOnCurrentQueryKeyboardAction extends Action {
}
public run(): Promise<void> {
let editor = this._editorService.activeControl;
if (editor && editor instanceof QueryEditor) {
let queryEditor: QueryEditor = editor;
queryEditor.focus();
const editor = this._editorService.activeControl;
if (editor instanceof QueryEditor) {
editor.focus();
}
return Promise.resolve(null);
}
@@ -98,10 +98,9 @@ export class RunQueryKeyboardAction extends Action {
}
public run(): Promise<void> {
let editor = this._editorService.activeControl;
if (editor && (editor instanceof QueryEditor || editor instanceof EditDataEditor)) {
let queryEditor: QueryEditor | EditDataEditor = editor;
queryEditor.runQuery();
const editor = this._editorService.activeControl;
if (editor instanceof QueryEditor || editor instanceof EditDataEditor) {
editor.runQuery();
}
return Promise.resolve(null);
}
@@ -124,10 +123,9 @@ export class RunCurrentQueryKeyboardAction extends Action {
}
public run(): Promise<void> {
let editor = this._editorService.activeControl;
if (editor && editor instanceof QueryEditor) {
let queryEditor: QueryEditor = editor;
queryEditor.runCurrentQuery();
const editor = this._editorService.activeControl;
if (editor instanceof QueryEditor) {
editor.runCurrentQuery();
}
return Promise.resolve(null);
}
@@ -147,10 +145,9 @@ export class RunCurrentQueryWithActualPlanKeyboardAction extends Action {
}
public run(): Promise<void> {
let editor = this._editorService.activeControl;
if (editor && editor instanceof QueryEditor) {
let queryEditor: QueryEditor = editor;
queryEditor.runCurrentQueryWithActualPlan();
const editor = this._editorService.activeControl;
if (editor instanceof QueryEditor) {
editor.runCurrentQueryWithActualPlan();
}
return Promise.resolve(null);
}
@@ -174,10 +171,9 @@ export class CancelQueryKeyboardAction extends Action {
}
public run(): Promise<void> {
let editor = this._editorService.activeControl;
if (editor && (editor instanceof QueryEditor || editor instanceof EditDataEditor)) {
let queryEditor: QueryEditor | EditDataEditor = editor;
queryEditor.cancelQuery();
const editor = this._editorService.activeControl;
if (editor instanceof QueryEditor || editor instanceof EditDataEditor) {
editor.cancelQuery();
}
return Promise.resolve(null);
}
@@ -193,17 +189,17 @@ export class RefreshIntellisenseKeyboardAction extends Action {
constructor(
id: string,
label: string,
@IEditorService private _editorService: IEditorService
@IConnectionManagementService private connectionManagementService: IConnectionManagementService,
@IEditorService private editorService: IEditorService
) {
super(id, label);
this.enabled = true;
}
public run(): Promise<void> {
let editor = this._editorService.activeControl;
if (editor && editor instanceof QueryEditor) {
let queryEditor: QueryEditor = editor;
queryEditor.rebuildIntelliSenseCache();
const editor = this.editorService.activeEditor;
if (editor instanceof QueryInput) {
this.connectionManagementService.rebuildIntelliSenseCache(editor.uri);
}
return Promise.resolve(null);
}
@@ -227,10 +223,9 @@ export class ToggleQueryResultsKeyboardAction extends Action {
}
public run(): Promise<void> {
let editor = this._editorService.activeControl;
if (editor && editor instanceof QueryEditor) {
let queryEditor: QueryEditor = editor;
queryEditor.toggleResultsEditorVisibility();
const editor = this._editorService.activeControl;
if (editor instanceof QueryEditor) {
editor.toggleResultsEditorVisibility();
}
return Promise.resolve(null);
}
@@ -243,18 +238,18 @@ export class RunQueryShortcutAction extends Action {
public static ID = 'runQueryShortcutAction';
constructor(
@IEditorService private _editorService: IEditorService,
@IQueryModelService protected _queryModelService: IQueryModelService,
@IQueryManagementService private _queryManagementService: IQueryManagementService,
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
@IConfigurationService private _workspaceConfigurationService: IConfigurationService
@IEditorService private readonly editorService: IEditorService,
@IQueryModelService protected readonly queryModelService: IQueryModelService,
@IQueryManagementService private readonly queryManagementService: IQueryManagementService,
@IConnectionManagementService private readonly connectionManagementService: IConnectionManagementService,
@IConfigurationService private readonly configurationService: IConfigurationService
) {
super(RunQueryShortcutAction.ID);
}
public run(index: number): Promise<void> {
let promise: Thenable<void> = Promise.resolve(null);
runActionOnActiveQueryEditor(this._editorService, (editor) => {
runActionOnActiveQueryEditor(this.editorService, (editor) => {
promise = this.runQueryShortcut(editor, index);
});
return new Promise((resolve, reject) => {
@@ -273,7 +268,7 @@ export class RunQueryShortcutAction extends Action {
throw new Error(nls.localize('queryShortcutNoEditor', 'Editor parameter is required for a shortcut to be executed'));
}
if (isConnected(editor, this._connectionManagementService)) {
if (isConnected(editor, this.connectionManagementService)) {
let shortcutText = this.getShortcutText(shortcutIndex);
if (!shortcutText.trim()) {
// no point going further
@@ -285,7 +280,7 @@ export class RunQueryShortcutAction extends Action {
let parameterText: string = editor.getSelectionText();
return this.escapeStringParamIfNeeded(editor, shortcutText, parameterText).then((escapedParam) => {
let queryString = `${shortcutText} ${escapedParam}`;
editor.currentQueryInput.runQueryString(queryString);
editor.input.runQueryString(queryString);
}).then(success => null, err => {
// swallow errors for now
return null;
@@ -297,7 +292,7 @@ export class RunQueryShortcutAction extends Action {
private getShortcutText(shortcutIndex: number) {
let shortcutSetting = Constants.shortcutStart + shortcutIndex;
let querySettings = WorkbenchUtils.getSqlConfigSection(this._workspaceConfigurationService, Constants.querySection);
let querySettings = WorkbenchUtils.getSqlConfigSection(this.configurationService, Constants.querySection);
let shortcutText = querySettings[shortcutSetting];
return shortcutText;
}
@@ -307,7 +302,7 @@ export class RunQueryShortcutAction extends Action {
if (this.canQueryProcMetadata(editor)) {
let dbName = this.getDatabaseName(editor);
let query = `exec dbo.sp_sproc_columns @procedure_name = N'${escapeSqlString(shortcutText, singleQuote)}', @procedure_owner = null, @procedure_qualifier = N'${escapeSqlString(dbName, singleQuote)}'`;
return this._queryManagementService.runQueryAndReturn(editor.uri, query)
return this.queryManagementService.runQueryAndReturn(editor.input.uri, query)
.then(result => {
switch (this.isProcWithSingleArgument(result)) {
case 1:
@@ -377,12 +372,12 @@ export class RunQueryShortcutAction extends Action {
}
private canQueryProcMetadata(editor: QueryEditor): boolean {
let info = this._connectionManagementService.getConnectionInfo(editor.uri);
let info = this.connectionManagementService.getConnectionInfo(editor.input.uri);
return (info && info.providerId === ConnectionConstants.mssqlProviderName);
}
private getDatabaseName(editor: QueryEditor): string {
let info = this._connectionManagementService.getConnectionInfo(editor.uri);
let info = this.connectionManagementService.getConnectionInfo(editor.input.uri);
return info.connectionProfile.databaseName;
}
}
@@ -398,39 +393,38 @@ export class ParseSyntaxAction extends Action {
constructor(
id: string,
label: string,
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
@IQueryManagementService private _queryManagementService: IQueryManagementService,
@IEditorService private _editorService: IEditorService,
@INotificationService private _notificationService: INotificationService
@IConnectionManagementService private readonly connectionManagementService: IConnectionManagementService,
@IQueryManagementService private readonly queryManagementService: IQueryManagementService,
@IEditorService private readonly editorService: IEditorService,
@INotificationService private readonly notificationService: INotificationService
) {
super(id, label);
this.enabled = true;
}
public run(): Promise<void> {
let editor = this._editorService.activeControl;
if (editor && editor instanceof QueryEditor) {
let queryEditor: QueryEditor = editor;
if (!queryEditor.isSelectionEmpty()) {
if (this.isConnected(queryEditor)) {
let text = queryEditor.getSelectionText();
const editor = this.editorService.activeControl;
if (editor instanceof QueryEditor) {
if (!editor.isSelectionEmpty()) {
if (this.isConnected(editor)) {
let text = editor.getSelectionText();
if (text === '') {
text = queryEditor.getAllText();
text = editor.getAllText();
}
this._queryManagementService.parseSyntax(queryEditor.connectedUri, text).then(result => {
this.queryManagementService.parseSyntax(editor.input.uri, text).then(result => {
if (result && result.parseable) {
this._notificationService.notify({
this.notificationService.notify({
severity: Severity.Info,
message: nls.localize('queryActions.parseSyntaxSuccess', 'Commands completed successfully')
});
} else if (result && result.errors.length > 0) {
let errorMessage = nls.localize('queryActions.parseSyntaxFailure', 'Command failed: ');
this._notificationService.error(`${errorMessage}${result.errors[0]}`);
this.notificationService.error(`${errorMessage}${result.errors[0]}`);
}
});
} else {
this._notificationService.notify({
this.notificationService.notify({
severity: Severity.Error,
message: nls.localize('queryActions.notConnected', 'Please connect to a server')
});
@@ -447,9 +441,9 @@ export class ParseSyntaxAction extends Action {
* Public for testing only.
*/
private isConnected(editor: QueryEditor): boolean {
if (!editor || !editor.currentQueryInput) {
if (!editor || !editor.input) {
return false;
}
return this._connectionManagementService.isConnected(editor.currentQueryInput.uri);
return this.connectionManagementService.isConnected(editor.input.uri);
}
}

View File

@@ -37,8 +37,8 @@ export abstract class QueryTaskbarAction extends Action {
private _classes: string[];
constructor(
protected _connectionManagementService: IConnectionManagementService,
protected editor: QueryEditor,
protected readonly connectionManagementService: IConnectionManagementService,
protected readonly editor: QueryEditor,
id: string,
enabledClass: string
) {
@@ -75,10 +75,10 @@ export abstract class QueryTaskbarAction extends Action {
* Public for testing only.
*/
public isConnected(editor: QueryEditor): boolean {
if (!editor || !editor.currentQueryInput) {
if (!editor || !editor.input) {
return false;
}
return this._connectionManagementService.isConnected(editor.currentQueryInput.uri);
return this.connectionManagementService.isConnected(editor.input.uri);
}
/**
@@ -87,12 +87,12 @@ export abstract class QueryTaskbarAction extends Action {
*/
protected connectEditor(editor: QueryEditor, runQueryOnCompletion?: RunQueryOnConnectionMode, selection?: ISelectionData): void {
let params: INewConnectionParams = {
input: editor.currentQueryInput,
input: editor.input,
connectionType: ConnectionType.editor,
runQueryOnCompletion: runQueryOnCompletion ? runQueryOnCompletion : RunQueryOnConnectionMode.none,
querySelection: selection
};
this._connectionManagementService.showConnectionDialog(params);
this.connectionManagementService.showConnectionDialog(params);
}
}
@@ -106,7 +106,7 @@ export class RunQueryAction extends QueryTaskbarAction {
constructor(
editor: QueryEditor,
@IQueryModelService protected _queryModelService: IQueryModelService,
@IQueryModelService protected readonly queryModelService: IQueryModelService,
@IConnectionManagementService connectionManagementService: IConnectionManagementService
) {
super(connectionManagementService, editor, RunQueryAction.ID, RunQueryAction.EnabledClass);
@@ -151,11 +151,11 @@ export class RunQueryAction extends QueryTaskbarAction {
// otherwise, either run the statement or the script depending on parameter
let selection: ISelectionData = editor.getSelection(false);
if (runCurrentStatement && selection && this.isCursorPosition(selection)) {
editor.currentQueryInput.runQueryStatement(selection);
editor.input.runQueryStatement(selection);
} else {
// get the selection again this time with trimming
selection = editor.getSelection();
editor.currentQueryInput.runQuery(selection);
editor.input.runQuery(selection);
}
}
}
@@ -176,7 +176,7 @@ export class CancelQueryAction extends QueryTaskbarAction {
constructor(
editor: QueryEditor,
@IQueryModelService private _queryModelService: IQueryModelService,
@IQueryModelService private readonly queryModelService: IQueryModelService,
@IConnectionManagementService connectionManagementService: IConnectionManagementService
) {
super(connectionManagementService, editor, CancelQueryAction.ID, CancelQueryAction.EnabledClass);
@@ -186,7 +186,7 @@ export class CancelQueryAction extends QueryTaskbarAction {
public run(): Promise<void> {
if (this.isConnected(this.editor)) {
this._queryModelService.cancelQuery(this.editor.currentQueryInput.uri);
this.queryModelService.cancelQuery(this.editor.input.uri);
}
return Promise.resolve(null);
}
@@ -202,7 +202,6 @@ export class EstimatedQueryPlanAction extends QueryTaskbarAction {
constructor(
editor: QueryEditor,
@IQueryModelService private _queryModelService: IQueryModelService,
@IConnectionManagementService connectionManagementService: IConnectionManagementService
) {
super(connectionManagementService, editor, EstimatedQueryPlanAction.ID, EstimatedQueryPlanAction.EnabledClass);
@@ -229,7 +228,7 @@ export class EstimatedQueryPlanAction extends QueryTaskbarAction {
}
if (this.isConnected(editor)) {
editor.currentQueryInput.runQuery(editor.getSelection(), {
editor.input.runQuery(editor.getSelection(), {
displayEstimatedQueryPlan: true
});
}
@@ -242,7 +241,6 @@ export class ActualQueryPlanAction extends QueryTaskbarAction {
constructor(
editor: QueryEditor,
@IQueryModelService private _queryModelService: IQueryModelService,
@IConnectionManagementService connectionManagementService: IConnectionManagementService
) {
super(connectionManagementService, editor, ActualQueryPlanAction.ID, ActualQueryPlanAction.EnabledClass);
@@ -273,7 +271,7 @@ export class ActualQueryPlanAction extends QueryTaskbarAction {
if (!selection) {
selection = editor.getAllSelection();
}
editor.currentQueryInput.runQuery(selection, {
editor.input.runQuery(selection, {
displayActualQueryPlan: true
});
}
@@ -299,7 +297,7 @@ export class DisconnectDatabaseAction extends QueryTaskbarAction {
public run(): Promise<void> {
// Call disconnectEditor regardless of the connection state and let the ConnectionManagementService
// determine if we need to disconnect, cancel an in-progress conneciton, or do nothing
this._connectionManagementService.disconnectEditor(this.editor.currentQueryInput);
this.connectionManagementService.disconnectEditor(this.editor.input);
return Promise.resolve(null);
}
}
@@ -350,22 +348,14 @@ export class ToggleConnectDatabaseAction extends QueryTaskbarAction {
public static DisconnectClass = 'disconnect';
public static ID = 'toggleConnectDatabaseAction';
private _connected: boolean;
private _connectLabel: string;
private _disconnectLabel: string;
private _connectLabel = nls.localize('connectDatabaseLabel', 'Connect');
private _disconnectLabel = nls.localize('disconnectDatabaseLabel', 'Disconnect');
constructor(
editor: QueryEditor,
isConnected: boolean,
private _connected: boolean,
@IConnectionManagementService connectionManagementService: IConnectionManagementService
) {
let enabledClass: string;
super(connectionManagementService, editor, ToggleConnectDatabaseAction.ID, enabledClass);
this._connectLabel = nls.localize('connectDatabaseLabel', 'Connect');
this._disconnectLabel = nls.localize('disconnectDatabaseLabel', 'Disconnect');
this.connected = isConnected;
super(connectionManagementService, editor, ToggleConnectDatabaseAction.ID, undefined);
}
public get connected(): boolean {
@@ -393,7 +383,7 @@ export class ToggleConnectDatabaseAction extends QueryTaskbarAction {
if (this.connected) {
// Call disconnectEditor regardless of the connection state and let the ConnectionManagementService
// determine if we need to disconnect, cancel an in-progress connection, or do nothing
this._connectionManagementService.disconnectEditor(this.editor.currentQueryInput);
this.connectionManagementService.disconnectEditor(this.editor.input);
} else {
this.connectEditor(this.editor);
}
@@ -444,14 +434,14 @@ export class ListDatabasesActionItem implements IActionViewItem {
// CONSTRUCTOR /////////////////////////////////////////////////////////
constructor(
private _editor: QueryEditor,
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
@INotificationService private _notificationService: INotificationService,
@IContextViewService contextViewProvider: IContextViewService,
@IConfigurationService private readonly _configurationService: IConfigurationService
@IConnectionManagementService private readonly connectionManagementService: IConnectionManagementService,
@INotificationService private readonly notificationService: INotificationService,
@IConfigurationService private readonly configurationService: IConfigurationService
) {
this._toDispose = [];
this._databaseListDropdown = $('.databaseListDropdown');
this._isInAccessibilityMode = this._configurationService.getValue('editor.accessibilitySupport') === 'on';
this._isInAccessibilityMode = this.configurationService.getValue('editor.accessibilitySupport') === 'on';
if (this._isInAccessibilityMode) {
this._databaseSelectBox = new SelectBox([this._selectDatabaseString], this._selectDatabaseString, contextViewProvider, undefined, { ariaLabel: this._selectDatabaseString });
@@ -467,12 +457,11 @@ export class ListDatabasesActionItem implements IActionViewItem {
actionLabel: nls.localize('listDatabases.toggleDatabaseNameDropdown', 'Select Database Toggle Dropdown')
});
this._dropdown.onValueChange(s => this.databaseSelected(s));
this._toDispose.push(this._dropdown.onFocus(() => { self.onDropdownFocus(); }));
this._toDispose.push(this._dropdown.onFocus(() => this.onDropdownFocus()));
}
// Register event handlers
let self = this;
this._toDispose.push(this._connectionManagementService.onConnectionChanged(params => { self.onConnectionChanged(params); }));
this._toDispose.push(this.connectionManagementService.onConnectionChanged(params => this.onConnectionChanged(params)));
}
// PUBLIC METHODS //////////////////////////////////////////////////////
@@ -546,22 +535,22 @@ export class ListDatabasesActionItem implements IActionViewItem {
// PRIVATE HELPERS /////////////////////////////////////////////////////
private databaseSelected(dbName: string): void {
let uri = this._editor.connectedUri;
let uri = this._editor.input.uri;
if (!uri) {
return;
}
let profile = this._connectionManagementService.getConnectionProfile(uri);
let profile = this.connectionManagementService.getConnectionProfile(uri);
if (!profile) {
return;
}
this._connectionManagementService.changeDatabase(this._editor.uri, dbName)
this.connectionManagementService.changeDatabase(this._editor.input.uri, dbName)
.then(
result => {
if (!result) {
this.resetDatabaseName();
this._notificationService.notify({
this.notificationService.notify({
severity: Severity.Error,
message: nls.localize('changeDatabase.failed', "Failed to change database")
});
@@ -569,7 +558,7 @@ export class ListDatabasesActionItem implements IActionViewItem {
},
error => {
this.resetDatabaseName();
this._notificationService.notify({
this.notificationService.notify({
severity: Severity.Error,
message: nls.localize('changeDatabase.failedWithError', "Failed to change database {0}", error)
});
@@ -577,9 +566,9 @@ export class ListDatabasesActionItem implements IActionViewItem {
}
private getCurrentDatabaseName() {
let uri = this._editor.connectedUri;
let uri = this._editor.input.uri;
if (uri) {
let profile = this._connectionManagementService.getConnectionProfile(uri);
let profile = this.connectionManagementService.getConnectionProfile(uri);
if (profile) {
return profile.databaseName;
}
@@ -600,7 +589,7 @@ export class ListDatabasesActionItem implements IActionViewItem {
return;
}
let uri = this._editor.connectedUri;
let uri = this._editor.input.uri;
if (uri !== connParams.connectionUri) {
return;
}
@@ -609,14 +598,12 @@ export class ListDatabasesActionItem implements IActionViewItem {
}
private onDropdownFocus(): void {
let self = this;
let uri = self._editor.connectedUri;
let uri = this._editor.input.uri;
if (!uri) {
return;
}
self._connectionManagementService.listDatabases(uri)
this.connectionManagementService.listDatabases(uri)
.then(result => {
if (result && result.databaseNames) {
this._dropdown.values = result.databaseNames;
@@ -630,12 +617,11 @@ export class ListDatabasesActionItem implements IActionViewItem {
if (this._isInAccessibilityMode) {
this._databaseSelectBox.enable();
let self = this;
let uri = self._editor.connectedUri;
let uri = this._editor.input.uri;
if (!uri) {
return;
}
self._connectionManagementService.listDatabases(uri)
this.connectionManagementService.listDatabases(uri)
.then(result => {
if (result && result.databaseNames) {
this._databaseSelectBox.setOptions(result.databaseNames);

File diff suppressed because it is too large Load Diff

View File

@@ -16,7 +16,6 @@ import * as types from 'vs/base/common/types';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { QueryResultsInput } from 'sql/workbench/parts/query/common/queryResultsInput';
import { IQueryModelService } from 'sql/platform/query/common/queryModel';
import { QueryResultsView } from 'sql/workbench/parts/query/browser/queryResultsView';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IStorageService } from 'vs/platform/storage/common/storage';
@@ -95,7 +94,6 @@ export class QueryResultsEditor extends BaseEditor {
constructor(
@ITelemetryService telemetryService: ITelemetryService,
@IThemeService themeService: IThemeService,
@IQueryModelService private _queryModelService: IQueryModelService,
@IConfigurationService private _configurationService: IConfigurationService,
@IInstantiationService private _instantiationService: IInstantiationService,
@IStorageService storageService: IStorageService

View File

@@ -8,19 +8,21 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Event, Emitter } from 'vs/base/common/event';
import { URI } from 'vs/base/common/uri';
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
import { EditorInput, EditorModel, ConfirmResult, EncodingMode, IEncodingSupport } from 'vs/workbench/common/editor';
import { EditorInput, ConfirmResult, EncodingMode, IEncodingSupport } from 'vs/workbench/common/editor';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IEditorViewState } from 'vs/editor/common/editorCommon';
import { IConnectionManagementService, IConnectableInput, INewConnectionParams, RunQueryOnConnectionMode } from 'sql/platform/connection/common/connectionManagement';
import { QueryResultsInput } from 'sql/workbench/parts/query/common/queryResultsInput';
import { IQueryModelService } from 'sql/platform/query/common/queryModel';
import { IQueryEditorService } from 'sql/workbench/services/queryEditor/common/queryEditorService';
import { ISelectionData, ExecutionPlanOptions } from 'azdata';
import { UntitledEditorModel } from 'vs/workbench/common/editor/untitledEditorModel';
import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
const MAX_SIZE = 13;
type PublicPart<T> = { [K in keyof T]: T[K] };
function trimTitle(title: string): string {
const length = title.length;
const diff = length - MAX_SIZE;
@@ -33,30 +35,81 @@ function trimTitle(title: string): string {
}
}
export interface IQueryEditorStateChange {
connectedChange?: boolean;
resultsVisibleChange?: boolean;
executingChange?: boolean;
connectingChange?: boolean;
}
export class QueryEditorState {
private _connected = false;
private _resultsVisible = false;
private _executing = false;
private _connecting = false;
private _onChange = new Emitter<IQueryEditorStateChange>();
public onChange = this._onChange.event;
public set connected(val: boolean) {
if (val !== this._connected) {
this._connected = val;
this._onChange.fire({ connectedChange: true });
}
}
public get connected(): boolean {
return this._connected;
}
public set connecting(val: boolean) {
if (val !== this._connecting) {
this._connecting = val;
this._onChange.fire({ connectingChange: true });
}
}
public get connecting(): boolean {
return this._connecting;
}
public set resultsVisible(val: boolean) {
if (val !== this._resultsVisible) {
this._resultsVisible = val;
this._onChange.fire({ resultsVisibleChange: true });
}
}
public get resultsVisible(): boolean {
return this._resultsVisible;
}
public set executing(val: boolean) {
if (val !== this._executing) {
this._executing = val;
this._onChange.fire({ executingChange: true });
}
}
public get executing(): boolean {
return this._executing;
}
}
/**
* Input for the QueryEditor. This input is simply a wrapper around a QueryResultsInput for the QueryResultsEditor
* and a UntitledEditorInput for the SQL File Editor.
*/
export class QueryInput extends EditorInput implements IEncodingSupport, IConnectableInput, IDisposable {
export class QueryInput extends EditorInput implements IEncodingSupport, IConnectableInput, PublicPart<UntitledEditorInput>, IDisposable {
public static ID: string = 'workbench.editorinputs.queryInput';
public static SCHEMA: string = 'sql';
private _runQueryEnabled: boolean;
private _cancelQueryEnabled: boolean;
private _connectEnabled: boolean;
private _disconnectEnabled: boolean;
private _changeConnectionEnabled: boolean;
private _listDatabasesConnected: boolean;
private _state = new QueryEditorState();
public get state(): QueryEditorState { return this._state; }
private _updateTaskbar: Emitter<void>;
private _showQueryResultsEditor: Emitter<void>;
private _updateSelection: Emitter<ISelectionData>;
private _currentEventCallbacks: IDisposable[];
public savedViewState: IEditorViewState;
constructor(
private _description: string,
private _sql: UntitledEditorInput,
@@ -64,16 +117,12 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec
private _connectionProviderName: string,
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
@IQueryModelService private _queryModelService: IQueryModelService,
@IQueryEditorService private _queryEditorService: IQueryEditorService,
@IConfigurationService private _configurationService: IConfigurationService
) {
super();
this._updateTaskbar = new Emitter<void>();
this._showQueryResultsEditor = new Emitter<void>();
this._updateSelection = new Emitter<ISelectionData>();
this._toDispose = [];
this._currentEventCallbacks = [];
// re-emit sql editor events through this editor if it exists
if (this._sql) {
this._toDispose.push(this._sql.onDidChangeDirty(() => this._onDidChangeDirty.fire()));
@@ -130,17 +179,6 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec
public get uri(): string { return this.getResource().toString(); }
public get sql(): UntitledEditorInput { return this._sql; }
public get results(): QueryResultsInput { return this._results; }
public get updateTaskbarEvent(): Event<void> { return this._updateTaskbar.event; }
public get showQueryResultsEditorEvent(): Event<void> { return this._showQueryResultsEditor.event; }
public get updateSelectionEvent(): Event<ISelectionData> { return this._updateSelection.event; }
public get runQueryEnabled(): boolean { return this._runQueryEnabled; }
public get cancelQueryEnabled(): boolean { return this._cancelQueryEnabled; }
public get connectEnabled(): boolean { return this._connectEnabled; }
public get disconnectEnabled(): boolean { return this._disconnectEnabled; }
public get changeConnectionEnabled(): boolean { return this._changeConnectionEnabled; }
public get listDatabasesConnected(): boolean { return this._listDatabasesConnected; }
public getQueryResultsInputResource(): string { return this._results.uri; }
public showQueryResultsEditor(): void { this._showQueryResultsEditor.fire(); }
public updateSelection(selection: ISelectionData): void { this._updateSelection.fire(selection); }
public getTypeId(): string { return QueryInput.ID; }
// Description is shown beside the tab name in the combobox of open editors
@@ -163,7 +201,7 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec
// Forwarding resource functions to the inline sql file editor
public get onDidModelChangeContent(): Event<void> { return this._sql.onDidModelChangeContent; }
public get onDidModelChangeEncoding(): Event<void> { return this._sql.onDidModelChangeEncoding; }
public resolve(refresh?: boolean): Promise<EditorModel> { return this._sql.resolve(); }
public resolve(): Promise<UntitledEditorModel & IResolvedTextEditorModel> { return this._sql.resolve(); }
public save(): Promise<boolean> { return this._sql.save(); }
public isDirty(): boolean { return this._sql.isDirty(); }
public confirmSave(): Promise<ConfirmResult> { return this._sql.confirmSave(); }
@@ -207,43 +245,37 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec
// State update funtions
public runQuery(selection: ISelectionData, executePlanOptions?: ExecutionPlanOptions): void {
this._queryModelService.runQuery(this.uri, selection, this, executePlanOptions);
this.showQueryResultsEditor();
this.state.executing = true;
}
public runQueryStatement(selection: ISelectionData): void {
this._queryModelService.runQueryStatement(this.uri, selection, this);
this.showQueryResultsEditor();
this.state.executing = true;
}
public runQueryString(text: string): void {
this._queryModelService.runQueryString(this.uri, text, this);
this.showQueryResultsEditor();
this.state.executing = true;
}
public onConnectStart(): void {
this._runQueryEnabled = false;
this._cancelQueryEnabled = false;
this._connectEnabled = false;
this._disconnectEnabled = true;
this._changeConnectionEnabled = false;
this._listDatabasesConnected = false;
this._updateTaskbar.fire();
this.state.connecting = true;
this.state.connected = false;
}
public onConnectReject(): void {
this.onDisconnect();
this._updateTaskbar.fire();
this.state.connecting = false;
this.state.connected = false;
}
public onConnectCanceled(): void {
this.state.connecting = false;
this.state.connected = false;
}
public onConnectSuccess(params?: INewConnectionParams): void {
this._runQueryEnabled = true;
this._connectEnabled = false;
this._disconnectEnabled = true;
this._changeConnectionEnabled = true;
this._listDatabasesConnected = true;
this.state.connected = true;
this.state.connecting = false;
let isRunningQuery = this._queryModelService.isRunningQuery(this.uri);
if (!isRunningQuery && params && params.runQueryOnCompletion) {
@@ -258,30 +290,19 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec
this.runQuery(selection, { displayActualQueryPlan: true });
}
}
this._updateTaskbar.fire();
this._onDidChangeLabel.fire();
}
public onDisconnect(): void {
this._runQueryEnabled = true;
this._cancelQueryEnabled = false;
this._connectEnabled = true;
this._disconnectEnabled = false;
this._changeConnectionEnabled = false;
this._listDatabasesConnected = false;
this._updateTaskbar.fire();
this.state.connected = false;
}
public onRunQuery(): void {
this._runQueryEnabled = false;
this._cancelQueryEnabled = true;
this._updateTaskbar.fire();
this.state.executing = true;
this.state.resultsVisible = true;
}
public onQueryComplete(): void {
this._runQueryEnabled = true;
this._cancelQueryEnabled = false;
this._updateTaskbar.fire();
this.state.executing = false;
}
// Clean up functions
@@ -289,7 +310,6 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec
this._sql.dispose();
this._results.dispose();
this._toDispose = dispose(this._toDispose);
this._currentEventCallbacks = dispose(this._currentEventCallbacks);
super.dispose();
}
@@ -301,18 +321,6 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec
this._results.close();
}
/**
* Unsubscribe all events in _currentEventCallbacks and set the new callbacks
* to be unsubscribed the next time this method is called.
*
* This method is used to ensure that all callbacks point to the current QueryEditor
* in the case that this QueryInput is moved between different QueryEditors.
*/
public setEventCallbacks(callbacks: IDisposable[]): void {
this._currentEventCallbacks = dispose(this._currentEventCallbacks);
this._currentEventCallbacks = callbacks;
}
/**
* Get the color that should be displayed
*/

View File

@@ -142,7 +142,7 @@ export class CommandLineService implements ICommandLineProcessing {
let activeEditor = this._editorService.editors.filter(v => v.getResource().toString() === uriString).pop();
if (activeEditor) {
let queryInput = activeEditor as QueryInput;
if (queryInput && queryInput.connectEnabled) {
if (queryInput && queryInput.state.connected) {
let options: IConnectionCompletionOptions = {
params: { connectionType: ConnectionType.editor, runQueryOnCompletion: RunQueryOnConnectionMode.none, input: queryInput },
saveTheConnection: false,