Skip to content

Commit

Permalink
feat(tree-explorer): add buttons to ask Copilot and create playground…
Browse files Browse the repository at this point in the history
…s from tree view VSCODE-651 (#890)

Co-authored-by: Alena Khineika <[email protected]>
  • Loading branch information
gagik and alenakhineika authored Dec 6, 2024
1 parent 2dc7651 commit fabbc8c
Show file tree
Hide file tree
Showing 15 changed files with 268 additions and 30 deletions.
Binary file modified fonts/mongodb-icons.woff
Binary file not shown.
1 change: 1 addition & 0 deletions images/icons/playground.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
72 changes: 52 additions & 20 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,11 @@
"dark": "images/dark/add.svg"
}
},
{
"command": "mdb.createNewPlaygroundFromTreeItem",
"title": "Create MongoDB Playground",
"icon": "$(mdb-playground)"
},
{
"command": "mdb.changeActiveConnection",
"title": "MongoDB: Change Active Connection"
Expand Down Expand Up @@ -330,10 +335,7 @@
{
"command": "mdb.addDatabase",
"title": "Add Database...",
"icon": {
"light": "images/light/plus-circle.svg",
"dark": "images/dark/plus-circle.svg"
}
"icon": "$(mdb-plus-circle)"
},
{
"command": "mdb.searchForDocuments",
Expand Down Expand Up @@ -371,13 +373,15 @@
"command": "mdb.refreshDatabase",
"title": "Refresh"
},
{
"command": "mdb.askCopilotFromTreeItem",
"title": "Ask MongoDB Copilot",
"icon": "$(copilot)"
},
{
"command": "mdb.addCollection",
"title": "Add Collection...",
"icon": {
"light": "images/light/plus-circle.svg",
"dark": "images/dark/plus-circle.svg"
}
"icon": "$(mdb-plus-circle)"
},
{
"command": "mdb.viewCollectionDocuments",
Expand Down Expand Up @@ -422,10 +426,7 @@
{
"command": "mdb.createIndexFromTreeView",
"title": "Create New Index...",
"icon": {
"light": "images/light/plus-circle.svg",
"dark": "images/dark/plus-circle.svg"
}
"icon": "$(mdb-plus-circle)"
},
{
"command": "mdb.insertObjectIdToEditor",
Expand Down Expand Up @@ -454,10 +455,7 @@
{
"command": "mdb.addStreamProcessor",
"title": "Add StreamProcessor...",
"icon": {
"light": "images/light/plus-circle.svg",
"dark": "images/dark/plus-circle.svg"
}
"icon": "$(mdb-plus-circle)"
},
{
"command": "mdb.startStreamProcessor",
Expand Down Expand Up @@ -587,7 +585,7 @@
{
"command": "mdb.addCollection",
"when": "view == mongoDBConnectionExplorer && viewItem == databaseTreeItem",
"group": "inline"
"group": "inline@3"
},
{
"command": "mdb.addCollection",
Expand All @@ -604,10 +602,30 @@
"when": "view == mongoDBConnectionExplorer && viewItem == databaseTreeItem",
"group": "2@1"
},
{
"command": "mdb.askCopilotFromTreeItem",
"when": "mdb.isCopilotActive == true && view == mongoDBConnectionExplorer && (viewItem == databaseTreeItem || viewItem == collectionTreeItem)",
"group": "inline@1"
},
{
"command": "mdb.askCopilotFromTreeItem",
"when": "mdb.isCopilotActive == true && view == mongoDBConnectionExplorer && (viewItem == databaseTreeItem || viewItem == collectionTreeItem)",
"group": "3@1"
},
{
"command": "mdb.createNewPlaygroundFromTreeItem",
"when": "view == mongoDBConnectionExplorer && (viewItem == databaseTreeItem || viewItem == collectionTreeItem)",
"group": "inline@2"
},
{
"command": "mdb.createNewPlaygroundFromTreeItem",
"when": "view == mongoDBConnectionExplorer && (viewItem == databaseTreeItem || viewItem == collectionTreeItem)",
"group": "3@2"
},
{
"command": "mdb.dropDatabase",
"when": "view == mongoDBConnectionExplorer && viewItem == databaseTreeItem",
"group": "3@1"
"group": "4@1"
},
{
"command": "mdb.viewCollectionDocuments",
Expand Down Expand Up @@ -1157,19 +1175,33 @@
}
},
"icons": {
"mdb-connection-active": {
"mdb-playground": {
"description": "MongoDB Icon",
"default": {
"fontPath": "./fonts/mongodb-icons.woff",
"fontCharacter": "\\ea01"
}
},
"mdb-connection-inactive": {
"mdb-plus-circle": {
"description": "MongoDB Icon",
"default": {
"fontPath": "./fonts/mongodb-icons.woff",
"fontCharacter": "\\ea02"
}
},
"mdb-connection-active": {
"description": "MongoDB Icon",
"default": {
"fontPath": "./fonts/mongodb-icons.woff",
"fontCharacter": "\\ea03"
}
},
"mdb-connection-inactive": {
"description": "MongoDB Icon",
"default": {
"fontPath": "./fonts/mongodb-icons.woff",
"fontCharacter": "\\ea04"
}
}
}
},
Expand Down
15 changes: 13 additions & 2 deletions scripts/generate-icon-font.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import { GlyphData } from 'webfont/dist/src/types';
import prettier from 'prettier';

/** Icons to include in the generated icon font */
const INCLUDED_ICONS = ['connection-active', 'connection-inactive'];
const INCLUDED_ICONS = [
'light/connection-active',
'light/connection-inactive',
'playground',
'plus-circle',
];

/**
* Generates an icon font from the included icons and outputs package.json
Expand All @@ -13,7 +18,13 @@ const INCLUDED_ICONS = ['connection-active', 'connection-inactive'];
*/
async function main(): Promise<void> {
const font = await webfont({
files: INCLUDED_ICONS.map((icon) => `./images/light/${icon}.svg`),
files: INCLUDED_ICONS.map((icon) => {
// Legacy support for icons inside light and dark folders.
if (icon.startsWith('light/')) {
return `./images/${icon}.svg`;
}
return `./images/icons/${icon}.svg`;
}),
fontName: 'MongoDB Icons',
formats: ['woff'],
normalize: true,
Expand Down
2 changes: 2 additions & 0 deletions src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ enum EXTENSION_COMMANDS {
MDB_OPEN_PLAYGROUND_FROM_TREE_VIEW = 'mdb.openPlaygroundFromTreeView',
MDB_CONNECT_TO_CONNECTION_TREE_VIEW = 'mdb.connectToConnectionTreeItem',
MDB_CREATE_PLAYGROUND_FROM_TREE_VIEW = 'mdb.createNewPlaygroundFromTreeView',
MDB_CREATE_PLAYGROUND_FROM_TREE_ITEM = 'mdb.createNewPlaygroundFromTreeItem',
MDB_DISCONNECT_FROM_CONNECTION_TREE_VIEW = 'mdb.disconnectFromConnectionTreeItem',
MDB_EDIT_CONNECTION = 'mdb.editConnection',
MDB_REFRESH_CONNECTION = 'mdb.refreshConnection',
Expand Down Expand Up @@ -75,6 +76,7 @@ enum EXTENSION_COMMANDS {
OPEN_PARTICIPANT_CODE_IN_PLAYGROUND = 'mdb.openParticipantCodeInPlayground',
SEND_MESSAGE_TO_PARTICIPANT = 'mdb.sendMessageToParticipant',
SEND_MESSAGE_TO_PARTICIPANT_FROM_INPUT = 'mdb.sendMessageToParticipantFromInput',
ASK_COPILOT_FROM_TREE_ITEM = 'mdb.askCopilotFromTreeItem',
RUN_PARTICIPANT_CODE = 'mdb.runParticipantCode',
CONNECT_WITH_PARTICIPANT = 'mdb.connectWithParticipant',
SELECT_DATABASE_WITH_PARTICIPANT = 'mdb.selectDatabaseWithParticipant',
Expand Down
32 changes: 29 additions & 3 deletions src/editors/playgroundController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type ConnectionController from '../connectionController';
import { DataServiceEventTypes } from '../connectionController';
import { createLogger } from '../logging';
import type { ConnectionTreeItem } from '../explorer';
import { CollectionTreeItem } from '../explorer';
import { DatabaseTreeItem } from '../explorer';
import formatError from '../utils/formatError';
import type { LanguageServerController } from '../language';
Expand Down Expand Up @@ -41,6 +42,8 @@ import {
getPlaygroundExtensionForTelemetry,
} from '../utils/playground';
import type ExportToLanguageCodeLensProvider from './exportToLanguageCodeLensProvider';
import { playgroundFromDatabaseTreeItemTemplate } from '../templates/playgroundFromDatabaseTreeItemTemplate';
import { playgroundFromCollectionTreeItemTemplate } from '../templates/playgroundFromCollectionTreeItemTemplate';

const log = createLogger('playground controller');

Expand Down Expand Up @@ -316,13 +319,36 @@ export default class PlaygroundController {
return this._createPlaygroundFileWithContent(content);
}

async createPlaygroundFromTreeItem(
treeItem: DatabaseTreeItem | CollectionTreeItem
): Promise<boolean> {
let content = '';
if (treeItem instanceof DatabaseTreeItem) {
content = playgroundFromDatabaseTreeItemTemplate(treeItem.databaseName);
this._telemetryService.trackPlaygroundCreated('fromDatabaseTreeItem');
} else if (treeItem instanceof CollectionTreeItem) {
content = playgroundFromCollectionTreeItemTemplate(
treeItem.databaseName,
treeItem.collectionName
);
this._telemetryService.trackPlaygroundCreated('fromCollectionTreeItem');
}

return this._createPlaygroundFileWithContent(content);
}

async createPlayground(): Promise<boolean> {
const useDefaultTemplate = !!vscode.workspace
.getConfiguration('mdb')
.get('useDefaultTemplateForPlayground');
const isStreams = this._connectionController.isConnectedToAtlasStreams();
const template = isStreams ? playgroundStreamsTemplate : playgroundTemplate;
const content = useDefaultTemplate ? template : '';
let content = '';
if (useDefaultTemplate) {
const isStreams = this._connectionController.isConnectedToAtlasStreams();
const template = isStreams
? playgroundStreamsTemplate
: playgroundTemplate;
content = template;
}

this._telemetryService.trackPlaygroundCreated('crud');
return this._createPlaygroundFileWithContent(content);
Expand Down
3 changes: 2 additions & 1 deletion src/editors/playgroundSelectionCodeActionProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as vscode from 'vscode';

import EXTENSION_COMMANDS from '../commands';
import { isPlayground, getSelectedText } from '../utils/playground';
import { COPILOT_CHAT_EXTENSION_ID } from '../participant/constants';

export const EXPORT_TO_LANGUAGE_ALIASES = [
{ id: 'csharp', alias: 'C#' },
Expand Down Expand Up @@ -42,7 +43,7 @@ export default class PlaygroundSelectionCodeActionProvider

provideCodeActions(): vscode.CodeAction[] | undefined {
const editor = vscode.window.activeTextEditor;
const copilot = vscode.extensions.getExtension('github.copilot-chat');
const copilot = vscode.extensions.getExtension(COPILOT_CHAT_EXTENSION_ID);
let codeActions: vscode.CodeAction[] = [
this.createCodeAction({
title: 'Run selected playground blocks',
Expand Down
34 changes: 32 additions & 2 deletions src/mdbExtensionController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ import type {
SendMessageToParticipantOptions,
SendMessageToParticipantFromInputOptions,
} from './participant/participantTypes';
import {
COPILOT_CHAT_EXTENSION_ID,
COPILOT_EXTENSION_ID,
} from './participant/constants';

// This class is the top-level controller for our extension.
// Commands which the extensions handles are defined in the function `activate`.
Expand Down Expand Up @@ -177,12 +181,26 @@ export default class MDBExtensionController implements vscode.Disposable {
// ------ In-app notifications ------ //
void this.showCopilotIntroductionForEstablishedUsers();

const copilot = vscode.extensions.getExtension('GitHub.copilot');
const copilot = vscode.extensions.getExtension(COPILOT_EXTENSION_ID);
void vscode.commands.executeCommand(
'setContext',
'mdb.isCopilotActive',
copilot?.isActive
);

// TODO: This is a workaround related to https://github.com/microsoft/vscode/issues/234426
// If the extension was found but is not activated, there is a chance that the MongoDB extension
// was activated before the Copilot one, so we check again after a delay.
if (copilot && !copilot?.isActive) {
setTimeout(() => {
const copilot = vscode.extensions.getExtension(COPILOT_EXTENSION_ID);
void vscode.commands.executeCommand(
'setContext',
'mdb.isCopilotActive',
copilot?.isActive === true
);
}, 3000);
}
}

registerCommands = (): void => {
Expand Down Expand Up @@ -330,6 +348,13 @@ export default class MDBExtensionController implements vscode.Disposable {
return true;
}
);
this.registerParticipantCommand(
EXTENSION_COMMANDS.ASK_COPILOT_FROM_TREE_ITEM,
async (treeItem: DatabaseTreeItem | CollectionTreeItem) => {
await this._participantController.askCopilotFromTreeItem(treeItem);
return true;
}
);
this.registerParticipantCommand(
EXTENSION_COMMANDS.RUN_PARTICIPANT_CODE,
({ runnableContent }: RunParticipantCodeCommandArgs) => {
Expand Down Expand Up @@ -742,6 +767,11 @@ export default class MDBExtensionController implements vscode.Disposable {
EXTENSION_COMMANDS.MDB_CREATE_PLAYGROUND_FROM_TREE_VIEW,
() => this._playgroundController.createPlayground()
);
this.registerCommand(
EXTENSION_COMMANDS.MDB_CREATE_PLAYGROUND_FROM_TREE_ITEM,
(treeItem: DatabaseTreeItem | CollectionTreeItem) =>
this._playgroundController.createPlaygroundFromTreeItem(treeItem)
);
this.registerCommand(
EXTENSION_COMMANDS.MDB_REFRESH_PLAYGROUNDS_FROM_TREE_VIEW,
() => this._playgroundsExplorer.refresh()
Expand Down Expand Up @@ -972,7 +1002,7 @@ export default class MDBExtensionController implements vscode.Disposable {
}
);

const copilot = vscode.extensions.getExtension('github.copilot-chat');
const copilot = vscode.extensions.getExtension(COPILOT_CHAT_EXTENSION_ID);
if (result?.title === action) {
await this._participantController.sendMessageToParticipant({
message: '',
Expand Down
1 change: 1 addition & 0 deletions src/participant/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ChatMetadataStore } from './chatMetadata';
export const CHAT_PARTICIPANT_ID = 'mongodb.participant';
export const CHAT_PARTICIPANT_MODEL = 'gpt-4o';
export const COPILOT_EXTENSION_ID = 'GitHub.copilot';
export const COPILOT_CHAT_EXTENSION_ID = 'GitHub.copilot-chat';

export type ParticipantResponseType =
| 'query'
Expand Down
Loading

0 comments on commit fabbc8c

Please sign in to comment.