From 7f5ed0e5eafc2989966e40ff80e3ac3aa0b86239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 22 Dec 2022 10:31:42 +0100 Subject: [PATCH] refactoring --- .../collection-selection-actions.element.ts | 33 ++--- .../collection/collection.context.ts | 119 ++++++++++++++++++ .../collection/collection.element.ts | 18 +-- .../collection-view-media-grid.element.ts | 22 ++-- .../collection-view-media-table.element.ts | 20 +-- .../dashboard-media-management.element.ts | 86 +++++-------- .../src/core/stores/store.ts | 9 +- 7 files changed, 204 insertions(+), 103 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/components/collection/collection.context.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/collection/collection-selection-actions.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/collection/collection-selection-actions.element.ts index 05f71063d6..bfead8d5a9 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/collection/collection-selection-actions.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/collection/collection-selection-actions.element.ts @@ -1,10 +1,10 @@ import { UUITextStyles } from '@umbraco-ui/uui-css'; import { css, html, LitElement, nothing } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; +import type { UmbCollectionContext } from './collection.context'; import { UmbContextConsumerMixin } from '@umbraco-cms/context-api'; import type { MediaDetails } from '@umbraco-cms/models'; import { UmbObserverMixin } from '@umbraco-cms/observable-api'; -import type { UmbDashboardMediaManagementElement } from 'src/backoffice/dashboards/media-management/dashboard-media-management.element'; @customElement('umb-collection-selection-actions') export class UmbCollectionSelectionActionsElement extends UmbContextConsumerMixin(UmbObserverMixin(LitElement)) { @@ -28,18 +28,18 @@ export class UmbCollectionSelectionActionsElement extends UmbContextConsumerMixi public entityType = 'media'; @state() - private _mediaItems: Array = []; + private _nodesLength = 0; @state() - private _selection: Array = []; + private _selectionLength = 0; - private _mediaContext?: UmbDashboardMediaManagementElement; + private _collectionContext?: UmbCollectionContext; constructor() { super(); - this.consumeAllContexts(['umbMediaContext'], (instance) => { - this._mediaContext = instance['umbMediaContext']; - this._observeMediaContext(); + this.consumeContext('umbCollectionContext', (instance) => { + this._collectionContext = instance; + this._observeCollectionContext(); }); } @@ -50,27 +50,28 @@ export class UmbCollectionSelectionActionsElement extends UmbContextConsumerMixi } private _handleClearSelection() { - this._mediaContext?.setSelection([]); + this._collectionContext?.setSelection([]); } - private _observeMediaContext() { - if (!this._mediaContext) return; + private _observeCollectionContext() { + if (!this._collectionContext) return; - this.observe>(this._mediaContext.mediaItems, (mediaItems) => { - this._mediaItems = mediaItems; + // TODO: Make sure it only updates on length change. + this.observe>(this._collectionContext.data, (mediaItems) => { + this._nodesLength = mediaItems.length; }); - this.observe>(this._mediaContext.selection, (selection) => { - this._selection = selection; + this.observe>(this._collectionContext.selection, (selection) => { + this._selectionLength = selection.length; }); } private _renderSelectionCount() { - return html`
${this._selection.length} of ${this._mediaItems.length} selected
`; + return html`
${this._selectionLength} of ${this._nodesLength} selected
`; } render() { - if (this._selection.length === 0) return nothing; + if (this._selectionLength === 0) return nothing; return html` = UmbTreeDataStore> { + + + private _target: HTMLElement; + private _entityKey:string; + + + protected _storeConsumer!:UmbContextConsumer; + private _store?: StoreType; + + private _data: BehaviorSubject> = new BehaviorSubject(>[]); + public readonly data: Observable> = this._data.asObservable(); + protected _dataObserver?:Subscription; + + + private _selection: BehaviorSubject> = new BehaviorSubject(>[]); + public readonly selection: Observable> = this._selection.asObservable(); + + /* + TODO: + private _search: BehaviorSubject = new BehaviorSubject(''); + public readonly search: Observable = this._search.asObservable(); + */ + + constructor(target:HTMLElement, entityKey: string, storeAlias:string) { + this._target = target; + this._entityKey = entityKey; + + this._storeConsumer = new UmbContextConsumer(this._target, storeAlias, (_instance: StoreType) => { + this._store = _instance; + if(!this._store) { + // TODO: if we keep the type assumption of _store existing, then we should here make sure to break the application in a good way. + return; + } + this._onStoreSubscription(); + }); + } + + connectedCallback() { + this._storeConsumer.attach(); + } + + disconnectedCallback() { + this._storeConsumer.detach(); + } + + + public getData() { + return this._data.getValue(); + } + + /* + public update(data: Partial) { + this._data.next({ ...this.getData(), ...data }); + } + */ + + protected _onStoreSubscription(): void { + if(!this._store) { + return; + } + + if (this._entityKey) { + this._dataObserver = this._store.getTreeItemChildren(this._entityKey).subscribe((nodes) => { + this._data.next(nodes); + }); + } else { + this._dataObserver = this._store.getTreeRoot().subscribe((nodes) => { + this._data.next(nodes); + }); + } + } + + + + /* + TODO: + public setSearch(value: string) { + if (!value) value = ''; + + this._search.next(value); + } + */ + + + public setSelection(value: Array) { + if (!value) return; + this._selection.next(value); + } + + public clearSelection() { + this._selection.next([]); + } + + public select(key: string) { + const selection = this._selection.getValue(); + this._selection.next([...selection, key]); + } + + public deselect(key: string) { + const selection = this._selection.getValue(); + this._selection.next(selection.filter((k) => k !== key)); + } + + + + + // TODO: how can we make sure to call this. + public destroy(): void { + this._data.unsubscribe(); + } + +} + diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/collection/collection.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/collection/collection.element.ts index a7a9f26b6a..30f4d94bdf 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/collection/collection.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/collection/collection.element.ts @@ -4,12 +4,12 @@ import { customElement, state, property } from 'lit/decorators.js'; import { map } from 'rxjs'; import './collection-selection-actions.element'; import './collection-toolbar.element'; +import type { UmbCollectionContext } from './collection.context'; import { createExtensionElement } from '@umbraco-cms/extensions-api'; -import type { ManifestCollectionView } from '@umbraco-cms/models'; +import type { ManifestCollectionView, MediaDetails } from '@umbraco-cms/models'; import { UmbObserverMixin } from '@umbraco-cms/observable-api'; import { umbExtensionsRegistry } from '@umbraco-cms/extensions-registry'; import { UmbContextConsumerMixin } from '@umbraco-cms/context-api'; -import type { UmbDashboardMediaManagementElement } from 'src/backoffice/dashboards/media-management/dashboard-media-management.element'; @customElement('umb-collection') export class UmbCollectionElement extends UmbContextConsumerMixin(UmbObserverMixin(LitElement)) { @@ -32,7 +32,7 @@ export class UmbCollectionElement extends UmbContextConsumerMixin(UmbObserverMix @state() private _selection: Array = []; - private _mediaContext?: UmbDashboardMediaManagementElement; + private _collectionContext?: UmbCollectionContext; private _entityType!: string; @@ -51,16 +51,16 @@ export class UmbCollectionElement extends UmbContextConsumerMixin(UmbObserverMix constructor() { super(); - this.consumeAllContexts(['umbMediaContext'], (instance) => { - this._mediaContext = instance['umbMediaContext']; - this._observeMediaContext(); + this.consumeContext('umbCollectionContext', (instance) => { + this._collectionContext = instance; + this._observeCollectionContext(); }); } - private _observeMediaContext() { - if (!this._mediaContext) return; + private _observeCollectionContext() { + if (!this._collectionContext) return; - this.observe>(this._mediaContext.selection, (selection) => { + this.observe>(this._collectionContext.selection, (selection) => { this._selection = selection; }); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/collection/views/collection-view-media-grid.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/collection/views/collection-view-media-grid.element.ts index a32abaa630..a55fe5d21c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/collection/views/collection-view-media-grid.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/collection/views/collection-view-media-grid.element.ts @@ -2,10 +2,10 @@ import { UUITextStyles } from '@umbraco-ui/uui-css'; import { css, html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { repeat } from 'lit/directives/repeat.js'; +import type { UmbCollectionContext } from '../collection.context'; import type { MediaDetails } from '@umbraco-cms/models'; import { UmbContextConsumerMixin } from '@umbraco-cms/context-api'; import { UmbObserverMixin } from '@umbraco-cms/observable-api'; -import type { UmbDashboardMediaManagementElement } from 'src/backoffice/dashboards/media-management/dashboard-media-management.element'; @customElement('umb-collection-view-media-grid') export class UmbCollectionViewsMediaGridElement extends UmbContextConsumerMixin(UmbObserverMixin(LitElement)) { @@ -71,7 +71,7 @@ export class UmbCollectionViewsMediaGridElement extends UmbContextConsumerMixin( @state() private _selection: Array = []; - private _mediaContext?: UmbDashboardMediaManagementElement; + private _collectionContext?: UmbCollectionContext; constructor() { super(); @@ -85,20 +85,20 @@ export class UmbCollectionViewsMediaGridElement extends UmbContextConsumerMixin( e.preventDefault(); this.toggleAttribute('dragging', false); }); - this.consumeAllContexts(['umbMediaContext'], (instance) => { - this._mediaContext = instance['umbMediaContext']; - this._observeMediaContext(); + this.consumeContext('umbCollectionContext', (instance) => { + this._collectionContext = instance; + this._observeCollectionContext(); }); } - private _observeMediaContext() { - if (!this._mediaContext) return; + private _observeCollectionContext() { + if (!this._collectionContext) return; - this.observe>(this._mediaContext.mediaItems, (mediaItems) => { + this.observe>(this._collectionContext.data, (mediaItems) => { this._mediaItems = mediaItems; }); - this.observe>(this._mediaContext.selection, (selection) => { + this.observe>(this._collectionContext.selection, (selection) => { this._selection = selection; }); } @@ -109,11 +109,11 @@ export class UmbCollectionViewsMediaGridElement extends UmbContextConsumerMixin( } private _handleSelect(mediaItem: MediaDetails) { - this._mediaContext?.select(mediaItem.key); + this._collectionContext?.select(mediaItem.key); } private _handleDeselect(mediaItem: MediaDetails) { - this._mediaContext?.deselect(mediaItem.key); + this._collectionContext?.deselect(mediaItem.key); } private _isSelected(mediaItem: MediaDetails) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/collection/views/collection-view-media-table.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/collection/views/collection-view-media-table.element.ts index 0fdbf8a73f..62c9fb45cb 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/collection/views/collection-view-media-table.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/collection/views/collection-view-media-table.element.ts @@ -1,10 +1,10 @@ import { UUITextStyles } from '@umbraco-ui/uui-css'; import { css, html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; +import type { UmbCollectionContext } from '../collection.context'; import { UmbContextConsumerMixin } from '@umbraco-cms/context-api'; import type { MediaDetails } from '@umbraco-cms/models'; import { UmbObserverMixin } from '@umbraco-cms/observable-api'; -import type { UmbDashboardMediaManagementElement } from 'src/backoffice/dashboards/media-management/dashboard-media-management.element'; @customElement('umb-collection-view-media-table') export class UmbCollectionViewMediaTableElement extends UmbContextConsumerMixin(UmbObserverMixin(LitElement)) { @@ -16,24 +16,24 @@ export class UmbCollectionViewMediaTableElement extends UmbContextConsumerMixin( @state() private _selection: Array = []; - private _mediaContext?: UmbDashboardMediaManagementElement; + private _collectionContext?: UmbCollectionContext; constructor() { super(); - this.consumeAllContexts(['umbMediaContext'], (instance) => { - this._mediaContext = instance['umbMediaContext']; - this._observeMediaContext(); + this.consumeContext('umbCollectionContext', (instance) => { + this._collectionContext = instance; + this._observeCollectionContext(); }); } - private _observeMediaContext() { - if (!this._mediaContext) return; + private _observeCollectionContext() { + if (!this._collectionContext) return; - this.observe>(this._mediaContext.mediaItems, (mediaItems) => { - this._mediaItems = mediaItems; + this.observe>(this._collectionContext.data, (nodes) => { + this._mediaItems = nodes; }); - this.observe>(this._mediaContext.selection, (selection) => { + this.observe>(this._collectionContext.selection, (selection) => { this._selection = selection; }); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/media-management/dashboard-media-management.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/media-management/dashboard-media-management.element.ts index c071c0c8ec..a1f73d1e94 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/media-management/dashboard-media-management.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/media-management/dashboard-media-management.element.ts @@ -2,11 +2,10 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { css, html, LitElement } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import '../../components/collection/collection.element'; -import { BehaviorSubject, Observable } from 'rxjs'; -import type { MediaDetails } from '@umbraco-cms/models'; import { UmbContextConsumerMixin, UmbContextProviderMixin } from '@umbraco-cms/context-api'; import { UmbObserverMixin } from '@umbraco-cms/observable-api'; -import { UmbMediaStore } from '@umbraco-cms/stores/media/media.store'; +import { UmbMediaStore, UmbMediaStoreItemType } from '@umbraco-cms/stores/media/media.store'; +import { UmbCollectionContext } from '@umbraco-cms/components/collection/collection.context'; @customElement('umb-dashboard-media-management') export class UmbDashboardMediaManagementElement extends UmbContextProviderMixin( @@ -25,68 +24,47 @@ export class UmbDashboardMediaManagementElement extends UmbContextProviderMixin( `, ]; + + private _collectionContext?:UmbCollectionContext; + + private _entityKey!: string; @property() - public entityKey = ''; + public get entityKey(): string { + return this._entityKey; + } + public set entityKey(value: string) { + this._entityKey = value; + this._provideWorkspace(); + } - private _mediaStore?: UmbMediaStore; - - private _selection: BehaviorSubject> = new BehaviorSubject(>[]); - public readonly selection: Observable> = this._selection.asObservable(); - - private _mediaItems: BehaviorSubject> = new BehaviorSubject(>[]); - public readonly mediaItems: Observable> = this._mediaItems.asObservable(); - - private _search: BehaviorSubject = new BehaviorSubject(''); - public readonly search: Observable = this._search.asObservable(); + constructor() { super(); - this.provideContext('umbMediaContext', this); - this.consumeAllContexts(['umbMediaStore'], (instance) => { - this._mediaStore = instance['umbMediaStore']; - this._observeMediaItems(); - }); + // TODO: subscribe selection. } - private _observeMediaItems() { - if (!this._mediaStore) return; - if (this.entityKey) { - this.observe>(this._mediaStore?.getTreeItemChildren(this.entityKey), (items) => { - this._mediaItems.next(items); - }); - } else { - this.observe>(this._mediaStore?.getTreeRoot(), (items) => { - this._mediaItems.next(items); - }); + connectedCallback(): void { + super.connectedCallback(); + // TODO: avoid this connection, our own approach on Lit-Controller could be handling this case. + this._collectionContext?.connectedCallback(); + } + disconnectedCallback(): void { + super.connectedCallback() + // TODO: avoid this connection, our own approach on Lit-Controller could be handling this case. + this._collectionContext?.disconnectedCallback(); + } + + + protected _provideWorkspace() { + if(this._entityKey) { + this._collectionContext = new UmbCollectionContext(this, this._entityKey, 'umbMediaStore'); + this.provideContext('umbCollectionContext', this._collectionContext); } } - public setSearch(value: string) { - if (!value) value = ''; - - this._search.next(value); - this._observeMediaItems(); - this.requestUpdate('search'); - } - - public setSelection(value: Array) { - if (!value) return; - this._selection.next(value); - this.requestUpdate('selection'); - } - - public select(key: string) { - const selection = this._selection.getValue(); - this._selection.next([...selection, key]); - this.requestUpdate('selection'); - } - - public deselect(key: string) { - const selection = this._selection.getValue(); - this._selection.next(selection.filter((k) => k !== key)); - this.requestUpdate('selection'); - } + render() { return html``; diff --git a/src/Umbraco.Web.UI.Client/src/core/stores/store.ts b/src/Umbraco.Web.UI.Client/src/core/stores/store.ts index 8e3ddad2fc..cfe8b81100 100644 --- a/src/Umbraco.Web.UI.Client/src/core/stores/store.ts +++ b/src/Umbraco.Web.UI.Client/src/core/stores/store.ts @@ -8,8 +8,11 @@ export interface UmbDataStoreIdentifiers { export interface UmbDataStore { readonly items: Observable>; updateItems(items: Array): void; - getTreeRoot?(): Observable>; - getTreeItemChildren?(key: string): Observable>; +} + +export interface UmbTreeDataStore extends UmbDataStore { + getTreeRoot(): Observable>; + getTreeItemChildren(key: string): Observable>; } /** @@ -87,4 +90,4 @@ export abstract class UmbNodeStoreBase extend * @memberof UmbNodeStoreBase */ abstract save(data: T[]): Promise; -} +} \ No newline at end of file