Skip to content

Add "Copy As" submenu to Notebook Query Result context menus#22395

Draft
lewis-sanchez wants to merge 15 commits into
mainfrom
lewissanchez/editData/copy-as-submenu
Draft

Add "Copy As" submenu to Notebook Query Result context menus#22395
lewis-sanchez wants to merge 15 commits into
mainfrom
lewissanchez/editData/copy-as-submenu

Conversation

@lewis-sanchez

@lewis-sanchez lewis-sanchez commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Description

This PR fixes #22209

This PR adds a sub-context menu for "Copy As" commands, so that they are similar to the ones present in the query results grid for regular query editors. There are a total of 4 "Copy As" commands that are being added:

  1. Copy as CSV
  2. Copy as JSON
  3. Copy as INSERT INTO
  4. Copy as IN clause

Because the iframe where the query results grid is rendered doesn't have a way to communicate back to SQL Tools Service, the copying logic had to be implemented client side, otherwise we most likely could have reused the same copying functionality used by the regular query results grid.

The new context menu options appear in the results grid that appears after a query is executed in a SQL notebook:
image

Result Grid and Notebook Result Grid

Result Grid:

Copy as CSV

image
John,2003-11-09,john.smith@example.com
Mariah,2004-01-30,mariah.jones@example.com
John,2003-11-09,john.smith@example.com
Mariah,2004-01-30,mariah.jones@example.com
John,2003-11-09,john.smith@example.com
Mariah,2004-01-30,mariah.jones@example.com
image

Copy as JSON

[
  {
    "FirstName": "John",
    "DateOfBirth": null,
    "Email": "john.smith@example.com"
  },
  {
    "FirstName": "Mariah",
    "DateOfBirth": null,
    "Email": "mariah.jones@example.com"
  },
  {
    "FirstName": "John",
    "DateOfBirth": null,
    "Email": "john.smith@example.com"
  },
  {
    "FirstName": "Mariah",
    "DateOfBirth": null,
    "Email": "mariah.jones@example.com"
  },
  {
    "FirstName": null,
    "DateOfBirth": "2005-01-01T00:00:00",
    "Email": null
  },
  {
    "FirstName": null,
    "DateOfBirth": "2005-01-02T00:00:00",
    "Email": null
  }
]

Copy as INSERT INTO

image
INSERT INTO TableName (FirstName, DateOfBirth, Email)
VALUES
    ('John', '2003-11-09', 'john.smith@example.com'),
    ('Mariah', '2004-01-30', 'mariah.jones@example.com'),
    ('John', '2003-11-09', 'john.smith@example.com'),
    ('Mariah', '2004-01-30', 'mariah.jones@example.com'),
    ('John', '2003-11-09', 'john.smith@example.com'),
    ('Mariah', '2004-01-30', 'mariah.jones@example.com');
image
INSERT INTO TableName (FirstName, DateOfBirth, Email)
VALUES
    ('John', NULL, NULL),
    ('Mariah', NULL, NULL),
    (NULL, '2005-01-01', NULL),
    (NULL, '2005-01-02', NULL),
    (NULL, NULL, 'j.oneil@example.com'),
    (NULL, NULL, 'Stu.Brad@example.com');
image
INSERT INTO TableName (FirstName, DateOfBirth, Email)
VALUES
    (NULL, '2005-01-01', NULL),
    (NULL, '2005-01-02', NULL),
    ('Jacob', NULL, NULL),
    ('Stu', NULL, NULL),
    (NULL, NULL, 'john.smith@example.com'),
    (NULL, NULL, 'mariah.jones@example.com');

Copy as IN Clause

image image image
IN
(
    'Cindy',
    'Mariah',
    'Jim'
)

Notebook Result Grid:

Copy as CSV

image
John,2003-11-09,john.smith@example.com
Mariah,2004-01-30,mariah.jones@example.com
John,2003-11-09,john.smith@example.com
Mariah,2004-01-30,mariah.jones@example.com
John,2003-11-09,john.smith@example.com
Mariah,2004-01-30,mariah.jones@example.com

Copy as JSON

image
[
  {
    "FirstName": "John",
    "DateOfBirth": null,
    "Email": "john.smith@example.com"
  },
  {
    "FirstName": "Mariah",
    "DateOfBirth": null,
    "Email": "mariah.jones@example.com"
  },
  {
    "FirstName": "John",
    "DateOfBirth": null,
    "Email": "john.smith@example.com"
  },
  {
    "FirstName": "Mariah",
    "DateOfBirth": null,
    "Email": "mariah.jones@example.com"
  },
  {
    "FirstName": null,
    "DateOfBirth": "2005-01-01",
    "Email": null
  },
  {
    "FirstName": null,
    "DateOfBirth": "2005-01-02",
    "Email": null
  }
]

Copy as INSERT INTO

image
INSERT INTO TableName (FirstName, DateOfBirth, Email)
VALUES
    ('John', '2003-11-09', 'john.smith@example.com'),
    ('Mariah', '2004-01-30', 'mariah.jones@example.com'),
    ('John', '2003-11-09', 'john.smith@example.com'),
    ('Mariah', '2004-01-30', 'mariah.jones@example.com'),
    ('John', '2003-11-09', 'john.smith@example.com'),
    ('Mariah', '2004-01-30', 'mariah.jones@example.com');
image
INSERT INTO TableName (FirstName, DateOfBirth, Email)
VALUES
    ('John', NULL, NULL),
    ('Mariah', NULL, NULL),
    (NULL, '2005-01-01', NULL),
    (NULL, '2005-01-02', NULL),
    (NULL, NULL, 'j.oneil@example.com'),
    (NULL, NULL, 'Stu.Brad@example.com');
