diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index f6339dca28..6713d77e6a 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -34,6 +34,7 @@ "./document-type": "./dist-cms/packages/documents/document-types/index.js", "./document": "./dist-cms/packages/documents/documents/index.js", "./dynamic-root": "./dist-cms/packages/dynamic-root/index.js", + "./entity": "./dist-cms/packages/core/entity/index.js", "./entity-action": "./dist-cms/packages/core/entity-action/index.js", "./entity-bulk-action": "./dist-cms/packages/core/entity-bulk-action/index.js", "./event": "./dist-cms/packages/core/event/index.js", diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action-list.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action-list.element.ts index 4db7611b63..b9c3f9d207 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action-list.element.ts @@ -1,3 +1,4 @@ +import { UmbEntityContext } from '@umbraco-cms/backoffice/entity'; import type { UmbEntityActionArgs } from './types.js'; import { html, customElement, property, state, css } from '@umbraco-cms/backoffice/external/lit'; import type { ManifestEntityAction, MetaEntityAction } from '@umbraco-cms/backoffice/extension-registry'; @@ -43,8 +44,13 @@ export class UmbEntityActionListElement extends UmbLitElement { [UmbEntityActionArgs] >; + #entityContext = new UmbEntityContext(this); + #generateApiArgs() { - if (!this._props.entityType || this._props.unique !== undefined) return; + if (!this._props.entityType || this._props.unique === undefined) return; + + this.#entityContext.setEntityType(this._props.entityType); + this.#entityContext.setUnique(this._props.unique); this._apiArgs = (manifest: ManifestEntityAction) => { return [{ entityType: this._props.entityType!, unique: this._props.unique!, meta: manifest.meta }]; @@ -59,7 +65,7 @@ export class UmbEntityActionListElement extends UmbLitElement { .filter=${this._filter} .elementProps=${this._props} .apiArgs=${this._apiArgs}> - ` + ` : ''; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity/entity.context-token.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity/entity.context-token.ts new file mode 100644 index 0000000000..252e6ef906 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity/entity.context-token.ts @@ -0,0 +1,4 @@ +import type { UmbEntityContext } from './entity.context.js'; +import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; + +export const UMB_ENTITY_CONTEXT = new UmbContextToken('UmbEntityContext'); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity/entity.context.test.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity/entity.context.test.ts new file mode 100644 index 0000000000..e01e1937b0 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity/entity.context.test.ts @@ -0,0 +1,77 @@ +import { expect } from '@open-wc/testing'; +import { UmbEntityContext } from './entity.context.js'; +import { UMB_ENTITY_CONTEXT } from './entity.context-token.js'; +import { Observable } from '@umbraco-cms/backoffice/external/rxjs'; +import { customElement } from '@umbraco-cms/backoffice/external/lit'; +import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api'; + +@customElement('umb-test-host') +export class UmbTestHostElement extends UmbElementMixin(HTMLElement) {} + +@customElement('umb-test-child') +export class UmbTestChildElement extends UmbElementMixin(HTMLElement) {} + +describe('UmbEntityContext', () => { + let context: UmbEntityContext; + let host: UmbTestHostElement; + let child: UmbTestChildElement; + + beforeEach(() => { + host = new UmbTestHostElement(); + child = new UmbTestChildElement(); + host.appendChild(child); + document.body.appendChild(host); + context = new UmbEntityContext(host); + }); + + describe('Public API', () => { + describe('properties', () => { + it('has a entity type property', () => { + expect(context).to.have.property('entityType').to.be.an.instanceOf(Observable); + }); + + it('has a unique property', () => { + expect(context).to.have.property('unique').to.be.an.instanceOf(Observable); + }); + }); + + describe('methods', () => { + it('has a getEntityType method', () => { + expect(context).to.have.property('getEntityType').that.is.a('function'); + }); + + it('has a setEntityType method', () => { + expect(context).to.have.property('setEntityType').that.is.a('function'); + }); + + it('has a getUnique method', () => { + expect(context).to.have.property('getUnique').that.is.a('function'); + }); + + it('has a setUnique method', () => { + expect(context).to.have.property('setUnique').that.is.a('function'); + }); + }); + }); + + describe('set and get entity type', () => { + it('should set entity type', () => { + context.setEntityType('entity-type'); + expect(context.getEntityType()).to.equal('entity-type'); + }); + }); + + describe('set and get unique', () => { + it('should set unique', () => { + context.setUnique('unique-value'); + expect(context.getUnique()).to.equal('unique-value'); + }); + }); + + describe('it is provided as a context', () => { + it('should be provided as a context', async () => { + const providedContext = await child.getContext(UMB_ENTITY_CONTEXT); + expect(providedContext).to.equal(context); + }); + }); +}); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity/entity.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity/entity.context.ts new file mode 100644 index 0000000000..8f193465ae --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity/entity.context.ts @@ -0,0 +1,63 @@ +import { UMB_ENTITY_CONTEXT } from './entity.context-token.js'; +import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { UmbStringState } from '@umbraco-cms/backoffice/observable-api'; + +/** + * Provides the entity context + * @export + * @class UmbEntityContext + * @extends {UmbContextBase} + */ +export class UmbEntityContext extends UmbContextBase { + #entityType = new UmbStringState(undefined); + public readonly entityType = this.#entityType.asObservable(); + + #unique = new UmbStringState(undefined); + public readonly unique = this.#unique.asObservable(); + + /** + * Creates an instance of UmbEntityContext. + * @param {UmbControllerHost} host + * @memberof UmbEntityContext + */ + constructor(host: UmbControllerHost) { + super(host, UMB_ENTITY_CONTEXT); + } + + /** + * Set the entity type + * @param {string | undefined} entityType + * @memberof UmbEntityContext + */ + setEntityType(entityType: string | undefined) { + this.#entityType.setValue(entityType); + } + + /** + * Get the entity type + * @returns {string | undefined} + * @memberof UmbEntityContext + */ + getEntityType(): string | undefined { + return this.#entityType.getValue(); + } + + /** + * Set the unique + * @param {string | null | undefined} unique + * @memberof UmbEntityContext + */ + setUnique(unique: string | null | undefined) { + this.#unique.setValue(unique); + } + + /** + * Get the unique + * @returns {string | null | undefined} + * @memberof UmbEntityContext + */ + getUnique() { + return this.#unique.getValue(); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity/index.ts new file mode 100644 index 0000000000..74308b50c9 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity/index.ts @@ -0,0 +1,2 @@ +export { UMB_ENTITY_CONTEXT } from './entity.context-token.js'; +export { UmbEntityContext } from './entity.context.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/section/section-sidebar-context-menu/section-sidebar-context-menu.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/section/section-sidebar-context-menu/section-sidebar-context-menu.element.ts index 02b1b834e0..574a0e7085 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/section/section-sidebar-context-menu/section-sidebar-context-menu.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/section/section-sidebar-context-menu/section-sidebar-context-menu.element.ts @@ -3,6 +3,7 @@ import { UMB_SECTION_SIDEBAR_CONTEXT } from '../section-sidebar/index.js'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { css, html, nothing, customElement, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { observeMultiple } from '@umbraco-cms/backoffice/observable-api'; @customElement('umb-section-sidebar-context-menu') export class UmbSectionSidebarContextMenuElement extends UmbLitElement { @@ -25,26 +26,37 @@ export class UmbSectionSidebarContextMenuElement extends UmbLitElement { this.consumeContext(UMB_SECTION_SIDEBAR_CONTEXT, (instance) => { this.#sectionSidebarContext = instance; + this.#observeEntityModel(); if (this.#sectionSidebarContext) { // make prettier not break the lines on the next 4 lines: // prettier-ignore this.observe( this.#sectionSidebarContext.contextMenuIsOpen, (value) => (this._isOpen = value), '_observeContextMenuIsOpen'); // prettier-ignore - this.observe(this.#sectionSidebarContext.unique, (value) => (this._unique = value), '_observeUnique'); - // prettier-ignore - this.observe(this.#sectionSidebarContext.entityType, (value) => (this._entityType = value), '_observeEntityType'); - // prettier-ignore this.observe(this.#sectionSidebarContext.headline, (value) => (this._headline = value), '_observeHeadline'); } else { this.removeUmbControllerByAlias('_observeContextMenuIsOpen'); - this.removeUmbControllerByAlias('_observeUnique'); - this.removeUmbControllerByAlias('_observeEntityType'); this.removeUmbControllerByAlias('_observeHeadline'); } }); } + #observeEntityModel() { + if (!this.#sectionSidebarContext) { + this.removeUmbControllerByAlias('_observeEntityModel'); + return; + } + + this.observe( + observeMultiple([this.#sectionSidebarContext.unique, this.#sectionSidebarContext.entityType]), + (values) => { + this._unique = values[0]; + this._entityType = values[1]; + }, + ), + '_observeEntityModel'; + } + #closeContextMenu() { this.#sectionSidebarContext?.closeContextMenu(); } @@ -70,7 +82,6 @@ export class UmbSectionSidebarContextMenuElement extends UmbLitElement { return this._isOpen ? html`
` : nothing; } - // TODO: allow different views depending on left or right click #renderModal() { return this._isOpen && this._unique !== undefined && this._entityType ? html`
diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts index 927acdbecb..c017ba460c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts @@ -1,3 +1,4 @@ +import { UmbEntityContext } from '@umbraco-cms/backoffice/entity'; import { UmbDocumentTypeDetailRepository } from '../../document-types/repository/detail/document-type-detail.repository.js'; import { UmbDocumentPropertyDataContext } from '../property-dataset-context/document-property-dataset-context.js'; import { UMB_DOCUMENT_ENTITY_TYPE } from '../entity.js'; @@ -132,6 +133,9 @@ export class UmbDocumentWorkspaceContext }, ); + // TODO: this should be set up for all entity workspace contexts in a base class + #entityContext = new UmbEntityContext(this); + constructor(host: UmbControllerHost) { super(host, UMB_DOCUMENT_WORKSPACE_ALIAS); @@ -162,6 +166,8 @@ export class UmbDocumentWorkspaceContext component: () => import('./document-workspace-editor.element.js'), setup: (_component, info) => { const unique = info.match.params.unique; + this.#entityContext.setEntityType(UMB_DOCUMENT_ENTITY_TYPE); + this.#entityContext.setUnique(unique); this.load(unique); }, }, diff --git a/src/Umbraco.Web.UI.Client/tsconfig.json b/src/Umbraco.Web.UI.Client/tsconfig.json index a3a4e7e517..2daf00620f 100644 --- a/src/Umbraco.Web.UI.Client/tsconfig.json +++ b/src/Umbraco.Web.UI.Client/tsconfig.json @@ -52,6 +52,7 @@ "@umbraco-cms/backoffice/document-type": ["./src/packages/documents/document-types/index.ts"], "@umbraco-cms/backoffice/document": ["./src/packages/documents/documents/index.ts"], "@umbraco-cms/backoffice/dynamic-root": ["./src/packages/dynamic-root/index.ts"], + "@umbraco-cms/backoffice/entity": ["./src/packages/core/entity/index.ts"], "@umbraco-cms/backoffice/entity-action": ["./src/packages/core/entity-action/index.ts"], "@umbraco-cms/backoffice/entity-bulk-action": ["./src/packages/core/entity-bulk-action/index.ts"], "@umbraco-cms/backoffice/event": ["./src/packages/core/event/index.ts"],