mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-20 09:35:38 -05:00
Time elapsed status item (#3006)
* added time elapsed status item * add missing files
This commit is contained in:
@@ -23,9 +23,7 @@ export class ConnectionStatusbarItem implements IStatusbarItem {
|
||||
|
||||
constructor(
|
||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
|
||||
@IEditorGroupsService private _editorGroupService: IEditorGroupsService,
|
||||
@IEditorService private _editorService: EditorServiceImpl,
|
||||
@ICapabilitiesService private _capabilitiesService: ICapabilitiesService,
|
||||
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ export function parseTimeString(value: string): number | boolean {
|
||||
* @param value The number of milliseconds to convert to a timespan string
|
||||
* @returns A properly formatted timespan string.
|
||||
*/
|
||||
export function parseNumAsTimeString(value: number): string {
|
||||
export function parseNumAsTimeString(value: number, includeFraction: boolean = true): string {
|
||||
let tempVal = value;
|
||||
let h = Math.floor(tempVal / msInH);
|
||||
tempVal %= msInH;
|
||||
@@ -85,7 +85,7 @@ export function parseNumAsTimeString(value: number): string {
|
||||
|
||||
let rs = hs + ':' + ms + ':' + ss;
|
||||
|
||||
return tempVal > 0 ? rs + '.' + mss : rs;
|
||||
return tempVal > 0 && includeFraction ? rs + '.' + mss : rs;
|
||||
}
|
||||
|
||||
export function generateUri(connection: IConnectionProfile, purpose?: 'dashboard' | 'insights' | 'connection'): string {
|
||||
|
||||
@@ -9,7 +9,6 @@ import QueryRunner from 'sql/parts/query/execution/queryRunner';
|
||||
|
||||
import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar';
|
||||
import { IDisposable, combinedDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorCloseEvent } from 'vs/workbench/common/editor';
|
||||
import { append, $, hide, show } from 'vs/base/browser/dom';
|
||||
@@ -25,7 +24,6 @@ export class RowCountStatusBarItem implements IStatusbarItem {
|
||||
|
||||
constructor(
|
||||
@IEditorService private _editorService: EditorServiceImpl,
|
||||
@IEditorGroupsService private _editorGroupService: IEditorGroupsService,
|
||||
@IQueryModelService private _queryModelService: IQueryModelService
|
||||
) { }
|
||||
|
||||
@@ -36,7 +34,7 @@ export class RowCountStatusBarItem implements IStatusbarItem {
|
||||
];
|
||||
|
||||
this._element = append(container, $('.query-statusbar-group'));
|
||||
this._flavorElement = append(this._element, $('a.editor-status-selection'));
|
||||
this._flavorElement = append(this._element, $('.editor-status-selection'));
|
||||
this._flavorElement.title = nls.localize('rowStatus', "Row Count");
|
||||
hide(this._flavorElement);
|
||||
|
||||
@@ -65,11 +63,10 @@ export class RowCountStatusBarItem implements IStatusbarItem {
|
||||
if (queryRunner) {
|
||||
if (queryRunner.hasCompleted) {
|
||||
this._displayValue(queryRunner);
|
||||
} else if (queryRunner.isExecuting) {
|
||||
this.dispose = queryRunner.addListener('complete', () => {
|
||||
this._displayValue(queryRunner);
|
||||
});
|
||||
}
|
||||
this.dispose = queryRunner.onQueryEnd(e => {
|
||||
this._displayValue(queryRunner);
|
||||
});
|
||||
} else {
|
||||
this.dispose = this._queryModelService.onRunQueryComplete(e => {
|
||||
if (e === currentUri) {
|
||||
|
||||
107
src/sql/parts/query/common/timeElapsedStatus.ts
Normal file
107
src/sql/parts/query/common/timeElapsedStatus.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as WorkbenchUtils from 'sql/workbench/common/sqlWorkbenchUtils';
|
||||
import { IQueryModelService } from '../execution/queryModel';
|
||||
import QueryRunner from 'sql/parts/query/execution/queryRunner';
|
||||
import { parseNumAsTimeString } from 'sql/parts/connection/common/utils';
|
||||
|
||||
import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar';
|
||||
import { IDisposable, combinedDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorCloseEvent } from 'vs/workbench/common/editor';
|
||||
import { append, $, hide, show } from 'vs/base/browser/dom';
|
||||
import * as nls from 'vs/nls';
|
||||
import { EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { IntervalTimer } from 'vs/base/common/async';
|
||||
|
||||
export class TimeElapsedStatusBarItem implements IStatusbarItem {
|
||||
|
||||
private _element: HTMLElement;
|
||||
private _flavorElement: HTMLElement;
|
||||
|
||||
private dispose: IDisposable[] = [];
|
||||
private intervalTimer = new IntervalTimer();
|
||||
|
||||
constructor(
|
||||
@IEditorService private _editorService: EditorServiceImpl,
|
||||
@IQueryModelService private _queryModelService: IQueryModelService
|
||||
) { }
|
||||
|
||||
render(container: HTMLElement): IDisposable {
|
||||
let disposables = [
|
||||
this._editorService.onDidVisibleEditorsChange(() => this._onEditorsChanged()),
|
||||
this._editorService.onDidCloseEditor(event => this._onEditorClosed(event))
|
||||
];
|
||||
|
||||
this._element = append(container, $('.query-statusbar-group'));
|
||||
this._flavorElement = append(this._element, $('.editor-status-selection'));
|
||||
this._flavorElement.title = nls.localize('timeElapsed', "Time Elapsed");
|
||||
hide(this._flavorElement);
|
||||
|
||||
this._showStatus();
|
||||
|
||||
return combinedDisposable(disposables);
|
||||
}
|
||||
|
||||
private _onEditorsChanged() {
|
||||
this._showStatus();
|
||||
}
|
||||
|
||||
private _onEditorClosed(event: IEditorCloseEvent) {
|
||||
hide(this._flavorElement);
|
||||
}
|
||||
|
||||
// Show/hide query status for active editor
|
||||
private _showStatus(): void {
|
||||
this.intervalTimer.cancel();
|
||||
hide(this._flavorElement);
|
||||
dispose(this.dispose);
|
||||
this._flavorElement.innerText = '';
|
||||
this.dispose = [];
|
||||
let activeEditor = this._editorService.activeControl;
|
||||
if (activeEditor) {
|
||||
let currentUri = WorkbenchUtils.getEditorUri(activeEditor.input);
|
||||
if (currentUri) {
|
||||
let queryRunner = this._queryModelService.getQueryRunner(currentUri);
|
||||
if (queryRunner) {
|
||||
if (queryRunner.hasCompleted || queryRunner.isExecuting) {
|
||||
this._displayValue(queryRunner);
|
||||
}
|
||||
this.dispose.push(queryRunner.onQueryStart(e => {
|
||||
this._displayValue(queryRunner);
|
||||
}));
|
||||
this.dispose.push(queryRunner.onQueryEnd(e => {
|
||||
this._displayValue(queryRunner);
|
||||
}));
|
||||
} else {
|
||||
this.dispose.push(this._queryModelService.onRunQueryStart(e => {
|
||||
if (e === currentUri) {
|
||||
this._displayValue(this._queryModelService.getQueryRunner(currentUri));
|
||||
}
|
||||
}));
|
||||
this.dispose.push(this._queryModelService.onRunQueryComplete(e => {
|
||||
if (e === currentUri) {
|
||||
this._displayValue(this._queryModelService.getQueryRunner(currentUri));
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _displayValue(runner: QueryRunner) {
|
||||
this.intervalTimer.cancel();
|
||||
if (runner.isExecuting) {
|
||||
this.intervalTimer.cancelAndSet(() => {
|
||||
this._flavorElement.innerText = parseNumAsTimeString(Date.now() - runner.queryStartTime.getTime(), false);
|
||||
}, 1000);
|
||||
this._flavorElement.innerText = parseNumAsTimeString(Date.now() - runner.queryStartTime.getTime(), false);
|
||||
} else {
|
||||
this._flavorElement.innerText = parseNumAsTimeString(runner.queryEndTime.getTime() - runner.queryStartTime.getTime(), false);
|
||||
}
|
||||
show(this._flavorElement);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import { QueryInput } from 'sql/parts/query/common/queryInput';
|
||||
import { QueryStatusbarItem } from 'sql/parts/query/execution/queryStatus';
|
||||
import { SqlFlavorStatusbarItem } from 'sql/parts/query/common/flavorStatus';
|
||||
import { RowCountStatusBarItem } from 'sql/parts/query/common/rowCountStatus';
|
||||
import { TimeElapsedStatusBarItem } from 'sql/parts/query/common/timeElapsedStatus';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
|
||||
@@ -86,6 +87,12 @@ export class QueryModelService implements IQueryModelService {
|
||||
|
||||
// Register Statusbar items
|
||||
|
||||
(<statusbar.IStatusbarRegistry>platform.Registry.as(statusbar.Extensions.Statusbar)).registerStatusbarItem(new statusbar.StatusbarItemDescriptor(
|
||||
TimeElapsedStatusBarItem,
|
||||
statusbar.StatusbarAlignment.RIGHT,
|
||||
100 /* Should appear to the right of the SQL editor status */
|
||||
));
|
||||
|
||||
(<statusbar.IStatusbarRegistry>platform.Registry.as(statusbar.Extensions.Statusbar)).registerStatusbarItem(new statusbar.StatusbarItemDescriptor(
|
||||
RowCountStatusBarItem,
|
||||
statusbar.StatusbarAlignment.RIGHT,
|
||||
@@ -352,7 +359,7 @@ export class QueryModelService implements IQueryModelService {
|
||||
|
||||
public disposeQuery(ownerUri: string): void {
|
||||
// Get existing query runner
|
||||
let queryRunner = this.getQueryRunner(ownerUri);
|
||||
let queryRunner = this.internalGetQueryRunner(ownerUri);
|
||||
if (queryRunner) {
|
||||
queryRunner.disposeQuery();
|
||||
}
|
||||
@@ -444,7 +451,7 @@ export class QueryModelService implements IQueryModelService {
|
||||
|
||||
public disposeEdit(ownerUri: string): Thenable<void> {
|
||||
// Get existing query runner
|
||||
let queryRunner = this.getQueryRunner(ownerUri);
|
||||
let queryRunner = this.internalGetQueryRunner(ownerUri);
|
||||
if (queryRunner) {
|
||||
return queryRunner.disposeEdit(ownerUri);
|
||||
}
|
||||
@@ -453,7 +460,7 @@ export class QueryModelService implements IQueryModelService {
|
||||
|
||||
public updateCell(ownerUri: string, rowId: number, columnId: number, newValue: string): Thenable<sqlops.EditUpdateCellResult> {
|
||||
// Get existing query runner
|
||||
let queryRunner = this.getQueryRunner(ownerUri);
|
||||
let queryRunner = this.internalGetQueryRunner(ownerUri);
|
||||
if (queryRunner) {
|
||||
return queryRunner.updateCell(ownerUri, rowId, columnId, newValue).then((result) => result, error => {
|
||||
this._notificationService.notify({
|
||||
@@ -468,7 +475,7 @@ export class QueryModelService implements IQueryModelService {
|
||||
|
||||
public commitEdit(ownerUri): Thenable<void> {
|
||||
// Get existing query runner
|
||||
let queryRunner = this.getQueryRunner(ownerUri);
|
||||
let queryRunner = this.internalGetQueryRunner(ownerUri);
|
||||
if (queryRunner) {
|
||||
return queryRunner.commitEdit(ownerUri).then(() => { }, error => {
|
||||
this._notificationService.notify({
|
||||
@@ -483,7 +490,7 @@ export class QueryModelService implements IQueryModelService {
|
||||
|
||||
public createRow(ownerUri: string): Thenable<sqlops.EditCreateRowResult> {
|
||||
// Get existing query runner
|
||||
let queryRunner = this.getQueryRunner(ownerUri);
|
||||
let queryRunner = this.internalGetQueryRunner(ownerUri);
|
||||
if (queryRunner) {
|
||||
return queryRunner.createRow(ownerUri);
|
||||
}
|
||||
@@ -492,7 +499,7 @@ export class QueryModelService implements IQueryModelService {
|
||||
|
||||
public deleteRow(ownerUri: string, rowId: number): Thenable<void> {
|
||||
// Get existing query runner
|
||||
let queryRunner = this.getQueryRunner(ownerUri);
|
||||
let queryRunner = this.internalGetQueryRunner(ownerUri);
|
||||
if (queryRunner) {
|
||||
return queryRunner.deleteRow(ownerUri, rowId);
|
||||
}
|
||||
@@ -501,7 +508,7 @@ export class QueryModelService implements IQueryModelService {
|
||||
|
||||
public revertCell(ownerUri: string, rowId: number, columnId: number): Thenable<sqlops.EditRevertCellResult> {
|
||||
// Get existing query runner
|
||||
let queryRunner = this.getQueryRunner(ownerUri);
|
||||
let queryRunner = this.internalGetQueryRunner(ownerUri);
|
||||
if (queryRunner) {
|
||||
return queryRunner.revertCell(ownerUri, rowId, columnId);
|
||||
}
|
||||
@@ -510,16 +517,25 @@ export class QueryModelService implements IQueryModelService {
|
||||
|
||||
public revertRow(ownerUri: string, rowId: number): Thenable<void> {
|
||||
// Get existing query runner
|
||||
let queryRunner = this.getQueryRunner(ownerUri);
|
||||
let queryRunner = this.internalGetQueryRunner(ownerUri);
|
||||
if (queryRunner) {
|
||||
return queryRunner.revertRow(ownerUri, rowId);
|
||||
}
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
public getQueryRunner(ownerUri): QueryRunner {
|
||||
let queryRunner: QueryRunner = undefined;
|
||||
if (this._queryInfoMap.has(ownerUri)) {
|
||||
queryRunner = this._getQueryInfo(ownerUri).queryRunner;
|
||||
}
|
||||
// return undefined if not found or is already executing
|
||||
return queryRunner;
|
||||
}
|
||||
|
||||
// PRIVATE METHODS //////////////////////////////////////////////////////
|
||||
|
||||
public getQueryRunner(ownerUri): QueryRunner {
|
||||
private internalGetQueryRunner(ownerUri): QueryRunner {
|
||||
let queryRunner: QueryRunner = undefined;
|
||||
if (this._queryInfoMap.has(ownerUri)) {
|
||||
let existingRunner = this._getQueryInfo(ownerUri).queryRunner;
|
||||
|
||||
@@ -112,6 +112,15 @@ export default class QueryRunner {
|
||||
private _onBatchEnd = new Emitter<sqlops.BatchSummary>();
|
||||
public readonly onBatchEnd: Event<sqlops.BatchSummary> = this._onBatchEnd.event;
|
||||
|
||||
private _queryStartTime: Date;
|
||||
public get queryStartTime(): Date {
|
||||
return this._queryStartTime;
|
||||
}
|
||||
private _queryEndTime: Date;
|
||||
public get queryEndTime(): Date {
|
||||
return this._queryEndTime;
|
||||
}
|
||||
|
||||
// CONSTRUCTOR /////////////////////////////////////////////////////////
|
||||
constructor(
|
||||
public uri: string,
|
||||
@@ -185,9 +194,10 @@ export default class QueryRunner {
|
||||
this._debouncedMessage.clear();
|
||||
this._debouncedResultSet.clear();
|
||||
this._planXml = new Deferred<string>();
|
||||
let ownerUri = this.uri;
|
||||
this._batchSets = [];
|
||||
this._hasCompleted = false;
|
||||
this._queryStartTime = undefined;
|
||||
this._queryEndTime = undefined;
|
||||
if (types.isObject(input) || types.isUndefinedOrNull(input)) {
|
||||
// Update internal state to show that we're executing the query
|
||||
this._resultLineOffset = input ? input.startLine : 0;
|
||||
@@ -203,20 +213,22 @@ export default class QueryRunner {
|
||||
|
||||
// Send the request to execute the query
|
||||
return runCurrentStatement
|
||||
? this._queryManagementService.runQueryStatement(ownerUri, input.startLine, input.startColumn).then(() => this.handleSuccessRunQueryResult(), e => this.handleFailureRunQueryResult(e))
|
||||
: this._queryManagementService.runQuery(ownerUri, input, runOptions).then(() => this.handleSuccessRunQueryResult(), e => this.handleFailureRunQueryResult(e));
|
||||
? this._queryManagementService.runQueryStatement(this.uri, input.startLine, input.startColumn).then(() => this.handleSuccessRunQueryResult(), e => this.handleFailureRunQueryResult(e))
|
||||
: this._queryManagementService.runQuery(this.uri, input, runOptions).then(() => this.handleSuccessRunQueryResult(), e => this.handleFailureRunQueryResult(e));
|
||||
} else if (types.isString(input)) {
|
||||
// Update internal state to show that we're executing the query
|
||||
this._isExecuting = true;
|
||||
this._totalElapsedMilliseconds = 0;
|
||||
|
||||
return this._queryManagementService.runQueryString(ownerUri, input).then(() => this.handleSuccessRunQueryResult(), e => this.handleFailureRunQueryResult(e));
|
||||
return this._queryManagementService.runQueryString(this.uri, input).then(() => this.handleSuccessRunQueryResult(), e => this.handleFailureRunQueryResult(e));
|
||||
} else {
|
||||
return Promise.reject('Unknown input');
|
||||
}
|
||||
}
|
||||
|
||||
private handleSuccessRunQueryResult() {
|
||||
// this isn't exact, but its the best we can do
|
||||
this._queryStartTime = new Date();
|
||||
// The query has started, so lets fire up the result pane
|
||||
this._onQueryStart.fire();
|
||||
this._eventEmitter.emit(EventType.START);
|
||||
@@ -241,6 +253,8 @@ export default class QueryRunner {
|
||||
* Handle a QueryComplete from the service layer
|
||||
*/
|
||||
public handleQueryComplete(result: sqlops.QueryExecuteCompleteNotificationResult): void {
|
||||
// this also isn't exact but its the best we can do
|
||||
this._queryEndTime = new Date();
|
||||
|
||||
// Store the batch sets we got back as a source of "truth"
|
||||
this._isExecuting = false;
|
||||
|
||||
Reference in New Issue
Block a user