image
INSERT INTO TableName (FirstName, DateOfBirth, Email)
VALUES
    (NULL, '2005-01-01', NULL),
    (NULL, '2005-01-02', NULL),
    ('Jacob', NULL, NULL),
    ('Stu', NULL, NULL),
    (NULL, NULL, 'john.smith@example.com'),
    (NULL, NULL, 'mariah.jones@example.com');

Copy as IN clause

image
image
image
IN
(
    'Cindy',
    'Mariah',
    'Jim'
)

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

  • New or updated unit tests added
  • All existing tests pass (npm run test)
  • Code follows contributing guidelines
  • Telemetry/logging updated if relevant
  • No regressions or UX breakage

Reviewers: Please read our reviewer guidelines

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a “Copy As” submenu to the Notebook query results grid context menu (matching the regular query editor grid UX) and implements the associated client-side formatting/copying behavior, including an iframe→extension-host path for displaying errors.

Changes:

  • Adds a “Copy As” submenu to the notebook grid context menu with CSV/JSON/INSERT INTO/IN clause formatting.
  • Plumbs postMessage through the notebook renderer so the context menu can surface errors via the extension host.
  • Introduces unit tests covering the new formatter behaviors.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
localization/xliff/vscode-mssql.xlf Adds localized string entry for the IN-clause single-column error.
extensions/mssql/test/unit/notebooks/notebookContextMenu.test.ts New unit tests validating CSV/JSON/IN clause/INSERT formatting behavior.
extensions/mssql/src/webviews/pages/NotebookRenderer/notebookResultsOutput.tsx Passes postMessage down to the result grid component.
extensions/mssql/src/webviews/pages/NotebookRenderer/notebookResultGrid.tsx Extends grid props with postMessage and wires it into the context menu plugin.
extensions/mssql/src/webviews/pages/NotebookRenderer/notebookResultGrid.css Updates context menu styling and adds focused/hover/submenu indicator styling.
extensions/mssql/src/webviews/pages/NotebookRenderer/notebookRendererEntry.tsx Passes renderer postMessage into the notebook result grid.
extensions/mssql/src/webviews/pages/NotebookRenderer/notebookContextMenu.plugin.ts Implements submenu + new “Copy As” actions and client-side formatters; adds keyboard navigation and error posting.
extensions/mssql/src/webviews/common/locConstants.ts Adds localized constant for the IN-clause single-column error message.
extensions/mssql/src/sharedInterfaces/notebookQueryResult.ts Adds NotebookShowErrorMessage interface for renderer messaging.
extensions/mssql/src/notebooks/sqlNotebookController.ts Handles showError renderer messages by calling vscode.window.showErrorMessage.
extensions/mssql/l10n/bundle.l10n.json Adds localized string entry for the IN-clause single-column error.

Comment on lines 172 to 176
// Use setTimeout so the current right-click event doesn't immediately dismiss the menu
setTimeout(() => {
menu.focus();
document.addEventListener("mousedown", this.dismissHandler!);
}, 0);
Comment thread extensions/mssql/test/unit/notebooks/notebookContextMenu.test.ts
@github-actions

github-actions Bot commented Jun 26, 2026

Copy link
Copy Markdown

PR Changes

Category Target Branch PR Branch Difference
vscode-mssql VSIX 79310 KB 79291 KB ⚪ -19 KB ( 0% )
sql-database-projects VSIX 2950 KB 2945 KB ⚪ -5 KB ( 0% )
data-workspace VSIX 188 KB 188 KB ⚪ 0 KB ( 0% )
keymap VSIX 7 KB 7 KB ⚪ 0 KB ( 0% )

@codecov-commenter

codecov-commenter commented Jun 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 52.91751% with 234 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.59%. Comparing base (b10efdc) to head (4fdad04).
⚠️ Report is 18 commits behind head on main.

Files with missing lines Patch % Lines
...ges/NotebookRenderer/notebookContextMenu.plugin.ts 52.91% 226 Missing ⚠️
...sions/mssql/src/notebooks/sqlNotebookController.ts 11.11% 8 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (b10efdc) and HEAD (4fdad04). Click for more details.

HEAD has 3 uploads less than BASE
Flag BASE (b10efdc) HEAD (4fdad04)
mssql 2 1
sqlproj 2 1
data-workspace 2 1
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##             main   #22395       +/-   ##
===========================================
- Coverage   88.25%   75.59%   -12.67%     
===========================================
  Files         415      408        -7     
  Lines      131028   131338      +310     
  Branches     8393     8426       +33     
===========================================
- Hits       115640    99282    -16358     
- Misses      15388    32056    +16668     
Flag Coverage Δ
data-workspace 78.37% <ø> (ø)
mssql 75.23% <52.91%> (-14.10%) ⬇️
sqlproj 78.87% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
.../mssql/src/sharedInterfaces/notebookQueryResult.ts 100.00% <100.00%> (ø)
...tensions/mssql/src/webviews/common/locConstants.ts 25.59% <100.00%> (-62.52%) ⬇️
...sions/mssql/src/notebooks/sqlNotebookController.ts 68.95% <11.11%> (-23.15%) ⬇️
...ges/NotebookRenderer/notebookContextMenu.plugin.ts 43.93% <52.91%> (ø)

... and 202 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@lewis-sanchez
lewis-sanchez marked this pull request as draft July 7, 2026 20:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: SQL Notebook result grid context menu is missing the "Copy As" submenu

3 participants