diff --git a/packages/vsx-registry/package.json b/packages/vsx-registry/package.json index 65f6aa0e4ffc8..9cb6671888d99 100644 --- a/packages/vsx-registry/package.json +++ b/packages/vsx-registry/package.json @@ -5,6 +5,7 @@ "dependencies": { "@theia/core": "1.46.0", "@theia/filesystem": "1.46.0", + "@theia/navigator": "1.46.0", "@theia/ovsx-client": "1.46.0", "@theia/plugin-ext": "1.46.0", "@theia/plugin-ext-vscode": "1.46.0", diff --git a/packages/vsx-registry/src/browser/vsx-extension-commands.ts b/packages/vsx-registry/src/browser/vsx-extension-commands.ts index e79ba161d5ed3..7184b74eb0fdf 100644 --- a/packages/vsx-registry/src/browser/vsx-extension-commands.ts +++ b/packages/vsx-registry/src/browser/vsx-extension-commands.ts @@ -36,6 +36,13 @@ export namespace VSXExtensionsCommands { label: nls.localizeByDefault('Install from VSIX') + '...', dialogLabel: nls.localizeByDefault('Install from VSIX') }; + export const INSTALL_VSIX: Command = { + id: 'vsxExtensions.installVSIX', + label: nls.localizeByDefault('Install Extension VSIX'), + originalLabel: 'Install Extension VSIX', + category: nls.localizeByDefault(EXTENSIONS_CATEGORY), + originalCategory: EXTENSIONS_CATEGORY, + }; export const INSTALL_ANOTHER_VERSION: Command = { id: 'vsxExtensions.installAnotherVersion' }; diff --git a/packages/vsx-registry/src/browser/vsx-extensions-contribution.ts b/packages/vsx-registry/src/browser/vsx-extensions-contribution.ts index b301d3a0fc75d..f990ab69a4971 100644 --- a/packages/vsx-registry/src/browser/vsx-extensions-contribution.ts +++ b/packages/vsx-registry/src/browser/vsx-extensions-contribution.ts @@ -14,29 +14,32 @@ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 // ***************************************************************************** -import { DateTime } from 'luxon'; -import { injectable, inject, postConstruct } from '@theia/core/shared/inversify'; -import debounce = require('@theia/core/shared/lodash.debounce'); -import { Command, CommandRegistry } from '@theia/core/lib/common/command'; -import { AbstractViewContribution } from '@theia/core/lib/browser/shell/view-contribution'; -import { VSXExtensionsViewContainer } from './vsx-extensions-view-container'; -import { VSXExtensionsModel } from './vsx-extensions-model'; +import { CommonMenus, LabelProvider, PreferenceService, QuickInputService, QuickPickItem } from '@theia/core/lib/browser'; +import { ClipboardService } from '@theia/core/lib/browser/clipboard-service'; import { ColorContribution } from '@theia/core/lib/browser/color-application-contribution'; import { ColorRegistry } from '@theia/core/lib/browser/color-registry'; -import { Color } from '@theia/core/lib/common/color'; import { FrontendApplication } from '@theia/core/lib/browser/frontend-application'; import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application-contribution'; -import { MenuModelRegistry, MessageService, nls } from '@theia/core/lib/common'; +import { AbstractViewContribution } from '@theia/core/lib/browser/shell/view-contribution'; +import { MenuModelRegistry, MessageService, SelectionService, nls } from '@theia/core/lib/common'; +import { Color } from '@theia/core/lib/common/color'; +import { Command, CommandRegistry } from '@theia/core/lib/common/command'; +import URI from '@theia/core/lib/common/uri'; +import { UriAwareCommandHandler } from '@theia/core/lib/common/uri-command-handler'; +import { inject, injectable, postConstruct } from '@theia/core/shared/inversify'; import { FileDialogService, OpenFileDialogProps } from '@theia/filesystem/lib/browser'; -import { LabelProvider, PreferenceService, QuickPickItem, QuickInputService, CommonMenus } from '@theia/core/lib/browser'; +import { NAVIGATOR_CONTEXT_MENU } from '@theia/navigator/lib/browser/navigator-contribution'; +import { OVSXApiFilter, VSXExtensionRaw } from '@theia/ovsx-client'; import { VscodeCommands } from '@theia/plugin-ext-vscode/lib/browser/plugin-vscode-commands-contribution'; -import { VSXExtensionsContextMenu, VSXExtension } from './vsx-extension'; -import { ClipboardService } from '@theia/core/lib/browser/clipboard-service'; -import { BUILTIN_QUERY, INSTALLED_QUERY, RECOMMENDED_QUERY } from './vsx-extensions-search-model'; +import { DateTime } from 'luxon'; +import { OVSXClientProvider } from '../common/ovsx-client-provider'; import { IGNORE_RECOMMENDATIONS_ID } from './recommended-extensions/recommended-extensions-preference-contribution'; +import { VSXExtension, VSXExtensionsContextMenu } from './vsx-extension'; import { VSXExtensionsCommands } from './vsx-extension-commands'; -import { VSXExtensionRaw, OVSXApiFilter } from '@theia/ovsx-client'; -import { OVSXClientProvider } from '../common/ovsx-client-provider'; +import { VSXExtensionsModel } from './vsx-extensions-model'; +import { BUILTIN_QUERY, INSTALLED_QUERY, RECOMMENDED_QUERY } from './vsx-extensions-search-model'; +import { VSXExtensionsViewContainer } from './vsx-extensions-view-container'; +import debounce = require('@theia/core/shared/lodash.debounce'); export namespace VSXCommands { export const TOGGLE_EXTENSIONS: Command = { @@ -57,6 +60,7 @@ export class VSXExtensionsContribution extends AbstractViewContribution this.installFromVSIX() }); + commands.registerCommand(VSXExtensionsCommands.INSTALL_VSIX, + UriAwareCommandHandler.MonoSelect(this.selectionService, { + execute: fileURI => this.installVSIX(fileURI) + } + )); + commands.registerCommand(VSXExtensionsCommands.INSTALL_ANOTHER_VERSION, { // Check downloadUrl to ensure we have an idea of where to look for other versions. isEnabled: (extension: VSXExtension) => !extension.builtin && !!extension.downloadUrl, @@ -143,6 +153,11 @@ export class VSXExtensionsContribution extends AbstractViewContribution { + const extensionName = this.labelProvider.getName(fileURI); + try { + await this.commandRegistry.executeCommand(VscodeCommands.INSTALL_FROM_VSIX.id, fileURI); + this.messageService.info(nls.localizeByDefault('Completed installing {0} extension from VSIX.', extensionName)); + } catch (e) { + this.messageService.error(nls.localize('theia/vsx-registry/failedInstallingVSIX', 'Failed to install {0} from VSIX.', extensionName)); + console.warn(e); + } + } + /** * Given an extension, displays a quick pick of other compatible versions and installs the selected version. * diff --git a/packages/vsx-registry/src/browser/vsx-extensions-widget.tsx b/packages/vsx-registry/src/browser/vsx-extensions-widget.tsx index 6b79ed3dea49f..63e2a38579cc7 100644 --- a/packages/vsx-registry/src/browser/vsx-extensions-widget.tsx +++ b/packages/vsx-registry/src/browser/vsx-extensions-widget.tsx @@ -15,7 +15,7 @@ // ***************************************************************************** import { injectable, interfaces, postConstruct, inject } from '@theia/core/shared/inversify'; -import { TreeModel, TreeNode } from '@theia/core/lib/browser'; +import { Message, TreeModel, TreeNode } from '@theia/core/lib/browser'; import { SourceTreeWidget } from '@theia/core/lib/browser/source-tree'; import { VSXExtensionsSource, VSXExtensionsSourceOptions } from './vsx-extensions-source'; import { nls } from '@theia/core/lib/common/nls'; @@ -153,4 +153,13 @@ export class VSXExtensionsWidget extends SourceTreeWidget implements BadgeWidget } return super.renderTree(model); } + + protected override onAfterShow(msg: Message): void { + super.onAfterShow(msg); + if (this.options.id === VSXExtensionsSourceOptions.INSTALLED) { + // This is needed when an Extension was installed outside of the extension view. + // E.g. using explorer context menu. + this.doUpdateRows(); + } + } } diff --git a/packages/vsx-registry/tsconfig.json b/packages/vsx-registry/tsconfig.json index ba51f2ea3a5ee..c2d9957cb1436 100644 --- a/packages/vsx-registry/tsconfig.json +++ b/packages/vsx-registry/tsconfig.json @@ -18,6 +18,9 @@ { "path": "../filesystem" }, + { + "path": "../navigator" + }, { "path": "../plugin-ext" },