stable, but still has the startup problem
This commit is contained in:
@@ -10,7 +10,7 @@ import { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
|
||||
|
||||
export abstract class UmbBaseExtensionInitializer<
|
||||
ManifestType extends ManifestWithDynamicConditions = ManifestWithDynamicConditions,
|
||||
SubClassType = never
|
||||
SubClassType = never,
|
||||
> extends UmbBaseController {
|
||||
#promiseResolvers: Array<() => void> = [];
|
||||
#manifestObserver!: UmbObserverController<ManifestType | undefined>;
|
||||
@@ -20,7 +20,7 @@ export abstract class UmbBaseExtensionInitializer<
|
||||
#manifest?: ManifestType;
|
||||
#conditionControllers: Array<UmbExtensionCondition> = [];
|
||||
#onPermissionChanged?: (isPermitted: boolean, controller: SubClassType) => void;
|
||||
protected _positive?: boolean;
|
||||
protected _isConditionsPositive?: boolean;
|
||||
#isPermitted?: boolean;
|
||||
|
||||
get weight() {
|
||||
@@ -53,7 +53,7 @@ export abstract class UmbBaseExtensionInitializer<
|
||||
extensionRegistry: UmbExtensionRegistry<ManifestCondition>,
|
||||
extensionTypeName: string,
|
||||
alias: string,
|
||||
onPermissionChanged?: (isPermitted: boolean, controller: SubClassType) => void
|
||||
onPermissionChanged?: (isPermitted: boolean, controller: SubClassType) => void,
|
||||
) {
|
||||
super(host, extensionTypeName + '_' + alias);
|
||||
this.#extensionRegistry = extensionRegistry;
|
||||
@@ -79,7 +79,7 @@ export abstract class UmbBaseExtensionInitializer<
|
||||
this.#overwrites = [];
|
||||
this.#cleanConditions();
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -132,10 +132,12 @@ export abstract class UmbBaseExtensionInitializer<
|
||||
this.observe(
|
||||
this.#extensionRegistry.getByTypeAndAliases('condition', conditionAliases),
|
||||
async (manifests) => {
|
||||
const oldLength = this.#conditionControllers.length;
|
||||
|
||||
// New comers:
|
||||
manifests.forEach((conditionManifest) => {
|
||||
const configsOfThisType = conditionConfigs.filter(
|
||||
(conditionConfig) => conditionConfig.alias === conditionManifest.alias
|
||||
(conditionConfig) => conditionConfig.alias === conditionManifest.alias,
|
||||
);
|
||||
|
||||
// Spin up conditions, based of condition configs:
|
||||
@@ -153,15 +155,18 @@ export abstract class UmbBaseExtensionInitializer<
|
||||
]);
|
||||
if (conditionController) {
|
||||
// Some how listen to it? callback/event/onChange something.
|
||||
// then call this one: this.#onConditionsChanged();
|
||||
this.#conditionControllers.push(conditionController);
|
||||
this.#onConditionsChangedCallback();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// If a change to amount of condition controllers, this will make sure that when new conditions are added, the callback is fired, so the extensions can be re-evaluated, starting out as bad.
|
||||
if (oldLength !== this.#conditionControllers.length) {
|
||||
this.#onConditionsChangedCallback();
|
||||
}
|
||||
},
|
||||
'_observeConditions'
|
||||
'_observeConditions',
|
||||
);
|
||||
} else {
|
||||
this.removeControllerByAlias('_observeConditions');
|
||||
@@ -182,21 +187,28 @@ export abstract class UmbBaseExtensionInitializer<
|
||||
}
|
||||
|
||||
#onConditionsChangedCallback = async () => {
|
||||
const oldValue = this.#isPermitted ?? false;
|
||||
// We will collect old value here, but we need to re-collect it after a async method have been called, as it could have changed in the mean time.
|
||||
let oldValue = this.#isPermitted ?? false;
|
||||
|
||||
// Find a condition that is not permitted (Notice how no conditions, means that this extension is permitted)
|
||||
const isPositive =
|
||||
this.#conditionsAreInitialized() &&
|
||||
this.#conditionControllers.find((condition) => condition.permitted === false) === undefined;
|
||||
|
||||
this._positive = isPositive;
|
||||
this._isConditionsPositive = isPositive;
|
||||
|
||||
if (isPositive) {
|
||||
if (this.#isPermitted !== true) {
|
||||
this.#isPermitted = await this._conditionsAreGood();
|
||||
const newPermission = await this._conditionsAreGood();
|
||||
// We update the oldValue as this point, cause in this way we are sure its the value at this point, when doing async code someone else might have changed the state in the mean time.
|
||||
oldValue = this.#isPermitted ?? false;
|
||||
// Only set new permission if we are still positive.
|
||||
this.#isPermitted = newPermission;
|
||||
}
|
||||
} else if (this.#isPermitted !== false) {
|
||||
await this._conditionsAreBad();
|
||||
// Clean up:
|
||||
this.#isPermitted = false;
|
||||
await this._conditionsAreBad();
|
||||
}
|
||||
if (oldValue !== this.#isPermitted) {
|
||||
if (this.#isPermitted) {
|
||||
@@ -215,13 +227,34 @@ export abstract class UmbBaseExtensionInitializer<
|
||||
return otherClass?.manifest === this.manifest;
|
||||
}
|
||||
|
||||
/*
|
||||
public hostConnected(): void {
|
||||
super.hostConnected();
|
||||
//this.#onConditionsChangedCallback();
|
||||
}
|
||||
|
||||
public hostDisconnected(): void {
|
||||
super.hostDisconnected();
|
||||
this._runtimePositive = false;
|
||||
if (this.#isPermitted === true) {
|
||||
this.#isPermitted = false;
|
||||
this._conditionsAreBad();
|
||||
this.#onPermissionChanged?.(false, this as any);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
public destroy(): void {
|
||||
this.#promiseResolvers = [];
|
||||
this.#isPermitted = undefined;
|
||||
this._isConditionsPositive = false;
|
||||
if (this.#isPermitted === true) {
|
||||
this.#isPermitted = undefined;
|
||||
this._conditionsAreBad();
|
||||
this.#onPermissionChanged?.(false, this as any);
|
||||
}
|
||||
this.#overwrites = [];
|
||||
this.#cleanConditions();
|
||||
super.destroy();
|
||||
// Destroy the conditions controllers, are begin destroyed cause they are controllers.
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ import type {
|
||||
UmbBaseExtensionInitializer,
|
||||
UmbExtensionRegistry,
|
||||
} from '@umbraco-cms/backoffice/extension-api';
|
||||
import { UmbBaseController, UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbBaseController, type UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
import type { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
|
||||
|
||||
export type PermittedControllerType<ControllerType extends { manifest: any }> = ControllerType & {
|
||||
manifest: Required<Pick<ControllerType, 'manifest'>>;
|
||||
@@ -18,7 +19,7 @@ export abstract class UmbBaseExtensionsInitializer<
|
||||
ManifestTypeName extends keyof ManifestTypeMap<ManifestTypes> | string,
|
||||
ManifestType extends ManifestBase = SpecificManifestTypeOrManifestBase<ManifestTypes, ManifestTypeName>,
|
||||
ControllerType extends UmbBaseExtensionInitializer<ManifestType> = UmbBaseExtensionInitializer<ManifestType>,
|
||||
MyPermittedControllerType extends ControllerType = PermittedControllerType<ControllerType>
|
||||
MyPermittedControllerType extends ControllerType = PermittedControllerType<ControllerType>,
|
||||
> extends UmbBaseController {
|
||||
#promiseResolvers: Array<() => void> = [];
|
||||
#extensionRegistry: UmbExtensionRegistry<ManifestType>;
|
||||
@@ -39,7 +40,7 @@ export abstract class UmbBaseExtensionsInitializer<
|
||||
extensionRegistry: UmbExtensionRegistry<ManifestType>,
|
||||
type: ManifestTypeName | Array<ManifestTypeName>,
|
||||
filter: undefined | null | ((manifest: ManifestType) => boolean),
|
||||
onChange?: (permittedManifests: Array<MyPermittedControllerType>) => void
|
||||
onChange?: (permittedManifests: Array<MyPermittedControllerType>) => void,
|
||||
) {
|
||||
super(host, 'extensionsInitializer_' + (Array.isArray(type) ? type.join('_') : type));
|
||||
this.#extensionRegistry = extensionRegistry;
|
||||
@@ -109,6 +110,7 @@ export abstract class UmbBaseExtensionsInitializer<
|
||||
hasChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasChanged) {
|
||||
// The final list of permitted extensions to be displayed, this will be stripped from extensions that are overwritten by another extension and sorted accordingly.
|
||||
const exposedPermittedExts = [...this._permittedExts];
|
||||
|
||||
@@ -5,24 +5,24 @@ import { ManifestApi, ManifestCondition } from '../types/index.js';
|
||||
import { UmbBaseExtensionInitializer } from './base-extension-initializer.controller.js';
|
||||
import { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
|
||||
|
||||
/**
|
||||
* This Controller manages a single Extension and its API instance.
|
||||
* When the extension is permitted to be used, its API will be instantiated and available for the consumer.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const controller = new UmbExtensionApiController(host, extensionRegistry, alias, [], (permitted, ctrl) => { ctrl.api.helloWorld() }));
|
||||
* ```
|
||||
* ```ts
|
||||
* const controller = new UmbExtensionApiController(host, extensionRegistry, alias, [], (permitted, ctrl) => { ctrl.api.helloWorld() }));
|
||||
* ```
|
||||
* @export
|
||||
* @class UmbExtensionApiController
|
||||
*/
|
||||
export class UmbExtensionApiInitializer<
|
||||
ManifestType extends ManifestApi = ManifestApi,
|
||||
ManifestType extends ManifestApi = ManifestApi,
|
||||
ControllerType extends UmbExtensionApiInitializer<ManifestType, any> = any,
|
||||
ExtensionApiInterface extends UmbApi = ManifestType extends ManifestApi ? NonNullable<ManifestType['API_TYPE']> : UmbApi
|
||||
ExtensionApiInterface extends UmbApi = ManifestType extends ManifestApi
|
||||
? NonNullable<ManifestType['API_TYPE']>
|
||||
: UmbApi,
|
||||
> extends UmbBaseExtensionInitializer<ManifestType, ControllerType> {
|
||||
|
||||
#api?: ExtensionApiInterface;
|
||||
#constructorArguments?: Array<unknown>;
|
||||
|
||||
@@ -35,7 +35,6 @@ export class UmbExtensionApiInitializer<
|
||||
return this.#api;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The props that are passed to the class.
|
||||
* @type {Record<string, any>}
|
||||
@@ -67,7 +66,7 @@ export class UmbExtensionApiInitializer<
|
||||
extensionRegistry: UmbExtensionRegistry<ManifestCondition>,
|
||||
alias: string,
|
||||
constructorArguments: Array<unknown> | undefined,
|
||||
onPermissionChanged?: (isPermitted: boolean, controller: ControllerType) => void
|
||||
onPermissionChanged?: (isPermitted: boolean, controller: ControllerType) => void,
|
||||
) {
|
||||
super(host, extensionRegistry, 'extApi_', alias, onPermissionChanged);
|
||||
this.#constructorArguments = constructorArguments;
|
||||
@@ -88,13 +87,16 @@ export class UmbExtensionApiInitializer<
|
||||
protected async _conditionsAreGood() {
|
||||
const manifest = this.manifest!; // In this case we are sure its not undefined.
|
||||
|
||||
const newApi = await createExtensionApi<ExtensionApiInterface>(manifest as unknown as ManifestApi<ExtensionApiInterface>, this.#constructorArguments);
|
||||
if (!this._positive) {
|
||||
const newApi = await createExtensionApi<ExtensionApiInterface>(
|
||||
manifest as unknown as ManifestApi<ExtensionApiInterface>,
|
||||
this.#constructorArguments,
|
||||
);
|
||||
if (!this._isConditionsPositive) {
|
||||
// We are not positive anymore, so we will back out of this creation.
|
||||
return false;
|
||||
}
|
||||
this.#api = newApi;
|
||||
|
||||
|
||||
if (this.#api) {
|
||||
//this.#assignProperties();
|
||||
return true; // we will confirm we have a component and are still good to go.
|
||||
|
||||
@@ -9,15 +9,15 @@ import { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
* When the extension is permitted to be used, its Element will be instantiated and available for the consumer.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const controller = new UmbExtensionElementController(host, extensionRegistry, alias, (permitted, ctrl) => { console.log("Extension is permitted and this is the element: ", ctrl.component) }));
|
||||
* ```
|
||||
* ```ts
|
||||
* const controller = new UmbExtensionElementController(host, extensionRegistry, alias, (permitted, ctrl) => { console.log("Extension is permitted and this is the element: ", ctrl.component) }));
|
||||
* ```
|
||||
* @export
|
||||
* @class UmbExtensionElementController
|
||||
*/
|
||||
export class UmbExtensionElementInitializer<
|
||||
ManifestType extends ManifestWithDynamicConditions = ManifestWithDynamicConditions,
|
||||
ControllerType extends UmbExtensionElementInitializer<ManifestType, any> = any
|
||||
ControllerType extends UmbExtensionElementInitializer<ManifestType, any> = any,
|
||||
> extends UmbBaseExtensionInitializer<ManifestType, ControllerType> {
|
||||
#defaultElement?: string;
|
||||
#component?: HTMLElement;
|
||||
@@ -60,7 +60,7 @@ export class UmbExtensionElementInitializer<
|
||||
extensionRegistry: UmbExtensionRegistry<ManifestCondition>,
|
||||
alias: string,
|
||||
onPermissionChanged: (isPermitted: boolean, controller: ControllerType) => void,
|
||||
defaultElement?: string
|
||||
defaultElement?: string,
|
||||
) {
|
||||
super(host, extensionRegistry, 'extElement_', alias, onPermissionChanged);
|
||||
this.#defaultElement = defaultElement;
|
||||
@@ -80,7 +80,7 @@ export class UmbExtensionElementInitializer<
|
||||
const manifest = this.manifest!; // In this case we are sure its not undefined.
|
||||
|
||||
const newComponent = await createExtensionElement(manifest, this.#defaultElement);
|
||||
if (!this._positive) {
|
||||
if (!this._isConditionsPositive) {
|
||||
// We are not positive anymore, so we will back out of this creation.
|
||||
return false;
|
||||
}
|
||||
@@ -90,7 +90,7 @@ export class UmbExtensionElementInitializer<
|
||||
(this.#component as any).manifest = manifest;
|
||||
return true; // we will confirm we have a component and are still good to go.
|
||||
} else {
|
||||
console.warn('Manifest did not provide any useful data for a web component to be created.')
|
||||
console.warn('Manifest did not provide any useful data for a web component to be created.');
|
||||
}
|
||||
|
||||
return false; // we will reject the state, we have no component, we are not good to be shown.
|
||||
|
||||
Reference in New Issue
Block a user