Skip to content

Commit ed9b0b4

Browse files
authored
Merge pull request #2106 from umbraco/v14/feature/property-validation-mandatory-indicator
Feature: Property label mandatory indicator
2 parents 773346c + 7365dac commit ed9b0b4

File tree

4 files changed

+101
-33
lines changed

4 files changed

+101
-33
lines changed

src/packages/core/content-type/components/property-type-based-property/property-type-based-property.element.ts

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,27 @@
11
import type { UmbPropertyEditorConfig } from '../../../property-editor/index.js';
22
import type { UmbPropertyTypeModel } from '../../types.js';
3+
import { css, customElement, html, ifDefined, property, state } from '@umbraco-cms/backoffice/external/lit';
34
import { UmbContentPropertyContext } from '@umbraco-cms/backoffice/content';
4-
import type { UmbDataTypeDetailModel } from '@umbraco-cms/backoffice/data-type';
55
import { UmbDataTypeDetailRepository } from '@umbraco-cms/backoffice/data-type';
6-
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
7-
import { css, html, ifDefined, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
6+
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
87
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
8+
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
9+
import type { UmbDataTypeDetailModel } from '@umbraco-cms/backoffice/data-type';
910
import type { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
10-
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
11+
1112
@customElement('umb-property-type-based-property')
1213
export class UmbPropertyTypeBasedPropertyElement extends UmbLitElement {
1314
@property({ type: Object, attribute: false })
14-
public get property(): UmbPropertyTypeModel | undefined {
15-
return this._property;
16-
}
1715
public set property(value: UmbPropertyTypeModel | undefined) {
1816
const oldProperty = this._property;
1917
this._property = value;
2018
if (this._property?.dataType.unique !== oldProperty?.dataType.unique) {
2119
this._observeDataType(this._property?.dataType.unique);
2220
}
2321
}
22+
public get property(): UmbPropertyTypeModel | undefined {
23+
return this._property;
24+
}
2425
private _property?: UmbPropertyTypeModel;
2526

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

7576
override render() {
76-
return this._propertyEditorUiAlias && this._property?.alias
77-
? html`<umb-property
78-
.dataPath=${this.dataPath}
79-
.alias=${this._property.alias}
80-
.label=${this._property.name}
81-
.description=${this._property.description ?? undefined}
82-
.appearance=${this._property.appearance}
83-
property-editor-ui-alias=${ifDefined(this._propertyEditorUiAlias)}
84-
.config=${this._dataTypeData}></umb-property>`
85-
: '';
77+
if (!this._propertyEditorUiAlias || !this._property?.alias) return;
78+
return html`
79+
<umb-property
80+
.dataPath=${this.dataPath}
81+
.alias=${this._property.alias}
82+
.label=${this._property.name}
83+
.description=${this._property.description ?? undefined}
84+
.appearance=${this._property.appearance}
85+
property-editor-ui-alias=${ifDefined(this._propertyEditorUiAlias)}
86+
.config=${this._dataTypeData}
87+
.validation=${this._property.validation}>
88+
</umb-property>
89+
`;
8690
}
8791

8892
static override styles = [

src/packages/core/property/property-layout/property-layout.element.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,19 +51,28 @@ export class UmbPropertyLayoutElement extends UmbLitElement {
5151
public description = '';
5252

5353
/**
54-
* @description Make the property appear invalid
54+
* @description Make the property appear invalid.
5555
* @type {boolean}
5656
* @attr
5757
* @default undefined
5858
*/
5959
@property({ type: Boolean, reflect: true })
6060
public invalid?: boolean;
6161

62+
/**
63+
* @description Display a mandatory indicator.
64+
* @type {boolean}
65+
* @attr
66+
* @default false
67+
*/
68+
@property({ type: Boolean, reflect: true })
69+
public mandatory?: boolean;
70+
6271
override render() {
6372
// TODO: Only show alias on label if user has access to DocumentType within settings:
6473
return html`
6574
<div id="headerColumn">
66-
<uui-label id="label" title=${this.alias}>
75+
<uui-label id="label" title=${this.alias} ?required=${this.mandatory}>
6776
${this.localize.string(this.label)}
6877
${when(this.invalid, () => html`<uui-badge color="danger" attention>!</uui-badge>`)}
6978
</uui-label>

src/packages/core/property/property/property.context.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,39 @@ import type { UmbVariantId } from '@umbraco-cms/backoffice/variant';
1414
import type { UmbPropertyEditorConfigProperty } from '@umbraco-cms/backoffice/property-editor';
1515
import { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
1616
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
17-
import type { UmbPropertyTypeAppearanceModel } from '@umbraco-cms/backoffice/content-type';
17+
import type {
18+
UmbPropertyTypeAppearanceModel,
19+
UmbPropertyTypeValidationModel,
20+
} from '@umbraco-cms/backoffice/content-type';
1821

1922
export class UmbPropertyContext<ValueType = any> extends UmbContextBase<UmbPropertyContext<ValueType>> {
2023
#alias = new UmbStringState(undefined);
2124
public readonly alias = this.#alias.asObservable();
25+
2226
#label = new UmbStringState(undefined);
2327
public readonly label = this.#label.asObservable();
28+
2429
#description = new UmbStringState(undefined);
2530
public readonly description = this.#description.asObservable();
31+
2632
#appearance = new UmbObjectState<UmbPropertyTypeAppearanceModel | undefined>(undefined);
2733
public readonly appearance = this.#appearance.asObservable();
34+
2835
#value = new UmbDeepState<ValueType | undefined>(undefined);
2936
public readonly value = this.#value.asObservable();
37+
3038
#configValues = new UmbArrayState<UmbPropertyEditorConfigProperty>([], (x) => x.alias);
3139
public readonly configValues = this.#configValues.asObservable();
3240

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

44+
#validation = new UmbObjectState<UmbPropertyTypeValidationModel | undefined>(undefined);
45+
public readonly validation = this.#validation.asObservable();
46+
3647
private _editor = new UmbBasicState<UmbPropertyEditorUiElement | undefined>(undefined);
3748
public readonly editor = this._editor.asObservable();
49+
3850
setEditor(editor: UmbPropertyEditorUiElement | undefined) {
3951
this._editor.setValue(editor ?? undefined);
4052
}
@@ -108,24 +120,28 @@ export class UmbPropertyContext<ValueType = any> extends UmbContextBase<UmbPrope
108120
public getAlias(): string | undefined {
109121
return this.#alias.getValue();
110122
}
123+
111124
public setLabel(label: string | undefined): void {
112125
this.#label.setValue(label);
113126
}
114127
public getLabel(): string | undefined {
115128
return this.#label.getValue();
116129
}
130+
117131
public setDescription(description: string | undefined): void {
118132
this.#description.setValue(description);
119133
}
120134
public getDescription(): string | undefined {
121135
return this.#description.getValue();
122136
}
137+
123138
public setAppearance(appearance: UmbPropertyTypeAppearanceModel | undefined): void {
124139
this.#appearance.setValue(appearance);
125140
}
126141
public getAppearance(): UmbPropertyTypeAppearanceModel | undefined {
127142
return this.#appearance.getValue();
128143
}
144+
129145
/**
130146
* Set the value of this property.
131147
* @param value {ValueType} the whole value to be set
@@ -143,19 +159,28 @@ export class UmbPropertyContext<ValueType = any> extends UmbContextBase<UmbPrope
143159
public getValue(): ValueType | undefined {
144160
return this.#value.getValue();
145161
}
162+
146163
public setConfig(config: Array<UmbPropertyEditorConfigProperty> | undefined): void {
147164
this.#configValues.setValue(config ?? []);
148165
}
149166
public getConfig(): Array<UmbPropertyEditorConfigProperty> | undefined {
150167
return this.#configValues.getValue();
151168
}
169+
152170
public setVariantId(variantId: UmbVariantId | undefined): void {
153171
this.#variantId.setValue(variantId);
154172
}
155173
public getVariantId(): UmbVariantId | undefined {
156174
return this.#variantId.getValue();
157175
}
158176

177+
public setValidation(validation: UmbPropertyTypeValidationModel | undefined): void {
178+
this.#validation.setValue(validation);
179+
}
180+
public getValidation(): UmbPropertyTypeValidationModel | undefined {
181+
return this.#validation.getValue();
182+
}
183+
159184
public resetValue(): void {
160185
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]
161186
}

src/packages/core/property/property/property.element.ts

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
import { UmbPropertyContext } from './property.context.js';
2-
import type { ManifestPropertyEditorUi } from '@umbraco-cms/backoffice/extension-registry';
3-
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
4-
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
5-
import { css, html, customElement, property, state, nothing } from '@umbraco-cms/backoffice/external/lit';
2+
import { css, customElement, html, property, state, nothing } from '@umbraco-cms/backoffice/external/lit';
63
import { createExtensionElement } from '@umbraco-cms/backoffice/extension-api';
7-
import type { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
4+
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
85
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
9-
import type {
10-
UmbPropertyEditorConfigCollection,
11-
UmbPropertyEditorConfig,
12-
} from '@umbraco-cms/backoffice/property-editor';
6+
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
137
import {
148
UmbBindValidationMessageToFormControl,
159
UmbFormControlValidator,
1610
UmbObserveValidationStateController,
1711
} from '@umbraco-cms/backoffice/validation';
18-
import type { UmbPropertyTypeAppearanceModel } from '@umbraco-cms/backoffice/content-type';
12+
import type { ManifestPropertyEditorUi } from '@umbraco-cms/backoffice/extension-registry';
13+
import type {
14+
UmbPropertyEditorConfigCollection,
15+
UmbPropertyEditorConfig,
16+
} from '@umbraco-cms/backoffice/property-editor';
17+
import type {
18+
UmbPropertyTypeAppearanceModel,
19+
UmbPropertyTypeValidationModel,
20+
} from '@umbraco-cms/backoffice/content-type';
21+
import type { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
1922

2023
/**
2124
* @element umb-property
@@ -112,6 +115,17 @@ export class UmbPropertyElement extends UmbLitElement {
112115
return this.#propertyContext.getConfig();
113116
}
114117

118+
/**
119+
* Validation: Validation settings for the property.
120+
*/
121+
@property({ type: Object, attribute: false })
122+
public set validation(validation: UmbPropertyTypeValidationModel | undefined) {
123+
this.#propertyContext.setValidation(validation);
124+
}
125+
public get validation() {
126+
return this.#propertyContext.getValidation();
127+
}
128+
115129
/**
116130
* DataPath, declare the path to the value of the data that this property represents.
117131
* @public
@@ -152,6 +166,9 @@ export class UmbPropertyElement extends UmbLitElement {
152166
@state()
153167
private _orientation: 'horizontal' | 'vertical' = 'horizontal';
154168

169+
@state()
170+
private _mandatory?: boolean;
171+
155172
#propertyContext = new UmbPropertyContext(this);
156173

157174
#controlValidator?: UmbFormControlValidator;
@@ -169,34 +186,46 @@ export class UmbPropertyElement extends UmbLitElement {
169186
},
170187
null,
171188
);
189+
172190
this.observe(
173191
this.#propertyContext.label,
174192
(label) => {
175193
this._label = label;
176194
},
177195
null,
178196
);
197+
179198
this.observe(
180199
this.#propertyContext.description,
181200
(description) => {
182201
this._description = description;
183202
},
184203
null,
185204
);
205+
186206
this.observe(
187207
this.#propertyContext.variantDifference,
188208
(variantDifference) => {
189209
this._variantDifference = variantDifference;
190210
},
191211
null,
192212
);
213+
193214
this.observe(
194215
this.#propertyContext.appearance,
195216
(appearance) => {
196217
this._orientation = appearance?.labelOnTop ? 'vertical' : 'horizontal';
197218
},
198219
null,
199220
);
221+
222+
this.observe(
223+
this.#propertyContext.validation,
224+
(validation) => {
225+
this._mandatory = validation?.mandatory;
226+
},
227+
null,
228+
);
200229
}
201230

202231
private _onPropertyEditorChange = (e: CustomEvent): void => {
@@ -297,10 +326,11 @@ export class UmbPropertyElement extends UmbLitElement {
297326
return html`
298327
<umb-property-layout
299328
id="layout"
300-
.alias=${this._alias}
301-
.label=${this._label}
302-
.description=${this._description}
329+
.alias=${this._alias ?? ''}
330+
.label=${this._label ?? ''}
331+
.description=${this._description ?? ''}
303332
.orientation=${this._orientation ?? 'horizontal'}
333+
?mandatory=${this._mandatory}
304334
?invalid=${this._invalid}>
305335
${this.#renderPropertyActionMenu()}
306336
${this._variantDifference

0 commit comments

Comments
 (0)