Skip to content

Commit 35221cb

Browse files
authored
Copy-and-Paste 2: Basic copy and paste task (#147)
2 parents 3817c60 + 85c31a4 commit 35221cb

15 files changed

Lines changed: 998 additions & 43 deletions

l10n/bundle.l10n.json

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,15 @@
1717
"⏩ Run All": "⏩ Run All",
1818
"⏳ Running All…": "⏳ Running All…",
1919
"⏳ Running Command…": "⏳ Running Command…",
20+
"⏹️ Task '{taskName}' was stopped. {message}": "⏹️ Task '{taskName}' was stopped. {message}",
2021
"▶️ Run Command": "▶️ Run Command",
22+
"▶️ Task '{taskName}' starting...": "▶️ Task '{taskName}' starting...",
2123
"⚠️ **Security:** TLS/SSL Disabled": "⚠️ **Security:** TLS/SSL Disabled",
24+
"⚠️ Task '{taskName}' failed. {message}": "⚠️ Task '{taskName}' failed. {message}",
2225
"⚠ TLS/SSL Disabled": "⚠ TLS/SSL Disabled",
2326
"✅ **Security:** TLS/SSL Enabled": "✅ **Security:** TLS/SSL Enabled",
27+
"✅ Task '{taskName}' completed successfully. {message}": "✅ Task '{taskName}' completed successfully. {message}",
28+
"🟡 Task '{taskName}' initializing...": "🟡 Task '{taskName}' initializing...",
2429
"$(add) Create...": "$(add) Create...",
2530
"$(check) Success": "$(check) Success",
2631
"$(error) Failure": "$(error) Failure",
@@ -46,7 +51,9 @@
4651
"Always upload": "Always upload",
4752
"An element with the following id already exists: {id}": "An element with the following id already exists: {id}",
4853
"An error has occurred. Check output window for more details.": "An error has occurred. Check output window for more details.",
54+
"An error occurred while writing documents: {0}": "An error occurred while writing documents: {0}",
4955
"An item with id \"{0}\" already exists for workspace \"{1}\".": "An item with id \"{0}\" already exists for workspace \"{1}\".",
56+
"An unknown error occurred while inserting documents.": "An unknown error occurred while inserting documents.",
5057
"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}\".",
5158
"API: Registered new migration provider: \"{providerId}\" - \"{providerLabel}\"": "API: Registered new migration provider: \"{providerId}\" - \"{providerLabel}\"",
5259
"Are you sure?": "Are you sure?",
@@ -81,6 +88,7 @@
8188
"Click here to retry": "Click here to retry",
8289
"Click here to update credentials": "Click here to update credentials",
8390
"Click to view resource": "Click to view resource",
91+
"Collection \"{0}\" from database \"{1}\" has been marked for copy.": "Collection \"{0}\" from database \"{1}\" has been marked for copy.",
8492
"Collection name cannot begin with the system. prefix (Reserved for internal use).": "Collection name cannot begin with the system. prefix (Reserved for internal use).",
8593
"Collection name cannot contain .system.": "Collection name cannot contain .system.",
8694
"Collection name cannot contain the $.": "Collection name cannot contain the $.",
@@ -98,10 +106,16 @@
98106
"Connection string is not set": "Connection string is not set",
99107
"Connection string not found.": "Connection string not found.",
100108
"Connection updated successfully.": "Connection updated successfully.",
109+
"Copied {0} of {1} documents": "Copied {0} of {1} documents",
110+
"Copy": "Copy",
111+
"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.",
112+
"Copy \"{sourceCollection}\" from \"{sourceDatabase}\" to \"{targetDatabase}/{targetCollection}\"": "Copy \"{sourceCollection}\" from \"{sourceDatabase}\" to \"{targetDatabase}/{targetCollection}\"",
113+
"Copy operation completed successfully": "Copy operation completed successfully",
101114
"CosmosDB Accounts": "CosmosDB Accounts",
102115
"Could not find {0}": "Could not find {0}",
103116
"Could not find the Azure Resource Groups extension": "Could not find the Azure Resource Groups extension",
104117
"Could not find unique name for new file.": "Could not find unique name for new file.",
118+
"Counting documents in source collection...": "Counting documents in source collection...",
105119
"Create an Azure Account...": "Create an Azure Account...",
106120
"Create an Azure for Students Account...": "Create an Azure for Students Account...",
107121
"Create collection": "Create collection",
@@ -148,6 +162,7 @@
148162
"Element with id of {rootId} not found.": "Element with id of {rootId} not found.",
149163
"Enable TLS/SSL (Default)": "Enable TLS/SSL (Default)",
150164
"Enforce TLS/SSL checks for a secure connection.": "Enforce TLS/SSL checks for a secure connection.",
165+
"Ensuring target collection exists...": "Ensuring target collection exists...",
151166
"Enter a collection name.": "Enter a collection name.",
152167
"Enter a database name.": "Enter a database name.",
153168
"Enter the Azure VM tag key used for discovering DocumentDB instances.": "Enter the Azure VM tag key used for discovering DocumentDB instances.",
@@ -189,26 +204,37 @@
189204
"Exporting documents": "Exporting documents",
190205
"Exporting…": "Exporting…",
191206
"Extension dependency with id \"{0}\" must be updated.": "Extension dependency with id \"{0}\" must be updated.",
207+
"Failed to abort transaction: {0}": "Failed to abort transaction: {0}",
208+
"Failed to commit transaction: {0}": "Failed to commit transaction: {0}",
192209
"Failed to connect to \"{cluster}\"": "Failed to connect to \"{cluster}\"",
193210
"Failed to connect to VM \"{vmName}\"": "Failed to connect to VM \"{vmName}\"",
211+
"Failed to copy collection: {0}": "Failed to copy collection: {0}",
212+
"Failed to count documents in source collection: {0}": "Failed to count documents in source collection: {0}",
194213
"Failed to create Azure management clients: {0}": "Failed to create Azure management clients: {0}",
195214
"Failed to create role assignment \"{0}\" for the {2} resource \"{1}\".": "Failed to create role assignment \"{0}\" for the {2} resource \"{1}\".",
196215
"Failed to create role assignment(s).": "Failed to create role assignment(s).",
197216
"Failed to delete documents. Unknown error.": "Failed to delete documents. Unknown error.",
198217
"Failed to delete item \"{0}\".": "Failed to delete item \"{0}\".",
199218
"Failed to delete secrets for item \"{0}\".": "Failed to delete secrets for item \"{0}\".",
219+
"Failed to end session: {0}": "Failed to end session: {0}",
220+
"Failed to ensure target collection exists: {0}": "Failed to ensure target collection exists: {0}",
200221
"Failed to export documents. Please see the output for details.": "Failed to export documents. Please see the output for details.",
201222
"Failed to extract the connection string from the selected account.": "Failed to extract the connection string from the selected account.",
202223
"Failed to extract the connection string from the selected node.": "Failed to extract the connection string from the selected node.",
203224
"Failed to find commandId on generic tree item.": "Failed to find commandId on generic tree item.",
225+
"Failed to get collection {0} in database {1}: {2}": "Failed to get collection {0} in database {1}: {2}",
204226
"Failed to get public IP": "Failed to get public IP",
205227
"Failed to initialize Azure management clients": "Failed to initialize Azure management clients",
206228
"Failed to initialize task": "Failed to initialize task",
229+
"Failed to overwrite documents: {0}": "Failed to overwrite documents: {0}",
207230
"Failed to parse secrets for key {0}:": "Failed to parse secrets for key {0}:",
208231
"Failed to process URI: {0}": "Failed to process URI: {0}",
209232
"Failed to rename the connection.": "Failed to rename the connection.",
210233
"Failed to save credentials for \"{cluster}\".": "Failed to save credentials for \"{cluster}\".",
211234
"Failed to save credentials.": "Failed to save credentials.",
235+
"Failed to start a session: {0}": "Failed to start a session: {0}",
236+
"Failed to start a transaction with the provided session: {0}": "Failed to start a transaction with the provided session: {0}",
237+
"Failed to start a transaction: {0}": "Failed to start a transaction: {0}",
212238
"Failed to store secrets for key {0}:": "Failed to store secrets for key {0}:",
213239
"Failed to update the connection.": "Failed to update the connection.",
214240
"Failed with code \"{0}\".": "Failed with code \"{0}\".",
@@ -253,6 +279,7 @@
253279
"Invalid connection type selected.": "Invalid connection type selected.",
254280
"Invalid document ID: {0}": "Invalid document ID: {0}",
255281
"Invalid semver \"{0}\".": "Invalid semver \"{0}\".",
282+
"Invalid source or target node type.": "Invalid source or target node type.",
256283
"Invalid workspace resource ID: {0}": "Invalid workspace resource ID: {0}",
257284
"JSON View": "JSON View",
258285
"Learn more": "Learn more",
@@ -292,6 +319,7 @@
292319
"No": "No",
293320
"No Azure subscription found for this tree item.": "No Azure subscription found for this tree item.",
294321
"No Azure VMs found with tag \"{tagName}\" in subscription \"{subscriptionName}\".": "No Azure VMs found with tag \"{tagName}\" in subscription \"{subscriptionName}\".",
322+
"No collection has been marked for copy. Please use Copy Collection first.": "No collection has been marked for copy. Please use Copy Collection first.",
295323
"No collection selected.": "No collection selected.",
296324
"No commands found in this document.": "No commands found in this document.",
297325
"No Connectivity": "No Connectivity",
@@ -304,6 +332,7 @@
304332
"No scope was provided for the role assignment.": "No scope was provided for the role assignment.",
305333
"No session found for id {sessionId}": "No session found for id {sessionId}",
306334
"No subscriptions found": "No subscriptions found",
335+
"No target node selected.": "No target node selected.",
307336
"Not connected to any MongoDB database.": "Not connected to any MongoDB database.",
308337
"Note: This confirmation type can be configured in the extension settings.": "Note: This confirmation type can be configured in the extension settings.",
309338
"Note: You can disable these URL handling confirmations in the extension settings.": "Note: You can disable these URL handling confirmations in the extension settings.",
@@ -369,8 +398,11 @@
369398
"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.",
370399
"Simulated failure at step {0} for testing purposes": "Simulated failure at step {0} for testing purposes",
371400
"Skip for now": "Skip for now",
401+
"Skipped document with _id: {0} due to error: {1}": "Skipped document with _id: {0} due to error: {1}",
372402
"Small breadcrumb example with buttons": "Small breadcrumb example with buttons",
373403
"Some items could not be displayed": "Some items could not be displayed",
404+
"Source collection is empty.": "Source collection is empty.",
405+
"Source: Collection \"{0}\" from database \"{1}\", connectionId: {2}": "Source: Collection \"{0}\" from database \"{1}\", connectionId: {2}",
374406
"Specified character lengths should be 1 character or greater.": "Specified character lengths should be 1 character or greater.",
375407
"Started executable: \"{command}\". Connecting to host…": "Started executable: \"{command}\". Connecting to host…",
376408
"Starting executable: \"{command}\"": "Starting executable: \"{command}\"",
@@ -386,6 +418,8 @@
386418
"Tag can only contain alphanumeric characters, underscores, periods, and hyphens.": "Tag can only contain alphanumeric characters, underscores, periods, and hyphens.",
387419
"Tag cannot be empty.": "Tag cannot be empty.",
388420
"Tag cannot be longer than 256 characters.": "Tag cannot be longer than 256 characters.",
421+
"Target: Collection \"{0}\" from database \"{1}\", connectionId: {2}": "Target: Collection \"{0}\" from database \"{1}\", connectionId: {2}",
422+
"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.",
389423
"Task completed successfully": "Task completed successfully",
390424
"Task created and ready to start": "Task created and ready to start",
391425
"Task failed": "Task failed",
@@ -479,7 +513,6 @@
479513
"with Popover": "with Popover",
480514
"Working…": "Working…",
481515
"Would you like to open the Collection View?": "Would you like to open the Collection View?",
482-
"Write error: {0}": "Write error: {0}",
483516
"Yes": "Yes",
484517
"Yes, continue": "Yes, continue",
485518
"Yes, open Collection View": "Yes, open Collection View",

package.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,18 @@
444444
"category": "DocumentDB",
445445
"command": "vscode-documentdb.command.containerView.open",
446446
"title": "Open Collection"
447+
},
448+
{
449+
"//": "Copy Collection",
450+
"category": "DocumentDB",
451+
"command": "vscode-documentdb.command.copyCollection",
452+
"title": "Copy Collection…"
453+
},
454+
{
455+
"//": "Paste Collection",
456+
"category": "DocumentDB",
457+
"command": "vscode-documentdb.command.pasteCollection",
458+
"title": "Paste Collection…"
447459
}
448460
],
449461
"submenus": [
@@ -682,6 +694,18 @@
682694
"command": "vscode-documentdb.command.refresh",
683695
"when": "view =~ /discoveryView/ && viewItem =~ /\\benableRefreshCommand\\b/i",
684696
"group": "zheLastGroup@1"
697+
},
698+
{
699+
"//": "[Collection] Copy Collection",
700+
"command": "vscode-documentdb.command.copyCollection",
701+
"when": "view =~ /connectionsView|discoveryView/ && viewItem =~ /treeitem[.]collection(?![a-z.\\/])/i && viewItem =~ /experience[.](mongocluster|mongodb)/i",
702+
"group": "A@2"
703+
},
704+
{
705+
"//": "[Collection] Paste Collection",
706+
"command": "vscode-documentdb.command.pasteCollection",
707+
"when": "view =~ /connectionsView|discoveryView/ && viewItem =~ /treeitem[.]collection(?![a-z.\\/])/i && viewItem =~ /experience[.](mongocluster|mongodb)/i",
708+
"group": "A@2"
685709
}
686710
],
687711
"explorer/context": [],
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { type IActionContext } from '@microsoft/vscode-azext-utils';
7+
import * as vscode from 'vscode';
8+
import { ext } from '../../extensionVariables';
9+
import { type CollectionItem } from '../../tree/documentdb/CollectionItem';
10+
11+
export async function copyCollection(_context: IActionContext, node: CollectionItem): Promise<void> {
12+
if (!node) {
13+
throw new Error(vscode.l10n.t('No node selected.'));
14+
}
15+
// Store the node in extension variables
16+
ext.copiedCollectionNode = node;
17+
18+
// Show confirmation message
19+
const collectionName = node.collectionInfo.name;
20+
const databaseName = node.databaseInfo.name;
21+
22+
void vscode.window.showInformationMessage(
23+
vscode.l10n.t('Collection "{0}" from database "{1}" has been marked for copy.', collectionName, databaseName),
24+
);
25+
}

