diff --git a/packages/vsx-registry/src/browser/style/index.css b/packages/vsx-registry/src/browser/style/index.css index ed1c895e63e0e..00e6d7e42dc43 100644 --- a/packages/vsx-registry/src/browser/style/index.css +++ b/packages/vsx-registry/src/browser/style/index.css @@ -28,6 +28,11 @@ min-height: calc(var(--theia-content-line-height)*3) } +.theia-vsx-extension.incompatible { + opacity: 0.6; + cursor: default; +} + .theia-vsx-extensions-search-bar { padding: var(--theia-ui-padding) var(--theia-scrollbar-width) var(--theia-ui-padding) 18px /* expansion toggle padding of tree elements in result list */; display: flex; diff --git a/packages/vsx-registry/src/browser/vsx-extension-preferences.ts b/packages/vsx-registry/src/browser/vsx-extension-preferences.ts new file mode 100644 index 0000000000000..fe7366db8bd24 --- /dev/null +++ b/packages/vsx-registry/src/browser/vsx-extension-preferences.ts @@ -0,0 +1,52 @@ +/******************************************************************************** + * Copyright (C) 2021 Ericsson and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ********************************************************************************/ + +import { interfaces } from '@theia/core/shared/inversify'; +import { createPreferenceProxy, PreferenceProxy, PreferenceService, PreferenceContribution, PreferenceSchema } from '@theia/core/lib/browser'; +import { nls } from '@theia/core'; + +export const VSXExtensionConfigSchema: PreferenceSchema = { + 'type': 'object', + properties: { + 'extensions.displayIncompatible': { + type: 'boolean', + description: nls.localize('theia/vsx-registry/displayIncompatible', 'Controls whether to display incompatible extensions when searching.'), + default: true + } + } +}; + +export interface VSXExtensionConfiguration { + 'extensions.displayIncompatible': boolean; +} + +export const VSXExtensionPreferenceContribution = Symbol('VSXExtensionPreferenceContribution'); +export const VSXExtensionPreferences = Symbol('VSXExtensionPreferences'); +export type VSXExtensionPreferences = PreferenceProxy; + +export function createVSXExtensionPreferences(preferences: PreferenceService, schema: PreferenceSchema = VSXExtensionConfigSchema): VSXExtensionPreferences { + return createPreferenceProxy(preferences, schema); +} + +export function bindVSXExtensionPreferences(bind: interfaces.Bind): void { + bind(VSXExtensionPreferences).toDynamicValue(ctx => { + const preferences = ctx.container.get(PreferenceService); + const contribution = ctx.container.get(VSXExtensionPreferenceContribution); + return createVSXExtensionPreferences(preferences, contribution.schema); + }).inSingletonScope(); + bind(VSXExtensionPreferenceContribution).toConstantValue({ schema: VSXExtensionConfigSchema }); + bind(PreferenceContribution).toService(VSXExtensionPreferenceContribution); +} diff --git a/packages/vsx-registry/src/browser/vsx-extension.tsx b/packages/vsx-registry/src/browser/vsx-extension.tsx index ecf1b6091bb03..dab3f4f0d7d66 100644 --- a/packages/vsx-registry/src/browser/vsx-extension.tsx +++ b/packages/vsx-registry/src/browser/vsx-extension.tsx @@ -28,7 +28,7 @@ import { ProgressService } from '@theia/core/lib/common/progress-service'; import { Endpoint } from '@theia/core/lib/browser/endpoint'; import { VSXEnvironment } from '../common/vsx-environment'; import { VSXExtensionsSearchModel } from './vsx-extensions-search-model'; -import { MenuPath } from '@theia/core/lib/common'; +import { MenuPath, nls } from '@theia/core/lib/common'; import { codicon, ContextMenuRenderer, TooltipService } from '@theia/core/lib/browser'; import { VSXExtensionNamespaceAccess, VSXUser } from '@theia/ovsx-client/lib/ovsx-types'; @@ -144,6 +144,11 @@ export class VSXExtension implements VSXExtensionData, TreeElement { return type === PluginType.System; } + get compatible(): boolean { + // An extension is not compatible if it has no compatible version. + return !!this.version; + } + update(data: Partial): void { for (const key of VSXExtensionData.KEYS) { if (key in data) { @@ -260,7 +265,10 @@ export class VSXExtension implements VSXExtensionData, TreeElement { } get tooltip(): string { - let md = `__${this.displayName}__ ${this.version}\n\n${this.description}\n_____\n\nPublisher: ${this.publisher}`; + const version = this.version !== undefined + ? this.version + : nls.localize('theia/vsx-registry/noCompatibleVersion', 'No Compatible Version'); + let md = `__${this.displayName}__ ${version}\n\n${this.description}\n_____\n\nPublisher: ${this.publisher}`; if (this.license) { md += ` \rLicense: ${this.license}`; @@ -384,21 +392,27 @@ export abstract class AbstractVSXExtensionComponent extends React.Component; } if (busy) { if (installed) { - return ; + return ; } - return ; + return ; } if (installed) { - return
-
; + return ( +
+ +
+
+ ); + } + if (compatible) { + return ; } - return ; } } @@ -414,16 +428,19 @@ const downloadCompactFormatter = new Intl.NumberFormat(undefined, { notation: 'c export class VSXExtensionComponent extends AbstractVSXExtensionComponent { render(): React.ReactNode { - const { iconUrl, publisher, displayName, description, version, downloadCount, averageRating, tooltipId, tooltip } = this.props.extension; + const { iconUrl, publisher, displayName, description, version, downloadCount, averageRating, tooltipId, tooltip, compatible } = this.props.extension; + const extensionVersion = version !== undefined + ? version + : nls.localize('theia/vsx-registry/noCompatibleVersion', 'No Compatible Version'); - return
+ return
{iconUrl ? :
}
- {displayName} {version} + {displayName} {extensionVersion}
{!!downloadCount && {downloadCompactFormatter.format(downloadCount)}} diff --git a/packages/vsx-registry/src/browser/vsx-extensions-model.ts b/packages/vsx-registry/src/browser/vsx-extensions-model.ts index 3fa521820032d..e9b048d851746 100644 --- a/packages/vsx-registry/src/browser/vsx-extensions-model.ts +++ b/packages/vsx-registry/src/browser/vsx-extensions-model.ts @@ -31,6 +31,7 @@ import { RecommendedExtensions } from './recommended-extensions/recommended-exte import URI from '@theia/core/lib/common/uri'; import { VSXResponseError, VSXSearchParam } from '@theia/ovsx-client/lib/ovsx-types'; import { OVSXClientProvider } from '../common/ovsx-client-provider'; +import { VSXExtensionPreferences } from './vsx-extension-preferences'; @injectable() export class VSXExtensionsModel { @@ -56,6 +57,9 @@ export class VSXExtensionsModel { @inject(WorkspaceService) protected readonly workspaceService: WorkspaceService; + @inject(VSXExtensionPreferences) + protected vsxPreferences: VSXExtensionPreferences; + @inject(VSXExtensionsSearchModel) readonly search: VSXExtensionsSearchModel; @@ -175,7 +179,7 @@ export class VSXExtensionsModel { for (const data of result.extensions) { const id = data.namespace.toLowerCase() + '.' + data.name.toLowerCase(); const extension = client.getLatestCompatibleVersion(data); - if (!extension) { + if (!extension && this.vsxPreferences.get('extensions.displayIncompatible') === false) { continue; } this.setExtension(id).update(Object.assign(data, { @@ -184,7 +188,7 @@ export class VSXExtensionsModel { iconUrl: data.files.icon, readmeUrl: data.files.readme, licenseUrl: data.files.license, - version: extension.version + version: extension?.version })); searchResult.add(id); } diff --git a/packages/vsx-registry/src/browser/vsx-registry-frontend-module.ts b/packages/vsx-registry/src/browser/vsx-registry-frontend-module.ts index efcdbb93e4b44..26abe530a5b2f 100644 --- a/packages/vsx-registry/src/browser/vsx-registry-frontend-module.ts +++ b/packages/vsx-registry/src/browser/vsx-registry-frontend-module.ts @@ -35,6 +35,7 @@ import { bindExtensionPreferences } from './recommended-extensions/recommended-e import { bindPreferenceProviderOverrides } from './recommended-extensions/preference-provider-overrides'; import { OVSXClientProvider, createOVSXClient } from '../common/ovsx-client-provider'; import { VSXEnvironment, VSX_ENVIRONMENT_PATH } from '../common/vsx-environment'; +import { bindVSXExtensionPreferences } from './vsx-extension-preferences'; export default new ContainerModule((bind, unbind) => { bind(OVSXClientProvider).toDynamicValue(ctx => { @@ -105,4 +106,6 @@ export default new ContainerModule((bind, unbind) => { bindExtensionPreferences(bind); bindPreferenceProviderOverrides(bind, unbind); + + bindVSXExtensionPreferences(bind); });