Variants: Implements validation hints to the variant selector (closes #19953) (#20179)

* feat: gets hints and assigns to variants to enable the view to show a badge if there is a hint

* feat: find the first hint on the non-active variant

* feat: protect against non-variants

* feat: ignore invariant variants

* feat: adds a render method for hints

* chore: removes comment

* only add a new hint if the weight is higher
This commit is contained in:
Jacob Overgaard
2025-09-18 17:37:21 +02:00
committed by GitHub
parent 3025dcdf31
commit aa2d4f1207

View File

@@ -10,6 +10,8 @@ import { UUIInputEvent } from '@umbraco-cms/backoffice/external/uui';
import type { UmbEntityVariantModel, UmbEntityVariantOptionModel } from '@umbraco-cms/backoffice/variant';
import type { UUIInputElement, UUIPopoverContainerElement } from '@umbraco-cms/backoffice/external/uui';
import type { DocumentVariantStateModel } from '@umbraco-cms/backoffice/external/backend-api';
import { UMB_HINT_CONTEXT } from '@umbraco-cms/backoffice/hint';
import type { UmbHint, UmbVariantHint } from '@umbraco-cms/backoffice/hint';
@customElement('umb-workspace-split-view-variant-selector')
export class UmbWorkspaceSplitViewVariantSelectorElement<
@@ -96,8 +98,35 @@ export class UmbWorkspaceSplitViewVariantSelectorElement<
this.#observeDatasetContext();
this.#observeCurrentVariant();
});
this.consumeContext(UMB_HINT_CONTEXT, (context) => {
this.observe(
context?.descendingHints(),
(hints) => {
this._hintMap.clear();
hints?.forEach((hint) => {
if (this.#isVariantHint(hint) && hint.variantId) {
// Add the hint if there is no existing hint for this variantId or if the existing hint has a lower weight
const existingHint = this._hintMap.get(hint.variantId.toString());
if (!existingHint || existingHint.weight < hint.weight) {
this._hintMap.set(hint.variantId.toString(), hint);
}
}
});
this.requestUpdate('_hintMap');
},
'umbObserveHints',
);
});
}
#isVariantHint(hint: UmbHint): hint is UmbVariantHint {
return hint && 'variantId' in hint;
}
@state()
private _hintMap = new Map<string, UmbVariantHint>();
async #observeVariants(workspaceContext?: UmbVariantDatasetWorkspaceContext) {
this.observe(
workspaceContext?.variantOptions,
@@ -302,6 +331,16 @@ export class UmbWorkspaceSplitViewVariantSelectorElement<
override render() {
if (!this._variantId) return nothing;
let firstHintOnInactiveVariant: UmbVariantHint | undefined;
if (this._activeVariant) {
const hintsOrderedByWeight = Array.from(this._hintMap.values()).sort((a, b) => (b.weight || 0) - (a.weight || 0));
firstHintOnInactiveVariant = hintsOrderedByWeight.find((hint) => {
if (!hint.variantId) return false;
return !hint.variantId.isInvariant() && hint.variantId.compare(this._activeVariant!) === false;
});
}
return html`
<uui-input
id="name-input"
@@ -330,6 +369,7 @@ export class UmbWorkspaceSplitViewVariantSelectorElement<
${this.#getVariantSpecInfo(this._activeVariant)}
${this.#renderReadOnlyTag(this._activeVariant?.culture)}
<uui-symbol-expand .open=${this._variantSelectorOpen}></uui-symbol-expand>
${this.#renderHintBadge(firstHintOnInactiveVariant)}
</uui-button>
${this._activeVariants.length > 1
? html`
@@ -360,8 +400,11 @@ export class UmbWorkspaceSplitViewVariantSelectorElement<
const variantId = UmbVariantId.Create(variantOption);
const notCreated = this.#isCreateMode(variantOption, variantId);
const subVariantOptions = this.#getSegmentVariantOptionsForCulture(variantOption, variantId);
const hint = this._hintMap.get(variantId.toString());
const active = this.#isVariantActive(variantId);
return html`
<div class="variant culture-variant ${this.#isVariantActive(variantId) ? 'selected' : ''}">
<div class="variant culture-variant ${active ? 'selected' : ''}">
${this._variesBySegment && this.#isCreated(variantOption) && subVariantOptions.length > 0
? html`<div class="expand-area">${this.#renderExpandToggle(variantId)}</div>`
: nothing}
@@ -381,6 +424,7 @@ export class UmbWorkspaceSplitViewVariantSelectorElement<
</div>
</div>
<div class="specs-info">${this.#getVariantSpecInfo(variantOption)}</div>
${this.#renderHintBadge(!active ? hint : undefined)}
</button>
${this.#renderSplitViewButton(variantOption)}
</div>
@@ -390,6 +434,13 @@ export class UmbWorkspaceSplitViewVariantSelectorElement<
`;
}
#renderHintBadge(hint?: UmbVariantHint) {
if (!hint) return nothing;
return html`<div class="hint">
<uui-badge .color=${hint.color ?? 'default'} ?attention=${hint.color === 'invalid'}>${hint.text}</uui-badge>
</div>`;
}
#isCreated(variantOption: VariantOptionModelType) {
return (
variantOption.variant?.state &&