Skip to content

Commit d45a8f2

Browse files
authored
Segments: The experience of working with Segments and Segmented Blocks (#20358)
* initial notes * flat mapper impl * first tests passed * return incoming value to ensure it does not result in an error from an extension * define the manifest type on UmbPropertyValueResolver * finish property value flat-mapper * make sure also to map values with no extension * clean up test * export controller * fix block editor property resolver * fix mapper types * ensureVariantsData method * ensure Block List only updates if it has an update * ensure varians across for shared across segment and shared across cultures * fix variant selector hints for segments * fix hints in variant selector for segmented variants
1 parent 0ded9a7 commit d45a8f2

File tree

22 files changed

+394
-56
lines changed

22 files changed

+394
-56
lines changed

src/Umbraco.Web.UI.Client/src/assets/lang/da.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2473,8 +2473,7 @@ export default {
24732473
confirmDeleteBlockTypeNotice:
24742474
'Indholdet vil stadigt eksistere, men redigering af dette indhold vil ikke\n være muligt. Indholdet vil blive vist som ikke understøttet indhold.\n ',
24752475
confirmDeleteBlockGroupTitle: 'Slet gruppe?',
2476-
confirmDeleteBlockGroupMessage:
2477-
'Er du sikker på at du vil slette gruppen <strong>%0%</strong>?',
2476+
confirmDeleteBlockGroupMessage: 'Er du sikker på at du vil slette gruppen <strong>%0%</strong>?',
24782477
confirmDeleteBlockGroupNotice:
24792478
'Indholdet af gruppens blokke vil stadigt eksistere, men redigering af dette indhold vil ikke\n være muligt. Indholdet vil blive vist som ikke understøttet indhold.\n ',
24802479
blockConfigurationOverlayTitle: "Konfiguration af '%0%'",

src/Umbraco.Web.UI.Client/src/assets/lang/en.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2605,8 +2605,7 @@ export default {
26052605
confirmDeleteBlockTypeNotice:
26062606
'The content of this block will still be present, editing of this content will no longer be available and will be shown as unsupported content.',
26072607
confirmDeleteBlockGroupTitle: 'Delete group?',
2608-
confirmDeleteBlockGroupMessage:
2609-
'Are you sure you want to delete group <strong>%0%</strong>?',
2608+
confirmDeleteBlockGroupMessage: 'Are you sure you want to delete group <strong>%0%</strong>?',
26102609
confirmDeleteBlockGroupNotice:
26112610
'The content of these Blocks will still be present, editing of this content will no longer be available and will be shown as unsupported content.',
26122611
blockConfigurationOverlayTitle: "Configuration of '%0%'",

src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-editor/manifests.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,7 @@ export const manifests: Array<UmbExtensionManifest | UmbExtensionManifestKind> =
7373
alias: 'Umb.PropertyValueResolver.BlockGrid',
7474
name: 'Block Value Resolver',
7575
api: UmbStandardBlockValueResolver,
76-
meta: {
77-
editorAlias: UMB_BLOCK_GRID_PROPERTY_EDITOR_SCHEMA_ALIAS,
78-
},
76+
forEditorAlias: UMB_BLOCK_GRID_PROPERTY_EDITOR_SCHEMA_ALIAS,
7977
},
8078
blockGridSchemaManifest,
8179
...propertyActionManifests,

src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-editor/property-editor-ui-block-grid.element.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import type {
1717
UmbPropertyEditorUiElement,
1818
UmbPropertyEditorConfigCollection,
1919
} from '@umbraco-cms/backoffice/property-editor';
20-
import { observeMultiple } from '@umbraco-cms/backoffice/observable-api';
20+
import { jsonStringComparison, observeMultiple } from '@umbraco-cms/backoffice/observable-api';
2121
import { UMB_PROPERTY_CONTEXT, UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property';
2222
import { UmbFormControlMixin, UmbValidationContext } from '@umbraco-cms/backoffice/validation';
2323
import type { UmbBlockTypeGroup } from '@umbraco-cms/backoffice/block-type';
@@ -181,15 +181,22 @@ export class UmbPropertyEditorUIBlockGridElement
181181
]).pipe(debounceTime(20)),
182182
([layouts, contents, settings, exposes]) => {
183183
if (layouts.length === 0) {
184+
if (this.value === undefined) {
185+
return;
186+
}
184187
super.value = undefined;
185188
} else {
186-
super.value = {
189+
const newValue = {
187190
...super.value,
188191
layout: { [UMB_BLOCK_GRID_PROPERTY_EDITOR_SCHEMA_ALIAS]: layouts },
189192
contentData: contents,
190193
settingsData: settings,
191194
expose: exposes,
192195
};
196+
if (jsonStringComparison(this.value, newValue)) {
197+
return;
198+
}
199+
super.value = newValue;
193200
}
194201

195202
// If we don't have a value set from the outside or an internal value, we don't want to set the value.

src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/manifests.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,7 @@ export const manifests: Array<UmbExtensionManifest> = [
5151
alias: 'Umb.PropertyValueResolver.BlockList',
5252
name: 'Block Value Resolver',
5353
api: UmbStandardBlockValueResolver,
54-
meta: {
55-
editorAlias: UMB_BLOCK_LIST_PROPERTY_EDITOR_SCHEMA_ALIAS,
56-
},
54+
forEditorAlias: UMB_BLOCK_LIST_PROPERTY_EDITOR_SCHEMA_ALIAS,
5755
},
5856
blockListSchemaManifest,
5957
];

src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
UmbFormControlMixin,
2626
UmbValidationContext,
2727
} from '@umbraco-cms/backoffice/validation';
28-
import { observeMultiple } from '@umbraco-cms/backoffice/observable-api';
28+
import { jsonStringComparison, observeMultiple } from '@umbraco-cms/backoffice/observable-api';
2929
import { debounceTime } from '@umbraco-cms/backoffice/external/rxjs';
3030
import { UMB_CONTENT_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/content';
3131

@@ -339,15 +339,22 @@ export class UmbPropertyEditorUIBlockListElement
339339
]).pipe(debounceTime(20)),
340340
([layouts, contents, settings, exposes]) => {
341341
if (layouts.length === 0) {
342+
if (this.value === undefined) {
343+
return;
344+
}
342345
super.value = undefined;
343346
} else {
344-
super.value = {
347+
const newValue = {
345348
...super.value,
346349
layout: { [UMB_BLOCK_LIST_PROPERTY_EDITOR_SCHEMA_ALIAS]: layouts },
347350
contentData: contents,
348351
settingsData: settings,
349352
expose: exposes,
350353
};
354+
if (jsonStringComparison(this.value, newValue)) {
355+
return;
356+
}
357+
super.value = newValue;
351358
}
352359

353360
// If we don't have a value set from the outside or an internal value, we don't want to set the value.

src/Umbraco.Web.UI.Client/src/packages/content/content/controller/merge-content-variant-data.controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ export class UmbMergeContentVariantDataController extends UmbControllerBase {
135135
// If api is not to be found, then we can continue using the draftValue as is.
136136
return draftValue;
137137
}
138-
(api as any).manifest = manifest;
138+
api.manifest = manifest;
139139

140140
let newValue = draftValue;
141141

src/Umbraco.Web.UI.Client/src/packages/content/content/manager/content-data-manager.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ export class UmbContentWorkspaceDataManager<
5353
this.updateVariantData(variantId);
5454
}
5555

56+
ensureVariantsData(variantIds: UmbVariantId[]) {
57+
this.initiatePropertyValueChange();
58+
for (const variantId of variantIds) {
59+
this.updateVariantData(variantId);
60+
}
61+
this.finishPropertyValueChange();
62+
}
63+
5664
updateVariantData(variantId: UmbVariantId, update?: Partial<ModelVariantType>) {
5765
if (!this.#variantScaffold) throw new Error('Variant scaffold data is missing');
5866

src/Umbraco.Web.UI.Client/src/packages/content/content/workspace/content-detail-workspace-base.ts

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
} from '@umbraco-cms/backoffice/entity-action';
2929
import { UmbLanguageCollectionRepository } from '@umbraco-cms/backoffice/language';
3030
import {
31+
UmbPropertyValueFlatMapperController,
3132
UmbPropertyValuePresetVariantBuilderController,
3233
UmbVariantPropertyGuardManager,
3334
} from '@umbraco-cms/backoffice/property';
@@ -287,7 +288,7 @@ export abstract class UmbContentDetailWorkspaceContextBase<
287288
if (variesByCulture && variesBySegment) {
288289
return languages.flatMap((language) => {
289290
const culture = {
290-
variant: variants.find((x) => x.culture === language.unique),
291+
variant: variants.find((x) => x.culture === language.unique && x.segment === null),
291292
language,
292293
culture: language.unique,
293294
segment: null,
@@ -496,10 +497,7 @@ export abstract class UmbContentDetailWorkspaceContextBase<
496497
* @memberof UmbContentDetailWorkspaceContextBase
497498
*/
498499
public setName(name: string, variantId?: UmbVariantId): void {
499-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
500-
// @ts-ignore
501-
// TODO: fix type error
502-
this._data.updateVariantData(variantId ?? UmbVariantId.CreateInvariant(), { name });
500+
this._data.updateVariantData(variantId ?? UmbVariantId.CreateInvariant(), { name } as Partial<VariantModelType>);
503501
}
504502

505503
/**
@@ -661,36 +659,65 @@ export abstract class UmbContentDetailWorkspaceContextBase<
661659

662660
const currentData = this.getData();
663661
if (currentData) {
664-
const values = appendToFrozenArray(
662+
const values: DetailModelType['values'] = appendToFrozenArray(
665663
currentData.values ?? [],
666664
entry,
667665
(x) => x.alias === alias && variantId!.compare(x),
668666
);
669667

670-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
671-
// @ts-ignore
672-
// TODO: fix type error
673-
this._data.updateCurrent({ values });
674-
675-
/**
676-
* Handling of Not-Culture but Segment variant properties: [NL]
677-
* We need to ensure variant-entries across all culture variants for the given segment variant, when er property is configured to vary by segment but not culture.
678-
* This is the only different case, in all other cases its fine to just target the given variant.
679-
*/
680-
if (this.getVariesByCulture() && property.variesByCulture === false && property.variesBySegment === true) {
668+
this.#ensureVariantsExistsForProperty(variantId, entry);
669+
670+
this._data.updateCurrent({ values } as Partial<DetailModelType>);
671+
}
672+
673+
this.finishPropertyValueChange();
674+
}
675+
676+
async #ensureVariantsExistsForProperty(variantId: UmbVariantId, entry: UmbElementValueModel) {
677+
// TODO: Implement queueing of these operations to ensure this does not execute too often. [NL]
678+
679+
const cultureOptions = await firstValueFrom(this.variantOptions);
680+
let valueVariantIds: Array<UmbVariantId> = [];
681+
682+
// Find inner values to determine if any of this holds variants that needs to be created.
683+
if (variantId.isInvariant() && entry.value) {
684+
valueVariantIds = await new UmbPropertyValueFlatMapperController(this).flatMap(entry, (property) => {
685+
return UmbVariantId.CreateFromPartial(property);
686+
});
687+
}
688+
689+
valueVariantIds.push(variantId);
690+
/**
691+
* Handling of Not-Culture but Segment variant properties: [NL]
692+
* We need to ensure variant-entries across all culture variants for the given segment variant, when er property is configured to vary by segment but not culture.
693+
* This is the only different case, in all other cases its fine to just target the given variant.
694+
*/
695+
const variantOptionsToCheck: Array<UmbVariantId> = [];
696+
for (const variant of valueVariantIds) {
697+
// If a non-culture but segmented value, then spread across all cultures for the given segment:
698+
if (this.getVariesByCulture() && variant.culture === null && variant.segment !== null) {
681699
// get all culture options:
682-
const cultureOptions = await firstValueFrom(this.variantOptions);
683700
for (const cultureOption of cultureOptions) {
684-
if (cultureOption.segment === variantId.segment) {
685-
this._data.ensureVariantData(UmbVariantId.Create(cultureOption));
701+
if (cultureOption.segment === variant.segment) {
702+
variantOptionsToCheck.push(UmbVariantId.Create(cultureOption));
686703
}
687704
}
688-
} else {
689-
// otherwise we know the property variant-id will be matching with a variant:
690-
this._data.ensureVariantData(variantId);
705+
// If a non-segmented but culture-variant value, then spread across all segments for the given culture:
706+
}
707+
if (this.getVariesBySegment() && variant.culture !== null && variant.segment === null) {
708+
// get all culture options:
709+
for (const cultureOption of cultureOptions) {
710+
if (cultureOption.culture === variant.culture) {
711+
variantOptionsToCheck.push(UmbVariantId.Create(cultureOption));
712+
}
713+
}
714+
} else if (cultureOptions.some((x) => variant.compare(x))) {
715+
// otherwise we can parse the variant-id on:
716+
variantOptionsToCheck.push(variant);
691717
}
692718
}
693-
this.finishPropertyValueChange();
719+
720+
this._data.ensureVariantsData(variantOptionsToCheck);
694721
}
695722

696723
public initiatePropertyValueChange() {

src/Umbraco.Web.UI.Client/src/packages/core/components/badge/badge.element.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,20 @@ export class UmbBadgeElement extends LitElement {
4747
css`
4848
:host {
4949
position: absolute;
50-
anchor-name: --umb-badge-anchor;
5150
/** because inset has no effect on uui-badge in this case, we then apply it here: */
5251
inset: var(--uui-badge-inset, -8px -8px auto auto);
5352
}
5453
54+
:host([inline-mode]) {
55+
position: relative;
56+
margin-left: 12px;
57+
}
58+
5559
@supports (position-anchor: --my-name) {
56-
uui-badge {
60+
:host(:not([inline-mode])) {
61+
anchor-name: --umb-badge-anchor;
62+
}
63+
:host(:not([inline-mode])) uui-badge {
5764
position: fixed;
5865
position-anchor: --umb-badge-anchor;
5966
z-index: 1;

0 commit comments

Comments
 (0)