diff --git a/src/sql/azdata.proposed.d.ts b/src/sql/azdata.proposed.d.ts index 802e472a9a..27722342bd 100644 --- a/src/sql/azdata.proposed.d.ts +++ b/src/sql/azdata.proposed.d.ts @@ -1369,6 +1369,29 @@ declare module 'azdata' { * Display value of property to show in tooltip and other UI element. */ displayValue: string; + /** + * Data type of the property value + */ + dataType: ExecutionPlanGraphElementPropertyDataType; + /** + * Indicates which value is better when 2 similar properties are compared. + */ + betterValue: ExecutionPlanGraphElementPropertyBetterValue; + } + + export enum ExecutionPlanGraphElementPropertyDataType { + Number = 0, + String = 1, + Boolean = 2, + Nested = 3 + } + + export enum ExecutionPlanGraphElementPropertyBetterValue { + LowerNumber = 0, + HigherNumber = 1, + True = 2, + False = 3, + None = 4 } export interface ExecutionPlanRecommendations { diff --git a/src/sql/base/browser/ui/table/formatters.ts b/src/sql/base/browser/ui/table/formatters.ts index a1596b303b..dc61c62cab 100644 --- a/src/sql/base/browser/ui/table/formatters.ts +++ b/src/sql/base/browser/ui/table/formatters.ts @@ -90,7 +90,6 @@ export function textFormatter(row: number | undefined, cell: any | undefined, va let valueToDisplay = ''; let titleValue = ''; let cellStyle = ''; - if (DBCellValue.isDBCellValue(value)) { valueToDisplay = 'NULL'; if (!value.isNull) { diff --git a/src/sql/base/browser/ui/table/plugins/textWithIconColumn.ts b/src/sql/base/browser/ui/table/plugins/textWithIconColumn.ts index a6d654d741..26f9e49ad3 100644 --- a/src/sql/base/browser/ui/table/plugins/textWithIconColumn.ts +++ b/src/sql/base/browser/ui/table/plugins/textWithIconColumn.ts @@ -20,7 +20,8 @@ export class TextWithIconColumn implements TableColum resizable: this.options.resizable, formatter: (row: number, cell: number, value: any, columnDef: Slick.Column, dataContext: T): string => { const iconValue = getIconCellValue(this.options, dataContext); - return `
${escape(iconValue.title ?? '')}
`; + const titleValue = escape(iconValue.title ?? ''); + return `
${titleValue}
`; }, width: this.options.width, name: this.options.name, diff --git a/src/sql/workbench/api/common/sqlExtHost.api.impl.ts b/src/sql/workbench/api/common/sqlExtHost.api.impl.ts index 3dd992d470..3b8754c80a 100644 --- a/src/sql/workbench/api/common/sqlExtHost.api.impl.ts +++ b/src/sql/workbench/api/common/sqlExtHost.api.impl.ts @@ -597,7 +597,9 @@ export function createAdsApiFactory(accessor: ServicesAccessor): IAdsExtensionAp }; const executionPlan: typeof azdata.executionPlan = { - BadgeType: sqlExtHostTypes.executionPlan.BadgeType + BadgeType: sqlExtHostTypes.executionPlan.BadgeType, + ExecutionPlanGraphElementPropertyDataType: sqlExtHostTypes.executionPlan.ExecutionPlanGraphElementPropertyDataType, + ExecutionPlanGraphElementPropertyBetterValue: sqlExtHostTypes.executionPlan.ExecutionPlanGraphElementPropertyBetterValue }; return { diff --git a/src/sql/workbench/api/common/sqlExtHostTypes.ts b/src/sql/workbench/api/common/sqlExtHostTypes.ts index 82ebf727a9..a737696126 100644 --- a/src/sql/workbench/api/common/sqlExtHostTypes.ts +++ b/src/sql/workbench/api/common/sqlExtHostTypes.ts @@ -1041,4 +1041,19 @@ export namespace executionPlan { CriticalWarning = 1, Parallelism = 2 } + + export enum ExecutionPlanGraphElementPropertyDataType { + Number = 0, + String = 1, + Boolean = 2, + Nested = 3 + } + + export enum ExecutionPlanGraphElementPropertyBetterValue { + LowerNumber = 0, + HigherNumber = 1, + True = 2, + False = 3, + None = 4 + } } diff --git a/src/sql/workbench/contrib/executionPlan/browser/compareExecutionPlanInput.ts b/src/sql/workbench/contrib/executionPlan/browser/compareExecutionPlanInput.ts index 5b21c5f160..59790d01a4 100644 --- a/src/sql/workbench/contrib/executionPlan/browser/compareExecutionPlanInput.ts +++ b/src/sql/workbench/contrib/executionPlan/browser/compareExecutionPlanInput.ts @@ -53,5 +53,7 @@ export class ExecutionPlanComparisonInput extends EditorInput { export interface ExecutionPlanComparisonEditorModel { topExecutionPlan?: azdata.executionPlan.ExecutionPlanGraph[]; + topPlanIndex?: number; bottomExecutionPlan?: azdata.executionPlan.ExecutionPlanGraph[]; + bottomPlanIndex?: number; } diff --git a/src/sql/workbench/contrib/executionPlan/browser/constants.ts b/src/sql/workbench/contrib/executionPlan/browser/constants.ts index 1ff84cad82..039ddf87c7 100644 --- a/src/sql/workbench/contrib/executionPlan/browser/constants.ts +++ b/src/sql/workbench/contrib/executionPlan/browser/constants.ts @@ -279,6 +279,11 @@ export const splitScreenHorizontallyIconClassName = 'ep-split-screen-horizontall export const splitScreenVerticallyIconClassName = 'ep-split-screen-vertically-icon'; export const resetZoomIconClassName = 'ep-reset-zoom-icon'; export const executionPlanCompareIconClassName = 'ep-plan-compare-icon'; +export const executionPlanComparisonPropertiesDifferent = 'ep-properties-different'; +export const executionPlanComparisonPropertiesRedDownArrow = 'ep-properties-red-down-arrow'; +export const executionPlanComparisonPropertiesGreenDownArrow = 'ep-properties-green-down-arrow'; +export const executionPlanComparisonPropertiesRedUpArrow = 'ep-properties-red-up-arrow'; +export const executionPlanComparisonPropertiesGreenUpArrow = 'ep-properties-green-up-arrow'; /** * Plan comparison polygon border colors diff --git a/src/sql/workbench/contrib/executionPlan/browser/executionPlanComparisonEditor.ts b/src/sql/workbench/contrib/executionPlan/browser/executionPlanComparisonEditor.ts index eee77f459e..a8295c5dc6 100644 --- a/src/sql/workbench/contrib/executionPlan/browser/executionPlanComparisonEditor.ts +++ b/src/sql/workbench/contrib/executionPlan/browser/executionPlanComparisonEditor.ts @@ -69,10 +69,10 @@ export class ExecutionPlanComparisonEditor extends EditorPane { input._executionPlanComparisonView = this._instantiationService.createInstance(ExecutionPlanComparisonEditorView, this._editorContainer); if (this.input.preloadModel) { if (this.input.preloadModel.topExecutionPlan) { - input._executionPlanComparisonView.addExecutionPlanGraph(this.input.preloadModel.topExecutionPlan); + input._executionPlanComparisonView.addExecutionPlanGraph(this.input.preloadModel.topExecutionPlan, this.input.preloadModel.topPlanIndex); } if (this.input.preloadModel.bottomExecutionPlan) { - input._executionPlanComparisonView.addExecutionPlanGraph(this.input.preloadModel.bottomExecutionPlan); + input._executionPlanComparisonView.addExecutionPlanGraph(this.input.preloadModel.bottomExecutionPlan, this.input.preloadModel.bottomPlanIndex); } } } else { // Getting the cached comparison view from the input and adding it to the base editor node. diff --git a/src/sql/workbench/contrib/executionPlan/browser/executionPlanComparisonEditorView.ts b/src/sql/workbench/contrib/executionPlan/browser/executionPlanComparisonEditorView.ts index cad9d911f1..da489a823c 100644 --- a/src/sql/workbench/contrib/executionPlan/browser/executionPlanComparisonEditorView.ts +++ b/src/sql/workbench/contrib/executionPlan/browser/executionPlanComparisonEditorView.ts @@ -29,6 +29,7 @@ import { errorForeground, listHoverBackground, textLinkForeground } from 'vs/pla import { ExecutionPlanViewHeader } from 'sql/workbench/contrib/executionPlan/browser/executionPlanViewHeader'; import { attachSelectBoxStyler } from 'sql/platform/theme/common/styler'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; +import { generateUuid } from 'vs/base/common/uuid'; import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry'; export class ExecutionPlanComparisonEditorView { @@ -92,7 +93,7 @@ export class ExecutionPlanComparisonEditorView { private _activeBottomPlanIndex: number = 0; private _bottomPlanRecommendations: ExecutionPlanViewHeader; private _bottomSimilarNode: Map = new Map(); - + private _latestRequestUuid: string; private get _activeBottomPlanDiagram(): AzdataGraphView { if (this.bottomPlanDiagrams.length > 0) { @@ -101,6 +102,10 @@ export class ExecutionPlanComparisonEditorView { return undefined; } + private createQueryDropdownPrefixString(query: string, index: number, totalQueries: number): string { + return localize('queryDropdownPrefix', "Query {0} of {1}: {2}", index, totalQueries, query); + } + constructor( parentContainer: HTMLElement, @IInstantiationService private _instantiationService: IInstantiationService, @@ -180,7 +185,9 @@ export class ExecutionPlanComparisonEditorView { this._topPlanDropdown = new SelectBox(['option 1', 'option2'], 'option1', this.contextViewService, this._topPlanDropdownContainer); this._topPlanDropdown.render(this._topPlanDropdownContainer); this._topPlanDropdown.onDidSelect(async (e) => { - this._activeBottomPlanDiagram.clearSubtreePolygon(); + if (this._activeBottomPlanDiagram) { + this._activeBottomPlanDiagram.clearSubtreePolygon(); + } this._activeTopPlanDiagram.clearSubtreePolygon(); this._topPlanDiagramContainers.forEach(c => { c.style.display = 'none'; @@ -205,7 +212,9 @@ export class ExecutionPlanComparisonEditorView { this._bottomPlanDropdown.render(this._bottomPlanDropdownContainer); this._bottomPlanDropdown.onDidSelect(async (e) => { this._activeBottomPlanDiagram.clearSubtreePolygon(); - this._activeTopPlanDiagram.clearSubtreePolygon(); + if (this._activeTopPlanDiagram) { + this._activeTopPlanDiagram.clearSubtreePolygon(); + } this._bottomPlanDiagramContainers.forEach(c => { c.style.display = 'none'; }); @@ -285,7 +294,7 @@ export class ExecutionPlanComparisonEditorView { graphFileContent: fileContent, graphFileType: extname(fileURI.fsPath).replace('.', '') }); - await this.addExecutionPlanGraph(executionPlanGraphs.graphs); + await this.addExecutionPlanGraph(executionPlanGraphs.graphs, 0); } this._placeholderInfoboxContainer.style.display = ''; this._placeholderLoading.loading = false; @@ -297,14 +306,14 @@ export class ExecutionPlanComparisonEditorView { } - public async addExecutionPlanGraph(executionPlanGraphs: azdata.executionPlan.ExecutionPlanGraph[]): Promise { + public async addExecutionPlanGraph(executionPlanGraphs: azdata.executionPlan.ExecutionPlanGraph[], preSelectIndex: number): Promise { if (!this._topPlanDiagramModels) { this._topPlanDiagramModels = executionPlanGraphs; - this._topPlanDropdown.setOptions(executionPlanGraphs.map(e => { + this._topPlanDropdown.setOptions(executionPlanGraphs.map((e, index) => { return { - text: e.query + text: this.createQueryDropdownPrefixString(e.query, index + 1, executionPlanGraphs.length) }; - }), 0); + })); executionPlanGraphs.forEach((e, i) => { const graphContainer = DOM.$('.plan-diagram'); @@ -326,10 +335,7 @@ export class ExecutionPlanComparisonEditorView { this.topPlanDiagrams.push(diagram); graphContainer.style.display = 'none'; }); - - this._topPlanDiagramContainers[0].style.display = ''; - this._topPlanRecommendations.recommendations = executionPlanGraphs[0].recommendations; - this.topPlanDiagrams[0].selectElement(undefined); + this._topPlanDropdown.select(preSelectIndex); this._propertiesView.setTopElement(executionPlanGraphs[0].root); this._propertiesAction.enabled = true; this._zoomInAction.enabled = true; @@ -339,11 +345,11 @@ export class ExecutionPlanComparisonEditorView { this._toggleOrientationAction.enabled = true; } else { this._bottomPlanDiagramModels = executionPlanGraphs; - this._bottomPlanDropdown.setOptions(executionPlanGraphs.map(e => { + this._bottomPlanDropdown.setOptions(executionPlanGraphs.map((e, index) => { return { - text: e.query + text: this.createQueryDropdownPrefixString(e.query, index + 1, executionPlanGraphs.length) }; - }), 0); + })); executionPlanGraphs.forEach((e, i) => { const graphContainer = DOM.$('.plan-diagram'); this._bottomPlanDiagramContainers.push(graphContainer); @@ -364,18 +370,17 @@ export class ExecutionPlanComparisonEditorView { this.bottomPlanDiagrams.push(diagram); graphContainer.style.display = 'none'; }); - - this._bottomPlanDiagramContainers[0].style.display = ''; - this._bottomPlanRecommendations.recommendations = executionPlanGraphs[0].recommendations; - this.bottomPlanDiagrams[0].selectElement(undefined); + this._bottomPlanDropdown.select(preSelectIndex); this._propertiesView.setBottomElement(executionPlanGraphs[0].root); this._addExecutionPlanAction.enabled = false; - await this.getSkeletonNodes(); } this.refreshSplitView(); } private async getSkeletonNodes(): Promise { + if (!this._activeBottomPlanDiagram) { + return; + } this._progressService.withProgress( { location: ProgressLocation.Notification, @@ -389,8 +394,14 @@ export class ExecutionPlanComparisonEditorView { if (this._topPlanDiagramModels && this._bottomPlanDiagramModels) { this._topPlanDiagramModels[this._activeTopPlanIndex].graphFile.graphFileType = 'sqlplan'; this._bottomPlanDiagramModels[this._activeBottomPlanIndex].graphFile.graphFileType = 'sqlplan'; + + const currentRequestId = generateUuid(); + this._latestRequestUuid = currentRequestId; const result = await this._executionPlanService.compareExecutionPlanGraph(this._topPlanDiagramModels[this._activeTopPlanIndex].graphFile, this._bottomPlanDiagramModels[this._activeBottomPlanIndex].graphFile); + if (currentRequestId !== this._latestRequestUuid) { + return; + } this.getSimilarSubtrees(result.firstComparisonResult); this.getSimilarSubtrees(result.secondComparisonResult, true); let colorIndex = 0; diff --git a/src/sql/workbench/contrib/executionPlan/browser/executionPlanComparisonPropertiesView.ts b/src/sql/workbench/contrib/executionPlan/browser/executionPlanComparisonPropertiesView.ts index 0ac75875a2..5b89c88cc0 100644 --- a/src/sql/workbench/contrib/executionPlan/browser/executionPlanComparisonPropertiesView.ts +++ b/src/sql/workbench/contrib/executionPlan/browser/executionPlanComparisonPropertiesView.ts @@ -5,13 +5,16 @@ import { ExecutionPlanPropertiesViewBase, PropertiesSortType } from 'sql/workbench/contrib/executionPlan/browser/executionPlanPropertiesViewBase'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import type * as azdata from 'azdata'; +import * as azdata from 'azdata'; import { localize } from 'vs/nls'; import { textFormatter } from 'sql/base/browser/ui/table/formatters'; import { isString } from 'vs/base/common/types'; import { removeLineBreaks } from 'sql/base/common/strings'; import * as DOM from 'vs/base/browser/dom'; import { InternalExecutionPlanElement } from 'sql/workbench/contrib/executionPlan/browser/azdataGraphView'; +import { executionPlanComparisonPropertiesDifferent, executionPlanComparisonPropertiesGreenDownArrow, executionPlanComparisonPropertiesRedDownArrow, executionPlanComparisonPropertiesGreenUpArrow, executionPlanComparisonPropertiesRedUpArrow } from 'sql/workbench/contrib/executionPlan/browser/constants'; +import * as sqlExtHostType from 'sql/workbench/api/common/sqlExtHostTypes'; +import { TextWithIconColumn } from 'sql/base/browser/ui/table/plugins/textWithIconColumn'; export class ExecutionPlanComparisonPropertiesView extends ExecutionPlanPropertiesViewBase { private _model: ExecutionPlanComparisonPropertiesViewModel; @@ -44,7 +47,7 @@ export class ExecutionPlanComparisonPropertiesView extends ExecutionPlanProperti } const titleText = localize('executionPlanComparisonPropertiesTopOperation', "Top operation: {0}", target); this._topOperationNameContainer.innerText = titleText; - this._bottomOperationNameContainer.title = titleText; + this._topOperationNameContainer.title = titleText; this.addDataToTable(); } @@ -88,15 +91,13 @@ export class ExecutionPlanComparisonPropertiesView extends ExecutionPlanProperti }); } if (this._model.bottomElement) { - columns.push({ + columns.push(new TextWithIconColumn({ id: 'value', name: localize('nodePropertyViewNameValueColumnBottomHeader', "Value (Bottom Plan)"), field: 'value2', width: 150, - editor: Slick.Editors.Text, headerCssClass: 'prop-table-header', - formatter: textFormatter - }); + }).definition); } let topProps = []; @@ -204,19 +205,55 @@ export class ExecutionPlanComparisonPropertiesView extends ExecutionPlanProperti const topProp = v.topProp; const bottomProp = v.bottomProp; const parentRowCellStyling = 'font-weight: bold'; - + let diffIconClass = 'default-bottom-column-cell-styling'; if (topProp && bottomProp) { row['displayOrder'] = v.topProp.displayOrder; + if (v.topProp.displayValue !== v.bottomProp.displayValue) { + switch (v.topProp.betterValue) { + case sqlExtHostType.executionPlan.ExecutionPlanGraphElementPropertyBetterValue.None: + diffIconClass = executionPlanComparisonPropertiesDifferent; + break; + case sqlExtHostType.executionPlan.ExecutionPlanGraphElementPropertyBetterValue.LowerNumber: + if (parseFloat(v.bottomProp.displayValue) < parseFloat(v.topProp.displayValue)) { + diffIconClass = executionPlanComparisonPropertiesGreenDownArrow; + } else { + diffIconClass = executionPlanComparisonPropertiesRedUpArrow; + } + break; + case sqlExtHostType.executionPlan.ExecutionPlanGraphElementPropertyBetterValue.HigherNumber: + if (parseFloat(v.bottomProp.displayValue) > parseFloat(v.topProp.displayValue)) { + diffIconClass = executionPlanComparisonPropertiesGreenUpArrow; + } else { + diffIconClass = executionPlanComparisonPropertiesRedDownArrow; + } + break; + case sqlExtHostType.executionPlan.ExecutionPlanGraphElementPropertyBetterValue.True: + if (v.bottomProp.displayValue === 'True') { + diffIconClass = executionPlanComparisonPropertiesGreenUpArrow; + } else { + diffIconClass = executionPlanComparisonPropertiesRedDownArrow; + } + break; + case sqlExtHostType.executionPlan.ExecutionPlanGraphElementPropertyBetterValue.False: + if (v.bottomProp.displayValue === 'False') { + diffIconClass = executionPlanComparisonPropertiesGreenDownArrow; + } else { + diffIconClass = executionPlanComparisonPropertiesRedUpArrow; + } + break; + } + } row['value1'] = { text: removeLineBreaks(v.topProp.displayValue, ' ') }; row['value2'] = { - text: removeLineBreaks(v.bottomProp.displayValue, ' ') + iconCssClass: diffIconClass, + title: removeLineBreaks(v.bottomProp.displayValue, ' ') }; if ((topProp && !isString(topProp.value)) || (bottomProp && !isString(bottomProp.value))) { row['name'].style = parentRowCellStyling; row['value1'].style = parentRowCellStyling; - row['value2'].style = parentRowCellStyling; + row['value2'].iconCssClass += ` parent-row-styling`; } rows.push(row); if (!isString(topProp.value) && !isString(bottomProp.value)) { @@ -240,12 +277,13 @@ export class ExecutionPlanComparisonPropertiesView extends ExecutionPlanProperti } else if (!topProp && bottomProp) { row['displayOrder'] = v.bottomProp.displayOrder; row['value2'] = { - text: v.bottomProp.displayValue + title: v.bottomProp.displayValue, + iconCssClass: diffIconClass }; rows.push(row); if (!isString(bottomProp.value)) { row['name'].style = parentRowCellStyling; - row['value2'].style = parentRowCellStyling; + row['value2'].iconCssClass += ` parent-row-styling`; this.convertPropertiesToTableRows(undefined, bottomProp.value, rows.length - 1, indent + 2, rows); } } diff --git a/src/sql/workbench/contrib/executionPlan/browser/executionPlanFileView.ts b/src/sql/workbench/contrib/executionPlan/browser/executionPlanFileView.ts index b7a9d258e6..966117b0bc 100644 --- a/src/sql/workbench/contrib/executionPlan/browser/executionPlanFileView.ts +++ b/src/sql/workbench/contrib/executionPlan/browser/executionPlanFileView.ts @@ -19,7 +19,7 @@ export class ExecutionPlanFileView { private _loadingSpinner: LoadingSpinner; private _loadingErrorInfoBox: InfoBox; private _executionPlanViews: ExecutionPlanView[] = []; - private _graphs?: azdata.executionPlan.ExecutionPlanGraph[] = []; + public graphs?: azdata.executionPlan.ExecutionPlanGraph[] = []; private _container = DOM.$('.eps-container'); private _planCache: Map = new Map(); @@ -56,10 +56,10 @@ export class ExecutionPlanFileView { public addGraphs(newGraphs: azdata.executionPlan.ExecutionPlanGraph[] | undefined) { if (newGraphs) { newGraphs.forEach(g => { - const ep = this.instantiationService.createInstance(ExecutionPlanView, this._container, this._executionPlanViews.length + 1); + const ep = this.instantiationService.createInstance(ExecutionPlanView, this._container, this._executionPlanViews.length + 1, this); ep.model = g; this._executionPlanViews.push(ep); - this._graphs.push(g); + this.graphs.push(g); this.updateRelativeCosts(); }); } @@ -104,7 +104,7 @@ export class ExecutionPlanFileView { } private updateRelativeCosts() { - const sum = this._graphs.reduce((prevCost: number, cg) => { + const sum = this.graphs.reduce((prevCost: number, cg) => { return prevCost += cg.root.subTreeCost + cg.root.cost; }, 0); diff --git a/src/sql/workbench/contrib/executionPlan/browser/executionPlanPropertiesViewBase.ts b/src/sql/workbench/contrib/executionPlan/browser/executionPlanPropertiesViewBase.ts index 1d07094be8..567e1c5000 100644 --- a/src/sql/workbench/contrib/executionPlan/browser/executionPlanPropertiesViewBase.ts +++ b/src/sql/workbench/contrib/executionPlan/browser/executionPlanPropertiesViewBase.ts @@ -227,7 +227,7 @@ export class SortPropertiesReverseAlphabeticallyAction extends Action { export class SortPropertiesByDisplayOrderAction extends Action { public static ID = 'ep.propertiesView.sortByDisplayOrder'; - public static LABEL = localize('executionPlanPropertyViewSortByDisplayOrder', "Categorized"); + public static LABEL = localize('executionPlanPropertyViewSortByDisplayOrder', "Importance"); constructor() { super(SortPropertiesByDisplayOrderAction.ID, SortPropertiesByDisplayOrderAction.LABEL, sortByDisplayOrderIconClassNames); diff --git a/src/sql/workbench/contrib/executionPlan/browser/executionPlanView.ts b/src/sql/workbench/contrib/executionPlan/browser/executionPlanView.ts index d308fcb808..55b2e2d146 100644 --- a/src/sql/workbench/contrib/executionPlan/browser/executionPlanView.ts +++ b/src/sql/workbench/contrib/executionPlan/browser/executionPlanView.ts @@ -36,6 +36,7 @@ import { AzdataGraphView } from 'sql/workbench/contrib/executionPlan/browser/azd import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry'; import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys'; import { ExecutionPlanComparisonInput } from 'sql/workbench/contrib/executionPlan/browser/compareExecutionPlanInput'; +import { ExecutionPlanFileView } from 'sql/workbench/contrib/executionPlan/browser/executionPlanFileView'; export class ExecutionPlanView implements ISashLayoutProvider { @@ -70,6 +71,7 @@ export class ExecutionPlanView implements ISashLayoutProvider { constructor( private _parent: HTMLElement, private _graphIndex: number, + private _executionPlanFileView: ExecutionPlanFileView, @IInstantiationService public readonly _instantiationService: IInstantiationService, @IThemeService private readonly _themeService: IThemeService, @IContextViewService public readonly contextViewService: IContextViewService, @@ -285,7 +287,8 @@ export class ExecutionPlanView implements ISashLayoutProvider { public compareCurrentExecutionPlan() { this._editorService.openEditor(this._instantiationService.createInstance(ExecutionPlanComparisonInput, { - topExecutionPlan: [this._model] + topExecutionPlan: this._executionPlanFileView.graphs, + topPlanIndex: this._graphIndex - 1 }), { pinned: true }); diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/addDark.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/addDark.svg new file mode 100644 index 0000000000..2614ef210e --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/addDark.svg @@ -0,0 +1 @@ +Add_16x diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/customZoomDark.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/customZoomDark.svg new file mode 100644 index 0000000000..0fa913155a --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/customZoomDark.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/differentValues.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/differentValues.svg new file mode 100644 index 0000000000..2a6f0839ca --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/differentValues.svg @@ -0,0 +1 @@ + diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/disableTooltipDark.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/disableTooltipDark.svg new file mode 100644 index 0000000000..fd5137b60a --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/disableTooltipDark.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/downArrowBetter.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/downArrowBetter.svg new file mode 100644 index 0000000000..2be736504e --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/downArrowBetter.svg @@ -0,0 +1 @@ + diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/downArrowWorse.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/downArrowWorse.svg new file mode 100644 index 0000000000..e9bd826458 --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/downArrowWorse.svg @@ -0,0 +1 @@ + diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/enableTooltipDark.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/enableTooltipDark.svg new file mode 100644 index 0000000000..49ea8b8588 --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/enableTooltipDark.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/execution-plan-compareDark.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/execution-plan-compareDark.svg new file mode 100644 index 0000000000..5a83502b85 --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/execution-plan-compareDark.svg @@ -0,0 +1 @@ +BranchCompare_16x diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/openPlanFileDark.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/openPlanFileDark.svg new file mode 100644 index 0000000000..c80f2d21e5 --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/openPlanFileDark.svg @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/openPropertiesDark.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/openPropertiesDark.svg new file mode 100644 index 0000000000..a99ec3e65f --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/openPropertiesDark.svg @@ -0,0 +1 @@ + diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/openQueryDark.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/openQueryDark.svg new file mode 100644 index 0000000000..54e69bbe39 --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/openQueryDark.svg @@ -0,0 +1,19 @@ + + + + + + + + + + diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/resetZoomDark.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/resetZoomDark.svg new file mode 100644 index 0000000000..03c6343142 --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/resetZoomDark.svg @@ -0,0 +1 @@ +ResetView_16x diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/saveDark.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/saveDark.svg new file mode 100644 index 0000000000..cb4847e2b0 --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/saveDark.svg @@ -0,0 +1 @@ +Save_16x diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/searchDark.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/searchDark.svg new file mode 100644 index 0000000000..cd14951267 --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/searchDark.svg @@ -0,0 +1 @@ +Search_16x diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/sortAlphabeticallyDark.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/sortAlphabeticallyDark.svg new file mode 100644 index 0000000000..1e03cfddf3 --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/sortAlphabeticallyDark.svg @@ -0,0 +1 @@ +SortAscending_16x diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/sortByDisplayOrderDark.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/sortByDisplayOrderDark.svg new file mode 100644 index 0000000000..f105b69806 --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/sortByDisplayOrderDark.svg @@ -0,0 +1 @@ + diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/sortReverseAlphabeticallyDark.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/sortReverseAlphabeticallyDark.svg new file mode 100644 index 0000000000..f66ab0f0f3 --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/sortReverseAlphabeticallyDark.svg @@ -0,0 +1 @@ +SortDescending_16x diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/splitScreenHorizontallyDark.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/splitScreenHorizontallyDark.svg new file mode 100644 index 0000000000..350f2c457b --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/splitScreenHorizontallyDark.svg @@ -0,0 +1 @@ +SplitScreenHorizontal_16x diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/splitScreenVerticallyDark.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/splitScreenVerticallyDark.svg new file mode 100644 index 0000000000..e477fd23ac --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/splitScreenVerticallyDark.svg @@ -0,0 +1 @@ +SplitScreenVertical_16x diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/upArrowBetter.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/upArrowBetter.svg new file mode 100644 index 0000000000..d58810ddfc --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/upArrowBetter.svg @@ -0,0 +1 @@ + diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/upArrowWorse.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/upArrowWorse.svg new file mode 100644 index 0000000000..83349d5877 --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/upArrowWorse.svg @@ -0,0 +1 @@ + diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/zoomDark.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/zoomDark.svg new file mode 100644 index 0000000000..6cbff04bc4 --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/zoomDark.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/zoomInDark.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/zoomInDark.svg new file mode 100644 index 0000000000..9dfa3ee813 --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/zoomInDark.svg @@ -0,0 +1 @@ +ZoomIn_16x diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/zoomOutDark.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/zoomOutDark.svg new file mode 100644 index 0000000000..ed03901266 --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/zoomOutDark.svg @@ -0,0 +1 @@ +ZoomOut_16x diff --git a/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/zoomToFitDark.svg b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/zoomToFitDark.svg new file mode 100644 index 0000000000..f8e3bb4243 --- /dev/null +++ b/src/sql/workbench/contrib/executionPlan/browser/images/actionIcons/zoomToFitDark.svg @@ -0,0 +1 @@ +ZoomToFit_16x diff --git a/src/sql/workbench/contrib/executionPlan/browser/media/executionPlan.css b/src/sql/workbench/contrib/executionPlan/browser/media/executionPlan.css index 5aba48e808..d91f9b06ba 100644 --- a/src/sql/workbench/contrib/executionPlan/browser/media/executionPlan.css +++ b/src/sql/workbench/contrib/executionPlan/browser/media/executionPlan.css @@ -244,6 +244,14 @@ However we always want it to be the width of the container it is resizing. background-repeat: no-repeat; } +.vs-dark .eps-container .ep-save-plan-icon, +.hc-black .eps-container .ep-save-plan-icon { + background-image: url(../images/actionIcons/saveDark.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; +} + .eps-container .ep-open-properties-icon { background-image: url(../images/actionIcons/openProperties.svg); background-size: 16px 16px; @@ -251,6 +259,14 @@ However we always want it to be the width of the container it is resizing. background-repeat: no-repeat; } +.vs-dark .eps-container .ep-open-properties-icon, +.hc-black .eps-container .ep-open-properties-icon { + background-image: url(../images/actionIcons/openPropertiesDark.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; +} + .eps-container .ep-open-query-icon { background-image: url(../images/actionIcons/openQuery.svg); background-size: 16px 16px; @@ -258,6 +274,14 @@ However we always want it to be the width of the container it is resizing. background-repeat: no-repeat; } +.vs-dark .eps-container .ep-open-query-icon, +.hc-black .eps-container .ep-open-query-icon { + background-image: url(../images/actionIcons/openQueryDark.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; +} + .eps-container .ep-open-plan-file-icon { background-image: url(../images/actionIcons/openPlanFile.svg); background-size: 16px 16px; @@ -265,6 +289,15 @@ However we always want it to be the width of the container it is resizing. background-repeat: no-repeat; } +.vs-dark .eps-container .ep-open-plan-file-icon, +.hc-black .eps-container .ep-open-plan-file-icon { + background-image: url(../images/actionIcons/openPlanFileDark.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; +} + + .eps-container .ep-search-icon { background-image: url(../images/actionIcons/search.svg); background-size: 16px 16px; @@ -272,6 +305,14 @@ However we always want it to be the width of the container it is resizing. background-repeat: no-repeat; } +.vs-dark .eps-container .ep-search-icon, +.hc-black .eps-container .ep-search-icon { + background-image: url(../images/actionIcons/searchDark.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; +} + .eps-container .ep-sort-alphabetically-icon { background-image: url(../images/actionIcons/sortAlphabetically.svg); background-size: 16px 16px; @@ -279,6 +320,14 @@ However we always want it to be the width of the container it is resizing. background-repeat: no-repeat; } +.vs-dark .eps-container .ep-sort-alphabetically-icon, +.hc-black .eps-container .ep-sort-alphabetically-icon { + background-image: url(../images/actionIcons/sortAlphabeticallyDark.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; +} + .eps-container .ep-sort-reverse-alphabetically-icon { background-image: url(../images/actionIcons/sortReverseAlphabetically.svg); background-size: 16px 16px; @@ -286,6 +335,14 @@ However we always want it to be the width of the container it is resizing. background-repeat: no-repeat; } +.vs-dark .eps-container .ep-sort-reverse-alphabetically-icon, +.hc-black .eps-container .ep-sort-reverse-alphabetically-icon { + background-image: url(../images/actionIcons/sortReverseAlphabeticallyDark.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; +} + .eps-container .ep-sort-display-order-icon { background-image: url(../images/actionIcons/sortByDisplayOrder.svg); background-size: 16px 16px; @@ -293,6 +350,14 @@ However we always want it to be the width of the container it is resizing. background-repeat: no-repeat; } +.vs-dark .eps-container .ep-sort-display-order-icon, +.hc-black .eps-container .ep-sort-display-order-icon { + background-image: url(../images/actionIcons/sortByDisplayOrderDark.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; +} + .eps-container .ep-zoom-in-icon { background-image: url(../images/actionIcons/zoomIn.svg); background-size: 16px 16px; @@ -300,6 +365,14 @@ However we always want it to be the width of the container it is resizing. background-repeat: no-repeat; } +.vs-dark .eps-container .ep-zoom-in-icon, +.hc-black .eps-container .ep-zoom-in-icon { + background-image: url(../images/actionIcons/zoomInDark.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; +} + .eps-container .ep-zoom-out-icon { background-image: url(../images/actionIcons/zoomOut.svg); background-size: 16px 16px; @@ -307,6 +380,14 @@ However we always want it to be the width of the container it is resizing. background-repeat: no-repeat; } +.vs-dark .eps-container .ep-zoom-out-icon, +.hc-black .eps-container .ep-zoom-out-icon { + background-image: url(../images/actionIcons/zoomOutDark.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; +} + .eps-container .ep-custom-zoom-icon { background-image: url(../images/actionIcons/customZoom.svg); background-size: 16px 16px; @@ -314,6 +395,14 @@ However we always want it to be the width of the container it is resizing. background-repeat: no-repeat; } +.vs-dark .eps-container .ep-custom-zoom-icon, +.hc-black .eps-container .ep-custom-zoom-icon { + background-image: url(../images/actionIcons/customZoomDark.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; +} + .eps-container .ep-zoom-to-fit-icon { background-image: url(../images/actionIcons/zoomToFit.svg); background-size: 16px 16px; @@ -321,6 +410,14 @@ However we always want it to be the width of the container it is resizing. background-repeat: no-repeat; } +.vs-dark .eps-container .ep-zoom-to-fit-icon, +.hc-black .eps-container .ep-zoom-to-fit-icon { + background-image: url(../images/actionIcons/zoomToFitDark.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; +} + .eps-container .ep-zoom-icon { background-image: url(../images/actionIcons/zoom.svg); background-size: 16px 16px; @@ -328,6 +425,13 @@ However we always want it to be the width of the container it is resizing. background-repeat: no-repeat; } +.eps-container .ep-zoom-icon { + background-image: url(../images/actionIcons/zoomDark.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; +} + .eps-container .ep-enable-tooltip-icon { background-image: url(../images/actionIcons/enableTooltip.svg); background-size: 16px 16px; @@ -335,6 +439,14 @@ However we always want it to be the width of the container it is resizing. background-repeat: no-repeat; } +.vs-dark .eps-container .ep-enable-tooltip-icon, +.hc-black .eps-container .ep-enable-tooltip-icon { + background-image: url(../images/actionIcons/enableTooltipDark.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; +} + .eps-container .ep-disable-tooltip-icon { background-image: url(../images/actionIcons/disableTooltip.svg); background-size: 16px 16px; @@ -342,6 +454,14 @@ However we always want it to be the width of the container it is resizing. background-repeat: no-repeat; } +.vs-dark .eps-container .ep-disable-tooltip-icon, +.hc-black .eps-container .ep-disable-tooltip-icon { + background-image: url(../images/actionIcons/disableTooltipDark.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; +} + .eps-container .ep-add-icon { background-image: url(../images/actionIcons/add.svg); background-size: 16px 16px; @@ -349,6 +469,14 @@ However we always want it to be the width of the container it is resizing. background-repeat: no-repeat; } +.vs-dark .eps-container .ep-add-icon, +.hc-black .eps-container .ep-add-icon { + background-image: url(../images/actionIcons/addDark.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; +} + .eps-container .ep-settings-icon { background-image: url(../images/actionIcons/settings.svg); background-size: 16px 16px; @@ -363,6 +491,14 @@ However we always want it to be the width of the container it is resizing. background-repeat: no-repeat; } +.vs-dark .ep-split-screen-horizontally-icon, +.hc-black .ep-split-screen-horizontally-icon { + background-image: url(../images/actionIcons/splitScreenHorizontallyDark.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; +} + .eps-container .ep-split-screen-vertically-icon { background-image: url(../images/actionIcons/splitScreenVertically.svg); background-size: 16px 16px; @@ -370,6 +506,14 @@ However we always want it to be the width of the container it is resizing. background-repeat: no-repeat; } +.vs-dark .eps-container .ep-split-screen-vertically-icon, +.hc-black .eps-container .ep-split-screen-vertically-icon { + background-image: url(../images/actionIcons/splitScreenVerticallyDark.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; +} + .eps-container .ep-reset-zoom-icon { background-image: url(../images/actionIcons/resetZoom.svg); background-size: 16px 16px; @@ -377,6 +521,15 @@ However we always want it to be the width of the container it is resizing. background-repeat: no-repeat; } +.vs-dark .eps-container .ep-reset-zoom-icon, +.hc-black .eps-container .ep-reset-zoom-icon { + background-image: url(../images/actionIcons/resetZoomDark.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; +} + + .eps-container .ep-plan-compare-icon { background-image: url(../images/actionIcons/execution-plan-compare.svg); background-size: 16px 16px; @@ -384,6 +537,59 @@ However we always want it to be the width of the container it is resizing. background-repeat: no-repeat; } +.vs-dark .eps-container .ep-plan-compare-icon, +.hc-black .eps-container .ep-plan-compare-icon { + background-image: url(../images/actionIcons/execution-plan-compareDark.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; +} + +.eps-container .ep-properties-different { + background-image: url(../images/actionIcons/differentValues.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; + width: 16px; + height: auto; +} + +.eps-container .ep-properties-red-down-arrow { + background-image: url(../images/actionIcons/downArrowWorse.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; + width: 16px; + height: auto; +} + +.eps-container .ep-properties-green-down-arrow { + background-image: url(../images/actionIcons/downArrowBetter.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; + width: 16px; + height: auto; +} + +.eps-container .ep-properties-red-up-arrow { + background-image: url(../images/actionIcons/upArrowWorse.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; + width: 16px; + height: auto; +} + +.eps-container .ep-properties-green-down-arrow { + background-image: url(../images/actionIcons/downArrowBetter.svg); + background-size: 16px 16px; + background-position: center; + background-repeat: no-repeat; + width: 16px; + height: auto; +} + .eps-container .comparison-editor { width: 100%; height: 100%; @@ -522,3 +728,15 @@ However we always want it to be the width of the container it is resizing. .eps-container .comparison-editor .properties .table-container { overflow: hidden; } + +.eps-container .comparison-editor .editor-toolbar .action-item .codicon.action-label { + padding-left: 20px; +} + +.eps-container .comparison-editor .parent-row-styling { + font-weight: bold; +} + +.eps-container .comparison-editor .default-bottom-column-cell-styling { + padding-left: 0px; +}