Skip to main content
Glama
nrwl

Nx MCP Server

Official
by nrwl
migrate-sidebar-view-provider.ts6.64 kB
import { MigrateViewData } from '@nx-console/shared-types'; import { isDeepStrictEqual } from 'util'; import { CancellationToken, commands, Disposable, ExtensionContext, Uri, WebviewView, WebviewViewProvider, WebviewViewResolveContext, window, } from 'vscode'; import { ActorRef, EventObject } from 'xstate'; import { startMigration } from './commands/start-migration'; import { viewPackageJsonDiff } from './git-extension/view-diff'; import { cancelMigration, confirmPackageChanges, } from './commands/migrate-commands'; import { gte, NxVersion } from '@nx-console/nx-version'; import { vscodeLogger } from '@nx-console/vscode-output-channels'; export class MigrateSidebarViewProvider implements WebviewViewProvider { public static viewId = 'nxMigrate'; private _view: WebviewView | undefined; private _webviewSourceUri: Uri; private _refreshSubscription: Disposable | undefined; private _migrateViewData: MigrateViewData | undefined; constructor( private extensionContext: ExtensionContext, private actor: ActorRef<any, EventObject>, ) { this._webviewSourceUri = Uri.joinPath( this.extensionContext.extensionUri, 'migrate-sidebar-webview', ); } resolveWebviewView( webviewView: WebviewView, context: WebviewViewResolveContext, token: CancellationToken, ): Thenable<void> | void { this.ensureStateSubscription(); this._view = webviewView; webviewView.webview.options = { enableScripts: true, localResourceRoots: [this.extensionContext.extensionUri], }; webviewView.webview.html = this.getWebviewContent(webviewView); this.setViewBadge(); webviewView.onDidDispose(() => { this._refreshSubscription?.dispose(); }); webviewView.onDidChangeVisibility((event) => { vscodeLogger.log('onDidChangeVisibility'); if (webviewView.visible) { commands.executeCommand('nxMigrate.refresh'); } }); webviewView.webview.onDidReceiveMessage((message) => { if (message.type === 'start-migration') { startMigration(message.custom); } else if (message.type === 'open') { commands.executeCommand('nxMigrate.open'); } else if (message.type === 'view-diff') { viewPackageJsonDiff(); } else if (message.type === 'confirm-changes') { confirmPackageChanges(); } else if (message.type === 'cancel-migration') { cancelMigration(); } }); } refresh() { if (!this._view) { return; } this._view.webview.html = this.getWebviewContent(this._view); this.setViewBadge(); } private getWebviewContent(webviewView: WebviewView): string { 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 state='${JSON.stringify( this.actor.getSnapshot().value, )}' migrateViewData='${JSON.stringify( this._migrateViewData, )}'></root-element> </body> </html>`; } private ensureStateSubscription() { if (this._refreshSubscription) { return; } this._migrateViewData = this.actor.getSnapshot().context; const sub = this.actor.subscribe((state) => { const newState = state.context; if (newState && !isDeepStrictEqual(this._migrateViewData, newState)) { this._migrateViewData = newState; this.refresh(); } }); this._refreshSubscription = new Disposable(() => { sub.unsubscribe(); this._refreshSubscription = undefined; }); this.extensionContext.subscriptions.push(this._refreshSubscription); } private setViewBadge() { if ( !this._migrateViewData.currentNxVersion || !this._migrateViewData.latestNxVersion ) { this._view.badge = { value: 0, tooltip: '' }; return; } if ( !isNonPatchUpdateAvailable( this._migrateViewData.currentNxVersion, this._migrateViewData.latestNxVersion, ) ) { this._view.badge = { value: 0, tooltip: '' }; return; } const latestMajor = this._migrateViewData.latestNxVersion.major; const latestMinor = this._migrateViewData.latestNxVersion.minor; const currentMajor = this._migrateViewData.currentNxVersion.major; const currentMinor = this._migrateViewData.currentNxVersion.minor; if (latestMajor == currentMajor) { const difference = latestMinor - currentMinor; this._view.badge = { value: difference, tooltip: `nx ${ this._migrateViewData.currentNxVersion.full } is ${difference} minor version${ difference === 1 ? '' : 's' } behind latest.`, }; } else { const difference = latestMajor - currentMajor; this._view.badge = { value: difference, tooltip: `nx ${ this._migrateViewData.currentNxVersion.full } is ${difference} major version${ difference === 1 ? '' : 's' } behind latest.`, }; } } static create(context: ExtensionContext, actor: ActorRef<any, EventObject>) { const onboardingProvider = new MigrateSidebarViewProvider(context, actor); context.subscriptions.push( window.registerWebviewViewProvider( MigrateSidebarViewProvider.viewId, onboardingProvider, ), ); } } function isNonPatchUpdateAvailable( currentNxVersion: NxVersion, latestNxVersion: NxVersion, ): boolean { return ( !!currentNxVersion && !!latestNxVersion && gte(latestNxVersion, currentNxVersion) && (latestNxVersion.major > currentNxVersion.major || latestNxVersion.minor > currentNxVersion.minor) ); }

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