Merge branch 'release/15.0' into v15/hotfix/create-options-extension-point
This commit is contained in:
@@ -149,7 +149,7 @@ export class UmbBlockGridEntriesElement extends UmbFormControlMixin(UmbLitElemen
|
||||
// Currently there is no server validation for areas. So we can leave out the data path for it for now. [NL]
|
||||
this.#controlValidator = new UmbFormControlValidator(this, this);
|
||||
|
||||
//new UmbBindServerValidationToFormControl(this, this, "$.values.[?(@.alias = 'my-input-alias')].value");
|
||||
//new UmbBindServerValidationToFormControl(this, this, "$.values.[?(@.alias == 'my-input-alias')].value");
|
||||
}
|
||||
}
|
||||
public get areaKey(): string | null | undefined {
|
||||
|
||||
@@ -118,7 +118,6 @@ export class UmbPropertyEditorUIBlockListElement
|
||||
/**
|
||||
* Sets the input to readonly mode, meaning value cannot be changed but still able to read and select its content.
|
||||
* @type {boolean}
|
||||
* @attr
|
||||
* @default
|
||||
*/
|
||||
@property({ type: Boolean, reflect: true })
|
||||
@@ -156,8 +155,6 @@ export class UmbPropertyEditorUIBlockListElement
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
//this.#validationContext.messages.debug('block list');
|
||||
|
||||
this.consumeContext(UMB_PROPERTY_CONTEXT, (context) => {
|
||||
this.observe(
|
||||
context.dataPath,
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
import {
|
||||
GetPropertyNameFromPath,
|
||||
UmbDataPathPropertyValueQuery,
|
||||
UmbValidationPathTranslatorBase,
|
||||
} from '@umbraco-cms/backoffice/validation';
|
||||
|
||||
export class UmbBlockElementDataValidationPathTranslator extends UmbValidationPathTranslatorBase {
|
||||
constructor(host: UmbControllerHost) {
|
||||
super(host);
|
||||
}
|
||||
|
||||
translate(path: string) {
|
||||
if (!this._context) return;
|
||||
if (path.indexOf('$.') !== 0) {
|
||||
// We do not handle this path.
|
||||
return false;
|
||||
}
|
||||
|
||||
const rest = path.substring(2);
|
||||
const key = GetPropertyNameFromPath(rest);
|
||||
|
||||
const specificValue = { alias: key };
|
||||
// replace the values[ number ] with JSON-Path filter values[@.(...)], continues by the rest of the path:
|
||||
//return '$.values' + UmbVariantValuesValidationPathTranslator(specificValue) + path.substring(path.indexOf(']'));
|
||||
return '$.values[' + UmbDataPathPropertyValueQuery(specificValue) + '.value';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
import {
|
||||
UmbAbstractArrayValidationPathTranslator,
|
||||
UmbDataPathPropertyValueQuery,
|
||||
} from '@umbraco-cms/backoffice/validation';
|
||||
|
||||
export class UmbBlockElementValuesDataValidationPathTranslator extends UmbAbstractArrayValidationPathTranslator {
|
||||
constructor(host: UmbControllerHost) {
|
||||
super(host, '$.values[', UmbDataPathPropertyValueQuery);
|
||||
}
|
||||
|
||||
getDataFromIndex(index: number) {
|
||||
if (!this._context) return;
|
||||
const data = this._context.getTranslationData();
|
||||
return data.values[index];
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,14 @@ import type { UmbBlockDataModel } from '../types.js';
|
||||
|
||||
/**
|
||||
* Validation Data Path Query generator for Block Element Data.
|
||||
* write a JSON-Path filter similar to `?(@.key = 'my-key://1234')`
|
||||
* write a JSON-Path filter similar to `?(@.key == 'my-key://1234')`
|
||||
* @param key {string} - The key of the block Element data.
|
||||
* @param data {{key: string}} - A data object with the key property.
|
||||
* @returns
|
||||
*/
|
||||
export function UmbDataPathBlockElementDataQuery(data: Pick<UmbBlockDataModel, 'key'>): string {
|
||||
// write a array of strings for each property, where alias must be present and culture and segment are optional
|
||||
//const filters: Array<string> = [`@.key = '${key}'`];
|
||||
//const filters: Array<string> = [`@.key == '${key}'`];
|
||||
//return `?(${filters.join(' && ')})`;
|
||||
return `?(@.key = '${data.key}')`;
|
||||
return `?(@.key == '${data.key}')`;
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from './block-data-validation-path-translator.controller.js';
|
||||
export * from './block-element-values-validation-path-translator.controller.js';
|
||||
export * from './block-element-data-validation-path-translator.controller.js';
|
||||
export * from './data-path-element-data-query.function.js';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { UmbBlockDataModel, UmbBlockDataValueModel } from '../types.js';
|
||||
import { UmbBlockElementValuesDataValidationPathTranslator } from '../validation/block-element-values-validation-path-translator.controller.js';
|
||||
import { UmbBlockElementPropertyDatasetContext } from './block-element-property-dataset.context.js';
|
||||
import type { UmbContentTypeModel, UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type';
|
||||
import { UmbContentTypeStructureManager } from '@umbraco-cms/backoffice/content-type';
|
||||
@@ -43,7 +44,7 @@ export class UmbBlockElementManager extends UmbControllerBase {
|
||||
this.observe(this.contentTypeId, (id) => this.structure.loadType(id));
|
||||
this.observe(this.unique, (key) => {
|
||||
if (key) {
|
||||
this.validation.setDataPath('$.' + dataPathPropertyName + `[?(@.key = '${key}')]`);
|
||||
this.validation.setDataPath('$.' + dataPathPropertyName + `[?(@.key == '${key}')]`);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -198,6 +199,9 @@ export class UmbBlockElementManager extends UmbControllerBase {
|
||||
|
||||
// Provide Validation Context for this view:
|
||||
this.validation.provideAt(host);
|
||||
|
||||
// TODO: Implement ctrl alias.
|
||||
new UmbBlockElementValuesDataValidationPathTranslator(host);
|
||||
}
|
||||
|
||||
public override destroy(): void {
|
||||
|
||||
@@ -5,6 +5,8 @@ import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import type { UmbContentTypeModel, UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type';
|
||||
import { UmbContentTypePropertyStructureHelper } from '@umbraco-cms/backoffice/content-type';
|
||||
import { UmbLitElement, umbDestroyOnDisconnect } from '@umbraco-cms/backoffice/lit-element';
|
||||
import type { UmbVariantId } from '@umbraco-cms/backoffice/variant';
|
||||
import { UmbDataPathPropertyValueQuery } from '@umbraco-cms/backoffice/validation';
|
||||
|
||||
@customElement('umb-block-workspace-view-edit-properties')
|
||||
export class UmbBlockWorkspaceViewEditPropertiesElement extends UmbLitElement {
|
||||
@@ -38,12 +40,22 @@ export class UmbBlockWorkspaceViewEditPropertiesElement extends UmbLitElement {
|
||||
@state()
|
||||
private _ownerEntityType?: string;
|
||||
|
||||
#variantId?: UmbVariantId;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext(UMB_BLOCK_WORKSPACE_CONTEXT, (workspaceContext) => {
|
||||
this.#blockWorkspace = workspaceContext;
|
||||
this._ownerEntityType = this.#blockWorkspace.getEntityType();
|
||||
this.observe(
|
||||
workspaceContext.variantId,
|
||||
(variantId) => {
|
||||
this.#variantId = variantId;
|
||||
this.#generatePropertyDataPath();
|
||||
},
|
||||
'observeVariantId',
|
||||
);
|
||||
this.#setStructureManager();
|
||||
});
|
||||
}
|
||||
@@ -61,10 +73,24 @@ export class UmbBlockWorkspaceViewEditPropertiesElement extends UmbLitElement {
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
#generatePropertyDataPath() {
|
||||
if (!this._propertyStructure) return;
|
||||
this._dataPaths = this._propertyStructure.map((property) => `$.${property.alias}`);
|
||||
}
|
||||
*/
|
||||
|
||||
#generatePropertyDataPath() {
|
||||
if (!this.#variantId || !this._propertyStructure) return;
|
||||
this._dataPaths = this._propertyStructure.map(
|
||||
(property) =>
|
||||
`$.values[${UmbDataPathPropertyValueQuery({
|
||||
alias: property.alias,
|
||||
culture: property.variesByCulture ? this.#variantId!.culture : null,
|
||||
segment: property.variesBySegment ? this.#variantId!.segment : null,
|
||||
})}].value`,
|
||||
);
|
||||
}
|
||||
|
||||
override render() {
|
||||
return repeat(
|
||||
|
||||
@@ -130,7 +130,6 @@ export class UmbPropertyElement extends UmbLitElement {
|
||||
* DataPath, declare the path to the value of the data that this property represents.
|
||||
* @public
|
||||
* @type {string}
|
||||
* @attr
|
||||
* @default
|
||||
*/
|
||||
@property({ type: String, attribute: 'data-path' })
|
||||
|
||||
@@ -15,7 +15,7 @@ A Validation message consist of a type, path and body. This typically looks like
|
||||
```
|
||||
{
|
||||
type: "client",
|
||||
path: "$.values[?(@.alias = 'my-property-alias')].value",
|
||||
path: "$.values[?(@.alias == 'my-property-alias')].value",
|
||||
message: "Must contain at least 3 words"
|
||||
}
|
||||
```
|
||||
@@ -61,7 +61,7 @@ Data:
|
||||
|
||||
JsonPath:
|
||||
```
|
||||
"$.values.[?(@.alias = 'my-alias')].value"
|
||||
"$.values.[?(@.alias == 'my-alias')].value"
|
||||
```
|
||||
|
||||
Paths are based on JSONPath, using JSON Path Queries when looking up data of an Array. Using Queries enables Paths to not point to specific index, but what makes a entry unique.
|
||||
@@ -107,7 +107,7 @@ Such conversation could be from this path:
|
||||
|
||||
To this path:
|
||||
```
|
||||
"$.values.[?(@.alias = 'my-alias')].value"
|
||||
"$.values.[?(@.alias == 'my-alias')].value"
|
||||
```
|
||||
|
||||
Once this path is converted to use Json Path Queries, the Data can be changed. The concerned entry might get another index. Without that affecting the accuracy of the path.
|
||||
@@ -135,7 +135,7 @@ The Data Path is a JSON Path defining where the data of this input is located in
|
||||
this.#validationMessageBinder = new UmbBindServerValidationToFormControl(
|
||||
this,
|
||||
this.querySelector('#myInput"),
|
||||
"$.values.[?(@.alias = 'my-input-alias')].value",
|
||||
"$.values.[?(@.alias == 'my-input-alias')].value",
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
@@ -100,10 +100,10 @@ export class UmbValidationController extends UmbControllerBase implements UmbVal
|
||||
* @example
|
||||
* ```ts
|
||||
* const validationContext = new UmbValidationContext(this);
|
||||
* validationContext.setDataPath("$.values[?(@.alias='my-property')].value");
|
||||
* validationContext.setDataPath("$.values[?(@.alias == 'my-property')].value");
|
||||
* ```
|
||||
*
|
||||
* A message with the path: '$.values[?(@.alias='my-property')].value.innerProperty', will for above example become '$.innerProperty' for the local Validation Context.
|
||||
* A message with the path: '$.values[?(@.alias == 'my-property')].value.innerProperty', will for above example become '$.innerProperty' for the local Validation Context.
|
||||
*/
|
||||
setDataPath(dataPath: string): void {
|
||||
if (this.#baseDataPath) {
|
||||
|
||||
@@ -3,21 +3,21 @@ import type { UmbVariantPropertyValueModel } from '@umbraco-cms/backoffice/varia
|
||||
|
||||
/**
|
||||
* Validation Data Path Query generator for Property Value.
|
||||
* write a JSON-Path filter similar to `?(@.alias = 'myAlias' && @.culture == 'en-us' && @.segment == 'mySegment')`
|
||||
* write a JSON-Path filter similar to `?(@.alias == 'myAlias' && @.culture == 'en-us' && @.segment == 'mySegment')`
|
||||
* where culture and segment are optional
|
||||
* @param value
|
||||
* @returns
|
||||
* @param {UmbVariantPropertyValueModel} value - the object holding value and alias.
|
||||
* @returns {string} - a JSON-path query
|
||||
*/
|
||||
export function UmbDataPathPropertyValueQuery(
|
||||
value: UmbPartialSome<Omit<UmbVariantPropertyValueModel, 'value'>, 'culture' | 'segment'>,
|
||||
): string {
|
||||
// write a array of strings for each property, where alias must be present and culture and segment are optional
|
||||
const filters: Array<string> = [`@.alias = '${value.alias}'`];
|
||||
const filters: Array<string> = [`@.alias == '${value.alias}'`];
|
||||
if (value.culture !== undefined) {
|
||||
filters.push(`@.culture = ${value.culture ? `'${value.culture}'` : 'null'}`);
|
||||
filters.push(`@.culture == ${value.culture ? `'${value.culture}'` : 'null'}`);
|
||||
}
|
||||
if (value.segment !== undefined) {
|
||||
filters.push(`@.segment = ${value.segment ? `'${value.segment}'` : 'null'}`);
|
||||
filters.push(`@.segment == ${value.segment ? `'${value.segment}'` : 'null'}`);
|
||||
}
|
||||
return `?(${filters.join(' && ')})`;
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@ export function UmbDataPathVariantQuery(
|
||||
value: UmbPartialSome<Pick<UmbVariantPropertyValueModel, 'culture' | 'segment'>, 'segment'>,
|
||||
): string {
|
||||
// write a array of strings for each property, where culture must be present and segment is optional
|
||||
const filters: Array<string> = [`@.culture = ${value.culture ? `'${value.culture}'` : 'null'}`];
|
||||
const filters: Array<string> = [`@.culture == ${value.culture ? `'${value.culture}'` : 'null'}`];
|
||||
if (value.segment !== undefined) {
|
||||
filters.push(`@.segment = ${value.segment ? `'${value.segment}'` : 'null'}`);
|
||||
filters.push(`@.segment == ${value.segment ? `'${value.segment}'` : 'null'}`);
|
||||
}
|
||||
return `?(${filters.join(' && ')})`;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
/**
|
||||
*
|
||||
* @param data
|
||||
* @param path
|
||||
* @param {object} data - object to traverse for the value.
|
||||
* @param {string} path - the JSON path to the value that should be found
|
||||
* @returns {unknown} - the found value.
|
||||
*/
|
||||
export function GetValueByJsonPath(data: any, path: string): any {
|
||||
export function GetValueByJsonPath(data: unknown, path: string): unknown {
|
||||
// strip $ from the path:
|
||||
const strippedPath = path.startsWith('$.') ? path.slice(2) : path;
|
||||
// get value from the path:
|
||||
@@ -12,23 +13,9 @@ export function GetValueByJsonPath(data: any, path: string): any {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
export function GetPropertyNameFromPath(path: string): string {
|
||||
// find next '.' or '[' in the path, using regex:
|
||||
const match = path.match(/\.|\[/);
|
||||
// If no match is found, we assume its a single key so lets return the value of the key:
|
||||
if (match === null || match.index === undefined) return path;
|
||||
|
||||
// split the path at the first match:
|
||||
return path.slice(0, match.index);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param data
|
||||
* @param path
|
||||
* @returns {any}
|
||||
* @param {object} data - object to traverse for the value.
|
||||
* @param {string} path - the JSON path to the value that should be found
|
||||
* @returns {unknown} - the found value.
|
||||
*/
|
||||
function GetNextPropertyValueFromPath(data: any, path: string): any {
|
||||
if (!data) return undefined;
|
||||
@@ -90,8 +77,8 @@ function GetNextPropertyValueFromPath(data: any, path: string): any {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param filter
|
||||
* @returns {Array<(queryFilter: any) => boolean>} - array of methods that returns true if the given items property value matches the value of the query.
|
||||
* @param {string} filter - A JSON Query, limited to filtering features. Do not support other JSON PATH Query features.
|
||||
* @returns {Array<(queryFilter: any) => boolean>} - An array of methods that returns true if the given items property value matches the value of the query.
|
||||
*/
|
||||
function JsFilterFromJsonPathFilter(filter: string): Array<(item: any) => boolean> {
|
||||
// strip ?( and ) from the filter
|
||||
@@ -101,7 +88,7 @@ function JsFilterFromJsonPathFilter(filter: string): Array<(item: any) => boolea
|
||||
// map each part to a function that returns true if the part is true
|
||||
return parts.map((part) => {
|
||||
// split the part into key and value
|
||||
const [path, equal] = part.split(' = ');
|
||||
const [path, equal] = part.split(' == ');
|
||||
// remove @.
|
||||
const key = path.slice(2);
|
||||
// remove quotes:
|
||||
|
||||
@@ -30,7 +30,7 @@ describe('UmbJsonPathFunctions', () => {
|
||||
});
|
||||
|
||||
it('query of first entry in an array', () => {
|
||||
const result = GetValueByJsonPath({ values: [{ id: '123', value: 'test' }] }, "$.values[?(@.id = '123')].value");
|
||||
const result = GetValueByJsonPath({ values: [{ id: '123', value: 'test' }] }, "$.values[?(@.id == '123')].value");
|
||||
|
||||
expect(result).to.eq('test');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user