Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
52a7720
added copy/paste commands to package.json
tnaum-ms Jun 10, 2025
59a970b
Merge branch 'feature/copy-and-paste' into dev/xingfan/111-copy-and-p…
tnaum-ms Jun 10, 2025
33f7d40
feat: basic copy+paste UX for experimenting
tnaum-ms Jun 10, 2025
aca6916
fix: updated eslint config to exclude the `api/dist` folder
tnaum-ms Jun 10, 2025
eab7593
Apply suggestions from code review
tnaum-ms Jun 10, 2025
30d5a72
Merge branch 'copilot/fix-130' of https://github.com/microsoft/vscode…
xingfan-git Jun 11, 2025
a4df3f6
Merge branch 'next' of https://github.com/microsoft/vscode-documentdb…
xingfan-git Jun 13, 2025
52eec8d
draft copy paste task
xingfan-git Jun 16, 2025
3a737fb
Revert "draft copy paste task"
xingfan-git Jun 19, 2025
1e76085
merge feature/copy-and-paste branch to pull changes for task progress
xingfan-git Jun 19, 2025
95ee9da
draft version for copy paste collection task
xingfan-git Jun 30, 2025
fbf169a
refine insert result parsing
xingfan-git Jul 12, 2025
c1e8552
two strategies
xingfan-git Jul 12, 2025
b721aaf
l10n
xingfan-git Jul 12, 2025
2458adc
overwrite
xingfan-git Jul 15, 2025
1f4c942
Merge branch 'feature/copy-and-paste' into dev/xingfan/111-copy-and-p…
tnaum-ms Aug 13, 2025
d8eff8d
Updated copy-paste-task, minor changes + update to final state reporting
tnaum-ms Aug 13, 2025
21b409b
l10n updates
tnaum-ms Aug 13, 2025
96a841c
feat: centralized task status udpates in the outputChannel
tnaum-ms Aug 13, 2025
a955b24
refreshed Copy-Paste task implememtation for readability
tnaum-ms Aug 13, 2025
7582e3b
ux tweak / emojii...
tnaum-ms Aug 13, 2025
3037998
refactoring file locations
tnaum-ms Aug 13, 2025
cd7983d
finalized refactoring
tnaum-ms Aug 13, 2025
e567242
removed obsolete code / commented out code.
tnaum-ms Aug 13, 2025
884116d
tweak to the copy-and-paste task display name
tnaum-ms Aug 13, 2025
85c31a4
fix: updated taskService tests to ignore ext.outputChannel.appendLine…
tnaum-ms Aug 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion l10n/bundle.l10n.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,15 @@
"⏩ Run All": "⏩ Run All",
"⏳ Running All…": "⏳ Running All…",
"⏳ Running Command…": "⏳ Running Command…",
"⏹️ Task '{taskName}' was stopped. {message}": "⏹️ Task '{taskName}' was stopped. {message}",
"▶️ Run Command": "▶️ Run Command",
"▶️ Task '{taskName}' starting...": "▶️ Task '{taskName}' starting...",
"⚠️ **Security:** TLS/SSL Disabled": "⚠️ **Security:** TLS/SSL Disabled",
"⚠️ Task '{taskName}' failed. {message}": "⚠️ Task '{taskName}' failed. {message}",
"⚠ TLS/SSL Disabled": "⚠ TLS/SSL Disabled",
"✅ **Security:** TLS/SSL Enabled": "✅ **Security:** TLS/SSL Enabled",
"✅ Task '{taskName}' completed successfully. {message}": "✅ Task '{taskName}' completed successfully. {message}",
"🟡 Task '{taskName}' initializing...": "🟡 Task '{taskName}' initializing...",
"$(add) Create...": "$(add) Create...",
"$(check) Success": "$(check) Success",
"$(error) Failure": "$(error) Failure",
Expand All @@ -46,7 +51,9 @@
"Always upload": "Always upload",
"An element with the following id already exists: {id}": "An element with the following id already exists: {id}",
"An error has occurred. Check output window for more details.": "An error has occurred. Check output window for more details.",
"An error occurred while writing documents: {0}": "An error occurred while writing documents: {0}",
"An item with id \"{0}\" already exists for workspace \"{1}\".": "An item with id \"{0}\" already exists for workspace \"{1}\".",
"An unknown error occurred while inserting documents.": "An unknown error occurred while inserting documents.",
"API version \"{0}\" for extension id \"{1}\" is no longer supported. Minimum version is \"{2}\".": "API version \"{0}\" for extension id \"{1}\" is no longer supported. Minimum version is \"{2}\".",
"API: Registered new migration provider: \"{providerId}\" - \"{providerLabel}\"": "API: Registered new migration provider: \"{providerId}\" - \"{providerLabel}\"",
"Are you sure?": "Are you sure?",
Expand Down Expand Up @@ -81,6 +88,7 @@
"Click here to retry": "Click here to retry",
"Click here to update credentials": "Click here to update credentials",
"Click to view resource": "Click to view resource",
"Collection \"{0}\" from database \"{1}\" has been marked for copy.": "Collection \"{0}\" from database \"{1}\" has been marked for copy.",
"Collection name cannot begin with the system. prefix (Reserved for internal use).": "Collection name cannot begin with the system. prefix (Reserved for internal use).",
"Collection name cannot contain .system.": "Collection name cannot contain .system.",
"Collection name cannot contain the $.": "Collection name cannot contain the $.",
Expand All @@ -98,10 +106,16 @@
"Connection string is not set": "Connection string is not set",
"Connection string not found.": "Connection string not found.",
"Connection updated successfully.": "Connection updated successfully.",
"Copied {0} of {1} documents": "Copied {0} of {1} documents",
"Copy": "Copy",
"Copy \"{0}\"\nto \"{1}\"?\nThis will add all documents from the source collection to the target collection.": "Copy \"{0}\"\nto \"{1}\"?\nThis will add all documents from the source collection to the target collection.",
"Copy \"{sourceCollection}\" from \"{sourceDatabase}\" to \"{targetDatabase}/{targetCollection}\"": "Copy \"{sourceCollection}\" from \"{sourceDatabase}\" to \"{targetDatabase}/{targetCollection}\"",
"Copy operation completed successfully": "Copy operation completed successfully",
"CosmosDB Accounts": "CosmosDB Accounts",
"Could not find {0}": "Could not find {0}",
"Could not find the Azure Resource Groups extension": "Could not find the Azure Resource Groups extension",
"Could not find unique name for new file.": "Could not find unique name for new file.",
"Counting documents in source collection...": "Counting documents in source collection...",
"Create an Azure Account...": "Create an Azure Account...",
"Create an Azure for Students Account...": "Create an Azure for Students Account...",
"Create collection": "Create collection",
Expand Down Expand Up @@ -148,6 +162,7 @@
"Element with id of {rootId} not found.": "Element with id of {rootId} not found.",
"Enable TLS/SSL (Default)": "Enable TLS/SSL (Default)",
"Enforce TLS/SSL checks for a secure connection.": "Enforce TLS/SSL checks for a secure connection.",
"Ensuring target collection exists...": "Ensuring target collection exists...",
"Enter a collection name.": "Enter a collection name.",
"Enter a database name.": "Enter a database name.",
"Enter the Azure VM tag key used for discovering DocumentDB instances.": "Enter the Azure VM tag key used for discovering DocumentDB instances.",
Expand Down Expand Up @@ -189,26 +204,37 @@
"Exporting documents": "Exporting documents",
"Exporting…": "Exporting…",
"Extension dependency with id \"{0}\" must be updated.": "Extension dependency with id \"{0}\" must be updated.",
"Failed to abort transaction: {0}": "Failed to abort transaction: {0}",
"Failed to commit transaction: {0}": "Failed to commit transaction: {0}",
"Failed to connect to \"{cluster}\"": "Failed to connect to \"{cluster}\"",
"Failed to connect to VM \"{vmName}\"": "Failed to connect to VM \"{vmName}\"",
"Failed to copy collection: {0}": "Failed to copy collection: {0}",
"Failed to count documents in source collection: {0}": "Failed to count documents in source collection: {0}",
"Failed to create Azure management clients: {0}": "Failed to create Azure management clients: {0}",
"Failed to create role assignment \"{0}\" for the {2} resource \"{1}\".": "Failed to create role assignment \"{0}\" for the {2} resource \"{1}\".",
"Failed to create role assignment(s).": "Failed to create role assignment(s).",
"Failed to delete documents. Unknown error.": "Failed to delete documents. Unknown error.",
"Failed to delete item \"{0}\".": "Failed to delete item \"{0}\".",
"Failed to delete secrets for item \"{0}\".": "Failed to delete secrets for item \"{0}\".",
"Failed to end session: {0}": "Failed to end session: {0}",
"Failed to ensure target collection exists: {0}": "Failed to ensure target collection exists: {0}",
"Failed to export documents. Please see the output for details.": "Failed to export documents. Please see the output for details.",
"Failed to extract the connection string from the selected account.": "Failed to extract the connection string from the selected account.",
"Failed to extract the connection string from the selected node.": "Failed to extract the connection string from the selected node.",
"Failed to find commandId on generic tree item.": "Failed to find commandId on generic tree item.",
"Failed to get collection {0} in database {1}: {2}": "Failed to get collection {0} in database {1}: {2}",
"Failed to get public IP": "Failed to get public IP",
"Failed to initialize Azure management clients": "Failed to initialize Azure management clients",
"Failed to initialize task": "Failed to initialize task",
"Failed to overwrite documents: {0}": "Failed to overwrite documents: {0}",
"Failed to parse secrets for key {0}:": "Failed to parse secrets for key {0}:",
"Failed to process URI: {0}": "Failed to process URI: {0}",
"Failed to rename the connection.": "Failed to rename the connection.",
"Failed to save credentials for \"{cluster}\".": "Failed to save credentials for \"{cluster}\".",
"Failed to save credentials.": "Failed to save credentials.",
"Failed to start a session: {0}": "Failed to start a session: {0}",
"Failed to start a transaction with the provided session: {0}": "Failed to start a transaction with the provided session: {0}",
"Failed to start a transaction: {0}": "Failed to start a transaction: {0}",
"Failed to store secrets for key {0}:": "Failed to store secrets for key {0}:",
"Failed to update the connection.": "Failed to update the connection.",
"Failed with code \"{0}\".": "Failed with code \"{0}\".",
Expand Down Expand Up @@ -253,6 +279,7 @@
"Invalid connection type selected.": "Invalid connection type selected.",
"Invalid document ID: {0}": "Invalid document ID: {0}",
"Invalid semver \"{0}\".": "Invalid semver \"{0}\".",
"Invalid source or target node type.": "Invalid source or target node type.",
"Invalid workspace resource ID: {0}": "Invalid workspace resource ID: {0}",
"JSON View": "JSON View",
"Learn more": "Learn more",
Expand Down Expand Up @@ -292,6 +319,7 @@
"No": "No",
"No Azure subscription found for this tree item.": "No Azure subscription found for this tree item.",
"No Azure VMs found with tag \"{tagName}\" in subscription \"{subscriptionName}\".": "No Azure VMs found with tag \"{tagName}\" in subscription \"{subscriptionName}\".",
"No collection has been marked for copy. Please use Copy Collection first.": "No collection has been marked for copy. Please use Copy Collection first.",
"No collection selected.": "No collection selected.",
"No commands found in this document.": "No commands found in this document.",
"No Connectivity": "No Connectivity",
Expand All @@ -304,6 +332,7 @@
"No scope was provided for the role assignment.": "No scope was provided for the role assignment.",
"No session found for id {sessionId}": "No session found for id {sessionId}",
"No subscriptions found": "No subscriptions found",
"No target node selected.": "No target node selected.",
"Not connected to any MongoDB database.": "Not connected to any MongoDB database.",
"Note: This confirmation type can be configured in the extension settings.": "Note: This confirmation type can be configured in the extension settings.",
"Note: You can disable these URL handling confirmations in the extension settings.": "Note: You can disable these URL handling confirmations in the extension settings.",
Expand Down Expand Up @@ -369,8 +398,11 @@
"Signing out programmatically is not supported. You must sign out by selecting the account in the Accounts menu and choosing Sign Out.": "Signing out programmatically is not supported. You must sign out by selecting the account in the Accounts menu and choosing Sign Out.",
"Simulated failure at step {0} for testing purposes": "Simulated failure at step {0} for testing purposes",
"Skip for now": "Skip for now",
"Skipped document with _id: {0} due to error: {1}": "Skipped document with _id: {0} due to error: {1}",
"Small breadcrumb example with buttons": "Small breadcrumb example with buttons",
"Some items could not be displayed": "Some items could not be displayed",
"Source collection is empty.": "Source collection is empty.",
"Source: Collection \"{0}\" from database \"{1}\", connectionId: {2}": "Source: Collection \"{0}\" from database \"{1}\", connectionId: {2}",
"Specified character lengths should be 1 character or greater.": "Specified character lengths should be 1 character or greater.",
"Started executable: \"{command}\". Connecting to host…": "Started executable: \"{command}\". Connecting to host…",
"Starting executable: \"{command}\"": "Starting executable: \"{command}\"",
Expand All @@ -386,6 +418,8 @@
"Tag can only contain alphanumeric characters, underscores, periods, and hyphens.": "Tag can only contain alphanumeric characters, underscores, periods, and hyphens.",
"Tag cannot be empty.": "Tag cannot be empty.",
"Tag cannot be longer than 256 characters.": "Tag cannot be longer than 256 characters.",
"Target: Collection \"{0}\" from database \"{1}\", connectionId: {2}": "Target: Collection \"{0}\" from database \"{1}\", connectionId: {2}",
"Task aborted due to an error: {0}. {1} document(s) were inserted in total.": "Task aborted due to an error: {0}. {1} document(s) were inserted in total.",
"Task completed successfully": "Task completed successfully",
"Task created and ready to start": "Task created and ready to start",
"Task failed": "Task failed",
Expand Down Expand Up @@ -479,7 +513,6 @@
"with Popover": "with Popover",
"Working…": "Working…",
"Would you like to open the Collection View?": "Would you like to open the Collection View?",
"Write error: {0}": "Write error: {0}",
"Yes": "Yes",
"Yes, continue": "Yes, continue",
"Yes, open Collection View": "Yes, open Collection View",
Expand Down
24 changes: 24 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,18 @@
"category": "DocumentDB",
"command": "vscode-documentdb.command.containerView.open",
"title": "Open Collection"
},
{
"//": "Copy Collection",
"category": "DocumentDB",
"command": "vscode-documentdb.command.copyCollection",
"title": "Copy Collection…"
},
{
"//": "Paste Collection",
"category": "DocumentDB",
"command": "vscode-documentdb.command.pasteCollection",
"title": "Paste Collection…"
}
],
"submenus": [
Expand Down Expand Up @@ -682,6 +694,18 @@
"command": "vscode-documentdb.command.refresh",
"when": "view =~ /discoveryView/ && viewItem =~ /\\benableRefreshCommand\\b/i",
"group": "zheLastGroup@1"
},
{
"//": "[Collection] Copy Collection",
"command": "vscode-documentdb.command.copyCollection",
"when": "view =~ /connectionsView|discoveryView/ && viewItem =~ /treeitem[.]collection(?![a-z.\\/])/i && viewItem =~ /experience[.](mongocluster|mongodb)/i",
"group": "A@2"
},
{
"//": "[Collection] Paste Collection",
"command": "vscode-documentdb.command.pasteCollection",
"when": "view =~ /connectionsView|discoveryView/ && viewItem =~ /treeitem[.]collection(?![a-z.\\/])/i && viewItem =~ /experience[.](mongocluster|mongodb)/i",
"group": "A@2"
}
],
"explorer/context": [],
Expand Down
25 changes: 25 additions & 0 deletions src/commands/copyCollection/copyCollection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { type IActionContext } from '@microsoft/vscode-azext-utils';
import * as vscode from 'vscode';
import { ext } from '../../extensionVariables';
import { type CollectionItem } from '../../tree/documentdb/CollectionItem';