src/commands/importDocuments/importDocuments.ts

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import * as l10n from '@vscode/l10n';
88
import { EJSON, type Document } from 'bson';
99
import * as fs from 'node:fs/promises';
1010
import * as vscode from 'vscode';
11-
import { ClustersClient } from '../../documentdb/ClustersClient';
11+
import { ClustersClient, isBulkWriteError } from '../../documentdb/ClustersClient';
1212
import {
1313
AzureDomains,
1414
getHostsFromConnectionString,
@@ -285,10 +285,31 @@ async function insertDocumentWithBufferIntoCluster(
285285
// Documents to process could be the current document (if too large)
286286
// or the contents of the buffer (if it was full)
287287
const client = await ClustersClient.getClient(node.cluster.id);
288-
const insertResult = await client.insertDocuments(databaseName, collectionName, documentsToProcess as Document[]);
289-
290-
return {
291-
count: insertResult.insertedCount,
292-
errorOccurred: insertResult.insertedCount < (documentsToProcess?.length || 0),
293-
};
288+
try {
289+
const insertResult = await client.insertDocuments(
290+
databaseName,
291+
collectionName,
292+
documentsToProcess as Document[],
293+
false,
294+
);
295+
return {
296+
count: insertResult.insertedCount,
297+
errorOccurred: false,
298+
};
299+
} catch (error) {
300+
if (isBulkWriteError(error)) {
301+
// Handle MongoDB bulk write errors
302+
// It could be a partial failure, so we need to check the result
303+
return {
304+
count: error.result.insertedCount,
305+
errorOccurred: true,
306+
};
307+
} else {
308+
// Handle other errors
309+
return {
310+
count: 0,
311+
errorOccurred: true,
312+
};
313+
}
314+
}
294315
}

0 commit comments

Comments
 (0)