Property Value Preset builder caller args (#20111)

* update types for callArgs

* note for Engage

* implement callArgs type updates

* tests

* implement callArgs for Value Preset Builder

* updated fallback and console.log feedback

* change to warn

* remove unused import

* JS docs

* TODO

* lint fix
This commit is contained in:
Niels Lyngsø
2025-09-16 12:07:54 +02:00
committed by GitHub
parent ef1aaf8bce
commit 5fd01e000c
8 changed files with 102 additions and 16 deletions

View File

@@ -414,7 +414,11 @@ export abstract class UmbBlockManagerContext<
if (segments) {
controller.setSegments(segments);
}
const values = await controller.create(valueDefinitions);
const values = await controller.create(valueDefinitions, {
entityType: 'block',
entityUnique: key,
entityTypeUnique: contentTypeKey,
});
// Set culture and segment for all values:

View File

@@ -382,8 +382,12 @@ export abstract class UmbContentDetailWorkspaceContextBase<
}
protected override async _scaffoldProcessData(data: DetailModelType): Promise<DetailModelType> {
const contentTypeUnique: string | undefined = (data as any)[this.#contentTypePropertyName].unique;
if (!contentTypeUnique) {
throw new Error(`Could not find content type unique on property '${this.#contentTypePropertyName}'`);
}
// Load the content type structure, usually this comes from the data, but in this case we are making the data, and we need this to be able to complete the data. [NL]
await this.structure.loadType((data as any)[this.#contentTypePropertyName].unique);
await this.structure.loadType(contentTypeUnique);
/**
* TODO: Should we also set Preset Values when loading Content, because maybe content contains uncreated Cultures or Segments.
@@ -393,6 +397,7 @@ export abstract class UmbContentDetailWorkspaceContextBase<
const cultures = this.#languages.getValue().map((x) => x.unique);
if (this.structure.variesBySegment) {
// TODO: v.17 Engage please note we have not implemented support for segments yet. [NL]
console.warn('Segments are not yet implemented for preset');
}
// TODO: Add Segments for Presets:
@@ -432,7 +437,11 @@ export abstract class UmbContentDetailWorkspaceContextBase<
controller.setSegments(segments);
}
const presetValues = await controller.create(valueDefinitions);
const presetValues = await controller.create(valueDefinitions, {
entityType: this.getEntityType(),
entityUnique: data.unique,
entityTypeUnique: contentTypeUnique,
});
// Don't just set the values, as we could have some already populated from a blueprint.
// If we have a value from both a blueprint and a preset, use the latter as priority.

View File

@@ -72,7 +72,10 @@ describe('UmbPropertyValuePresetBuilderController', () => {
},
];
const result = await ctrl.create(propertyTypes);
const result = await ctrl.create(propertyTypes, {
entityUnique: 'test-unique',
entityType: 'test',
});
expect(result.length).to.be.equal(1);
expect(result[0]?.value).to.be.equal('first');
@@ -120,7 +123,10 @@ describe('UmbPropertyValuePresetBuilderController', () => {
},
];
const result = await ctrl.create(propertyTypes);
const result = await ctrl.create(propertyTypes, {
entityUnique: 'test-unique',
entityType: 'test',
});
expect(result.length).to.be.equal(1);
expect(result[0]?.value).to.be.equal('first_second');
@@ -168,7 +174,10 @@ describe('UmbPropertyValuePresetBuilderController', () => {
},
];
const result = await ctrl.create(propertyTypes);
const result = await ctrl.create(propertyTypes, {
entityUnique: 'test-unique',
entityType: 'test',
});
expect(result.length).to.be.equal(1);
expect(result[0]?.value).to.be.equal('second_first');
@@ -233,7 +242,10 @@ describe('UmbPropertyValuePresetBuilderController', () => {
},
];
const result = await ctrl.create(propertyTypes);
const result = await ctrl.create(propertyTypes, {
entityUnique: 'test-unique',
entityType: 'test',
});
expect(result.length).to.be.equal(2);
expect(result[0]?.alias).to.be.equal('test');
@@ -310,7 +322,10 @@ describe('UmbPropertyValuePresetBuilderController', () => {
},
];
const result = await ctrl.create(propertyTypes);
const result = await ctrl.create(propertyTypes, {
entityUnique: 'test-unique',
entityType: 'test',
});
// Test that only the right presets are used:
expect(result.length).to.be.equal(3);

View File

@@ -5,6 +5,7 @@ import type {
UmbPropertyTypePresetWithSchemaAliasModel,
UmbPropertyValuePreset,
UmbPropertyValuePresetApiCallArgs,
UmbPropertyValuePresetApiCallArgsEntityBase,
} from './types.js';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { createExtensionApi } from '@umbraco-cms/backoffice/extension-api';
@@ -15,14 +16,37 @@ const EMPTY_CALL_ARGS = Object.freeze({});
export class UmbPropertyValuePresetBuilderController<
ReturnType = UmbPropertyValueData | UmbPropertyValueDataPotentiallyWithEditorAlias,
> extends UmbControllerBase {
#baseCreateArgs?: UmbPropertyValuePresetApiCallArgsEntityBase;
/**
* Clones the property data.
* @param {UmbPropertyValueDataPotentiallyWithEditorAlias} propertyTypes - Data about the properties to make a preset for.
* @param createArgs
* @returns {Promise<UmbPropertyValueDataPotentiallyWithEditorAlias>} - A promise that resolves to the cloned property data.
*/
async create<GivenPropertyTypesType extends UmbPropertyTypePresetModel>(
propertyTypes: Array<GivenPropertyTypesType>,
// TODO: Remove Option argument and Partial<> in v.17.0 [NL]
createArgs?: Partial<UmbPropertyValuePresetApiCallArgsEntityBase>,
): Promise<Array<ReturnType>> {
//
// TODO: Clean up warnings in v.17.0 [NL]
this.#baseCreateArgs = {
entityType:
createArgs?.entityType ??
'needs to be parsed to the UmbPropertyValuePresetBuilderController, this is not present because of a custom legacy implementation',
entityUnique:
createArgs?.entityUnique ??
'needs to be parsed to the UmbPropertyValuePresetBuilderController, this is not present because of a custom legacy implementation',
entityTypeUnique: createArgs?.entityTypeUnique,
};
if (!createArgs?.entityUnique || !createArgs?.entityType) {
console.warn(
`entityUnique or entityType was not provided for UmbPropertyValuePresetBuilderController.create in the second argument. This will be required in v.17.0 and must be provided when calling create().`,
);
}
const result = await Promise.all(propertyTypes.map(this.#createPropertyPreset));
//Merge all the values into a single array:
@@ -87,9 +111,17 @@ export class UmbPropertyValuePresetBuilderController<
protected async _generatePropertyValue(
apis: Array<UmbPropertyValuePreset>,
propertyType: UmbPropertyTypePresetModel | UmbPropertyTypePresetWithSchemaAliasModel,
callArgs: UmbPropertyValuePresetApiCallArgs,
incomingCallArgs: Partial<UmbPropertyValuePresetApiCallArgs>,
): Promise<ReturnType | undefined> {
let value: unknown = undefined;
const callArgs: UmbPropertyValuePresetApiCallArgs = {
...this.#baseCreateArgs!,
alias: propertyType.alias,
propertyEditorUiAlias: propertyType.propertyEditorUiAlias,
propertyEditorSchemaAlias: (propertyType as UmbPropertyTypePresetWithSchemaAliasModel).propertyEditorSchemaAlias,
...incomingCallArgs,
};
// Important to use a inline for loop, to secure that each entry is processed(asynchronously) in order
for (const api of apis) {
if (!api.processValue) {

View File

@@ -63,7 +63,10 @@ describe('UmbPropertyValuePresetVariantBuilderController', () => {
},
];
const result = await ctrl.create(propertyTypes);
const result = await ctrl.create(propertyTypes, {
entityType: 'test',
entityUnique: 'some-unique',
});
expect(result.length).to.be.equal(2);
expect(result[0]?.value).to.be.equal('value for culture cultureA');
@@ -86,7 +89,10 @@ describe('UmbPropertyValuePresetVariantBuilderController', () => {
];
try {
await ctrl.create(propertyTypes);
await ctrl.create(propertyTypes, {
entityType: 'test',
entityUnique: 'some-unique',
});
expect.fail('Expected to fail');
} catch (e) {}
});
@@ -105,7 +111,10 @@ describe('UmbPropertyValuePresetVariantBuilderController', () => {
},
];
const result = await ctrl.create(propertyTypes);
const result = await ctrl.create(propertyTypes, {
entityType: 'test',
entityUnique: 'some-unique',
});
expect(result.length).to.be.equal(3);
expect(result[0]?.value).to.be.equal('value for culture invariant');
@@ -132,7 +141,10 @@ describe('UmbPropertyValuePresetVariantBuilderController', () => {
},
];
const result = await ctrl.create(propertyTypes);
const result = await ctrl.create(propertyTypes, {
entityType: 'test',
entityUnique: 'some-unique',
});
expect(result.length).to.be.equal(1);
expect(result[0]?.value).to.be.equal('value for culture invariant');
@@ -155,7 +167,10 @@ describe('UmbPropertyValuePresetVariantBuilderController', () => {
},
];
const result = await ctrl.create(propertyTypes);
const result = await ctrl.create(propertyTypes, {
entityType: 'test',
entityUnique: 'some-unique',
});
expect(result.length).to.be.equal(6);

View File

@@ -14,6 +14,8 @@ export class UmbPropertyValuePresetVariantBuilderController extends UmbPropertyV
// Always declare the default segment (null)
#segments: Array<null | string> = [null];
// TODO: We properly need to break this, as Engage needs to control which Segments are available for each culture, maybe investigate the option to go about a new option to just parse options.? Break in v.17.0 [NL]
setCultures(cultures: Array<string>): void {
this.#cultures = cultures;
}

View File

@@ -33,7 +33,17 @@ export interface UmbPropertyTypePresetModelTypeModel {
variesByCulture?: boolean;
variesBySegment?: boolean;
}
export interface UmbPropertyValuePresetApiCallArgs {
export interface UmbPropertyValuePresetApiCallArgsEntityBase {
entityType: string;
entityUnique: string;
entityTypeUnique?: string;
}
export interface UmbPropertyValuePresetApiCallArgs extends UmbPropertyValuePresetApiCallArgsEntityBase {
alias: string;
propertyEditorUiAlias: string;
propertyEditorSchemaAlias?: string;
variantId?: UmbVariantId;
}

View File

@@ -4,4 +4,3 @@ import { Italic } from '@umbraco-cms/backoffice/external/tiptap';
export default class UmbTiptapItalicExtensionApi extends UmbTiptapExtensionApiBase {
getTiptapExtensions = () => [Italic];
}