implement range validation for areas
This commit is contained in:
@@ -138,7 +138,6 @@ export class UmbBlockGridEntriesElement extends UmbFormControlMixin(UmbLitElemen
|
||||
public set areaKey(value: string | null | undefined) {
|
||||
this._areaKey = value;
|
||||
this.#context.setAreaKey(value ?? null);
|
||||
this.#setupValidation();
|
||||
}
|
||||
public get areaKey(): string | null | undefined {
|
||||
return this._areaKey;
|
||||
@@ -169,27 +168,43 @@ export class UmbBlockGridEntriesElement extends UmbFormControlMixin(UmbLitElemen
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.observe(this.#context.layoutEntries, (layoutEntries) => {
|
||||
//const oldValue = this._layoutEntries;
|
||||
this.#sorter.setModel(layoutEntries);
|
||||
this._layoutEntries = layoutEntries;
|
||||
//this.requestUpdate('layoutEntries', oldValue);
|
||||
});
|
||||
this.observe(
|
||||
this.#context.layoutEntries,
|
||||
(layoutEntries) => {
|
||||
//const oldValue = this._layoutEntries;
|
||||
this.#sorter.setModel(layoutEntries);
|
||||
this._layoutEntries = layoutEntries;
|
||||
//this.requestUpdate('layoutEntries', oldValue);
|
||||
},
|
||||
null,
|
||||
);
|
||||
|
||||
this.observe(this.#context.amountOfAllowedBlockTypes, (length) => {
|
||||
this._canCreate = length > 0;
|
||||
if (length === 1) {
|
||||
this.observe(
|
||||
this.#context.firstAllowedBlockTypeName(),
|
||||
(firstAllowedName) => {
|
||||
this._singleBlockTypeName = firstAllowedName;
|
||||
},
|
||||
'observeSingleBlockTypeName',
|
||||
);
|
||||
} else {
|
||||
this.removeUmbControllerByAlias('observeSingleBlockTypeName');
|
||||
}
|
||||
});
|
||||
this.observe(
|
||||
this.#context.amountOfAllowedBlockTypes,
|
||||
(length) => {
|
||||
this._canCreate = length > 0;
|
||||
if (length === 1) {
|
||||
this.observe(
|
||||
this.#context.firstAllowedBlockTypeName(),
|
||||
(firstAllowedName) => {
|
||||
this._singleBlockTypeName = firstAllowedName;
|
||||
},
|
||||
'observeSingleBlockTypeName',
|
||||
);
|
||||
} else {
|
||||
this.removeUmbControllerByAlias('observeSingleBlockTypeName');
|
||||
}
|
||||
},
|
||||
null,
|
||||
);
|
||||
|
||||
this.observe(
|
||||
this.#context.rangeLimits,
|
||||
(rangeLimits) => {
|
||||
this.#setupRangeValidation(rangeLimits);
|
||||
},
|
||||
null,
|
||||
);
|
||||
|
||||
this.#context.getManager().then((manager) => {
|
||||
this.observe(
|
||||
@@ -207,42 +222,25 @@ export class UmbBlockGridEntriesElement extends UmbFormControlMixin(UmbLitElemen
|
||||
this.#controlValidator = new UmbFormControlValidator(this, this /*, this.#dataPath*/);
|
||||
}
|
||||
|
||||
async #getLimitValidation() {
|
||||
if (this._areaKey === null) {
|
||||
// This validation setup is not be as configurable as it should be, but it is a start. Alternatively we should consume the manager and observe the configuration. [NL]
|
||||
const manager = await this.#context.getManager();
|
||||
const config = manager.getEditorConfiguration();
|
||||
const min = config?.getValueByAlias<UmbNumberRangeValueType>('validationLimit')?.min ?? 0;
|
||||
const max = config?.getValueByAlias<UmbNumberRangeValueType>('validationLimit')?.max ?? Infinity;
|
||||
return { min, max };
|
||||
} else {
|
||||
return { min: 3, max: 4 };
|
||||
}
|
||||
}
|
||||
|
||||
#rangeUnderflowValidator?: UmbFormControlValidatorConfig;
|
||||
#rangeOverflowValidator?: UmbFormControlValidatorConfig;
|
||||
async #setupValidation() {
|
||||
const rangeLimit = await this.#getLimitValidation();
|
||||
|
||||
console.log('setup validation', this);
|
||||
|
||||
async #setupRangeValidation(rangeLimit: UmbNumberRangeValueType | undefined) {
|
||||
if (this.#rangeUnderflowValidator) {
|
||||
this.removeValidator(this.#rangeUnderflowValidator);
|
||||
this.#rangeUnderflowValidator = undefined;
|
||||
}
|
||||
if (rangeLimit.min !== 0) {
|
||||
if (rangeLimit?.min !== 0) {
|
||||
this.#rangeUnderflowValidator = this.addValidator(
|
||||
'rangeUnderflow',
|
||||
() => {
|
||||
return this.localize.term(
|
||||
'validation_entriesShort',
|
||||
rangeLimit.min,
|
||||
rangeLimit.min - (this._layoutEntries.length ?? 0),
|
||||
rangeLimit!.min,
|
||||
(rangeLimit!.min ?? 0) - this._layoutEntries.length,
|
||||
);
|
||||
},
|
||||
() => {
|
||||
return (this._layoutEntries.length ?? 0) < rangeLimit.min;
|
||||
return this._layoutEntries.length < (rangeLimit?.min ?? 0);
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -251,18 +249,18 @@ export class UmbBlockGridEntriesElement extends UmbFormControlMixin(UmbLitElemen
|
||||
this.removeValidator(this.#rangeOverflowValidator);
|
||||
this.#rangeOverflowValidator = undefined;
|
||||
}
|
||||
if (rangeLimit.max !== Infinity) {
|
||||
if (rangeLimit?.max !== Infinity) {
|
||||
this.#rangeOverflowValidator = this.addValidator(
|
||||
'rangeOverflow',
|
||||
() => {
|
||||
return this.localize.term(
|
||||
'validation_entriesExceed',
|
||||
rangeLimit.max,
|
||||
(this._layoutEntries.length ?? 0) - rangeLimit.max,
|
||||
rangeLimit!.max,
|
||||
this._layoutEntries.length - (rangeLimit!.max ?? this._layoutEntries.length),
|
||||
);
|
||||
},
|
||||
() => {
|
||||
return (this._layoutEntries.length ?? 0) > rangeLimit.max;
|
||||
return (this._layoutEntries.length ?? 0) > (rangeLimit?.max ?? Infinity);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,10 +4,11 @@ import { UMB_BLOCK_GRID_ENTRY_CONTEXT, type UmbBlockGridWorkspaceData } from '..
|
||||
import type { UmbBlockGridLayoutModel, UmbBlockGridTypeAreaType, UmbBlockGridTypeModel } from '../types.js';
|
||||
import { UMB_BLOCK_GRID_MANAGER_CONTEXT } from './block-grid-manager.context.js';
|
||||
import type { UmbBlockGridScalableContainerContext } from './block-grid-scale-manager/block-grid-scale-manager.controller.js';
|
||||
import { UmbArrayState, UmbNumberState, UmbStringState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UmbArrayState, UmbNumberState, UmbObjectState, UmbStringState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/modal';
|
||||
import { pathFolderName } from '@umbraco-cms/backoffice/utils';
|
||||
import type { UmbNumberRangeValueType } from '@umbraco-cms/backoffice/models';
|
||||
|
||||
export class UmbBlockGridEntriesContext
|
||||
extends UmbBlockEntriesContext<
|
||||
@@ -31,6 +32,9 @@ export class UmbBlockGridEntriesContext
|
||||
#parentUnique?: string | null;
|
||||
#areaKey?: string | null;
|
||||
|
||||
#rangeLimits = new UmbObjectState<UmbNumberRangeValueType | undefined>(undefined);
|
||||
readonly rangeLimits = this.#rangeLimits.asObservable();
|
||||
|
||||
#allowedBlockTypes = new UmbArrayState<UmbBlockGridTypeModel>([], (x) => x.contentElementTypeKey);
|
||||
public readonly allowedBlockTypes = this.#allowedBlockTypes.asObservable();
|
||||
public readonly amountOfAllowedBlockTypes = this.#allowedBlockTypes.asObservablePart((x) => x.length);
|
||||
@@ -121,6 +125,7 @@ export class UmbBlockGridEntriesContext
|
||||
if (!this._manager) return;
|
||||
|
||||
this.#getAllowedBlockTypes();
|
||||
this.#getRangeLimits();
|
||||
|
||||
this.observe(
|
||||
this._manager.propertyAlias,
|
||||
@@ -185,6 +190,7 @@ export class UmbBlockGridEntriesContext
|
||||
|
||||
this.removeUmbControllerByAlias('observeAreaType');
|
||||
this.#getAllowedBlockTypes();
|
||||
this.#getRangeLimits();
|
||||
} else {
|
||||
if (!this.#parentEntry) return;
|
||||
|
||||
@@ -228,6 +234,7 @@ export class UmbBlockGridEntriesContext
|
||||
hostEl.style.setProperty('--umb-block-grid--area-column-span', areaType?.columnSpan?.toString() ?? '');
|
||||
hostEl.style.setProperty('--umb-block-grid--area-row-span', areaType?.rowSpan?.toString() ?? '');
|
||||
this.#getAllowedBlockTypes();
|
||||
this.#getRangeLimits();
|
||||
},
|
||||
'observeAreaType',
|
||||
);
|
||||
@@ -235,10 +242,14 @@ export class UmbBlockGridEntriesContext
|
||||
}
|
||||
|
||||
#getAllowedBlockTypes() {
|
||||
if (this.#areaKey === undefined || !this._manager) return;
|
||||
|
||||
if (!this._manager) return;
|
||||
this.#allowedBlockTypes.setValue(this.#retrieveAllowedElementTypes());
|
||||
}
|
||||
#getRangeLimits() {
|
||||
if (!this._manager) return;
|
||||
const range = this.#retrieveRangeLimits();
|
||||
this.#rangeLimits.setValue(range);
|
||||
}
|
||||
|
||||
getPathForCreateBlock(index: number) {
|
||||
return this._catalogueRouteBuilderState.getValue()?.({ view: 'create', index: index });
|
||||
@@ -324,10 +335,34 @@ export class UmbBlockGridEntriesContext
|
||||
|
||||
// No specific permissions setup, so we will fallback to items allowed in areas:
|
||||
return this._manager.getBlockTypes().filter((x) => x.allowInAreas);
|
||||
} else if (this.#areaKey === null) {
|
||||
// If AreaKey is null, then we are in the root, looking for items allowed as root:
|
||||
return this._manager.getBlockTypes().filter((x) => x.allowAtRoot);
|
||||
}
|
||||
|
||||
// If no AreaKey, then we are in the root, looking for items allowed as root:
|
||||
return this._manager.getBlockTypes().filter((x) => x.allowAtRoot);
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @returns an NumberRange of the min and max allowed items in the current area. Or undefined if not ready jet.
|
||||
*/
|
||||
#retrieveRangeLimits(): UmbNumberRangeValueType | undefined {
|
||||
if (this.#areaKey != null) {
|
||||
// Area entries:
|
||||
if (!this.#areaType) return undefined;
|
||||
|
||||
return { min: this.#areaType.minAllowed ?? 0, max: this.#areaType.maxAllowed ?? Infinity };
|
||||
} else if (this.#areaKey === null) {
|
||||
if (!this._manager) return undefined;
|
||||
|
||||
const config = this._manager.getEditorConfiguration();
|
||||
const min = config?.getValueByAlias<UmbNumberRangeValueType>('validationLimit')?.min ?? 0;
|
||||
const max = config?.getValueByAlias<UmbNumberRangeValueType>('validationLimit')?.max ?? Infinity;
|
||||
return { min, max };
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,7 +27,7 @@ type FlagTypes =
|
||||
| 'valid';
|
||||
|
||||
// Acceptable as an internal interface/type, BUT if exposed externally this should be turned into a public interface in a separate file.
|
||||
interface UmbFormControlValidatorConfig {
|
||||
export interface UmbFormControlValidatorConfig {
|
||||
flagKey: FlagTypes;
|
||||
getMessageMethod: () => string;
|
||||
checkMethod: () => boolean;
|
||||
|
||||
Reference in New Issue
Block a user