Skip to content

Commit

Permalink
Merge pull request #2106 from umbraco/v14/feature/property-validation…
Browse files Browse the repository at this point in the history
…-mandatory-indicator

Feature: Property label mandatory indicator
  • Loading branch information
leekelleher authored Jul 8, 2024
2 parents 773346c + 7365dac commit ed9b0b4
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
import type { UmbPropertyEditorConfig } from '../../../property-editor/index.js';
import type { UmbPropertyTypeModel } from '../../types.js';
import { css, customElement, html, ifDefined, property, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbContentPropertyContext } from '@umbraco-cms/backoffice/content';
import type { UmbDataTypeDetailModel } from '@umbraco-cms/backoffice/data-type';
import { UmbDataTypeDetailRepository } from '@umbraco-cms/backoffice/data-type';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, ifDefined, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { UmbDataTypeDetailModel } from '@umbraco-cms/backoffice/data-type';
import type { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';

@customElement('umb-property-type-based-property')
export class UmbPropertyTypeBasedPropertyElement extends UmbLitElement {
@property({ type: Object, attribute: false })
public get property(): UmbPropertyTypeModel | undefined {
return this._property;
}
public set property(value: UmbPropertyTypeModel | undefined) {
const oldProperty = this._property;
this._property = value;
if (this._property?.dataType.unique !== oldProperty?.dataType.unique) {
this._observeDataType(this._property?.dataType.unique);
}
}
public get property(): UmbPropertyTypeModel | undefined {
return this._property;
}
private _property?: UmbPropertyTypeModel;

@property({ type: String, attribute: 'data-path' })
Expand Down Expand Up @@ -73,16 +74,19 @@ export class UmbPropertyTypeBasedPropertyElement extends UmbLitElement {
}

override render() {
return this._propertyEditorUiAlias && this._property?.alias
? html`<umb-property
.dataPath=${this.dataPath}
.alias=${this._property.alias}
.label=${this._property.name}
.description=${this._property.description ?? undefined}
.appearance=${this._property.appearance}
property-editor-ui-alias=${ifDefined(this._propertyEditorUiAlias)}
.config=${this._dataTypeData}></umb-property>`
: '';
if (!this._propertyEditorUiAlias || !this._property?.alias) return;
return html`
<umb-property
.dataPath=${this.dataPath}
.alias=${this._property.alias}
.label=${this._property.name}
.description=${this._property.description ?? undefined}
.appearance=${this._property.appearance}
property-editor-ui-alias=${ifDefined(this._propertyEditorUiAlias)}
.config=${this._dataTypeData}
.validation=${this._property.validation}>
</umb-property>
`;
}

static override styles = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,28 @@ export class UmbPropertyLayoutElement extends UmbLitElement {
public description = '';

/**
* @description Make the property appear invalid
* @description Make the property appear invalid.
* @type {boolean}
* @attr
* @default undefined
*/
@property({ type: Boolean, reflect: true })
public invalid?: boolean;

/**
* @description Display a mandatory indicator.
* @type {boolean}
* @attr
* @default false
*/
@property({ type: Boolean, reflect: true })
public mandatory?: boolean;

override render() {
// TODO: Only show alias on label if user has access to DocumentType within settings:
return html`
<div id="headerColumn">
<uui-label id="label" title=${this.alias}>
<uui-label id="label" title=${this.alias} ?required=${this.mandatory}>
${this.localize.string(this.label)}
${when(this.invalid, () => html`<uui-badge color="danger" attention>!</uui-badge>`)}
</uui-label>
Expand Down
27 changes: 26 additions & 1 deletion src/packages/core/property/property/property.context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,39 @@ import type { UmbVariantId } from '@umbraco-cms/backoffice/variant';
import type { UmbPropertyEditorConfigProperty } from '@umbraco-cms/backoffice/property-editor';
import { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import type { UmbPropertyTypeAppearanceModel } from '@umbraco-cms/backoffice/content-type';
import type {
UmbPropertyTypeAppearanceModel,
UmbPropertyTypeValidationModel,
} from '@umbraco-cms/backoffice/content-type';

export class UmbPropertyContext<ValueType = any> extends UmbContextBase<UmbPropertyContext<ValueType>> {
#alias = new UmbStringState(undefined);
public readonly alias = this.#alias.asObservable();

#label = new UmbStringState(undefined);
public readonly label = this.#label.asObservable();

#description = new UmbStringState(undefined);
public readonly description = this.#description.asObservable();

#appearance = new UmbObjectState<UmbPropertyTypeAppearanceModel | undefined>(undefined);
public readonly appearance = this.#appearance.asObservable();

#value = new UmbDeepState<ValueType | undefined>(undefined);
public readonly value = this.#value.asObservable();

#configValues = new UmbArrayState<UmbPropertyEditorConfigProperty>([], (x) => x.alias);
public readonly configValues = this.#configValues.asObservable();

#config = new UmbClassState<UmbPropertyEditorConfigCollection | undefined>(undefined);
public readonly config = this.#config.asObservable();

#validation = new UmbObjectState<UmbPropertyTypeValidationModel | undefined>(undefined);
public readonly validation = this.#validation.asObservable();

private _editor = new UmbBasicState<UmbPropertyEditorUiElement | undefined>(undefined);
public readonly editor = this._editor.asObservable();

setEditor(editor: UmbPropertyEditorUiElement | undefined) {
this._editor.setValue(editor ?? undefined);
}
Expand Down Expand Up @@ -108,24 +120,28 @@ export class UmbPropertyContext<ValueType = any> extends UmbContextBase<UmbPrope
public getAlias(): string | undefined {
return this.#alias.getValue();
}

public setLabel(label: string | undefined): void {
this.#label.setValue(label);
}
public getLabel(): string | undefined {
return this.#label.getValue();
}

public setDescription(description: string | undefined): void {
this.#description.setValue(description);
}
public getDescription(): string | undefined {
return this.#description.getValue();
}

public setAppearance(appearance: UmbPropertyTypeAppearanceModel | undefined): void {
this.#appearance.setValue(appearance);
}
public getAppearance(): UmbPropertyTypeAppearanceModel | undefined {
return this.#appearance.getValue();
}

/**
* Set the value of this property.
* @param value {ValueType} the whole value to be set
Expand All @@ -143,19 +159,28 @@ export class UmbPropertyContext<ValueType = any> extends UmbContextBase<UmbPrope
public getValue(): ValueType | undefined {
return this.#value.getValue();
}

public setConfig(config: Array<UmbPropertyEditorConfigProperty> | undefined): void {
this.#configValues.setValue(config ?? []);
}
public getConfig(): Array<UmbPropertyEditorConfigProperty> | undefined {
return this.#configValues.getValue();
}

public setVariantId(variantId: UmbVariantId | undefined): void {
this.#variantId.setValue(variantId);
}
public getVariantId(): UmbVariantId | undefined {
return this.#variantId.getValue();
}

public setValidation(validation: UmbPropertyTypeValidationModel | undefined): void {
this.#validation.setValue(validation);
}
public getValidation(): UmbPropertyTypeValidationModel | undefined {
return this.#validation.getValue();
}

public resetValue(): void {
this.setValue(undefined); // TODO: We should get the value from the server aka. the value from the persisted data. (Most workspaces holds this data, via dataset) [NL]
}
Expand Down
56 changes: 43 additions & 13 deletions src/packages/core/property/property/property.element.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import { UmbPropertyContext } from './property.context.js';
import type { ManifestPropertyEditorUi } from '@umbraco-cms/backoffice/extension-registry';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, customElement, property, state, nothing } from '@umbraco-cms/backoffice/external/lit';
import { css, customElement, html, property, state, nothing } from '@umbraco-cms/backoffice/external/lit';
import { createExtensionElement } from '@umbraco-cms/backoffice/extension-api';
import type { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type {
UmbPropertyEditorConfigCollection,
UmbPropertyEditorConfig,
} from '@umbraco-cms/backoffice/property-editor';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import {
UmbBindValidationMessageToFormControl,
UmbFormControlValidator,
UmbObserveValidationStateController,
} from '@umbraco-cms/backoffice/validation';
import type { UmbPropertyTypeAppearanceModel } from '@umbraco-cms/backoffice/content-type';
import type { ManifestPropertyEditorUi } from '@umbraco-cms/backoffice/extension-registry';
import type {
UmbPropertyEditorConfigCollection,
UmbPropertyEditorConfig,
} from '@umbraco-cms/backoffice/property-editor';
import type {
UmbPropertyTypeAppearanceModel,
UmbPropertyTypeValidationModel,
} from '@umbraco-cms/backoffice/content-type';
import type { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';

/**
* @element umb-property
Expand Down Expand Up @@ -112,6 +115,17 @@ export class UmbPropertyElement extends UmbLitElement {
return this.#propertyContext.getConfig();
}

/**
* Validation: Validation settings for the property.
*/
@property({ type: Object, attribute: false })
public set validation(validation: UmbPropertyTypeValidationModel | undefined) {
this.#propertyContext.setValidation(validation);
}
public get validation() {
return this.#propertyContext.getValidation();
}

/**
* DataPath, declare the path to the value of the data that this property represents.
* @public
Expand Down Expand Up @@ -152,6 +166,9 @@ export class UmbPropertyElement extends UmbLitElement {
@state()
private _orientation: 'horizontal' | 'vertical' = 'horizontal';

@state()
private _mandatory?: boolean;

#propertyContext = new UmbPropertyContext(this);

#controlValidator?: UmbFormControlValidator;
Expand All @@ -169,34 +186,46 @@ export class UmbPropertyElement extends UmbLitElement {
},
null,
);

this.observe(
this.#propertyContext.label,
(label) => {
this._label = label;
},
null,
);

this.observe(
this.#propertyContext.description,
(description) => {
this._description = description;
},
null,
);

this.observe(
this.#propertyContext.variantDifference,
(variantDifference) => {
this._variantDifference = variantDifference;
},
null,
);

this.observe(
this.#propertyContext.appearance,
(appearance) => {
this._orientation = appearance?.labelOnTop ? 'vertical' : 'horizontal';
},
null,
);

this.observe(
this.#propertyContext.validation,
(validation) => {
this._mandatory = validation?.mandatory;
},
null,
);
}

private _onPropertyEditorChange = (e: CustomEvent): void => {
Expand Down Expand Up @@ -297,10 +326,11 @@ export class UmbPropertyElement extends UmbLitElement {
return html`
<umb-property-layout
id="layout"
.alias=${this._alias}
.label=${this._label}
.description=${this._description}
.alias=${this._alias ?? ''}
.label=${this._label ?? ''}
.description=${this._description ?? ''}
.orientation=${this._orientation ?? 'horizontal'}
?mandatory=${this._mandatory}
?invalid=${this._invalid}>
${this.#renderPropertyActionMenu()}
${this._variantDifference
Expand Down

0 comments on commit ed9b0b4

Please sign in to comment.