Skip to content

Commit eaca062

Browse files
authored
feat(tree-explorer): Add open and copy document tree view context menu items VSCODE-348 (#445)
1 parent 4767b65 commit eaca062

13 files changed

+185
-40
lines changed

package.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,14 @@
404404
{
405405
"command": "mdb.generateObjectIdToClipboard",
406406
"title": "MongoDB: Generate ObjectId to Clipboard"
407+
},
408+
{
409+
"command": "mdb.openMongoDBDocumentFromTree",
410+
"title": "Open Document"
411+
},
412+
{
413+
"command": "mdb.copyDocumentContentsFromTreeView",
414+
"title": "Copy Document"
407415
}
408416
],
409417
"menus": {
@@ -590,6 +598,16 @@
590598
{
591599
"command": "mdb.createIndexFromTreeView",
592600
"when": "view == mongoDBConnectionExplorer && viewItem == indexListTreeItem"
601+
},
602+
{
603+
"command": "mdb.openMongoDBDocumentFromTree",
604+
"when": "view == mongoDBConnectionExplorer && viewItem == documentTreeItem",
605+
"group": "1@1"
606+
},
607+
{
608+
"command": "mdb.copyDocumentContentsFromTreeView",
609+
"when": "view == mongoDBConnectionExplorer && viewItem == documentTreeItem",
610+
"group": "2@1"
593611
}
594612
],
595613
"editor/title": [
@@ -755,6 +773,14 @@
755773
{
756774
"command": "mdb.copySchemaFieldName",
757775
"when": "false"
776+
},
777+
{
778+
"command": "mdb.openMongoDBDocumentFromTree",
779+
"when": "false"
780+
},
781+
{
782+
"command": "mdb.copyDocumentContentsFromTreeView",
783+
"when": "false"
758784
}
759785
]
760786
},

src/commands/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ enum EXTENSION_COMMANDS {
6060
MDB_CREATE_INDEX_TREE_VIEW = 'mdb.createIndexFromTreeView',
6161
MDB_INSERT_OBJECTID_TO_EDITOR = 'mdb.insertObjectIdToEditor',
6262
MDB_GENERATE_OBJECTID_TO_CLIPBOARD = 'mdb.generateObjectIdToClipboard',
63+
MDB_COPY_DOCUMENT_CONTENTS_FROM_TREE_VIEW = 'mdb.copyDocumentContentsFromTreeView',
6364
}
6465

6566
export default EXTENSION_COMMANDS;

