From e549217e66aee6c0f175e783b25425dafeeb2b23 Mon Sep 17 00:00:00 2001 From: Engiber Lozada <89547469+engijlr@users.noreply.github.com> Date: Thu, 13 Nov 2025 21:42:48 +0100 Subject: [PATCH] Content Type Designer: Use input-with-alias and implement regex validation for Alias. (#20755) * Implemented input-with-alias in the content-type-design-editor. * Added auto-generate-alias property to the input and revert deletion of checkAliasAutoGenerate method. * Added form-validation-message. * Added validation to the input-with-alias element to avoid special characters. --- .../src/assets/lang/en.ts | 1 + .../src/assets/lang/es.ts | 1 + ...ent-type-design-editor-property.element.ts | 151 ++++++------------ .../input-with-alias.element.ts | 27 +++- 4 files changed, 81 insertions(+), 99 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts b/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts index a04d3fe3cc..839dfc9e7e 100644 --- a/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts +++ b/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts @@ -2246,6 +2246,7 @@ export default { rangeExceeds: 'The low value must not exceed the high value.', invalidExtensions: 'One or more of the extensions are invalid.', allowedExtensions: 'Allowed extensions are:', + aliasInvalidFormat: 'Special characters are not allowed in alias', disallowedExtensions: 'Disallowed extensions are:', }, healthcheck: { diff --git a/src/Umbraco.Web.UI.Client/src/assets/lang/es.ts b/src/Umbraco.Web.UI.Client/src/assets/lang/es.ts index 2e8ca5780b..6c525bd179 100644 --- a/src/Umbraco.Web.UI.Client/src/assets/lang/es.ts +++ b/src/Umbraco.Web.UI.Client/src/assets/lang/es.ts @@ -1393,6 +1393,7 @@ export default { invalidDate: 'Fecha no válida', invalidNumber: 'No es un número', invalidEmail: 'Email no válido', + aliasInvalidFormat: 'No se permiten caracteres especiales en el alias', }, healthcheck: { checkSuccessMessage: "El valor fue establecido en el valor recomendado: '%0%'.", diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor-property.element.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor-property.element.ts index 043d7cfd22..0e322bd403 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor-property.element.ts @@ -2,13 +2,14 @@ import type { UmbContentTypePropertyStructureHelper } from '../../../structure/i import type { UmbContentTypeModel, UmbPropertyTypeModel, UmbPropertyTypeScaffoldModel } from '../../../types.js'; import { UmbPropertyTypeContext } from './content-type-design-editor-property.context.js'; import { css, html, customElement, property, state, nothing } from '@umbraco-cms/backoffice/external/lit'; -import { generateAlias } from '@umbraco-cms/backoffice/utils'; import { umbConfirmModal } from '@umbraco-cms/backoffice/modal'; import { UmbDataTypeDetailRepository } from '@umbraco-cms/backoffice/data-type'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { UMB_EDIT_PROPERTY_TYPE_WORKSPACE_PATH_PATTERN } from '@umbraco-cms/backoffice/property-type'; -import type { UUIInputElement, UUIInputLockElement, UUIInputEvent } from '@umbraco-cms/backoffice/external/uui'; +import type { UUIInputEvent } from '@umbraco-cms/backoffice/external/uui'; +import type { UmbInputWithAliasElement } from '@umbraco-cms/backoffice/components'; +import { umbBindToValidation } from '@umbraco-cms/backoffice/validation'; /** * @element umb-content-type-design-editor-property @@ -20,7 +21,6 @@ export class UmbContentTypeDesignEditorPropertyElement extends UmbLitElement { #context = new UmbPropertyTypeContext(this); #dataTypeDetailRepository = new UmbDataTypeDetailRepository(this); #dataTypeUnique?: string; - #propertyUnique?: string; @property({ attribute: false }) public set propertyStructureHelper(value: UmbContentTypePropertyStructureHelper | undefined) { @@ -49,7 +49,6 @@ export class UmbContentTypeDesignEditorPropertyElement extends UmbLitElement { this._property = value; this.#context.setAlias(value?.alias); this.#context.setLabel(value?.name); - this.#checkAliasAutoGenerate(this._property?.unique); this.#checkInherited(); this.#setDataType(this._property?.dataType?.unique); this.requestUpdate('property', oldValue); @@ -86,20 +85,6 @@ export class UmbContentTypeDesignEditorPropertyElement extends UmbLitElement { @state() private _dataTypeName?: string; - @state() - private _aliasLocked = true; - - #autoGenerateAlias = true; - - #checkAliasAutoGenerate(unique: string | undefined) { - if (unique === this.#propertyUnique) return; - this.#propertyUnique = unique; - - if (this.#context.getAlias()) { - this.#autoGenerateAlias = false; - } - } - async #checkInherited() { if (this._propertyStructureHelper && this._property) { // We can first match with something if we have a name [NL] @@ -131,19 +116,6 @@ export class UmbContentTypeDesignEditorPropertyElement extends UmbLitElement { this._propertyStructureHelper.partialUpdateProperty(this._property.unique, partialObject); } - #onToggleAliasLock(event: CustomEvent) { - if (!this.property?.alias && (event.target as UUIInputLockElement).locked) { - this.#autoGenerateAlias = true; - } else { - this.#autoGenerateAlias = false; - } - - this._aliasLocked = !this._aliasLocked; - if (!this._aliasLocked) { - (event.target as UUIInputElement)?.focus(); - } - } - async #setDataType(dataTypeUnique: string | undefined) { if (!dataTypeUnique) { this._dataTypeName = undefined; @@ -173,28 +145,23 @@ export class UmbContentTypeDesignEditorPropertyElement extends UmbLitElement { this._propertyStructureHelper?.removeProperty(unique); } - #onAliasChanged(event: UUIInputEvent) { - this.#singleValueUpdate('alias', event.target.value.toString()); - } - - #onNameChanged(event: UUIInputEvent) { - const newName = event.target.value.toString(); - if (this.#autoGenerateAlias) { - this.#singleValueUpdate('alias', generateAlias(newName ?? '')); - } - this.#singleValueUpdate('name', newName); + #onNameAliasChange(e: InputEvent & { target: UmbInputWithAliasElement }) { + this.#partialUpdate({ + name: e.target.value, + alias: e.target.alias, + } as UmbPropertyTypeModel); } override render() { // TODO: Only show alias on label if user has access to DocumentType within settings: [NL] - return this._inherited ? this.renderInheritedProperty() : this.renderEditableProperty(); + return this._inherited ? this.#renderInheritedProperty() : this.#renderEditableProperty(); } - renderInheritedProperty() { + #renderInheritedProperty() { if (!this.property) return; if (this.sortModeActive) { - return this.renderSortableProperty(); + return this.#renderSortableProperty(); } else { return html`
- ${this.renderPropertyTags()} + ${this.#renderPropertyName()} ${this.#renderPropertyTags()} ${this._inherited ? html` @@ -220,22 +187,27 @@ export class UmbContentTypeDesignEditorPropertyElement extends UmbLitElement { } } - renderEditableProperty() { + #renderEditableProperty() { if (!this.property || !this.editPropertyTypePath) return; if (this.sortModeActive) { - return this.renderSortableProperty(); + return this.#renderSortableProperty(); } else { return html`