Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions src/apps/backoffice/components/backoffice-main.element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { UmbBackofficeContext, UMB_BACKOFFICE_CONTEXT_TOKEN } from '../backoffic
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbSectionContext, UMB_SECTION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/section';
import type { UmbRoute, UmbRouterSlotChangeEvent } from '@umbraco-cms/backoffice/router';
import type { ManifestSection, UmbSectionExtensionElement } from '@umbraco-cms/backoffice/extension-registry';
import type { ManifestSection, UmbSectionElement } from '@umbraco-cms/backoffice/extension-registry';
import {
UmbExtensionManifestController,
createExtensionElementOrFallback,
createExtensionElement,
} from '@umbraco-cms/backoffice/extension-api';
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';

Expand Down Expand Up @@ -48,18 +48,17 @@ export class UmbBackofficeMainElement extends UmbLitElement {
const oldValue = this._routes;

// TODO: Refactor this for re-use across the app where the routes are re-generated at any time.
// TODO: remove section-routes that does not exist anymore.
this._routes = this._sections.map((section) => {
this._routes = this._sections.filter(x => x.manifest).map((section) => {
const existingRoute = this._routes.find((r) => r.alias === section.alias);
if (existingRoute) {
return existingRoute;
} else {
return {
alias: section.alias,
path: this._routePrefix + (section.manifest as any).meta.pathname,
component: () => createExtensionElementOrFallback(section.manifest, 'umb-section-default'),
path: this._routePrefix + (section.manifest as ManifestSection).meta.pathname,
component: () => createExtensionElement((section.manifest as ManifestSection), 'umb-section-default'),
setup: (component) => {
(component as UmbSectionExtensionElement).manifest = section.manifest as any;
(component as UmbSectionElement).manifest = section.manifest as ManifestSection;
},
};
}
Expand Down Expand Up @@ -104,7 +103,7 @@ export class UmbBackofficeMainElement extends UmbLitElement {
:host {
background-color: var(--uui-color-background);
display: block;
height: calc(100% - 60px); // 60 => top header height
height: calc(100% - 60px); // 60 => top header height, TODO: Make sure this comes from somewhere so it is maintainable and eventually responsive.
}
`,
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ describe('UmbBaseExtensionController', () => {
type: 'condition',
name: 'test-condition-valid',
alias: 'Umb.Test.Condition.Valid',
class: UmbTestConditionAlwaysValid,
api: UmbTestConditionAlwaysValid,
};
});

Expand Down Expand Up @@ -407,7 +407,7 @@ describe('UmbBaseExtensionController', () => {
type: 'condition',
name: 'test-condition-invalid',
alias: 'Umb.Test.Condition.Invalid',
class: UmbTestConditionAlwaysInvalid,
api: UmbTestConditionAlwaysInvalid,
};
});

Expand Down Expand Up @@ -503,7 +503,7 @@ describe('UmbBaseExtensionController', () => {
type: 'condition',
name: 'test-condition-delay',
alias: 'Umb.Test.Condition.Delay',
class: UmbSwitchCondition,
api: UmbSwitchCondition,
};

extensionRegistry.register(manifest);
Expand Down Expand Up @@ -568,7 +568,7 @@ describe('UmbBaseExtensionController', () => {
type: 'condition',
name: 'test-condition-delay',
alias: 'Umb.Test.Condition.Delay',
class: UmbSwitchCondition,
api: UmbSwitchCondition,
};

extensionRegistry.register(manifest);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
type ManifestCondition,
type ManifestWithDynamicConditions,
type UmbExtensionRegistry,
createExtensionClass,
createExtensionApi,
} from '@umbraco-cms/backoffice/extension-api';
import { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';

Expand Down Expand Up @@ -142,7 +142,7 @@ export abstract class UmbBaseExtensionController<
// Check if we already have a controller for this config:
const existing = this.#conditionControllers.find((controller) => controller.config === conditionConfig);
if (!existing) {
const conditionController = await createExtensionClass<UmbExtensionCondition>(conditionManifest, [
const conditionController = await createExtensionApi<UmbExtensionCondition>(conditionManifest, [
{
host: this,
manifest: conditionManifest,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ describe('UmbBaseExtensionsController', () => {
type: 'condition',
name: 'test-condition-valid',
alias: 'Umb.Test.Condition.Valid',
class: UmbTestConditionAlwaysValid,
api: UmbTestConditionAlwaysValid,
});
});

Expand Down Expand Up @@ -320,7 +320,7 @@ describe('UmbBaseExtensionsController', () => {
type: 'condition',
name: 'test-condition-invalid',
alias: 'Umb.Test.Condition.Invalid',
class: UmbTestConditionAlwaysInvalid,
api: UmbTestConditionAlwaysInvalid,
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ describe('UmbExtensionElementController', () => {
type: 'condition',
name: 'test-condition-delay',
alias: 'Umb.Test.Condition.Delay',
class: UmbSwitchCondition,
api: UmbSwitchCondition,
};

extensionRegistry.register(manifest);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createExtensionElement } from '../create-extension-element.function.js';
import { createExtensionElement } from '../functions/create-extension-element.function.js';
import { UmbExtensionRegistry } from '../registry/extension.registry.js';
import { isManifestElementableType } from '../type-guards/is-manifest-elementable-type.function.js';
import { ManifestCondition, ManifestWithDynamicConditions } from '../types.js';
Expand Down Expand Up @@ -69,13 +69,15 @@ export class UmbExtensionElementController<
protected async _conditionsAreGood() {
const manifest = this.manifest!; // In this case we are sure its not undefined.

console.log("---defaultElement", this._defaultElement)
if (isManifestElementableType(manifest)) {
const newComponent = await createExtensionElement(manifest);
const newComponent = await createExtensionElement(manifest, this._defaultElement);
if (!this._positive) {
// We are not positive anymore, so we will back out of this creation.
return false;
}
this._component = newComponent;

} else if (this._defaultElement) {
this._component = document.createElement(this._defaultElement);
} else {
Expand Down
35 changes: 0 additions & 35 deletions src/libs/extension-api/create-extension-class.function.ts

This file was deleted.

This file was deleted.

38 changes: 0 additions & 38 deletions src/libs/extension-api/create-extension-element.function.ts

This file was deleted.

37 changes: 37 additions & 0 deletions src/libs/extension-api/functions/create-extension-api.function.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { hasApiExport, hasDefaultExport, isManifestApiConstructorType } from '../type-guards/index.js';
import type { ManifestApi, ClassConstructor, ManifestElementAndApi } from '../types.js';
import { loadExtensionApi } from '../functions/load-extension-api.function.js';

//TODO: Write tests for this method:
export async function createExtensionApi<ApiType = unknown>(
manifest: ManifestApi<ApiType> | ManifestElementAndApi<any, ApiType>,
constructorArguments: unknown[]
): Promise<ApiType | undefined> {
const js = await loadExtensionApi(manifest);

if (isManifestApiConstructorType<ApiType>(manifest)) {
return new manifest.api(...constructorArguments);
}

if (js) {
if (hasApiExport<ClassConstructor<ApiType>>(js)) {
return new js.api(...constructorArguments);
}
if (hasDefaultExport<ClassConstructor<ApiType>>(js)) {
return new js.default(...constructorArguments);
}

console.error(
`-- Extension of alias "${manifest.alias}" did not succeed creating an api class instance, missing a 'api' or 'default' export of the served JavaScript file`,
manifest
);

return undefined;
}

console.error(
`-- Extension of alias "${manifest.alias}" did not succeed creating an api class instance, missing a JavaScript file via the 'apiJs' or 'js' property or a ClassConstructor in 'api' in the manifest.`,
manifest
);
return undefined;
}
120 changes: 120 additions & 0 deletions src/libs/extension-api/functions/create-extension-api.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { expect } from '@open-wc/testing';
import { ManifestApi } from '../types.js';
import { createExtensionApi } from './create-extension-api.function.js';




class UmbExtensionApiTrueTestClass {
isValidClassInstance() {
return true;
}
}

class UmbExtensionApiFalseTestClass {
isValidClassInstance() {
return false;
}
}



const jsModuleWithDefaultExport = {
default: UmbExtensionApiTrueTestClass
};

const jsModuleWithApiExport = {
api: UmbExtensionApiTrueTestClass
};

const jsModuleWithDefaultAndApiExport = {
default: UmbExtensionApiFalseTestClass,
api: UmbExtensionApiTrueTestClass
};



describe('Extension-Api: Create Extension Api', () => {



it('Returns `undefined` when manifest does not have any correct properties', async () => {

const manifest: ManifestApi = {
type: 'my-test-type',
alias: 'Umb.Test.CreateExtensionApi',
name: 'pretty name'
};

const api = await createExtensionApi(manifest, []);
expect(api).to.be.undefined;
});

it('Handles when `api` property contains a class constructor', async () => {

const manifest: ManifestApi<UmbExtensionApiTrueTestClass> = {
type: 'my-test-type',
alias: 'Umb.Test.CreateExtensionApi',
name: 'pretty name',
api: UmbExtensionApiTrueTestClass
};

const api = await createExtensionApi(manifest, []);
expect(api).to.not.be.undefined;
if(api) {
expect(api.isValidClassInstance()).to.be.true;
}
});

it('Handles when `loader` has a default export', async () => {

const manifest: ManifestApi<UmbExtensionApiTrueTestClass> = {
type: 'my-test-type',
alias: 'Umb.Test.CreateExtensionApi',
name: 'pretty name',
loader: () => Promise.resolve(jsModuleWithDefaultExport)
};

const api = await createExtensionApi(manifest, []);
expect(api).to.not.be.undefined;
if(api) {
expect(api.isValidClassInstance()).to.be.true;
}
});

it('Handles when `loader` has a api export', async () => {

const manifest: ManifestApi<UmbExtensionApiTrueTestClass> = {
type: 'my-test-type',
alias: 'Umb.Test.CreateExtensionApi',
name: 'pretty name',
loader: () => Promise.resolve(jsModuleWithApiExport)
};

const api = await createExtensionApi(manifest, []);
expect(api).to.not.be.undefined;
if(api) {
expect(api.isValidClassInstance()).to.be.true;
}
});

it('Prioritizes api export from loader property', async () => {

const manifest: ManifestApi<UmbExtensionApiTrueTestClass> = {
type: 'my-test-type',
alias: 'Umb.Test.CreateExtensionApi',
name: 'pretty name',
loader: () => Promise.resolve(jsModuleWithDefaultAndApiExport)
};

const api = await createExtensionApi(manifest, []);
expect(api).to.not.be.undefined;
if(api) {
expect(api.isValidClassInstance()).to.be.true;
}
});

//TODO: Test apiJs
//TODO: Test js

});
Loading