From 5e58d1fc61507d7fa648a26ebfb4271604a7d20b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 24 Jan 2023 13:37:11 +0100 Subject: [PATCH] section context subject implementation --- .../create-observable-part.method.ts | 2 +- .../observable-api/observer.controller.ts | 2 +- .../section-dashboards.element.ts | 15 ++-- .../section-sidebar-menu.element.ts | 4 +- .../section-sidebar.element.ts | 9 +-- .../section-views/section-views.element.ts | 70 ++++++++----------- .../components/section/section.context.ts | 31 ++++---- .../components/section/section.element.ts | 6 +- .../components/tree/tree-item.element.ts | 4 +- 9 files changed, 68 insertions(+), 75 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/create-observable-part.method.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/create-observable-part.method.ts index 4d10b39e78..588ef9e96e 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/create-observable-part.method.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/create-observable-part.method.ts @@ -12,7 +12,7 @@ import { MappingFunction, MemoizationFunction, defaultMemoization } from "./uniq * public readonly myPart = CreateObservablePart(this._data, (data) => data.myPart); */ -export function createObservablePart( +export function createObservablePart( source$: Observable, mappingFunction: MappingFunction, memoizationFunction?: MemoizationFunction diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/observer.controller.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/observer.controller.ts index 6598b7a358..38f51421cc 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/observer.controller.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/observer.controller.ts @@ -2,7 +2,7 @@ import { Observable } from 'rxjs'; import { UmbObserver } from './observer'; import { UmbControllerInterface, UmbControllerHostInterface } from '@umbraco-cms/controller'; -export class UmbObserverController extends UmbObserver implements UmbControllerInterface { +export class UmbObserverController extends UmbObserver implements UmbControllerInterface { _alias?: string; public get unique() { return this._alias; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-dashboards/section-dashboards.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-dashboards/section-dashboards.element.ts index ba493baa14..5ed63e6e8d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-dashboards/section-dashboards.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-dashboards/section-dashboards.element.ts @@ -8,7 +8,6 @@ import { createExtensionElement } from '@umbraco-cms/extensions-api'; import type { ManifestDashboard, ManifestDashboardCollection, - ManifestSection, ManifestWithMeta, } from '@umbraco-cms/models'; import { umbExtensionsRegistry } from '@umbraco-cms/extensions-registry'; @@ -58,7 +57,7 @@ export class UmbSectionDashboardsElement extends UmbLitElement { @state() private _currentSectionPathname = ''; - private _currentSectionAlias = ''; + private _currentSectionAlias?: string; private _sectionContext?: UmbSectionContext; constructor() { @@ -73,12 +72,12 @@ export class UmbSectionDashboardsElement extends UmbLitElement { private _observeSectionContext() { if (!this._sectionContext) return; - this.observe(this._sectionContext.manifest.pipe(first()), (section) => { - if (section) { - this._currentSectionAlias = section.alias; - this._currentSectionPathname = section.meta.pathname; - this._observeDashboards(); - } + this.observe(this._sectionContext.alias.pipe(first()), (alias) => { + this._currentSectionAlias = alias; + this._observeDashboards(); + }); + this.observe(this._sectionContext.pathname.pipe(first()), (pathname) => { + this._currentSectionPathname = pathname || ''; }); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar-menu/section-sidebar-menu.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar-menu/section-sidebar-menu.element.ts index f46bc00785..f52c749747 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar-menu/section-sidebar-menu.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar-menu/section-sidebar-menu.element.ts @@ -28,8 +28,8 @@ export class UmbSectionSidebarMenuElement extends UmbLitElement { private _observeCurrentSection() { if (!this._sectionContext) return; - this.observe(this._sectionContext?.manifest, (section) => { - this._currentSectionAlias = section.alias; + this.observe(this._sectionContext?.alias, (alias) => { + this._currentSectionAlias = alias; }); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar/section-sidebar.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar/section-sidebar.element.ts index 7964674b21..ddd1d24f6b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar/section-sidebar.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar/section-sidebar.element.ts @@ -2,7 +2,6 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { css, html } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { UmbSectionContext, UMB_SECTION_CONTEXT_TOKEN } from '../section.context'; -import type { ManifestSection } from '@umbraco-cms/models'; import '../../tree/context-menu/tree-context-menu.service'; import { UmbLitElement } from '@umbraco-cms/element'; @@ -48,9 +47,11 @@ export class UmbSectionSidebarElement extends UmbLitElement { private _observeSectionContext() { if (!this._sectionContext) return; - this.observe(this._sectionContext.manifest, (section) => { - this._sectionLabel = section.meta.label || section.name; - this._sectionPathname = section.meta.pathname; + this.observe(this._sectionContext.pathname, (pathname) => { + this._sectionPathname = pathname || ''; + }); + this.observe(this._sectionContext.label, (label) => { + this._sectionLabel = label || ''; }); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-views/section-views.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-views/section-views.element.ts index b9946e3bde..cca976d6a2 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-views/section-views.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-views/section-views.element.ts @@ -1,11 +1,12 @@ import { UUITextStyles } from '@umbraco-ui/uui-css'; import { css, html, nothing } from 'lit'; import { customElement, state } from 'lit/decorators.js'; -import { EMPTY, map, of, Subscription, switchMap } from 'rxjs'; +import { map, of } from 'rxjs'; import { UmbSectionContext, UMB_SECTION_CONTEXT_TOKEN } from '../section.context'; import type { ManifestSectionView } from '@umbraco-cms/models'; import { umbExtensionsRegistry } from '@umbraco-cms/extensions-registry'; import { UmbLitElement } from '@umbraco-cms/element'; +import { UmbObserverController } from '@umbraco-cms/observable-api'; @customElement('umb-section-views') export class UmbSectionViewsElement extends UmbLitElement { @@ -35,11 +36,10 @@ export class UmbSectionViewsElement extends UmbLitElement { private _routerFolder = ''; @state() - private _activeViewPathname?: ManifestSectionView; + private _activeViewPathname?: string; private _sectionContext?: UmbSectionContext; - private _viewsSubscription?: Subscription; - private _activeViewPathnameSubscription?: Subscription; + private _extensionsObserver?: UmbObserverController; constructor() { super(); @@ -60,43 +60,35 @@ export class UmbSectionViewsElement extends UmbLitElement { private _observeViews() { if (!this._sectionContext) return; - this._viewsSubscription?.unsubscribe(); - - this._viewsSubscription = this._sectionContext?.manifest - .pipe( - switchMap((section) => { - if (!section) return EMPTY; - - return ( - umbExtensionsRegistry - ?.extensionsOfType('sectionView') - .pipe( - map((views) => - views - .filter((view) => view.meta.sections.includes(section.alias)) - .sort((a, b) => b.meta.weight - a.meta.weight) - ) - ) ?? of([]) - ); - }) - ) - .subscribe((views) => { - this._views = views; - }); + this.observe(this._sectionContext.alias, (sectionAlias) => { + this._observeExtensions(sectionAlias); + }, 'viewsObserver') + } + private _observeExtensions(sectionAlias?: string) { + this._extensionsObserver?.destroy(); + if(sectionAlias) { + this._extensionsObserver = this.observe( + umbExtensionsRegistry?.extensionsOfType('sectionView').pipe( + map((views) => + views + .filter((view) => view.meta.sections.includes(sectionAlias)) + .sort((a, b) => b.meta.weight - a.meta.weight) + ) + ) ?? of([]) + , + (views) => { + this._views = views; + } + ); + } } private _observeActiveView() { - this._activeViewPathnameSubscription?.unsubscribe(); - - this._activeViewPathnameSubscription = this._sectionContext?.activeViewPathname.subscribe((pathname) => { - this._activeViewPathname = pathName; - }); - } - - disconnectedCallback(): void { - super.disconnectedCallback(); - this._viewsSubscription?.unsubscribe(); - this._activeViewPathnameSubscription?.unsubscribe(); + if(this._sectionContext) { + this.observe(this._sectionContext?.activeViewPathname, (pathname) => { + this._activeViewPathname = pathname; + }, 'activeViewPathnameObserver'); + } } render() { @@ -113,7 +105,7 @@ export class UmbSectionViewsElement extends UmbLitElement { + ?active="${this._activeViewPathname?.includes(view.meta.pathname)}"> ${view.meta.label || view.name} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section.context.ts index 28d1439994..9cb0e9594d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section.context.ts @@ -7,8 +7,12 @@ export type ActiveTreeItemType = Entity | undefined; export class UmbSectionContext { - #manifest; - public readonly manifest; + #manifestAlias = new BehaviorSubject(undefined); + #manifestPathname = new BehaviorSubject(undefined); + #manifestLabel = new BehaviorSubject(undefined); + public readonly alias = this.#manifestAlias.asObservable(); + public readonly pathname = this.#manifestPathname.asObservable(); + public readonly label = this.#manifestLabel.asObservable(); /* This was not used anywhere @@ -17,24 +21,21 @@ export class UmbSectionContext { */ // TODO: what is the best context to put this in? - #activeTreeItem = new UniqueObjectBehaviorSubject(undefined); + #activeTreeItem = new UniqueObjectBehaviorSubject(undefined); public readonly activeTreeItem = this.#activeTreeItem.asObservable(); // TODO: what is the best context to put this in? #activeViewPathname = new BehaviorSubject(undefined); public readonly activeViewPathname = this.#activeViewPathname.asObservable(); - constructor(sectionManifest: ManifestSection) { - this.#manifest = new BehaviorSubject(sectionManifest); - this.manifest = this.#manifest.asObservable(); + constructor(manifest: ManifestSection) { + this.setManifest(manifest); } - public setManifest(data: ManifestSection) { - this.#manifest.next({ ...data }); - } - - public getData() { - return this.#manifest.getValue(); + public setManifest(manifest?: ManifestSection) { + this.#manifestAlias.next(manifest?.alias); + this.#manifestPathname.next(manifest?.meta?.pathname); + this.#manifestLabel.next(manifest ? (manifest.meta?.label || manifest.name) : undefined); } /* @@ -44,12 +45,12 @@ export class UmbSectionContext { } */ - public setActiveTreeItem(item: ActiveTreeItemType) { + public setActiveTreeItem(item?: ActiveTreeItemType) { this.#activeTreeItem.next(item); } - public setActiveView(view: ManifestSectionView) { - this.#activeViewPathname.next(view.meta.pathname); + public setActiveView(view?: ManifestSectionView) { + this.#activeViewPathname.next(view?.meta.pathname); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section.element.ts index 4b04b25ca2..8d30e70f66 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section.element.ts @@ -60,8 +60,8 @@ export class UmbSectionElement extends UmbLitElement { private _observeMenuItems() { if (!this._sectionContext) return; - this.observe(this._sectionContext?.manifest, (section) => { - this._observeSidebarMenuItem(section?.alias); + this.observe(this._sectionContext?.alias, (alias) => { + this._observeSidebarMenuItem(alias); }); this.observe(umbExtensionsRegistry.extensionsOfType('workspace'), (workspaceExtensions) => { @@ -142,7 +142,7 @@ export class UmbSectionElement extends UmbLitElement { if (!this._sectionContext) return; this.observe( - this._sectionContext.manifest.pipe( + this._sectionContext.alias.pipe( switchMap((section) => { if (!section) return EMPTY; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree-item.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree-item.element.ts index 4ae7b87aff..3b638b09bb 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree-item.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree-item.element.ts @@ -116,8 +116,8 @@ export class UmbTreeItem extends UmbLitElement { private _observeSection() { if (!this._sectionContext) return; - this.observe(this._sectionContext?.manifest, (section) => { - this._href = this._constructPath(section?.meta.pathname || '', this.entityType, this.key); + this.observe(this._sectionContext?.pathname, (pathname) => { + this._href = this._constructPath(pathname || '', this.entityType, this.key); }); }