Skip to content

Commit 696bf4e

Browse files
committed
Merge remote-tracking branch 'origin' into chore/build-and-test-jobs
2 parents 63bf63d + 2d4465e commit 696bf4e

File tree

60 files changed

+301
-196
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+301
-196
lines changed

src/apps/backoffice/components/backoffice-main.element.ts

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { UmbBackofficeContext } from '../backoffice.context.js';
22
import { UMB_BACKOFFICE_CONTEXT } from '../backoffice.context.js';
33
import { css, html, customElement, state, nothing } from '@umbraco-cms/backoffice/external/lit';
44
import { UmbSectionContext, UMB_SECTION_CONTEXT, UMB_SECTION_PATH_PATTERN } from '@umbraco-cms/backoffice/section';
5-
import type { UmbRoute, UmbRouterSlotChangeEvent } from '@umbraco-cms/backoffice/router';
5+
import type { PageComponent, UmbRoute, UmbRouterSlotChangeEvent } from '@umbraco-cms/backoffice/router';
66
import type { ManifestSection, UmbSectionElement } from '@umbraco-cms/backoffice/extension-registry';
77
import type { UmbExtensionManifestInitializer } from '@umbraco-cms/backoffice/extension-api';
88
import { createExtensionElement } from '@umbraco-cms/backoffice/extension-api';
@@ -11,7 +11,7 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
1111
@customElement('umb-backoffice-main')
1212
export class UmbBackofficeMainElement extends UmbLitElement {
1313
@state()
14-
private _routes: Array<UmbRoute & { alias: string }> = [];
14+
private _routes: Array<UmbRoute> = [];
1515

1616
@state()
1717
private _sections: Array<UmbExtensionManifestInitializer<ManifestSection>> = [];
@@ -43,28 +43,41 @@ export class UmbBackofficeMainElement extends UmbLitElement {
4343

4444
private _createRoutes() {
4545
if (!this._sections) return;
46-
const oldValue = this._routes;
4746

4847
// TODO: Refactor this for re-use across the app where the routes are re-generated at any time.
49-
this._routes = this._sections
48+
const newRoutes = this._sections
5049
.filter((x) => x.manifest)
5150
.map((section) => {
52-
const existingRoute = this._routes.find((r) => r.alias === section.alias);
51+
const existingRoute = this._routes.find(
52+
(r) => r.path === UMB_SECTION_PATH_PATTERN.generateLocal({ sectionName: section.manifest!.meta.pathname }),
53+
);
5354
if (existingRoute) {
5455
return existingRoute;
5556
} else {
5657
return {
57-
alias: section.alias,
58+
//alias: section.alias,
5859
path: UMB_SECTION_PATH_PATTERN.generateLocal({ sectionName: section.manifest!.meta.pathname }),
5960
component: () => createExtensionElement(section.manifest!, 'umb-section-default'),
60-
setup: (component) => {
61-
(component as UmbSectionElement).manifest = section.manifest as ManifestSection;
61+
setup: (component: PageComponent) => {
62+
(component as UmbSectionElement).manifest = section.manifest;
6263
},
6364
};
6465
}
6566
});
6667

67-
this.requestUpdate('_routes', oldValue);
68+
if (newRoutes.length > 0) {
69+
newRoutes.push({
70+
path: ``,
71+
redirectTo: newRoutes[0].path,
72+
});
73+
74+
newRoutes.push({
75+
path: `**`,
76+
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
77+
});
78+
}
79+
80+
this._routes = newRoutes;
6881
}
6982

7083
private _onRouteChange = async (event: UmbRouterSlotChangeEvent) => {

src/assets/lang/da-dk.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2521,4 +2521,8 @@ export default {
25212521
detailedLevelDescription:
25222522
'\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 ',
25232523
},
2524+
routing: {
2525+
routeNotFoundTitle: 'Ikke fundet',
2526+
routeNotFoundDescription: 'Den side du leder efter kunne ikke findes. Kontroller adressen og prøv igen.',
2527+
},
25242528
} as UmbLocalizationDictionary;

src/assets/lang/en-us.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2522,4 +2522,8 @@ export default {
25222522
detailedLevelDescription:
25232523
'\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 ',
25242524
},
2525+
routing: {
2526+
routeNotFoundTitle: 'Not found',
2527+
routeNotFoundDescription: 'The requested route could not be found. Please check the URL and try again.',
2528+
},
25252529
} as UmbLocalizationDictionary;

src/assets/lang/en.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2591,4 +2591,8 @@ export default {
25912591
detailedLevelDescription:
25922592
'We will send:\n<ul>\n <li>Anonymized site ID, Umbraco version, and packages installed.</li>\n <li>Number of: Root nodes, Content nodes, Macros, 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>',
25932593
},
2594+
routing: {
2595+
routeNotFoundTitle: 'Not found',
2596+
routeNotFoundDescription: 'The requested route could not be found. Please check the URL and try again.',
2597+
},
25942598
} as UmbLocalizationDictionary;

src/external/router-slot/router-slot.ts

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ ensureAnchorHistory();
4545
* @event changestate - Dispatched when the router slot state changes.
4646
*/
4747
export class RouterSlot<D = any, P = any> extends HTMLElement implements IRouterSlot<D, P> {
48+
/**
49+
* Method to cancel navigation if changed.
50+
*/
51+
private _cancelNavigation ?:() => void;
52+
4853
/**
4954
* Listeners on the router.
5055
*/
@@ -197,8 +202,17 @@ export class RouterSlot<D = any, P = any> extends HTMLElement implements IRouter
197202
this._routes.push(...routes);
198203

199204
if (navigate === undefined) {
200-
// If navigate is not determined, then we will check if we have a route match. If not then we will re-render.
205+
// If navigate is not determined, then we will check if we have a route match. If not then we will re-render. [NL]
201206
navigate = this._routeMatch === null;
207+
if (navigate === false) {
208+
if (this.isConnected) {
209+
const newMatch = this.getRouteMatch();
210+
// Check if this match matches the current match (aka. If the path has changed), if so we should navigate. [NL]
211+
if(newMatch) {
212+
navigate = shouldNavigate(this.match, newMatch);
213+
}
214+
}
215+
}
202216
}
203217

204218
// Navigate fallback:
@@ -232,13 +246,21 @@ export class RouterSlot<D = any, P = any> extends HTMLElement implements IRouter
232246

233247
// Either choose the parent fragment or the current path if no parent exists.
234248
// The root router slot will always use the entire path.
235-
const pathFragment =
236-
this.parent != null && this.parent.fragments != null ? this.parent.fragments.rest : pathWithoutBasePath();
249+
const pathFragment = this.getPathFragment();
237250

238251
// Route to the path
239252
await this.renderPath(pathFragment);
240253
}
241254

255+
protected getPathFragment() {
256+
return this.parent != null && this.parent.fragments != null ? this.parent.fragments.rest : pathWithoutBasePath();
257+
}
258+
259+
protected getRouteMatch() {
260+
// Find the corresponding route.
261+
return matchRoutes(this._routes, this.getPathFragment());
262+
}
263+
242264
/**
243265
* Attaches listeners, either globally or on the parent router.
244266
*/
@@ -296,6 +318,8 @@ export class RouterSlot<D = any, P = any> extends HTMLElement implements IRouter
296318
* Returns true if a navigation was made to a new page.
297319
*/
298320
protected async renderPath(path: string | PathFragment): Promise<boolean> {
321+
322+
// 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]
299323
// Find the corresponding route.
300324
const match = matchRoutes(this._routes, path);
301325

@@ -312,10 +336,17 @@ export class RouterSlot<D = any, P = any> extends HTMLElement implements IRouter
312336
// Only change route if its a new route.
313337
const navigate = shouldNavigate(this.match, match);
314338
if (navigate) {
339+
340+
// 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]
341+
this._cancelNavigation?.();
315342
// Listen for another push state event. If another push state event happens
316343
// while we are about to navigate we have to cancel.
317344
let navigationInvalidated = false;
318-
const cancelNavigation = () => (navigationInvalidated = true);
345+
const cancelNavigation = () => {
346+
navigationInvalidated = true;
347+
this._cancelNavigation = undefined;
348+
};
349+
this._cancelNavigation = cancelNavigation;
319350
const removeChangeListener: EventListenerSubscription = addListener<Event, GlobalRouterEvent>(
320351
GLOBAL_ROUTER_EVENTS_TARGET,
321352
'changestate',
@@ -378,16 +409,23 @@ export class RouterSlot<D = any, P = any> extends HTMLElement implements IRouter
378409
return cancel();
379410
}
380411

381-
// Remove the old page by clearing the slot
382-
this.clearChildren();
412+
// We have some routes that share the same component instance, those should not be removed and re-appended [NL]
413+
const isTheSameComponent = this.firstChild === page;
414+
415+
if(!isTheSameComponent) {
416+
// Remove the old page by clearing the slot
417+
this.clearChildren();
418+
}
383419

384420
// Store the new route match before we append the new page to the DOM.
385421
// We do this to ensure that we can find the match in the connectedCallback of the page.
386422
this._routeMatch = match;
387423

388-
if (page) {
389-
// Append the new page
390-
this.appendChild(page);
424+
if(!isTheSameComponent) {
425+
if (page) {
426+
// Append the new page
427+
this.appendChild(page);
428+
}
391429
}
392430
}
393431

src/libs/extension-api/controller/base-extension-initializer.controller.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ export abstract class UmbBaseExtensionInitializer<
211211
// Check if we already have a controller for this config:
212212
const existing = this.#conditionControllers.find((controller) => controller.config === conditionConfig);
213213
if (!existing) {
214+
// 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]
214215
const conditionController = await createExtensionApi(this, conditionManifest, [
215216
{
216217
manifest: conditionManifest,

src/libs/observable-api/observer.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ export type ObserverCallback<T> = (value: T) => void;
55

66
export class UmbObserver<T> {
77
#source!: Observable<T>;
8-
#callback!: ObserverCallback<T>;
8+
#callback?: ObserverCallback<T>;
99
#subscription!: Subscription;
1010

1111
constructor(source: Observable<T>, callback?: ObserverCallback<T>) {
1212
this.#source = source;
1313
if (callback) {
14+
this.#callback = callback;
1415
this.#subscription = source.subscribe(callback);
1516
}
1617
}
@@ -44,7 +45,7 @@ export class UmbObserver<T> {
4445

4546
hostConnected() {
4647
// Notice: This will not re-subscribe if this controller was destroyed. Only if the subscription was closed.
47-
if (this.#subscription?.closed) {
48+
if (this.#subscription?.closed && this.#callback) {
4849
this.#subscription = this.#source.subscribe(this.#callback);
4950
}
5051
}

src/packages/block/block-grid/components/block-grid-areas-container/block-grid-areas-container.element.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { UMB_BLOCK_GRID_MANAGER_CONTEXT } from '../../context/block-grid-manager.context-token.js';
22
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
3-
import { UMB_BLOCK_GRID_ENTRY_CONTEXT, type UmbBlockGridTypeAreaType } from '@umbraco-cms/backoffice/block-grid';
43
import { css, customElement, html, repeat, state } from '@umbraco-cms/backoffice/external/lit';
4+
import { UMB_BLOCK_GRID_ENTRY_CONTEXT, type UmbBlockGridTypeAreaType } from '@umbraco-cms/backoffice/block-grid';
55

66
import '../block-grid-entries/index.js';
77
/**

src/packages/block/block-grid/context/block-grid-entry.context.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@ import {
55
type UmbBlockGridScalableContext,
66
UmbBlockGridScaleManager,
77
} from './block-grid-scale-manager/block-grid-scale-manager.controller.js';
8-
import { UmbBlockEntryContext } from '@umbraco-cms/backoffice/block';
9-
import type { UmbContentTypeModel, UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type';
10-
import type { UmbBlockGridTypeModel, UmbBlockGridLayoutModel } from '@umbraco-cms/backoffice/block-grid';
11-
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
128
import {
139
UmbArrayState,
1410
UmbBooleanState,
@@ -17,6 +13,10 @@ import {
1713
appendToFrozenArray,
1814
observeMultiple,
1915
} from '@umbraco-cms/backoffice/observable-api';
16+
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
17+
import type { UmbContentTypeModel, UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type';
18+
import { UmbBlockEntryContext } from '@umbraco-cms/backoffice/block';
19+
import type { UmbBlockGridTypeModel, UmbBlockGridLayoutModel } from '@umbraco-cms/backoffice/block-grid';
2020

2121
export class UmbBlockGridEntryContext
2222
extends UmbBlockEntryContext<

src/packages/block/block-grid/property-editors/block-grid-areas-config/property-editor-ui-block-grid-areas-config.element.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import type { UmbBlockGridTypeAreaType } from '../../index.js';
2-
import { UMB_BLOCK_GRID_DEFAULT_LAYOUT_STYLESHEET } from '../../context/block-grid-manager.context.js';
31
import { UMB_BLOCK_GRID_AREA_TYPE_WORKSPACE_MODAL } from '../../components/block-grid-area-config-entry/index.js';
2+
import { UMB_BLOCK_GRID_DEFAULT_LAYOUT_STYLESHEET } from '../../context/block-grid-manager.context.js';
3+
import type { UmbBlockGridTypeAreaType } from '../../index.js';
44
import { UmbBlockGridAreaTypeEntriesContext } from './block-grid-area-type-entries.context.js';
55
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
66
import { html, customElement, property, state, repeat } from '@umbraco-cms/backoffice/external/lit';
@@ -127,7 +127,6 @@ export class UmbPropertyEditorUIBlockGridAreasConfigElement
127127
//TODO: open area edit workspace
128128
}
129129

130-
// TODO: Needs localizations:
131130
override render() {
132131
return this._areaGridColumns
133132
? html`${this._styleElement}

0 commit comments

Comments
 (0)