Skip to content

Commit

Permalink
Initial changes for query store dashboard (microsoft#24272)
Browse files Browse the repository at this point in the history
* create empty query store dashboard

* add placeholder report content

* cleanup

* more cleanup
  • Loading branch information
kisantia authored Sep 6, 2023
1 parent 52a7607 commit 9f4e19f
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 34 deletions.
9 changes: 2 additions & 7 deletions extensions/query-store/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,8 @@
"contributes": {
"commands": [
{
"command": "queryStore.topResourceConsumingQueriesOpen",
"title": "%queryStore.topResourceConsumingQueriesOpen%",
"category": "%queryStore.category%"
},
{
"command": "queryStore.overallResourceConsumptionOpen",
"title": "%queryStore.overallResourceConsumptionOpen%",
"command": "queryStore.openQueryStoreDashboard",
"title": "%queryStore.openQueryStoreDashboard%",
"category": "%queryStore.category%"
}
],
Expand Down
3 changes: 1 addition & 2 deletions extensions/query-store/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@
"queryStore.displayName": "Query Store",
"queryStore.description": "Query Store extension for Azure Data Studio.",
"queryStore.category": "Query Store",
"queryStore.topResourceConsumingQueriesOpen": "Open Top Resource Consuming Queries",
"queryStore.overallResourceConsumptionOpen": "Open Overall Resource Consumption"
"queryStore.openQueryStoreDashboard": "Query Store"
}
2 changes: 2 additions & 0 deletions extensions/query-store/src/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import * as nls from 'vscode-nls';

const localize = nls.loadMessageBundle();

export function queryStoreDashboardTitle(databaseName: string): string { return localize('queryStoreDashboardTitle', "Query Store - {0}", databaseName); }

export const overallResourceConsumption = localize('overallResourceConsumption', "Overall Resource Consumption");
export const duration = localize('duration', "Duration");
export const executionCount = localize('executionCount', "Execution Count");
Expand Down
8 changes: 4 additions & 4 deletions extensions/query-store/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
*--------------------------------------------------------------------------------------------*/

import * as vscode from 'vscode';
import { TopResourceConsumingQueries } from './reports/topResourceConsumingQueries';
import { OverallResourceConsumption } from './reports/overallResourceConsumption';
import { QueryStoreDashboard } from './reports/queryStoreDashboard';

export async function activate(context: vscode.ExtensionContext): Promise<void> {
// TODO: get db name
context.subscriptions.push(vscode.commands.registerCommand('queryStore.topResourceConsumingQueriesOpen', async () => { await new TopResourceConsumingQueries(context, 'WideWorldImporters').open() }));
context.subscriptions.push(vscode.commands.registerCommand('queryStore.overallResourceConsumptionOpen', async () => { await new OverallResourceConsumption(context, 'WideWorldImporters').open() }));
// TODO: add OE entry point with condition for command to only be visible for db's with Query Store enabled (or consider always showing and having a way to enable when dashboard is opened?)
// TODO: remove entry point from command palette - keeping for now to speed up testing so a connection doesn't need to be made to launch the dashboard
context.subscriptions.push(vscode.commands.registerCommand('queryStore.openQueryStoreDashboard', async () => { await new QueryStoreDashboard('AdventureWorks', context).open() }));
}

export function deactivate(): void {
Expand Down
33 changes: 14 additions & 19 deletions extensions/query-store/src/reports/baseQueryStoreReport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,40 +11,35 @@ import * as constants from '../common/constants';
import { ConfigureDialog } from '../settings/configureDialog';

export abstract class BaseQueryStoreReport {
protected editor: azdata.workspace.ModelViewEditor;
protected flexModel?: azdata.FlexContainer;
protected configureDialog?: ConfigureDialog;
protected configureButton?: azdata.ButtonComponent;

constructor(reportName: string, private reportTitle: string, protected resizeable: boolean, private extensionContext: vscode.ExtensionContext) {
this.editor = azdata.workspace.createModelViewEditor(reportName, { retainContextWhenHidden: true, supportsSave: false }, reportName);
constructor(private reportTitle: string, protected resizeable: boolean, private extensionContext: vscode.ExtensionContext) { }

public get ReportContent(): azdata.FlexContainer | undefined {
return this.flexModel;
}

/**
* Creates and opens the report
*/
public async open(): Promise<void> {
this.editor.registerContent(async (view) => {
this.flexModel = <azdata.FlexContainer>view.modelBuilder.flexContainer().component();

const toolbar = await this.createToolbar(view);
this.flexModel.addItem(toolbar, { flex: 'none' });
public async createReport(view: azdata.ModelView): Promise<void> {
this.flexModel = <azdata.FlexContainer>view.modelBuilder.flexContainer().component();

const views = await this.createViews(view);
const toolbar = await this.createToolbar(view);
this.flexModel.addItem(toolbar, { flex: 'none' });

const mainContainer = await this.createMainContainer(view, views);
const views = await this.createViews(view);

this.flexModel.addItem(mainContainer, { CSSStyles: { 'width': '100%', 'height': '100%' } });
const mainContainer = await this.createMainContainer(view, views);

this.flexModel.setLayout({
flexFlow: 'column',
height: '100%'
});
this.flexModel.addItem(mainContainer, { CSSStyles: { 'width': '100%', 'height': '100%' } });

await view.initializeModel(this.flexModel);
this.flexModel.setLayout({
flexFlow: 'column',
height: '100%'
});

await this.editor.openEditor();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class OverallResourceConsumption extends BaseQueryStoreReport {
private logicalReads: QueryStoreView;

constructor(extensionContext: vscode.ExtensionContext, databaseName: string) {
super(constants.overallResourceConsumption, constants.overallResourceConsumptionToolbarLabel(databaseName), /*resizeable*/ false, extensionContext);
super(constants.overallResourceConsumptionToolbarLabel(databaseName), /*resizeable*/ false, extensionContext);
this.duration = new QueryStoreView(constants.duration, 'chartreuse');
this.executionCount = new QueryStoreView(constants.executionCount, 'coral');
this.cpuTime = new QueryStoreView(constants.cpuTime, 'darkturquoise');
Expand Down
48 changes: 48 additions & 0 deletions extensions/query-store/src/reports/queryStoreDashboard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as vscode from 'vscode';
import * as azdata from 'azdata';
import * as constants from '../common/constants';
import { TopResourceConsumingQueries } from './topResourceConsumingQueries';
import { OverallResourceConsumption } from './overallResourceConsumption';

export class QueryStoreDashboard {
constructor(private dbName: string, private extensionContext: vscode.ExtensionContext) { }

/**
* Creates and opens the report
*/
public async open(): Promise<void> {
// TODO: update title based on selected tab to have the current selected report in editor tab title
const dashboard = azdata.window.createModelViewDashboard(constants.queryStoreDashboardTitle(this.dbName));
dashboard.registerTabs(async (view: azdata.ModelView) => {
const topResourceConsumingQueriesReport = new TopResourceConsumingQueries(this.extensionContext, this.dbName);
const overallResourceConsumptionReport = new OverallResourceConsumption(this.extensionContext, this.dbName);

await Promise.all([topResourceConsumingQueriesReport.createReport(view), overallResourceConsumptionReport.createReport(view)]);

const topResourceConsumingQueriesTab: azdata.DashboardTab = {
id: 'TopResourceConsumingQueriesTab',
content: topResourceConsumingQueriesReport.ReportContent!,
title: constants.topResourceConsumingQueries
};

const overallResourceConsumptionTab: azdata.DashboardTab = {
id: 'OverallResourceConsumptionTab',
content: overallResourceConsumptionReport.ReportContent!,
title: constants.overallResourceConsumption
};

return [
overallResourceConsumptionTab,
topResourceConsumingQueriesTab
];
});

await dashboard.open();
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export class TopResourceConsumingQueries extends BaseQueryStoreReport {
private plan: QueryStoreView;

constructor(extensionContext: vscode.ExtensionContext, databaseName: string) {
super(constants.topResourceConsumingQueries, constants.topResourceConsumingQueriesToolbarLabel(databaseName), /*resizeable*/ true, extensionContext);
super(constants.topResourceConsumingQueriesToolbarLabel(databaseName), /*resizeable*/ true, extensionContext);
this.queries = new QueryStoreView(constants.queries, 'chartreuse');
this.planSummary = new QueryStoreView(constants.planSummary('x'), 'coral'); // TODO: replace 'x' with actual query id
this.plan = new QueryStoreView(constants.plan('x'), 'darkturquoise');
Expand Down

0 comments on commit 9f4e19f

Please sign in to comment.