Merge pull request #1897 from umbraco/feature/extendable-section-routes

Feature: Extendable section routes
This commit is contained in:
Mads Rasmussen
2024-05-26 11:12:45 +02:00
committed by GitHub
9 changed files with 111 additions and 20 deletions

View File

@@ -69,6 +69,7 @@ import type { ManifestAppEntryPoint } from './app-entry-point.model.js';
import type { ManifestBackofficeEntryPoint } from './backoffice-entry-point.model.js';
import type { ManifestEntryPoint } from './entry-point.model.js';
import type { ManifestMonacoMarkdownEditorAction } from './monaco-markdown-editor-action.model.js';
import type { ManifestSectionRoute } from './section-route.model.js';
import type { ManifestBase, ManifestBundle, ManifestCondition } from '@umbraco-cms/backoffice/extension-api';
export type * from './app-entry-point.model.js';
@@ -196,6 +197,7 @@ export type ManifestTypes =
| ManifestSectionSidebarApp
| ManifestSectionSidebarAppMenuKind
| ManifestSectionView
| ManifestSectionRoute
| ManifestStore
| ManifestTheme
| ManifestTinyMcePlugin

View File

@@ -0,0 +1,12 @@
import type { UmbRouteEntry } from '../../router/types.js';
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
import type { ManifestElementAndApi } from '@umbraco-cms/backoffice/extension-api';
export interface ManifestSectionRoute extends ManifestElementAndApi<UmbControllerHostElement, UmbRouteEntry> {
type: 'sectionRoute';
meta: MetaSectionRoute;
}
export interface MetaSectionRoute {
path?: string;
}

View File

@@ -8,3 +8,4 @@ export * from './router-slot.element.js';
export * from './path-pattern.class.js';
export * from './modal-registration/modal-route-registration.interface.js';
export * from './modal-registration/modal-route-registration.controller.js';
export * from './types.js';

View File

@@ -0,0 +1,7 @@
import type { IRoutingInfo, PageComponent } from '@umbraco-cms/backoffice/external/router-slot';
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
export interface UmbRouteEntry extends UmbApi {
getPath?(): string;
setup?(element: PageComponent, info: IRoutingInfo): void;
}

View File