src/editors/editorsController.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ export default class EditorsController {
124124
this._documentIdStore = new DocumentIdStore();
125125
this._mongoDBDocumentService = new MongoDBDocumentService(
126126
this._context,
127-
this._documentIdStore,
128127
this._connectionController,
129128
this._statusView,
130129
this._telemetryService

src/editors/mongoDBDocumentService.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { EJSON, Document } from 'bson';
44

55
import ConnectionController from '../connectionController';
66
import { createLogger } from '../logging';
7-
import DocumentIdStore from './documentIdStore';
87
import { DocumentSource } from '../documentSource';
98
import type { EditDocumentInfo } from '../types/editDocumentInfoType';
109
import formatError from '../utils/formatError';
@@ -21,20 +20,17 @@ export const VIEW_DOCUMENT_SCHEME = 'VIEW_DOCUMENT_SCHEME';
2120

2221
export default class MongoDBDocumentService {
2322
_context: vscode.ExtensionContext;
24-
_documentIdStore: DocumentIdStore;
2523
_connectionController: ConnectionController;
2624
_statusView: StatusView;
2725
_telemetryService: TelemetryService;
2826

2927
constructor(
3028
context: vscode.ExtensionContext,
31-
documentIdStore: DocumentIdStore,
3229
connectionController: ConnectionController,
3330
statusView: StatusView,
3431
telemetryService: TelemetryService
3532
) {
3633
this._context = context;
37-
this._documentIdStore = documentIdStore;
3834
this._connectionController = connectionController;
3935
this._statusView = statusView;
4036
this._telemetryService = telemetryService;

src/explorer/documentListTreeItem.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import DocumentTreeItem from './documentTreeItem';
77
import formatError from '../utils/formatError';
88
import { getImagesPath } from '../extensionConstants';
99
import TreeItemParent from './treeItemParentInterface';
10+
import type { DataService } from 'mongodb-data-service';
1011

1112
const path = require('path');
1213
const log = createLogger('tree view document list');
@@ -104,15 +105,15 @@ export default class DocumentListTreeItem
104105
namespace: string;
105106
type: CollectionTypes;
106107

107-
private _dataService: any;
108+
private _dataService: DataService;
108109

109110
isExpanded: boolean;
110111

111112
constructor(
112113
collectionName: string,
113114
databaseName: string,
114115
type: CollectionTypes,
115-
dataService: any,
116+
dataService: DataService,
116117
isExpanded: boolean,
117118
maxDocumentsToShow: number,
118119
cachedDocumentCount: number | null,
@@ -173,7 +174,8 @@ export default class DocumentListTreeItem
173174
new DocumentTreeItem(
174175
(pastTreeItem as DocumentTreeItem).document,
175176
this.namespace,
176-
index
177+
index,
178+
this._dataService
177179
)
178180
);
179181
});
@@ -217,7 +219,12 @@ export default class DocumentListTreeItem
217219
if (documents) {
218220
documents.forEach((document, index) => {
219221
this._childrenCache.push(
220-
new DocumentTreeItem(document, this.namespace, index)
222+
new DocumentTreeItem(
223+
document,
224+
this.namespace,
225+
index,
226+
this._dataService
227+
)
221228
);
222229
});
223230
}

src/explorer/documentTreeItem.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import { EJSON } from 'bson';
22
import * as vscode from 'vscode';
3+
import type { Document } from 'mongodb';
4+
import type { DataService } from 'mongodb-data-service';
5+
import { promisify } from 'util';
6+
import formatError from '../utils/formatError';
37

48
export const DOCUMENT_ITEM = 'documentTreeItem';
59

@@ -10,10 +14,16 @@ export default class DocumentTreeItem
1014
contextValue = DOCUMENT_ITEM;
1115

1216
namespace: string;
13-
document: any;
17+
dataService: DataService;
18+
document: Document;
1419
documentId: EJSON.SerializableTypes;
1520

16-
constructor(document: any, namespace: string, documentIndexInTree: number) {
21+
constructor(
22+
document: Document,
23+
namespace: string,
24+
documentIndexInTree: number,
25+
dataService: DataService
26+
) {
1727
// A document can not have a `_id` when it is in a view. In this instance
1828
// we just show the document's index in the tree.
1929
super(
@@ -27,6 +37,7 @@ export default class DocumentTreeItem
2737
? JSON.stringify(document._id)
2838
: `Document ${documentIndexInTree + 1}`;
2939

40+
this.dataService = dataService;
3041
this.document = document;
3142
this.documentId = document._id;
3243
this.namespace = namespace;
@@ -41,4 +52,23 @@ export default class DocumentTreeItem
4152
getChildren(): Thenable<DocumentTreeItem[]> {
4253
return Promise.resolve([]);
4354
}
55+
56+
async getStringifiedEJSONDocumentContents(): Promise<string> {
57+
try {
58+
const find = promisify(this.dataService.find.bind(this.dataService));
59+
const documents = await find(
60+
this.namespace,
61+
{ _id: this.documentId },
62+
{ limit: 1 }
63+
);
64+
65+
if (!documents || documents.length === 0) {
66+
throw new Error('document not found');
67+
}
68+
69+
return EJSON.stringify(documents[0], undefined, 2);
70+
} catch (error) {
71+
throw new Error(formatError(error).message);
72+
}
73+
}
4474
}

src/mdbExtensionController.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,17 @@ export default class MDBExtensionController implements vscode.Disposable {
550550
(playgroundsTreeItem: PlaygroundsTreeItem) =>
551551
this._playgroundController.openPlayground(playgroundsTreeItem.filePath)
552552
);
553+
this.registerCommand(
554+
EXTENSION_COMMANDS.MDB_COPY_DOCUMENT_CONTENTS_FROM_TREE_VIEW,
555+
async (documentTreeItem: DocumentTreeItem): Promise<boolean> => {
556+
const documentContents =
557+
await documentTreeItem.getStringifiedEJSONDocumentContents();
558+
await vscode.env.clipboard.writeText(documentContents);
559+
void vscode.window.showInformationMessage('Copied to clipboard.');
560+
561+
return true;
562+
}
563+
);
553564
this.registerCommand(
554565
EXTENSION_COMMANDS.MDB_INSERT_OBJECTID_TO_EDITOR,
555566
async (): Promise<boolean> => {

src/test/suite/editors/mongoDBDocumentService.test.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { EJSON } from 'bson';
55
import sinon from 'sinon';
66

77
import ConnectionController from '../../../connectionController';
8-
import DocumentIdStore from '../../../editors/documentIdStore';
98
import { DocumentSource } from '../../../documentSource';
109
import formatError from '../../../utils/formatError';
1110
import MongoDBDocumentService from '../../../editors/mongoDBDocumentService';
@@ -18,7 +17,6 @@ import { TestExtensionContext } from '../stubs';
1817
const expect = chai.expect;
1918

2019
suite('MongoDB Document Service Test Suite', () => {
21-
const testDocumentIdStore = new DocumentIdStore();
2220
const mockExtensionContext = new TestExtensionContext();
2321
const testStorageController = new StorageController(mockExtensionContext);
2422
const testStatusView = new StatusView(mockExtensionContext);
@@ -33,7 +31,6 @@ suite('MongoDB Document Service Test Suite', () => {
3331
);
3432
const testMongoDBDocumentService = new MongoDBDocumentService(
3533
mockExtensionContext,
36-
testDocumentIdStore,
3734
testConnectionController,
3835
testStatusView,
3936
testTelemetryService

src/test/suite/explorer/documentListTreeItem.test.ts

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import * as vscode from 'vscode';
2+
import { before } from 'mocha';
23
import assert from 'assert';
4+
import type { DataService } from 'mongodb-data-service';
35

46
const { contributes } = require('../../../../package.json');
57

@@ -12,13 +14,19 @@ import DocumentListTreeItem, {
1214
import { DataServiceStub, mockDocuments } from '../stubs';
1315

1416
suite('DocumentListTreeItem Test Suite', () => {
17+
let dataServiceMock: DataService;
18+
19+
before(() => {
20+
dataServiceMock = new DataServiceStub() as any as DataService;
21+
});
22+
1523
test('its context value should be in the package json', () => {
1624
let documentListRegisteredCommandInPackageJson = false;
1725
const testDocumentListTreeItem = new DocumentListTreeItem(
1826
'collectionName',
1927
'databaseName',
2028
CollectionTypes.collection,
21-
'not_real_dataservice',
29+
dataServiceMock,
2230
false,
2331
MAX_DOCUMENTS_VISIBLE,
2432
null,
@@ -44,7 +52,7 @@ suite('DocumentListTreeItem Test Suite', () => {
4452
'collectionName',
4553
'databaseName',
4654
CollectionTypes.collection,
47-
'not_real_dataservice',
55+
'not_real_dataservice' as any as DataService,
4856
false,
4957
MAX_DOCUMENTS_VISIBLE,
5058
null,
@@ -75,7 +83,7 @@ suite('DocumentListTreeItem Test Suite', () => {
7583
'mock_collection_name',
7684
'mock_db_name',
7785
CollectionTypes.collection,
78-
new DataServiceStub(),
86+
dataServiceMock,
7987
false,
8088
MAX_DOCUMENTS_VISIBLE,
8189
null,
@@ -96,7 +104,7 @@ suite('DocumentListTreeItem Test Suite', () => {
96104
'mock_collection_name',
97105
'mock_db_name',
98106
CollectionTypes.collection,
99-
new DataServiceStub(),
107+
dataServiceMock,
100108
false,
101109
MAX_DOCUMENTS_VISIBLE,
102110
null,
@@ -119,7 +127,7 @@ suite('DocumentListTreeItem Test Suite', () => {
119127
'mock_collection_name',
120128
'mock_db_name',
121129
CollectionTypes.view,
122-
new DataServiceStub(),
130+
dataServiceMock,
123131
false,
124132
MAX_DOCUMENTS_VISIBLE,
125133
null,
@@ -139,7 +147,7 @@ suite('DocumentListTreeItem Test Suite', () => {
139147
'mock_collection_name_1',
140148
'mock_db_name',
141149
CollectionTypes.collection,
142-
new DataServiceStub(),
150+
dataServiceMock,
143151
false,
144152
MAX_DOCUMENTS_VISIBLE,
145153
25,
@@ -166,7 +174,7 @@ suite('DocumentListTreeItem Test Suite', () => {
166174
'mock_collection_name_2',
167175
'mock_db_name',
168176
CollectionTypes.collection,
169-
new DataServiceStub(),
177+
dataServiceMock,
170178
false,
171179
MAX_DOCUMENTS_VISIBLE,
172180
25,
@@ -193,7 +201,7 @@ suite('DocumentListTreeItem Test Suite', () => {
193201
'mock_collection_name_3',
194202
'mock_db_name',
195203
CollectionTypes.collection,
196-
new DataServiceStub(),
204+
dataServiceMock,
197205
false,
198206
MAX_DOCUMENTS_VISIBLE,
199207
25,
@@ -225,7 +233,7 @@ suite('DocumentListTreeItem Test Suite', () => {
225233
'mock_collection_name_4',
226234
'mock_db_name',
227235
CollectionTypes.collection,
228-
new DataServiceStub(),
236+
dataServiceMock,
229237
false,
230238
MAX_DOCUMENTS_VISIBLE,
231239
25,
@@ -258,7 +266,7 @@ suite('DocumentListTreeItem Test Suite', () => {
258266
'mock_collection_name_1',
259267
'mock_db_name',
260268
CollectionTypes.collection,
261-
new DataServiceStub(),
269+
dataServiceMock,
262270
false,
263271
MAX_DOCUMENTS_VISIBLE,
264272
maxDocs,
@@ -275,7 +283,7 @@ suite('DocumentListTreeItem Test Suite', () => {
275283
'mock_collection_name_4',
276284
'mock_db_name',
277285
CollectionTypes.collection,
278-
new DataServiceStub(),
286+
dataServiceMock,
279287
false,
280288
MAX_DOCUMENTS_VISIBLE,
281289
maxDocs,
@@ -300,7 +308,7 @@ suite('DocumentListTreeItem Test Suite', () => {
300308
'mock_collection_name_4',
301309
'mock_db_name',
302310
CollectionTypes.view,
303-
new DataServiceStub(),
311+
dataServiceMock,
304312
false,
305313
MAX_DOCUMENTS_VISIBLE,
306314
null,
@@ -319,7 +327,7 @@ suite('DocumentListTreeItem Test Suite', () => {
319327
'mock_collection_name_4',
320328
'mock_db_name',
321329
CollectionTypes.collection,
322-
new DataServiceStub(),
330+
dataServiceMock,
323331
false,
324332
MAX_DOCUMENTS_VISIBLE,
325333
null,
@@ -340,7 +348,7 @@ suite('DocumentListTreeItem Test Suite', () => {
340348
'mock_collection_name_4',
341349
'mock_db_name',
342350
CollectionTypes.collection,
343-
new DataServiceStub(),
351+
dataServiceMock,
344352
false,
345353
MAX_DOCUMENTS_VISIBLE,
346354
25,
@@ -357,7 +365,7 @@ suite('DocumentListTreeItem Test Suite', () => {
357365
'mock_collection_name_4',
358366
'mock_db_name',
359367
CollectionTypes.collection,
360-
new DataServiceStub(),
368+
dataServiceMock,
361369
false,
362370
MAX_DOCUMENTS_VISIBLE,
363371
2200000,

0 commit comments

Comments
 (0)