Skip to main content
Glama
nrwl

Nx MCP Server

Official
by nrwl
cloud-onboarding-view.ts6.31 kB
import { CloudOnboardingInfo } from '@nx-console/shared-types'; import { getNxWorkspacePath } from '@nx-console/vscode-configuration'; import { CancellationToken, commands, Disposable, ExtensionContext, tasks, Uri, WebviewView, WebviewViewProvider, WebviewViewResolveContext, window, } from 'vscode'; import { getNxAccessToken, getNxCloudId, getNxCloudUrl, } from '@nx-console/shared-nx-cloud'; import { withTimeout } from '@nx-console/shared-utils'; import { getNxVersion } from '@nx-console/vscode-nx-workspace'; import { CliTaskProvider } from '@nx-console/vscode-tasks'; import { getTelemetry } from '@nx-console/vscode-telemetry'; import { isDeepStrictEqual } from 'util'; import { ActorRef, EventObject } from 'xstate'; import { getCloudOnboardingUrl } from './get-cloud-onboarding-url'; export class CloudOnboardingViewProvider implements WebviewViewProvider { public static viewId = 'nxCloudOnboarding'; private _view: WebviewView | undefined; private _webviewSourceUri: Uri; private _refreshSubscription: Disposable | undefined; private onboardingInfo: CloudOnboardingInfo | undefined; constructor( private extensionContext: ExtensionContext, private actor: ActorRef<any, EventObject>, ) { this._webviewSourceUri = Uri.joinPath( this.extensionContext.extensionUri, 'nx-cloud-onboarding-webview', ); this.ensureStateSubscription(); } async resolveWebviewView( webviewView: WebviewView, _context: WebviewViewResolveContext, _token: CancellationToken, ): Promise<void> { this.ensureStateSubscription(); this._view = webviewView; webviewView.webview.options = { enableScripts: true, localResourceRoots: [this.extensionContext.extensionUri], }; webviewView.webview.html = this.getWebviewContent( webviewView, this.onboardingInfo, ); webviewView.webview.onDidReceiveMessage((event) => { this.handleWebviewMessage(event); }); webviewView.onDidDispose(() => { this._refreshSubscription?.dispose(); }); } async refresh() { if (this._view) { this._view.webview.html = this.getWebviewContent( this._view, this.onboardingInfo, ); } } private handleWebviewMessage(event: any) { switch (event.type) { case 'connect-to-cloud': { commands.executeCommand('nx.connectToCloud'); break; } case 'login': { commands.executeCommand('nxCloud.login'); tasks.onDidEndTaskProcess((taskEndEvent) => { if (taskEndEvent.execution.task.name === 'nx-cloud login') { this.refresh(); } }); break; } case 'finish-cloud-setup': { finishCloudSetup(); break; } case 'generate-ci': { generateCI(); break; } case 'open-cloud-app': { commands.executeCommand('nxCloud.openApp'); break; } default: { break; } } } private getWebviewContent( webviewView: WebviewView, cloudOnboardingInfo: CloudOnboardingInfo | undefined, ) { const webviewScriptUri = webviewView.webview.asWebviewUri( Uri.joinPath(this._webviewSourceUri, 'main.js'), ); const codiconsUri = webviewView.webview.asWebviewUri( Uri.joinPath( this.extensionContext.extensionUri, 'node_modules', '@vscode', 'codicons', 'dist', 'codicon.css', ), ); const vscodeElementsUri = webviewView.webview.asWebviewUri( Uri.joinPath( this.extensionContext.extensionUri, 'node_modules', '@vscode-elements', 'elements', 'dist', 'bundled.js', ), ); return `<!DOCTYPE html> <html lang="en"> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href="${codiconsUri}" rel="stylesheet" id="vscode-codicon-stylesheet"> <title>Nx Cloud Onboarding</title> <script src="${vscodeElementsUri}" type="module" ></script> </head> <body> <script type="module" src="${webviewScriptUri}"></script> <root-element cloudOnboardingInfo='${JSON.stringify( cloudOnboardingInfo, )}'></root-element> </body> </html>`; } private ensureStateSubscription() { if (this._refreshSubscription) { return; } this.onboardingInfo = this.actor.getSnapshot().context.onboardingInfo; const sub = this.actor.subscribe((state) => { const newState = state.context.onboardingInfo as | CloudOnboardingInfo | undefined; if (newState && !isDeepStrictEqual(this.onboardingInfo, newState)) { this.onboardingInfo = newState; this.refresh(); } }); this._refreshSubscription = new Disposable(() => { sub.unsubscribe(); this._refreshSubscription = undefined; }); this.extensionContext.subscriptions.push(this._refreshSubscription); } static create( extensionContext: ExtensionContext, actor: ActorRef<any, EventObject>, ) { const onboardingProvider = new CloudOnboardingViewProvider( extensionContext, actor, ); extensionContext.subscriptions.push( window.registerWebviewViewProvider( CloudOnboardingViewProvider.viewId, onboardingProvider, ), ); } } async function finishCloudSetup() { getTelemetry().logUsage('cloud.finish-setup'); const workspacePath = getNxWorkspacePath(); const nxCloudUrl = await getNxCloudUrl(workspacePath); if (nxCloudUrl) { process.env['NX_CLOUD_API'] = nxCloudUrl; } let url: string | undefined; await withTimeout(async () => { url = await getCloudOnboardingUrl(); }, 5000); if (nxCloudUrl) { delete process.env['NX_CLOUD_API']; } if (url) { commands.executeCommand('vscode.open', Uri.parse(url)); } else { window.showErrorMessage( 'Failed to retrieve Nx Cloud URL. Run `nx@latest connect` in the terminal.', ); } } function generateCI() { getTelemetry().logUsage('cloud.generate-ci-workflow'); CliTaskProvider.instance.executeTask({ command: 'generate', positional: '@nx/workspace:ci-workflow', flags: [], }); }

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