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 d275ef2f0d..fa305961d4 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,6 +1,9 @@ -import type { UmbBlockDataValueModel, UmbBlockValueType } from '../types.js'; +import type { UmbBlockDataValueModel, UmbBlockExposeModel, UmbBlockValueType } from '../types.js'; import type { UmbContentValueModel } from '@umbraco-cms/backoffice/content'; -import type { UmbPropertyValueResolver } from '@umbraco-cms/backoffice/property'; +import type { + UmbPropertyValueResolver, + UmbPropertyValueResolverEnsureVariantArgs, +} from '@umbraco-cms/backoffice/property'; export class UmbBlockValueResolver implements UmbPropertyValueResolver, UmbBlockDataValueModel> @@ -35,5 +38,43 @@ export class UmbBlockValueResolver return property; } + async ensureVariants( + property: UmbContentValueModel, + args: UmbPropertyValueResolverEnsureVariantArgs, + ) { + if (property.value && args.selectedVariants) { + const currentExposes = property.value.expose ?? []; + const contentKeys = property.value.contentData.map((x) => x.key); + + const newExposes = contentKeys.flatMap((contentKey) => + args.selectedVariants.map((v) => ({ + contentKey: contentKey, + culture: v.culture, + segment: v.segment, + })), + ) as Array; + + // make exposes unique: + const expose = [ + ...currentExposes, + ...newExposes.filter( + (n) => + !currentExposes.some( + (p) => p.contentKey === n.contentKey && p.culture === n.culture && p.segment === n.segment, + ), + ), + ]; + + return { + ...property, + value: { + ...property.value, + expose, + }, + }; + } + return property; + } + destroy(): void {} } 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 bf2728652f..587a317675 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 @@ -112,11 +112,12 @@ export class UmbContentWorkspaceDataManager< // 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 { - selectedVariants = [...selectedVariants, invariantVariantId]; + variantsToStore = [...selectedVariants, invariantVariantId]; } const data = this.current.getValue(); @@ -134,6 +135,7 @@ export class UmbContentWorkspaceDataManager< persistedData?.values, data.values, selectedVariants, + variantsToStore, ), variants: this.#buildSaveVariants(persistedData?.variants, data.variants, selectedVariants), }; @@ -145,57 +147,52 @@ export class UmbContentWorkspaceDataManager< persistedValues: Array | undefined, draftValues: Array | undefined, selectedVariants: Array, + variantsToStore: Array, ): Promise> { - // Make array of unique values, based on persistedValues and draftValues. unique values are based upon alias culture and segment - const uniqueValues = [ - ...new Set( - [...(persistedValues ?? []), ...(draftValues ?? [])].map((x) => ({ - alias: x.alias, - culture: x.culture, - segment: x.segment, - })), - ), - ]; + // Make array of unique values, based on persistedValues and draftValues. Both alias, culture and segment has to be taken into account. [NL] + + const uniqueValues = [...(persistedValues ?? []), ...(draftValues ?? [])].filter( + (n, i, self) => + i === self.findIndex((v) => v.alias === n.alias && v.culture === n.culture && v.segment === n.segment), + ); // Map unique values to their respective draft values. - return await Promise.all( - uniqueValues - .map((value) => { + return ( + await Promise.all( + uniqueValues.map((value) => { const persistedValue = persistedValues?.find( (x) => x.alias === value.alias && x.culture === value.culture && x.segment === value.segment, ); + // Should this value be saved? - if (selectedVariants.some((x) => x.equal(UmbVariantId.CreateFromPartial(value)))) { + if (variantsToStore.some((x) => x.equal(UmbVariantId.CreateFromPartial(value)))) { const draftValue = draftValues?.find( (x) => x.alias === value.alias && x.culture === value.culture && x.segment === value.segment, ); - return this.#buildSaveValue(persistedValue, draftValue, selectedVariants); + return this.#buildSaveValue(persistedValue, draftValue, selectedVariants, variantsToStore); } else { // TODO: Check if this promise is needed: [NL] return Promise.resolve(persistedValue); } - }) - .filter((x) => x !== undefined) as Array>, - ); + }), + ) + ).filter((x) => x !== undefined) as Array; } async #buildSaveValue( persistedValue: UmbPotentialContentValueModel | undefined, draftValue: UmbPotentialContentValueModel | undefined, selectedVariants: Array, + variantsToStore: Array, ): Promise { const editorAlias = draftValue?.editorAlias ?? persistedValue?.editorAlias; if (!editorAlias) { console.error(`Editor alias not found for ${editorAlias}`); return draftValue; } - if (!persistedValue) { - // If the persisted value does not exists then no need to combine. - return draftValue; - } if (!draftValue) { - // If the draft value does not exists then no need to combine. + // If the draft value does not exists then no need to process. return undefined; } @@ -216,27 +213,41 @@ export class UmbContentWorkspaceDataManager< return draftValue; } + let newValue = draftValue; + if (api.processValues) { // The a property values resolver resolves one value, we need to gather the persisted inner values first, and store them here: const persistedValuesHolder: Array> = []; - await api.processValues(persistedValue, async (values) => { - persistedValuesHolder.push(values as unknown as Array); - return undefined; - }); + if (persistedValue) { + await api.processValues(persistedValue, async (values) => { + persistedValuesHolder.push(values as unknown as Array); + return undefined; + }); + } let valuesIndex = 0; - return await api.processValues(draftValue, async (values) => { + newValue = await api.processValues(newValue, async (values) => { // got some values (content and/or settings): // but how to get the persisted and the draft of this..... const persistedValues = persistedValuesHolder[valuesIndex++]; - return await this.#buildSaveValues(persistedValues, values, selectedVariants); + return await this.#buildSaveValues(persistedValues, values, selectedVariants, variantsToStore); }); } + if (api.ensureVariants) { + // The a property values resolver resolves one value, we need to gather the persisted inner values first, and store them here: + //const persistedVariants = newValue ? ((await api.readVariants(newValue)) ?? []) : []; + + const args = { + selectedVariants, + }; + newValue = await api.ensureVariants(newValue, args); + } + // the api did not provide a value processor, so we will return the draftValue: - return draftValue; + return newValue; } #buildSaveVariants( diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property/property-value-resolver/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property/property-value-resolver/types.ts index 4dda7a010a..0e6cbcd0e3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property/property-value-resolver/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property/property-value-resolver/types.ts @@ -1,5 +1,5 @@ -import type { UmbEntityVariantModel } from '../../variant/types.js'; import type { UmbPropertyValueData } from '../types/index.js'; +import type { UmbVariantId } from '@umbraco-cms/backoffice/variant'; import type { UmbApi } from '@umbraco-cms/backoffice/extension-api'; export type * from './property-value-resolver.extension.js'; @@ -7,10 +7,9 @@ export type * from './property-value-resolver.extension.js'; export interface UmbPropertyValueResolver< PropertyValueType extends UmbPropertyValueData = UmbPropertyValueData, InnerPropertyValueType extends UmbPropertyValueData = PropertyValueType, - InnerVariantModelType extends UmbEntityVariantModel = UmbEntityVariantModel, > extends UmbApi { processValues?: UmbPropertyValueResolverValueProcessor; - processVariants?: UmbPropertyValueResolverVariantProcessor; + ensureVariants?: UmbPropertyValueResolverEnsureVariants; } export type UmbPropertyValueResolverValueProcessor< @@ -21,10 +20,13 @@ export type UmbPropertyValueResolverValueProcessor< valuesProcessor: (values: Array) => Promise | undefined>, ) => PromiseLike; -export type UmbPropertyValueResolverVariantProcessor< +export type UmbPropertyValueResolverEnsureVariants< PropertyValueType extends UmbPropertyValueData = UmbPropertyValueData, - VariantType extends UmbEntityVariantModel = UmbEntityVariantModel, > = ( value: PropertyValueType, - variantsProcessor: (variants: Array) => Promise | undefined>, + args: UmbPropertyValueResolverEnsureVariantArgs, ) => PromiseLike; + +export type UmbPropertyValueResolverEnsureVariantArgs = { + selectedVariants: Array; +};