Merge branch 'v14/feature/router-404' into v14/bugfix/hide-content-workspace-view-when-no-properties

This commit is contained in:
Mads Rasmussen
2024-07-02 09:12:40 +02:00
63 changed files with 306 additions and 246 deletions

View File

@@ -2,7 +2,7 @@ import type { UmbBackofficeContext } from '../backoffice.context.js';
import { UMB_BACKOFFICE_CONTEXT } from '../backoffice.context.js';
import { css, html, customElement, state, nothing } from '@umbraco-cms/backoffice/external/lit';
import { UmbSectionContext, UMB_SECTION_CONTEXT, UMB_SECTION_PATH_PATTERN } from '@umbraco-cms/backoffice/section';
import type { UmbRoute, UmbRouterSlotChangeEvent } from '@umbraco-cms/backoffice/router';
import type { PageComponent, UmbRoute, UmbRouterSlotChangeEvent } from '@umbraco-cms/backoffice/router';
import type { ManifestSection, UmbSectionElement } from '@umbraco-cms/backoffice/extension-registry';
import type { UmbExtensionManifestInitializer } from '@umbraco-cms/backoffice/extension-api';
import { createExtensionElement } from '@umbraco-cms/backoffice/extension-api';
@@ -11,7 +11,7 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
@customElement('umb-backoffice-main')
export class UmbBackofficeMainElement extends UmbLitElement {
@state()
private _routes: Array<UmbRoute & { alias: string }> = [];
private _routes: Array<UmbRoute> = [];
@state()
private _sections: Array<UmbExtensionManifestInitializer<ManifestSection>> = [];
@@ -43,28 +43,39 @@ export class UmbBackofficeMainElement extends UmbLitElement {
private _createRoutes() {
if (!this._sections) return;
const oldValue = this._routes;
// TODO: Refactor this for re-use across the app where the routes are re-generated at any time.
this._routes = this._sections
const newRoutes = this._sections
.filter((x) => x.manifest)
.map((section) => {
const existingRoute = this._routes.find((r) => r.alias === section.alias);
const existingRoute = this._routes.find((r) => r.path === UMB_SECTION_PATH_PATTERN.generateLocal({ sectionName: section.manifest!.meta.pathname }));
if (existingRoute) {
return existingRoute;
} else {
return {
alias: section.alias,
//alias: section.alias,
path: UMB_SECTION_PATH_PATTERN.generateLocal({ sectionName: section.manifest!.meta.pathname }),
component: () => createExtensionElement(section.manifest!, 'umb-section-default'),
setup: (component) => {
(component as UmbSectionElement).manifest = section.manifest as ManifestSection;
setup: (component: PageComponent) => {
(component as UmbSectionElement).manifest = section.manifest;
},
};
}
});
this.requestUpdate('_routes', oldValue);
if(newRoutes.length > 0 ) {
newRoutes.push({
path: ``,
redirectTo: newRoutes[0].path
});
}
newRoutes.push({
path: `**`,
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
});
this._routes = newRoutes;
}
private _onRouteChange = async (event: UmbRouterSlotChangeEvent) => {

View File

@@ -2524,4 +2524,8 @@ export default {
detailedLevelDescription:
'\n We will send:\n <ul>\n <li>Anonymized site ID, Umbraco version, and packages installed.</li>\n <li>Number of: Root nodes, Content nodes, Media, Document Types, Templates, Languages, Domains, User Group, Users, Members, Backoffice external login providers, and Property Editors in use.</li>\n <li>System information: Webserver, server OS, server framework, server OS language, and database provider.</li>\n <li>Configuration settings: Modelsbuilder mode, if custom Umbraco path exists, ASP environment, whether the delivery API is enabled, and allows public access, and if you are in debug mode.</li>\n </ul>\n <em>We might change what we send on the Detailed level in the future. If so, it will be listed above.\n <br>By choosing "Detailed" you agree to current and future anonymized information being collected.</em>\n ',
},
routing: {
routeNotFoundTitle: 'Not found',
routeNotFoundDescription: 'The requested route could not be found. Please check the URL and try again.'
}
} as UmbLocalizationDictionary;

View File

@@ -45,6 +45,11 @@ ensureAnchorHistory();
* @event changestate - Dispatched when the router slot state changes.
*/
export class RouterSlot<D = any, P = any> extends HTMLElement implements IRouterSlot<D, P> {
/**
* Method to cancel navigation if changed.
*/
private _cancelNavigation ?:() => void;
/**
* Listeners on the router.
*/
@@ -197,8 +202,17 @@ export class RouterSlot<D = any, P = any> extends HTMLElement implements IRouter
this._routes.push(...routes);
if (navigate === undefined) {
// If navigate is not determined, then we will check if we have a route match. If not then we will re-render.
// If navigate is not determined, then we will check if we have a route match. If not then we will re-render. [NL]
navigate = this._routeMatch === null;
if (navigate === false) {
if (this.isConnected) {
const newMatch = this.getRouteMatch();
// Check if this match matches the current match (aka. If the path has changed), if so we should navigate. [NL]
if(newMatch) {
navigate = shouldNavigate(this.match, newMatch);
}
}
}
}
// Navigate fallback:
@@ -232,13 +246,21 @@ export class RouterSlot<D = any, P = any> extends HTMLElement implements IRouter
// Either choose the parent fragment or the current path if no parent exists.
// The root router slot will always use the entire path.
const pathFragment =
this.parent != null && this.parent.fragments != null ? this.parent.fragments.rest : pathWithoutBasePath();
const pathFragment = this.getPathFragment();
// Route to the path
await this.renderPath(pathFragment);
}
protected getPathFragment() {
return this.parent != null && this.parent.fragments != null ? this.parent.fragments.rest : pathWithoutBasePath();
}
protected getRouteMatch() {
// Find the corresponding route.
return matchRoutes(this._routes, this.getPathFragment());
}
/**
* Attaches listeners, either globally or on the parent router.
*/
@@ -296,6 +318,8 @@ export class RouterSlot<D = any, P = any> extends HTMLElement implements IRouter
* Returns true if a navigation was made to a new page.
*/
protected async renderPath(path: string | PathFragment): Promise<boolean> {
// Notice: Since this is never called from any other place than one higher in this file(when writing this...), we could just retrieve the path and find a match by using this.getRouteMatch() [NL]
// Find the corresponding route.
const match = matchRoutes(this._routes, path);
@@ -312,10 +336,17 @@ export class RouterSlot<D = any, P = any> extends HTMLElement implements IRouter
// Only change route if its a new route.
const navigate = shouldNavigate(this.match, match);
if (navigate) {
// If another navigation is still begin resolved in this very moment, then we need to cancel that so it does not end up overriding this new navigation.[NL]
this._cancelNavigation?.();
// Listen for another push state event. If another push state event happens
// while we are about to navigate we have to cancel.
let navigationInvalidated = false;
const cancelNavigation = () => (navigationInvalidated = true);
const cancelNavigation = () => {
navigationInvalidated = true;
this._cancelNavigation = undefined;
};
this._cancelNavigation = cancelNavigation;
const removeChangeListener: EventListenerSubscription = addListener<Event, GlobalRouterEvent>(
GLOBAL_ROUTER_EVENTS_TARGET,
'changestate',
@@ -378,16 +409,23 @@ export class RouterSlot<D = any, P = any> extends HTMLElement implements IRouter
return cancel();
}
// Remove the old page by clearing the slot
this.clearChildren();
// We have some routes that share the same component instance, those should not be removed and re-appended [NL]
const isTheSameComponent = this.firstChild === page;
if(!isTheSameComponent) {
// Remove the old page by clearing the slot
this.clearChildren();
}
// Store the new route match before we append the new page to the DOM.
// We do this to ensure that we can find the match in the connectedCallback of the page.
this._routeMatch = match;
if (page) {
// Append the new page
this.appendChild(page);
if(!isTheSameComponent) {
if (page) {
// Append the new page
this.appendChild(page);
}
}
}

View File

@@ -211,6 +211,8 @@ export abstract class UmbBaseExtensionInitializer<
// Check if we already have a controller for this config:
const existing = this.#conditionControllers.find((controller) => controller.config === conditionConfig);
if (!existing) {
// TODO: Be aware that we might not have a host element any longer at this moment, but I did not want to make a fix for it jet, as its a good indication to if something else is terrible wrong [NL]
const conditionController = await createExtensionApi(this, conditionManifest, [
{
manifest: conditionManifest,

View File

@@ -5,12 +5,13 @@ export type ObserverCallback<T> = (value: T) => void;
export class UmbObserver<T> {
#source!: Observable<T>;
#callback!: ObserverCallback<T>;
#callback?: ObserverCallback<T>;
#subscription!: Subscription;
constructor(source: Observable<T>, callback?: ObserverCallback<T>) {
this.#source = source;
if (callback) {
this.#callback = callback;
this.#subscription = source.subscribe(callback);
}
}
@@ -44,7 +45,7 @@ export class UmbObserver<T> {
hostConnected() {
// Notice: This will not re-subscribe if this controller was destroyed. Only if the subscription was closed.
if (this.#subscription?.closed) {
if (this.#subscription?.closed && this.#callback) {
this.#subscription = this.#source.subscribe(this.#callback);
}
}

View File

@@ -1,7 +1,7 @@
import { UmbBlockGridAreaConfigEntryContext } from './block-grid-area-config-entry.context.js';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { html, css, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import { UmbBlockGridAreaConfigEntryContext } from './block-grid-area-config-entry.context.js';
import '../block-grid-block/index.js';
import '../block-scale-handler/index.js';

View File

@@ -1,4 +1,3 @@
import type { UmbBlockGridTypeAreaType } from '../../../types.js';
import type { UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property';
import { UMB_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/property';
import type {
@@ -14,6 +13,7 @@ import { UmbArrayState, UmbObjectState, appendToFrozenArray } from '@umbraco-cms
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import type { ManifestWorkspace, PropertyEditorSettingsProperty } from '@umbraco-cms/backoffice/extension-registry';
import type { UmbBlockGridTypeAreaType } from '../../../types.js';
export class UmbBlockGridAreaTypeWorkspaceContext
extends UmbSubmittableWorkspaceContextBase<UmbBlockGridTypeAreaType>

View File

@@ -1,7 +1,7 @@
import { UMB_BLOCK_GRID_MANAGER_CONTEXT } from '../../context/block-grid-manager.context-token.js';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UMB_BLOCK_GRID_ENTRY_CONTEXT, type UmbBlockGridTypeAreaType } from '@umbraco-cms/backoffice/block-grid';
import { css, customElement, html, repeat, state } from '@umbraco-cms/backoffice/external/lit';
import { UMB_BLOCK_GRID_MANAGER_CONTEXT } from '../../context/block-grid-manager.context-token.js';
import { UMB_BLOCK_GRID_ENTRY_CONTEXT, type UmbBlockGridTypeAreaType } from '@umbraco-cms/backoffice/block-grid';
import '../block-grid-entries/index.js';
/**

View File

@@ -1,13 +1,4 @@
import { closestColumnSpanOption } from '../utils/index.js';
import { UMB_BLOCK_GRID_MANAGER_CONTEXT } from './block-grid-manager.context-token.js';
import { UMB_BLOCK_GRID_ENTRIES_CONTEXT } from './block-grid-entries.context-token.js';
import {
type UmbBlockGridScalableContext,
UmbBlockGridScaleManager,
} from './block-grid-scale-manager/block-grid-scale-manager.controller.js';
import { UmbBlockEntryContext } from '@umbraco-cms/backoffice/block';
import type { UmbContentTypeModel, UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type';
import type { UmbBlockGridTypeModel, UmbBlockGridLayoutModel } from '@umbraco-cms/backoffice/block-grid';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import {
UmbArrayState,
@@ -17,6 +8,15 @@ import {
appendToFrozenArray,
observeMultiple,
} from '@umbraco-cms/backoffice/observable-api';
import { closestColumnSpanOption } from '../utils/index.js';
import { UMB_BLOCK_GRID_MANAGER_CONTEXT } from './block-grid-manager.context-token.js';
import { UMB_BLOCK_GRID_ENTRIES_CONTEXT } from './block-grid-entries.context-token.js';
import {
type UmbBlockGridScalableContext,
UmbBlockGridScaleManager,
} from './block-grid-scale-manager/block-grid-scale-manager.controller.js';
import { UmbBlockEntryContext } from '@umbraco-cms/backoffice/block';
import type { UmbBlockGridTypeModel, UmbBlockGridLayoutModel } from '@umbraco-cms/backoffice/block-grid';
export class UmbBlockGridEntryContext
extends UmbBlockEntryContext<

View File

@@ -1,7 +1,7 @@
import { closestColumnSpanOption } from '../../utils/index.js';
import { getAccumulatedValueOfIndex, getInterpolatedIndexOfPositionInWeightMap } from '@umbraco-cms/backoffice/utils';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { closestColumnSpanOption } from '../../utils/index.js';
// This might be more generic than Block Grid, but this is where it belongs currently:
export interface UmbBlockGridScalableContext extends UmbControllerHost {

View File

@@ -1,7 +1,3 @@
import type { UmbBlockGridTypeAreaType } from '../../index.js';
import { UMB_BLOCK_GRID_DEFAULT_LAYOUT_STYLESHEET } from '../../context/block-grid-manager.context.js';
import { UMB_BLOCK_GRID_AREA_TYPE_WORKSPACE_MODAL } from '../../components/block-grid-area-config-entry/index.js';
import { UmbBlockGridAreaTypeEntriesContext } from './block-grid-area-type-entries.context.js';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { html, customElement, property, state, repeat } from '@umbraco-cms/backoffice/external/lit';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
@@ -13,6 +9,10 @@ import {
import { UmbId } from '@umbraco-cms/backoffice/id';
import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router';
import { incrementString } from '@umbraco-cms/backoffice/utils';
import { UMB_BLOCK_GRID_AREA_TYPE_WORKSPACE_MODAL } from '../../components/block-grid-area-config-entry/index.js';
import { UMB_BLOCK_GRID_DEFAULT_LAYOUT_STYLESHEET } from '../../context/block-grid-manager.context.js';
import type { UmbBlockGridTypeAreaType } from '../../index.js';
import { UmbBlockGridAreaTypeEntriesContext } from './block-grid-area-type-entries.context.js';
@customElement('umb-property-editor-ui-block-grid-areas-config')
export class UmbPropertyEditorUIBlockGridAreasConfigElement
@@ -127,7 +127,6 @@ export class UmbPropertyEditorUIBlockGridAreasConfigElement
//TODO: open area edit workspace
}
// TODO: Needs localizations:
override render() {
return this._areaGridColumns
? html`${this._styleElement}

View File

@@ -1,6 +1,6 @@
import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
import { manifests as workspaceViewManifests } from './views/manifests.js';
import { UMB_BLOCK_GRID_TYPE_WORKSPACE_ALIAS } from './index.js';
import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
export const manifests: Array<ManifestTypes> = [
...workspaceViewManifests,

View File

@@ -1,5 +1,5 @@
import { UMB_BLOCK_GRID_TYPE_WORKSPACE_ALIAS } from '../index.js';
import type { ManifestTypes, ManifestWorkspaceView } from '@umbraco-cms/backoffice/extension-registry';
import { UMB_BLOCK_GRID_TYPE_WORKSPACE_ALIAS } from '../index.js';
export const workspaceViews: Array<ManifestWorkspaceView> = [
{
@@ -53,7 +53,7 @@ export const workspaceViews: Array<ManifestWorkspaceView> = [
{
alias: 'Umb.Condition.WorkspaceAlias',
match: UMB_BLOCK_GRID_TYPE_WORKSPACE_ALIAS,
},
}
],
},
];

View File

@@ -1,10 +1,10 @@
import { UMB_BLOCK_TYPE_WORKSPACE_CONTEXT } from './block-type-workspace.context-token.js';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { customElement, css, html, state, property } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbRepositoryItemsManager } from '@umbraco-cms/backoffice/repository';
import type { UmbDocumentTypeItemModel } from '@umbraco-cms/backoffice/document-type';
import { UMB_DOCUMENT_TYPE_ITEM_REPOSITORY_ALIAS } from '@umbraco-cms/backoffice/document-type';
import { UMB_BLOCK_TYPE_WORKSPACE_CONTEXT } from './block-type-workspace.context-token.js';
@customElement('umb-block-type-workspace-editor')
export class UmbBlockTypeWorkspaceEditorElement extends UmbLitElement {

View File

@@ -1,5 +1,3 @@
import type { UmbBlockTypeBaseModel, UmbBlockTypeWithGroupKey } from '../types.js';
import { UmbBlockTypeWorkspaceEditorElement } from './block-type-workspace-editor.element.js';
import type { UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property';
import { UMB_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/property';
import type {
@@ -14,6 +12,8 @@ import {
import { UmbArrayState, UmbObjectState, appendToFrozenArray } from '@umbraco-cms/backoffice/observable-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import type { ManifestWorkspace, PropertyEditorSettingsProperty } from '@umbraco-cms/backoffice/extension-registry';
import type { UmbBlockTypeBaseModel, UmbBlockTypeWithGroupKey } from '../types.js';
import { UmbBlockTypeWorkspaceEditorElement } from './block-type-workspace-editor.element.js';
export class UmbBlockTypeWorkspaceContext<BlockTypeData extends UmbBlockTypeWithGroupKey = UmbBlockTypeWithGroupKey>
extends UmbSubmittableWorkspaceContextBase<BlockTypeData>
@@ -27,7 +27,7 @@ export class UmbBlockTypeWorkspaceContext<BlockTypeData extends UmbBlockTypeWith
//readonly data = this.#data.asObservable();
// TODO: Get the name of the contentElementType..
readonly name = this.#data.asObservablePart((data) => 'block');
readonly name = this.#data.asObservablePart(() => 'block');
readonly unique = this.#data.asObservablePart((data) => data?.contentElementTypeKey);
#properties = new UmbArrayState<PropertyEditorSettingsProperty>([], (x) => x.alias);

View File

@@ -24,7 +24,7 @@ export const manifests: Array<ManifestTypes> = [
{
type: 'workspace',
kind: 'routable',
name: 'Block List Type Workspace',
name: 'Block Workspace',
alias: UMB_BLOCK_WORKSPACE_ALIAS,
api: () => import('./block-workspace.context.js'),
meta: {
@@ -61,7 +61,7 @@ export const manifests: Array<ManifestTypes> = [
alias: 'Umb.WorkspaceView.Block.Settings',
name: 'Block Workspace Settings View',
js: () => import('./views/edit/block-workspace-view-edit.element.js'),
weight: 1000,
weight: 900,
meta: {
label: '#general_settings',
pathname: 'settings',
@@ -75,7 +75,7 @@ export const manifests: Array<ManifestTypes> = [
},
{
alias: 'Umb.Condition.BlockWorkspaceHasSettings',
},
}
],
} as any,
];

View File

@@ -116,6 +116,10 @@ export class UmbBlockWorkspaceViewEditElement extends UmbLitElement implements U
path: '',
redirectTo: routes[0]?.path,
});
routes.push({
path: `**`,
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
});
}
this._routes = routes;

View File

@@ -98,6 +98,11 @@ export class UmbCollectionViewManager extends UmbControllerBase {
});
}
routes.push({
path: `**`,
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
});
this.#routes.setValue(routes);
}
}

View File

@@ -226,6 +226,11 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements
}
}
routes.push({
path: `**`,
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
});
this._routes = routes;
}

View File

@@ -108,11 +108,10 @@ export class UmbContentWorkspaceViewEditElement extends UmbLitElement implements
});
}
// Find the routes who are removed:
//const removedRoutes = this._routes.filter((route) => !routes.find((r) => r.path === route.path));
// Find the routes who are new:
//const newRoutes = routes.filter((route) => !this._routes.find((r) => r.path === route.path));
routes.push({
path: `**`,
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
});
this._routes = routes;
}

View File

@@ -1,5 +1,3 @@
import { UMB_PROPERTY_DATASET_CONTEXT } from '../property-dataset/index.js';
import type { UmbVariantId } from '@umbraco-cms/backoffice/variant';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import {
@@ -11,6 +9,8 @@ import {
UmbStringState,
} from '@umbraco-cms/backoffice/observable-api';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { UMB_PROPERTY_DATASET_CONTEXT } from '../property-dataset/index.js';
import type { UmbVariantId } from '@umbraco-cms/backoffice/variant';
import type { UmbPropertyEditorConfigProperty } from '@umbraco-cms/backoffice/property-editor';
import { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';

View File

@@ -0,0 +1,56 @@
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, customElement } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
/**
* A fallback view to be used in Workspace Views, maybe this can be upgraded at a later point.
*/
// TODO: Rename and move this file to a more generic place.
@customElement('umb-route-not-found')
export class UmbRouteNotFoundElement extends UmbLitElement {
override render() {
return html`
<div class="uui-text">
<h4><umb-localize key="routing_routeNotFoundTitle"></umb-localize></h4>
<umb-localize key="routing_routeNotFoundDescription"></umb-localize>
</div>
`;
}
static override styles = [
UmbTextStyles,
css`
:host {
display: block;
width: 100%;
height: 100%;
min-width: 0;
}
:host > div {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100%;
opacity: 0;
animation: fadeIn 4s .2s forwards;
}
@keyframes fadeIn {
100% {
opacity: 100%;
}
}
`,
];
}
export default UmbRouteNotFoundElement;
declare global {
interface HTMLElementTagNameMap {
'umb-route-not-found': UmbRouteNotFoundElement;
}
}

View File

@@ -9,3 +9,4 @@ 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';
export * from './components/not-found/route-not-found.element.js';

View File

@@ -28,7 +28,8 @@ export class UmbRouterSlotElement extends UmbLitElement {
value ??= [];
const oldValue = this.#router.routes;
if (
value.filter((route) => (oldValue ? oldValue.findIndex((r) => r.path === route.path) === -1 : true)).length > 0
value.length !== oldValue?.length ||
value.filter((route) => (oldValue?.findIndex((r) => r.path === route.path) === -1)).length > 0
) {
this.#router.routes = value;
}

View File

@@ -13,12 +13,12 @@ import type { IRoute, IRoutingInfo, PageComponent, UmbRoute } from '@umbraco-cms
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbExtensionElementInitializer } from '@umbraco-cms/backoffice/extension-api';
import {
UmbExtensionsApiInitializer,
UmbExtensionsElementInitializer,
UmbExtensionsManifestInitializer,
createExtensionApi,
createExtensionElement,
} from '@umbraco-cms/backoffice/extension-api';
import { aliasToPath, debounce } from '@umbraco-cms/backoffice/utils';
import { aliasToPath } from '@umbraco-cms/backoffice/utils';
/**
* @export
@@ -86,15 +86,12 @@ export class UmbSectionDefaultElement extends UmbLitElement implements UmbSectio
const api = await createExtensionApi(this, extensionController.manifest);
return {
path:
path: (
api?.getPath?.() ||
extensionController.manifest.meta?.path ||
aliasToPath(extensionController.manifest.alias),
// TODO: look into removing the "as PageComponent" type hack
// be aware that this is kind of a hack to pass the manifest element to the router. But as the two resolve components
// in a similar way. I currently find it more safe to let the router do the component resolving instead
// of replicating it as a custom resolver here.
component: extensionController.manifest.element as PageComponent | PromiseLike<PageComponent>,
aliasToPath(extensionController.manifest.alias)
),
component: () => createExtensionElement(extensionController.manifest),
setup: (element: PageComponent, info: IRoutingInfo) => {
api?.setup?.(element, info);
},
@@ -102,14 +99,12 @@ export class UmbSectionDefaultElement extends UmbLitElement implements UmbSectio
}),
);
this.#debouncedCreateRoutes(routes);
this.#createRoutes(routes);
},
'umbRouteExtensionApisInitializer',
);
}
#debouncedCreateRoutes = debounce(this.#createRoutes, 50);
#createRoutes(routes: Array<IRoute>) {
this._routes = [
...routes,

View File

@@ -71,17 +71,18 @@ export class UmbWorkspaceEditorElement extends UmbLitElement {
} as UmbRoute;
});
// If we have a post fix then we need to add a direct from the empty url of the split-view-index:
// TODO: This is problematic, cause if a workspaceView appears later, then this takes over. And it is also a problem if it does not use redirect, but just a view defined with and empty path.
const firstRoute = newRoutes[0];
if (firstRoute) {
newRoutes.push({
path: ``,
redirectTo: firstRoute.path,
});
}
newRoutes.push({
path: '',
redirectTo: newRoutes[0]?.path,
});
}
newRoutes.push({
path: `**`,
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
});
this._routes = newRoutes;
}

View File

@@ -1,17 +1,17 @@
import type { ActiveVariant } from '../../controllers/index.js';
import { UMB_WORKSPACE_SPLIT_VIEW_CONTEXT } from './workspace-split-view.context.js';
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
import { UMB_PROPERTY_DATASET_CONTEXT, isNameablePropertyDatasetContext } from '@umbraco-cms/backoffice/property';
import {
type UUIInputElement,
UUIInputEvent,
type UUIPopoverContainerElement,
} from '@umbraco-cms/backoffice/external/uui';
import { css, html, nothing, customElement, state, query } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement, umbFocus } from '@umbraco-cms/backoffice/lit-element';
import { DocumentVariantStateModel } from '@umbraco-cms/backoffice/external/backend-api';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { UmbDocumentWorkspaceContext } from '@umbraco-cms/backoffice/document';
import type { ActiveVariant } from '../../controllers/index.js';
import { UMB_WORKSPACE_SPLIT_VIEW_CONTEXT } from './workspace-split-view.context.js';
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
import { UMB_PROPERTY_DATASET_CONTEXT, isNameablePropertyDatasetContext } from '@umbraco-cms/backoffice/property';
import { UmbLitElement, umbFocus } from '@umbraco-cms/backoffice/lit-element';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
type UmbDocumentVariantOption = {
culture: string | null;

View File

@@ -1,9 +1,9 @@
import { UMB_VARIANT_WORKSPACE_CONTEXT } from '../../contexts/index.js';
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import { UmbNumberState } from '@umbraco-cms/backoffice/observable-api';
import { UMB_VARIANT_WORKSPACE_CONTEXT } from '../../contexts/index.js';
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
import type { UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property';
export class UmbWorkspaceSplitViewContext extends UmbContextBase<UmbWorkspaceSplitViewContext> {

View File

@@ -1,6 +1,6 @@
import { css, html, customElement, property, ifDefined } from '@umbraco-cms/backoffice/external/lit';
import { UmbWorkspaceSplitViewContext } from './workspace-split-view.context.js';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, customElement, property, ifDefined } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
// import local components
@@ -34,6 +34,7 @@ export class UmbWorkspaceSplitViewElement extends UmbLitElement {
splitViewContext = new UmbWorkspaceSplitViewContext(this);
override render() {
return html`
<umb-workspace-editor
alias=${this.alias}

View File

@@ -8,6 +8,14 @@ export class UmbWorkspaceRouteManager extends UmbControllerBase {
public readonly routes = this.#routes.asObservable();
setRoutes(routes: Array<UmbRoute>) {
this.#routes.setValue(routes);
this.#routes.setValue(
[
...routes,
{
path: `**`,
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
}
]
);
}
}

View File

@@ -1,5 +1,5 @@
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
export type ActiveVariant = {
index: number;
@@ -13,7 +13,7 @@ export type ActiveVariant = {
* @description - Class managing the split view state for a workspace context.
*/
export class UmbWorkspaceSplitViewManager {
#activeVariantsInfo = new UmbArrayState<ActiveVariant>([], (x) => x.index);
#activeVariantsInfo = new UmbArrayState<ActiveVariant>([], (x) => x.index).sortBy((a, b) => (a.index || 0) - (b.index || 0));
public readonly activeVariantsInfo = this.#activeVariantsInfo.asObservable();
private _routeBase?: string;
@@ -25,7 +25,7 @@ export class UmbWorkspaceSplitViewManager {
}
setActiveVariant(index: number, culture: string | null, segment: string | null) {
this.#activeVariantsInfo.appendOne({ index, culture: culture || null, segment: segment || null });
this.#activeVariantsInfo.appendOneAt({ index, culture: culture ?? null, segment: segment ?? null }, index);
}
getActiveVariants() {
@@ -39,7 +39,7 @@ export class UmbWorkspaceSplitViewManager {
}
public activeVariantByIndex(index: number) {
return this.#activeVariantsInfo.asObservablePart((data) => data[index] || undefined);
return this.#activeVariantsInfo.asObservablePart((data) => data.find(x => x.index === index) || undefined);
}
public switchVariant(index: number, variantId: UmbVariantId) {

View File

@@ -1,38 +0,0 @@
import type { UmbSubmittableWorkspaceContext } from '../../contexts/tokens/submittable-workspace-context.interface.js';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import { html, customElement, state, css } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbRoute } from '@umbraco-cms/backoffice/router';
import { UmbExtensionsApiInitializer } from '@umbraco-cms/backoffice/extension-api';
@customElement('umb-editable-workspace')
export class UmbEditableWorkspaceElement extends UmbLitElement {
@state()
_routes: UmbRoute[] = [];
public set api(api: UmbSubmittableWorkspaceContext) {
this.observe(api.routes.routes, (routes) => (this._routes = routes));
new UmbExtensionsApiInitializer(this, umbExtensionsRegistry, 'workspaceContext', [api]);
}
override render() {
return html` <umb-router-slot .routes="${this._routes}"></umb-router-slot>`;
}
static override styles = [
css`
form {
display: contents;
}
`,
];
}
export default UmbEditableWorkspaceElement;
declare global {
interface HTMLElementTagNameMap {
'umb-editable-workspace': UmbEditableWorkspaceElement;
}
}

View File

@@ -1,13 +0,0 @@
import type { UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry';
export const manifest: UmbBackofficeManifestKind = {
type: 'kind',
alias: 'Umb.Kind.Workspace.Editable',
matchKind: 'editable',
matchType: 'workspace',
manifest: {
type: 'workspace',
kind: 'editable',
element: () => import('./editable-workspace.element.js'),
},
};

View File

@@ -1,22 +0,0 @@
import { expect, fixture, html } from '@open-wc/testing';
import { UmbEditableWorkspaceElement } from './editable-workspace.element.js';
import { type UmbTestRunnerWindow, defaultA11yConfig } from '@umbraco-cms/internal/test-utils';
describe('UmbEditableWorkspaceElement', () => {
let element: UmbEditableWorkspaceElement;
beforeEach(async () => {
element = await fixture(html`<umb-editable-workspace></umb-editable-workspace>`);
});
it('is defined with its own instance', () => {
expect(element).to.be.instanceOf(UmbEditableWorkspaceElement);
});
if ((window as UmbTestRunnerWindow).__UMBRACO_TEST_RUN_A11Y_TEST) {
it('passes the a11y audit', async () => {
// TODO: should we use shadowDom here?
await expect(element).to.be.accessible(defaultA11yConfig);
});
}
});

View File

@@ -1,5 +1,4 @@
import { manifest as editableKindManifest } from './editable/editable-workspace.kind.js';
import { manifest as routableKindManifest } from './routable/routable-workspace.kind.js';
import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry';
export const manifests: Array<ManifestTypes | UmbBackofficeManifestKind> = [routableKindManifest, editableKindManifest];
export const manifests: Array<ManifestTypes | UmbBackofficeManifestKind> = [routableKindManifest];

View File

@@ -1,6 +1,3 @@
import { UmbDataTypeDetailRepository } from '../repository/detail/data-type-detail.repository.js';
import type { UmbDataTypeDetailModel, UmbDataTypePropertyModel } from '../types.js';
import { UmbDataTypeWorkspaceEditorElement } from './data-type-workspace-editor.element.js';
import type { UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property';
import type {
UmbInvariantDatasetWorkspaceContext,
@@ -10,7 +7,6 @@ import {
UmbSubmittableWorkspaceContextBase,
UmbInvariantWorkspacePropertyDatasetContext,
UmbWorkspaceIsNewRedirectController,
UmbWorkspaceRouteManager,
} from '@umbraco-cms/backoffice/workspace';
import {
appendToFrozenArray,
@@ -29,7 +25,9 @@ import {
UmbRequestReloadChildrenOfEntityEvent,
UmbRequestReloadStructureForEntityEvent,
} from '@umbraco-cms/backoffice/entity-action';
import { UMB_PROPERTY_EDITOR_SCHEMA_ALIAS_DEFAULT } from '@umbraco-cms/backoffice/property-editor';
import type { UmbDataTypeDetailModel, UmbDataTypePropertyModel } from '../types.js';
import { UmbDataTypeDetailRepository } from '../repository/detail/data-type-detail.repository.js';
import { UmbDataTypeWorkspaceEditorElement } from './data-type-workspace-editor.element.js';
type EntityType = UmbDataTypeDetailModel;
export class UmbDataTypeWorkspaceContext

View File

@@ -10,7 +10,7 @@ const DATA_TYPE_WORKSPACE_ALIAS = 'Umb.Workspace.DataType';
const workspace: ManifestWorkspaces = {
type: 'workspace',
kind: 'editable',
kind: 'routable',
alias: DATA_TYPE_WORKSPACE_ALIAS,
name: 'Data Type Workspace',
api: () => import('./data-type-workspace.context.js'),

View File

@@ -1,10 +1,6 @@
import { UmbDictionaryDetailRepository } from '../repository/index.js';
import type { UmbDictionaryDetailModel } from '../types.js';
import { UmbDictionaryWorkspaceEditorElement } from './dictionary-workspace-editor.element.js';
import {
type UmbSubmittableWorkspaceContext,
UmbSubmittableWorkspaceContextBase,
UmbWorkspaceRouteManager,
UmbWorkspaceIsNewRedirectController,
type UmbRoutableWorkspaceContext,
} from '@umbraco-cms/backoffice/workspace';
@@ -15,6 +11,9 @@ import {
UmbRequestReloadChildrenOfEntityEvent,
UmbRequestReloadStructureForEntityEvent,
} from '@umbraco-cms/backoffice/entity-action';
import type { UmbDictionaryDetailModel } from '../types.js';
import { UmbDictionaryDetailRepository } from '../repository/index.js';
import { UmbDictionaryWorkspaceEditorElement } from './dictionary-workspace-editor.element.js';
export class UmbDictionaryWorkspaceContext
extends UmbSubmittableWorkspaceContextBase<UmbDictionaryDetailModel>

View File

@@ -1,10 +1,10 @@
import type { UmbDocumentBlueprintVariantOptionModel } from '../types.js';
import { UmbDocumentBlueprintWorkspaceSplitViewElement } from './document-blueprint-workspace-split-view.element.js';
import { UMB_DOCUMENT_BLUEPRINT_WORKSPACE_CONTEXT } from './document-blueprint-workspace.context-token.js';
import { customElement, state, css, html } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { UmbRoute, UmbRouterSlotInitEvent } from '@umbraco-cms/backoffice/router';
import type { UmbDocumentBlueprintVariantOptionModel } from '../types.js';
import { UMB_DOCUMENT_BLUEPRINT_WORKSPACE_CONTEXT } from './document-blueprint-workspace.context-token.js';
import { UmbDocumentBlueprintWorkspaceSplitViewElement } from './document-blueprint-workspace-split-view.element.js';
@customElement('umb-document-blueprint-workspace-editor')
export class UmbDocumentBlueprintWorkspaceEditorElement extends UmbLitElement {
@@ -83,17 +83,12 @@ export class UmbDocumentBlueprintWorkspaceEditorElement extends UmbLitElement {
});
}
const oldValue = this._routes;
routes.push({
path: `**`,
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
});
// is there any differences in the amount ot the paths? [NL]
// TODO: if we make a memorization function as the observer, we can avoid this check and avoid the whole build of routes. [NL]
if (oldValue && oldValue.length === routes.length) {
// is there any differences in the paths? [NL]
const hasDifferences = oldValue.some((route, index) => route.path !== routes[index].path);
if (!hasDifferences) return;
}
this._routes = routes;
this.requestUpdate('_routes', oldValue);
}
private _gotWorkspaceRoute = (e: UmbRouterSlotInitEvent) => {
@@ -101,7 +96,7 @@ export class UmbDocumentBlueprintWorkspaceEditorElement extends UmbLitElement {
};
override render() {
return this._routes && this._routes.length > 0
return this._routes
? html`<umb-router-slot .routes=${this._routes} @init=${this._gotWorkspaceRoute}></umb-router-slot>`
: '';
}

View File

@@ -1,14 +1,3 @@
import { UmbDocumentTypeDetailRepository } from '../repository/detail/document-type-detail.repository.js';
import { UMB_DOCUMENT_TYPE_ENTITY_TYPE } from '../entity.js';
import type { UmbDocumentTypeDetailModel } from '../types.js';
import {
UMB_CREATE_DOCUMENT_TYPE_WORKSPACE_PATH_PATTERN,
UMB_CREATE_DOCUMENT_TYPE_WORKSPACE_PRESET_ELEMENT,
UMB_CREATE_DOCUMENT_TYPE_WORKSPACE_PRESET_TEMPLATE,
UMB_EDIT_DOCUMENT_TYPE_WORKSPACE_PATH_PATTERN,
type UmbCreateDocumentTypeWorkspacePresetType,
} from '../paths.js';
import { UmbDocumentTypeWorkspaceEditorElement } from './document-type-workspace-editor.element.js';
import { UmbContentTypeStructureManager } from '@umbraco-cms/backoffice/content-type';
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
import {
@@ -18,7 +7,6 @@ import {
import {
UmbSubmittableWorkspaceContextBase,
UmbWorkspaceIsNewRedirectController,
UmbWorkspaceRouteManager,
} from '@umbraco-cms/backoffice/workspace';
import { UmbTemplateDetailRepository } from '@umbraco-cms/backoffice/template';
import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action';
@@ -31,6 +19,17 @@ import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import type { UmbReferenceByUnique } from '@umbraco-cms/backoffice/models';
import type { UmbRoutableWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
import type { UmbPathPatternTypeAsEncodedParamsType } from '@umbraco-cms/backoffice/router';
import {
UMB_CREATE_DOCUMENT_TYPE_WORKSPACE_PATH_PATTERN,
UMB_CREATE_DOCUMENT_TYPE_WORKSPACE_PRESET_ELEMENT,
UMB_CREATE_DOCUMENT_TYPE_WORKSPACE_PRESET_TEMPLATE,
UMB_EDIT_DOCUMENT_TYPE_WORKSPACE_PATH_PATTERN,
type UmbCreateDocumentTypeWorkspacePresetType,
} from '../paths.js';
import type { UmbDocumentTypeDetailModel } from '../types.js';
import { UMB_DOCUMENT_TYPE_ENTITY_TYPE } from '../entity.js';
import { UmbDocumentTypeDetailRepository } from '../repository/detail/document-type-detail.repository.js';
import { UmbDocumentTypeWorkspaceEditorElement } from './document-type-workspace-editor.element.js';
type EntityType = UmbDocumentTypeDetailModel;
export class UmbDocumentTypeWorkspaceContext

View File

@@ -1,4 +1,3 @@
import { isDocumentUserPermission } from '../utils.js';
import { UMB_CURRENT_USER_CONTEXT } from '@umbraco-cms/backoffice/current-user';
import { UMB_ENTITY_CONTEXT } from '@umbraco-cms/backoffice/entity';
import { observeMultiple } from '@umbraco-cms/backoffice/observable-api';
@@ -10,6 +9,7 @@ import type {
} from '@umbraco-cms/backoffice/extension-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import type { DocumentPermissionPresentationModel } from '@umbraco-cms/backoffice/external/backend-api';
import { isDocumentUserPermission } from '../utils.js';
export class UmbDocumentUserPermissionCondition
extends UmbConditionBase<UmbDocumentUserPermissionConditionConfig>

View File

@@ -1,11 +1,11 @@
import type { UmbDocumentVariantOptionModel } from '../types.js';
import { UmbDocumentWorkspaceSplitViewElement } from './document-workspace-split-view.element.js';
import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from './document-workspace.context-token.js';
import { customElement, state, css, html } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { UmbRoute, UmbRouterSlotInitEvent } from '@umbraco-cms/backoffice/router';
import { UMB_APP_LANGUAGE_CONTEXT } from '@umbraco-cms/backoffice/language';
import type { UmbDocumentVariantOptionModel } from '../types.js';
import { UmbDocumentWorkspaceSplitViewElement } from './document-workspace-split-view.element.js';
import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from './document-workspace.context-token.js';
// TODO: This seem fully identical with Media Workspace Editor, so we can refactor this to a generic component. [NL]
@customElement('umb-document-workspace-editor')
@@ -101,7 +101,8 @@ export class UmbDocumentWorkspaceEditorElement extends UmbLitElement {
const route = routes.find((route) => route.path === this.#appCulture);
if (!route) {
history.pushState({}, '', `${this.#workspaceRoute}/${routes[routes.length - 2].path}`);
// TODO: Notice: here is a specific index used for fallback, this could be made more solid [NL]
history.pushState({}, '', `${this.#workspaceRoute}/${routes[routes.length - 3].path}`);
return;
}
@@ -110,16 +111,12 @@ export class UmbDocumentWorkspaceEditorElement extends UmbLitElement {
});
}
const oldValue = this._routes;
routes.push({
path: `**`,
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
});
// is there any differences in the amount ot the paths? [NL]
if (oldValue && oldValue.length === routes.length) {
// is there any differences in the paths? [NL]
const hasDifferences = oldValue.some((route, index) => route.path !== routes[index].path);
if (!hasDifferences) return;
}
this._routes = routes;
this.requestUpdate('_routes', oldValue);
}
private _gotWorkspaceRoute = (e: UmbRouterSlotInitEvent) => {
@@ -128,7 +125,7 @@ export class UmbDocumentWorkspaceEditorElement extends UmbLitElement {
};
override render() {
return this._routes && this._routes.length > 0
return this._routes
? html`<umb-router-slot .routes=${this._routes} @init=${this._gotWorkspaceRoute}></umb-router-slot>`
: '';
}

View File

@@ -1,8 +1,8 @@
import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from './document-workspace.context-token.js';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, nothing, customElement, state, repeat } from '@umbraco-cms/backoffice/external/lit';
import type { ActiveVariant } from '@umbraco-cms/backoffice/workspace';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from './document-workspace.context-token.js';
@customElement('umb-document-workspace-split-view')
export class UmbDocumentWorkspaceSplitViewElement extends UmbLitElement {

View File

@@ -24,7 +24,10 @@ export class UmbDashboardHealthCheckElement extends UmbLitElement {
{
path: ``,
component: () => import('./views/health-check-overview.element.js'),
},
},{
path: `**`,
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
}
];
private _healthCheckDashboardContext = new UmbHealthCheckDashboardContext(this);

View File

@@ -1,7 +1,6 @@
import {
type UmbSubmittableWorkspaceContext,
UmbSubmittableWorkspaceContextBase,
UmbWorkspaceRouteManager,
UmbWorkspaceIsNewRedirectController,
type UmbRoutableWorkspaceContext,
} from '@umbraco-cms/backoffice/workspace';

View File

@@ -6,7 +6,6 @@ import {
UmbSubmittableWorkspaceContextBase,
type UmbRoutableWorkspaceContext,
UmbWorkspaceIsNewRedirectController,
UmbWorkspaceRouteManager,
} from '@umbraco-cms/backoffice/workspace';
import { UmbContentTypeStructureManager } from '@umbraco-cms/backoffice/content-type';
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';

View File

@@ -52,6 +52,10 @@ export class UmbMediaSectionViewElement extends UmbLitElement {
path: '',
redirectTo: 'collection',
},
{
path: `**`,
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
}
];
},
'_observeConfigDataType',

View File

@@ -83,17 +83,12 @@ export class UmbMediaWorkspaceEditorElement extends UmbLitElement {
});
}
const oldValue = this._routes;
routes.push({
path: `**`,
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
});
// is there any differences in the amount ot the paths? [NL]
// TODO: if we make a memorization function as the observer, we can avoid this check and avoid the whole build of routes. [NL]
if (oldValue && oldValue.length === routes.length) {
// is there any differences in the paths? [NL]
const hasDifferences = oldValue.some((route, index) => route.path !== routes[index].path);
if (!hasDifferences) return;
}
this._routes = routes;
this.requestUpdate('_routes', oldValue);
}
private _gotWorkspaceRoute = (e: UmbRouterSlotInitEvent) => {

View File

@@ -28,6 +28,10 @@ export class UmbMemberGroupSectionViewElement extends UmbLitElement {
path: '',
redirectTo: 'collection',
},
{
path: `**`,
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
}
];
override render() {

View File

@@ -5,7 +5,6 @@ import { UmbMemberGroupWorkspaceEditorElement } from './member-group-workspace-e
import {
type UmbSubmittableWorkspaceContext,
UmbSubmittableWorkspaceContextBase,
UmbWorkspaceRouteManager,
UmbWorkspaceIsNewRedirectController,
type UmbRoutableWorkspaceContext,
} from '@umbraco-cms/backoffice/workspace';

View File

@@ -5,7 +5,6 @@ import { UmbMemberTypeWorkspaceEditorElement } from './member-type-workspace-edi
import {
UmbSubmittableWorkspaceContextBase,
type UmbRoutableWorkspaceContext,
UmbWorkspaceRouteManager,
UmbWorkspaceIsNewRedirectController,
} from '@umbraco-cms/backoffice/workspace';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';

View File

@@ -28,6 +28,10 @@ export class UmbMemberSectionViewElement extends UmbLitElement {
path: '',
redirectTo: 'collection',
},
{
path: `**`,
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
}
];
override render() {

View File

@@ -85,17 +85,12 @@ export class UmbMemberWorkspaceEditorElement extends UmbLitElement {
});
}
const oldValue = this._routes;
routes.push({
path: `**`,
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
});
// is there any differences in the amount ot the paths? [NL]
// TODO: if we make a memorization function as the observer, we can avoid this check and avoid the whole build of routes. [NL]
if (oldValue && oldValue.length === routes.length) {
// is there any differences in the paths? [NL]
const hasDifferences = oldValue.some((route, index) => route.path !== routes[index].path);
if (!hasDifferences) return;
}
this._routes = routes;
this.requestUpdate('_routes', oldValue);
}
private _gotWorkspaceRoute = (e: UmbRouterSlotInitEvent) => {

View File

@@ -61,6 +61,10 @@ export class UmbCreatedPackagesSectionViewElement extends UmbLitElement implemen
path: '',
redirectTo: 'overview',
});
routes.push({
path: `**`,
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
});
this._routes = routes;
}

View File

@@ -28,7 +28,10 @@ export class UmbDashboardExamineManagementElement extends UmbLitElement {
{
path: ``,
component: () => import('./views/section-view-examine-overview.js'),
},
},{
path: `**`,
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
}
];
@state()

View File

@@ -8,7 +8,6 @@ import type { UmbRoutableWorkspaceContext, UmbSubmittableWorkspaceContext } from
import {
UmbSubmittableWorkspaceContextBase,
UmbWorkspaceIsNewRedirectController,
UmbWorkspaceRouteManager,
} from '@umbraco-cms/backoffice/workspace';
import { loadCodeEditor } from '@umbraco-cms/backoffice/code-editor';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';

View File

@@ -44,6 +44,10 @@ export class UmbPartialViewWorkspaceElement extends UmbLitElement {
this.#workspaceContext.load(unique);
},
},
{
path: `**`,
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
}
];
constructor() {

View File

@@ -10,7 +10,6 @@ import {
type UmbRoutableWorkspaceContext,
type UmbSubmittableWorkspaceContext,
UmbWorkspaceIsNewRedirectController,
UmbWorkspaceRouteManager,
} from '@umbraco-cms/backoffice/workspace';
import { loadCodeEditor } from '@umbraco-cms/backoffice/code-editor';
import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action';

View File

@@ -6,7 +6,6 @@ import { UmbStylesheetWorkspaceEditorElement } from './stylesheet-workspace-edit
import {
type UmbSubmittableWorkspaceContext,
UmbSubmittableWorkspaceContextBase,
UmbWorkspaceRouteManager,
UmbWorkspaceIsNewRedirectController,
type UmbRoutableWorkspaceContext,
} from '@umbraco-cms/backoffice/workspace';

View File

@@ -8,7 +8,6 @@ import type { UmbRoutableWorkspaceContext, UmbSubmittableWorkspaceContext } from
import {
UmbSubmittableWorkspaceContextBase,
UmbWorkspaceIsNewRedirectController,
UmbWorkspaceRouteManager,
} from '@umbraco-cms/backoffice/workspace';
import { UmbBooleanState, UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';

View File

@@ -30,6 +30,10 @@ export class UmbUserGroupSectionViewElement extends UmbLitElement {
path: '',
redirectTo: 'collection',
},
{
path: `**`,
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
}
];
override render() {

View File

@@ -6,7 +6,6 @@ import type { UmbRoutableWorkspaceContext, UmbSubmittableWorkspaceContext } from
import {
UmbSubmittableWorkspaceContextBase,
UmbWorkspaceIsNewRedirectController,
UmbWorkspaceRouteManager,
} from '@umbraco-cms/backoffice/workspace';
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';

View File

@@ -34,6 +34,10 @@ export class UmbSectionViewUsersElement extends UmbLitElement {
path: '',
redirectTo: 'collection',
},
{
path: `**`,
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
}
];
override render() {