diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/structure/content-type-property-structure-helper.class.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/structure/content-type-property-structure-helper.class.ts index 5a03b13c6ef3..120b81481437 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/structure/content-type-property-structure-helper.class.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/structure/content-type-property-structure-helper.class.ts @@ -26,6 +26,7 @@ export class UmbContentTypePropertyStructureHelper([], (x) => x.unique); readonly propertyStructure = this.#propertyStructure.asObservable(); + readonly propertyAliases = this.#propertyStructure.asObservablePart((x) => x.map((e) => e.alias)); constructor(host: UmbControllerHost) { super(host); diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content/global-components/content-workspace-property.element.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content/global-components/content-workspace-property.element.ts new file mode 100644 index 000000000000..df128bc49016 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content/global-components/content-workspace-property.element.ts @@ -0,0 +1,136 @@ +import { UMB_CONTENT_WORKSPACE_CONTEXT } from '../constants.js'; +import { html, customElement, property, state, nothing } from '@umbraco-cms/backoffice/external/lit'; +import type { UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property'; +import { UmbVariantId } from '@umbraco-cms/backoffice/variant'; +import { UmbDataPathPropertyValueQuery } from '@umbraco-cms/backoffice/validation'; + +@customElement('umb-content-workspace-property') +export class UmbContentWorkspacePropertyElement extends UmbLitElement { + private _alias?: string | undefined; + + @property({ type: String, attribute: 'alias' }) + public get alias(): string | undefined { + return this._alias; + } + public set alias(value: string | undefined) { + this._alias = value; + this.#observePropertyType(); + } + + @state() + _datasetVariantId?: UmbVariantId; + + @state() + _dataPath?: string; + + @state() + _viewable?: boolean; + + @state() + _writeable?: boolean; + + @state() + _workspaceContext?: typeof UMB_CONTENT_WORKSPACE_CONTEXT.TYPE; + + @state() + _propertyType?: UmbPropertyTypeModel; + + constructor() { + super(); + + // The Property Dataset is local to the active variant, we use this to retrieve the variant we like to gather the value from. + this.consumeContext(UMB_PROPERTY_DATASET_CONTEXT, (datasetContext) => { + this._datasetVariantId = datasetContext?.getVariantId(); + }); + + // The Content Workspace Context is used to retrieve the property type we like to observe. + // This gives us the configuration from the property type as part of the data type. + this.consumeContext(UMB_CONTENT_WORKSPACE_CONTEXT, async (workspaceContext) => { + this._workspaceContext = workspaceContext; + this.#observePropertyType(); + }); + } + + async #observePropertyType() { + if (!this._alias || !this._workspaceContext) return; + + this.observe(await this._workspaceContext?.structure.propertyStructureByAlias(this._alias), (propertyType) => { + this._propertyType = propertyType; + this.#checkViewGuard(); + }); + } + + #checkViewGuard() { + if (!this._workspaceContext || !this._propertyType || !this._datasetVariantId) return; + + const propertyVariantId = new UmbVariantId( + this._propertyType.variesByCulture ? this._datasetVariantId.culture : null, + this._propertyType.variesBySegment ? this._datasetVariantId.segment : null, + ); + + this.observe( + this._workspaceContext.propertyViewGuard.isPermittedForVariantAndProperty( + propertyVariantId, + this._propertyType, + this._datasetVariantId, + ), + (permitted) => { + this._viewable = permitted; + }, + `umbObservePropertyViewGuard`, + ); + } + + override willUpdate(changedProperties: Map) { + super.willUpdate(changedProperties); + if ( + changedProperties.has('_propertyType') || + changedProperties.has('_datasetVariantId') || + changedProperties.has('_workspaceContext') + ) { + if (this._datasetVariantId && this._propertyType && this._workspaceContext) { + const propertyVariantId = new UmbVariantId( + this._propertyType.variesByCulture ? this._datasetVariantId.culture : null, + this._propertyType.variesBySegment ? this._datasetVariantId.segment : null, + ); + this._dataPath = `$.values[${UmbDataPathPropertyValueQuery({ + alias: this._propertyType.alias, + culture: propertyVariantId.culture, + segment: propertyVariantId.segment, + })}].value`; + + this.observe( + this._workspaceContext.propertyWriteGuard.isPermittedForVariantAndProperty( + propertyVariantId, + this._propertyType, + propertyVariantId, + ), + (write) => { + this._writeable = write; + }, + 'observeView', + ); + } + } + } + + override render() { + if (!this._viewable) return nothing; + if (!this._dataPath || this._writeable === undefined) return nothing; + + return html``; + } +} + +export default UmbContentWorkspacePropertyElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-content-workspace-property': UmbContentWorkspacePropertyElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content/global-components/index.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content/global-components/index.ts new file mode 100644 index 000000000000..4ad34abcf309 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content/global-components/index.ts @@ -0,0 +1 @@ +export * from './content-workspace-property.element.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content/index.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content/index.ts index d9a9888ec030..f87b3be75a24 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/content/content/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content/index.ts @@ -2,9 +2,11 @@ export * from './collection/index.js'; export * from './components/index.js'; export * from './constants.js'; export * from './controller/merge-content-variant-data.controller.js'; +export * from './global-components/index.js'; export * from './manager/index.js'; export * from './property-dataset-context/index.js'; export * from './workspace/index.js'; + export type * from './repository/index.js'; export type * from './types.js'; export type * from './variant-picker/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content/workspace/views/edit/content-editor-properties.element.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content/workspace/views/edit/content-editor-properties.element.ts index 797722426c0b..451be57c5a81 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/content/content/workspace/views/edit/content-editor-properties.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content/workspace/views/edit/content-editor-properties.element.ts @@ -1,5 +1,5 @@ import { UMB_CONTENT_WORKSPACE_CONTEXT } from '../../content-workspace.context-token.js'; -import { css, html, customElement, property, state, repeat, nothing } from '@umbraco-cms/backoffice/external/lit'; +import { css, html, customElement, property, state, repeat } from '@umbraco-cms/backoffice/external/lit'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import type { UmbContentTypeModel, @@ -8,17 +8,10 @@ import type { } from '@umbraco-cms/backoffice/content-type'; import { UmbContentTypePropertyStructureHelper } from '@umbraco-cms/backoffice/content-type'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; -import { UmbVariantId } from '@umbraco-cms/backoffice/variant'; -import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property'; - -import './content-editor-property.element.js'; @customElement('umb-content-workspace-view-edit-properties') export class UmbContentWorkspaceViewEditPropertiesElement extends UmbLitElement { - #workspaceContext?: typeof UMB_CONTENT_WORKSPACE_CONTEXT.TYPE; #propertyStructureHelper = new UmbContentTypePropertyStructureHelper(this); - #properties?: Array; - #visiblePropertiesUniques: Array = []; @property({ type: String, attribute: 'container-id', reflect: false }) public get containerId(): string | null | undefined { @@ -29,86 +22,36 @@ export class UmbContentWorkspaceViewEditPropertiesElement extends UmbLitElement } @state() - _datasetVariantId?: UmbVariantId; + _properties: Array = []; @state() _visibleProperties?: Array; constructor() { super(); - - this.consumeContext(UMB_PROPERTY_DATASET_CONTEXT, (datasetContext) => { - this._datasetVariantId = datasetContext?.getVariantId(); - this.#processPropertyStructure(); - }); - this.consumeContext(UMB_CONTENT_WORKSPACE_CONTEXT, (workspaceContext) => { - this.#workspaceContext = workspaceContext; this.#propertyStructureHelper.setStructureManager( // Assuming its the same content model type that we are working with here... [NL] workspaceContext?.structure as unknown as UmbContentTypeStructureManager, ); this.observe( - this.#propertyStructureHelper.propertyStructure, + this.#propertyStructureHelper.propertyAliases, (properties) => { - this.#properties = properties; - this.#processPropertyStructure(); + this._properties = properties; }, 'observePropertyStructure', ); }); } - #processPropertyStructure() { - if (!this.#workspaceContext || !this.#properties || !this.#propertyStructureHelper || !this._datasetVariantId) { - return; - } - - const propertyViewGuard = this.#workspaceContext.propertyViewGuard; - - this.#properties.forEach((property) => { - const propertyVariantId = new UmbVariantId( - property.variesByCulture ? this._datasetVariantId?.culture : null, - property.variesBySegment ? this._datasetVariantId?.segment : null, - ); - this.observe( - propertyViewGuard.isPermittedForVariantAndProperty(propertyVariantId, property, this._datasetVariantId!), - (permitted) => { - if (permitted) { - this.#visiblePropertiesUniques.push(property.unique); - this.#calculateVisibleProperties(); - } else { - const index = this.#visiblePropertiesUniques.indexOf(property.unique); - if (index !== -1) { - this.#visiblePropertiesUniques.splice(index, 1); - this.#calculateVisibleProperties(); - } - } - }, - `propertyViewGuard-permittedForVariantAndProperty-${property.unique}`, - ); - }); - } - - #calculateVisibleProperties() { - this._visibleProperties = this.#properties!.filter((property) => - this.#visiblePropertiesUniques.includes(property.unique), - ); - } - override render() { - return this._datasetVariantId && this._visibleProperties - ? repeat( - this._visibleProperties, - (property) => property.alias, - (property) => - html``, - ) - : nothing; + return repeat( + this._properties, + (property) => property, + (property) => + html``, + ); } static override styles = [ diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content/workspace/views/edit/content-editor-property.element.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content/workspace/views/edit/content-editor-property.element.ts deleted file mode 100644 index d06fc9859d42..000000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/content/content/workspace/views/edit/content-editor-property.element.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { UMB_CONTENT_WORKSPACE_CONTEXT } from '../../content-workspace.context-token.js'; -import { html, customElement, property, state, nothing } from '@umbraco-cms/backoffice/external/lit'; -import type { UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type'; -import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; -import { UmbDataPathPropertyValueQuery } from '@umbraco-cms/backoffice/validation'; -import { UmbVariantId } from '@umbraco-cms/backoffice/variant'; - -@customElement('umb-content-workspace-view-edit-property') -export class UmbContentWorkspaceViewEditPropertyElement extends UmbLitElement { - // - @property({ attribute: false }) - variantId?: UmbVariantId; - - @property({ attribute: false }) - property?: UmbPropertyTypeModel; - - @state() - _dataPath?: string; - - @state() - _writeable?: boolean; - - @state() - _context?: typeof UMB_CONTENT_WORKSPACE_CONTEXT.TYPE; - - constructor() { - super(); - - this.consumeContext(UMB_CONTENT_WORKSPACE_CONTEXT, (context) => { - this._context = context; - }); - } - - override willUpdate(changedProperties: Map) { - super.willUpdate(changedProperties); - if (changedProperties.has('property') || changedProperties.has('variantId') || changedProperties.has('_context')) { - if (this.variantId && this.property && this._context) { - const propertyVariantId = new UmbVariantId( - this.property.variesByCulture ? this.variantId.culture : null, - this.property.variesBySegment ? this.variantId.segment : null, - ); - this._dataPath = `$.values[${UmbDataPathPropertyValueQuery({ - alias: this.property.alias, - culture: propertyVariantId.culture, - segment: propertyVariantId.segment, - })}].value`; - - this.observe( - this._context.propertyWriteGuard.isPermittedForVariantAndProperty( - propertyVariantId, - this.property, - this.variantId, - ), - (write) => { - this._writeable = write; - }, - 'observeView', - ); - } - } - } - - override render() { - if (!this._dataPath || this._writeable === undefined) return nothing; - - return html``; - } -} - -export default UmbContentWorkspaceViewEditPropertyElement; - -declare global { - interface HTMLElementTagNameMap { - 'umb-content-workspace-view-edit-property': UmbContentWorkspaceViewEditPropertyElement; - } -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item/tree-item.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item/tree-item.element.ts index 54ae3c458099..90ab9c2cdc08 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item/tree-item.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item/tree-item.element.ts @@ -31,7 +31,7 @@ export class UmbTreeItemElement extends UmbExtensionElementAndApiSlotElementBase // This method gets all extensions based on a type, then filters them based on the entity type. and then we get the alias of the first one [NL] createObservablePart( umbExtensionsRegistry.byTypeAndFilter(this.getExtensionType(), filterByEntityType), - (x) => x[0].alias, + (x) => x[0]?.alias, ), (alias) => { this.alias = alias;