Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Property label mandatory indicator #2106

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading