1
>
/*---------------------------------------------------------------------------------------------
extensionFeatures.ts
2
>
* Copyright (c) Microsoft Corporation. All rights reserved.
3
>
* Licensed under the MIT License. See License.txt in the project root for license information.
4
>
*--------------------------------------------------------------------------------------------*/
5
>
6
>
import { IMarkdownString } from '../../../../base/common/htmlContent.js';
7
>
import { Event } from '../../../../base/common/event.js';
8
>
import { ExtensionIdentifier, IExtensionManifest } from '../../../../platform/extensions/common/extensions.js';
9
>
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
10
>
import { Registry } from '../../../../platform/registry/common/platform.js';
11
>
import { IDisposable } from '../../../../base/common/lifecycle.js';
12
>
import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js';
13
>
import Severity from '../../../../base/common/severity.js';
14
>
import { IStringDictionary } from '../../../../base/common/collections.js';
15
>
import { ResolvedKeybinding } from '../../../../base/common/keybindings.js';
16
>
import { Color } from '../../../../base/common/color.js';
17
>
import { ThemeIcon } from '../../../../base/common/themables.js';
18
>
19
>
export namespace Extensions {
20
>
export const ExtensionFeaturesRegistry = 'workbench.registry.extensionFeatures';
21
>
}
22
>
23
>
export interface IExtensionFeatureRenderer extends IDisposable {
24
>
type: string;
25
>
shouldRender(manifest: IExtensionManifest): boolean;
26
>
render(manifest: IExtensionManifest): IDisposable;
27
>
}
28
>
29
>
export interface IRenderedData<T> extends IDisposable {
30
>
readonly data: T;
31
>
readonly onDidChange?: Event<T>;
32
>
}
33
>
34
>
export interface IExtensionFeatureMarkdownRenderer extends IExtensionFeatureRenderer {
35
>
type: 'markdown';
36
>
render(manifest: IExtensionManifest): IRenderedData<IMarkdownString>;
37
>
}
38
>
39
>
export type IRowData = string | IMarkdownString | ResolvedKeybinding | Color | ReadonlyArray<ResolvedKeybinding | IMarkdownString | Color>;
40
>
41
>
export interface ITableData {
42
>
headers: string[];
43
>
rows: IRowData[][];
44
>
}
45
>
46
>
export interface IExtensionFeatureTableRenderer extends IExtensionFeatureRenderer {
47
>
type: 'table';
48
>
render(manifest: IExtensionManifest): IRenderedData<ITableData>;
49
>
}
50
>
51
>
export interface IExtensionFeatureMarkdownAndTableRenderer extends IExtensionFeatureRenderer {
52
>
type: 'markdown+table';
53
>
render(manifest: IExtensionManifest): IRenderedData<Array<IMarkdownString | ITableData>>;
54
>
}
55
>
56
>
export interface IExtensionFeatureDescriptor {
57
>
readonly id: string;
58
>
readonly label: string;
59
>
// label of the access data, if different from the feature title.
60
>
// This is useful when the feature is a part of a larger feature and the access data is not about the larger feature.
61
>
// This is shown in the access chart like "There were ${accessCount} ${accessLabel} requests from this extension".
62
>
readonly accessDataLabel?: string;
63
>
readonly description?: string;
64
>
readonly icon?: ThemeIcon;
65
>
readonly access: {
66
>
readonly canToggle?: boolean;
67
>
readonly requireUserConsent?: boolean;
68
>
readonly extensionsList?: IStringDictionary<boolean>;
69
>
};
70
>
readonly renderer?: SyncDescriptor<IExtensionFeatureRenderer>;
71
>
}
72
>
73
>
export interface IExtensionFeaturesRegistry {
74
>
75
>
registerExtensionFeature(descriptor: IExtensionFeatureDescriptor): IDisposable;
76
>
getExtensionFeature(id: string): IExtensionFeatureDescriptor | undefined;
77
>
getExtensionFeatures(): ReadonlyArray<IExtensionFeatureDescriptor>;
78
>
}
79
>
80
>
export interface IExtensionFeatureAccessData {
81
>
readonly current?: {
82
>
readonly accessTimes: Date[];
83
>
readonly lastAccessed: Date;
84
>
readonly status?: { readonly severity: Severity; readonly message: string };
85
>
};
86
>
readonly accessTimes: Date[];
87
>
}
88
>
89
>
export const IExtensionFeaturesManagementService = createDecorator<IExtensionFeaturesManagementService>('IExtensionFeaturesManagementService');
90
>
export interface IExtensionFeaturesManagementService {
91
>
readonly _serviceBrand: undefined;
92
>
93
>
readonly onDidChangeEnablement: Event<{ readonly extension: ExtensionIdentifier; readonly featureId: string; readonly enabled: boolean }>;
94
>
isEnabled(extension: ExtensionIdentifier, featureId: string): boolean;
95
>
setEnablement(extension: ExtensionIdentifier, featureId: string, enabled: boolean): void;
96
>
getEnablementData(featureId: string): { readonly extension: ExtensionIdentifier; readonly enabled: boolean }[];
97
>
98
>
getAccess(extension: ExtensionIdentifier, featureId: string, justification?: string): Promise<boolean>;
99
>
100
>
readonly onDidChangeAccessData: Event<{ readonly extension: ExtensionIdentifier; readonly featureId: string; readonly accessData: IExtensionFeatureAccessData }>;
101
>
getAllAccessDataForExtension(extension: ExtensionIdentifier): Map<string, IExtensionFeatureAccessData>;
102
>
getAccessData(extension: ExtensionIdentifier, featureId: string): IExtensionFeatureAccessData | undefined;
103
>
setStatus(extension: ExtensionIdentifier, featureId: string, status: { readonly severity: Severity; readonly message: string } | undefined): void;
104
>
}
105
>
106
>
class ExtensionFeaturesRegistry implements IExtensionFeaturesRegistry {
107
>
108
>
private readonly extensionFeatures = new Map<string, IExtensionFeatureDescriptor>();
109
>
110
>
registerExtensionFeature(descriptor: IExtensionFeatureDescriptor): IDisposable {
111
if (this.extensionFeatures.has(descriptor.id)) {
112
throw new Error(`Extension feature with id '${descriptor.id}' already exists`);