mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -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:
@@ -1 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.065 13H15v2H2.056v-2h5.009zm3.661-12H7.385L8.44 2.061 7.505 3H15V1h-4.274zM3.237 9H2.056v2H15V9H3.237zm4.208-4l.995 1-.995 1H15V5H7.445z" fill="#424242"/><path d="M5.072 4.03L7.032 6 5.978 7.061l-1.96-1.97-1.961 1.97L1 6l1.96-1.97L1 2.061 2.056 1l1.96 1.97L5.977 1l1.057 1.061L5.072 4.03z" fill="#A1260D"/></svg>
|
||||
|
Before Width: | Height: | Size: 419 B |
@@ -1 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.065 13H15v2H2.056v-2h5.009zm3.661-12H7.385L8.44 2.061 7.505 3H15V1h-4.274zM3.237 9H2.056v2H15V9H3.237zm4.208-4l.995 1-.995 1H15V5H7.445z" fill="#C5C5C5"/><path d="M5.072 4.03L7.032 6 5.978 7.061l-1.96-1.97-1.961 1.97L1 6l1.96-1.97L1 2.061 2.056 1l1.96 1.97L5.977 1l1.057 1.061L5.072 4.03z" fill="#F48771"/></svg>
|
||||
|
Before Width: | Height: | Size: 419 B |
@@ -1,21 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.profiler-column-tree {
|
||||
height: calc(100% - 25px);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tree-row > * {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.vs .codicon.clear-results {
|
||||
background-image: url('clear.svg');
|
||||
}
|
||||
|
||||
.vs-dark .codicon.clear-results {
|
||||
background-image: url('clear_inverse.svg');
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.profiler-filter-dialog {
|
||||
height: 300px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.profiler-filter-clause-table {
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.clause-table-container{
|
||||
max-height: 270px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.profiler-filter-remove-condition {
|
||||
width:20px;
|
||||
height:20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.profiler-filter-clause-table-action {
|
||||
cursor: pointer;
|
||||
margin-right: 10px;
|
||||
padding: 2px;
|
||||
text-decoration: underline;
|
||||
display: inline-block;
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions, IConfigu
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import * as nls from 'vs/nls';
|
||||
|
||||
import { ProfilerInput } from 'sql/workbench/contrib/profiler/browser/profilerInput';
|
||||
import { ProfilerInput } from 'sql/workbench/browser/editor/profiler/profilerInput';
|
||||
import { ProfilerEditor } from 'sql/workbench/contrib/profiler/browser/profilerEditor';
|
||||
import { PROFILER_VIEW_TEMPLATE_SETTINGS, PROFILER_SESSION_TEMPLATE_SETTINGS, IProfilerViewTemplate, IProfilerSessionTemplate, EngineType, PROFILER_FILTER_SETTINGS } from 'sql/workbench/services/profiler/browser/interfaces';
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IEditorService, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
||||
import { ProfilerInput } from 'sql/workbench/contrib/profiler/browser/profilerInput';
|
||||
import { ProfilerInput } from 'sql/workbench/browser/editor/profiler/profilerInput';
|
||||
import * as TaskUtilities from 'sql/workbench/browser/taskUtilities';
|
||||
import { IProfilerService } from 'sql/workbench/services/profiler/browser/interfaces';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { ProfilerEditor } from 'sql/workbench/contrib/profiler/browser/profilerEditor';
|
||||
import { ObjectExplorerActionsContext } from 'sql/workbench/contrib/objectExplorer/browser/objectExplorerActions';
|
||||
import { ObjectExplorerActionsContext } from 'sql/workbench/services/objectExplorer/browser/objectExplorerActions';
|
||||
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
||||
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
|
||||
import { mssqlProviderName } from 'sql/platform/connection/common/constants';
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { IProfilerService } from 'sql/workbench/services/profiler/browser/interfaces';
|
||||
import { IProfilerController } from 'sql/workbench/contrib/profiler/common/interfaces';
|
||||
import { ProfilerInput } from 'sql/workbench/contrib/profiler/browser/profilerInput';
|
||||
import { ProfilerInput } from 'sql/workbench/browser/editor/profiler/profilerInput';
|
||||
import { Task } from 'sql/workbench/services/tasks/browser/tasksRegistry';
|
||||
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
||||
import { IConnectionManagementService, IConnectionCompletionOptions } from 'sql/platform/connection/common/connectionManagement';
|
||||
|
||||
@@ -1,414 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/profiler';
|
||||
|
||||
import { Modal } from 'sql/workbench/browser/modal/modal';
|
||||
import { ProfilerInput } from 'sql/workbench/contrib/profiler/browser/profilerInput';
|
||||
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
|
||||
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
|
||||
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import * as nls from 'vs/nls';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { SelectBox } from 'vs/base/browser/ui/selectBox/selectBox';
|
||||
import { Tree } from 'vs/base/parts/tree/browser/treeImpl';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { IDataSource, ITree, IRenderer } from 'vs/base/parts/tree/browser/tree';
|
||||
import { attachListStyler } from 'vs/platform/theme/common/styler';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfigurationService';
|
||||
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
|
||||
import { attachModalDialogStyler } from 'sql/workbench/common/styler';
|
||||
|
||||
class EventItem {
|
||||
|
||||
constructor(
|
||||
private _name: string,
|
||||
private _parent: SessionItem,
|
||||
private _columns?: Array<ColumnItem>,
|
||||
) {
|
||||
if (!_columns) {
|
||||
this._columns = new Array<ColumnItem>();
|
||||
}
|
||||
}
|
||||
|
||||
public hasChildren(): boolean {
|
||||
return this._columns && this._columns.length > 0;
|
||||
}
|
||||
|
||||
public getChildren(): Array<ColumnItem> {
|
||||
return this._columns;
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
public addColumn(...columns: Array<ColumnItem>) {
|
||||
this._columns = this._columns.concat(columns);
|
||||
}
|
||||
|
||||
public get parent(): SessionItem {
|
||||
return this._parent;
|
||||
}
|
||||
|
||||
public get selected(): boolean {
|
||||
return this._columns.every(i => i.selected);
|
||||
}
|
||||
|
||||
public set selected(val: boolean) {
|
||||
this._columns.forEach(i => i.selected = val);
|
||||
}
|
||||
|
||||
public get indeterminate(): boolean {
|
||||
return this._columns.some(i => i.selected) && !this.selected;
|
||||
}
|
||||
}
|
||||
|
||||
class ColumnItem {
|
||||
public selected: boolean;
|
||||
public readonly indeterminate = false;
|
||||
constructor(
|
||||
private _name: string,
|
||||
private _parent: EventItem
|
||||
) { }
|
||||
|
||||
public get id(): string {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
public get parent(): EventItem {
|
||||
return this._parent;
|
||||
}
|
||||
}
|
||||
|
||||
class ColumnSortedColumnItem {
|
||||
constructor(
|
||||
private _name: string,
|
||||
private _parent: SessionItem
|
||||
) { }
|
||||
|
||||
public get id(): string {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
public get parent(): SessionItem {
|
||||
return this._parent;
|
||||
}
|
||||
|
||||
public get selected(): boolean {
|
||||
return this._parent.getUnsortedChildren()
|
||||
.every(e => e.getChildren().filter(c => c.id === this.id)
|
||||
.every(c => c.selected));
|
||||
}
|
||||
|
||||
public set selected(val: boolean) {
|
||||
this._parent.getUnsortedChildren()
|
||||
.forEach(e => e.getChildren()
|
||||
.filter(c => c.id === this.id)
|
||||
.forEach(c => c.selected = val));
|
||||
}
|
||||
|
||||
public get indeterminate(): boolean {
|
||||
return this._parent.getUnsortedChildren()
|
||||
.some(e => e.getChildren()
|
||||
.filter(c => c.id === this.id)
|
||||
.some(c => c.selected))
|
||||
&& !this.selected;
|
||||
}
|
||||
}
|
||||
|
||||
class SessionItem {
|
||||
private _sortedColumnItems: Array<ColumnSortedColumnItem> = [];
|
||||
constructor(
|
||||
private _name: string,
|
||||
private _sort: 'event' | 'column',
|
||||
private _events?: Array<EventItem>
|
||||
) {
|
||||
if (!_events) {
|
||||
this._events = new Array<EventItem>();
|
||||
} else {
|
||||
_events.forEach(e => {
|
||||
e.getChildren().forEach(c => {
|
||||
if (!this._sortedColumnItems.some(i => i.id === c.id)) {
|
||||
this._sortedColumnItems.push(new ColumnSortedColumnItem(c.id, this));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
public hasChildren(): boolean {
|
||||
if (this._sort === 'event') {
|
||||
return this._events && this._events.length > 0;
|
||||
} else {
|
||||
return this._events && this._events.some(i => i.hasChildren());
|
||||
}
|
||||
}
|
||||
|
||||
public getUnsortedChildren(): Array<EventItem> {
|
||||
return this._events;
|
||||
}
|
||||
|
||||
public getChildren(): Array<EventItem | ColumnSortedColumnItem> {
|
||||
if (this._sort === 'event') {
|
||||
return this._events;
|
||||
} else {
|
||||
return this._sortedColumnItems;
|
||||
}
|
||||
}
|
||||
|
||||
public addEvents(...events: Array<EventItem>) {
|
||||
this._events = this._events.concat(events);
|
||||
events.forEach(e => {
|
||||
e.getChildren().forEach(c => {
|
||||
if (!this._sortedColumnItems.some(i => i.id === c.id)) {
|
||||
this._sortedColumnItems.push(new ColumnSortedColumnItem(c.id, this));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public changeSort(type: 'event' | 'column'): void {
|
||||
this._sort = type;
|
||||
}
|
||||
}
|
||||
|
||||
class TreeRenderer implements IRenderer {
|
||||
|
||||
private _onSelectedChange = new Emitter<any>();
|
||||
public onSelectedChange: Event<any> = this._onSelectedChange.event;
|
||||
|
||||
getHeight(tree: ITree, element: any): number {
|
||||
return 22;
|
||||
}
|
||||
|
||||
getTemplateId(tree: ITree, element: any): string {
|
||||
if (element instanceof SessionItem) {
|
||||
return 'session';
|
||||
} else if (element instanceof EventItem) {
|
||||
return 'event';
|
||||
} else if (element instanceof ColumnItem) {
|
||||
return 'column';
|
||||
} else if (element instanceof ColumnSortedColumnItem) {
|
||||
return 'columnSorted';
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
renderTemplate(tree: ITree, templateId: string, container: HTMLElement): RenderTemplate {
|
||||
const data = Object.create(null);
|
||||
const row = document.createElement('div');
|
||||
row.className = 'tree-row';
|
||||
DOM.append(container, row);
|
||||
data.toDispose = [];
|
||||
data.checkbox = document.createElement('input');
|
||||
DOM.append(row, data.checkbox);
|
||||
data.checkbox.type = 'checkbox';
|
||||
data.toDispose.push(DOM.addStandardDisposableListener(data.checkbox, 'change', () => {
|
||||
data.context.selected = !data.context.selected;
|
||||
this._onSelectedChange.fire(data.context);
|
||||
}));
|
||||
data.label = document.createElement('div');
|
||||
DOM.append(row, data.label);
|
||||
return data;
|
||||
}
|
||||
|
||||
renderElement(tree: ITree, element: any, templateId: string, templateData: RenderTemplate): void {
|
||||
templateData.context = element;
|
||||
templateData.label.innerText = element.id;
|
||||
templateData.checkbox.checked = element.selected;
|
||||
templateData.checkbox.indeterminate = element.indeterminate;
|
||||
}
|
||||
|
||||
disposeTemplate(tree: ITree, templateId: string, templateData: RenderTemplate): void {
|
||||
dispose(templateData.toDispose);
|
||||
}
|
||||
}
|
||||
|
||||
interface RenderTemplate {
|
||||
label: HTMLElement;
|
||||
toDispose: Array<IDisposable>;
|
||||
checkbox: HTMLInputElement;
|
||||
context?: any;
|
||||
}
|
||||
|
||||
class TreeDataSource implements IDataSource {
|
||||
|
||||
getId(tree: ITree, element: any): string {
|
||||
if (element instanceof EventItem) {
|
||||
return element.parent.id + element.id;
|
||||
} else if (element instanceof ColumnItem) {
|
||||
return element.parent.parent.id + element.parent.id + element.id;
|
||||
} else if (element instanceof SessionItem) {
|
||||
return element.id;
|
||||
} else if (element instanceof ColumnSortedColumnItem) {
|
||||
return element.id;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
hasChildren(tree: ITree, element: any): boolean {
|
||||
if (element instanceof SessionItem) {
|
||||
return element.hasChildren();
|
||||
} else if (element instanceof EventItem) {
|
||||
return element.hasChildren();
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
getChildren(tree: ITree, element: any): Promise<Array<any>> {
|
||||
if (element instanceof EventItem) {
|
||||
return Promise.resolve(element.getChildren());
|
||||
} else if (element instanceof SessionItem) {
|
||||
return Promise.resolve(element.getChildren());
|
||||
} else {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
|
||||
getParent(tree: ITree, element: any): Promise<any> {
|
||||
if (element instanceof ColumnItem) {
|
||||
return Promise.resolve(element.parent);
|
||||
} else if (element instanceof EventItem) {
|
||||
return Promise.resolve(element.parent);
|
||||
} else if (element instanceof ColumnSortedColumnItem) {
|
||||
return Promise.resolve(element.parent);
|
||||
} else {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
|
||||
shouldAutoexpand?(tree: ITree, element: any): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export class ProfilerColumnEditorDialog extends Modal {
|
||||
|
||||
private _selectBox: SelectBox;
|
||||
private readonly _options = [
|
||||
{ text: nls.localize('eventSort', "Sort by event") },
|
||||
{ text: nls.localize('nameColumn', "Sort by column") }
|
||||
];
|
||||
private _tree: Tree;
|
||||
private _element: SessionItem;
|
||||
private _treeContainer: HTMLElement;
|
||||
|
||||
constructor(
|
||||
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IAdsTelemetryService telemetryService: IAdsTelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IContextViewService private _contextViewService: IContextViewService,
|
||||
@IClipboardService clipboardService: IClipboardService,
|
||||
@ILogService logService: ILogService,
|
||||
@ITextResourcePropertiesService textResourcePropertiesService: ITextResourcePropertiesService
|
||||
) {
|
||||
super(nls.localize('profilerColumnDialog.profiler', "Profiler"), TelemetryKeys.Profiler, telemetryService, layoutService, clipboardService, themeService, logService, textResourcePropertiesService, contextKeyService);
|
||||
}
|
||||
|
||||
public render(): void {
|
||||
super.render();
|
||||
this._register(attachModalDialogStyler(this, this._themeService));
|
||||
this.addFooterButton(nls.localize('profilerColumnDialog.ok', "OK"), () => this.onAccept(undefined));
|
||||
this.addFooterButton(nls.localize('profilerColumnDialog.cancel', "Cancel"), () => this.onClose(undefined));
|
||||
}
|
||||
|
||||
protected renderBody(container: HTMLElement): void {
|
||||
const body = DOM.append(container, DOM.$(''));
|
||||
this._selectBox = new SelectBox(this._options, 0, this._contextViewService);
|
||||
this._selectBox.render(body);
|
||||
this._register(this._selectBox.onDidSelect(e => {
|
||||
this._element.changeSort(e.index === 0 ? 'event' : 'column');
|
||||
this._tree.refresh(this._element, true);
|
||||
}));
|
||||
this._treeContainer = DOM.append(body, DOM.$('.profiler-column-tree'));
|
||||
const renderer = new TreeRenderer();
|
||||
this._tree = new Tree(this._treeContainer, { dataSource: new TreeDataSource(), renderer });
|
||||
this._register(renderer.onSelectedChange(e => this._tree.refresh(e, true)));
|
||||
this._register(attachListStyler(this._tree, this._themeService));
|
||||
}
|
||||
|
||||
public open(input: ProfilerInput): void {
|
||||
super.show();
|
||||
this._updateList();
|
||||
}
|
||||
|
||||
protected onAccept(e: StandardKeyboardEvent): void {
|
||||
this._updateInput();
|
||||
super.onAccept(e);
|
||||
}
|
||||
|
||||
// currently not used, this dialog is a work in progress
|
||||
// tracked in issue #1545 https://github.com/Microsoft/azuredatastudio/issues/1545
|
||||
private _updateInput(): void {
|
||||
/*
|
||||
this._element.getUnsortedChildren().forEach(e => {
|
||||
let origEvent = this._input.sessionTemplate.view.events.find(i => i.name === e.id);
|
||||
if (e.indeterminate) {
|
||||
e.getChildren().forEach(c => {
|
||||
if (origEvent.columns.includes(c.id) && !c.selected) {
|
||||
origEvent.columns = origEvent.columns.filter(i => i !== c.id);
|
||||
} else if (!origEvent.columns.includes(c.id) && c.selected) {
|
||||
origEvent.columns.push(c.id);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
origEvent.columns = e.getChildren()
|
||||
.filter(c => c.selected)
|
||||
.map(c => c.id);
|
||||
}
|
||||
});
|
||||
let newColumns = this._input.sessionTemplate.view.events.reduce<Array<string>>((p, e) => {
|
||||
e.columns.forEach(c => {
|
||||
if (!p.includes(c)) {
|
||||
p.push(c);
|
||||
}
|
||||
});
|
||||
return p;
|
||||
}, []);
|
||||
newColumns.unshift('EventClass');
|
||||
this._input.setColumns(newColumns);
|
||||
*/
|
||||
}
|
||||
|
||||
// currently not used, this dialog is a work in progress
|
||||
// tracked in issue #1545 https://github.com/Microsoft/azuredatastudio/issues/1545
|
||||
private _updateList(): void {
|
||||
/*
|
||||
this._element = new SessionItem(this._input.sessionTemplate.name, this._selectedValue === 0 ? 'event' : 'column');
|
||||
this._input.sessionTemplate.events.forEach(item => {
|
||||
let event = new EventItem(item.name, this._element);
|
||||
item.optionalColumns.forEach(col => {
|
||||
let column = new ColumnItem(col, event);
|
||||
column.selected = this._input.sessionTemplate.view.events.find(i => i.name === event.id).columns.includes(col);
|
||||
event.addColumn(column);
|
||||
});
|
||||
this._element.addEvents(event);
|
||||
});
|
||||
this._tree.setInput(this._element);
|
||||
this._tree.layout(DOM.getTotalHeight(this._treeContainer));
|
||||
*/
|
||||
}
|
||||
|
||||
protected layout(height?: number): void {
|
||||
this._tree.layout(DOM.getContentHeight(this._treeContainer));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,14 +3,14 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ProfilerInput } from 'sql/workbench/contrib/profiler/browser/profilerInput';
|
||||
import { ProfilerInput } from 'sql/workbench/browser/editor/profiler/profilerInput';
|
||||
import { TabbedPanel } from 'sql/base/browser/ui/panel/panel';
|
||||
import { Table } from 'sql/base/browser/ui/table/table';
|
||||
import { TableDataView } from 'sql/base/browser/ui/table/tableDataView';
|
||||
import { IProfilerService, IProfilerViewTemplate } from 'sql/workbench/services/profiler/browser/interfaces';
|
||||
import { Taskbar } from 'sql/base/browser/ui/taskbar/taskbar';
|
||||
import { attachTableStyler } from 'sql/platform/theme/common/styler';
|
||||
import { IProfilerStateChangedEvent } from 'sql/workbench/contrib/profiler/common/profilerState';
|
||||
import { IProfilerStateChangedEvent } from 'sql/workbench/common/editor/profiler/profilerState';
|
||||
import { ProfilerTableEditor, ProfilerTableViewState } from 'sql/workbench/contrib/profiler/browser/profilerTableEditor';
|
||||
import * as Actions from 'sql/workbench/contrib/profiler/browser/profilerActions';
|
||||
import { CONTEXT_PROFILER_EDITOR, PROFILER_TABLE_COMMAND_SEARCH } from 'sql/workbench/contrib/profiler/common/interfaces';
|
||||
|
||||
@@ -1,350 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/profilerFilterDialog';
|
||||
import { Button } from 'sql/base/browser/ui/button/button';
|
||||
import { Modal } from 'sql/workbench/browser/modal/modal';
|
||||
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
|
||||
import { attachButtonStyler, attachInputBoxStyler } from 'sql/platform/theme/common/styler';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ProfilerInput } from 'sql/workbench/contrib/profiler/browser/profilerInput';
|
||||
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox';
|
||||
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox';
|
||||
import { attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { ProfilerFilter, ProfilerFilterClause, ProfilerFilterClauseOperator, IProfilerService } from 'sql/workbench/services/profiler/browser/interfaces';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfigurationService';
|
||||
import { find, firstIndex } from 'vs/base/common/arrays';
|
||||
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { attachModalDialogStyler } from 'sql/workbench/common/styler';
|
||||
|
||||
|
||||
const ClearText: string = localize('profilerFilterDialog.clear', "Clear all");
|
||||
const ApplyText: string = localize('profilerFilterDialog.apply', "Apply");
|
||||
const OkText: string = localize('profilerFilterDialog.ok', "OK");
|
||||
const CancelText: string = localize('profilerFilterDialog.cancel', "Cancel");
|
||||
const DialogTitle: string = localize('profilerFilterDialog.title', "Filters");
|
||||
const RemoveText: string = localize('profilerFilterDialog.remove', "Remove this clause");
|
||||
const SaveFilterText: string = localize('profilerFilterDialog.saveFilter', "Save Filter");
|
||||
const LoadFilterText: string = localize('profilerFilterDialog.loadFilter', "Load Filter");
|
||||
const AddClauseText: string = localize('profilerFilterDialog.addClauseText', "Add a clause");
|
||||
const TitleIconClass: string = 'icon filterLabel';
|
||||
|
||||
const FieldText: string = localize('profilerFilterDialog.fieldColumn', "Field");
|
||||
const OperatorText: string = localize('profilerFilterDialog.operatorColumn', "Operator");
|
||||
const ValueText: string = localize('profilerFilterDialog.valueColumn', "Value");
|
||||
|
||||
const Equals: string = '=';
|
||||
const NotEquals: string = '<>';
|
||||
const LessThan: string = '<';
|
||||
const LessThanOrEquals: string = '<=';
|
||||
const GreaterThan: string = '>';
|
||||
const GreaterThanOrEquals: string = '>=';
|
||||
const IsNull: string = localize('profilerFilterDialog.isNullOperator', "Is Null");
|
||||
const IsNotNull: string = localize('profilerFilterDialog.isNotNullOperator', "Is Not Null");
|
||||
const Contains: string = localize('profilerFilterDialog.containsOperator', "Contains");
|
||||
const NotContains: string = localize('profilerFilterDialog.notContainsOperator', "Not Contains");
|
||||
const StartsWith: string = localize('profilerFilterDialog.startsWithOperator', "Starts With");
|
||||
const NotStartsWith: string = localize('profilerFilterDialog.notStartsWithOperator', "Not Starts With");
|
||||
|
||||
const Operators = [Equals, NotEquals, LessThan, LessThanOrEquals, GreaterThan, GreaterThanOrEquals, GreaterThan, GreaterThanOrEquals, IsNull, IsNotNull, Contains, NotContains, StartsWith, NotStartsWith];
|
||||
|
||||
export class ProfilerFilterDialog extends Modal {
|
||||
|
||||
private _clauseBuilder: HTMLElement;
|
||||
private _okButton: Button;
|
||||
private _cancelButton: Button;
|
||||
private _applyButton: Button;
|
||||
private _loadFilterButton: Button;
|
||||
private _saveFilterButton: Button;
|
||||
private _input: ProfilerInput;
|
||||
private _clauseRows: ClauseRowUI[] = [];
|
||||
|
||||
|
||||
constructor(
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IClipboardService clipboardService: IClipboardService,
|
||||
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
|
||||
@IAdsTelemetryService telemetryService: IAdsTelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@ILogService logService: ILogService,
|
||||
@IContextViewService private contextViewService: IContextViewService,
|
||||
@IProfilerService private profilerService: IProfilerService,
|
||||
@ITextResourcePropertiesService textResourcePropertiesService: ITextResourcePropertiesService
|
||||
) {
|
||||
super('', TelemetryKeys.ProfilerFilter, telemetryService, layoutService, clipboardService, themeService, logService, textResourcePropertiesService, contextKeyService, { isFlyout: false, hasTitleIcon: true });
|
||||
}
|
||||
|
||||
public open(input: ProfilerInput) {
|
||||
this._input = input;
|
||||
this.render();
|
||||
this.show();
|
||||
this._okButton.focus();
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
|
||||
}
|
||||
|
||||
public render() {
|
||||
super.render();
|
||||
this.title = DialogTitle;
|
||||
this.titleIconClassName = TitleIconClass;
|
||||
this._register(attachModalDialogStyler(this, this._themeService));
|
||||
this._saveFilterButton = this.addFooterButton(SaveFilterText, () => this.saveFilter(), 'left');
|
||||
this._loadFilterButton = this.addFooterButton(LoadFilterText, () => this.loadSavedFilter(), 'left');
|
||||
this._applyButton = this.addFooterButton(ApplyText, () => this.filterSession());
|
||||
this._okButton = this.addFooterButton(OkText, () => this.handleOkButtonClick());
|
||||
this._cancelButton = this.addFooterButton(CancelText, () => this.hide());
|
||||
this._register(attachButtonStyler(this._okButton, this._themeService));
|
||||
this._register(attachButtonStyler(this._cancelButton, this._themeService));
|
||||
this._register(attachButtonStyler(this._applyButton, this._themeService));
|
||||
this._register(attachButtonStyler(this._saveFilterButton, this._themeService));
|
||||
this._register(attachButtonStyler(this._loadFilterButton, this._themeService));
|
||||
}
|
||||
|
||||
protected renderBody(container: HTMLElement) {
|
||||
const body = DOM.append(container, DOM.$('.profiler-filter-dialog'));
|
||||
const clauseTableContainer = DOM.append(body, DOM.$('.clause-table-container'));
|
||||
this._clauseBuilder = DOM.append(clauseTableContainer, DOM.$('table.profiler-filter-clause-table'));
|
||||
const headerRow = DOM.append(this._clauseBuilder, DOM.$('tr'));
|
||||
DOM.append(headerRow, DOM.$('td')).innerText = FieldText;
|
||||
DOM.append(headerRow, DOM.$('td')).innerText = OperatorText;
|
||||
DOM.append(headerRow, DOM.$('td')).innerText = ValueText;
|
||||
DOM.append(headerRow, DOM.$('td')).innerText = '';
|
||||
|
||||
this._input.filter.clauses.forEach(clause => {
|
||||
this.addClauseRow(true, clause.field, this.convertToOperatorString(clause.operator), clause.value);
|
||||
});
|
||||
|
||||
this.createClauseTableActionLink(AddClauseText, body, () => { this.addClauseRow(false); });
|
||||
this.createClauseTableActionLink(ClearText, body, () => { this.handleClearButtonClick(); });
|
||||
}
|
||||
|
||||
protected layout(height?: number): void {
|
||||
// Nothing to re-layout
|
||||
}
|
||||
|
||||
/* espace key */
|
||||
protected onClose() {
|
||||
this.hide();
|
||||
}
|
||||
|
||||
/* enter key */
|
||||
protected onAccept() {
|
||||
this.handleOkButtonClick();
|
||||
}
|
||||
|
||||
private handleOkButtonClick(): void {
|
||||
this.filterSession();
|
||||
this.hide();
|
||||
}
|
||||
|
||||
private handleClearButtonClick() {
|
||||
this._clauseRows.forEach(clause => {
|
||||
clause.row.remove();
|
||||
});
|
||||
this._clauseRows = [];
|
||||
}
|
||||
|
||||
private createClauseTableActionLink(text: string, parent: HTMLElement, handler: () => void): void {
|
||||
const actionLink = DOM.append(parent, DOM.$('.profiler-filter-clause-table-action', {
|
||||
'tabIndex': '0',
|
||||
'role': 'button'
|
||||
}));
|
||||
actionLink.innerText = text;
|
||||
DOM.addDisposableListener(actionLink, DOM.EventType.CLICK, handler);
|
||||
DOM.addStandardDisposableListener(actionLink, DOM.EventType.KEY_DOWN, (e: StandardKeyboardEvent) => {
|
||||
if (e.equals(KeyCode.Space) || e.equals(KeyCode.Enter)) {
|
||||
handler();
|
||||
e.stopPropagation();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private createSelectBox(container: HTMLElement, options: string[], selectedOption: string, ariaLabel: string): SelectBox {
|
||||
const dropdown = new SelectBox(options, selectedOption, this.contextViewService, undefined, { ariaLabel: ariaLabel });
|
||||
dropdown.render(container);
|
||||
this._register(attachSelectBoxStyler(dropdown, this._themeService));
|
||||
return dropdown;
|
||||
}
|
||||
|
||||
private filterSession(): void {
|
||||
this._input.filterSession(this.getFilter());
|
||||
}
|
||||
|
||||
private saveFilter(): void {
|
||||
this.profilerService.saveFilter(this.getFilter()).catch(e => onUnexpectedError(e));
|
||||
}
|
||||
|
||||
private loadSavedFilter(): void {
|
||||
// for now we only have one saved filter, this is enough for what user asked for so far.
|
||||
const savedFilters = this.profilerService.getFilters();
|
||||
if (savedFilters && savedFilters.length > 0) {
|
||||
const savedFilter = savedFilters[0];
|
||||
this._clauseRows.forEach(clause => {
|
||||
clause.row.remove();
|
||||
});
|
||||
this._clauseRows = [];
|
||||
savedFilter.clauses.forEach(clause => {
|
||||
this.addClauseRow(true, clause.field, this.convertToOperatorString(clause.operator), clause.value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private getFilter(): ProfilerFilter {
|
||||
const clauses: ProfilerFilterClause[] = [];
|
||||
|
||||
this._clauseRows.forEach(row => {
|
||||
clauses.push({
|
||||
field: row.field.value,
|
||||
operator: this.convertToOperatorEnum(row.operator.value),
|
||||
value: row.value.value
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
name: 'default',
|
||||
clauses: clauses
|
||||
};
|
||||
}
|
||||
|
||||
private addClauseRow(setInitialValue: boolean, field?: string, operator?: string, value?: string): void {
|
||||
const columns = this._input.columns.map(column => column.name);
|
||||
if (field && !find(columns, x => x === field)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const row = DOM.append(this._clauseBuilder, DOM.$('tr'));
|
||||
const clauseId = generateUuid();
|
||||
|
||||
const fieldDropDown = this.createSelectBox(DOM.append(row, DOM.$('td')), columns, columns[0], FieldText);
|
||||
|
||||
const operatorDropDown = this.createSelectBox(DOM.append(row, DOM.$('td')), Operators, Operators[0], OperatorText);
|
||||
|
||||
const valueText = new InputBox(DOM.append(row, DOM.$('td')), undefined, {});
|
||||
this._register(attachInputBoxStyler(valueText, this._themeService));
|
||||
|
||||
const removeCell = DOM.append(row, DOM.$('td'));
|
||||
const removeClauseButton = DOM.append(removeCell, DOM.$('.profiler-filter-remove-condition.codicon.remove', {
|
||||
'tabIndex': '0',
|
||||
'aria-label': RemoveText,
|
||||
'title': RemoveText,
|
||||
'role': 'button'
|
||||
}));
|
||||
|
||||
DOM.addStandardDisposableListener(removeClauseButton, DOM.EventType.KEY_DOWN, (e: StandardKeyboardEvent) => {
|
||||
if (e.equals(KeyCode.Space) || e.equals(KeyCode.Enter)) {
|
||||
this.removeRow(clauseId);
|
||||
e.stopPropagation();
|
||||
}
|
||||
});
|
||||
|
||||
DOM.addDisposableListener(removeClauseButton, DOM.EventType.CLICK, (e: MouseEvent) => {
|
||||
this.removeRow(clauseId);
|
||||
});
|
||||
|
||||
if (setInitialValue) {
|
||||
fieldDropDown.selectWithOptionName(field);
|
||||
operatorDropDown.selectWithOptionName(operator);
|
||||
valueText.value = value;
|
||||
}
|
||||
|
||||
this._clauseRows.push({
|
||||
id: clauseId,
|
||||
row,
|
||||
field: fieldDropDown,
|
||||
operator: operatorDropDown,
|
||||
value: valueText
|
||||
});
|
||||
}
|
||||
|
||||
private removeRow(clauseId: string) {
|
||||
const idx = firstIndex(this._clauseRows, (entry) => { return entry.id === clauseId; });
|
||||
if (idx !== -1) {
|
||||
this._clauseRows[idx].row.remove();
|
||||
this._clauseRows.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
private convertToOperatorEnum(operator: string): ProfilerFilterClauseOperator {
|
||||
switch (operator) {
|
||||
case Equals:
|
||||
return ProfilerFilterClauseOperator.Equals;
|
||||
case NotEquals:
|
||||
return ProfilerFilterClauseOperator.NotEquals;
|
||||
case LessThan:
|
||||
return ProfilerFilterClauseOperator.LessThan;
|
||||
case LessThanOrEquals:
|
||||
return ProfilerFilterClauseOperator.LessThanOrEquals;
|
||||
case GreaterThan:
|
||||
return ProfilerFilterClauseOperator.GreaterThan;
|
||||
case GreaterThanOrEquals:
|
||||
return ProfilerFilterClauseOperator.GreaterThanOrEquals;
|
||||
case IsNull:
|
||||
return ProfilerFilterClauseOperator.IsNull;
|
||||
case IsNotNull:
|
||||
return ProfilerFilterClauseOperator.IsNotNull;
|
||||
case Contains:
|
||||
return ProfilerFilterClauseOperator.Contains;
|
||||
case NotContains:
|
||||
return ProfilerFilterClauseOperator.NotContains;
|
||||
case StartsWith:
|
||||
return ProfilerFilterClauseOperator.StartsWith;
|
||||
case NotStartsWith:
|
||||
return ProfilerFilterClauseOperator.NotStartsWith;
|
||||
default:
|
||||
throw new Error(`Not a valid operator: ${operator}`);
|
||||
}
|
||||
}
|
||||
|
||||
private convertToOperatorString(operator: ProfilerFilterClauseOperator): string {
|
||||
switch (operator) {
|
||||
case ProfilerFilterClauseOperator.Equals:
|
||||
return Equals;
|
||||
case ProfilerFilterClauseOperator.NotEquals:
|
||||
return NotEquals;
|
||||
case ProfilerFilterClauseOperator.LessThan:
|
||||
return LessThan;
|
||||
case ProfilerFilterClauseOperator.LessThanOrEquals:
|
||||
return LessThanOrEquals;
|
||||
case ProfilerFilterClauseOperator.GreaterThan:
|
||||
return GreaterThan;
|
||||
case ProfilerFilterClauseOperator.GreaterThanOrEquals:
|
||||
return GreaterThanOrEquals;
|
||||
case ProfilerFilterClauseOperator.IsNull:
|
||||
return IsNull;
|
||||
case ProfilerFilterClauseOperator.IsNotNull:
|
||||
return IsNotNull;
|
||||
case ProfilerFilterClauseOperator.Contains:
|
||||
return Contains;
|
||||
case ProfilerFilterClauseOperator.NotContains:
|
||||
return NotContains;
|
||||
case ProfilerFilterClauseOperator.StartsWith:
|
||||
return StartsWith;
|
||||
case ProfilerFilterClauseOperator.NotStartsWith:
|
||||
return NotStartsWith;
|
||||
default:
|
||||
throw new Error(`Not a valid operator: ${operator}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface ClauseRowUI {
|
||||
id: string;
|
||||
row: HTMLElement;
|
||||
field: SelectBox;
|
||||
operator: SelectBox;
|
||||
value: InputBox;
|
||||
}
|
||||
@@ -1,290 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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/contrib/profiler/common/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);
|
||||
}
|
||||
}
|
||||
@@ -4,11 +4,11 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IProfilerController } from 'sql/workbench/contrib/profiler/common/interfaces';
|
||||
import { ProfilerInput } from 'sql/workbench/contrib/profiler/browser/profilerInput';
|
||||
import { ProfilerInput } from 'sql/workbench/browser/editor/profiler/profilerInput';
|
||||
import { Table } from 'sql/base/browser/ui/table/table';
|
||||
import { attachTableStyler } from 'sql/platform/theme/common/styler';
|
||||
import { RowSelectionModel } from 'sql/base/browser/ui/table/plugins/rowSelectionModel.plugin';
|
||||
import { IProfilerStateChangedEvent } from 'sql/workbench/contrib/profiler/common/profilerState';
|
||||
import { IProfilerStateChangedEvent } from 'sql/workbench/common/editor/profiler/profilerState';
|
||||
import { FindWidget, ITableController, IConfigurationChangedEvent, ACTION_IDS, PROFILER_MAX_MATCHES } from 'sql/workbench/contrib/profiler/browser/profilerFindWidget';
|
||||
import { ProfilerFindNext, ProfilerFindPrevious } from 'sql/workbench/contrib/profiler/browser/profilerActions';
|
||||
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
|
||||
export interface IProfilerStateChangedEvent {
|
||||
isConnected?: boolean;
|
||||
isRunning?: boolean;
|
||||
isPaused?: boolean;
|
||||
isStopped?: boolean;
|
||||
autoscroll?: boolean;
|
||||
isPanelCollapsed?: boolean;
|
||||
}
|
||||
|
||||
export interface INewProfilerState {
|
||||
isConnected?: boolean;
|
||||
isRunning?: boolean;
|
||||
isPaused?: boolean;
|
||||
isStopped?: boolean;
|
||||
autoscroll?: boolean;
|
||||
isPanelCollapsed?: boolean;
|
||||
}
|
||||
|
||||
export class ProfilerState implements IDisposable {
|
||||
|
||||
private _isConnected: boolean;
|
||||
private _isRunning: boolean;
|
||||
private _isPaused: boolean;
|
||||
private _isStopped: boolean;
|
||||
private _autoscroll: boolean;
|
||||
private _isPanelCollapsed = true;
|
||||
|
||||
public get isConnected(): boolean { return this._isConnected; }
|
||||
public get isRunning(): boolean { return this._isRunning; }
|
||||
public get isPaused(): boolean { return this._isPaused; }
|
||||
public get isStopped(): boolean { return this._isStopped; }
|
||||
public get autoscroll(): boolean { return this._autoscroll; }
|
||||
public get isPanelCollapsed(): boolean { return this._isPanelCollapsed; }
|
||||
|
||||
private readonly _onProfilerStateChange = new Emitter<IProfilerStateChangedEvent>();
|
||||
public readonly onProfilerStateChange = this._onProfilerStateChange.event;
|
||||
|
||||
public dispose(): void {
|
||||
}
|
||||
|
||||
public change(newState: INewProfilerState): void {
|
||||
let changeEvent: IProfilerStateChangedEvent = {
|
||||
isConnected: false,
|
||||
isRunning: false,
|
||||
isPaused: false,
|
||||
isStopped: false,
|
||||
autoscroll: false,
|
||||
isPanelCollapsed: false
|
||||
};
|
||||
let somethingChanged = false;
|
||||
|
||||
if (typeof newState.isConnected !== 'undefined') {
|
||||
if (this._isConnected !== newState.isConnected) {
|
||||
this._isConnected = newState.isConnected;
|
||||
changeEvent.isConnected = true;
|
||||
somethingChanged = true;
|
||||
}
|
||||
}
|
||||
if (typeof newState.isRunning !== 'undefined') {
|
||||
if (this._isRunning !== newState.isRunning) {
|
||||
this._isRunning = newState.isRunning;
|
||||
changeEvent.isRunning = true;
|
||||
somethingChanged = true;
|
||||
}
|
||||
}
|
||||
if (typeof newState.isPaused !== 'undefined') {
|
||||
if (this._isPaused !== newState.isPaused) {
|
||||
this._isPaused = newState.isPaused;
|
||||
changeEvent.isPaused = true;
|
||||
somethingChanged = true;
|
||||
}
|
||||
}
|
||||
if (typeof newState.isStopped !== 'undefined') {
|
||||
if (this._isStopped !== newState.isStopped) {
|
||||
this._isStopped = newState.isStopped;
|
||||
changeEvent.isStopped = true;
|
||||
somethingChanged = true;
|
||||
}
|
||||
}
|
||||
if (typeof newState.autoscroll !== 'undefined') {
|
||||
if (this._autoscroll !== newState.autoscroll) {
|
||||
this._autoscroll = newState.autoscroll;
|
||||
changeEvent.autoscroll = true;
|
||||
somethingChanged = true;
|
||||
}
|
||||
}
|
||||
if (typeof newState.isPanelCollapsed !== 'undefined') {
|
||||
if (this._isPanelCollapsed !== newState.isPanelCollapsed) {
|
||||
this._isPanelCollapsed = newState.isPanelCollapsed;
|
||||
changeEvent.isPanelCollapsed = true;
|
||||
somethingChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (somethingChanged) {
|
||||
this._onProfilerStateChange.fire(changeEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user