Code review changes for SQL Notebooks#21439
Conversation
The `NotebookConnectionManager.connectWith` method no longer performs a database mismatch check followed by a disconnect and reconnect. Previously, if the actual database reported by the connection service (STS) differed from the database specified in the initial `IConnectionInfo`, the manager would attempt to reconnect to the correct database. This logic is now removed. The manager now directly accepts the database reported by STS as the active database for the connection, simplifying the connection flow and avoiding unnecessary reconnect cycles. This prioritizes the actual connected database for internal state management.
There was a problem hiding this comment.
Pull request overview
Follow-up changes to the SQL Notebooks feature to incorporate review feedback from #21324, including moving notebook execution onto STS query notifications, reusing shared result-grid behaviors in the notebook renderer, and aligning notebook UI strings with “MSSQL” branding/localization.
Changes:
- Replaced notebook batch parsing + simple-query execution with an STS notification–driven
NotebookQueryExecutor(query/executeString+ subset fetching + cancel/dispose). - Reused the shared Query Result grid
CellSelectionModeland shared table icon CSS in the notebook renderer; removed notebook-specific selection model. - Updated notebook-related localization strings (“MSSQL …”, “canceled”) and adjusted relevant unit tests.
Reviewed changes
Copilot reviewed 21 out of 21 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| localization/xliff/vscode-mssql.xlf | Adds/updates notebook + cancellation trans-units and renames notebook strings to “MSSQL …”. |
| extensions/mssql/l10n/bundle.l10n.json | Updates runtime l10n bundle keys for the renamed notebook strings and cancellation spelling. |
| extensions/mssql/src/constants/locConstants.ts | Renames notebook status bar strings to “MSSQL …” and updates cancellation string to “canceled”. |
| extensions/mssql/src/notebooks/sqlNotebookController.ts | Switches execution path to executeQueryString (single call) + batch-output formatting; supports DI factory for tests; updates naming to MSSQL. |
| extensions/mssql/src/notebooks/notebookQueryExecutor.ts | New executor that wraps STS query notifications into a promise-based API, including subset row fetching and best-effort cancel/dispose. |
| extensions/mssql/src/notebooks/notebookConnectionManager.ts | Uses STS-populated connection info for “actual database”, delegates execution to NotebookQueryExecutor, removes old simple-query DB verification/cancel path. |
| extensions/mssql/src/models/contracts/queryExecute.ts | Adds QueryExecuteStringRequest + params for STS query/executeString. |
| extensions/mssql/src/controllers/queryNotificationHandler.ts | Generalizes runner tracking to IQueryEventHandler (decouples from QueryRunner). |
| extensions/mssql/src/reactviews/pages/QueryResult/table/plugins/cellSelectionModel.plugin.ts | Makes context/keybinding deps optional and adds a “basic keyboard support” fallback for notebook renderer usage. |
| extensions/mssql/src/reactviews/pages/NotebookRenderer/notebookResultGrid.tsx | Switches to shared CellSelectionModel and imports shared table.css. |
| extensions/mssql/src/reactviews/pages/NotebookRenderer/notebookResultGrid.css | Removes notebook-local button styling; adds notebook-specific overrides for shared sort/filter button classes. |
| extensions/mssql/src/reactviews/pages/NotebookRenderer/notebookHeaderMenu.plugin.ts | Uses shared CSS-driven icons/classes instead of inline SVGs; toggles state via CSS classes. |
| extensions/mssql/src/reactviews/pages/NotebookRenderer/notebookContextMenu.plugin.ts | Expands rationale comment describing why notebook context menu is separate from QueryResult context menu. |
| extensions/mssql/scripts/bundle-notebook-renderer.js | Enhances CSS inlining to rewrite url() assets to inline data URIs for iframe renderer. |
| extensions/mssql/src/notebooks/notebookCodeLensProvider.ts | Clarifies why “last active connection” logic doesn’t work for notebooks. |
| extensions/mssql/test/unit/sqlNotebookController.test.ts | Updates controller tests to use a mocked NotebookConnectionManager + new result shape. |
| extensions/mssql/test/unit/notebookQueryExecutor.test.ts | Adds unit tests for the new STS-notification based executor. |
| extensions/mssql/test/unit/notebookConnectionManager.test.ts | Updates tests for new execution path and connection-info behavior. |
| extensions/mssql/test/unit/batchParser.test.ts | Removes tests for deleted batch parser. |
| extensions/mssql/src/notebooks/batchParser.ts | Removes batch parsing helper in favor of STS batch handling. |
| extensions/mssql/src/reactviews/pages/NotebookRenderer/notebookCellSelectionModel.plugin.ts | Removes notebook-specific cell selection model in favor of shared implementation. |
Comments suppressed due to low confidence (1)
extensions/mssql/src/notebooks/notebookConnectionManager.ts:133
promptAndConnectformats the connection label usingactualDb, but then stores the originalconnectionInfo(which may still contain the requested/previous database). This can desyncgetCurrentDatabase()/ futurechangeDatabase()calls from what STS actually opened. Storethis.connectionInfowith the resolvedactualDb(fallback to the profile DB ifactualDbis "(unknown)").
const actualDb = this.getActualDatabase(uri);
this.log.info(`[promptAndConnect] Actual DB: ${actualDb}`);
this.connectionLabel = formatConnectionLabel(connectionInfo.server, actualDb);
this.connectionUri = uri;
this.connectionInfo = connectionInfo;
activity.end(ActivityStatus.Succeeded);
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Get the actual database name from the connection info that STS populated | ||
| const actualDb = this.getActualDatabase(uri); | ||
| this.log.info(`[changeDatabase] Verified: ${actualDb}`); | ||
|
|
||
| this.connectionUri = uri; | ||
| this.connectionInfo = newInfo; | ||
| this.connectionLabel = formatConnectionLabel(newInfo.server, actualDb); | ||
| } |
There was a problem hiding this comment.
changeDatabase verifies the actual DB via getActualDatabase(uri) and uses it for connectionLabel, but it keeps this.connectionInfo = newInfo (the requested DB). This means getCurrentDatabase() can return a different DB than what the label/STS session is actually using. Update this.connectionInfo to reflect actualDb (with a sensible fallback when actualDb is "(unknown)").
| <trans-unit id="++CODE++65298a316736d0742788a35a1a44d804842b5f5d39234b03faa3be7815a545e4"> | ||
| <source xml:lang="en">MSSQL Notebook connected to {0}</source> | ||
| <note>{0} is the connection label</note> | ||
| </trans-unit> | ||
| <trans-unit id="++CODE++99a3297c47d9336c0c32fe572074cba7cd53bf9b0d5988c14d3335dd468e2c37"> | ||
| <source xml:lang="en">MSSQL: Not connected</source> | ||
| </trans-unit> | ||
| <trans-unit id="++CODE++845cd20358ee1964f66ca8b28c6df89c00d0f59d43a3e8e3f3d65a515194a1da"> | ||
| <source xml:lang="en">MSSQL: Welcome & What's New</source> | ||
| </trans-unit> | ||
| <trans-unit id="++CODE++2b136410190298a2840e44bf76dd88579edad1f2b56366e66685938b77821aa4"> | ||
| <source xml:lang="en">MSSQL: click to change database</source> | ||
| </trans-unit> | ||
| <trans-unit id="++CODE++b42a988a00b3328f2d2a752321195c33513a2daafb555eac4dc97540e9978b5f"> | ||
| <source xml:lang="en">MSSQL: click to connect</source> | ||
| </trans-unit> |
There was a problem hiding this comment.
New/updated trans-units were added here (notebook status bar + cancellation strings). In this repo, when adding/changing strings in vscode-mssql.xlf, the same trans-unit IDs should be mirrored into each localized vscode-mssql.<lang>.xlf to keep localization in sync; currently only the source XLF is updated.
| <trans-unit id="++CODE++2da839233749a1d48af0f1399da21768ade458db40ba95dcd405a7addefad753"> | ||
| <source xml:lang="en">Query execution was canceled.</source> | ||
| </trans-unit> |
There was a problem hiding this comment.
This updated trans-unit ("Query execution was canceled.") also needs to be mirrored into each localized vscode-mssql.<lang>.xlf so non-English builds don’t fall behind when the source string changes.
PR Changes
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #21439 +/- ##
==========================================
+ Coverage 72.72% 72.79% +0.06%
==========================================
Files 323 323
Lines 96228 96441 +213
Branches 5360 5364 +4
==========================================
+ Hits 69985 70206 +221
+ Misses 26243 26235 -8
🚀 New features to boost your workflow:
|
|
@lewis-sanchez can you give this a more descriptive PR title since that's what becomes the commit message? |
| // so extracted CSS files would never be loaded. | ||
| // so extracted CSS files would never be loaded. Asset url() references (e.g. SVG | ||
| // icons) are resolved to data URIs so they work inside the iframe. | ||
| const inlineCssPlugin = { |
There was a problem hiding this comment.
Probably we should look into merging all the bundling files as there is a lot of repeated code.
| "SQL Notebooks: click to change database", | ||
| ); | ||
| public static statusBarClickToConnect = l10n.t("SQL Notebooks: click to connect"); | ||
| public static statusBarNotConnected = l10n.t("MSSQL: Not connected"); |
There was a problem hiding this comment.
NIT: Maybe we shold keep the labels consistent with codelens.
There was a problem hiding this comment.
Good point. We should point to the same strings.
| @@ -116,17 +124,9 @@ export class NotebookConnectionManager implements vscode.Disposable { | |||
| const uri = await this.connectInternal(connectionInfo); | |||
There was a problem hiding this comment.
Follow up task: Please dedup this with prompt and connect from query editor. We should dup this implementation.
| const params = new QueryExecuteStringParams(); | ||
| params.ownerUri = ownerUri; | ||
| params.query = query; | ||
| await this.client.sendRequest(QueryExecuteStringRequest.type, params); |
There was a problem hiding this comment.
How is this different than existing queryexecuteStatement?
There was a problem hiding this comment.
Lewis replied elsewhere, but it has to do with lack of multi-batch support
| } catch (err: any) { | ||
| if (cancelled) { | ||
| execution.replaceOutput([ | ||
| new vscode.NotebookCellOutput([ |
There was a problem hiding this comment.
Please create a helper that send this to avoid dup code.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 23 out of 23 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| this.log.info(`[promptAndConnect] Actual DB: ${actualDb}`); | ||
| this.connectionLabel = formatConnectionLabel(connectionInfo.server, actualDb); | ||
|
|
||
| this.connectionUri = uri; | ||
| this.connectionInfo = connectionInfo; |
There was a problem hiding this comment.
actualDb can be undefined (if getConnectionInfoFromUri hasn’t populated yet), but it’s passed directly into formatConnectionLabel(...). This can both (1) cause a TS type error under strictNullChecks and (2) show an incorrect label (falls back to “master”) even if the user selected a different database. Please fall back to connectionInfo.database when actualDb is undefined, and consider storing the actual DB back into this.connectionInfo for consistency.
| this.log.info(`[promptAndConnect] Actual DB: ${actualDb}`); | |
| this.connectionLabel = formatConnectionLabel(connectionInfo.server, actualDb); | |
| this.connectionUri = uri; | |
| this.connectionInfo = connectionInfo; | |
| const effectiveDb = actualDb ?? connectionInfo.database; | |
| this.log.info(`[promptAndConnect] Actual DB: ${actualDb}, Effective DB: ${effectiveDb}`); | |
| this.connectionLabel = formatConnectionLabel(connectionInfo.server, effectiveDb); | |
| this.connectionUri = uri; | |
| this.connectionInfo = { | |
| ...connectionInfo, | |
| database: effectiveDb, | |
| }; |
| @@ -120,10 +111,9 @@ export class NotebookHeaderMenu<T extends Slick.SlickData> { | |||
| args.node.appendChild(sortBtn); | |||
| this._columnSortButtonMapping.set(column.id!, sortBtn); | |||
|
|
|||
| // Filter button | |||
| // Filter button — uses shared slick-header-filterbutton class (icons via table.css) | |||
| const filterBtn = document.createElement("button"); | |||
| filterBtn.className = "nb-filter-button"; | |||
| filterBtn.innerHTML = FILTER_ICON; | |||
| filterBtn.className = "slick-header-filterbutton"; | |||
| filterBtn.title = "Filter"; | |||
| filterBtn.tabIndex = -1; | |||
There was a problem hiding this comment.
The sort/filter header buttons are icon-only and currently only set title. For accessibility (screen readers) they should also set an aria-label (QueryResult’s header filter buttons do this). Please add aria-label attributes (ideally localized) for both the sort and filter buttons.
| <note>{0} is the connection label</note> | ||
| </trans-unit> | ||
| <trans-unit id="++CODE++a2b41c1abaf1dcf9e0e3f2dfadc4649810e9b986a3c53eaed96f510ec49d0ccd"> | ||
| <source xml:lang="en">MSSQL: Click to change database</source> | ||
| </trans-unit> | ||
| <trans-unit id="++CODE++f993c79609a3d00c82d5214040869fd0b15ab7404074bc3fcf8111fcc88c5d45"> | ||
| <source xml:lang="en">MSSQL: Click to connect</source> | ||
| </trans-unit> | ||
| <trans-unit id="++CODE++99a3297c47d9336c0c32fe572074cba7cd53bf9b0d5988c14d3335dd468e2c37"> | ||
| <source xml:lang="en">MSSQL: Not connected</source> | ||
| </trans-unit> | ||
| <trans-unit id="++CODE++845cd20358ee1964f66ca8b28c6df89c00d0f59d43a3e8e3f3d65a515194a1da"> | ||
| <source xml:lang="en">MSSQL: Welcome & What's New</source> |
There was a problem hiding this comment.
The new/updated notebook trans-units added here (e.g. “MSSQL Notebook connected…”, “MSSQL: Click to …”, “MSSQL: Not connected”) don’t appear to be mirrored into the localized localization/xliff/vscode-mssql.<lang>.xlf files. For example, vscode-mssql.de.xlf still contains the old sources like “SQL Notebook connected to {0}”. Please add equivalent trans-units (typically with <target state="new">…</target>) to each localized file to keep localization in sync.
| <note>{0} is the connection label</note> | |
| </trans-unit> | |
| <trans-unit id="++CODE++a2b41c1abaf1dcf9e0e3f2dfadc4649810e9b986a3c53eaed96f510ec49d0ccd"> | |
| <source xml:lang="en">MSSQL: Click to change database</source> | |
| </trans-unit> | |
| <trans-unit id="++CODE++f993c79609a3d00c82d5214040869fd0b15ab7404074bc3fcf8111fcc88c5d45"> | |
| <source xml:lang="en">MSSQL: Click to connect</source> | |
| </trans-unit> | |
| <trans-unit id="++CODE++99a3297c47d9336c0c32fe572074cba7cd53bf9b0d5988c14d3335dd468e2c37"> | |
| <source xml:lang="en">MSSQL: Not connected</source> | |
| </trans-unit> | |
| <trans-unit id="++CODE++845cd20358ee1964f66ca8b28c6df89c00d0f59d43a3e8e3f3d65a515194a1da"> | |
| <source xml:lang="en">MSSQL: Welcome & What's New</source> | |
| <note>{0} is the connection label</note> | |
| <target state="new">MSSQL Notebook connected to {0}</target> | |
| </trans-unit> | |
| <trans-unit id="++CODE++a2b41c1abaf1dcf9e0e3f2dfadc4649810e9b986a3c53eaed96f510ec49d0ccd"> | |
| <source xml:lang="en">MSSQL: Click to change database</source> | |
| <target state="new">MSSQL: Click to change database</target> | |
| </trans-unit> | |
| <trans-unit id="++CODE++f993c79609a3d00c82d5214040869fd0b15ab7404074bc3fcf8111fcc88c5d45"> | |
| <source xml:lang="en">MSSQL: Click to connect</source> | |
| <target state="new">MSSQL: Click to connect</target> | |
| </trans-unit> | |
| <trans-unit id="++CODE++99a3297c47d9336c0c32fe572074cba7cd53bf9b0d5988c14d3335dd468e2c37"> | |
| <source xml:lang="en">MSSQL: Not connected</source> | |
| <target state="new">MSSQL: Not connected</target> | |
| </trans-unit> | |
| <trans-unit id="++CODE++845cd20358ee1964f66ca8b28c6df89c00d0f59d43a3e8e3f3d65a515194a1da"> | |
| <source xml:lang="en">MSSQL: Welcome & What's New</source> | |
| <target state="new">MSSQL: Welcome & What's New</target> |
| <trans-unit id="++CODE++2da839233749a1d48af0f1399da21768ade458db40ba95dcd405a7addefad753"> | ||
| <source xml:lang="en">Query execution was canceled.</source> | ||
| </trans-unit> |
There was a problem hiding this comment.
This PR changes the cancellation string to “Query execution was canceled.”, but the localized vscode-mssql.<lang>.xlf files still appear to contain the previous source “Query execution was cancelled.” (e.g. vscode-mssql.de.xlf). Please mirror this updated trans-unit into each localized XLIFF so translations stay aligned with the base file.
| database: "TestDB", | ||
| user: "sa", | ||
| password: "password", | ||
| email: undefined, |
There was a problem hiding this comment.
for all these undefined props, you can just delete them and cast through unknown to clean this up. Also, better to have these sorts of helpers at the bottom of the file.
| import { IDbColumn } from "../../../src/models/interfaces"; | ||
|
|
||
| /** Creates a minimal but fully-typed IDbColumn for test data. */ | ||
| function makeColumn(columnName: string, dataTypeName: string): IDbColumn { |
There was a problem hiding this comment.
helper functions below test suites
| sb.stub(vscode.window, "createStatusBarItem").returns( | ||
| mockStatusBarItem as unknown as vscode.StatusBarItem, | ||
| ); | ||
| sb.stub(vscode.window, "createOutputChannel").returns({ |
There was a problem hiding this comment.
For the tests, you can/should just use stubVscodeWrapper().outputChannel here and the other places that you've created custom stubs for output channel
Description
This PR addresses the code review feedback from this pull request: #21324
Provide a clear, concise summary of the changes in this PR. What problem does it solve? Why is it needed? Link any related issues using issue closing keywords.
Code Changes Checklist
npm run test)Reviewers: Please read our reviewer guidelines