diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index b3af37461e..53124e8d2c 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -15,6 +15,7 @@ "@umbraco-ui/uui-modal-container": "file:umbraco-ui-uui-modal-container-0.0.0.tgz", "@umbraco-ui/uui-modal-dialog": "file:umbraco-ui-uui-modal-dialog-0.0.0.tgz", "@umbraco-ui/uui-modal-sidebar": "file:umbraco-ui-uui-modal-sidebar-0.0.0.tgz", + "deepmerge-ts": "^4.2.1", "element-internals-polyfill": "^1.1.9", "lit": "^2.3.1", "openapi-typescript-fetch": "^1.1.3", @@ -10897,6 +10898,14 @@ "node": ">=0.10.0" } }, + "node_modules/deepmerge-ts": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-4.2.1.tgz", + "integrity": "sha512-xzJLiUo4z1dD2nggSfaMvHo5qWLoy/JVa9rKuktC6FrQQEBI8Qnj7KwuCYZhqBoGOOpGqs6+3MR2ZhSMcTr4BA==", + "engines": { + "node": ">=12.4.0" + } + }, "node_modules/default-browser-id": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-1.0.4.tgz", @@ -34836,6 +34845,11 @@ "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", "dev": true }, + "deepmerge-ts": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-4.2.1.tgz", + "integrity": "sha512-xzJLiUo4z1dD2nggSfaMvHo5qWLoy/JVa9rKuktC6FrQQEBI8Qnj7KwuCYZhqBoGOOpGqs6+3MR2ZhSMcTr4BA==" + }, "default-browser-id": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-1.0.4.tgz", diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 37ad82bc6a..95d21270c4 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -42,6 +42,7 @@ "@umbraco-ui/uui-modal-container": "file:umbraco-ui-uui-modal-container-0.0.0.tgz", "@umbraco-ui/uui-modal-dialog": "file:umbraco-ui-uui-modal-dialog-0.0.0.tgz", "@umbraco-ui/uui-modal-sidebar": "file:umbraco-ui-uui-modal-sidebar-0.0.0.tgz", + "deepmerge-ts": "^4.2.1", "element-internals-polyfill": "^1.1.9", "lit": "^2.3.1", "openapi-typescript-fetch": "^1.1.3", diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/property-editors/property-editor-content-picker.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/property-editors/property-editor-content-picker.element.ts index 28cbb05053..bd2606a45b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/property-editors/property-editor-content-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/property-editors/property-editor-content-picker.element.ts @@ -1,9 +1,13 @@ import { css, html, LitElement } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { customElement, state } from 'lit/decorators.js'; +import { customElement, property, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../core/context'; import { UmbModalService } from '../../core/services/modal'; +import { UmbEntityStore } from '../../core/stores/entity.store'; +import { Subscription } from 'rxjs'; +import { NodeEntity } from '../../mocks/data/node.data'; +import { Entity } from '../../mocks/data/entity.data'; @customElement('umb-property-editor-content-picker') export class UmbPropertyEditorContentPicker extends UmbContextConsumerMixin(LitElement) { @@ -31,55 +35,82 @@ export class UmbPropertyEditorContentPicker extends UmbContextConsumerMixin(LitE `, ]; - private _modalService?: UmbModalService; + @property({ type: Array }) + public value: Array = []; @state() - private _selectedContent: any[] = []; + private _items: Array = []; + + private _modalService?: UmbModalService; + private _entityStore?: UmbEntityStore; + private _pickedEntitiesSubscription?: Subscription; constructor() { super(); this.consumeContext('umbModalService', (modalService: UmbModalService) => { this._modalService = modalService; }); - } - private _open() { - const modalHandler = this._modalService?.contentPicker({ multiple: true }); - modalHandler?.onClose.then(({ selection }: any) => { - this._selectedContent = [...this._selectedContent, ...selection]; - this.requestUpdate('_selectedContent'); + this.consumeContext('umbEntityStore', (entityStore: UmbEntityStore) => { + this._entityStore = entityStore; + this._observePickedEntities(); }); } - private _removeContent(index: number, content: any) { + private _observePickedEntities() { + this._pickedEntitiesSubscription?.unsubscribe(); + this._pickedEntitiesSubscription = this._entityStore?.getByKeys(this.value).subscribe((entities) => { + this._items = entities; + }); + } + + private _openPicker() { + const modalHandler = this._modalService?.contentPicker({ multiple: true }); + modalHandler?.onClose.then(({ selection }: any) => { + this._setValue([...this.value, ...selection]); + }); + } + + private _removeItem(item: Entity) { const modalHandler = this._modalService?.confirm({ color: 'danger', headline: 'Remove', confirmLabel: 'Remove', - content: html`Remove ${content.name}?`, + content: html`Remove ${item.name}?`, }); modalHandler?.onClose.then(({ confirmed }) => { if (confirmed) { - this._selectedContent.splice(index, 1); - this.requestUpdate('_selectedContent'); + const newValue = this.value.filter((value) => value !== item.key); + this._setValue(newValue); } }); } - private _renderContent(content: any, index: number) { + private _setValue(newValue: Array) { + this.value = newValue; + this._observePickedEntities(); + this.dispatchEvent(new CustomEvent('property-editor-change', { bubbles: true, composed: true })); + } + + disconnectedCallback() { + super.disconnectedCallback(); + this._pickedEntitiesSubscription?.unsubscribe(); + } + + private _renderItem(item: Entity) { return html` - + - this._removeContent(index, content)}>Remove + this._removeItem(item)}>Remove `; } render() { - return html`${this._selectedContent.map((content, index) => this._renderContent(content, index))} - Add`; + return html`${this._items.map((item) => this._renderItem(item))} + Add`; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tree/data-types/tree-data-types.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tree/data-types/tree-data-types.context.ts index b893124a15..60f60b3496 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/tree/data-types/tree-data-types.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tree/data-types/tree-data-types.context.ts @@ -5,7 +5,7 @@ import { UmbTreeContext } from '../tree.context'; export class UmbTreeDataTypesContext implements UmbTreeContext { public entityStore: UmbEntityStore; - private _entityType = 'dataType'; + private _rootKey = '29d78e6c-c1bf-4c15-b820-d511c237ffae'; constructor(entityStore: UmbEntityStore) { this.entityStore = entityStore; @@ -13,23 +13,20 @@ export class UmbTreeDataTypesContext implements UmbTreeContext { public fetchRoot() { const data = { - id: -1, - key: '3fd3eba5-c893-4d3c-af67-f574e6eded38', + key: this._rootKey, name: 'Data Types', hasChildren: true, - type: 'dataType', + type: 'dataTypeRoot', icon: 'favorite', parentKey: '', }; this.entityStore.update([data]); - return this.entityStore.entities.pipe( - map((items) => items.filter((item) => item.type === this._entityType && item.parentKey === '')) - ); + return this.entityStore.entities.pipe(map((items) => items.filter((item) => item.key === this._rootKey))); } - public fetchChildren(key: string) { + public fetchChildren(key = '') { // TODO: figure out url structure - fetch(`/umbraco/backoffice/entities?type=${this._entityType}&parentKey=${key}`) + fetch(`/umbraco/backoffice/entities/data-types?parentKey=${key}`) .then((res) => res.json()) .then((data) => { this.entityStore.update(data); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tree/document-types/tree-document-types.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tree/document-types/tree-document-types.context.ts index 2079409a12..ef7a90ea90 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/tree/document-types/tree-document-types.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tree/document-types/tree-document-types.context.ts @@ -5,7 +5,7 @@ import { UmbTreeContext } from '../tree.context'; export class UmbTreeDocumentTypesContext implements UmbTreeContext { public entityStore: UmbEntityStore; - private _entityType = 'documentType'; + private _rootKey = 'f50eb86d-3ef2-4011-8c5d-c56c04eec0da'; constructor(entityStore: UmbEntityStore) { this.entityStore = entityStore; @@ -13,23 +13,20 @@ export class UmbTreeDocumentTypesContext implements UmbTreeContext { public fetchRoot() { const data = { - id: -1, - key: '055a17d0-525a-4d06-9f75-92dc174ab0bd', + key: this._rootKey, name: 'Document Types', hasChildren: true, - type: 'documentType', + type: 'documentTypeRoot', icon: 'favorite', parentKey: '', }; this.entityStore.update([data]); - return this.entityStore.entities.pipe( - map((items) => items.filter((item) => item.type === this._entityType && item.parentKey === '')) - ); + return this.entityStore.entities.pipe(map((items) => items.filter((item) => item.key === this._rootKey))); } public fetchChildren(key: string) { // TODO: figure out url structure - fetch(`/umbraco/backoffice/entities?type=${this._entityType}&parentKey=${key}`) + fetch(`/umbraco/backoffice/entities/document-types?parentKey=${key}`) .then((res) => res.json()) .then((data) => { this.entityStore.update(data); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tree/document/tree-document.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tree/document/tree-document.context.ts index 4b10210045..4587ef6267 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/tree/document/tree-document.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tree/document/tree-document.context.ts @@ -5,27 +5,27 @@ import { UmbTreeContext } from '../tree.context'; export class UmbTreeDocumentContext implements UmbTreeContext { public entityStore: UmbEntityStore; - private _entityType = 'document'; + private _rootKey = 'ba23245c-d8c0-46f7-a2bc-7623743d6eba'; constructor(entityStore: UmbEntityStore) { this.entityStore = entityStore; } public fetchRoot() { - fetch(`/umbraco/backoffice/entities?type=${this._entityType}&parentKey=`) + fetch(`/umbraco/backoffice/entities/documents?parentKey=${this._rootKey}`) .then((res) => res.json()) .then((data) => { this.entityStore.update(data); }); return this.entityStore.entities.pipe( - map((items) => items.filter((item) => item.type === this._entityType && item.parentKey === '' && !item.isTrashed)) + map((items) => items.filter((item) => item.parentKey === this._rootKey && !item.isTrashed)) ); } public fetchChildren(key: string) { // TODO: figure out url structure - fetch(`/umbraco/backoffice/entities?type=${this._entityType}&parentKey=${key}`) + fetch(`/umbraco/backoffice/entities/documents?parentKey=${key}`) .then((res) => res.json()) .then((data) => { this.entityStore.update(data); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tree/extensions/tree-extensions.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tree/extensions/tree-extensions.context.ts index 43f5111d19..97658f084b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/tree/extensions/tree-extensions.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tree/extensions/tree-extensions.context.ts @@ -5,7 +5,7 @@ import { UmbTreeContext } from '../tree.context'; export class UmbTreeExtensionsContext implements UmbTreeContext { public entityStore: UmbEntityStore; - private _entityType = 'extension'; + private _rootKey = 'fd32ea8b-893b-4ee9-b1d0-72f41c4a6d38'; constructor(entityStore: UmbEntityStore) { this.entityStore = entityStore; @@ -13,8 +13,7 @@ export class UmbTreeExtensionsContext implements UmbTreeContext { public fetchRoot() { const data = { - id: -1, - key: 'fd32ea8b-893b-4ee9-b1d0-72f41c4a6d38', + key: this._rootKey, name: 'Extensions', hasChildren: false, type: 'extensionsList', @@ -22,19 +21,6 @@ export class UmbTreeExtensionsContext implements UmbTreeContext { parentKey: '', }; this.entityStore.update([data]); - - return this.entityStore.entities.pipe( - map((items) => items.filter((item) => item.type === 'extensionsList' && item.parentKey === '')) - ); - } - - public fetchChildren(key: string) { - fetch(`/umbraco/backoffice/entities?type=${this._entityType}&parentKey=${key}`) - .then((res) => res.json()) - .then((data) => { - this.entityStore.update(data); - }); - - return this.entityStore.entities.pipe(map((items) => items.filter((item) => item.parentKey === key))); + return this.entityStore.entities.pipe(map((items) => items.filter((item) => item.key === this._rootKey))); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tree/media/tree-media.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tree/media/tree-media.context.ts index 13613fc291..a19820ed2b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/tree/media/tree-media.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tree/media/tree-media.context.ts @@ -5,27 +5,25 @@ import { UmbTreeContext } from '../tree.context'; export class UmbTreeMediaContext implements UmbTreeContext { public entityStore: UmbEntityStore; - private _entityType = 'media'; + private _rootKey = 'c0858d71-52be-4bb2-822f-42fa0c9a1ea5'; constructor(entityStore: UmbEntityStore) { this.entityStore = entityStore; } public fetchRoot() { - fetch(`/umbraco/backoffice/entities?type=${this._entityType}&parentKey=`) + fetch(`/umbraco/backoffice/entities/media?parentKey=${this._rootKey}`) .then((res) => res.json()) .then((data) => { this.entityStore.update(data); }); - return this.entityStore.entities.pipe( - map((items) => items.filter((item) => item.type === this._entityType && item.parentKey === '')) - ); + return this.entityStore.entities.pipe(map((items) => items.filter((item) => item.parentKey === this._rootKey))); } public fetchChildren(key: string) { // TODO: figure out url structure - fetch(`/umbraco/backoffice/entities?type=${this._entityType}&parentKey=${key}`) + fetch(`/umbraco/backoffice/entities/media?parentKey=${key}`) .then((res) => res.json()) .then((data) => { this.entityStore.update(data); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tree/member-groups/tree-member-groups.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tree/member-groups/tree-member-groups.context.ts index 1fcd2fbd9f..481fe32d36 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/tree/member-groups/tree-member-groups.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tree/member-groups/tree-member-groups.context.ts @@ -5,7 +5,7 @@ import { UmbTreeContext } from '../tree.context'; export class UmbTreeMemberGroupsContext implements UmbTreeContext { public entityStore: UmbEntityStore; - private _entityType = 'memberGroup'; + private _rootKey = '575645a5-0f25-4671-b9a0-be515096ad6b'; constructor(entityStore: UmbEntityStore) { this.entityStore = entityStore; @@ -13,24 +13,21 @@ export class UmbTreeMemberGroupsContext implements UmbTreeContext { public fetchRoot() { const data = { - id: -1, - key: 'd46d144e-33d8-41e3-bf7a-545287e16e3c', + key: this._rootKey, name: 'Member Groups', hasChildren: true, - type: 'memberGroup', + type: 'memberGroupRoot', icon: 'favorite', parentKey: '', }; this.entityStore.update([data]); - return this.entityStore.entities.pipe( - map((items) => items.filter((item) => item.type === this._entityType && item.parentKey === '')) - ); + return this.entityStore.entities.pipe(map((items) => items.filter((item) => item.key === this._rootKey))); } public fetchChildren(key: string) { // TODO: figure out url structure - fetch(`/umbraco/backoffice/entities?type=${this._entityType}&parentKey=${key}`) + fetch(`/umbraco/backoffice/entities/member-groups?parentKey=${key}`) .then((res) => res.json()) .then((data) => { this.entityStore.update(data); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tree/members/tree-members.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tree/members/tree-members.context.ts index df113125f5..b18bca6331 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/tree/members/tree-members.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tree/members/tree-members.context.ts @@ -5,7 +5,7 @@ import { UmbTreeContext } from '../tree.context'; export class UmbTreeMembersContext implements UmbTreeContext { public entityStore: UmbEntityStore; - private _entityType = 'member'; + private _rootKey = '8f974b62-392b-4ddd-908c-03c2e03ab1a6'; constructor(entityStore: UmbEntityStore) { this.entityStore = entityStore; @@ -13,8 +13,7 @@ export class UmbTreeMembersContext implements UmbTreeContext { public fetchRoot() { const data = { - id: -1, - key: '24fcd88a-d1bb-423b-b794-8a94dcddcb6a', + key: this._rootKey, parentKey: '', name: 'Members', hasChildren: true, @@ -22,14 +21,12 @@ export class UmbTreeMembersContext implements UmbTreeContext { icon: 'favorite', }; this.entityStore.update([data]); - return this.entityStore.entities.pipe( - map((items) => items.filter((item) => item.type === this._entityType && item.parentKey === '')) - ); + return this.entityStore.entities.pipe(map((items) => items.filter((item) => item.key === this._rootKey))); } public fetchChildren(key: string) { // TODO: figure out url structure - fetch(`/umbraco/backoffice/entities?type=${this._entityType}&parentKey=${key}`) + fetch(`/umbraco/backoffice/entities/members?parentKey=${key}`) .then((res) => res.json()) .then((data) => { this.entityStore.update(data); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tree/shared/tree-item.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tree/shared/tree-item.element.ts index 55afe27adf..54b74b03b4 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/tree/shared/tree-item.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tree/shared/tree-item.element.ts @@ -61,6 +61,14 @@ export class UmbTreeItem extends UmbContextConsumerMixin(LitElement) { }); } + connectedCallback(): void { + super.connectedCallback(); + this.addEventListener('selected', (e) => { + e.stopPropagation(); + this.dispatchEvent(new CustomEvent('select', { bubbles: true, composed: true })); + }); + } + private _useSection() { this._sectionSubscription?.unsubscribe(); @@ -82,7 +90,7 @@ export class UmbTreeItem extends UmbContextConsumerMixin(LitElement) { this._childrenSubscription?.unsubscribe(); - this._childrenSubscription = this._treeContext?.fetchChildren(this.itemKey).subscribe((items) => { + this._childrenSubscription = this._treeContext?.fetchChildren?.(this.itemKey).subscribe((items) => { if (items?.length === 0) return; this._childItems = items; this._loading = false; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tree/shared/tree-navigator.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tree/shared/tree-navigator.element.ts index 5e462f765d..63237d5436 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/tree/shared/tree-navigator.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tree/shared/tree-navigator.element.ts @@ -32,7 +32,7 @@ export class UmbTreeNavigator extends UmbContextConsumerMixin(LitElement) { private _observeTreeRoot() { this._loading = true; - this._treeRootSubscription = this._treeContext?.fetchRoot().subscribe((items) => { + this._treeRootSubscription = this._treeContext?.fetchRoot?.().subscribe((items) => { if (items?.length === 0) return; this._items = items; this._loading = false; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tree/tree.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tree/tree.context.ts index f99d53d6f9..dfe8fb322f 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/tree/tree.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tree/tree.context.ts @@ -4,6 +4,6 @@ import { Entity } from '../../mocks/data/entity.data'; export interface UmbTreeContext { entityStore: UmbEntityStore; - fetchRoot(): Observable; - fetchChildren(key: string): Observable; + fetchRoot?(): Observable; + fetchChildren?(key: string): Observable; } diff --git a/src/Umbraco.Web.UI.Client/src/core/services/modal/layouts/content-picker/modal-layout-content-picker.element.ts b/src/Umbraco.Web.UI.Client/src/core/services/modal/layouts/content-picker/modal-layout-content-picker.element.ts index 176bc76aee..cb5d3a1c53 100644 --- a/src/Umbraco.Web.UI.Client/src/core/services/modal/layouts/content-picker/modal-layout-content-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/core/services/modal/layouts/content-picker/modal-layout-content-picker.element.ts @@ -46,46 +46,31 @@ export class UmbModalLayoutContentPickerElement extends UmbModalLayoutElement = []; - private _clickContent(content: any) { - if (this._selectedContent.includes(content)) { - this._selectedContent = this._selectedContent.filter((c) => c !== content); + private _handleSelect(e: CustomEvent) { + e.stopPropagation(); + const item = e.composedPath()?.[0] as any; + const key = item.itemKey; + this._select(key); + } + + private _select(key: string) { + // TODO: implement single selection + if (this._selection.includes(key)) { + this._selection = this._selection.filter((c) => c !== key); } else { - this._selectedContent.push(content); + this._selection.push(key); } - - this.requestUpdate('_selectedContent'); } private _submit() { - this.modalHandler?.close({ selection: this._selectedContent }); + this.modalHandler?.close({ selection: this._selection }); } private _close() { - this.modalHandler?.close(); + this.modalHandler?.close({ selection: this._selection }); } render() { @@ -96,7 +81,7 @@ export class UmbModalLayoutContentPickerElement extends UmbModalLayoutElement
- +
diff --git a/src/Umbraco.Web.UI.Client/src/core/stores/entity.store.ts b/src/Umbraco.Web.UI.Client/src/core/stores/entity.store.ts index 35ada7a1a2..eea162238b 100644 --- a/src/Umbraco.Web.UI.Client/src/core/stores/entity.store.ts +++ b/src/Umbraco.Web.UI.Client/src/core/stores/entity.store.ts @@ -1,10 +1,17 @@ -import { BehaviorSubject, Observable } from 'rxjs'; +import { BehaviorSubject, Observable, map } from 'rxjs'; import { Entity } from '../../mocks/data/entity.data'; +import { deepmerge } from 'deepmerge-ts'; export class UmbEntityStore { private _entities: BehaviorSubject> = new BehaviorSubject(>[]); public readonly entities: Observable> = this._entities.asObservable(); + getByKeys(keys: Array): Observable> { + return this.entities.pipe( + map((entities: Array) => entities.filter((entity: Entity) => keys.includes(entity.key))) + ); + } + update(entities: Array) { this._updateStore(entities); } @@ -17,9 +24,8 @@ export class UmbEntityStore { const index = storedItems.map((storedNode) => storedNode.key).indexOf(updatedItem.key); if (index !== -1) { - // TODO consider deep merge const entityKeys = Object.keys(storedItems[index]); - const mergedData = Object.assign(storedItems[index], updatedItem); + const mergedData = deepmerge(storedItems[index], updatedItem); for (const [key] of Object.entries(mergedData)) { if (entityKeys.indexOf(key) === -1) { diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/data.ts index 88adc3312d..3a264b6606 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/data.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/data.ts @@ -1,7 +1,9 @@ import { entities } from './entities'; +import { deepmerge } from 'deepmerge-ts'; +import { Entity } from './entity.data'; // Temp mocked database -export class UmbData { +export class UmbData { private _data: Array = []; constructor(data: Array) { @@ -42,13 +44,12 @@ export class UmbData } private _updateEntity(saveItem: T) { - // TODO consider deep merge const entityIndex = entities.findIndex((item) => item.key === saveItem.key); const entity = entities[entityIndex]; if (!entity) return; const entityKeys = Object.keys(entity); - const mergedData = Object.assign(entity, saveItem); + const mergedData = deepmerge(entity, saveItem); for (const [key] of Object.entries(mergedData)) { if (entityKeys.indexOf(key) === -1) { diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/entities.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/entities.ts index c3d774665b..6f474a87f0 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/entities.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/entities.ts @@ -5,7 +5,7 @@ export const entities: Array = [ id: 1, key: '865a11f9-d140-4f21-8dfe-2caafc65a971', type: 'member', - parentKey: '24fcd88a-d1bb-423b-b794-8a94dcddcb6a', + parentKey: '8f974b62-392b-4ddd-908c-03c2e03ab1a6', name: 'Member 1', hasChildren: false, isTrashed: false, @@ -14,16 +14,16 @@ export const entities: Array = [ id: 2, key: '06c6919c-6fa7-4aa5-8214-0582c721c472', type: 'member', - parentKey: '24fcd88a-d1bb-423b-b794-8a94dcddcb6a', + parentKey: '8f974b62-392b-4ddd-908c-03c2e03ab1a6', name: 'Member 2', - hasChildren: true, + hasChildren: false, isTrashed: false, }, { id: 3, key: '725a26c4-158d-4dc0-8aaa-b64473b11aa8', type: 'member', - parentKey: '06c6919c-6fa7-4aa5-8214-0582c721c472', + parentKey: '8f974b62-392b-4ddd-908c-03c2e03ab1a6', name: 'Member 3', hasChildren: false, isTrashed: false, @@ -31,7 +31,7 @@ export const entities: Array = [ { id: 4, key: '14be0f66-1472-452a-abde-9da6b4136073', - parentKey: 'd46d144e-33d8-41e3-bf7a-545287e16e3c', + parentKey: '575645a5-0f25-4671-b9a0-be515096ad6b', type: 'memberGroup', name: 'Member Group 1', hasChildren: false, @@ -40,7 +40,7 @@ export const entities: Array = [ { id: 5, key: '8d5cf29a-e73b-4bf5-ad56-8adf6cbf8766', - parentKey: 'd46d144e-33d8-41e3-bf7a-545287e16e3c', + parentKey: '575645a5-0f25-4671-b9a0-be515096ad6b', type: 'memberGroup', name: 'Member Group 2', hasChildren: false, @@ -49,7 +49,7 @@ export const entities: Array = [ { id: 1245, key: 'dt-1', - parentKey: '3fd3eba5-c893-4d3c-af67-f574e6eded38', + parentKey: '29d78e6c-c1bf-4c15-b820-d511c237ffae', name: 'Text', hasChildren: false, isTrashed: false, @@ -58,7 +58,7 @@ export const entities: Array = [ { id: 1244, key: 'dt-2', - parentKey: '3fd3eba5-c893-4d3c-af67-f574e6eded38', + parentKey: '29d78e6c-c1bf-4c15-b820-d511c237ffae', name: 'Textarea', hasChildren: false, isTrashed: false, @@ -67,7 +67,7 @@ export const entities: Array = [ { id: 1246, key: 'dt-3', - parentKey: '3fd3eba5-c893-4d3c-af67-f574e6eded38', + parentKey: '29d78e6c-c1bf-4c15-b820-d511c237ffae', name: 'My JS Property Editor', hasChildren: false, isTrashed: false, @@ -76,7 +76,7 @@ export const entities: Array = [ { id: 1247, key: 'dt-4', - parentKey: '3fd3eba5-c893-4d3c-af67-f574e6eded38', + parentKey: '29d78e6c-c1bf-4c15-b820-d511c237ffae', name: 'Context Example', hasChildren: false, isTrashed: false, @@ -85,7 +85,7 @@ export const entities: Array = [ { id: 1248, key: 'dt-5', - parentKey: '3fd3eba5-c893-4d3c-af67-f574e6eded38', + parentKey: '29d78e6c-c1bf-4c15-b820-d511c237ffae', name: 'Content Picker (DataType)', hasChildren: false, isTrashed: false, @@ -98,7 +98,7 @@ export const entities: Array = [ type: 'documentType', hasChildren: false, isTrashed: false, - parentKey: '055a17d0-525a-4d06-9f75-92dc174ab0bd', + parentKey: 'f50eb86d-3ef2-4011-8c5d-c56c04eec0da', }, { id: 100, @@ -107,7 +107,7 @@ export const entities: Array = [ type: 'documentType', hasChildren: false, isTrashed: false, - parentKey: '055a17d0-525a-4d06-9f75-92dc174ab0bd', + parentKey: 'f50eb86d-3ef2-4011-8c5d-c56c04eec0da', }, { id: 2001, @@ -117,7 +117,7 @@ export const entities: Array = [ icon: 'picture', hasChildren: false, isTrashed: false, - parentKey: '', + parentKey: 'c0858d71-52be-4bb2-822f-42fa0c9a1ea5', }, { id: 2002, @@ -127,7 +127,7 @@ export const entities: Array = [ icon: 'picture', hasChildren: false, isTrashed: false, - parentKey: '', + parentKey: 'c0858d71-52be-4bb2-822f-42fa0c9a1ea5', }, { id: 1, @@ -137,7 +137,7 @@ export const entities: Array = [ icon: 'document', hasChildren: false, isTrashed: false, - parentKey: '', + parentKey: 'ba23245c-d8c0-46f7-a2bc-7623743d6eba', }, { id: 2, @@ -147,7 +147,7 @@ export const entities: Array = [ icon: 'favorite', hasChildren: false, isTrashed: false, - parentKey: '', + parentKey: 'ba23245c-d8c0-46f7-a2bc-7623743d6eba', }, { id: 3, @@ -157,6 +157,6 @@ export const entities: Array = [ icon: 'document', hasChildren: false, isTrashed: false, - parentKey: '', + parentKey: 'ba23245c-d8c0-46f7-a2bc-7623743d6eba', }, ]; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/domains/entity.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/domains/entity.handlers.ts index de9120a066..3bd26cefef 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/domains/entity.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/domains/entity.handlers.ts @@ -3,11 +3,39 @@ import { umbEntityData } from '../data/entity.data'; // TODO: add schema export const handlers = [ - rest.get('/umbraco/backoffice/entities', (req, res, ctx) => { + rest.get('/umbraco/backoffice/entities/documents', (req, res, ctx) => { console.warn('Please move to schema'); - const entityType = req.url.searchParams.get('type') ?? ''; - const parentKey = req.url.searchParams.get('parentKey') ?? ''; - const entities = umbEntityData.getItems(entityType, parentKey); - return res(ctx.status(200), ctx.json(entities)); + return handleRequest('document', req, res, ctx); + }), + + rest.get('/umbraco/backoffice/entities/media', (req, res, ctx) => { + console.warn('Please move to schema'); + return handleRequest('media', req, res, ctx); + }), + + rest.get('/umbraco/backoffice/entities/members', (req, res, ctx) => { + console.warn('Please move to schema'); + return handleRequest('member', req, res, ctx); + }), + + rest.get('/umbraco/backoffice/entities/member-groups', (req, res, ctx) => { + console.warn('Please move to schema'); + return handleRequest('memberGroup', req, res, ctx); + }), + + rest.get('/umbraco/backoffice/entities/data-types', (req, res, ctx) => { + console.warn('Please move to schema'); + return handleRequest('dataType', req, res, ctx); + }), + + rest.get('/umbraco/backoffice/entities/document-types', (req, res, ctx) => { + console.warn('Please move to schema'); + return handleRequest('documentType', req, res, ctx); }), ]; + +const handleRequest = (entityType: string, req: any, res: any, ctx: any) => { + const parentKey = req.url.searchParams.get('parentKey') ?? ''; + const entities = umbEntityData.getItems(entityType, parentKey); + return res(ctx.status(200), ctx.json(entities)); +};