mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-12 19:18:32 -05:00
More Layering (#9139)
* move handling generated files to the serilization classes * remove unneeded methods * add more folders to strictire compile, add more strict compile options * update ci * wip * add more layering and fix issues * add more strictness * remove unnecessary assertion * add missing checks * fix indentation * wip * remove jsdoc * fix layering * fix compile * fix compile errors * wip * wip * finish layering * fix css * more layering * rip * reworking results serializer * move some files around * move capabilities to platform wip * implement capabilities register provider * fix capabilities service * fix usage of the regist4ry * add contribution * wip * wip * wip * remove no longer good parts * fix strict-nulls * fix issues with startup * another try * fix startup * fix imports * fix tests * fix tests * fix more tests * fix tests * fix more tests * fix broken test * fix tabbing * fix naming * wip * finished layering * fix imports * fix valid layers * fix layers
This commit is contained in:
226
src/sql/workbench/browser/editData/editDataInput.ts
Normal file
226
src/sql/workbench/browser/editData/editDataInput.ts
Normal file
@@ -0,0 +1,226 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { EditorInput, EncodingMode, IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { IConnectionManagementService, IConnectableInput, INewConnectionParams } from 'sql/platform/connection/common/connectionManagement';
|
||||
import { IQueryModelService } from 'sql/workbench/services/query/common/queryModel';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { EditSessionReadyParams } from 'azdata';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as nls from 'vs/nls';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { EditDataResultsInput } from 'sql/workbench/browser/editData/editDataResultsInput';
|
||||
import { IEditorViewState } from 'vs/editor/common/editorCommon';
|
||||
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
||||
import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
|
||||
import { IUntitledTextEditorModel, UntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
|
||||
|
||||
/**
|
||||
* Input for the EditDataEditor.
|
||||
*/
|
||||
export class EditDataInput extends EditorInput implements IConnectableInput {
|
||||
public static ID: string = 'workbench.editorinputs.editDataInput';
|
||||
private _hasBootstrapped: boolean;
|
||||
private _updateTaskbar: Emitter<EditDataInput>;
|
||||
private _editorInitializing: Emitter<boolean>;
|
||||
private _showResultsEditor: Emitter<EditDataInput | undefined>;
|
||||
private _refreshButtonEnabled: boolean;
|
||||
private _stopButtonEnabled: boolean;
|
||||
private _setup: boolean;
|
||||
private _rowLimit?: number;
|
||||
private _objectType: string;
|
||||
private _useQueryFilter: boolean;
|
||||
|
||||
public savedViewState?: IEditorViewState;
|
||||
|
||||
constructor(
|
||||
private _uri: URI,
|
||||
private _schemaName: string,
|
||||
private _tableName: string,
|
||||
private _sql: UntitledTextEditorInput,
|
||||
private _queryString: string,
|
||||
private _results: EditDataResultsInput,
|
||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
|
||||
@IQueryModelService private _queryModelService: IQueryModelService,
|
||||
@INotificationService private notificationService: INotificationService
|
||||
) {
|
||||
super();
|
||||
this._hasBootstrapped = false;
|
||||
this._updateTaskbar = new Emitter<EditDataInput>();
|
||||
this._showResultsEditor = new Emitter<EditDataInput>();
|
||||
this._editorInitializing = new Emitter<boolean>();
|
||||
this._setup = false;
|
||||
this._stopButtonEnabled = false;
|
||||
this._refreshButtonEnabled = false;
|
||||
this._useQueryFilter = false;
|
||||
|
||||
// re-emit sql editor events through this editor if it exists.
|
||||
// also set dirty status to false to prevent rerendering.
|
||||
if (this._sql) {
|
||||
this._register(this._sql.onDidChangeDirty(async () => {
|
||||
const model = await this._sql.resolve() as UntitledTextEditorModel;
|
||||
model.setDirty(false);
|
||||
this._onDidChangeDirty.fire();
|
||||
}));
|
||||
}
|
||||
|
||||
//TODO determine is this is a table or a view
|
||||
this._objectType = 'TABLE';
|
||||
|
||||
// Attach to event callbacks
|
||||
if (this._queryModelService) {
|
||||
let self = this;
|
||||
|
||||
// Register callbacks for the Actions
|
||||
this._register(
|
||||
this._queryModelService.onRunQueryStart(uri => {
|
||||
if (self.uri === uri) {
|
||||
self.initEditStart();
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
this._register(
|
||||
this._queryModelService.onEditSessionReady((result) => {
|
||||
if (self.uri === result.ownerUri) {
|
||||
self.initEditEnd(result);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Getters/Setters
|
||||
public get tableName(): string { return this._tableName; }
|
||||
public get schemaName(): string { return this._schemaName; }
|
||||
public get uri(): string { return unescape(this._uri.toString()); }
|
||||
public get sql(): UntitledTextEditorInput { return this._sql; }
|
||||
public get results(): EditDataResultsInput { return this._results; }
|
||||
public getResultsInputResource(): string { return this._results.uri; }
|
||||
public get updateTaskbarEvent(): Event<EditDataInput> { return this._updateTaskbar.event; }
|
||||
public get editorInitializingEvent(): Event<boolean> { return this._editorInitializing.event; }
|
||||
public get showResultsEditorEvent(): Event<EditDataInput | undefined> { return this._showResultsEditor.event; }
|
||||
public get stopButtonEnabled(): boolean { return this._stopButtonEnabled; }
|
||||
public get refreshButtonEnabled(): boolean { return this._refreshButtonEnabled; }
|
||||
public get hasBootstrapped(): boolean { return this._hasBootstrapped; }
|
||||
public get setup(): boolean { return this._setup; }
|
||||
public get rowLimit(): number | undefined { return this._rowLimit; }
|
||||
public get objectType(): string { return this._objectType; }
|
||||
public showResultsEditor(): void { this._showResultsEditor.fire(undefined); }
|
||||
public isDirty(): boolean { return false; }
|
||||
public save(): Promise<IEditorInput | undefined> { return Promise.resolve(undefined); }
|
||||
public getTypeId(): string { return EditDataInput.ID; }
|
||||
public setBootstrappedTrue(): void { this._hasBootstrapped = true; }
|
||||
public getResource(): URI { return this._uri; }
|
||||
public supportsSplitEditor(): boolean { return false; }
|
||||
public setupComplete() { this._setup = true; }
|
||||
public get queryString(): string {
|
||||
return this._queryString;
|
||||
}
|
||||
public set queryString(queryString: string) {
|
||||
this._queryString = queryString;
|
||||
}
|
||||
public get queryPaneEnabled(): boolean {
|
||||
return this._useQueryFilter;
|
||||
}
|
||||
public set queryPaneEnabled(useQueryFilter: boolean) {
|
||||
this._useQueryFilter = useQueryFilter;
|
||||
}
|
||||
|
||||
// State Update Callbacks
|
||||
public initEditStart(): void {
|
||||
this._editorInitializing.fire(true);
|
||||
this._refreshButtonEnabled = false;
|
||||
this._stopButtonEnabled = true;
|
||||
this._updateTaskbar.fire(this);
|
||||
}
|
||||
|
||||
public initEditEnd(result: EditSessionReadyParams): void {
|
||||
this._refreshButtonEnabled = true;
|
||||
this._stopButtonEnabled = false;
|
||||
if (!result.success) {
|
||||
this.notificationService.notify({
|
||||
severity: Severity.Error,
|
||||
message: result.message
|
||||
});
|
||||
}
|
||||
this._editorInitializing.fire(false);
|
||||
this._updateTaskbar.fire(this);
|
||||
}
|
||||
|
||||
public onConnectStart(): void {
|
||||
// TODO: Indicate connection started
|
||||
}
|
||||
|
||||
public onConnectReject(error?: string): void {
|
||||
if (error) {
|
||||
|
||||
this.notificationService.notify({
|
||||
severity: Severity.Error,
|
||||
message: nls.localize('connectionFailure', "Edit Data Session Failed To Connect")
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public onConnectCanceled(): void {
|
||||
}
|
||||
|
||||
public onConnectSuccess(params?: INewConnectionParams): void {
|
||||
let rowLimit: number | undefined = undefined;
|
||||
let queryString: string | undefined = undefined;
|
||||
if (this._useQueryFilter) {
|
||||
queryString = this._queryString;
|
||||
} else {
|
||||
rowLimit = this._rowLimit;
|
||||
}
|
||||
|
||||
this._queryModelService.initializeEdit(this.uri, this.schemaName, this.tableName, this._objectType, rowLimit, queryString);
|
||||
this.showResultsEditor();
|
||||
this._onDidChangeLabel.fire();
|
||||
}
|
||||
|
||||
public onDisconnect(): void {
|
||||
// TODO: deal with disconnections
|
||||
}
|
||||
|
||||
public onRowDropDownSet(rows: number) {
|
||||
this._rowLimit = rows;
|
||||
}
|
||||
|
||||
// Boiler Plate Functions
|
||||
public matches(otherInput: any): boolean {
|
||||
if (otherInput instanceof EditDataInput) {
|
||||
return this._sql.matches(otherInput.sql);
|
||||
}
|
||||
|
||||
return this._sql.matches(otherInput);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
// Dispose our edit session then disconnect our input
|
||||
this._queryModelService.disposeEdit(this.uri).then(() => {
|
||||
return this._connectionManagementService.disconnectEditor(this, true);
|
||||
});
|
||||
this._queryModelService.disposeQuery(this.uri);
|
||||
this._sql.dispose();
|
||||
this._results.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public get tabColor(): string {
|
||||
return this._connectionManagementService.getTabColorForUri(this.uri);
|
||||
}
|
||||
|
||||
public resolve(refresh?: boolean): Promise<IUntitledTextEditorModel & IResolvedTextEditorModel> { return this._sql.resolve(); }
|
||||
public getEncoding(): string { return this._sql.getEncoding(); }
|
||||
public getName(): string { return this._sql.getName(); }
|
||||
public get hasAssociatedFilePath(): boolean { return this._sql.model.hasAssociatedFilePath; }
|
||||
|
||||
public setEncoding(encoding: string, mode: EncodingMode /* ignored, we only have Encode */): void {
|
||||
this._sql.setEncoding(encoding, mode);
|
||||
}
|
||||
}
|
||||
105
src/sql/workbench/browser/editData/editDataResultsInput.ts
Normal file
105
src/sql/workbench/browser/editData/editDataResultsInput.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { EditorInput } from 'vs/workbench/common/editor';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
|
||||
/**
|
||||
* Input for the EditDataResultsEditor. This input helps with logic for the viewing and editing of
|
||||
* data in the results grid.
|
||||
*/
|
||||
export class EditDataResultsInput extends EditorInput {
|
||||
|
||||
// Tracks if the editor that holds this input should be visible (i.e. true if a query has been run)
|
||||
private _visible: boolean;
|
||||
|
||||
// Tracks if the editor has holds this input has has bootstrapped angular yet
|
||||
private _hasBootstrapped: boolean;
|
||||
|
||||
// Holds the HTML content for the editor when the editor discards this input and loads another
|
||||
private _editorContainer?: HTMLElement;
|
||||
public css?: HTMLStyleElement;
|
||||
|
||||
public readonly onRestoreViewStateEmitter = new Emitter<void>();
|
||||
public readonly onSaveViewStateEmitter = new Emitter<void>();
|
||||
|
||||
constructor(private _uri: string) {
|
||||
super();
|
||||
this._visible = false;
|
||||
this._hasBootstrapped = false;
|
||||
}
|
||||
|
||||
getTypeId(): string {
|
||||
return EditDataResultsInput.ID;
|
||||
}
|
||||
|
||||
matches(other: any): boolean {
|
||||
if (other instanceof EditDataResultsInput) {
|
||||
return (other._uri === this._uri);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
resolve(refresh?: boolean): Promise<any> {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
supportsSplitEditor(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
public setBootstrappedTrue(): void {
|
||||
this._hasBootstrapped = true;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._disposeContainer();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private _disposeContainer() {
|
||||
if (!this._editorContainer) {
|
||||
return;
|
||||
}
|
||||
|
||||
let parentContainer = this._editorContainer.parentNode;
|
||||
if (parentContainer) {
|
||||
parentContainer.removeChild(this._editorContainer);
|
||||
this._editorContainer = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
//// Properties
|
||||
|
||||
static get ID() {
|
||||
return 'workbench.editorinputs.editDataResultsInput';
|
||||
}
|
||||
|
||||
setContainer(container: HTMLElement) {
|
||||
this._disposeContainer();
|
||||
this._editorContainer = container;
|
||||
}
|
||||
|
||||
get container(): HTMLElement | undefined {
|
||||
return this._editorContainer;
|
||||
}
|
||||
|
||||
get hasBootstrapped(): boolean {
|
||||
return this._hasBootstrapped;
|
||||
}
|
||||
|
||||
get visible(): boolean {
|
||||
return this._visible;
|
||||
}
|
||||
|
||||
set visible(visible: boolean) {
|
||||
this._visible = visible;
|
||||
}
|
||||
|
||||
get uri(): string {
|
||||
return unescape(this._uri);
|
||||
}
|
||||
}
|
||||
173
src/sql/workbench/browser/editor/profiler/dashboardInput.ts
Normal file
173
src/sql/workbench/browser/editor/profiler/dashboardInput.ts
Normal file
@@ -0,0 +1,173 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { EditorInput, EditorModel } from 'vs/workbench/common/editor';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
|
||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
||||
import { mssqlProviderName } from 'sql/platform/connection/common/constants';
|
||||
|
||||
export class DashboardInput extends EditorInput {
|
||||
|
||||
private _uri: string;
|
||||
public static ID: string = 'workbench.editorinputs.connectiondashboardinputs';
|
||||
public static SCHEMA: string = 'sqldashboard';
|
||||
|
||||
private _initializedPromise: Thenable<void>;
|
||||
private _onConnectionChanged: IDisposable;
|
||||
|
||||
public get initializedPromise(): Thenable<void> {
|
||||
return this._initializedPromise;
|
||||
}
|
||||
|
||||
private _uniqueSelector: string;
|
||||
|
||||
public hasBootstrapped = false;
|
||||
// Holds the HTML content for the editor when the editor discards this input and loads another
|
||||
private _parentContainer: HTMLElement;
|
||||
|
||||
constructor(
|
||||
_connectionProfile: IConnectionProfile,
|
||||
@IConnectionManagementService private _connectionService: IConnectionManagementService,
|
||||
@IModeService modeService: IModeService,
|
||||
@IModelService model: IModelService
|
||||
) {
|
||||
super();
|
||||
// TODO; possible refactor
|
||||
// basically this is mimicing creating a "model" (the backing model for text for editors)
|
||||
// for dashboard, even though there is no backing text. We need this so that we can
|
||||
// tell the icon theme services that we are a dashboard resource, therefore loading the correct icon
|
||||
|
||||
// vscode has a comment that Mode's will eventually be removed (not sure the state of this comment)
|
||||
// so this might be able to be undone when that happens
|
||||
if (!model.getModel(this.getResource())) {
|
||||
model.createModel('', modeService.create('dashboard'), this.getResource());
|
||||
}
|
||||
this._initializedPromise = _connectionService.connectIfNotConnected(_connectionProfile, 'dashboard').then(
|
||||
u => {
|
||||
this._uri = u;
|
||||
const info = this._connectionService.getConnectionInfo(u);
|
||||
if (info) {
|
||||
this._onConnectionChanged = this._connectionService.onConnectionChanged(e => {
|
||||
if (e.connectionUri === u) {
|
||||
this._onDidChangeLabel.fire();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public setUniqueSelector(uniqueSelector: string): void {
|
||||
this._uniqueSelector = uniqueSelector;
|
||||
}
|
||||
|
||||
public getTypeId(): string {
|
||||
return DashboardInput.ID;
|
||||
}
|
||||
|
||||
public getResource(): URI {
|
||||
return URI.from({
|
||||
scheme: 'dashboard',
|
||||
path: 'dashboard'
|
||||
});
|
||||
}
|
||||
|
||||
public getName(): string {
|
||||
if (!this.connectionProfile) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let name = this.connectionProfile.connectionName ? this.connectionProfile.connectionName : this.connectionProfile.serverName;
|
||||
if (this.connectionProfile.databaseName
|
||||
&& !this.isMasterMssql()) {
|
||||
// Only add DB name if this is a non-default, non-master connection
|
||||
name = name + ':' + this.connectionProfile.databaseName;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private isMasterMssql(): boolean {
|
||||
return this.connectionProfile.providerName === mssqlProviderName
|
||||
&& this.connectionProfile.databaseName.toLowerCase() === 'master';
|
||||
}
|
||||
|
||||
public get uri(): string {
|
||||
return this._uri;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._disposeContainer();
|
||||
if (this._onConnectionChanged) {
|
||||
this._onConnectionChanged.dispose();
|
||||
}
|
||||
this._connectionService.disconnect(this._uri);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private _disposeContainer() {
|
||||
if (!this._parentContainer) {
|
||||
return;
|
||||
}
|
||||
|
||||
const parentNode = this._parentContainer.parentNode;
|
||||
if (parentNode) {
|
||||
parentNode.removeChild(this._parentContainer);
|
||||
this._parentContainer = null;
|
||||
}
|
||||
}
|
||||
|
||||
set container(container: HTMLElement) {
|
||||
this._disposeContainer();
|
||||
this._parentContainer = container;
|
||||
}
|
||||
|
||||
get container(): HTMLElement {
|
||||
return this._parentContainer;
|
||||
}
|
||||
|
||||
public supportsSplitEditor(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
public get connectionProfile(): IConnectionProfile {
|
||||
return this._connectionService.getConnectionProfile(this._uri);
|
||||
}
|
||||
|
||||
public resolve(refresh?: boolean): Promise<EditorModel> {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public get hasInitialized(): boolean {
|
||||
return !!this._uniqueSelector;
|
||||
}
|
||||
|
||||
public get uniqueSelector(): string {
|
||||
return this._uniqueSelector;
|
||||
}
|
||||
|
||||
public matches(otherinput: any): boolean {
|
||||
return otherinput instanceof DashboardInput
|
||||
&& DashboardInput.profileMatches(this.connectionProfile, otherinput.connectionProfile);
|
||||
}
|
||||
|
||||
// similar to the default profile match but without databasename
|
||||
public static profileMatches(profile1: IConnectionProfile, profile2: IConnectionProfile): boolean {
|
||||
return profile1 && profile2
|
||||
&& profile1.providerName === profile2.providerName
|
||||
&& profile1.serverName === profile2.serverName
|
||||
&& profile1.userName === profile2.userName
|
||||
&& profile1.authenticationType === profile2.authenticationType
|
||||
&& profile1.groupFullName === profile2.groupFullName;
|
||||
}
|
||||
|
||||
public get tabColor(): string {
|
||||
return this._connectionService.getTabColorForUri(this.uri);
|
||||
}
|
||||
}
|
||||
290
src/sql/workbench/browser/editor/profiler/profilerInput.ts
Normal file
290
src/sql/workbench/browser/editor/profiler/profilerInput.ts
Normal file
@@ -0,0 +1,290 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { TableDataView } from 'sql/base/browser/ui/table/tableDataView';
|
||||
import { IProfilerSession, IProfilerService, ProfilerSessionID, IProfilerViewTemplate, ProfilerFilter } from 'sql/workbench/services/profiler/browser/interfaces';
|
||||
import { ProfilerState } from 'sql/workbench/common/editor/profiler/profilerState';
|
||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import * as nls from 'vs/nls';
|
||||
|
||||
import { EditorInput } from 'vs/workbench/common/editor';
|
||||
import { IEditorModel } from 'vs/platform/editor/common/editor';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { FilterData } from 'sql/workbench/services/profiler/browser/profilerFilter';
|
||||
import { uriPrefixes } from 'sql/platform/connection/common/utils';
|
||||
import { find } from 'vs/base/common/arrays';
|
||||
|
||||
export class ProfilerInput extends EditorInput implements IProfilerSession {
|
||||
|
||||
public static ID: string = 'workbench.editorinputs.profilerinputs';
|
||||
public static SCHEMA: string = 'profiler';
|
||||
private _data: TableDataView<Slick.SlickData>;
|
||||
private _id: ProfilerSessionID;
|
||||
private _state: ProfilerState;
|
||||
private _columns: string[] = [];
|
||||
private _sessionName: string;
|
||||
private _viewTemplate: IProfilerViewTemplate;
|
||||
// mapping of event categories to what column they display under
|
||||
// used for coallescing multiple events with different names to the same column
|
||||
private _columnMapping: { [event: string]: string } = {};
|
||||
|
||||
private _onColumnsChanged = new Emitter<Slick.Column<Slick.SlickData>[]>();
|
||||
public onColumnsChanged: Event<Slick.Column<Slick.SlickData>[]> = this._onColumnsChanged.event;
|
||||
|
||||
private _filter: ProfilerFilter = { clauses: [] };
|
||||
|
||||
constructor(
|
||||
public connection: IConnectionProfile,
|
||||
@IProfilerService private _profilerService: IProfilerService,
|
||||
@INotificationService private _notificationService: INotificationService
|
||||
) {
|
||||
super();
|
||||
this._state = new ProfilerState();
|
||||
// set inital state
|
||||
this.state.change({
|
||||
isConnected: false,
|
||||
isStopped: true,
|
||||
isPaused: false,
|
||||
isRunning: false,
|
||||
autoscroll: true
|
||||
});
|
||||
|
||||
this._profilerService.registerSession(uriPrefixes.connection + generateUuid(), connection, this).then((id) => {
|
||||
this._id = id;
|
||||
this.state.change({ isConnected: true });
|
||||
});
|
||||
let searchFn = (val: { [x: string]: string }, exp: string): Array<number> => {
|
||||
let ret = new Array<number>();
|
||||
for (let i = 0; i < this._columns.length; i++) {
|
||||
let colVal = val[this._columns[i]];
|
||||
if (colVal && colVal.toLocaleLowerCase().indexOf(exp.toLocaleLowerCase()) > -1) {
|
||||
ret.push(i);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
let filterFn = (data: Array<Slick.SlickData>): Array<Slick.SlickData> => {
|
||||
return FilterData(this._filter, data);
|
||||
};
|
||||
|
||||
this._data = new TableDataView<Slick.SlickData>(undefined, searchFn, undefined, filterFn);
|
||||
}
|
||||
|
||||
public get providerType(): string {
|
||||
return this.connection ? this.connection.providerName : undefined;
|
||||
}
|
||||
|
||||
public set viewTemplate(template: IProfilerViewTemplate) {
|
||||
this._data.clear();
|
||||
this._viewTemplate = template;
|
||||
|
||||
let newColumns = this._viewTemplate.columns.reduce<Array<string>>((p, e) => {
|
||||
p.push(e.name);
|
||||
return p;
|
||||
}, []);
|
||||
|
||||
let newMapping: { [event: string]: string } = {};
|
||||
this._viewTemplate.columns.forEach(c => {
|
||||
c.eventsMapped.forEach(e => {
|
||||
newMapping[e] = c.name;
|
||||
});
|
||||
});
|
||||
this.setColumnMapping(newColumns, newMapping);
|
||||
}
|
||||
|
||||
public get viewTemplate(): IProfilerViewTemplate {
|
||||
return this._viewTemplate;
|
||||
}
|
||||
|
||||
public set sessionName(name: string) {
|
||||
if (!this.state.isRunning || !this.state.isPaused) {
|
||||
this._sessionName = name;
|
||||
}
|
||||
}
|
||||
|
||||
public get sessionName(): string {
|
||||
return this._sessionName;
|
||||
}
|
||||
|
||||
public getTypeId(): string {
|
||||
return ProfilerInput.ID;
|
||||
}
|
||||
|
||||
public resolve(refresh?: boolean): Promise<IEditorModel> {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public getName(): string {
|
||||
let name: string = nls.localize('profilerInput.profiler', "Profiler");
|
||||
if (!this.connection) {
|
||||
return name;
|
||||
}
|
||||
name += ': ' + this.connection.serverName.substring(0, 20);
|
||||
return name;
|
||||
}
|
||||
|
||||
public getResource(): URI {
|
||||
return URI.from({
|
||||
scheme: ProfilerInput.SCHEMA,
|
||||
path: 'profiler'
|
||||
});
|
||||
}
|
||||
|
||||
public get data(): TableDataView<Slick.SlickData> {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
public get columns(): Slick.Column<Slick.SlickData>[] {
|
||||
if (this._columns) {
|
||||
return this._columns.map(i => {
|
||||
return <Slick.Column<Slick.SlickData>>{
|
||||
id: i,
|
||||
field: i,
|
||||
name: i,
|
||||
sortable: true
|
||||
};
|
||||
});
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
public setColumns(columns: Array<string>) {
|
||||
this._columns = columns;
|
||||
this._onColumnsChanged.fire(this.columns);
|
||||
}
|
||||
|
||||
public setColumnMapping(columns: Array<string>, mapping: { [event: string]: string }) {
|
||||
this._columns = columns;
|
||||
this._columnMapping = mapping;
|
||||
this._onColumnsChanged.fire(this.columns);
|
||||
}
|
||||
|
||||
public get connectionName(): string {
|
||||
if (!types.isUndefinedOrNull(this.connection)) {
|
||||
if (this.connection.databaseName) {
|
||||
return `${this.connection.serverName} ${this.connection.databaseName}`;
|
||||
} else {
|
||||
return `${this.connection.serverName}`;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return nls.localize('profilerInput.notConnected', "Not connected");
|
||||
}
|
||||
}
|
||||
|
||||
public get id(): ProfilerSessionID {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
public get state(): ProfilerState {
|
||||
return this._state;
|
||||
}
|
||||
|
||||
public get filter(): ProfilerFilter {
|
||||
return this._filter;
|
||||
}
|
||||
|
||||
public onSessionStopped(notification: azdata.ProfilerSessionStoppedParams) {
|
||||
this._notificationService.error(nls.localize("profiler.sessionStopped", "XEvent Profiler Session stopped unexpectedly on the server {0}.", this.connection.serverName));
|
||||
|
||||
this.state.change({
|
||||
isStopped: true,
|
||||
isPaused: false,
|
||||
isRunning: false
|
||||
});
|
||||
}
|
||||
|
||||
public onProfilerSessionCreated(params: azdata.ProfilerSessionCreatedParams) {
|
||||
if (types.isUndefinedOrNull(params.sessionName) || types.isUndefinedOrNull(params.templateName)) {
|
||||
this._notificationService.error(nls.localize("profiler.sessionCreationError", "Error while starting new session"));
|
||||
} else {
|
||||
this._sessionName = params.sessionName;
|
||||
let sessionTemplate = find(this._profilerService.getSessionTemplates(), (template) => {
|
||||
return template.name === params.templateName;
|
||||
});
|
||||
if (!types.isUndefinedOrNull(sessionTemplate)) {
|
||||
let newView = find(this._profilerService.getViewTemplates(), (view) => {
|
||||
return view.name === sessionTemplate.defaultView;
|
||||
});
|
||||
if (!types.isUndefinedOrNull(newView)) {
|
||||
this.viewTemplate = newView;
|
||||
}
|
||||
}
|
||||
|
||||
this.data.clear();
|
||||
this.state.change({
|
||||
isStopped: false,
|
||||
isPaused: false,
|
||||
isRunning: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public onSessionStateChanged(state: ProfilerState) {
|
||||
this.state.change(state);
|
||||
}
|
||||
|
||||
public onMoreRows(eventMessage: azdata.ProfilerSessionEvents) {
|
||||
if (eventMessage.eventsLost) {
|
||||
this._notificationService.warn(nls.localize("profiler.eventsLost", "The XEvent Profiler session for {0} has lost events.", this.connection.serverName));
|
||||
}
|
||||
|
||||
let newEvents = [];
|
||||
for (let i: number = 0; i < eventMessage.events.length && i < 500; ++i) {
|
||||
let e: azdata.ProfilerEvent = eventMessage.events[i];
|
||||
let data = {};
|
||||
data['EventClass'] = e.name;
|
||||
data['StartTime'] = e.timestamp;
|
||||
|
||||
// Using ' ' instead of '' fixed the error where clicking through events
|
||||
// with empty text fields causes future text panes to be highlighted.
|
||||
// This is a temporary fix
|
||||
data['TextData'] = ' ';
|
||||
for (let key in e.values) {
|
||||
let columnName = this._columnMapping[key];
|
||||
if (columnName) {
|
||||
let value = e.values[key];
|
||||
data[columnName] = value;
|
||||
}
|
||||
}
|
||||
newEvents.push(data);
|
||||
}
|
||||
|
||||
if (newEvents.length > 0) {
|
||||
this._data.push(newEvents);
|
||||
}
|
||||
}
|
||||
|
||||
filterSession(filter: ProfilerFilter) {
|
||||
this._filter = filter;
|
||||
if (this._filter.clauses.length !== 0) {
|
||||
this.data.filter();
|
||||
} else {
|
||||
this.data.clearFilter();
|
||||
}
|
||||
}
|
||||
|
||||
clearFilter() {
|
||||
this._filter = { clauses: [] };
|
||||
this.data.clearFilter();
|
||||
}
|
||||
|
||||
isDirty(): boolean {
|
||||
return this.state.isRunning || this.state.isPaused;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
super.dispose();
|
||||
this._profilerService.disconnectSession(this.id);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user