@onerjs/shared-ui-components 8.48.4 → 8.48.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fluent/hoc/buttonLine.js +2 -1
- package/fluent/hoc/buttonLine.js.map +1 -1
- package/fluent/primitives/contextMenu.js.map +1 -1
- package/fluent/primitives/popover.js.map +1 -1
- package/modularTool/components/errorBoundary.d.ts +31 -0
- package/modularTool/components/errorBoundary.js +91 -0
- package/modularTool/components/errorBoundary.js.map +1 -0
- package/modularTool/components/extensibleAccordion.d.ts +67 -0
- package/modularTool/components/extensibleAccordion.js +148 -0
- package/modularTool/components/extensibleAccordion.js.map +1 -0
- package/modularTool/components/pane.d.ts +4 -0
- package/modularTool/components/pane.js +20 -0
- package/modularTool/components/pane.js.map +1 -0
- package/modularTool/components/teachingMoment.d.ts +20 -0
- package/modularTool/components/teachingMoment.js +17 -0
- package/modularTool/components/teachingMoment.js.map +1 -0
- package/modularTool/components/theme.d.ts +10 -0
- package/modularTool/components/theme.js +24 -0
- package/modularTool/components/theme.js.map +1 -0
- package/modularTool/components/uxContextProvider.d.ts +2 -0
- package/modularTool/components/uxContextProvider.js +19 -0
- package/modularTool/components/uxContextProvider.js.map +1 -0
- package/modularTool/contexts/extensionManagerContext.d.ts +6 -0
- package/modularTool/contexts/extensionManagerContext.js +6 -0
- package/modularTool/contexts/extensionManagerContext.js.map +1 -0
- package/modularTool/contexts/settingsContext.d.ts +3 -0
- package/modularTool/contexts/settingsContext.js +6 -0
- package/modularTool/contexts/settingsContext.js.map +1 -0
- package/modularTool/extensibility/builtInsExtensionFeed.d.ts +21 -0
- package/modularTool/extensibility/builtInsExtensionFeed.js +26 -0
- package/modularTool/extensibility/builtInsExtensionFeed.js.map +1 -0
- package/modularTool/extensibility/extensionFeed.d.ts +113 -0
- package/modularTool/extensibility/extensionFeed.js +2 -0
- package/modularTool/extensibility/extensionFeed.js.map +1 -0
- package/modularTool/extensibility/extensionManager.d.ts +111 -0
- package/modularTool/extensibility/extensionManager.js +277 -0
- package/modularTool/extensibility/extensionManager.js.map +1 -0
- package/modularTool/hooks/observableHooks.d.ts +35 -0
- package/modularTool/hooks/observableHooks.js +84 -0
- package/modularTool/hooks/observableHooks.js.map +1 -0
- package/modularTool/hooks/resourceHooks.d.ts +20 -0
- package/modularTool/hooks/resourceHooks.js +101 -0
- package/modularTool/hooks/resourceHooks.js.map +1 -0
- package/modularTool/hooks/settingsHooks.d.ts +8 -0
- package/modularTool/hooks/settingsHooks.js +40 -0
- package/modularTool/hooks/settingsHooks.js.map +1 -0
- package/modularTool/hooks/teachingMomentHooks.d.ts +34 -0
- package/modularTool/hooks/teachingMomentHooks.js +89 -0
- package/modularTool/hooks/teachingMomentHooks.js.map +1 -0
- package/modularTool/hooks/themeHooks.d.ts +17 -0
- package/modularTool/hooks/themeHooks.js +38 -0
- package/modularTool/hooks/themeHooks.js.map +1 -0
- package/modularTool/hooks/useResizeHandle.d.ts +35 -0
- package/modularTool/hooks/useResizeHandle.js +75 -0
- package/modularTool/hooks/useResizeHandle.js.map +1 -0
- package/modularTool/misc/assert.d.ts +5 -0
- package/modularTool/misc/assert.js +10 -0
- package/modularTool/misc/assert.js.map +1 -0
- package/modularTool/misc/graphUtils.d.ts +44 -0
- package/modularTool/misc/graphUtils.js +90 -0
- package/modularTool/misc/graphUtils.js.map +1 -0
- package/modularTool/misc/observableCollection.d.ts +23 -0
- package/modularTool/misc/observableCollection.js +43 -0
- package/modularTool/misc/observableCollection.js.map +1 -0
- package/modularTool/modularTool.d.ts +42 -0
- package/modularTool/modularTool.js +223 -0
- package/modularTool/modularTool.js.map +1 -0
- package/modularTool/modularity/serviceContainer.d.ts +64 -0
- package/modularTool/modularity/serviceContainer.js +181 -0
- package/modularTool/modularity/serviceContainer.js.map +1 -0
- package/modularTool/modularity/serviceDefinition.d.ts +64 -0
- package/modularTool/modularity/serviceDefinition.js +11 -0
- package/modularTool/modularity/serviceDefinition.js.map +1 -0
- package/modularTool/services/extensionsListService.d.ts +3 -0
- package/modularTool/services/extensionsListService.js +202 -0
- package/modularTool/services/extensionsListService.js.map +1 -0
- package/modularTool/services/globalSettings.d.ts +3 -0
- package/modularTool/services/globalSettings.js +9 -0
- package/modularTool/services/globalSettings.js.map +1 -0
- package/modularTool/services/reactContextService.d.ts +18 -0
- package/modularTool/services/reactContextService.js +5 -0
- package/modularTool/services/reactContextService.js.map +1 -0
- package/modularTool/services/settingsService.d.ts +24 -0
- package/modularTool/services/settingsService.js +41 -0
- package/modularTool/services/settingsService.js.map +1 -0
- package/modularTool/services/settingsStore.d.ts +55 -0
- package/modularTool/services/settingsStore.js +35 -0
- package/modularTool/services/settingsStore.js.map +1 -0
- package/modularTool/services/shellService.d.ts +256 -0
- package/modularTool/services/shellService.js +729 -0
- package/modularTool/services/shellService.js.map +1 -0
- package/modularTool/services/shellSettingsService.d.ts +3 -0
- package/modularTool/services/shellSettingsService.js +35 -0
- package/modularTool/services/shellSettingsService.js.map +1 -0
- package/modularTool/services/themeSelectorService.d.ts +3 -0
- package/modularTool/services/themeSelectorService.js +42 -0
- package/modularTool/services/themeSelectorService.js.map +1 -0
- package/modularTool/services/themeService.d.ts +60 -0
- package/modularTool/services/themeService.js +69 -0
- package/modularTool/services/themeService.js.map +1 -0
- package/modularTool/themes/babylonTheme.d.ts +3 -0
- package/modularTool/themes/babylonTheme.js +36 -0
- package/modularTool/themes/babylonTheme.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import { ToolContext } from "../../fluent/hoc/fluentToolWrapper.js";
|
|
4
|
+
import { useSetting } from "../hooks/settingsHooks.js";
|
|
5
|
+
import { CompactModeSettingDescriptor, DisableCopySettingDescriptor } from "../services/globalSettings.js";
|
|
6
|
+
export const UXContextProvider = (props) => {
|
|
7
|
+
const [compactMode] = useSetting(CompactModeSettingDescriptor);
|
|
8
|
+
const [disableCopy] = useSetting(DisableCopySettingDescriptor);
|
|
9
|
+
const toolsContext = useMemo(() => {
|
|
10
|
+
return {
|
|
11
|
+
toolName: "",
|
|
12
|
+
size: compactMode ? "small" : "medium",
|
|
13
|
+
disableCopy,
|
|
14
|
+
useFluent: true,
|
|
15
|
+
};
|
|
16
|
+
}, [compactMode, disableCopy]);
|
|
17
|
+
return _jsx(ToolContext.Provider, { value: toolsContext, children: props.children });
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=uxContextProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uxContextProvider.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/modularTool/components/uxContextProvider.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAoE,OAAO,EAAE,MAAM,OAAO,CAAC;AAElG,OAAO,EAAE,WAAW,EAAE,MAAM,mDAAmD,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,4BAA4B,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAExG,MAAM,CAAC,MAAM,iBAAiB,GAAyC,CAAC,KAAK,EAAE,EAAE;IAC7E,MAAM,CAAC,WAAW,CAAC,GAAG,UAAU,CAAC,4BAA4B,CAAC,CAAC;IAC/D,MAAM,CAAC,WAAW,CAAC,GAAG,UAAU,CAAC,4BAA4B,CAAC,CAAC;IAE/D,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,EAAE;QAC9B,OAAO;YACH,QAAQ,EAAE,EAAE;YACZ,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ;YACtC,WAAW;YACX,SAAS,EAAE,IAAI;SACwB,CAAC;IAChD,CAAC,EAAE,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;IAE/B,OAAO,KAAC,WAAW,CAAC,QAAQ,IAAC,KAAK,EAAE,YAAY,YAAG,KAAK,CAAC,QAAQ,GAAwB,CAAC;AAC9F,CAAC,CAAC","sourcesContent":["import { type ContextType, type FunctionComponent, type PropsWithChildren, useMemo } from \"react\";\r\n\r\nimport { ToolContext } from \"shared-ui-components/fluent/hoc/fluentToolWrapper\";\r\nimport { useSetting } from \"../hooks/settingsHooks\";\r\nimport { CompactModeSettingDescriptor, DisableCopySettingDescriptor } from \"../services/globalSettings\";\r\n\r\nexport const UXContextProvider: FunctionComponent<PropsWithChildren> = (props) => {\r\n const [compactMode] = useSetting(CompactModeSettingDescriptor);\r\n const [disableCopy] = useSetting(DisableCopySettingDescriptor);\r\n\r\n const toolsContext = useMemo(() => {\r\n return {\r\n toolName: \"\",\r\n size: compactMode ? \"small\" : \"medium\",\r\n disableCopy,\r\n useFluent: true,\r\n } satisfies ContextType<typeof ToolContext>;\r\n }, [compactMode, disableCopy]);\r\n\r\n return <ToolContext.Provider value={toolsContext}>{props.children}</ToolContext.Provider>;\r\n};\r\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type ExtensionManager } from "../extensibility/extensionManager.js";
|
|
2
|
+
export type ExtensionManagerContext = {
|
|
3
|
+
readonly extensionManager: ExtensionManager;
|
|
4
|
+
};
|
|
5
|
+
export declare const ExtensionManagerContext: import("react").Context<ExtensionManagerContext | undefined>;
|
|
6
|
+
export declare function useExtensionManager(): ExtensionManager | undefined;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
export const ExtensionManagerContext = createContext(undefined);
|
|
3
|
+
export function useExtensionManager() {
|
|
4
|
+
return useContext(ExtensionManagerContext)?.extensionManager;
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=extensionManagerContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extensionManagerContext.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/modularTool/contexts/extensionManagerContext.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAMlD,MAAM,CAAC,MAAM,uBAAuB,GAAG,aAAa,CAAsC,SAAS,CAAC,CAAC;AAErG,MAAM,UAAU,mBAAmB;IAC/B,OAAO,UAAU,CAAC,uBAAuB,CAAC,EAAE,gBAAgB,CAAC;AACjE,CAAC","sourcesContent":["import { type ExtensionManager } from \"../extensibility/extensionManager\";\r\n\r\nimport { createContext, useContext } from \"react\";\r\n\r\nexport type ExtensionManagerContext = {\r\n readonly extensionManager: ExtensionManager;\r\n};\r\n\r\nexport const ExtensionManagerContext = createContext<ExtensionManagerContext | undefined>(undefined);\r\n\r\nexport function useExtensionManager() {\r\n return useContext(ExtensionManagerContext)?.extensionManager;\r\n}\r\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settingsContext.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/modularTool/contexts/settingsContext.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAElD,MAAM,CAAC,MAAM,oBAAoB,GAAG,aAAa,CAA6B,SAAS,CAAC,CAAC;AAEzF,MAAM,UAAU,gBAAgB;IAC5B,OAAO,UAAU,CAAC,oBAAoB,CAAC,CAAC;AAC5C,CAAC","sourcesContent":["import { type ISettingsStore } from \"../services/settingsStore\";\r\n\r\nimport { createContext, useContext } from \"react\";\r\n\r\nexport const SettingsStoreContext = createContext<ISettingsStore | undefined>(undefined);\r\n\r\nexport function useSettingsStore() {\r\n return useContext(SettingsStoreContext);\r\n}\r\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type IExtensionFeed, type ExtensionMetadata, type IExtensionMetadataQuery, type ExtensionModule } from "./extensionFeed.js";
|
|
2
|
+
export type BuiltInExtension = ExtensionMetadata & {
|
|
3
|
+
/**
|
|
4
|
+
* Gets the extension module, typically dynamically importing the extension.
|
|
5
|
+
* @returns The extension module (e.g. a collection of ServiceDefinitions).
|
|
6
|
+
*/
|
|
7
|
+
getExtensionModuleAsync(): Promise<ExtensionModule>;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* A simple extension feed implementation that provides a fixed set of "built in" extensions.
|
|
11
|
+
* "Built in" in this context means extensions that are known at bundling time, and included
|
|
12
|
+
* in the bundle. Each extension can be dynamically imported so they are split into separate
|
|
13
|
+
* bundle chunks and downloaded only when first installed.
|
|
14
|
+
*/
|
|
15
|
+
export declare class BuiltInsExtensionFeed implements IExtensionFeed {
|
|
16
|
+
readonly name: string;
|
|
17
|
+
private readonly _extensions;
|
|
18
|
+
constructor(name: string, extensions: Iterable<BuiltInExtension>);
|
|
19
|
+
queryExtensionsAsync(filter?: string): Promise<IExtensionMetadataQuery>;
|
|
20
|
+
getExtensionModuleAsync(name: string): Promise<ExtensionModule | undefined>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A simple extension feed implementation that provides a fixed set of "built in" extensions.
|
|
3
|
+
* "Built in" in this context means extensions that are known at bundling time, and included
|
|
4
|
+
* in the bundle. Each extension can be dynamically imported so they are split into separate
|
|
5
|
+
* bundle chunks and downloaded only when first installed.
|
|
6
|
+
*/
|
|
7
|
+
export class BuiltInsExtensionFeed {
|
|
8
|
+
constructor(name, extensions) {
|
|
9
|
+
this.name = name;
|
|
10
|
+
this._extensions = Array.from(extensions);
|
|
11
|
+
}
|
|
12
|
+
async queryExtensionsAsync(filter) {
|
|
13
|
+
const filteredExtensions = filter ? this._extensions.filter((extension) => extension.name.includes(filter)) : this._extensions;
|
|
14
|
+
return {
|
|
15
|
+
totalCount: filteredExtensions.length,
|
|
16
|
+
getExtensionMetadataAsync: async (index, count) => {
|
|
17
|
+
return filteredExtensions.slice(index, index + count);
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
async getExtensionModuleAsync(name) {
|
|
22
|
+
const extension = this._extensions.find((ext) => ext.name === name);
|
|
23
|
+
return extension ? await extension.getExtensionModuleAsync() : undefined;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=builtInsExtensionFeed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builtInsExtensionFeed.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/modularTool/extensibility/builtInsExtensionFeed.ts"],"names":[],"mappings":"AAUA;;;;;GAKG;AACH,MAAM,OAAO,qBAAqB;IAG9B,YACoB,IAAY,EAC5B,UAAsC;QADtB,SAAI,GAAJ,IAAI,CAAQ;QAG5B,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC9C,CAAC;IAEM,KAAK,CAAC,oBAAoB,CAAC,MAAe;QAC7C,MAAM,kBAAkB,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;QAC/H,OAAO;YACH,UAAU,EAAE,kBAAkB,CAAC,MAAM;YACrC,yBAAyB,EAAE,KAAK,EAAE,KAAa,EAAE,KAAa,EAAE,EAAE;gBAC9D,OAAO,kBAAkB,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC;YAC1D,CAAC;SACJ,CAAC;IACN,CAAC;IAEM,KAAK,CAAC,uBAAuB,CAAC,IAAY;QAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QACpE,OAAO,SAAS,CAAC,CAAC,CAAC,MAAM,SAAS,CAAC,uBAAuB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7E,CAAC;CACJ","sourcesContent":["import { type IExtensionFeed, type ExtensionMetadata, type IExtensionMetadataQuery, type ExtensionModule } from \"./extensionFeed\";\r\n\r\nexport type BuiltInExtension = ExtensionMetadata & {\r\n /**\r\n * Gets the extension module, typically dynamically importing the extension.\r\n * @returns The extension module (e.g. a collection of ServiceDefinitions).\r\n */\r\n getExtensionModuleAsync(): Promise<ExtensionModule>;\r\n};\r\n\r\n/**\r\n * A simple extension feed implementation that provides a fixed set of \"built in\" extensions.\r\n * \"Built in\" in this context means extensions that are known at bundling time, and included\r\n * in the bundle. Each extension can be dynamically imported so they are split into separate\r\n * bundle chunks and downloaded only when first installed.\r\n */\r\nexport class BuiltInsExtensionFeed implements IExtensionFeed {\r\n private readonly _extensions: readonly BuiltInExtension[];\r\n\r\n public constructor(\r\n public readonly name: string,\r\n extensions: Iterable<BuiltInExtension>\r\n ) {\r\n this._extensions = Array.from(extensions);\r\n }\r\n\r\n public async queryExtensionsAsync(filter?: string): Promise<IExtensionMetadataQuery> {\r\n const filteredExtensions = filter ? this._extensions.filter((extension) => extension.name.includes(filter)) : this._extensions;\r\n return {\r\n totalCount: filteredExtensions.length,\r\n getExtensionMetadataAsync: async (index: number, count: number) => {\r\n return filteredExtensions.slice(index, index + count);\r\n },\r\n };\r\n }\r\n\r\n public async getExtensionModuleAsync(name: string): Promise<ExtensionModule | undefined> {\r\n const extension = this._extensions.find((ext) => ext.name === name);\r\n return extension ? await extension.getExtensionModuleAsync() : undefined;\r\n }\r\n}\r\n"]}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { type WeaklyTypedServiceDefinition } from "../modularity/serviceContainer.js";
|
|
2
|
+
export type PersonMetadata = {
|
|
3
|
+
/**
|
|
4
|
+
* The name of the person.
|
|
5
|
+
*/
|
|
6
|
+
readonly name: string;
|
|
7
|
+
/**
|
|
8
|
+
* The email address of the person.
|
|
9
|
+
*/
|
|
10
|
+
readonly email?: string;
|
|
11
|
+
/**
|
|
12
|
+
* The URL to the person's website.
|
|
13
|
+
*/
|
|
14
|
+
readonly url?: string;
|
|
15
|
+
/**
|
|
16
|
+
* The Babylon forum username of the person.
|
|
17
|
+
*/
|
|
18
|
+
readonly forumUserName?: string;
|
|
19
|
+
/**
|
|
20
|
+
* A base64 encoded PNG image to use as the person's avatar.
|
|
21
|
+
*/
|
|
22
|
+
readonly avatar?: string;
|
|
23
|
+
};
|
|
24
|
+
export type ExtensionMetadata = {
|
|
25
|
+
/**
|
|
26
|
+
* The name of the extension.
|
|
27
|
+
*/
|
|
28
|
+
readonly name: string;
|
|
29
|
+
/**
|
|
30
|
+
* The version of the extension (as valid semver).
|
|
31
|
+
*/
|
|
32
|
+
readonly version?: string;
|
|
33
|
+
/**
|
|
34
|
+
* The description of the extension.
|
|
35
|
+
*/
|
|
36
|
+
readonly description: string;
|
|
37
|
+
/**
|
|
38
|
+
* The keywords of the extension.
|
|
39
|
+
*/
|
|
40
|
+
readonly keywords?: readonly string[];
|
|
41
|
+
/**
|
|
42
|
+
* The URL to the extension homepage.
|
|
43
|
+
*/
|
|
44
|
+
readonly homepage?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Specify the place where your code lives. This is helpful for people who want to contribute.
|
|
47
|
+
*/
|
|
48
|
+
readonly repository?: string;
|
|
49
|
+
/**
|
|
50
|
+
* The URL to your extension's issue tracker and / or the email address to which issues should be reported. These are helpful for people who encounter issues with your extension.
|
|
51
|
+
*/
|
|
52
|
+
readonly bugs?: string;
|
|
53
|
+
/**
|
|
54
|
+
* A license for your package so that people know how they are permitted to use it, and any restrictions you're placing on it.
|
|
55
|
+
*/
|
|
56
|
+
readonly license?: string;
|
|
57
|
+
/**
|
|
58
|
+
* The primary author of the extension.
|
|
59
|
+
*/
|
|
60
|
+
readonly author?: string | PersonMetadata;
|
|
61
|
+
/**
|
|
62
|
+
* The contributors to the extension.
|
|
63
|
+
*/
|
|
64
|
+
readonly contributors?: readonly (string | PersonMetadata)[];
|
|
65
|
+
};
|
|
66
|
+
export type ExtensionModule = {
|
|
67
|
+
/**
|
|
68
|
+
* The default export of the module (e.g. export default).
|
|
69
|
+
*/
|
|
70
|
+
default: {
|
|
71
|
+
/**
|
|
72
|
+
* The services that are included with the extension.
|
|
73
|
+
*/
|
|
74
|
+
serviceDefinitions?: readonly WeaklyTypedServiceDefinition[];
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Represents a query to fetch subset ranges of extension metadata from a feed.
|
|
79
|
+
*/
|
|
80
|
+
export interface IExtensionMetadataQuery {
|
|
81
|
+
/**
|
|
82
|
+
* The total number of extensions that satisfy the query.
|
|
83
|
+
*/
|
|
84
|
+
readonly totalCount: number;
|
|
85
|
+
/**
|
|
86
|
+
* Fetches a range of extension metadata from the feed.
|
|
87
|
+
* @param index The index of the first extension to fetch.
|
|
88
|
+
* @param count The number of extensions to fetch.
|
|
89
|
+
* @returns A promise that resolves to the extension metadata.
|
|
90
|
+
*/
|
|
91
|
+
getExtensionMetadataAsync(index: number, count: number): Promise<readonly ExtensionMetadata[]>;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Represents a feed/source of extensions.
|
|
95
|
+
*/
|
|
96
|
+
export interface IExtensionFeed {
|
|
97
|
+
/**
|
|
98
|
+
* The name of the feed.
|
|
99
|
+
*/
|
|
100
|
+
readonly name: string;
|
|
101
|
+
/**
|
|
102
|
+
* Creates an extension metadata query given a filter.
|
|
103
|
+
* @param filter The filter to apply to the query.
|
|
104
|
+
* @returns A promise that resolves to the extension metadata query.
|
|
105
|
+
*/
|
|
106
|
+
queryExtensionsAsync(filter?: string): Promise<IExtensionMetadataQuery>;
|
|
107
|
+
/**
|
|
108
|
+
* Gets the extension module for the specified extension.
|
|
109
|
+
* @param name The name of the extension.
|
|
110
|
+
* @returns A promise that resolves to the extension module.
|
|
111
|
+
*/
|
|
112
|
+
getExtensionModuleAsync(name: string): Promise<ExtensionModule | undefined>;
|
|
113
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extensionFeed.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/modularTool/extensibility/extensionFeed.ts"],"names":[],"mappings":"","sourcesContent":["import { type WeaklyTypedServiceDefinition } from \"../modularity/serviceContainer\";\r\n\r\nexport type PersonMetadata = {\r\n /**\r\n * The name of the person.\r\n */\r\n readonly name: string;\r\n\r\n /**\r\n * The email address of the person.\r\n */\r\n readonly email?: string;\r\n\r\n /**\r\n * The URL to the person's website.\r\n */\r\n readonly url?: string;\r\n\r\n /**\r\n * The Babylon forum username of the person.\r\n */\r\n readonly forumUserName?: string;\r\n\r\n /**\r\n * A base64 encoded PNG image to use as the person's avatar.\r\n */\r\n readonly avatar?: string;\r\n};\r\n\r\nexport type ExtensionMetadata = {\r\n /**\r\n * The name of the extension.\r\n */\r\n readonly name: string;\r\n\r\n /**\r\n * The version of the extension (as valid semver).\r\n */\r\n readonly version?: string;\r\n\r\n /**\r\n * The description of the extension.\r\n */\r\n readonly description: string;\r\n\r\n /**\r\n * The keywords of the extension.\r\n */\r\n readonly keywords?: readonly string[];\r\n\r\n /**\r\n * The URL to the extension homepage.\r\n */\r\n readonly homepage?: string;\r\n\r\n /**\r\n * Specify the place where your code lives. This is helpful for people who want to contribute.\r\n */\r\n readonly repository?: string;\r\n\r\n /**\r\n * The URL to your extension's issue tracker and / or the email address to which issues should be reported. These are helpful for people who encounter issues with your extension.\r\n */\r\n readonly bugs?: string;\r\n\r\n /**\r\n * A license for your package so that people know how they are permitted to use it, and any restrictions you're placing on it.\r\n */\r\n readonly license?: string;\r\n\r\n /**\r\n * The primary author of the extension.\r\n */\r\n readonly author?: string | PersonMetadata;\r\n\r\n /**\r\n * The contributors to the extension.\r\n */\r\n readonly contributors?: readonly (string | PersonMetadata)[];\r\n};\r\n\r\nexport type ExtensionModule = {\r\n /**\r\n * The default export of the module (e.g. export default).\r\n */\r\n default: {\r\n /**\r\n * The services that are included with the extension.\r\n */\r\n serviceDefinitions?: readonly WeaklyTypedServiceDefinition[];\r\n };\r\n};\r\n\r\n/**\r\n * Represents a query to fetch subset ranges of extension metadata from a feed.\r\n */\r\nexport interface IExtensionMetadataQuery {\r\n /**\r\n * The total number of extensions that satisfy the query.\r\n */\r\n readonly totalCount: number;\r\n\r\n /**\r\n * Fetches a range of extension metadata from the feed.\r\n * @param index The index of the first extension to fetch.\r\n * @param count The number of extensions to fetch.\r\n * @returns A promise that resolves to the extension metadata.\r\n */\r\n getExtensionMetadataAsync(index: number, count: number): Promise<readonly ExtensionMetadata[]>;\r\n}\r\n\r\n/**\r\n * Represents a feed/source of extensions.\r\n */\r\nexport interface IExtensionFeed {\r\n /**\r\n * The name of the feed.\r\n */\r\n readonly name: string;\r\n\r\n /**\r\n * Creates an extension metadata query given a filter.\r\n * @param filter The filter to apply to the query.\r\n * @returns A promise that resolves to the extension metadata query.\r\n */\r\n queryExtensionsAsync(filter?: string): Promise<IExtensionMetadataQuery>;\r\n\r\n /**\r\n * Gets the extension module for the specified extension.\r\n * @param name The name of the extension.\r\n * @returns A promise that resolves to the extension module.\r\n */\r\n getExtensionModuleAsync(name: string): Promise<ExtensionModule | undefined>;\r\n}\r\n"]}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { type IDisposable } from "@onerjs/core/index.js";
|
|
2
|
+
import { type ServiceContainer } from "../modularity/serviceContainer.js";
|
|
3
|
+
import { type IExtensionFeed, type ExtensionMetadata } from "./extensionFeed.js";
|
|
4
|
+
/**
|
|
5
|
+
* Represents a loaded extension.
|
|
6
|
+
*/
|
|
7
|
+
export interface IExtension {
|
|
8
|
+
/**
|
|
9
|
+
* The metadata for the extension.
|
|
10
|
+
*/
|
|
11
|
+
readonly metadata: ExtensionMetadata;
|
|
12
|
+
/**
|
|
13
|
+
* Whether the extension is currently being installed, uninstalled, enabled, or disabled.
|
|
14
|
+
*/
|
|
15
|
+
readonly isStateChanging: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Whether the extension is enabled.
|
|
18
|
+
*/
|
|
19
|
+
readonly isInstalled: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Installs the extension.
|
|
22
|
+
*/
|
|
23
|
+
installAsync(): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Uninstalls the extension.
|
|
26
|
+
*/
|
|
27
|
+
uninstallAsync(): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Adds a handler that is called when the state of the extension changes.
|
|
30
|
+
* @param handler The handler to add.
|
|
31
|
+
* @returns A disposable that removes the handler when disposed.
|
|
32
|
+
*/
|
|
33
|
+
addStateChangedHandler(handler: () => void): IDisposable;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Provides information about an extension installation failure.
|
|
37
|
+
*/
|
|
38
|
+
export type InstallFailedInfo = {
|
|
39
|
+
/**
|
|
40
|
+
* The metadata of the extension that failed to install.
|
|
41
|
+
*/
|
|
42
|
+
extension: ExtensionMetadata;
|
|
43
|
+
/**
|
|
44
|
+
* The error that occurred during the installation.
|
|
45
|
+
*/
|
|
46
|
+
error: unknown;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Represents a query for loaded extensions.
|
|
50
|
+
*/
|
|
51
|
+
export interface IExtensionQuery {
|
|
52
|
+
/**
|
|
53
|
+
* The total number of extensions that satisfy the query.
|
|
54
|
+
*/
|
|
55
|
+
readonly totalCount: number;
|
|
56
|
+
/**
|
|
57
|
+
* Fetches a range of extensions from the query.
|
|
58
|
+
* @param index The index of the first extension to fetch.
|
|
59
|
+
* @param count The number of extensions to fetch.
|
|
60
|
+
* @returns A promise that resolves to the extensions.
|
|
61
|
+
*/
|
|
62
|
+
getExtensionsAsync(index: number, count: number): Promise<IExtension[]>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Manages the installation, uninstallation, enabling, and disabling of extensions.
|
|
66
|
+
*/
|
|
67
|
+
export declare class ExtensionManager implements IDisposable {
|
|
68
|
+
private readonly _namespace;
|
|
69
|
+
private readonly _serviceContainer;
|
|
70
|
+
private readonly _feeds;
|
|
71
|
+
private readonly _onInstallFailed;
|
|
72
|
+
private readonly _installedExtensions;
|
|
73
|
+
private readonly _stateChangedHandlers;
|
|
74
|
+
private constructor();
|
|
75
|
+
/**
|
|
76
|
+
* Creates a new instance of the ExtensionManager.
|
|
77
|
+
* This will automatically rehydrate previously installed and enabled extensions.
|
|
78
|
+
* @param namespace The namespace to use for storing extension state in local storage.
|
|
79
|
+
* @param serviceContainer The service container to use.
|
|
80
|
+
* @param feeds The extension feeds to include.
|
|
81
|
+
* @param onInstallFailed A callback that is called when an extension installation fails.
|
|
82
|
+
* @returns A promise that resolves to the new instance of the ExtensionManager.
|
|
83
|
+
*/
|
|
84
|
+
static CreateAsync(namespace: string, serviceContainer: ServiceContainer, feeds: readonly IExtensionFeed[], onInstallFailed: (info: InstallFailedInfo) => void): Promise<ExtensionManager>;
|
|
85
|
+
/**
|
|
86
|
+
* Gets the names of the feeds that are included in the extension manager.
|
|
87
|
+
* @returns The names of the feeds.
|
|
88
|
+
*/
|
|
89
|
+
get feedNames(): string[];
|
|
90
|
+
/**
|
|
91
|
+
* Queries the extension manager for extensions.
|
|
92
|
+
* @param filter The filter to apply to the query.
|
|
93
|
+
* @param feeds The feeds to include in the query.
|
|
94
|
+
* @param installedOnly Whether to only include installed extensions.
|
|
95
|
+
* @returns A promise that resolves to the extension query.
|
|
96
|
+
*/
|
|
97
|
+
queryExtensionsAsync(filter?: string, feeds?: string[], installedOnly?: boolean): Promise<IExtensionQuery>;
|
|
98
|
+
/**
|
|
99
|
+
* Disposes the extension manager.
|
|
100
|
+
*/
|
|
101
|
+
dispose(): void;
|
|
102
|
+
private _getInstalledExtensionStorageKey;
|
|
103
|
+
private _updateInstalledExtensionsStorage;
|
|
104
|
+
private _installAsync;
|
|
105
|
+
private _uninstallAsync;
|
|
106
|
+
private _enableAsync;
|
|
107
|
+
private _disableAsync;
|
|
108
|
+
private _addStateChangedHandler;
|
|
109
|
+
private _createExtension;
|
|
110
|
+
private _createInstalledExtension;
|
|
111
|
+
}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { Logger } from "@onerjs/core/Misc/logger.js";
|
|
2
|
+
const InstalledExtensionsKey = "Extensions/InstalledExtensions";
|
|
3
|
+
const ExtensionInstalledKeyPrefix = "Extensions/IsExtensionInstalled";
|
|
4
|
+
function GetExtensionInstalledKey(name) {
|
|
5
|
+
return `${ExtensionInstalledKeyPrefix}/${name}`;
|
|
6
|
+
}
|
|
7
|
+
function GetExtensionIdentity(feed, name) {
|
|
8
|
+
return `${feed}/${name}`;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Manages the installation, uninstallation, enabling, and disabling of extensions.
|
|
12
|
+
*/
|
|
13
|
+
export class ExtensionManager {
|
|
14
|
+
constructor(_namespace, _serviceContainer, _feeds, _onInstallFailed) {
|
|
15
|
+
this._namespace = _namespace;
|
|
16
|
+
this._serviceContainer = _serviceContainer;
|
|
17
|
+
this._feeds = _feeds;
|
|
18
|
+
this._onInstallFailed = _onInstallFailed;
|
|
19
|
+
this._installedExtensions = new Map();
|
|
20
|
+
this._stateChangedHandlers = new Map();
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Creates a new instance of the ExtensionManager.
|
|
24
|
+
* This will automatically rehydrate previously installed and enabled extensions.
|
|
25
|
+
* @param namespace The namespace to use for storing extension state in local storage.
|
|
26
|
+
* @param serviceContainer The service container to use.
|
|
27
|
+
* @param feeds The extension feeds to include.
|
|
28
|
+
* @param onInstallFailed A callback that is called when an extension installation fails.
|
|
29
|
+
* @returns A promise that resolves to the new instance of the ExtensionManager.
|
|
30
|
+
*/
|
|
31
|
+
static async CreateAsync(namespace, serviceContainer, feeds, onInstallFailed) {
|
|
32
|
+
namespace = `Babylon/${namespace}`;
|
|
33
|
+
const extensionManager = new ExtensionManager(namespace, serviceContainer, feeds, onInstallFailed);
|
|
34
|
+
// Rehydrate installed extensions.
|
|
35
|
+
const installedExtensionNames = JSON.parse(localStorage.getItem(`${namespace}/${InstalledExtensionsKey}`) ?? "[]");
|
|
36
|
+
for (const installedExtensionName of installedExtensionNames) {
|
|
37
|
+
const installedExtensionRaw = localStorage.getItem(`${namespace}/${GetExtensionInstalledKey(installedExtensionName)}`);
|
|
38
|
+
if (installedExtensionRaw) {
|
|
39
|
+
const installedExtensionData = JSON.parse(installedExtensionRaw);
|
|
40
|
+
const feed = feeds.find((feed) => feed.name === installedExtensionData.feed);
|
|
41
|
+
if (feed) {
|
|
42
|
+
const installedExtension = extensionManager._createInstalledExtension(installedExtensionData.metadata, feed);
|
|
43
|
+
extensionManager._installedExtensions.set(installedExtension.metadata.name, installedExtension);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Load installed and enabled extensions.
|
|
48
|
+
const enablePromises = [];
|
|
49
|
+
for (const extension of extensionManager._installedExtensions.values()) {
|
|
50
|
+
enablePromises.push((async () => {
|
|
51
|
+
try {
|
|
52
|
+
await extensionManager._enableAsync(extension.metadata, false, false);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// If enabling the extension fails, uninstall it. The extension install fail callback will still be called,
|
|
56
|
+
// so the owner of the ExtensionManager instance can decide what to do with the error.
|
|
57
|
+
await extensionManager._uninstallAsync(extension.metadata, false);
|
|
58
|
+
}
|
|
59
|
+
})());
|
|
60
|
+
}
|
|
61
|
+
await Promise.all(enablePromises);
|
|
62
|
+
return extensionManager;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Gets the names of the feeds that are included in the extension manager.
|
|
66
|
+
* @returns The names of the feeds.
|
|
67
|
+
*/
|
|
68
|
+
get feedNames() {
|
|
69
|
+
return this._feeds.map((feed) => feed.name);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Queries the extension manager for extensions.
|
|
73
|
+
* @param filter The filter to apply to the query.
|
|
74
|
+
* @param feeds The feeds to include in the query.
|
|
75
|
+
* @param installedOnly Whether to only include installed extensions.
|
|
76
|
+
* @returns A promise that resolves to the extension query.
|
|
77
|
+
*/
|
|
78
|
+
async queryExtensionsAsync(filter = "", feeds = this.feedNames, installedOnly = false) {
|
|
79
|
+
if (installedOnly) {
|
|
80
|
+
const installedExtensions = Array.from(this._installedExtensions.values()).filter((installedExtension) => feeds.includes(installedExtension.feed.name));
|
|
81
|
+
return {
|
|
82
|
+
totalCount: installedExtensions.length,
|
|
83
|
+
getExtensionsAsync: async (index, count) => {
|
|
84
|
+
return installedExtensions.slice(index, index + count).map((installedExtension) => this._createExtension(installedExtension.metadata, installedExtension.feed));
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
const queries = await Promise.all(this._feeds.filter((feed) => feeds.includes(feed.name)).map(async (feed) => Object.assign(await feed.queryExtensionsAsync(filter), { feed })));
|
|
89
|
+
const totalCount = queries.reduce((sum, query) => sum + query.totalCount, 0);
|
|
90
|
+
return {
|
|
91
|
+
totalCount,
|
|
92
|
+
getExtensionsAsync: async (index, count) => {
|
|
93
|
+
const extensions = new Array();
|
|
94
|
+
let remaining = count;
|
|
95
|
+
for (const query of queries) {
|
|
96
|
+
if (remaining <= 0) {
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
if (index >= query.totalCount) {
|
|
100
|
+
index -= query.totalCount;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
// This is intentionally sequential as we are querying for results until the count of results is met.
|
|
104
|
+
// eslint-disable-next-line no-await-in-loop
|
|
105
|
+
const metadataSlice = await query.getExtensionMetadataAsync(index, remaining);
|
|
106
|
+
extensions.push(...metadataSlice.map((metadata) => this._createExtension(metadata, query.feed)));
|
|
107
|
+
remaining -= metadataSlice.length;
|
|
108
|
+
index = 0;
|
|
109
|
+
}
|
|
110
|
+
return extensions;
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Disposes the extension manager.
|
|
116
|
+
*/
|
|
117
|
+
dispose() {
|
|
118
|
+
for (const installedExtension of this._installedExtensions.values()) {
|
|
119
|
+
// eslint-disable-next-line github/no-then
|
|
120
|
+
this._disableAsync(installedExtension.metadata, false).catch((error) => {
|
|
121
|
+
Logger.Warn(`Failed to disable extension ${installedExtension.metadata.name}: ${error}`);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
this._stateChangedHandlers.clear();
|
|
125
|
+
}
|
|
126
|
+
_getInstalledExtensionStorageKey(metadata, feed) {
|
|
127
|
+
return `${this._namespace}/${GetExtensionInstalledKey(GetExtensionIdentity(feed.name, metadata.name))}`;
|
|
128
|
+
}
|
|
129
|
+
_updateInstalledExtensionsStorage() {
|
|
130
|
+
localStorage.setItem(`${this._namespace}/${InstalledExtensionsKey}`, JSON.stringify(Array.from(this._installedExtensions.values()).map((extension) => GetExtensionIdentity(extension.feed.name, extension.metadata.name))));
|
|
131
|
+
}
|
|
132
|
+
async _installAsync(metadata, feed, isNestedStateChange) {
|
|
133
|
+
let installedExtension = this._installedExtensions.get(metadata.name);
|
|
134
|
+
if (!installedExtension) {
|
|
135
|
+
installedExtension = this._createInstalledExtension(metadata, feed);
|
|
136
|
+
installedExtension.isStateChanging = true;
|
|
137
|
+
this._installedExtensions.set(metadata.name, installedExtension);
|
|
138
|
+
try {
|
|
139
|
+
// Enable the extension.
|
|
140
|
+
await this._enableAsync(metadata, true, true);
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
this._installedExtensions.delete(metadata.name);
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
finally {
|
|
147
|
+
!isNestedStateChange && (installedExtension.isStateChanging = false);
|
|
148
|
+
}
|
|
149
|
+
// Mark the extension as being installed.
|
|
150
|
+
localStorage.setItem(this._getInstalledExtensionStorageKey(metadata, feed), JSON.stringify({
|
|
151
|
+
feed: feed.name,
|
|
152
|
+
metadata,
|
|
153
|
+
}));
|
|
154
|
+
this._updateInstalledExtensionsStorage();
|
|
155
|
+
}
|
|
156
|
+
return installedExtension;
|
|
157
|
+
}
|
|
158
|
+
async _uninstallAsync(metadata, isNestedStateChange) {
|
|
159
|
+
const installedExtension = this._installedExtensions.get(metadata.name);
|
|
160
|
+
if (installedExtension && (isNestedStateChange || !installedExtension.isStateChanging)) {
|
|
161
|
+
try {
|
|
162
|
+
!isNestedStateChange && (installedExtension.isStateChanging = true);
|
|
163
|
+
// Disable the extension.
|
|
164
|
+
await this._disableAsync(metadata, true);
|
|
165
|
+
// Remove the extension from in memory.
|
|
166
|
+
this._installedExtensions.delete(metadata.name);
|
|
167
|
+
// Mark the extension as being uninstalled.
|
|
168
|
+
localStorage.removeItem(this._getInstalledExtensionStorageKey(metadata, installedExtension.feed));
|
|
169
|
+
this._updateInstalledExtensionsStorage();
|
|
170
|
+
}
|
|
171
|
+
finally {
|
|
172
|
+
!isNestedStateChange && (installedExtension.isStateChanging = false);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
async _enableAsync(metadata, isInitialInstall, isNestedStateChange) {
|
|
177
|
+
const installedExtension = this._installedExtensions.get(metadata.name);
|
|
178
|
+
if (installedExtension && (isNestedStateChange || !installedExtension.isStateChanging)) {
|
|
179
|
+
try {
|
|
180
|
+
!isNestedStateChange && (installedExtension.isStateChanging = true);
|
|
181
|
+
// If we haven't done so already, load the extension module.
|
|
182
|
+
if (!installedExtension.extensionModule) {
|
|
183
|
+
installedExtension.extensionModule = await installedExtension.feed.getExtensionModuleAsync(metadata.name);
|
|
184
|
+
}
|
|
185
|
+
if (!installedExtension.extensionModule) {
|
|
186
|
+
throw new Error(`Unable to load extension module for "${metadata.name}" from feed "${installedExtension.feed.name}".`);
|
|
187
|
+
}
|
|
188
|
+
// Register the ServiceDefinitions.
|
|
189
|
+
let servicesRegistrationToken = null;
|
|
190
|
+
if (installedExtension.extensionModule.default.serviceDefinitions) {
|
|
191
|
+
servicesRegistrationToken = await this._serviceContainer.addServicesAsync(...installedExtension.extensionModule.default.serviceDefinitions);
|
|
192
|
+
}
|
|
193
|
+
// Create a registration token to for dispose.
|
|
194
|
+
installedExtension.registrationToken = {
|
|
195
|
+
dispose: () => {
|
|
196
|
+
servicesRegistrationToken?.dispose();
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
this._onInstallFailed({
|
|
202
|
+
extension: metadata,
|
|
203
|
+
error,
|
|
204
|
+
});
|
|
205
|
+
throw error;
|
|
206
|
+
}
|
|
207
|
+
finally {
|
|
208
|
+
!isNestedStateChange && (installedExtension.isStateChanging = false);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
async _disableAsync(metadata, isNestedStateChange) {
|
|
213
|
+
const installedExtension = this._installedExtensions.get(metadata.name);
|
|
214
|
+
if (installedExtension && (isNestedStateChange || !installedExtension.isStateChanging)) {
|
|
215
|
+
try {
|
|
216
|
+
!isNestedStateChange && (installedExtension.isStateChanging = true);
|
|
217
|
+
// Unregister the service registrations.
|
|
218
|
+
installedExtension.registrationToken?.dispose();
|
|
219
|
+
}
|
|
220
|
+
finally {
|
|
221
|
+
!isNestedStateChange && (installedExtension.isStateChanging = false);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
_addStateChangedHandler(metadata, handler) {
|
|
226
|
+
let stateChangedHandlers = this._stateChangedHandlers.get(metadata.name);
|
|
227
|
+
if (!stateChangedHandlers) {
|
|
228
|
+
this._stateChangedHandlers.set(metadata.name, (stateChangedHandlers = new Set()));
|
|
229
|
+
}
|
|
230
|
+
stateChangedHandlers.add(handler);
|
|
231
|
+
return {
|
|
232
|
+
dispose: () => {
|
|
233
|
+
stateChangedHandlers.delete(handler);
|
|
234
|
+
if (stateChangedHandlers.size === 0) {
|
|
235
|
+
this._stateChangedHandlers.delete(metadata.name);
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
_createExtension(metadata, feed) {
|
|
241
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
242
|
+
const extensionManager = this;
|
|
243
|
+
return {
|
|
244
|
+
metadata,
|
|
245
|
+
get isStateChanging() {
|
|
246
|
+
return extensionManager._installedExtensions.get(metadata.name)?.isStateChanging ?? false;
|
|
247
|
+
},
|
|
248
|
+
get isInstalled() {
|
|
249
|
+
return extensionManager._installedExtensions.has(metadata.name);
|
|
250
|
+
},
|
|
251
|
+
installAsync: async () => {
|
|
252
|
+
await extensionManager._installAsync(metadata, feed, false);
|
|
253
|
+
},
|
|
254
|
+
uninstallAsync: async () => await extensionManager._uninstallAsync(metadata, false),
|
|
255
|
+
addStateChangedHandler: (handler) => extensionManager._addStateChangedHandler(metadata, handler),
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
_createInstalledExtension(metadata, feed) {
|
|
259
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
260
|
+
const extensionManager = this;
|
|
261
|
+
let isStateChanging = false;
|
|
262
|
+
return {
|
|
263
|
+
metadata,
|
|
264
|
+
feed,
|
|
265
|
+
get isStateChanging() {
|
|
266
|
+
return isStateChanging;
|
|
267
|
+
},
|
|
268
|
+
set isStateChanging(value) {
|
|
269
|
+
if (value !== isStateChanging) {
|
|
270
|
+
isStateChanging = value;
|
|
271
|
+
extensionManager._stateChangedHandlers.get(this.metadata.name)?.forEach((handler) => handler());
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
//# sourceMappingURL=extensionManager.js.map
|