From d0420ec2a15e65aef3ba060033bae39595bd750f Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 27 May 2024 13:39:48 +0200 Subject: [PATCH 1/3] remove "magic" route fallback to the first section --- .../components/backoffice-main.element.ts | 16 ---------------- 1 file changed, 16 deletions(-) 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 d94257088e..d2c9ce601f 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 @@ -64,22 +64,6 @@ export class UmbBackofficeMainElement extends UmbLitElement { } }); - if (this._sections.length > 0) { - const fallbackSectionPath = UMB_SECTION_PATH_PATTERN.generateLocal({ - sectionName: this._sections[0].manifest!.meta.pathname, - }); - this._routes.push({ - alias: '__redirect', - path: '/', - redirectTo: fallbackSectionPath, - }); - this._routes.push({ - alias: '__redirect', - path: '/section/', - redirectTo: fallbackSectionPath, - }); - } - this.requestUpdate('_routes', oldValue); } From fd70593bded221b660702116c9748c54a3f48d3c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 27 May 2024 13:40:26 +0200 Subject: [PATCH 2/3] redirect to the first allowed section if we don't have a location --- .../user/current-user/current-user.context.ts | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/current-user.context.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/current-user.context.ts index 69e0d1cd18..f186692b09 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/current-user.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/current-user.context.ts @@ -7,6 +7,8 @@ import { firstValueFrom } from '@umbraco-cms/backoffice/external/rxjs'; import { UMB_AUTH_CONTEXT } from '@umbraco-cms/backoffice/auth'; import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; import { umbLocalizationRegistry } from '@umbraco-cms/backoffice/localization'; +import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; +import { UMB_SECTION_PATH_PATTERN } from '@umbraco-cms/backoffice/section'; export class UmbCurrentUserContext extends UmbContextBase { #currentUser = new UmbObjectState(undefined); @@ -43,6 +45,7 @@ export class UmbCurrentUserContext extends UmbContextBase if (asObservable) { this.observe(asObservable(), (currentUser) => { this.#currentUser?.setValue(currentUser); + this.#redirectToFirstAllowedSectionIfNeeded(); }); } } @@ -75,6 +78,36 @@ export class UmbCurrentUserContext extends UmbContextBase } }); } + + async #redirectToFirstAllowedSectionIfNeeded() { + const url = new URL(window.location.href); + + if (url.pathname === '/') { + const sectionManifest = await this.#firstAllowedSection(); + if (!sectionManifest) return; + + const fallbackSectionPath = UMB_SECTION_PATH_PATTERN.generateLocal({ + sectionName: sectionManifest.meta.pathname, + }); + + history.pushState(null, '', fallbackSectionPath); + } + } + + async #firstAllowedSection() { + const currentUser = this.#currentUser.getValue(); + if (!currentUser) return; + + /* TODO: this solution is not bullet proof as we still rely on the "correct" section to be registered at this point in time so we can get the path. + It probably would have been better if we used the section alias instead as the path. + Then we would have it available at all times and it also ensured a unique path. */ + const sections = await this.observe( + umbExtensionsRegistry.byTypeAndAliases('section', currentUser.allowedSections), + () => {}, + ).asPromise(); + + return sections[0]; + } } export default UmbCurrentUserContext; From d7ec3556c6a3047136b285ace86bb2056c21f1ef Mon Sep 17 00:00:00 2001 From: leekelleher Date: Mon, 27 May 2024 13:45:16 +0100 Subject: [PATCH 3/3] Observe current user's allowed section manifests to filter the section manifests. --- .../src/apps/backoffice/backoffice.context.ts | 27 ++++++++++++++++--- .../user/current-user/current-user.context.ts | 4 +-- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/apps/backoffice/backoffice.context.ts b/src/Umbraco.Web.UI.Client/src/apps/backoffice/backoffice.context.ts index f460ac4776..adcdeeda39 100644 --- a/src/Umbraco.Web.UI.Client/src/apps/backoffice/backoffice.context.ts +++ b/src/Umbraco.Web.UI.Client/src/apps/backoffice/backoffice.context.ts @@ -9,6 +9,7 @@ import type { ManifestSection } from '@umbraco-cms/backoffice/extension-registry import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import type { UmbExtensionManifestInitializer } from '@umbraco-cms/backoffice/extension-api'; import { UMB_AUTH_CONTEXT } from '@umbraco-cms/backoffice/auth'; +import { UMB_CURRENT_USER_CONTEXT } from '@umbraco-cms/backoffice/current-user'; export class UmbBackofficeContext extends UmbContextBase { #activeSectionAlias = new UmbStringState(undefined); @@ -23,9 +24,6 @@ export class UmbBackofficeContext extends UmbContextBase { constructor(host: UmbControllerHost) { super(host, UMB_BACKOFFICE_CONTEXT); - new UmbExtensionsManifestInitializer(this, umbExtensionsRegistry, 'section', null, (sections) => { - this.#allowedSections.setValue([...sections]); - }); // TODO: We need to ensure this request is called every time the user logs in, but this should be done somewhere across the app and not here [JOV] this.consumeContext(UMB_AUTH_CONTEXT, (authContext) => { @@ -34,6 +32,29 @@ export class UmbBackofficeContext extends UmbContextBase { this.#getVersion(); }); }); + + this.#init(); + } + + async #init() { + const userContext = await this.getContext(UMB_CURRENT_USER_CONTEXT); + this.observe( + userContext.allowedSections, + (allowedSections) => { + if (!allowedSections) return; + new UmbExtensionsManifestInitializer( + this, + umbExtensionsRegistry, + 'section', + (manifest) => allowedSections.includes(manifest.alias), + async (sections) => { + this.#allowedSections.setValue([...sections]); + }, + 'umbAllowedSectionsManifestInitializer', + ); + }, + 'umbAllowedSectionsObserver', + ); } async #getVersion() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/current-user.context.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/current-user.context.ts index f186692b09..fc2d2044b1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/current-user.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/current-user.context.ts @@ -13,7 +13,7 @@ import { UMB_SECTION_PATH_PATTERN } from '@umbraco-cms/backoffice/section'; export class UmbCurrentUserContext extends UmbContextBase { #currentUser = new UmbObjectState(undefined); readonly currentUser = this.#currentUser.asObservable(); - + readonly allowedSections = this.#currentUser.asObservablePart((user) => user?.allowedSections); readonly unique = this.#currentUser.asObservablePart((user) => user?.unique); readonly languageIsoCode = this.#currentUser.asObservablePart((user) => user?.languageIsoCode); readonly hasDocumentRootAccess = this.#currentUser.asObservablePart((user) => user?.hasDocumentRootAccess); @@ -99,7 +99,7 @@ export class UmbCurrentUserContext extends UmbContextBase if (!currentUser) return; /* TODO: this solution is not bullet proof as we still rely on the "correct" section to be registered at this point in time so we can get the path. - It probably would have been better if we used the section alias instead as the path. + It probably would have been better if we used the section alias instead as the path. Then we would have it available at all times and it also ensured a unique path. */ const sections = await this.observe( umbExtensionsRegistry.byTypeAndAliases('section', currentUser.allowedSections),