Merge pull request #624 from umbraco/feature/one-step-closer-to-core-code-aligned-with-packages

This commit is contained in:
Niels Lyngsø
2023-04-21 09:37:34 +02:00
committed by GitHub
28 changed files with 244 additions and 133 deletions

View File

@@ -70,6 +70,10 @@ export class UmbExtensionRegistry {
this._extensions.next([...extensionsValues, manifest as ManifestTypes]);
}
registerMany(manifests: Array<ManifestTypes>): void {
manifests.forEach((manifest) => this.register(manifest));
}
unregister(alias: string): void {
const oldExtensionsValues = this._extensions.getValue();
const newExtensionsValues = oldExtensionsValues.filter((extension) => extension.alias !== alias);

View File

@@ -3,26 +3,27 @@ import { hasInitExport, loadExtension, UmbExtensionRegistry } from '@umbraco-cms
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export class UmbEntryPointExtensionInitializer {
#rootHost;
#host;
#extensionRegistry;
#entryPointMap = new Map();
constructor(rootHost: UmbControllerHostElement, extensionRegistry: UmbExtensionRegistry) {
this.#rootHost = rootHost;
constructor(host: UmbControllerHostElement, extensionRegistry: UmbExtensionRegistry) {
this.#host = host;
this.#extensionRegistry = extensionRegistry;
// TODO: change entrypoint extension to be entryPoint:
extensionRegistry.extensionsOfType('entrypoint').subscribe((entryPoints) => {
extensionRegistry.extensionsOfType('entryPoint').subscribe((entryPoints) => {
entryPoints.forEach((entryPoint) => {
if (this.#entryPointMap.has(entryPoint.alias)) return;
this.#entryPointMap.set(entryPoint.alias, entryPoint);
this.instantiateEntryPoint(entryPoint);
});
});
}
instantiateEntryPoint(manifest: ManifestEntrypoint) {
loadExtension(manifest).then((js) => {
// If the extension has an onInit export, be sure to run that or else let the module handle itself
if (hasInitExport(js)) {
js.onInit(this.#rootHost, this.#extensionRegistry);
}
});
async instantiateEntryPoint(manifest: ManifestEntrypoint) {
const js = await loadExtension(manifest);
// If the extension has an onInit export, be sure to run that or else let the module handle itself
if (hasInitExport(js)) {
js.onInit(this.#host, this.#extensionRegistry);
}
}
}

View File

@@ -234,7 +234,7 @@ export interface ManifestWithMeta extends ManifestBase {
* You could have custom logic to decide which extensions to load/register by using extensionRegistry
*/
export interface ManifestEntrypoint extends ManifestBase {
type: 'entrypoint';
type: 'entryPoint';
/**
* The file location of the javascript file to load in the backoffice

View File

@@ -1,40 +1,30 @@
import { defineElement } from '@umbraco-ui/uui-base/lib/registration';
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { css, html } from 'lit';
import { UmbCurrentUserStore, UMB_CURRENT_USER_STORE_CONTEXT_TOKEN } from './users/current-user/current-user.store';
import {
UmbCurrentUserHistoryStore,
UMB_CURRENT_USER_HISTORY_STORE_CONTEXT_TOKEN,
} from './users/current-user/current-user-history.store';
import { UmbStoreExtensionInitializer } from '../core/store-extension-initializer';
import {
UmbBackofficeContext,
UMB_BACKOFFICE_CONTEXT_TOKEN,
} from './shared/components/backoffice-frame/backoffice.context';
import { UmbThemeContext } from './themes/theme.context';
import {
UMB_APP_LANGUAGE_CONTEXT_TOKEN,
UmbAppLanguageContext,
} from './settings/languages/app-language-select/app-language.context';
import { UmbServerExtensionController } from './packages/repository/server-extension.controller';
import { UmbExtensionInitializer } from './packages/repository/server-extension.controller';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api';
import { UmbModalContext, UMB_MODAL_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/modal';
import { createExtensionClass, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api';
import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification';
import { UmbEntryPointExtensionInitializer } from '@umbraco-cms/backoffice/extensions-registry';
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
// Domains
import './settings';
import './documents';
import './media';
import './members';
import './translation';
import './users';
import './packages';
import './search';
import './templating';
import './shared';
const CORE_PACKAGES = [
import('./shared/umbraco-package'),
import('./settings/umbraco-package'),
import('./documents/umbraco-package'),
import('./media/umbraco-package'),
import('./members/umbraco-package'),
import('./translation/umbraco-package'),
import('./users/umbraco-package'),
import('./packages/umbraco-package'),
import('./search/umbraco-package'),
import('./templating/umbraco-package'),
];
@defineElement('umb-backoffice')
export class UmbBackofficeElement extends UmbLitElement {
@@ -58,23 +48,12 @@ export class UmbBackofficeElement extends UmbLitElement {
constructor() {
super();
new UmbEntryPointExtensionInitializer(this, umbExtensionsRegistry);
this.provideContext(UMB_MODAL_CONTEXT_TOKEN, new UmbModalContext(this));
this.provideContext(UMB_NOTIFICATION_CONTEXT_TOKEN, new UmbNotificationContext());
this.provideContext(UMB_CURRENT_USER_STORE_CONTEXT_TOKEN, new UmbCurrentUserStore());
this.provideContext(UMB_APP_LANGUAGE_CONTEXT_TOKEN, new UmbAppLanguageContext(this));
this.provideContext(UMB_BACKOFFICE_CONTEXT_TOKEN, new UmbBackofficeContext());
new UmbThemeContext(this);
new UmbServerExtensionController(this, umbExtensionsRegistry);
this.provideContext(UMB_CURRENT_USER_HISTORY_STORE_CONTEXT_TOKEN, new UmbCurrentUserHistoryStore());
// Register All Stores
// TODO: can we use kinds here so we don't have to hardcode the types?
this.observe(umbExtensionsRegistry.extensionsOfTypes(['store', 'treeStore', 'itemStore']), (stores) => {
stores.forEach((store) => createExtensionClass(store, [this]));
});
new UmbEntryPointExtensionInitializer(this, umbExtensionsRegistry);
new UmbStoreExtensionInitializer(this);
new UmbExtensionInitializer(this, umbExtensionsRegistry, CORE_PACKAGES);
}
render() {

View File

@@ -4,9 +4,7 @@ import { manifests as contentMenuManifest } from './menu.manifests';
import { manifests as documentBlueprintManifests } from './document-blueprints/manifests';
import { manifests as documentTypeManifests } from './document-types/manifests';
import { manifests as documentManifests } from './documents/manifests';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api';
import { ManifestTypes } from '@umbraco-cms/backoffice/extensions-registry';
import type { UmbEntrypointOnInit } from '@umbraco-cms/backoffice/extensions-api';
export const manifests = [
...dashboardManifests,
@@ -17,8 +15,6 @@ export const manifests = [
...documentManifests,
];
const registerExtensions = (manifests: Array<ManifestTypes>) => {
manifests.forEach((manifest) => umbExtensionsRegistry.register(manifest));
export const onInit: UmbEntrypointOnInit = (_host, extensionRegistry) => {
extensionRegistry.registerMany(manifests);
};
registerExtensions(manifests);

View File

@@ -0,0 +1,10 @@
export const name = 'Umbraco.Core.DocumentManagement';
export const version = '0.0.1';
export const extensions = [
{
name: 'Document Management Entry Point',
alias: 'Umb.EntryPoint.DocumentManagement',
type: 'entryPoint',
loader: () => import('./index'),
},
];

View File

@@ -2,14 +2,10 @@ import { manifests as mediaSectionManifests } from './section.manifests';
import { manifests as mediaMenuManifests } from './menu.manifests';
import { manifests as mediaManifests } from './media/manifests';
import { manifests as mediaTypesManifests } from './media-types/manifests';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api';
import { ManifestTypes } from '@umbraco-cms/backoffice/extensions-registry';
import type { UmbEntrypointOnInit } from '@umbraco-cms/backoffice/extensions-api';
export const manifests = [...mediaSectionManifests, ...mediaMenuManifests, ...mediaManifests, ...mediaTypesManifests];
const registerExtensions = (manifests: Array<ManifestTypes>) => {
manifests.forEach((manifest) => umbExtensionsRegistry.register(manifest));
export const onInit: UmbEntrypointOnInit = (_host, extensionRegistry) => {
extensionRegistry.registerMany(manifests);
};
registerExtensions(manifests);

View File

@@ -0,0 +1,10 @@
export const name = 'Umbraco.Core.MediaManagement';
export const version = '0.0.1';
export const extensions = [
{
name: 'Media Management Entry Point',
alias: 'Umb.EntryPoint.MediaManagement',
type: 'entryPoint',
loader: () => import('./index'),
},
];

View File

@@ -3,9 +3,7 @@ import { manifests as menuSectionManifests } from './menu.manifests';
import { manifests as memberGroupManifests } from './member-groups/manifests';
import { manifests as memberTypeManifests } from './member-types/manifests';
import { manifests as memberManifests } from './members/manifests';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api';
import { ManifestTypes } from '@umbraco-cms/backoffice/extensions-registry';
import type { UmbEntrypointOnInit } from '@umbraco-cms/backoffice/extensions-api';
export const manifests = [
...memberSectionManifests,
@@ -15,8 +13,6 @@ export const manifests = [
...memberManifests,
];
const registerExtensions = (manifests: Array<ManifestTypes>) => {
manifests.forEach((manifest) => umbExtensionsRegistry.register(manifest));
export const onInit: UmbEntrypointOnInit = (_host, extensionRegistry) => {
extensionRegistry.registerMany(manifests);
};
registerExtensions(manifests);

View File

@@ -0,0 +1,10 @@
export const name = 'Umbraco.Core.MemberManagement';
export const version = '0.0.1';
export const extensions = [
{
name: 'Member Management Entry Point',
alias: 'Umb.EntryPoint.MemberManagement',
type: 'entryPoint',
loader: () => import('./index'),
},
];

View File

@@ -2,9 +2,7 @@ import { manifests as repositoryManifests } from './repository/manifests';
import { manifests as packageBuilderManifests } from './package-builder/manifests';
import { manifests as packageRepoManifests } from './package-repo/manifests';
import { manifests as packageSectionManifests } from './package-section/manifests';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api';
import { ManifestTypes } from '@umbraco-cms/backoffice/extensions-registry';
import type { UmbEntrypointOnInit } from '@umbraco-cms/backoffice/extensions-api';
export const manifests = [
...repositoryManifests,
@@ -13,8 +11,6 @@ export const manifests = [
...packageSectionManifests,
];
const registerExtensions = (manifests: Array<ManifestTypes>) => {
manifests.forEach((manifest) => umbExtensionsRegistry.register(manifest));
export const onInit: UmbEntrypointOnInit = (_host, extensionRegistry) => {
extensionRegistry.registerMany(manifests);
};
registerExtensions(manifests);

View File

@@ -3,19 +3,28 @@ import { UmbPackageRepository } from './package.repository';
import { UmbController, UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
import { UmbExtensionRegistry } from '@umbraco-cms/backoffice/extensions-api';
export class UmbServerExtensionController extends UmbController {
export class UmbExtensionInitializer extends UmbController {
#host: UmbControllerHostElement;
#extensionRegistry: UmbExtensionRegistry;
#unobserve = new Subject<void>();
#repository: UmbPackageRepository;
#localPackages: Array<Promise<any>>;
constructor(host: UmbControllerHostElement, private readonly extensionRegistry: UmbExtensionRegistry) {
super(host, UmbServerExtensionController.name);
constructor(
host: UmbControllerHostElement,
extensionRegistry: UmbExtensionRegistry,
localPackages: Array<Promise<any>>
) {
super(host, UmbExtensionInitializer.name);
this.#host = host;
this.#extensionRegistry = extensionRegistry;
this.#repository = new UmbPackageRepository(host);
this.#localPackages = localPackages;
}
hostConnected(): void {
this.#loadPackages();
this.#loadLocalPackages();
this.#loadServerPackages();
}
hostDisconnected(): void {
@@ -23,7 +32,14 @@ export class UmbServerExtensionController extends UmbController {
this.#unobserve.complete();
}
async #loadPackages() {
async #loadLocalPackages() {
this.#localPackages.forEach(async (packageImport) => {
const packageModule = await packageImport;
this.#extensionRegistry.registerMany(packageModule.extensions);
});
}
async #loadServerPackages() {
const extensions$ = await this.#repository.extensions();
extensions$
@@ -31,10 +47,6 @@ export class UmbServerExtensionController extends UmbController {
// If the app breaks then stop the request
takeUntil(this.#unobserve)
)
.subscribe((extensions) => {
extensions.forEach((extension) => {
this.extensionRegistry.register(extension);
});
});
.subscribe((extensions) => this.#extensionRegistry.registerMany(extensions));
}
}

View File

@@ -0,0 +1,10 @@
export const name = 'Umbraco.Core.PackageManagement';
export const version = '0.0.1';
export const extensions = [
{
name: 'Package Management Entry Point',
alias: 'Umb.EntryPoint.PackageManagement',
type: 'entryPoint',
loader: () => import('./index'),
},
];

View File

@@ -1,12 +1,8 @@
import { manifests as searchManifests } from '../search/manifests';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api';
import { ManifestTypes } from '@umbraco-cms/backoffice/extensions-registry';
import type { UmbEntrypointOnInit } from '@umbraco-cms/backoffice/extensions-api';
export const manifests = [...searchManifests];
const registerExtensions = (manifests: Array<ManifestTypes>) => {
manifests.forEach((manifest) => umbExtensionsRegistry.register(manifest));
export const onInit: UmbEntrypointOnInit = (_host, extensionRegistry) => {
extensionRegistry.registerMany(manifests);
};
registerExtensions(manifests);

View File

@@ -0,0 +1,10 @@
export const name = 'Umbraco.Core.Search';
export const version = '0.0.1';
export const extensions = [
{
name: 'Search Entry Point',
alias: 'Umb.EntryPoint.Search',
type: 'entryPoint',
loader: () => import('./index'),
},
];

View File

@@ -1,3 +1,4 @@
import { UmbThemeContext } from '../themes/theme.context';
import { manifests as settingsSectionManifests } from './section.manifests';
import { manifests as settingsMenuManifests } from './menu.manifests';
import { manifests as dashboardManifests } from './dashboards/manifests';
@@ -7,11 +8,12 @@ import { manifests as extensionManifests } from './extensions/manifests';
import { manifests as cultureManifests } from './cultures/manifests';
import { manifests as languageManifests } from './languages/manifests';
import { manifests as logviewerManifests } from './logviewer/manifests';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api';
import { ManifestTypes } from '@umbraco-cms/backoffice/extensions-registry';
import './data-types/components';
import {
UmbAppLanguageContext,
UMB_APP_LANGUAGE_CONTEXT_TOKEN,
} from './languages/app-language-select/app-language.context';
import { UmbContextProviderController } from '@umbraco-cms/backoffice/context-api';
import type { UmbEntrypointOnInit } from '@umbraco-cms/backoffice/extensions-api';
export const manifests = [
...settingsSectionManifests,
@@ -25,8 +27,8 @@ export const manifests = [
...relationTypeManifests,
];
const registerExtensions = (manifests: Array<ManifestTypes>) => {
manifests.forEach((manifest) => umbExtensionsRegistry.register(manifest));
export const onInit: UmbEntrypointOnInit = (host, extensionRegistry) => {
extensionRegistry.registerMany(manifests);
new UmbContextProviderController(host, UMB_APP_LANGUAGE_CONTEXT_TOKEN, new UmbAppLanguageContext(host));
new UmbThemeContext(host);
};
registerExtensions(manifests);

View File

@@ -19,7 +19,7 @@ const menuSectionSidebarApp: ManifestSectionSidebarAppMenuKind = {
kind: 'menu',
alias: 'Umb.SectionSidebarMenu.Settings',
name: 'Settings Section Sidebar Menu',
weight: 100,
weight: 200,
meta: {
label: 'Settings',
menu: 'Umb.Menu.Settings',

View File

@@ -0,0 +1,10 @@
export const name = 'Umbraco.Core.Settings';
export const version = '0.0.1';
export const extensions = [
{
name: 'Settings Entry Point',
alias: 'Umb.EntryPoint.Settings',
type: 'entryPoint',
loader: () => import('./index'),
},
];

View File

@@ -2,9 +2,10 @@ import { manifests as componentManifests } from './components';
import { manifests as propertyActionManifests } from './property-actions/manifests';
import { manifests as propertyEditorManifests } from './property-editors/manifests';
import { manifests as modalManifests } from './modals/manifests';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api';
import { ManifestTypes } from '@umbraco-cms/backoffice/extensions-registry';
import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification';
import { UmbModalContext, UMB_MODAL_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/modal';
import { UmbContextProviderController } from '@umbraco-cms/backoffice/context-api';
import type { UmbEntrypointOnInit } from '@umbraco-cms/backoffice/extensions-api';
export const manifests = [
...componentManifests,
@@ -13,8 +14,9 @@ export const manifests = [
...modalManifests,
];
const registerExtensions = (manifests: Array<ManifestTypes>) => {
manifests.forEach((manifest) => umbExtensionsRegistry.register(manifest));
};
export const onInit: UmbEntrypointOnInit = (host, extensionRegistry) => {
extensionRegistry.registerMany(manifests);
registerExtensions(manifests);
new UmbContextProviderController(host, UMB_MODAL_CONTEXT_TOKEN, new UmbModalContext(host));
new UmbContextProviderController(host, UMB_NOTIFICATION_CONTEXT_TOKEN, new UmbNotificationContext());
};

View File

@@ -0,0 +1,10 @@
export const name = 'Umbraco.Core';
export const version = '0.0.1';
export const extensions = [
{
name: 'Core Entry Point',
alias: 'Umb.EntryPoint.Core',
type: 'entryPoint',
loader: () => import('./index'),
},
];

View File

@@ -1,15 +1,12 @@
import { manifests as menuManifests } from './menu.manifests';
import { manifests as templateManifests } from './templates/manifests';
import { manifests as stylesheetManifests } from './stylesheets/manifests';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api';
import { ManifestTypes } from '@umbraco-cms/backoffice/extensions-registry';
import type { UmbEntrypointOnInit } from '@umbraco-cms/backoffice/extensions-api';
import './components';
export const manifests = [...menuManifests, ...templateManifests, ...stylesheetManifests];
const registerExtensions = (manifests: Array<ManifestTypes>) => {
manifests.forEach((manifest) => umbExtensionsRegistry.register(manifest));
export const onInit: UmbEntrypointOnInit = (_host, extensionRegistry) => {
extensionRegistry.registerMany(manifests);
};
registerExtensions(manifests);

View File

@@ -0,0 +1,10 @@
export const name = 'Umbraco.Core.Templating';
export const version = '0.0.1';
export const extensions = [
{
name: 'Templating Entry Point',
alias: 'Umb.EntryPoint.Templating',
type: 'entryPoint',
loader: () => import('./index'),
},
];

View File

@@ -1,12 +1,9 @@
import { manifests as translationSectionManifests } from './section.manifest';
import { manifests as dictionaryManifests } from './dictionary/manifests';
import type { ManifestTypes } from '@umbraco-cms/backoffice/extensions-registry';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api';
import { UmbEntrypointOnInit } from '@umbraco-cms/backoffice/extensions-api';
export const manifests = [...translationSectionManifests, ...dictionaryManifests];
const registerExtensions = (manifests: Array<ManifestTypes>) => {
manifests.forEach((manifest) => umbExtensionsRegistry.register(manifest));
export const onInit: UmbEntrypointOnInit = (_host, extensionRegistry) => {
extensionRegistry.registerMany(manifests);
};
registerExtensions(manifests);

View File

@@ -0,0 +1,10 @@
export const name = 'Umbraco.Core.TranslationManagement';
export const version = '0.0.1';
export const extensions = [
{
name: 'Translation Entry Point',
alias: 'Umb.EntryPoint.Translation',
type: 'entryPoint',
loader: () => import('./index'),
},
];

View File

@@ -3,13 +3,23 @@ import { manifests as userManifests } from './users/manifests';
import { manifests as userSectionManifests } from './user-section/manifests';
import { manifests as currentUserManifests } from './current-user/manifests';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api';
import { ManifestTypes } from '@umbraco-cms/backoffice/extensions-registry';
import { UmbCurrentUserStore, UMB_CURRENT_USER_STORE_CONTEXT_TOKEN } from './current-user/current-user.store';
import {
UmbCurrentUserHistoryStore,
UMB_CURRENT_USER_HISTORY_STORE_CONTEXT_TOKEN,
} from './current-user/current-user-history.store';
import { UmbEntrypointOnInit } from '@umbraco-cms/backoffice/extensions-api';
import { UmbContextProviderController } from '@umbraco-cms/backoffice/context-api';
export const manifests = [...userGroupManifests, ...userManifests, ...userSectionManifests, ...currentUserManifests];
const registerExtensions = (manifests: Array<ManifestTypes>) => {
manifests.forEach((manifest) => umbExtensionsRegistry.register(manifest));
};
export const onInit: UmbEntrypointOnInit = (host, extensionRegistry) => {
extensionRegistry.registerMany(manifests);
registerExtensions(manifests);
new UmbContextProviderController(host, UMB_CURRENT_USER_STORE_CONTEXT_TOKEN, new UmbCurrentUserStore());
new UmbContextProviderController(
host,
UMB_CURRENT_USER_HISTORY_STORE_CONTEXT_TOKEN,
new UmbCurrentUserHistoryStore()
);
};

View File

@@ -0,0 +1,10 @@
export const name = 'Umbraco.Core.UserManagement';
export const version = '0.0.1';
export const extensions = [
{
name: 'User Management Entry Point',
alias: 'Umb.EntryPoint.UserManagement',
type: 'entryPoint',
loader: () => import('./index'),
},
];

View File

@@ -42,7 +42,7 @@ export const manifestDevelopmentHandler = rest.get(umbracoPath('/package/manifes
{
extensions: [
{
type: 'entrypoint',
type: 'entryPoint',
name: 'My Custom Entry Point',
alias: 'My.Entrypoint.Custom',
js: '/App_Plugins/custom-entrypoint.js',

View File

@@ -0,0 +1,27 @@
import { createExtensionClass, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
import { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
export class UmbStoreExtensionInitializer {
public host: UmbControllerHostElement;
#storeMap = new Map();
constructor(host: UmbControllerHostElement) {
this.host = host;
new UmbObserverController(
this.host,
umbExtensionsRegistry.extensionsOfTypes(['store', 'treeStore', 'itemStore']),
(stores) => {
if (!stores) return;
stores.forEach((store) => {
if (this.#storeMap.has(store.alias)) return;
// Instantiate and provide stores. Stores are self providing when the class is instantiated.
this.#storeMap.set(store.alias, createExtensionClass(store, [this.host]));
});
}
);
}
}