diff --git a/src/Umbraco.Web.UI.Client/examples/modal-routed/dashboard.element.ts b/src/Umbraco.Web.UI.Client/examples/modal-routed/dashboard.element.ts index 967a4a7a88bb..61c0f6862f36 100644 --- a/src/Umbraco.Web.UI.Client/examples/modal-routed/dashboard.element.ts +++ b/src/Umbraco.Web.UI.Client/examples/modal-routed/dashboard.element.ts @@ -17,6 +17,7 @@ export class UmbDashboardElement extends UmbElementMixin(LitElement) { }, { path: '', + pathMatch: 'full', redirectTo: 'tab1', }, ]; diff --git a/src/Umbraco.Web.UI.Client/examples/modal-routed/modal/example-modal.element.ts b/src/Umbraco.Web.UI.Client/examples/modal-routed/modal/example-modal.element.ts index e1f0f5bdd4e7..45c0229e37b2 100644 --- a/src/Umbraco.Web.UI.Client/examples/modal-routed/modal/example-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/examples/modal-routed/modal/example-modal.element.ts @@ -17,6 +17,7 @@ export class UmbExampleModal extends UmbModalBaseElement { }, { path: '', + pathMatch: 'full', redirectTo: 'modalOverview', }, ]; diff --git a/src/Umbraco.Web.UI.Client/src/apps/backoffice/components/backoffice-main.element.ts b/src/Umbraco.Web.UI.Client/src/apps/backoffice/components/backoffice-main.element.ts index 9435f94a1b2e..0550e6c52cc3 100644 --- a/src/Umbraco.Web.UI.Client/src/apps/backoffice/components/backoffice-main.element.ts +++ b/src/Umbraco.Web.UI.Client/src/apps/backoffice/components/backoffice-main.element.ts @@ -63,8 +63,10 @@ export class UmbBackofficeMainElement extends UmbLitElement { if (newRoutes.length > 0) { newRoutes.push({ + path: '', + pathMatch: 'full', + awaitStability: true, redirectTo: newRoutes[0].path, - path: ``, }); newRoutes.push({ diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit.element.ts index 21205661e53f..e9ce9d3152ab 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit.element.ts @@ -123,6 +123,7 @@ export class UmbBlockWorkspaceViewEditElement extends UmbLitElement implements U if (!this._hasRootGroups) { routes.push({ path: '', + pathMatch: 'full', redirectTo: routes[0]?.path, }); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor.element.ts index 34d0e5d3a836..ec9b43034a7a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor.element.ts @@ -205,12 +205,14 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements }); routes.push({ path: '', + pathMatch: 'full', redirectTo: 'root', guards: [() => this.#processingTabId === undefined], }); } else { routes.push({ path: '', + pathMatch: 'full', redirectTo: routes[0]?.path, guards: [() => this.#processingTabId === undefined], }); diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content/workspace/views/edit/content-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content/workspace/views/edit/content-editor.element.ts index 6f9bb5f542bf..693808923e79 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/content/content/workspace/views/edit/content-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content/workspace/views/edit/content-editor.element.ts @@ -109,6 +109,7 @@ export class UmbContentWorkspaceViewEditElement extends UmbLitElement implements if (routes.length !== 0) { routes.push({ path: '', + pathMatch: 'full', redirectTo: routes[0].path, }); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/router/router-slot/model.ts b/src/Umbraco.Web.UI.Client/src/packages/core/router/router-slot/model.ts index 72e669027cf7..4b9892946a31 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/router/router-slot/model.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/router/router-slot/model.ts @@ -75,6 +75,9 @@ export interface IRedirectRoute extends IRouteBase { // The paths the route should redirect to. Can either be relative or absolute. redirectTo: string; + // First redirect when the routes appears stable. Delaying the redirect so other routes get the change to resolve first. + awaitStability?: boolean; + // Whether the query should be preserved when redirecting. preserveQuery?: boolean; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/router/router-slot/router-slot.ts b/src/Umbraco.Web.UI.Client/src/packages/core/router/router-slot/router-slot.ts index 3f3a0b9a8dc1..eebcec1dea48 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/router/router-slot/router-slot.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/router/router-slot/router-slot.ts @@ -314,6 +314,24 @@ export class RouterSlot extends HTMLElement implements IRouter } } + private getRedirectDelay() { + if ('connection' in navigator) { + const connection = + navigator.connection || (navigator as any).mozConnection || (navigator as any).webkitConnection; + + switch (connection.effectiveType) { + case 'slow-2g': + case '2g': + return 1200; + case '3g': + return 800; + case '4g': + return 200; + } + } + return 400; + } + /** * Loads a new path based on the routes. * Returns true if a navigation was made to a new page. @@ -387,6 +405,14 @@ export class RouterSlot extends HTMLElement implements IRouter // Redirect if necessary if (isRedirectRoute(route)) { cleanup(); + if (route.awaitStability === true) { + // await until browser is done loading, based on a guess: + const delay = this.getRedirectDelay(); + await new Promise((resolve) => setTimeout(resolve, delay)); + if (navigationInvalidated) { + return cancel(); + } + } handleRedirect(this, route); return false; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/workspace/document-blueprint-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/workspace/document-blueprint-workspace-editor.element.ts index 0f75fd2ac003..38a20c07f015 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/workspace/document-blueprint-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/workspace/document-blueprint-workspace-editor.element.ts @@ -79,6 +79,7 @@ export class UmbDocumentBlueprintWorkspaceEditorElement extends UmbLitElement { // Using first single view as the default route for now (hence the math below): routes.push({ path: '', + pathMatch: 'full', redirectTo: routes[variants.length * variants.length]?.path, }); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/dashboard/media-dashboard.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/dashboard/media-dashboard.element.ts index 10128585628e..3e5739daaa14 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/dashboard/media-dashboard.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/dashboard/media-dashboard.element.ts @@ -53,6 +53,7 @@ export class UmbMediaDashboardElement extends UmbLitElement { }, { path: '', + pathMatch: 'full', redirectTo: 'collection', }, { diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/media-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/media-workspace-editor.element.ts index d7eaa87ced30..92f0fc4701b4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/media-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/media-workspace-editor.element.ts @@ -79,6 +79,7 @@ export class UmbMediaWorkspaceEditorElement extends UmbLitElement { // Using first single view as the default route for now (hence the math below): routes.push({ path: '', + pathMatch: 'full', redirectTo: routes[variants.length * variants.length]?.path, }); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/workspace/member/member-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/workspace/member/member-workspace-editor.element.ts index 70aa290688ab..27e7c6651eb6 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/workspace/member/member-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/workspace/member/member-workspace-editor.element.ts @@ -81,6 +81,7 @@ export class UmbMemberWorkspaceEditorElement extends UmbLitElement { // Using first single view as the default route for now (hence the math below): routes.push({ path: '', + pathMatch: 'full', redirectTo: routes[options.length * options.length]?.path, }); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/packages/package-section/views/created/created-packages-section-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/packages/package-section/views/created/created-packages-section-view.element.ts index 7537effb3e3c..b132fc82f7db 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/packages/package-section/views/created/created-packages-section-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/packages/package-section/views/created/created-packages-section-view.element.ts @@ -54,6 +54,7 @@ export class UmbCreatedPackagesSectionViewElement extends UmbLitElement implemen routes.push({ path: '', + pathMatch: 'full', redirectTo: 'overview', }); routes.push({