From 08c50e8ffad4ddb1a416a39d43e256a2d60ee957 Mon Sep 17 00:00:00 2001 From: Hai Cao Date: Tue, 15 Oct 2024 23:01:06 -0700 Subject: [PATCH] Fix a few Query Result bugs: (#18234) * remove query result auto focus after tab switch * fix multi result in one batch * fix grid f font * message styling * fix grgird header styling * improve placeholder msg styling * add a button to reveal query result panel * hide message line * add config check altlthough not actually needed * use focus command insttead of show() --- localization/xliff/vscode-mssql.xlf | 3 + media/revealQueryResult.svg | 1 + package.json | 11 +++ package.nls.json | 1 + src/constants/constants.ts | 1 + src/controllers/mainController.ts | 10 +++ src/controllers/reactWebviewViewController.ts | 15 ++-- src/models/sqlOutputContentProvider.ts | 5 +- .../queryResultWebViewController.ts | 14 +++- .../pages/QueryResult/queryResultPane.tsx | 76 ++++++++++++++----- .../pages/QueryResult/table/interfaces.ts | 2 +- src/sharedInterfaces/queryResult.ts | 2 +- 12 files changed, 110 insertions(+), 31 deletions(-) create mode 100644 media/revealQueryResult.svg diff --git a/localization/xliff/vscode-mssql.xlf b/localization/xliff/vscode-mssql.xlf index 7df23f35..716a7870 100644 --- a/localization/xliff/vscode-mssql.xlf +++ b/localization/xliff/vscode-mssql.xlf @@ -1682,6 +1682,9 @@ Remove Microsoft Entra Account + + Reveal Query Result Panel + Run Query diff --git a/media/revealQueryResult.svg b/media/revealQueryResult.svg new file mode 100644 index 00000000..025d9bd1 --- /dev/null +++ b/media/revealQueryResult.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/package.json b/package.json index 00efc620..0ec4404b 100644 --- a/package.json +++ b/package.json @@ -308,6 +308,11 @@ "when": "editorLangId == sql && resourcePath in mssql.runningQueries", "group": "navigation@2" }, + { + "command": "mssql.revealQueryResultPanel", + "when": "editorLangId == sql && config.mssql.enableRichExperiences && view.queryResult.visible == false", + "group": "navigation@2" + }, { "command": "mssql.connect", "when": "editorLangId == sql && resource not in mssql.connections", @@ -571,6 +576,12 @@ "category": "MS SQL", "icon": "$(debug-stop)" }, + { + "command": "mssql.revealQueryResultPanel", + "title": "%mssql.revealQueryResultPanel%", + "category": "MS SQL", + "icon": "media/revealQueryResult.svg" + }, { "command": "mssql.connect", "title": "%mssql.connect%", diff --git a/package.nls.json b/package.nls.json index f7cd56e7..4ddb3039 100644 --- a/package.nls.json +++ b/package.nls.json @@ -2,6 +2,7 @@ "mssql.runQuery":"Execute Query", "mssql.runCurrentStatement":"Execute Current Statement", "mssql.cancelQuery":"Cancel Query", +"mssql.revealQueryResultPanel":"Reveal Query Result Panel", "mssql.changeDatabase":"Change Database", "mssql.addObjectExplorer":"Add Connection", "mssql.scriptSelect":"Select Top 1000", diff --git a/src/constants/constants.ts b/src/constants/constants.ts index ed06a2e7..d8dba41a 100644 --- a/src/constants/constants.ts +++ b/src/constants/constants.ts @@ -23,6 +23,7 @@ export const folderLabel = "Folder"; export const cmdRunQuery = "mssql.runQuery"; export const cmdRunCurrentStatement = "mssql.runCurrentStatement"; export const cmdCancelQuery = "mssql.cancelQuery"; +export const cmdrevealQueryResultPanel = "mssql.revealQueryResultPanel"; export const cmdConnect = "mssql.connect"; export const cmdDisconnect = "mssql.disconnect"; export const cmdChangeDatabase = "mssql.changeDatabase"; diff --git a/src/controllers/mainController.ts b/src/controllers/mainController.ts index 62b2a13d..a4878878 100644 --- a/src/controllers/mainController.ts +++ b/src/controllers/mainController.ts @@ -1080,6 +1080,16 @@ export default class MainController implements vscode.Disposable { }, ), ); + + // Reveal Query Results command + this._context.subscriptions.push( + vscode.commands.registerCommand( + Constants.cmdrevealQueryResultPanel, + () => { + vscode.commands.executeCommand("queryResult.focus"); + }, + ), + ); } /** diff --git a/src/controllers/reactWebviewViewController.ts b/src/controllers/reactWebviewViewController.ts index 61c4417d..04b62356 100644 --- a/src/controllers/reactWebviewViewController.ts +++ b/src/controllers/reactWebviewViewController.ts @@ -38,12 +38,17 @@ export class ReactWebviewViewController } /** - * Displays the webview in the foreground - * @param viewColumn The view column that the webview will be displayed in + * returns if the webview is visible */ - public revealToForeground( - viewColumn: vscode.ViewColumn = vscode.ViewColumn.One, - ): void {} + public isVisible(): boolean { + return this._webviewView.visible; + } + /** + * Displays the webview in the foreground + */ + public revealToForeground(): void { + this._webviewView.show(true); + } public resolveWebviewView( webviewView: vscode.WebviewView, diff --git a/src/models/sqlOutputContentProvider.ts b/src/models/sqlOutputContentProvider.ts index 4d5945b9..95a2bb1e 100644 --- a/src/models/sqlOutputContentProvider.ts +++ b/src/models/sqlOutputContentProvider.ts @@ -425,9 +425,10 @@ export class SqlOutputContentProvider { .get(uri) .proxy.sendEvent("resultSet", resultSet); } else { - this._queryResultWebviewController.getQueryResultState( + this._queryResultWebviewController.addResultSetSummary( uri, - ).resultSetSummaries[resultSet.batchId] = resultSet; + resultSet, + ); } }, ); diff --git a/src/queryResult/queryResultWebViewController.ts b/src/queryResult/queryResultWebViewController.ts index bb8e69fc..56bf172f 100644 --- a/src/queryResult/queryResultWebViewController.ts +++ b/src/queryResult/queryResultWebViewController.ts @@ -48,7 +48,6 @@ export class QueryResultWebviewController extends ReactWebviewViewController< const uri = editor?.document?.uri?.toString(true); if (uri && this._queryResultStateMap.has(uri)) { this.state = this.getQueryResultState(uri); - vscode.commands.executeCommand("queryResult.focus"); } else { this.state = { resultSetSummaries: {}, @@ -259,6 +258,19 @@ export class QueryResultWebviewController extends ReactWebviewViewController< return res; } + public addResultSetSummary( + uri: string, + resultSetSummary: qr.ResultSetSummary, + ) { + let state = this.getQueryResultState(uri); + const batchId = resultSetSummary.batchId; + const resultId = resultSetSummary.id; + if (!state.resultSetSummaries[batchId]) { + state.resultSetSummaries[batchId] = {}; + } + state.resultSetSummaries[batchId][resultId] = resultSetSummary; + } + public setSqlOutputContentProvider( provider: SqlOutputContentProvider, ): void { diff --git a/src/reactviews/pages/QueryResult/queryResultPane.tsx b/src/reactviews/pages/QueryResult/queryResultPane.tsx index 1e772491..c64c1423 100644 --- a/src/reactviews/pages/QueryResult/queryResultPane.tsx +++ b/src/reactviews/pages/QueryResult/queryResultPane.tsx @@ -62,6 +62,9 @@ const useStyles = makeStyles({ width: "100%", position: "relative", display: "flex", + fontFamily: "Menlo, Monaco, 'Courier New', monospace", + fontWeight: "normal", + fontSize: "12px", }, queryResultPaneOpenButton: { position: "absolute", @@ -77,11 +80,23 @@ const useStyles = makeStyles({ }, }, messagesRows: { + height: "18px", + fontSize: "12px", flexDirection: "row", ...shorthands.padding("10px"), "> *": { marginRight: "10px", }, + borderBottom: "none", + }, + noResultMessage: { + fontSize: "14px", + margin: "10px 0 0 10px", + }, + hidePanelLink: { + fontSize: "14px", + margin: "10px 0 0 10px", + cursor: "pointer", }, }); @@ -178,23 +193,22 @@ export const QueryResultPane = () => { const gridRefs = useRef([]); - const renderGrid = (idx: number) => { - const divId = `grid-parent-${idx}`; + const renderGrid = ( + batchId: number, + resultId: number, + gridCount: number, + totalResultCount: number, + ) => { + const divId = `grid-parent-${batchId}-${resultId}`; return (
{ return webViewState.extensionRpc .call("getRows", { uri: metadata?.uri, - batchId: - metadata?.resultSetSummaries[idx]?.batchId, - resultId: metadata?.resultSetSummaries[idx]?.id, + batchId: batchId, + resultId: resultId, rowStart: offset, numberOfRows: count, }) @@ -217,8 +230,9 @@ export const QueryResultPane = () => { } let r = response as qr.ResultSetSubset; var columnLength = - metadata?.resultSetSummaries[idx] - ?.columnInfo?.length; + metadata?.resultSetSummaries[batchId][ + resultId + ]?.columnInfo?.length; // if the result is an execution plan xml, // get the execution plan graph from it if (metadata?.isExecutionPlan) { @@ -251,15 +265,19 @@ export const QueryResultPane = () => { }); }); }} - ref={(gridRef) => (gridRefs.current[idx] = gridRef!)} - resultSetSummary={metadata?.resultSetSummaries[idx]} + ref={(gridRef) => (gridRefs.current[gridCount] = gridRef!)} + resultSetSummary={ + metadata?.resultSetSummaries[batchId][resultId] + } divId={divId} uri={metadata?.uri} webViewState={webViewState} />
); @@ -268,12 +286,22 @@ export const QueryResultPane = () => { const renderGridPanel = () => { const grids = []; gridRefs.current.forEach((r) => r?.refreshGrid()); + let totalResultCount = 0; + Object.values(metadata?.resultSetSummaries ?? []).forEach((v) => { + totalResultCount += Object.keys(v).length; + }); + + let count = 0; for ( let i = 0; i < Object.keys(metadata?.resultSetSummaries ?? []).length; i++ ) { - grids.push(renderGrid(i)); + var batch = metadata?.resultSetSummaries[i]; + for (let j = 0; j < Object.keys(batch ?? []).length; j++) { + grids.push(renderGrid(i, j, count, totalResultCount)); + count++; + } } return grids; }; @@ -304,9 +332,12 @@ export const QueryResultPane = () => { return !metadata || !hasResultsOrMessages(metadata) ? (
-
{locConstants.queryResult.noResultMessage}
+
+ {locConstants.queryResult.noResultMessage} +
{ await webViewState.extensionRpc.call("executeCommand", { command: "workbench.action.togglePanel", @@ -391,7 +422,10 @@ export const QueryResultPane = () => { {rows.map((row, index) => { return ( - + >; messages: IMessage[]; tabStates?: QueryResultTabStates; isExecutionPlan?: boolean;