@@ -1,4 +1,4 @@
import type { UmbWorkspaceElement } from '../workspace/workspace.element.js';
import type { ManifestSectionRoute } from '../extension-registry/models/section-route.model.js';
import type { UmbSectionMainViewElement } from './section-main-views/section-main-views.element.js';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, nothing, customElement, property, state, repeat } from '@umbraco-cms/backoffice/external/lit';
@@ -9,11 +9,14 @@ import type {
UmbSectionElement,
} from '@umbraco-cms/backoffice/extension-registry';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import type { UmbRoute } from '@umbraco-cms/backoffice/router';
import type { IRoute, IRoutingInfo, PageComponent, UmbRoute } from '@umbraco-cms/backoffice/router';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbExtensionElementInitializer } from '@umbraco-cms/backoffice/extension-api';
import { UmbExtensionsElementInitializer } from '@umbraco-cms/backoffice/extension-api';
import { UMB_WORKSPACE_PATH_PATTERN } from '@umbraco-cms/backoffice/workspace';
import {
UmbExtensionsElementAndApiInitializer,
UmbExtensionsElementInitializer,
} from '@umbraco-cms/backoffice/extension-api';
import { aliasToPath, debounce } from '@umbraco-cms/backoffice/utils';
/**
* @export
@@ -47,6 +50,10 @@ export class UmbSectionDefaultElement extends UmbLitElement implements UmbSectio
@state()
_splitPanelPosition = '300px';
#routeExtensionsController:
| UmbExtensionsElementAndApiInitializer<ManifestSectionRoute, 'sectionRoute', ManifestSectionRoute>
| undefined;
constructor() {
super();
@@ -56,7 +63,7 @@ export class UmbSectionDefaultElement extends UmbLitElement implements UmbSectio
this.requestUpdate('_sidebarApps', oldValue);
});
this.#createRoutes();
this.#observeRoutes();
const splitPanelPosition = localStorage.getItem('umb-split-panel-position');
if (splitPanelPosition) {
@@ -64,15 +71,44 @@ export class UmbSectionDefaultElement extends UmbLitElement implements UmbSectio
}
}
#createRoutes() {
this._routes = [
{
path: UMB_WORKSPACE_PATH_PATTERN.toString(),
component: () => import('../workspace/workspace.element.js'),
setup: (element, info) => {
(element as UmbWorkspaceElement).entityType = info.match.params.entityType;
},
#observeRoutes(): void {
this.#routeExtensionsController?.destroy();
this.#routeExtensionsController = new UmbExtensionsElementAndApiInitializer<
ManifestSectionRoute,
'sectionRoute',
ManifestSectionRoute
>(
this,
umbExtensionsRegistry,
'sectionRoute',
undefined,
undefined,
(sectionRouteExtensions) => {
const routes: Array<IRoute> = sectionRouteExtensions.map((extensionController) => {
return {
path:
extensionController.api?.getPath?.() ||
extensionController.manifest.meta?.path ||
aliasToPath(extensionController.manifest.alias),
component: extensionController.component,
setup: (element: PageComponent, info: IRoutingInfo) => {
extensionController.api?.setup?.(element, info);
},
};
});
this.#debouncedCreateRoutes(routes);
},
undefined, // We can leave the alias to undefined, as we destroy this our selfs.
);
}
#debouncedCreateRoutes = debounce(this.#createRoutes, 50);
#createRoutes(routes: Array<IRoute>) {
this._routes = [
...routes,
{
path: '**',
component: () => import('./section-main-views/section-main-views.element.js'),

View File

@@ -1 +1,3 @@
export const encodeFilePath = (path: string) => encodeURIComponent(path).replace('.', '-');
export const encodeFilePath = (path: string) => encodeURIComponent(path).replaceAll('.', '-');
export const aliasToPath = (path: string) => encodeFilePath(path);

View File

@@ -1,12 +1,14 @@
import { manifests as componentManifests } from './components/manifests.js';
import { manifests as workspaceKinds } from './kinds/manifests.js';
import { manifests as workspaceModals } from './modals/manifests.js';
import { manifests as workspaceConditions } from './conditions/manifests.js';
import { manifests as sectionRouteManifests } from './section-routes/manifests.js';
import { manifests as workspaceConditionManifests } from './conditions/manifests.js';
import { manifests as workspaceKindManifest } from './kinds/manifests.js';
import { manifests as workspaceModalManifest } from './modals/manifests.js';
import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry';
export const manifests: Array<ManifestTypes | UmbBackofficeManifestKind> = [
...workspaceConditions,
...workspaceKinds,
...componentManifests,
...workspaceModals,
...sectionRouteManifests,
...workspaceConditionManifests,
...workspaceKindManifest,
...workspaceModalManifest,
];

View File

@@ -0,0 +1,11 @@
import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
export const manifests: Array<ManifestTypes> = [
{
type: 'sectionRoute',
alias: 'Umb.SectionRoute.Workspace',
name: 'Workspace Section Route',
element: () => import('../workspace.element.js'),
api: () => import('./workspace-section-route.route-entry.js'),
},
];

View File

@@ -0,0 +1,18 @@
import { UMB_WORKSPACE_PATH_PATTERN } from '../paths.js';
import type { UmbWorkspaceElement } from '../workspace.element.js';
import type { IRoutingInfo, PageComponent, UmbRouteEntry } from '@umbraco-cms/backoffice/router';
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
export class UmbWorkspaceSectionRouteEntry implements UmbApi, UmbRouteEntry {
getPath(): string {
return UMB_WORKSPACE_PATH_PATTERN.toString();
}
setup(element: PageComponent, info: IRoutingInfo) {
(element as UmbWorkspaceElement).entityType = info.match.params.entityType;
}
destroy(): void {}
}
export { UmbWorkspaceSectionRouteEntry as api };