diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-type/workspace/block-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-type/workspace/block-type-workspace.context.ts index 8b9d425241..1d17eb81ec 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-type/workspace/block-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-type/workspace/block-type-workspace.context.ts @@ -1,6 +1,6 @@ import type { UmbBlockTypeBaseModel, UmbBlockTypeWithGroupKey } from '../types.js'; import { UmbBlockTypeWorkspaceEditorElement } from './block-type-workspace-editor.element.js'; -import type { UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property'; +import type { UmbPropertyDatasetContext, UmbPropertyValueData } from '@umbraco-cms/backoffice/property'; import { UMB_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/property'; import type { UmbInvariantDatasetWorkspaceContext, @@ -12,9 +12,11 @@ import { UmbInvariantWorkspacePropertyDatasetContext, UmbWorkspaceIsNewRedirectController, UmbWorkspaceIsNewRedirectControllerAlias, + umbObjectToPropertyValueArray, } from '@umbraco-cms/backoffice/workspace'; import { UmbObjectState, appendToFrozenArray } from '@umbraco-cms/backoffice/observable-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { firstValueFrom } from '@umbraco-cms/backoffice/external/rxjs'; export class UmbBlockTypeWorkspaceContext extends UmbSubmittableWorkspaceContextBase @@ -25,12 +27,18 @@ export class UmbBlockTypeWorkspaceContext(undefined); - //readonly data = this.#data.asObservable(); + readonly data = this.#data.asObservable(); - // TODO: Get the name of the contentElementType.. - readonly name = this.#data.asObservablePart(() => 'block'); + readonly name = this.#data.asObservablePart(() => 'block type'); readonly unique = this.#data.asObservablePart((data) => data?.contentElementTypeKey); + readonly values = this.#data.asObservablePart((data) => { + return umbObjectToPropertyValueArray(data); + }); + async getValues(): Promise | undefined> { + return umbObjectToPropertyValueArray(await firstValueFrom(this.data)); + } + constructor(host: UmbControllerHost, args: { manifest: ManifestWorkspace }) { super(host, args.manifest.alias); const manifest = args.manifest; diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/property-value-resolver/block-value-resolver.api.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/property-value-resolver/block-value-resolver.api.ts index 08ffcdc3f6..7abc94574f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/property-value-resolver/block-value-resolver.api.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/property-value-resolver/block-value-resolver.api.ts @@ -1,14 +1,14 @@ import type { UmbBlockDataValueModel, UmbBlockExposeModel, UmbBlockValueDataPropertiesBaseType } from '../types.js'; -import type { UmbContentValueModel } from '@umbraco-cms/backoffice/content'; +import type { UmbElementValueModel } from '@umbraco-cms/backoffice/content'; import type { UmbPropertyValueResolver } from '@umbraco-cms/backoffice/property'; export abstract class UmbBlockValueResolver - implements UmbPropertyValueResolver, UmbBlockDataValueModel, UmbBlockExposeModel> + implements UmbPropertyValueResolver, UmbBlockDataValueModel, UmbBlockExposeModel> { abstract processValues( - property: UmbContentValueModel, + property: UmbElementValueModel, valuesCallback: (values: Array) => Promise | undefined>, - ): Promise>; + ): Promise>; protected async _processValueBlockData( value: ValueType, @@ -30,9 +30,9 @@ export abstract class UmbBlockValueResolver } abstract processVariants( - property: UmbContentValueModel, + property: UmbElementValueModel, variantsCallback: (values: Array) => Promise | undefined>, - ): Promise>; + ): Promise>; protected async _processVariantBlockData( value: ValueType, diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/property-value-resolver/standard-block-value-resolver.api.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/property-value-resolver/standard-block-value-resolver.api.ts index 7837845e70..2f3c42d1f8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/property-value-resolver/standard-block-value-resolver.api.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/property-value-resolver/standard-block-value-resolver.api.ts @@ -1,10 +1,10 @@ import type { UmbBlockDataValueModel, UmbBlockExposeModel, UmbBlockValueType } from '../types.js'; import { UmbBlockValueResolver } from './block-value-resolver.api.js'; -import type { UmbContentValueModel } from '@umbraco-cms/backoffice/content'; +import type { UmbElementValueModel } from '@umbraco-cms/backoffice/content'; export class UmbStandardBlockValueResolver extends UmbBlockValueResolver { async processValues( - property: UmbContentValueModel, + property: UmbElementValueModel, valuesCallback: (values: Array) => Promise | undefined>, ) { if (property.value) { @@ -17,7 +17,7 @@ export class UmbStandardBlockValueResolver extends UmbBlockValueResolver, + property: UmbElementValueModel, variantsCallback: (values: Array) => Promise | undefined>, ) { if (property.value) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/types.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/types.ts index a95b0dab57..77f43f22d6 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/types.ts @@ -1,4 +1,4 @@ -import type { UmbContentValueModel } from '@umbraco-cms/backoffice/content'; +import type { UmbElementValueModel } from '@umbraco-cms/backoffice/content'; export interface UmbBlockLayoutBaseModel { contentKey: string; @@ -6,7 +6,7 @@ export interface UmbBlockLayoutBaseModel { } // eslint-disable-next-line @typescript-eslint/no-empty-object-type -export interface UmbBlockDataValueModel extends UmbContentValueModel {} +export interface UmbBlockDataValueModel extends UmbElementValueModel {} export interface UmbBlockDataModel { key: string; diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-manager.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-manager.ts index 67e9f1c087..9c9f33b029 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-manager.ts @@ -5,7 +5,6 @@ import { UmbContentTypeStructureManager } from '@umbraco-cms/backoffice/content- import { type Observable, UmbClassState, - UmbObjectState, appendToFrozenArray, mergeObservables, } from '@umbraco-cms/backoffice/observable-api'; @@ -14,27 +13,41 @@ import { type UmbClassInterface, UmbControllerBase } from '@umbraco-cms/backoffi import { UmbDocumentTypeDetailRepository } from '@umbraco-cms/backoffice/document-type'; import { UmbVariantId } from '@umbraco-cms/backoffice/variant'; import { UmbValidationController } from '@umbraco-cms/backoffice/validation'; +import { UmbElementWorkspaceDataManager, type UmbElementPropertyDataOwner } from '@umbraco-cms/backoffice/content'; +import { UmbReadOnlyVariantStateManager } from '@umbraco-cms/backoffice/utils'; -export class UmbBlockElementManager extends UmbControllerBase { +import { UmbDataTypeItemRepositoryManager } from '@umbraco-cms/backoffice/data-type'; + +export class UmbBlockElementManager + extends UmbControllerBase + implements UmbElementPropertyDataOwner +{ // - #data = new UmbObjectState(undefined); - readonly data = this.#data.asObservable(); + + readonly #data = new UmbElementWorkspaceDataManager(this); + //#data = new UmbObjectState(undefined); + readonly data = this.#data.current; #getDataPromise = new Promise((resolve) => { this.#getDataResolver = resolve; }); #getDataResolver!: () => void; + public readonly readOnlyState = new UmbReadOnlyVariantStateManager(this); + #variantId = new UmbClassState(undefined); readonly variantId = this.#variantId.asObservable(); - readonly unique = this.#data.asObservablePart((data) => data?.key); - readonly contentTypeId = this.#data.asObservablePart((data) => data?.contentTypeKey); + readonly unique = this.#data.createObservablePartOfCurrent((data) => data?.key); + readonly contentTypeId = this.#data.createObservablePartOfCurrent((data) => data?.contentTypeKey); - readonly values = this.#data.asObservablePart((data) => data?.values); + readonly values = this.#data.createObservablePartOfCurrent((data) => data?.values); getValues() { - return this.#data.getValue()?.values; + return this.#data.getCurrent()?.values; } + readonly #dataTypeItemManager = new UmbDataTypeItemRepositoryManager(this); + #dataTypeSchemaAliasMap = new Map(); + readonly structure = new UmbContentTypeStructureManager( this, new UmbDocumentTypeDetailRepository(this), @@ -51,10 +64,34 @@ export class UmbBlockElementManager extends UmbControllerBase { this.validation.setDataPath('$.' + dataPathPropertyName + `[?(@.key = '${key}')]`); } }); + + this.observe( + this.structure.contentTypeDataTypeUniques, + (dataTypeUniques: Array) => { + this.#dataTypeItemManager.setUniques(dataTypeUniques); + }, + null, + ); + this.observe( + this.#dataTypeItemManager.items, + (dataTypes) => { + // Make a map of the data type unique and editorAlias: + this.#dataTypeSchemaAliasMap = new Map( + dataTypes.map((dataType) => { + return [dataType.unique, dataType.propertyEditorSchemaAlias]; + }), + ); + }, + null, + ); } - reset() { - this.#data.setValue(undefined); + public isLoaded() { + return this.#getDataPromise; + } + + resetState() { + this.#data.clear(); } setVariantId(variantId: UmbVariantId | undefined) { @@ -66,12 +103,13 @@ export class UmbBlockElementManager extends UmbControllerBase { // TODO: rename to currentData: setData(data: UmbBlockDataModel | undefined) { - this.#data.setValue(data); + this.#data.setPersisted(data); + this.#data.setCurrent(data); this.#getDataResolver(); } getData() { - return this.#data.getValue(); + return this.#data.getCurrent(); } getUnique() { @@ -105,100 +143,79 @@ export class UmbBlockElementManager extends UmbControllerBase { /** * @function propertyValueByAlias - * @param {string} propertyAlias - Property Alias to observe the value of. - * @returns {Promise | undefined>} - Promise which resolves to an Observable + * @param {string} propertyAlias - The alias of the property + * @param {UmbVariantId} variantId - The variant + * @returns {Promise | undefined>} - An observable for the value of the property * @description Get an Observable for the value of this property. */ async propertyValueByAlias( propertyAlias: string, + variantId?: UmbVariantId, ): Promise | undefined> { - await this.#getDataPromise; - - return mergeObservables( - [ - this.#data.asObservablePart((data) => data?.values?.filter((x) => x?.alias === propertyAlias)), - await this.propertyVariantId(propertyAlias), - ], - ([propertyValues, propertyVariantId]) => { - if (!propertyValues || !propertyVariantId) return; - - return propertyValues.find((x) => propertyVariantId.compare(x))?.value as PropertyValueType; - }, + return this.#data.createObservablePartOfCurrent( + (data) => + data?.values?.find((x) => x?.alias === propertyAlias && (variantId ? variantId.compare(x) : true)) + ?.value as PropertyValueType, ); } /** * Get the current value of the property with the given alias and variantId. * @param {string} alias - The alias of the property - * @returns {ReturnType} The value or undefined if not set or found. + * @param {UmbVariantId | undefined} variantId - The variant id of the property + * @returns {ReturnType | undefined} The value or undefined if not set or found. */ - async getPropertyValue(alias: string) { - await this.#getDataPromise; - const managerVariantId = this.#variantId.getValue(); - if (!managerVariantId) return; - const property = await this.structure.getPropertyStructureByAlias(alias); - if (!property) return; - const variantId = this.#createPropertyVariantId(property, managerVariantId); - const currentData = this.getData(); - if (!currentData) return; - const newDataSet = currentData.values?.find((x) => x.alias === alias && (variantId ? variantId.compare(x) : true)); - return newDataSet?.value as ReturnType; + getPropertyValue(alias: string, variantId?: UmbVariantId) { + const currentData = this.#data.getCurrent(); + if (currentData) { + const newDataSet = currentData.values?.find( + (x) => x.alias === alias && (variantId ? variantId.compare(x) : true), + ); + return newDataSet?.value as ReturnType; + } + return undefined; } - - /** - * @function setPropertyValue - * @param {string} alias - The alias of the property - * @param {unknown} value - value can be a promise resolving into the actual value or the raw value it self. - * @returns {Promise} - * @description Set the value of this property. - */ - async setPropertyValue(alias: string, value: ValueType) { + async setPropertyValue(alias: string, value: ValueType, variantId?: UmbVariantId) { this.initiatePropertyValueChange(); - await this.#getDataPromise; - const managerVariantId = this.#variantId.getValue(); - if (!managerVariantId) return; + variantId ??= UmbVariantId.CreateInvariant(); const property = await this.structure.getPropertyStructureByAlias(alias); - if (!property) return; - const variantId = this.#createPropertyVariantId(property, managerVariantId); - const entry = { ...variantId.toObject(), alias, value } as UmbBlockDataValueModel; + if (!property) { + throw new Error(`Property alias "${alias}" not found.`); + } + + const editorAlias = this.#dataTypeSchemaAliasMap.get(property.dataType.unique); + if (!editorAlias) { + throw new Error(`Editor Alias of "${property.dataType.unique}" not found.`); + } + + const entry = { ...variantId.toObject(), alias, editorAlias, value } as UmbBlockDataValueModel; + const currentData = this.getData(); if (currentData) { const values = appendToFrozenArray( currentData.values ?? [], entry, - (x) => x.alias === alias && variantId.compare(x), + (x) => x.alias === alias && variantId!.compare(x), ); - this.#data.update({ values }); + this.#data.updateCurrent({ values }); } this.finishPropertyValueChange(); } - #updateLock = 0; initiatePropertyValueChange() { - this.#updateLock++; - this.#data.mute(); - // TODO: When ready enable this code will enable handling a finish automatically by this implementation 'using myState.initiatePropertyValueChange()' (Relies on TS support of Using) [NL] - /*return { - [Symbol.dispose]: this.finishPropertyValueChange, - };*/ + this.#data.initiatePropertyValueChange(); } finishPropertyValueChange = () => { - this.#updateLock--; - this.#triggerPropertyValueChanges(); + this.#data.finishPropertyValueChange(); }; - #triggerPropertyValueChanges() { - if (this.#updateLock === 0) { - this.#data.unmute(); - } + + public createPropertyDatasetContext(host: UmbControllerHost, variantId: UmbVariantId) { + return new UmbBlockElementPropertyDatasetContext(host, this, variantId); } - public createPropertyDatasetContext(host: UmbControllerHost) { - return new UmbBlockElementPropertyDatasetContext(host, this, this.getVariantId()); - } - - public setup(host: UmbClassInterface) { - this.createPropertyDatasetContext(host); + public setup(host: UmbClassInterface, variantId: UmbVariantId) { + this.createPropertyDatasetContext(host, variantId); // Provide Validation Context for this view: this.validation.provideAt(host); diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-property-dataset.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-property-dataset.context.ts index 291444df3a..89e7a7fd9f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-property-dataset.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-property-dataset.context.ts @@ -1,89 +1,28 @@ -import { UMB_BLOCK_ELEMENT_PROPERTY_DATASET_CONTEXT } from './block-element-property-dataset.context-token.js'; import type { UmbBlockElementManager } from './block-element-manager.js'; -import { UMB_BLOCK_WORKSPACE_CONTEXT } from './block-workspace.context-token.js'; import type { UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property'; -import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; -import type { Observable } from '@umbraco-cms/backoffice/external/rxjs'; -import { UmbBooleanState } from '@umbraco-cms/backoffice/observable-api'; -import { UmbVariantId } from '@umbraco-cms/backoffice/variant'; +import type { UmbVariantId } from '@umbraco-cms/backoffice/variant'; +import { UmbElementPropertyDatasetContext } from '@umbraco-cms/backoffice/content'; +import { createObservablePart } from '@umbraco-cms/backoffice/observable-api'; -export class UmbBlockElementPropertyDatasetContext extends UmbControllerBase implements UmbPropertyDatasetContext { - #elementManager: UmbBlockElementManager; - public getVariantId() { - return this.#elementManager.getVariantId(); +export class UmbBlockElementPropertyDatasetContext + extends UmbElementPropertyDatasetContext + implements UmbPropertyDatasetContext +{ + name; + culture; + segment; + + getName(): string { + return 'Block'; } - #variantId: UmbVariantId; - - #readOnly = new UmbBooleanState(false); - public readOnly = this.#readOnly.asObservable(); - - // default data: - - getEntityType() { - return this.#elementManager.getEntityType(); - } - getUnique() { - return this.#elementManager.getUnique(); - } - - getName(): string | undefined { - return 'TODO: get label'; - } - readonly name: Observable = 'TODO: get label observable' as any; constructor(host: UmbControllerHost, elementManager: UmbBlockElementManager, variantId?: UmbVariantId) { // The controller alias, is a very generic name cause we want only one of these for this controller host. - super(host, UMB_PROPERTY_DATASET_CONTEXT.toString()); - this.#elementManager = elementManager; - this.#variantId = variantId ?? UmbVariantId.CreateInvariant(); + super(host, elementManager, variantId); - this.consumeContext(UMB_BLOCK_WORKSPACE_CONTEXT, (workspace) => { - this.observe( - workspace.readOnlyState.states, - (states) => { - const isReadOnly = states.some((state) => state.variantId.equal(this.#variantId)); - this.#readOnly.setValue(isReadOnly); - }, - 'umbObserveReadOnlyStates', - ); - }); - - this.provideContext(UMB_BLOCK_ELEMENT_PROPERTY_DATASET_CONTEXT, this); - } - - propertyVariantId?(propertyAlias: string): Promise> { - return this.#elementManager.propertyVariantId(propertyAlias); - } - - /** - * @function propertyValueByAlias - * @param {string} propertyAlias - The alias of the property - * @returns {Promise | undefined>} - An observable of the property value. - * @description Get an Observable for the value of this property. - */ - async propertyValueByAlias(propertyAlias: string) { - return await this.#elementManager.propertyValueByAlias(propertyAlias); - } - - /** - * @function setPropertyValue - * @param {string} alias - The alias of the property - * @param {unknown} value - value can be a promise resolving into the actual value or the raw value it self. - * @returns {Promise} - * @description Set the value of this property. - */ - async setPropertyValue(alias: string, value: PromiseLike) { - this.#elementManager.setPropertyValue(alias, value); - } - - /** - * Gets the read-only state of the current variant culture. - * @returns {*} {boolean} - * @memberof UmbBlockGridInlinePropertyDatasetContext - */ - getReadOnly(): boolean { - return this.#readOnly.getValue(); + this.name = elementManager.name; + this.culture = createObservablePart(elementManager.variantId, (v) => v?.culture); + this.segment = createObservablePart(elementManager.variantId, (v) => v?.segment); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts index 4c0ad16a16..d850970f3c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts @@ -204,8 +204,8 @@ export class UmbBlockWorkspaceContext { if (variantId) { + context.content.setup(this, variantId); // TODO: Support segment name? const culture = variantId.culture; if (culture) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit.element.ts index bdf60dd194..669bb6fbb1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit.element.ts @@ -69,8 +69,16 @@ export class UmbBlockWorkspaceViewEditElement extends UmbLitElement implements U const blockManager = this.#blockWorkspace[this.#managerName]; this.#tabsStructureHelper.setStructureManager(blockManager.structure); - // Create Data Set & setup Validation Context: - blockManager.setup(this); + this.observe( + this.#blockWorkspace.variantId, + (variantId) => { + if (variantId) { + // Create Data Set & setup Validation Context: + blockManager.setup(this, variantId); + } + }, + 'observeVariantId', + ); this.observe( await this.#blockWorkspace![this.#managerName!].structure.hasRootContainers('Group'), diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content/controller/merge-content-variant-data.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content/controller/merge-content-variant-data.controller.ts index e4ecfc2c04..aa50029af8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/content/controller/merge-content-variant-data.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content/controller/merge-content-variant-data.controller.ts @@ -1,5 +1,5 @@ import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; -import type { UmbContentDetailModel, UmbPotentialContentValueModel } from '@umbraco-cms/backoffice/content'; +import type { UmbContentLikeDetailModel, UmbPotentialContentValueModel } from '@umbraco-cms/backoffice/content'; import { createExtensionApi } from '@umbraco-cms/backoffice/extension-api'; import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; import { UmbVariantId, type UmbVariantDataModel } from '@umbraco-cms/backoffice/variant'; @@ -17,13 +17,13 @@ function defaultCompareVariantMethod(a: UmbVariantDataModel, b: UmbVariantDataMo export class UmbMergeContentVariantDataController extends UmbControllerBase { /** * Merges content variant data based on selected variants and variants to store. - * @param {UmbContentDetailModel | undefined} persistedData - The persisted content variant data. - * @param {UmbContentDetailModel} currentData - The current content variant data. + * @param {UmbContentLikeDetailModel | undefined} persistedData - The persisted content variant data. + * @param {UmbContentLikeDetailModel} currentData - The current content variant data. * @param {Array} selectedVariants - The selected variants. * @param {Array} variantsToStore - The variants to store, we sometimes have additional variants that we like to process. This is typically the invariant variant, which we do not want to have as part of the variants data therefore a difference. - * @returns {Promise} - A promise that resolves to the merged content variant data. + * @returns {Promise} - A promise that resolves to the merged content variant data. */ - async process( + async process( persistedData: ModelType | undefined, currentData: ModelType, selectedVariants: Array, @@ -39,14 +39,17 @@ export class UmbMergeContentVariantDataController extends UmbControllerBase { currentData.values, variantsToStore, ), + }; + + if (currentData.variants) { // Notice for variants we do not want to include all the variants that we are processing. but just the once selected for the process. (Not include invariant if we are in a variant document) [NL] - variants: this.#processVariants( + result.variants = this.#processVariants( persistedData?.variants, currentData.variants, selectedVariants, defaultCompareVariantMethod, - ), - }; + ); + } this.destroy(); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content/index.ts index b955ee1cfe..a70ac6e23c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/content/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content/index.ts @@ -1,8 +1,8 @@ export { UMB_CONTENT_PROPERTY_CONTEXT } from './content-property.context-token.js'; export { UmbContentPropertyContext } from './content-property.context.js'; -export * from './manager/content-data-manager.js'; -export * from './controller/merge-content-variant-data.controller.js'; -export * from './property-dataset-context/content-property-dataset.context.js'; -export * from './workspace/index.js'; export * from './collection/index.js'; +export * from './controller/merge-content-variant-data.controller.js'; +export * from './manager/index.js'; +export * from './property-dataset-context/index.js'; +export * from './workspace/index.js'; export type * from './types.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content/manager/content-data-manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content/manager/content-data-manager.ts index e9cad5be02..3c6601037f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/content/manager/content-data-manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content/manager/content-data-manager.ts @@ -1,63 +1,24 @@ -import { UmbMergeContentVariantDataController } from '../controller/merge-content-variant-data.controller.js'; +import { UmbElementWorkspaceDataManager } from './element-data-manager.js'; import type { UmbContentDetailModel } from '@umbraco-cms/backoffice/content'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { appendToFrozenArray, jsonStringComparison } from '@umbraco-cms/backoffice/observable-api'; import { UmbVariantId, type UmbEntityVariantModel } from '@umbraco-cms/backoffice/variant'; -import { UmbEntityWorkspaceDataManager, type UmbWorkspaceDataManager } from '@umbraco-cms/backoffice/workspace'; export class UmbContentWorkspaceDataManager< - ModelType extends UmbContentDetailModel, - ModelVariantType extends UmbEntityVariantModel = ModelType extends { variants: UmbEntityVariantModel[] } - ? ModelType['variants'][0] - : never, - > - extends UmbEntityWorkspaceDataManager - implements UmbWorkspaceDataManager -{ + ModelType extends UmbContentDetailModel, + ModelVariantType extends UmbEntityVariantModel = ModelType extends { variants: UmbEntityVariantModel[] } + ? ModelType['variants'][0] + : never, +> extends UmbElementWorkspaceDataManager { // //#repository; #variantScaffold?: ModelVariantType; - #varies?: boolean; - //#variesByCulture?: boolean; - //#variesBySegment?: boolean; - constructor(host: UmbControllerHost, variantScaffold: ModelVariantType) { super(host); this.#variantScaffold = variantScaffold; } - #updateLock = 0; - initiatePropertyValueChange() { - this.#updateLock++; - this._current.mute(); - // TODO: When ready enable this code will enable handling a finish automatically by this implementation 'using myState.initiatePropertyValueChange()' (Relies on TS support of Using) [NL] - /*return { - [Symbol.dispose]: this.finishPropertyValueChange, - };*/ - } - finishPropertyValueChange = () => { - this.#updateLock--; - this.#triggerPropertyValueChanges(); - }; - #triggerPropertyValueChanges() { - if (this.#updateLock === 0) { - this._current.unmute(); - } - } - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - setVariesByCulture(vary: boolean | undefined) { - //this.#variesByCulture = vary; - } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - setVariesBySegment(vary: boolean | undefined) { - //this.#variesBySegment = vary; - } - setVaries(vary: boolean | undefined) { - this.#varies = vary; - } - ensureVariantData(variantId: UmbVariantId) { this.updateVariantData(variantId); } @@ -66,7 +27,7 @@ export class UmbContentWorkspaceDataManager< const currentData = this.getCurrent(); if (!currentData) throw new Error('Data is missing'); if (!this.#variantScaffold) throw new Error('Variant scaffold data is missing'); - if (this.#varies === true) { + if (this._varies === true) { // If variant Id is invariant, we don't to have the variant appended to our data. if (variantId.isInvariant()) return; const variant = currentData.variants.find((x) => variantId.compare(x)); @@ -82,7 +43,7 @@ export class UmbContentWorkspaceDataManager< ) as Array; // TODO: I have some trouble with TypeScript here, I does not look like me, but i had to give up. [NL] this._current.update({ variants: newVariants } as any); - } else if (this.#varies === false) { + } else if (this._varies === false) { // TODO: Beware about segments, in this case we need to also consider segments, if its allowed to vary by segments. const invariantVariantId = UmbVariantId.CreateInvariant(); const variant = currentData.variants.find((x) => invariantVariantId.compare(x)); @@ -102,32 +63,6 @@ export class UmbContentWorkspaceDataManager< } } - async constructData(selectedVariants: Array): Promise { - // Lets correct the selected variants, so invariant is included, or the only one if invariant. - // TODO: VDIVD: Could a document be set to invariant but hold variant data inside it? - const invariantVariantId = UmbVariantId.CreateInvariant(); - let variantsToStore = [invariantVariantId]; - if (this.#varies === false) { - // If we do not vary, we wil just pick the invariant variant id. - selectedVariants = [invariantVariantId]; - } else { - variantsToStore = [...selectedVariants, invariantVariantId]; - } - - const data = this._current.getValue(); - if (!data) throw new Error('Current data is missing'); - if (!data.unique) throw new Error('Unique of current data is missing'); - - const persistedData = this.getPersisted(); - - return await new UmbMergeContentVariantDataController(this).process( - persistedData, - data, - selectedVariants, - variantsToStore, - ); - } - getChangedVariants() { const persisted = this.getPersisted(); const current = this.getCurrent(); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content/manager/element-data-manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content/manager/element-data-manager.ts new file mode 100644 index 0000000000..7dd3ddc91e --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content/manager/element-data-manager.ts @@ -0,0 +1,70 @@ +import { UmbMergeContentVariantDataController } from '../controller/merge-content-variant-data.controller.js'; +import type { UmbElementDetailModel } from '@umbraco-cms/backoffice/content'; +import { UmbVariantId } from '@umbraco-cms/backoffice/variant'; +import { UmbEntityWorkspaceDataManager, type UmbWorkspaceDataManager } from '@umbraco-cms/backoffice/workspace'; + +export class UmbElementWorkspaceDataManager + extends UmbEntityWorkspaceDataManager + implements UmbWorkspaceDataManager +{ + protected _varies?: boolean; + //#variesByCulture?: boolean; + //#variesBySegment?: boolean; + + #updateLock = 0; + initiatePropertyValueChange() { + this.#updateLock++; + this._current.mute(); + // TODO: When ready enable this code will enable handling a finish automatically by this implementation 'using myState.initiatePropertyValueChange()' (Relies on TS support of Using) [NL] + /*return { + [Symbol.dispose]: this.finishPropertyValueChange, + };*/ + } + finishPropertyValueChange = () => { + this.#updateLock--; + this.#triggerPropertyValueChanges(); + }; + #triggerPropertyValueChanges() { + if (this.#updateLock === 0) { + this._current.unmute(); + } + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + setVariesByCulture(vary: boolean | undefined) { + //this.#variesByCulture = vary; + } + // eslint-disable-next-line @typescript-eslint/no-unused-vars + setVariesBySegment(vary: boolean | undefined) { + //this.#variesBySegment = vary; + } + setVaries(vary: boolean | undefined) { + this._varies = vary; + } + + async constructData(selectedVariants: Array): Promise { + // Lets correct the selected variants, so invariant is included, or the only one if invariant. + // TODO: VDIVD: Could a document be set to invariant but hold variant data inside it? + const invariantVariantId = UmbVariantId.CreateInvariant(); + let variantsToStore = [invariantVariantId]; + if (this._varies === false) { + // If we do not vary, we wil just pick the invariant variant id. + selectedVariants = [invariantVariantId]; + } else { + variantsToStore = [...selectedVariants, invariantVariantId]; + } + + const data = this._current.getValue(); + if (!data) throw new Error('Current data is missing'); + //if (!data.unique) throw new Error('Unique of current data is missing'); + + const persistedData = this.getPersisted(); + + return await new UmbMergeContentVariantDataController(this).process( + persistedData, + data, + selectedVariants, + variantsToStore, + ); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content/manager/element-data-properties.manager.tempts b/src/Umbraco.Web.UI.Client/src/packages/core/content/manager/element-data-properties.manager.tempts new file mode 100644 index 0000000000..ed8f8e9b87 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content/manager/element-data-properties.manager.tempts @@ -0,0 +1,160 @@ +import type { UmbElementPropertyDataOwner } from '../property-dataset-context/element-property-data-owner.interface.js'; +import type { UmbPropertyValueData } from '@umbraco-cms/backoffice/property'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; +import type { Observable } from '@umbraco-cms/backoffice/external/rxjs'; +import { + UmbBasicState, + classEqualMemoization, + createObservablePart, + mergeObservables, +} from '@umbraco-cms/backoffice/observable-api'; +import { UmbVariantId } from '@umbraco-cms/backoffice/variant'; +import type { UmbContentTypeModel, UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type'; + +type UmbPropertyVariantIdMapType = Array<{ alias: string; variantId: UmbVariantId }>; + +export class UmbElementDataPropertyManager< + ContentModel extends { values: Array }, + ContentTypeModel extends UmbContentTypeModel = UmbContentTypeModel, +> extends UmbControllerBase { + #dataOwner: UmbElementPropertyDataOwner; + #variantId: UmbVariantId; + + // eslint-disable-next-line no-unused-private-class-members + #propertyVariantIdPromise?: Promise; + #propertyVariantIdPromiseResolver?: () => void; + #propertyVariantIdMap = new UmbBasicState([]); + private readonly _propertyVariantIdMap = this.#propertyVariantIdMap.asObservable(); + + constructor( + host: UmbControllerHost, + dataOwner: UmbElementPropertyDataOwner, + variantId?: UmbVariantId, + ) { + // The controller alias, is a very generic name cause we want only one of these for this controller host. + super(host); + this.#dataOwner = dataOwner; + this.#variantId = variantId ?? UmbVariantId.CreateInvariant(); + + this.observe(this.#dataOwner.structure.contentTypeProperties, (props: UmbPropertyTypeModel[]) => { + this.#propertyVariantIdPromise ??= new Promise((resolve) => { + this.#propertyVariantIdPromiseResolver = resolve as any; + }); + const map = props.map((prop) => ({ alias: prop.alias, variantId: this.#createPropertyVariantId(prop) })); + this.#propertyVariantIdMap.setValue(map); + // Resolve promise, to let the once waiting on this know. + if (this.#propertyVariantIdPromiseResolver) { + this.#propertyVariantIdPromise = undefined; + this.#propertyVariantIdPromiseResolver(); + this.#propertyVariantIdPromiseResolver = undefined; + } + }); + } + + #createPropertyVariantId(property: UmbPropertyTypeModel) { + return UmbVariantId.Create({ + culture: property.variesByCulture ? this.#variantId.culture : null, + segment: property.variesBySegment ? this.#variantId.segment : null, + }); + } + + #propertiesObservable?: Observable>; + // Should it be possible to get the properties as a list of property aliases? + get properties(): Observable> { + if (!this.#propertiesObservable) { + this.#propertiesObservable = mergeObservables( + [this._propertyVariantIdMap, this.#dataOwner.values], + this.#mergeVariantIdsAndValues, + ); + } + + return this.#propertiesObservable; + } + + #mergeVariantIdsAndValues([props, values]: [UmbPropertyVariantIdMapType, Array | undefined]) { + const r: Array = []; + if (values) { + for (const prop of props) { + const f = values.find((v) => prop.alias === v.alias && prop.variantId.compare(v)); + if (f) { + r.push(f); + } + } + } + return r; + } + + async getProperties(): Promise> { + await this.#propertyVariantIdPromise; + return this.#mergeVariantIdsAndValues([this.#propertyVariantIdMap.getValue(), this.#dataOwner.getValues()]); + } + + /** + * @function propertyVariantId + * @param {string} propertyAlias - The property alias to observe the variantId of. + * @returns {Promise | undefined>} - The observable for this properties variantId. + * @description Get an Observable for the variant id of this property. + */ + async propertyVariantId(propertyAlias: string) { + return createObservablePart( + this._propertyVariantIdMap, + (x) => x.find((v) => v.alias === propertyAlias)?.variantId, + classEqualMemoization, + ); + } + + /** + * @function propertyValueByAlias + * @param {string} propertyAlias The alias of the property + * @returns {Promise | undefined>} - An observable of the property value + * @description Get an Observable for the value of this property. + */ + async propertyValueByAlias( + propertyAlias: string, + ): Promise | undefined> { + await this.#dataOwner.isLoaded(); + await this.#propertyVariantIdPromise; + const propVariantId = this.#propertyVariantIdMap.getValue().find((x) => x.alias === propertyAlias); + if (propVariantId) { + return this.#dataOwner.propertyValueByAlias(propertyAlias, propVariantId.variantId); + } + return; + } + + async propertyValueByAliasAndVariantId( + propertyAlias: string, + propertyVariantId: UmbVariantId, + ): Promise | undefined> { + return this.#dataOwner.propertyValueByAlias(propertyAlias, propertyVariantId); + } + + /** + * @function setPropertyValueByVariant + * @param {string} propertyAlias - The alias of the property + * @param {unknown} value - value can be a promise resolving into the actual value or the raw value it self. + * @param {UmbVariantId} propertyVariantId - The variant id for the value to be set for. + * @returns {Promise} - A promise that resolves once the value has been set. + * @description Get the value of this property. + */ + setPropertyValueByVariant(propertyAlias: string, value: unknown, propertyVariantId: UmbVariantId): Promise { + return this.#dataOwner.setPropertyValue(propertyAlias, value, propertyVariantId); + } + + /** + * @function setPropertyValue + * @param {string} propertyAlias - The alias for the value to be set + * @param {PromiseLike} value - value can be a promise resolving into the actual value or the raw value it self. + * @returns {Promise} + * @description Set the value of this property. + */ + async setPropertyValue(propertyAlias: string, value: PromiseLike) { + this.#dataOwner.initiatePropertyValueChange(); + await this.#propertyVariantIdPromise; + const propVariantId = this.#propertyVariantIdMap.getValue().find((x) => x.alias === propertyAlias); + if (propVariantId) { + return this.#dataOwner.setPropertyValue(propertyAlias, await value, propVariantId.variantId); + } + this.#dataOwner.finishPropertyValueChange(); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content/manager/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content/manager/index.ts new file mode 100644 index 0000000000..f590f322ce --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content/manager/index.ts @@ -0,0 +1,2 @@ +export * from './content-data-manager.js'; +export * from './element-data-manager.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content/property-dataset-context/content-property-dataset.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content/property-dataset-context/content-property-dataset.context.ts index e5187fc269..09a35613ba 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/content/property-dataset-context/content-property-dataset.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content/property-dataset-context/content-property-dataset.context.ts @@ -1,228 +1,57 @@ import type { UmbContentWorkspaceContext } from '../workspace/index.js'; import type { UmbContentDetailModel } from '../types.js'; -import type { UmbNameablePropertyDatasetContext, UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property'; -import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property'; +import { UmbElementPropertyDatasetContext } from './element-property-dataset.context.js'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; -import { type Observable, map } from '@umbraco-cms/backoffice/external/rxjs'; -import { - UmbBasicState, - UmbBooleanState, - UmbObjectState, - classEqualMemoization, - createObservablePart, - mergeObservables, -} from '@umbraco-cms/backoffice/observable-api'; -import type { UmbEntityVariantModel } from '@umbraco-cms/backoffice/variant'; -import { UmbVariantId } from '@umbraco-cms/backoffice/variant'; -import type { UmbContentTypeModel, UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type'; -import type { UmbWorkspaceUniqueType } from '@umbraco-cms/backoffice/workspace'; - -type UmbPropertyVariantIdMapType = Array<{ alias: string; variantId: UmbVariantId }>; +import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; +import type { UmbEntityVariantModel, UmbVariantId } from '@umbraco-cms/backoffice/variant'; +import type { UmbContentTypeModel } from '@umbraco-cms/backoffice/content-type'; export class UmbContentPropertyDatasetContext< - ContentModel extends UmbContentDetailModel = UmbContentDetailModel, - ContentTypeModel extends UmbContentTypeModel = UmbContentTypeModel, - VariantModelType extends UmbEntityVariantModel = UmbEntityVariantModel, - > - extends UmbContextBase - implements UmbPropertyDatasetContext, UmbNameablePropertyDatasetContext -{ - #workspace: UmbContentWorkspaceContext; - #variantId: UmbVariantId; - public getVariantId() { - return this.#variantId; - } - - #currentVariant = new UmbObjectState(undefined); + ContentModel extends UmbContentDetailModel = UmbContentDetailModel, + ContentTypeModel extends UmbContentTypeModel = UmbContentTypeModel, + VariantModelType extends UmbEntityVariantModel = UmbEntityVariantModel, +> extends UmbElementPropertyDatasetContext< + ContentModel, + ContentTypeModel, + UmbContentWorkspaceContext +> { + // + #currentVariant = new UmbObjectState(undefined); currentVariant = this.#currentVariant.asObservable(); name = this.#currentVariant.asObservablePart((x) => x?.name); culture = this.#currentVariant.asObservablePart((x) => x?.culture); segment = this.#currentVariant.asObservablePart((x) => x?.segment); - // eslint-disable-next-line no-unused-private-class-members - #propertyVariantIdPromise?: Promise; - #propertyVariantIdPromiseResolver?: () => void; - #propertyVariantIdMap = new UmbBasicState([]); - private readonly _propertyVariantIdMap = this.#propertyVariantIdMap.asObservable(); - - #readOnly = new UmbBooleanState(false); - public readOnly = this.#readOnly.asObservable(); - - getEntityType(): string { - return this.#workspace.getEntityType(); - } - getUnique(): UmbWorkspaceUniqueType | undefined { - return this.#workspace.getUnique(); - } getName(): string | undefined { - return this.#workspace.getName(this.#variantId); + return this._dataOwner.getName(this.getVariantId()); } setName(name: string) { - this.#workspace.setName(name, this.#variantId); + this._dataOwner.setName(name, this.getVariantId()); } + /** + * @deprecated Its not clear why we have this. We should either document the need better or get rid of it. + * @returns {UmbEntityVariantModel | undefined} - gives information about the current variant. + */ getVariantInfo() { - return this.#workspace.getVariant(this.#variantId); - } - - getReadOnly() { - return this.#readOnly.getValue(); + return this._dataOwner.getVariant(this.getVariantId()); } constructor( host: UmbControllerHost, - workspace: UmbContentWorkspaceContext, + dataOwner: UmbContentWorkspaceContext, variantId?: UmbVariantId, ) { // The controller alias, is a very generic name cause we want only one of these for this controller host. - super(host, UMB_PROPERTY_DATASET_CONTEXT); - this.#workspace = workspace; - this.#variantId = variantId ?? UmbVariantId.CreateInvariant(); + super(host, dataOwner, variantId); this.observe( - this.#workspace.variantById(this.#variantId), + this._dataOwner.variantById(this.getVariantId()), async (variantInfo) => { if (!variantInfo) return; this.#currentVariant.setValue(variantInfo); }, '_observeActiveVariant', ); - - this.observe( - this.#workspace.readOnlyState.states, - (states) => { - const isReadOnly = states.some((state) => state.variantId.equal(this.#variantId)); - this.#readOnly.setValue(isReadOnly); - }, - 'umbObserveReadOnlyStates', - ); - - // TODO: Refactor this into a separate manager/controller of some sort? [NL] - this.observe(this.#workspace.structure.contentTypeProperties, (props: UmbPropertyTypeModel[]) => { - this.#propertyVariantIdPromise ??= new Promise((resolve) => { - this.#propertyVariantIdPromiseResolver = resolve as any; - }); - const map = props.map((prop) => ({ alias: prop.alias, variantId: this.#createPropertyVariantId(prop) })); - this.#propertyVariantIdMap.setValue(map); - // Resolve promise, to let the once waiting on this know. - if (this.#propertyVariantIdPromiseResolver) { - this.#propertyVariantIdPromise = undefined; - this.#propertyVariantIdPromiseResolver(); - this.#propertyVariantIdPromiseResolver = undefined; - } - }); - } - - #createPropertyVariantId(property: UmbPropertyTypeModel) { - return UmbVariantId.Create({ - culture: property.variesByCulture ? this.#variantId.culture : null, - segment: property.variesBySegment ? this.#variantId.segment : null, - }); - } - - #propertiesObservable?: Observable; - // Should it be possible to get the properties as a list of property aliases? - get properties(): Observable { - if (!this.#propertiesObservable) { - this.#propertiesObservable = mergeObservables( - [this._propertyVariantIdMap, this.#workspace.values], - this.#mergeVariantIdsAndValues, - ); - } - - return this.#propertiesObservable; - } - - #mergeVariantIdsAndValues([props, values]: [UmbPropertyVariantIdMapType, ContentModel['values'] | undefined]) { - const r: ContentModel['values'] = []; - if (values) { - for (const prop of props) { - const f = values.find((v) => prop.alias === v.alias && prop.variantId.compare(v)); - if (f) { - r.push(f); - } - } - } - return r; - } - - async getProperties(): Promise { - await this.#propertyVariantIdPromise; - return this.#mergeVariantIdsAndValues([this.#propertyVariantIdMap.getValue(), this.#workspace.getValues()]); - } - - /** - * @function propertyVariantId - * @param {string} propertyAlias - The property alias to observe the variantId of. - * @returns {Promise | undefined>} - The observable for this properties variantId. - * @description Get an Observable for the variant id of this property. - */ - async propertyVariantId(propertyAlias: string) { - /* - return (await this.#workspace.structure.propertyStructureByAlias(propertyAlias)).pipe( - map((property) => (property ? this.#createPropertyVariantId(property) : undefined)), - ); - */ - return createObservablePart( - this._propertyVariantIdMap, - (x) => x.find((v) => v.alias === propertyAlias)?.variantId, - classEqualMemoization, - ); - } - - /** - * @function propertyValueByAlias - * @param {string} propertyAlias The alias of the property - * @returns {Promise | undefined>} - An observable of the property value - * @description Get an Observable for the value of this property. - */ - async propertyValueByAlias( - propertyAlias: string, - ): Promise | undefined> { - await this.#workspace.isLoaded(); - await this.#propertyVariantIdPromise; - const propVariantId = this.#propertyVariantIdMap.getValue().find((x) => x.alias === propertyAlias); - if (propVariantId) { - return this.#workspace.propertyValueByAlias(propertyAlias, propVariantId.variantId); - } - return; - } - - // TODO: Refactor: Not used currently, but should investigate if we can implement this, to spare some energy. - async propertyValueByAliasAndVariantId( - propertyAlias: string, - propertyVariantId: UmbVariantId, - ): Promise | undefined> { - return this.#workspace.propertyValueByAlias(propertyAlias, propertyVariantId); - } - - /** - * @function setPropertyValueByVariant - * @param {string} propertyAlias - The alias of the property - * @param {unknown} value - value can be a promise resolving into the actual value or the raw value it self. - * @param {UmbVariantId} propertyVariantId - The variant id for the value to be set for. - * @returns {Promise} - A promise that resolves once the value has been set. - * @description Get the value of this property. - */ - setPropertyValueByVariant(propertyAlias: string, value: unknown, propertyVariantId: UmbVariantId): Promise { - return this.#workspace.setPropertyValue(propertyAlias, value, propertyVariantId); - } - - /** - * @function setPropertyValue - * @param {string} propertyAlias - The alias for the value to be set - * @param {PromiseLike} value - value can be a promise resolving into the actual value or the raw value it self. - * @returns {Promise} - * @description Set the value of this property. - */ - async setPropertyValue(propertyAlias: string, value: PromiseLike) { - this.#workspace.initiatePropertyValueChange(); - await this.#propertyVariantIdPromise; - const propVariantId = this.#propertyVariantIdMap.getValue().find((x) => x.alias === propertyAlias); - if (propVariantId) { - return this.#workspace.setPropertyValue(propertyAlias, await value, propVariantId.variantId); - } - this.#workspace.finishPropertyValueChange(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content/property-dataset-context/element-property-data-owner.interface.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content/property-dataset-context/element-property-data-owner.interface.ts new file mode 100644 index 0000000000..142f7172de --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content/property-dataset-context/element-property-data-owner.interface.ts @@ -0,0 +1,36 @@ +import type { Observable } from '@umbraco-cms/backoffice/external/rxjs'; +import type { UmbPropertyValueData } from '@umbraco-cms/backoffice/property'; +import type { UmbContentTypeModel, UmbContentTypeStructureManager } from '@umbraco-cms/backoffice/content-type'; +import type { UmbVariantId } from '@umbraco-cms/backoffice/variant'; +import type { UmbApi } from '@umbraco-cms/backoffice/extension-api'; +import type { UmbEntityUnique } from '@umbraco-cms/backoffice/entity'; +import type { UmbReadOnlyVariantStateManager } from '@umbraco-cms/backoffice/utils'; + +/** + * The data supplier for a Element Property Dataset + */ +export interface UmbElementPropertyDataOwner< + ContentModel extends { values: Array }, + ContentTypeModel extends UmbContentTypeModel = UmbContentTypeModel, +> extends UmbApi { + unique: Observable; + getUnique(): UmbEntityUnique | undefined; + getEntityType(): string; + readonly structure: UmbContentTypeStructureManager; + readonly values: Observable; + getValues(): ContentModel['values'] | undefined; + + isLoaded(): Promise | undefined; + readonly readOnlyState: UmbReadOnlyVariantStateManager; + + // Same as from UmbVariantDatasetWorkspaceContext, could be refactored later [NL] + propertyValueByAlias( + alias: string, + variantId?: UmbVariantId, + ): Promise | undefined>; + getPropertyValue(alias: string, variantId?: UmbVariantId): ReturnValue | undefined; + setPropertyValue(alias: string, value: unknown, variantId?: UmbVariantId): Promise; + + initiatePropertyValueChange(): void; + finishPropertyValueChange(): void; +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content/property-dataset-context/element-property-dataset.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content/property-dataset-context/element-property-dataset.context.ts new file mode 100644 index 0000000000..7cf6c376e0 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content/property-dataset-context/element-property-dataset.context.ts @@ -0,0 +1,208 @@ +import type { UmbElementDetailModel } from '../types.js'; +import type { UmbElementPropertyDataOwner } from './element-property-data-owner.interface.js'; +import type { UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property'; +import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; +import type { Observable } from '@umbraco-cms/backoffice/external/rxjs'; +import { + UmbBasicState, + UmbBooleanState, + classEqualMemoization, + createObservablePart, + mergeObservables, +} from '@umbraco-cms/backoffice/observable-api'; +import { UmbVariantId } from '@umbraco-cms/backoffice/variant'; +import type { UmbContentTypeModel, UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type'; +import type { UmbEntityUnique } from '@umbraco-cms/backoffice/entity'; + +type UmbPropertyVariantIdMapType = Array<{ alias: string; variantId: UmbVariantId }>; + +export abstract class UmbElementPropertyDatasetContext< + ContentModel extends UmbElementDetailModel = UmbElementDetailModel, + ContentTypeModel extends UmbContentTypeModel = UmbContentTypeModel, + DataOwnerType extends UmbElementPropertyDataOwner = UmbElementPropertyDataOwner< + ContentModel, + ContentTypeModel + >, + > + extends UmbContextBase + implements UmbPropertyDatasetContext +{ + protected readonly _dataOwner: DataOwnerType; + #variantId: UmbVariantId; + public getVariantId() { + return this.#variantId; + } + + abstract name: Observable; + abstract culture: Observable; + abstract segment: Observable; + + // eslint-disable-next-line no-unused-private-class-members + #propertyVariantIdPromise?: Promise; + #propertyVariantIdPromiseResolver?: () => void; + #propertyVariantIdMap = new UmbBasicState([]); + private readonly _propertyVariantIdMap = this.#propertyVariantIdMap.asObservable(); + + #readOnly = new UmbBooleanState(false); + public readOnly = this.#readOnly.asObservable(); + + getEntityType(): string { + return this._dataOwner.getEntityType(); + } + getUnique(): UmbEntityUnique | undefined { + return this._dataOwner.getUnique(); + } + abstract getName(): string | undefined; + + getReadOnly() { + return this.#readOnly.getValue(); + } + + constructor(host: UmbControllerHost, dataOwner: DataOwnerType, variantId?: UmbVariantId) { + // The controller alias, is a very generic name cause we want only one of these for this controller host. + super(host, UMB_PROPERTY_DATASET_CONTEXT); + this._dataOwner = dataOwner; + this.#variantId = variantId ?? UmbVariantId.CreateInvariant(); + + this.observe( + this._dataOwner.readOnlyState.states, + (states) => { + const isReadOnly = states.some((state) => state.variantId.equal(this.#variantId)); + this.#readOnly.setValue(isReadOnly); + }, + 'umbObserveReadOnlyStates', + ); + + // TODO: Refactor this into a separate manager/controller of some sort? [NL] + this.observe(this._dataOwner.structure.contentTypeProperties, (props: UmbPropertyTypeModel[]) => { + this.#propertyVariantIdPromise ??= new Promise((resolve) => { + this.#propertyVariantIdPromiseResolver = resolve as any; + }); + const map = props.map((prop) => ({ alias: prop.alias, variantId: this.#createPropertyVariantId(prop) })); + this.#propertyVariantIdMap.setValue(map); + // Resolve promise, to let the once waiting on this know. + if (this.#propertyVariantIdPromiseResolver) { + this.#propertyVariantIdPromise = undefined; + this.#propertyVariantIdPromiseResolver(); + this.#propertyVariantIdPromiseResolver = undefined; + } + }); + } + + #createPropertyVariantId(property: UmbPropertyTypeModel) { + return UmbVariantId.Create({ + culture: property.variesByCulture ? this.#variantId.culture : null, + segment: property.variesBySegment ? this.#variantId.segment : null, + }); + } + + #propertiesObservable?: Observable; + // Should it be possible to get the properties as a list of property aliases? + get properties(): Observable { + if (!this.#propertiesObservable) { + this.#propertiesObservable = mergeObservables( + [this._propertyVariantIdMap, this._dataOwner.values], + this.#mergeVariantIdsAndValues, + ); + } + + return this.#propertiesObservable; + } + + #mergeVariantIdsAndValues([props, values]: [UmbPropertyVariantIdMapType, ContentModel['values'] | undefined]) { + const r: ContentModel['values'] = []; + if (values) { + for (const prop of props) { + const f = values.find((v) => prop.alias === v.alias && prop.variantId.compare(v)); + if (f) { + r.push(f); + } + } + } + return r as ContentModel['values']; + } + + async getProperties(): Promise { + await this.#propertyVariantIdPromise; + return this.#mergeVariantIdsAndValues([ + this.#propertyVariantIdMap.getValue(), + this._dataOwner.getValues(), + ]) as ContentModel['values']; + } + + /** + * @function propertyVariantId + * @param {string} propertyAlias - The property alias to observe the variantId of. + * @returns {Promise | undefined>} - The observable for this properties variantId. + * @description Get an Observable for the variant id of this property. + */ + async propertyVariantId(propertyAlias: string) { + /* + return (await this.#workspace.structure.propertyStructureByAlias(propertyAlias)).pipe( + map((property) => (property ? this.#createPropertyVariantId(property) : undefined)), + ); + */ + return createObservablePart( + this._propertyVariantIdMap, + (x) => x.find((v) => v.alias === propertyAlias)?.variantId, + classEqualMemoization, + ); + } + + /** + * @function propertyValueByAlias + * @param {string} propertyAlias The alias of the property + * @returns {Promise | undefined>} - An observable of the property value + * @description Get an Observable for the value of this property. + */ + async propertyValueByAlias( + propertyAlias: string, + ): Promise | undefined> { + await this._dataOwner.isLoaded(); + await this.#propertyVariantIdPromise; + const propVariantId = this.#propertyVariantIdMap.getValue().find((x) => x.alias === propertyAlias); + if (propVariantId) { + return this._dataOwner.propertyValueByAlias(propertyAlias, propVariantId.variantId); + } + return; + } + + // TODO: Refactor: Not used currently, but should investigate if we can implement this, to spare some energy. + async propertyValueByAliasAndVariantId( + propertyAlias: string, + propertyVariantId: UmbVariantId, + ): Promise | undefined> { + return this._dataOwner.propertyValueByAlias(propertyAlias, propertyVariantId); + } + + /** + * @function setPropertyValueByVariant + * @param {string} propertyAlias - The alias of the property + * @param {unknown} value - value can be a promise resolving into the actual value or the raw value it self. + * @param {UmbVariantId} propertyVariantId - The variant id for the value to be set for. + * @returns {Promise} - A promise that resolves once the value has been set. + * @description Get the value of this property. + */ + setPropertyValueByVariant(propertyAlias: string, value: unknown, propertyVariantId: UmbVariantId): Promise { + return this._dataOwner.setPropertyValue(propertyAlias, value, propertyVariantId); + } + + /** + * @function setPropertyValue + * @param {string} propertyAlias - The alias for the value to be set + * @param {PromiseLike} value - value can be a promise resolving into the actual value or the raw value it self. + * @returns {Promise} + * @description Set the value of this property. + */ + async setPropertyValue(propertyAlias: string, value: PromiseLike) { + this._dataOwner.initiatePropertyValueChange(); + await this.#propertyVariantIdPromise; + const propVariantId = this.#propertyVariantIdMap.getValue().find((x) => x.alias === propertyAlias); + if (propVariantId) { + return this._dataOwner.setPropertyValue(propertyAlias, await value, propVariantId.variantId); + } + this._dataOwner.finishPropertyValueChange(); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content/property-dataset-context/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content/property-dataset-context/index.ts new file mode 100644 index 0000000000..69c6bea4c8 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content/property-dataset-context/index.ts @@ -0,0 +1,3 @@ +export * from './content-property-dataset.context.js'; +export * from './element-property-data-owner.interface.js'; +export * from './element-property-dataset.context.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content/types.ts index e049e2250a..a1e7c8cd01 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/content/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content/types.ts @@ -1,11 +1,17 @@ import type { UmbPropertyValueData } from '@umbraco-cms/backoffice/property'; import type { UmbEntityVariantModel } from '@umbraco-cms/backoffice/variant'; -export interface UmbContentValueModel extends UmbPropertyValueData { +export interface UmbElementDetailModel { + values: Array; +} + +export interface UmbElementValueModel extends UmbPropertyValueData { editorAlias: string; culture: string | null; segment: string | null; } +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +export interface UmbContentValueModel extends UmbElementValueModel {} export interface UmbPotentialContentValueModel extends UmbPropertyValueData { editorAlias?: string; @@ -13,9 +19,12 @@ export interface UmbPotentialContentValueModel extends UmbP segment?: string | null; } -export interface UmbContentDetailModel { +export interface UmbContentDetailModel extends UmbElementDetailModel { unique: string; entityType: string; - values: Array; variants: Array; } + +export interface UmbContentLikeDetailModel + extends UmbElementDetailModel, + Partial> {} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content/workspace/content-workspace-context.interface.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content/workspace/content-workspace-context.interface.ts index 1d092e2c73..ecaeca41a7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/content/workspace/content-workspace-context.interface.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content/workspace/content-workspace-context.interface.ts @@ -1,7 +1,6 @@ -import type { UmbContentDetailModel } from '@umbraco-cms/backoffice/content'; +import type { UmbContentDetailModel, UmbElementPropertyDataOwner } from '@umbraco-cms/backoffice/content'; import type { UmbContentTypeModel } from '@umbraco-cms/backoffice/content-type'; import type { Observable } from '@umbraco-cms/backoffice/external/rxjs'; -import type { UmbReadOnlyVariantStateManager } from '@umbraco-cms/backoffice/utils'; import type { UmbVariantId, UmbEntityVariantModel } from '@umbraco-cms/backoffice/variant'; import type { UmbPropertyStructureWorkspaceContext, @@ -13,13 +12,13 @@ export interface UmbContentWorkspaceContext< ContentModel extends UmbContentDetailModel = UmbContentDetailModel, ContentTypeModel extends UmbContentTypeModel = UmbContentTypeModel, VariantModelType extends UmbEntityVariantModel = UmbEntityVariantModel, -> extends UmbRoutableWorkspaceContext, +> extends UmbElementPropertyDataOwner, + UmbRoutableWorkspaceContext, UmbVariantDatasetWorkspaceContext, UmbPropertyStructureWorkspaceContext { readonly IS_CONTENT_WORKSPACE_CONTEXT: true; - readonly readOnlyState: UmbReadOnlyVariantStateManager; - readonly values: Observable; - getValues(): ContentModel['values'] | undefined; + //readonly values: Observable; + //getValues(): ContentModel['values'] | undefined; // Data: getData(): ContentModel | undefined; @@ -27,6 +26,6 @@ export interface UmbContentWorkspaceContext< isLoaded(): Promise | undefined; variantById(variantId: UmbVariantId): Observable; - initiatePropertyValueChange(): void; - finishPropertyValueChange(): void; + //initiatePropertyValueChange(): void; + //finishPropertyValueChange(): void; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-type/workspace/property-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-type/workspace/property-type-workspace.context.ts index 858c6197e1..b9bcfe9751 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-type/workspace/property-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-type/workspace/property-type-workspace.context.ts @@ -1,6 +1,6 @@ import { UmbPropertyTypeWorkspaceEditorElement } from './property-type-workspace-editor.element.js'; import type { UmbPropertyTypeWorkspaceData } from './property-type-workspace.modal-token.js'; -import type { UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property'; +import type { UmbPropertyDatasetContext, UmbPropertyValueData } from '@umbraco-cms/backoffice/property'; import type { UmbInvariantDatasetWorkspaceContext, UmbRoutableWorkspaceContext, @@ -11,6 +11,7 @@ import { UmbInvariantWorkspacePropertyDatasetContext, UmbWorkspaceIsNewRedirectController, UmbWorkspaceIsNewRedirectControllerAlias, + umbObjectToPropertyValueArray, } from '@umbraco-cms/backoffice/workspace'; import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; @@ -18,6 +19,7 @@ import type { UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type' import { UMB_CONTENT_TYPE_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/content-type'; import { UmbId } from '@umbraco-cms/backoffice/id'; import { UmbValidationContext } from '@umbraco-cms/backoffice/validation'; +import { firstValueFrom } from '@umbraco-cms/backoffice/external/rxjs'; export class UmbPropertyTypeWorkspaceContext extends UmbSubmittableWorkspaceContextBase @@ -39,6 +41,13 @@ export class UmbPropertyTypeWorkspaceContext data?.name); readonly unique = this.#data.asObservablePart((data) => data?.id); + readonly values = this.#data.asObservablePart((data) => { + return umbObjectToPropertyValueArray(data); + }); + async getValues(): Promise | undefined> { + return umbObjectToPropertyValueArray(await firstValueFrom(this.data)); + } + constructor(host: UmbControllerHost, args: { manifest: ManifestWorkspace }) { super(host, args.manifest.alias); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property/property-dataset/property-dataset-base-context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property/property-dataset/property-dataset-base-context.ts index 2989a8e596..6338b44a49 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property/property-dataset/property-dataset-base-context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property/property-dataset/property-dataset-base-context.ts @@ -94,7 +94,7 @@ export class UmbPropertyDatasetContextBase /** * @returns {Array} - Array of properties as objects with alias and value properties. */ - getProperties() { + async getProperties() { return this.#properties.getValue(); } /** diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-entity-action-menu/workspace-entity-action-menu.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-entity-action-menu/workspace-entity-action-menu.element.ts index 377cc7cf7f..d7647ae806 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-entity-action-menu/workspace-entity-action-menu.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-entity-action-menu/workspace-entity-action-menu.element.ts @@ -1,16 +1,16 @@ import { UMB_ENTITY_WORKSPACE_CONTEXT } from '../../contexts/index.js'; -import type { UmbWorkspaceUniqueType } from '../../types.js'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { css, html, customElement, state, nothing, query } from '@umbraco-cms/backoffice/external/lit'; import type { UmbActionExecutedEvent } from '@umbraco-cms/backoffice/event'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import type { UUIPopoverContainerElement } from '@umbraco-cms/backoffice/external/uui'; +import type { UmbEntityUnique } from '@umbraco-cms/backoffice/entity'; @customElement('umb-workspace-entity-action-menu') export class UmbWorkspaceEntityActionMenuElement extends UmbLitElement { private _workspaceContext?: typeof UMB_ENTITY_WORKSPACE_CONTEXT.TYPE; @state() - private _unique?: UmbWorkspaceUniqueType; + private _unique?: UmbEntityUnique; @state() private _entityType?: string; @@ -39,14 +39,14 @@ export class UmbWorkspaceEntityActionMenuElement extends UmbLitElement { #onActionExecuted(event: UmbActionExecutedEvent) { event.stopPropagation(); - // TODO: This ignorer is just neede for JSON SCHEMA TO WORK, As its not updated with latest TS jet. + // TODO: This ignorer is just needed for JSON SCHEMA TO WORK, As its not updated with latest TS jet. // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this._popover?.hidePopover(); } #onPopoverToggle(event: ToggleEvent) { - // TODO: This ignorer is just neede for JSON SCHEMA TO WORK, As its not updated with latest TS jet. + // TODO: This ignorer is just needed for JSON SCHEMA TO WORK, As its not updated with latest TS jet. // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this._popoverOpen = event.newState === 'open'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/contexts/tokens/entity-workspace-context.interface.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/contexts/tokens/entity-workspace-context.interface.ts index 46fa7a12c7..022b385e73 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/contexts/tokens/entity-workspace-context.interface.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/contexts/tokens/entity-workspace-context.interface.ts @@ -1,8 +1,8 @@ import type { UmbWorkspaceContext } from '../../workspace-context.interface.js'; -import type { UmbWorkspaceUniqueType } from './../../types.js'; +import type { UmbEntityUnique } from '@umbraco-cms/backoffice/entity'; import type { Observable } from '@umbraco-cms/backoffice/external/rxjs'; export interface UmbEntityWorkspaceContext extends UmbWorkspaceContext { - unique: Observable; - getUnique(): UmbWorkspaceUniqueType | undefined; + unique: Observable; + getUnique(): UmbEntityUnique | undefined; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/data-manager/workspace-data-manager.interface.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/data-manager/workspace-data-manager.interface.ts index 568895229a..a07f81ae54 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/data-manager/workspace-data-manager.interface.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/data-manager/workspace-data-manager.interface.ts @@ -1,8 +1,7 @@ import type { UmbController } from '@umbraco-cms/backoffice/controller-api'; -import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; import type { MappingFunction, Observable } from '@umbraco-cms/backoffice/observable-api'; -export interface UmbWorkspaceDataManager extends UmbController { +export interface UmbWorkspaceDataManager extends UmbController { getPersisted(): ModelType | undefined; getCurrent(): ModelType | undefined; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity/entity-workspace-data-manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity/entity-workspace-data-manager.ts index baceb7e7c8..552dd59903 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity/entity-workspace-data-manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity/entity-workspace-data-manager.ts @@ -1,6 +1,5 @@ import type { UmbWorkspaceDataManager } from '../data-manager/workspace-data-manager.interface.js'; import { jsonStringComparison, UmbObjectState, type MappingFunction } from '@umbraco-cms/backoffice/observable-api'; -import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; /** @@ -10,7 +9,7 @@ import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; * @implements {UmbWorkspaceDataManager} * @template ModelType */ -export class UmbEntityWorkspaceDataManager +export class UmbEntityWorkspaceDataManager extends UmbControllerBase implements UmbWorkspaceDataManager { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/types.ts index 93c0e81b21..eae653cf08 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/types.ts @@ -1,2 +1,7 @@ +import type { UmbEntityUnique } from '@umbraco-cms/backoffice/entity'; + export type * from './extensions/types.js'; -export type UmbWorkspaceUniqueType = string | null; +/** + * @deprecated Use `UmbEntityUnique`instead. + */ +export type UmbWorkspaceUniqueType = UmbEntityUnique; diff --git a/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace.context.ts index d2c01bc008..cd1b9b5839 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace.context.ts @@ -49,6 +49,11 @@ export class UmbDataTypeWorkspaceContext readonly propertyEditorUiAlias = this._data.createObservablePartOfCurrent((data) => data?.editorUiAlias); readonly propertyEditorSchemaAlias = this._data.createObservablePartOfCurrent((data) => data?.editorAlias); + readonly values = this._data.createObservablePartOfCurrent((data) => data?.values); + async getValues() { + return this._data.getCurrent()?.values; + } + #properties = new UmbArrayState([], (x) => x.alias).sortBy( (a, b) => (a.weight || 0) - (b.weight || 0), ); diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/types.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/types.ts index 0c93761201..5b8d1ac93e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/types.ts @@ -2,7 +2,7 @@ import type { UmbDocumentBlueprintEntityType } from './entity.js'; import type { UmbEntityVariantModel, UmbEntityVariantOptionModel } from '@umbraco-cms/backoffice/variant'; import type { UmbReferenceByUnique } from '@umbraco-cms/backoffice/models'; import { DocumentVariantStateModel as UmbDocumentBlueprintVariantState } from '@umbraco-cms/backoffice/external/backend-api'; -import type { UmbContentValueModel } from '@umbraco-cms/backoffice/content'; +import type { UmbElementValueModel } from '@umbraco-cms/backoffice/content'; export { UmbDocumentBlueprintVariantState }; export interface UmbDocumentBlueprintDetailModel { @@ -27,7 +27,7 @@ export interface UmbDocumentBlueprintUrlInfoModel { } // eslint-disable-next-line @typescript-eslint/no-empty-object-type -export interface UmbDocumentBlueprintValueModel extends UmbContentValueModel {} +export interface UmbDocumentBlueprintValueModel extends UmbElementValueModel {} // eslint-disable-next-line @typescript-eslint/no-empty-object-type export interface UmbDocumentBlueprintVariantOptionModel diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/types.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/types.ts index 39c63629e1..02ef1bbdb4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/types.ts @@ -6,7 +6,7 @@ import type { } from '@umbraco-cms/backoffice/variant'; import type { UmbReferenceByUnique } from '@umbraco-cms/backoffice/models'; import { DocumentVariantStateModel as UmbDocumentVariantState } from '@umbraco-cms/backoffice/external/backend-api'; -import type { UmbContentDetailModel, UmbContentValueModel } from '@umbraco-cms/backoffice/content'; +import type { UmbContentDetailModel, UmbElementValueModel } from '@umbraco-cms/backoffice/content'; export { UmbDocumentVariantState }; export interface UmbDocumentDetailModel extends UmbContentDetailModel { @@ -34,7 +34,7 @@ export interface UmbDocumentUrlInfoModel { } // eslint-disable-next-line @typescript-eslint/no-empty-object-type -export interface UmbDocumentValueModel extends UmbContentValueModel {} +export interface UmbDocumentValueModel extends UmbElementValueModel {} // eslint-disable-next-line @typescript-eslint/no-empty-object-type export interface UmbDocumentVariantOptionModel extends UmbEntityVariantOptionModel {} 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 ff92c1aa1f..4813b6a90e 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 @@ -302,6 +302,7 @@ export class UmbDocumentWorkspaceContext async load(unique: string) { this.resetState(); this.#getDataPromise = this.repository.requestByUnique(unique); + type GetDataType = Awaited>; const { data, asObservable } = (await this.#getDataPromise) as GetDataType; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/types.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/types.ts index c1bde82de5..b622c93b33 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/types.ts @@ -1,7 +1,7 @@ import type { UmbMediaEntityType } from './entity.js'; import type { UmbEntityVariantModel, UmbEntityVariantOptionModel } from '@umbraco-cms/backoffice/variant'; import type { UmbReferenceByUnique } from '@umbraco-cms/backoffice/models'; -import type { UmbContentDetailModel, UmbContentValueModel } from '@umbraco-cms/backoffice/content'; +import type { UmbContentDetailModel, UmbElementValueModel } from '@umbraco-cms/backoffice/content'; export interface UmbMediaDetailModel extends UmbContentDetailModel { mediaType: { @@ -25,7 +25,7 @@ export interface UmbMediaUrlInfoModel { export interface UmbMediaVariantModel extends UmbEntityVariantModel {} // eslint-disable-next-line @typescript-eslint/no-empty-object-type -export interface UmbMediaValueModel extends UmbContentValueModel {} +export interface UmbMediaValueModel extends UmbElementValueModel {} // eslint-disable-next-line @typescript-eslint/no-empty-object-type export interface UmbMediaVariantOptionModel extends UmbEntityVariantOptionModel {} diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/types.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/types.ts index ca70bdbb59..db66e77104 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/types.ts @@ -1,7 +1,7 @@ import type { UmbMemberEntityType } from './entity.js'; import type { UmbMemberKindType } from './utils/index.js'; import type { UmbEntityVariantModel, UmbEntityVariantOptionModel } from '@umbraco-cms/backoffice/variant'; -import type { UmbContentDetailModel, UmbContentValueModel } from '@umbraco-cms/backoffice/content'; +import type { UmbContentDetailModel, UmbElementValueModel } from '@umbraco-cms/backoffice/content'; export interface UmbMemberDetailModel extends UmbContentDetailModel { email: string; @@ -28,7 +28,7 @@ export interface UmbMemberDetailModel extends UmbContentDetailModel { export interface UmbMemberVariantModel extends UmbEntityVariantModel {} // eslint-disable-next-line @typescript-eslint/no-empty-object-type -export interface UmbMemberValueModel extends UmbContentValueModel {} +export interface UmbMemberValueModel extends UmbElementValueModel {} // eslint-disable-next-line @typescript-eslint/no-empty-object-type export interface UmbMemberVariantOptionModel extends UmbEntityVariantOptionModel {} diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/workspace/member/member-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/workspace/member/member-workspace.context.ts index b4ac6079e3..06a24a07ec 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/workspace/member/member-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/workspace/member/member-workspace.context.ts @@ -18,7 +18,6 @@ import { UmbWorkspaceIsNewRedirectController, UmbWorkspaceIsNewRedirectControllerAlias, UmbWorkspaceSplitViewManager, - umbObjectToPropertyValueArray, } from '@umbraco-cms/backoffice/workspace'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { @@ -35,7 +34,7 @@ import type { UmbDataSourceResponse } from '@umbraco-cms/backoffice/repository'; import { UmbContentWorkspaceDataManager, type UmbContentWorkspaceContext } from '@umbraco-cms/backoffice/content'; import { UmbReadOnlyVariantStateManager } from '@umbraco-cms/backoffice/utils'; import { UmbDataTypeItemRepositoryManager } from '@umbraco-cms/backoffice/data-type'; -import { firstValueFrom, map } from '@umbraco-cms/backoffice/external/rxjs'; +import { map } from '@umbraco-cms/backoffice/external/rxjs'; import { UmbEntityContext, type UmbEntityModel } from '@umbraco-cms/backoffice/entity'; import { UmbRequestReloadChildrenOfEntityEvent, diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/property-value-resolver/rte-block-value-resolver.api.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/property-value-resolver/rte-block-value-resolver.api.ts index fbf8f45d17..b9d77a5d15 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/rte/property-value-resolver/rte-block-value-resolver.api.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/rte/property-value-resolver/rte-block-value-resolver.api.ts @@ -4,11 +4,11 @@ import { type UmbBlockDataValueModel, type UmbBlockExposeModel, } from '@umbraco-cms/backoffice/block'; -import type { UmbContentValueModel } from '@umbraco-cms/backoffice/content'; +import type { UmbElementValueModel } from '@umbraco-cms/backoffice/content'; export class UmbRteBlockValueResolver extends UmbBlockValueResolver { async processValues( - property: UmbContentValueModel, + property: UmbElementValueModel, valuesCallback: (values: Array) => Promise | undefined>, ) { if (property.value) { @@ -24,7 +24,7 @@ export class UmbRteBlockValueResolver extends UmbBlockValueResolver, + property: UmbElementValueModel, variantsCallback: (values: Array) => Promise | undefined>, ) { if (property.value) {