Skip to main content
Glama
nrwl

Nx MCP Server

Official
by nrwl
nx-project-tree-provider.ts7.24 kB
import { NxWorkspace } from '@nx-console/shared-types'; import { GlobalConfigurationStore } from '@nx-console/vscode-configuration'; import { onWorkspaceRefreshed } from '@nx-console/vscode-lsp-client'; import { getNxWorkspace, getProjectFolderTree, } from '@nx-console/vscode-nx-workspace'; import { CliTaskProvider, selectRunInformationAndRun, } from '@nx-console/vscode-tasks'; import { getTelemetry } from '@nx-console/vscode-telemetry'; import { AbstractTreeProvider, createProjectTargetString, surroundWithQuotesIfNeeded, } from '@nx-console/vscode-utils'; import { commands, env, ExtensionContext } from 'vscode'; import { NxTreeItem } from './nx-tree-item'; import { TargetViewItem } from './views/nx-project-base-view'; import { ListView, ListViewItem } from './views/nx-project-list-view'; import { TreeView, TreeViewItem } from './views/nx-project-tree-view'; import { NxConsolePluginsDefinition, ProjectViewTreeItem, loadPlugins, } from '@nx-console/shared-nx-console-plugins'; import { getNxWorkspacePath } from '@nx-console/vscode-configuration'; export type ViewItem = ListViewItem | TreeViewItem; interface NxOptionalFlags { skipNxCache: boolean; } /** * Provides data for the "Projects" tree view */ export class NxProjectTreeProvider extends AbstractTreeProvider<NxTreeItem> { private readonly listView: ListView = new ListView(); private readonly treeView: TreeView = new TreeView(); private workspaceData: NxWorkspace | undefined = undefined; private plugins: NxConsolePluginsDefinition | undefined = undefined; constructor(context: ExtensionContext) { super(); ( [ ['revealInExplorer', this.revealInExplorer], ['run-task-projects-view', this.runTask], ['run-task-projects-view-skip-cache', this.runTaskSkipNxCache], ['copyTaskToClipboard', this.copyTaskToClipboard], ['run-task-projects-view-options', this.runTaskWithOptions], ] as const ).forEach(([commandSuffix, callback]) => { context.subscriptions.push( commands.registerCommand(`nxConsole.${commandSuffix}`, callback, this), ); }); GlobalConfigurationStore.instance.onConfigurationChange(() => this.refresh(), ); onWorkspaceRefreshed(() => this.refresh()); } getParent() { // not implemented, because the reveal API is not needed for the projects view return null; } async getChildren(element?: NxTreeItem): Promise<NxTreeItem[] | undefined> { if (!element) { this.workspaceData = await getNxWorkspace(); this.plugins = await loadPlugins(getNxWorkspacePath()); this.treeView.workspaceData = this.workspaceData; this.listView.workspaceData = this.workspaceData; } let items: (TreeViewItem | ListViewItem)[] | undefined; if (this.shouldUseTreeView()) { if (!element) { const projectFolderTree = await getProjectFolderTree(); if (!projectFolderTree) { return; } const { treeMap, roots } = projectFolderTree; this.treeView.treeMap = treeMap; this.treeView.roots = roots; } items = await this.treeView.getChildren(element?.item as TreeViewItem); } else { items = await this.listView.getChildren(element?.item as ListViewItem); } if (!items) return; if (this.plugins.projectViewItemProcessors) { this.plugins.projectViewItemProcessors.forEach((processor) => { items = items.map((item) => { const processed = processor( item as ProjectViewTreeItem, this.workspaceData, ); item.label = processed.label ?? item.label; item.description = processed.description ?? item.description; item.tooltip = processed.tooltip ?? item.tooltip; item.iconPath = processed.iconPath ?? item.iconPath; item.collapsible = processed.collapsible ?? item.collapsible; return item; }); }); } return items.map((item) => new NxTreeItem(item)); } private shouldUseTreeView() { const config = GlobalConfigurationStore.instance.get('projectViewingStyle'); if (config === 'tree') { return true; } if (config === 'list') { return false; } if (!this.workspaceData) { return true; } return Object.keys(this.workspaceData.projectGraph.nodes).length > 10; } private async runTask( selection: NxTreeItem | undefined, optionalFlags?: NxOptionalFlags, ) { getTelemetry().logUsage('tasks.run', { source: 'projects-view', }); const viewItem = selection?.item; if ( !viewItem || viewItem.contextValue === 'project' || viewItem.contextValue === 'folder' || viewItem.contextValue === 'targetGroup' || viewItem.contextValue === 'projectGraphError' ) { // can not run a task on a project, folder or target group return; } const { project } = viewItem.nxProject; const target = viewItem.nxTarget; const flags = []; if (target.configuration) { flags.push(`--configuration=${target.configuration}`); } if (optionalFlags?.skipNxCache) { flags.push('--skip-nx-cache'); } CliTaskProvider.instance.executeTask({ command: 'run', positional: createProjectTargetString(project, target.name), flags, }); } private async runTaskSkipNxCache(selection: NxTreeItem | undefined) { this.runTask(selection, { skipNxCache: true }); } private async runTaskWithOptions(selection: NxTreeItem | undefined) { getTelemetry().logUsage('tasks.run', { source: 'projects-view', }); const item = selection?.item as TargetViewItem; const project = item?.nxProject.project; const target = item?.nxTarget.name; const configuration = item?.nxTarget.configuration; selectRunInformationAndRun(project, target, configuration, true); } private parseTreeItemId( id: string, ): { project: string; target: string; configuration?: string } | null { if (id.startsWith('target$$')) { const [, project, target] = id.split('$$'); return { project, target }; } if (id.startsWith('config$$')) { const [, project, target, configuration] = id.split('$$'); return { project, target, configuration }; } return null; } private async copyTaskToClipboard(selection: NxTreeItem | undefined) { getTelemetry().logUsage('tasks.copy-to-clipboard'); if (!selection) { return; } const parsed = this.parseTreeItemId(selection.id); if (!parsed) { env.clipboard.writeText( `nx run ${surroundWithQuotesIfNeeded(selection.id)}`, ); return; } let command = `${parsed.project}:${parsed.target}`; if (parsed.configuration) { command += `:${parsed.configuration}`; } env.clipboard.writeText(`nx run ${surroundWithQuotesIfNeeded(command)}`); } private async revealInExplorer(selection: NxTreeItem | undefined) { if (!selection) { return; } if (selection.resourceUri) { getTelemetry().logUsage('misc.show-project-configuration'); commands.executeCommand('revealInExplorer', selection.resourceUri); } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/nrwl/nx-console'

If you have feedback or need assistance with the MCP directory API, please join our Discord server