Path: blob/main/src/vs/workbench/services/extensionManagement/common/extensionFeatures.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { IMarkdownString } from '../../../../base/common/htmlContent.js';6import { Event } from '../../../../base/common/event.js';7import { ExtensionIdentifier, IExtensionManifest } from '../../../../platform/extensions/common/extensions.js';8import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';9import { Registry } from '../../../../platform/registry/common/platform.js';10import { IDisposable } from '../../../../base/common/lifecycle.js';11import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js';12import Severity from '../../../../base/common/severity.js';13import { IStringDictionary } from '../../../../base/common/collections.js';14import { ResolvedKeybinding } from '../../../../base/common/keybindings.js';15import { Color } from '../../../../base/common/color.js';16import { ThemeIcon } from '../../../../base/common/themables.js';1718export namespace Extensions {19export const ExtensionFeaturesRegistry = 'workbench.registry.extensionFeatures';20}2122export interface IExtensionFeatureRenderer extends IDisposable {23type: string;24shouldRender(manifest: IExtensionManifest): boolean;25render(manifest: IExtensionManifest): IDisposable;26}2728export interface IRenderedData<T> extends IDisposable {29readonly data: T;30readonly onDidChange?: Event<T>;31}3233export interface IExtensionFeatureMarkdownRenderer extends IExtensionFeatureRenderer {34type: 'markdown';35render(manifest: IExtensionManifest): IRenderedData<IMarkdownString>;36}3738export type IRowData = string | IMarkdownString | ResolvedKeybinding | Color | ReadonlyArray<ResolvedKeybinding | IMarkdownString | Color>;3940export interface ITableData {41headers: string[];42rows: IRowData[][];43}4445export interface IExtensionFeatureTableRenderer extends IExtensionFeatureRenderer {46type: 'table';47render(manifest: IExtensionManifest): IRenderedData<ITableData>;48}4950export interface IExtensionFeatureMarkdownAndTableRenderer extends IExtensionFeatureRenderer {51type: 'markdown+table';52render(manifest: IExtensionManifest): IRenderedData<Array<IMarkdownString | ITableData>>;53}5455export interface IExtensionFeatureDescriptor {56readonly id: string;57readonly label: string;58// label of the access data, if different from the feature title.59// This is useful when the feature is a part of a larger feature and the access data is not about the larger feature.60// This is shown in the access chart like "There were ${accessCount} ${accessLabel} requests from this extension".61readonly accessDataLabel?: string;62readonly description?: string;63readonly icon?: ThemeIcon;64readonly access: {65readonly canToggle?: boolean;66readonly requireUserConsent?: boolean;67readonly extensionsList?: IStringDictionary<boolean>;68};69readonly renderer?: SyncDescriptor<IExtensionFeatureRenderer>;70}7172export interface IExtensionFeaturesRegistry {7374registerExtensionFeature(descriptor: IExtensionFeatureDescriptor): IDisposable;75getExtensionFeature(id: string): IExtensionFeatureDescriptor | undefined;76getExtensionFeatures(): ReadonlyArray<IExtensionFeatureDescriptor>;77}7879export interface IExtensionFeatureAccessData {80readonly current?: {81readonly accessTimes: Date[];82readonly lastAccessed: Date;83readonly status?: { readonly severity: Severity; readonly message: string };84};85readonly accessTimes: Date[];86}8788export const IExtensionFeaturesManagementService = createDecorator<IExtensionFeaturesManagementService>('IExtensionFeaturesManagementService');89export interface IExtensionFeaturesManagementService {90readonly _serviceBrand: undefined;9192readonly onDidChangeEnablement: Event<{ readonly extension: ExtensionIdentifier; readonly featureId: string; readonly enabled: boolean }>;93isEnabled(extension: ExtensionIdentifier, featureId: string): boolean;94setEnablement(extension: ExtensionIdentifier, featureId: string, enabled: boolean): void;95getEnablementData(featureId: string): { readonly extension: ExtensionIdentifier; readonly enabled: boolean }[];9697getAccess(extension: ExtensionIdentifier, featureId: string, justification?: string): Promise<boolean>;9899readonly onDidChangeAccessData: Event<{ readonly extension: ExtensionIdentifier; readonly featureId: string; readonly accessData: IExtensionFeatureAccessData }>;100getAllAccessDataForExtension(extension: ExtensionIdentifier): Map<string, IExtensionFeatureAccessData>;101getAccessData(extension: ExtensionIdentifier, featureId: string): IExtensionFeatureAccessData | undefined;102setStatus(extension: ExtensionIdentifier, featureId: string, status: { readonly severity: Severity; readonly message: string } | undefined): void;103}104105class ExtensionFeaturesRegistry implements IExtensionFeaturesRegistry {106107private readonly extensionFeatures = new Map<string, IExtensionFeatureDescriptor>();108109registerExtensionFeature(descriptor: IExtensionFeatureDescriptor): IDisposable {110if (this.extensionFeatures.has(descriptor.id)) {111throw new Error(`Extension feature with id '${descriptor.id}' already exists`);112}113this.extensionFeatures.set(descriptor.id, descriptor);114return {115dispose: () => this.extensionFeatures.delete(descriptor.id)116};117}118119getExtensionFeature(id: string): IExtensionFeatureDescriptor | undefined {120return this.extensionFeatures.get(id);121}122123getExtensionFeatures(): ReadonlyArray<IExtensionFeatureDescriptor> {124return Array.from(this.extensionFeatures.values());125}126}127128Registry.add(Extensions.ExtensionFeaturesRegistry, new ExtensionFeaturesRegistry());129130131