export async function copyCollection(_context: IActionContext, node: CollectionItem): Promise<void> {
if (!node) {
Comment thread
tnaum-ms marked this conversation as resolved.
throw new Error(vscode.l10n.t('No node selected.'));
Comment thread
tnaum-ms marked this conversation as resolved.
}
// Store the node in extension variables
ext.copiedCollectionNode = node;

// Show confirmation message
const collectionName = node.collectionInfo.name;
const databaseName = node.databaseInfo.name;

void vscode.window.showInformationMessage(
vscode.l10n.t('Collection "{0}" from database "{1}" has been marked for copy.', collectionName, databaseName),
);
}
35 changes: 28 additions & 7 deletions src/commands/importDocuments/importDocuments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import * as l10n from '@vscode/l10n';
import { EJSON, type Document } from 'bson';
import * as fs from 'node:fs/promises';
import * as vscode from 'vscode';
import { ClustersClient } from '../../documentdb/ClustersClient';
import { ClustersClient, isBulkWriteError } from '../../documentdb/ClustersClient';
import {
AzureDomains,
getHostsFromConnectionString,
Expand Down Expand Up @@ -285,10 +285,31 @@ async function insertDocumentWithBufferIntoCluster(
// Documents to process could be the current document (if too large)
// or the contents of the buffer (if it was full)
const client = await ClustersClient.getClient(node.cluster.id);
const insertResult = await client.insertDocuments(databaseName, collectionName, documentsToProcess as Document[]);

return {
count: insertResult.insertedCount,
errorOccurred: insertResult.insertedCount < (documentsToProcess?.length || 0),
};
try {
const insertResult = await client.insertDocuments(
databaseName,
collectionName,
documentsToProcess as Document[],
false,
);
return {
count: insertResult.insertedCount,
errorOccurred: false,
};
} catch (error) {
if (isBulkWriteError(error)) {
// Handle MongoDB bulk write errors
// It could be a partial failure, so we need to check the result
return {
count: error.result.insertedCount,
errorOccurred: true,
};
} else {
// Handle other errors
return {
count: 0,
errorOccurred: true,
};
}
}
}
Loading