Feature: highlight invariant doc with variant blocks is unsupported (#18806)

* mark variant blocks in invariant docs as invalid

* implement RTE Blocks
This commit is contained in:
Niels Lyngsø
2025-04-02 06:25:34 +02:00
committed by GitHub
parent 8e0912cbf1
commit 11c19847cf
6 changed files with 146 additions and 3 deletions

View File

@@ -2657,6 +2657,8 @@ export default {
unsupportedBlockName: 'Unsupported',
unsupportedBlockDescription:
'This content is no longer supported in this Editor. If you are missing this content, please contact your administrator. Otherwise delete it.',
blockVariantConfigurationNotSupported:
'One or more Block Types of this Block Editor is using a Element-Type that is configured to Vary By Culture or Vary By Segment. This is not supported on a Content item that does not vary by Culture or Segment.',
},
contentTemplatesDashboard: {
whatHeadline: 'What are Document Blueprints?',

View File

@@ -9,6 +9,7 @@ import {
css,
type PropertyValueMap,
ref,
nothing,
} from '@umbraco-cms/backoffice/external/lit';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type {
@@ -24,6 +25,7 @@ import { debounceTime } from '@umbraco-cms/backoffice/external/rxjs';
// TODO: consider moving the components to the property editor folder as they are only used here
import '../../local-components.js';
import { UMB_CONTENT_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/content';
/**
* @element umb-property-editor-ui-block-grid
@@ -85,9 +87,51 @@ export class UmbPropertyEditorUIBlockGridElement
return super.value;
}
@state()
_notSupportedVariantSetting?: boolean;
constructor() {
super();
this.consumeContext(UMB_CONTENT_WORKSPACE_CONTEXT, (context) => {
this.observe(
observeMultiple([
this.#managerContext.blockTypes,
context.structure.variesByCulture,
context.structure.variesBySegment,
]),
async ([blockTypes, variesByCulture, variesBySegment]) => {
if (blockTypes.length > 0 && (variesByCulture === false || variesBySegment === false)) {
// check if any of the Blocks varyByCulture or Segment and then display a warning.
const promises = await Promise.all(
blockTypes.map(async (blockType) => {
const elementType = blockType.contentElementTypeKey;
await this.#managerContext.contentTypesLoaded;
const structure = await this.#managerContext.getStructure(elementType);
if (variesByCulture === false && structure?.getVariesByCulture() === true) {
// If block varies by culture but document does not.
return true;
} else if (variesBySegment === false && structure?.getVariesBySegment() === true) {
// If block varies by segment but document does not.
return true;
}
return false;
}),
);
this._notSupportedVariantSetting = promises.filter((x) => x === true).length > 0;
if (this._notSupportedVariantSetting) {
this.#validationContext.messages.addMessage(
'config',
'$',
'#blockEditor_blockVariantConfigurationNotSupported',
);
}
}
},
);
}).passContextAliasMatches();
this.consumeContext(UMB_PROPERTY_CONTEXT, (context) => {
this.observe(
context.dataPath,
@@ -195,6 +239,9 @@ export class UmbPropertyEditorUIBlockGridElement
}
override render() {
if (this._notSupportedVariantSetting) {
return nothing;
}
return html` <umb-block-grid-entries
${ref(this.#gotRootEntriesElement)}
.areaKey=${null}

View File

@@ -27,6 +27,7 @@ import {
} from '@umbraco-cms/backoffice/validation';
import { observeMultiple } from '@umbraco-cms/backoffice/observable-api';
import { debounceTime } from '@umbraco-cms/backoffice/external/rxjs';
import { UMB_CONTENT_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/content';
const SORTER_CONFIG: UmbSorterConfig<UmbBlockListLayoutModel, UmbBlockListEntryElement> = {
getUniqueOfElement: (element) => {
@@ -110,6 +111,8 @@ export class UmbPropertyEditorUIBlockListElement
this.#managerContext.contentTypesLoaded.then(() => {
const firstContentTypeName = this.#managerContext.getContentTypeNameOf(blocks[0].contentElementTypeKey);
this._createButtonLabel = this.localize.term('blockEditor_addThis', this.localize.string(firstContentTypeName));
// If we are in a invariant context:
});
}
}
@@ -157,9 +160,52 @@ export class UmbPropertyEditorUIBlockListElement
readonly #managerContext = new UmbBlockListManagerContext(this);
readonly #entriesContext = new UmbBlockListEntriesContext(this);
@state()
_notSupportedVariantSetting?: boolean;
constructor() {
super();
this.consumeContext(UMB_CONTENT_WORKSPACE_CONTEXT, (context) => {
this.observe(
observeMultiple([
this.#managerContext.blockTypes,
context.structure.variesByCulture,
context.structure.variesBySegment,
]),
async ([blockTypes, variesByCulture, variesBySegment]) => {
if (blockTypes.length > 0 && (variesByCulture === false || variesBySegment === false)) {
// check if any of the Blocks varyByCulture or Segment and then display a warning.
const promises = await Promise.all(
blockTypes.map(async (blockType) => {
const elementType = blockType.contentElementTypeKey;
await this.#managerContext.contentTypesLoaded;
const structure = await this.#managerContext.getStructure(elementType);
if (variesByCulture === false && structure?.getVariesByCulture() === true) {
// If block varies by culture but document does not.
return true;
} else if (variesBySegment === false && structure?.getVariesBySegment() === true) {
// If block varies by segment but document does not.
return true;
}
return false;
}),
);
this._notSupportedVariantSetting = promises.filter((x) => x === true).length > 0;
if (this._notSupportedVariantSetting) {
this.#validationContext.messages.addMessage(
'config',
'$',
'#blockEditor_blockVariantConfigurationNotSupported',
'blockConfigurationNotSupported',
);
}
}
},
);
}).passContextAliasMatches();
this.consumeContext(UMB_PROPERTY_CONTEXT, (context) => {
this.#gotPropertyContext(context);
});
@@ -193,7 +239,7 @@ export class UmbPropertyEditorUIBlockListElement
null,
);
this.consumeContext(UMB_PROPERTY_DATASET_CONTEXT, (context) => {
this.consumeContext(UMB_PROPERTY_DATASET_CONTEXT, async (context) => {
this.#managerContext.setVariantId(context.getVariantId());
});
@@ -334,6 +380,9 @@ export class UmbPropertyEditorUIBlockListElement
}
override render() {
if (this._notSupportedVariantSetting) {
return nothing;
}
return html`
${repeat(
this._layouts,

View File

@@ -3,7 +3,7 @@ import type { Observable } from '@umbraco-cms/backoffice/external/rxjs';
import { UmbId } from '@umbraco-cms/backoffice/id';
import { UmbArrayState, createObservablePart } from '@umbraco-cms/backoffice/observable-api';
export type UmbValidationMessageType = 'client' | 'server';
export type UmbValidationMessageType = 'client' | 'server' | 'config' | string;
export interface UmbValidationMessage {
type: UmbValidationMessageType;
key: string;
@@ -95,6 +95,14 @@ export class UmbValidationMessagesManager {
);
}
messagesOfNotTypeAndPath(type: UmbValidationMessageType, path: string): Observable<Array<UmbValidationMessage>> {
//path = path.toLowerCase();
// Find messages that matches the given type and path.
return createObservablePart(this.filteredMessages, (msgs) =>
msgs.filter((x) => x.type !== type && x.path === path),
);
}
hasMessagesOfPathAndDescendant(path: string): Observable<boolean> {
//path = path.toLowerCase();
return createObservablePart(this.filteredMessages, (msgs) =>

View File

@@ -43,7 +43,7 @@ export class UmbBindServerValidationToFormControl extends UmbControllerBase {
this.#context = context;
this.observe(
context.messages?.messagesOfTypeAndPath('server', dataPath),
context.messages?.messagesOfNotTypeAndPath('client', dataPath),
(messages) => {
this.#messages = messages ?? [];
this.#isValid = this.#messages.length === 0;

View File

@@ -16,6 +16,7 @@ import {
UmbValidationContext,
} from '@umbraco-cms/backoffice/validation';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UMB_CONTENT_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/content';
export abstract class UmbPropertyEditorUiRteElementBase
extends UmbFormControlMixin<UmbPropertyEditorRteValueType | undefined, typeof UmbLitElement, undefined>(UmbLitElement)
@@ -114,6 +115,42 @@ export abstract class UmbPropertyEditorUiRteElementBase
constructor() {
super();
this.consumeContext(UMB_CONTENT_WORKSPACE_CONTEXT, (context) => {
this.observe(
observeMultiple([
this.#managerContext.blockTypes,
context.structure.variesByCulture,
context.structure.variesBySegment,
]),
async ([blockTypes, variesByCulture, variesBySegment]) => {
if (blockTypes.length > 0 && (variesByCulture === false || variesBySegment === false)) {
// check if any of the Blocks varyByCulture or Segment and then display a warning.
const promises = await Promise.all(
blockTypes.map(async (blockType) => {
const elementType = blockType.contentElementTypeKey;
await this.#managerContext.contentTypesLoaded;
const structure = await this.#managerContext.getStructure(elementType);
if (variesByCulture === false && structure?.getVariesByCulture() === true) {
// If block varies by culture but document does not.
return true;
} else if (variesBySegment === false && structure?.getVariesBySegment() === true) {
// If block varies by segment but document does not.
return true;
}
return false;
}),
);
const notSupportedVariantSetting = promises.filter((x) => x === true).length > 0;
if (notSupportedVariantSetting) {
this.setCustomValidity('#blockEditor_blockVariantConfigurationNotSupported');
this.checkValidity();
}
}
},
);
}).passContextAliasMatches();
this.consumeContext(UMB_PROPERTY_CONTEXT, (context) => {
this.#gotPropertyContext(context);
});