Skip to content

Commit

Permalink
Block level variance (#17120)
Browse files Browse the repository at this point in the history
* Block level variance - initial commit

* Remove TODOs

* Only convert RTEs with blocks

* Fix JSON paths for block level property validation

* Rename Properties to Values

* Correct the JSON path of block level validation errors

* Make it possible to skip content migration + ensure backwards compat for the new block format

* Partial culture variance publishing at property level

* UDI to key conversion for block editors - draft, WIP, do NOT merge 😄  (#16970)

* Convert block UDIs to GUIDs

* Fix merge

* Fix merge issues

* Rework nested layout item key parsing for backwards compatibility

* Clean-up

* Reverse block layout item key calculation

* Review

* Use IOptions to skip content migrations

* Remove "published" from data editor feature naming, as it can be used in other contexts too

* Parallel migration

* Don't use deprecated constructor

* Ensure that layout follows structure for partial publishing

* Block Grid element level variance + tests (incl. refactor of element level variation tests)

* Rollback unintended changes to Program.cs

* Fix bad casing

* Minor formatting

* RTE element level variance + tests

* Remove obsoleted constructors

* Use Umbraco.RichText instead of Umbraco.TinyMCE as layout alias for blocks in the RTE

* Fix bad merge

* Temporary fix for new cache in integration tests

* Add EditorAlias to block level properties

* Remove the unintended PropertyEditorAlias output for block values

* Add EditorAlias to Datatype Item model

* Update OpenApi.json

* Introduce "expose" for blocks

* Strict (explicit) handling for Expose

* Improve handling of document and element level variance changes

* Refactor variance alignment for published rendering

* Block UDI to Key conversion should also register as a conversion

* Convert newly added RTE unit test to new RTE blocks format

* Minor review changes

* Run memory intensive tests on Linux only

* Add tests proving that AllowEditInvariantFromNonDefault has effect for block level variance too

* Fix the Platform annotations

* Removed Platform annotations for tests.

* Fix merge

* Obsolete old PublishCulture extension

* More fixing bad merge

---------

Co-authored-by: Niels Lyngsø <[email protected]>
Co-authored-by: nikolajlauridsen <[email protected]>
  • Loading branch information
3 people authored Sep 30, 2024
1 parent 1fa132f commit 1be503e
Show file tree
Hide file tree
Showing 91 changed files with 6,762 additions and 1,034 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ private static void Map(IDataType source, DataTypeItemResponseModel target, Mapp
target.Name = source.Name ?? string.Empty;
target.Id = source.Key;
target.EditorUiAlias = source.EditorUiAlias;
target.EditorAlias = source.EditorAlias;
target.IsDeletable = source.IsDeletableDataType();
}

Expand Down
4 changes: 4 additions & 0 deletions src/Umbraco.Cms.Api.Management/OpenApi.json
Original file line number Diff line number Diff line change
Expand Up @@ -35987,6 +35987,7 @@
},
"DataTypeItemResponseModel": {
"required": [
"editorAlias",
"id",
"isDeletable",
"name"
Expand All @@ -36004,6 +36005,9 @@
"type": "string",
"nullable": true
},
"editorAlias": {
"type": "string"
},
"isDeletable": {
"type": "boolean"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ public class DataTypeItemResponseModel : NamedItemResponseModelBase
{
public string? EditorUiAlias { get; set; }

public string EditorAlias { get; set; } = string.Empty;

public bool IsDeletable { get; set; }
}
54 changes: 52 additions & 2 deletions src/Umbraco.Core/Models/Blocks/BlockEditorDataConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,63 @@ public BlockEditorData<TValue, TLayout> Deserialize(string json)

public BlockEditorData<TValue, TLayout> Convert(TValue? value)
{
if (value?.GetLayouts() is not IEnumerable<TLayout> layouts)
if (value is not null)
{
var converted = ConvertOriginalBlockFormat(value.ContentData);
if (converted)
{
ConvertOriginalBlockFormat(value.SettingsData);
AmendExpose(value);
}
}

TLayout[]? layouts = value?.GetLayouts()?.ToArray();
if (layouts is null)
{
return BlockEditorData<TValue, TLayout>.Empty;
}

IEnumerable<ContentAndSettingsReference> references = GetBlockReferences(layouts);

return new BlockEditorData<TValue, TLayout>(references, value);
return new BlockEditorData<TValue, TLayout>(references, value!);
}

// this method is only meant to have any effect when migrating block editor values
// from the original format to the new, variant enabled format
private void AmendExpose(TValue value)
=> value.Expose = value.ContentData.Select(cd => new BlockItemVariation(cd.Key, null, null)).ToList();

// this method is only meant to have any effect when migrating block editor values
// from the original format to the new, variant enabled format
private bool ConvertOriginalBlockFormat(List<BlockItemData> blockItemDatas)
{
var converted = false;
foreach (BlockItemData blockItemData in blockItemDatas)
{
// only overwrite the Properties collection if none have been added at this point
if (blockItemData.Values.Any() is false && blockItemData.RawPropertyValues.Any())
{
blockItemData.Values = blockItemData
.RawPropertyValues
.Select(item => new BlockPropertyValue { Alias = item.Key, Value = item.Value })
.ToList();
converted = true;
}

// no matter what, clear the RawPropertyValues collection so it is not saved back to the DB
blockItemData.RawPropertyValues.Clear();

// assign the correct Key if only a UDI is set
if (blockItemData.Key == Guid.Empty && blockItemData.Udi is GuidUdi guidUdi)
{
blockItemData.Key = guidUdi.Guid;
converted = true;
}

// no matter what, clear the UDI value so it's not saved back to the DB
blockItemData.Udi = null;
}

return converted;
}
}
10 changes: 1 addition & 9 deletions src/Umbraco.Core/Models/Blocks/BlockGridEditorDataConverter.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.

using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Serialization;

namespace Umbraco.Cms.Core.Models.Blocks;
Expand All @@ -12,12 +10,6 @@ namespace Umbraco.Cms.Core.Models.Blocks;
/// </summary>
public class BlockGridEditorDataConverter : BlockEditorDataConverter<BlockGridValue, BlockGridLayoutItem>
{
[Obsolete("Use the constructor that takes IJsonSerializer. Will be removed in V15.")]
public BlockGridEditorDataConverter()
: this(StaticServiceProvider.Instance.GetRequiredService<IJsonSerializer>())
{
}

public BlockGridEditorDataConverter(IJsonSerializer jsonSerializer)
: base(jsonSerializer)
{
Expand All @@ -27,7 +19,7 @@ protected override IEnumerable<ContentAndSettingsReference> GetBlockReferences(I
{
IList<ContentAndSettingsReference> ExtractContentAndSettingsReferences(BlockGridLayoutItem item)
{
var references = new List<ContentAndSettingsReference> { new(item.ContentUdi, item.SettingsUdi) };
var references = new List<ContentAndSettingsReference> { new(item.ContentKey, item.SettingsKey) };
references.AddRange(item.Areas.SelectMany(area => area.Items.SelectMany(ExtractContentAndSettingsReferences)));
return references;
}
Expand Down
59 changes: 45 additions & 14 deletions src/Umbraco.Core/Models/Blocks/BlockGridItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,45 @@ public class BlockGridItem : IBlockReference<IPublishedElement, IPublishedElemen
/// <exception cref="ArgumentNullException">contentUdi
/// or
/// content</exception>
[Obsolete("Use constructor that accepts GUIDs instead. Will be removed in V18.")]
public BlockGridItem(Udi contentUdi, IPublishedElement content, Udi settingsUdi, IPublishedElement settings)
: this(
(contentUdi as GuidUdi)?.Guid ?? throw new ArgumentException(nameof(contentUdi)),
content,
(settingsUdi as GuidUdi)?.Guid,
settings)
{
ContentUdi = contentUdi ?? throw new ArgumentNullException(nameof(contentUdi));
}

public BlockGridItem(Guid contentKey, IPublishedElement content, Guid? settingsKey, IPublishedElement? settings)
{
ContentKey = contentKey;
ContentUdi = new GuidUdi(Constants.UdiEntityType.Element, contentKey);
Content = content ?? throw new ArgumentNullException(nameof(content));
SettingsUdi = settingsUdi;
SettingsKey = settingsKey;
SettingsUdi = settingsKey.HasValue
? new GuidUdi(Constants.UdiEntityType.Element, settingsKey.Value)
: null;
Settings = settings;
}

/// <summary>
/// Gets the content key.
/// </summary>
public Guid ContentKey { get; set; }

/// <summary>
/// Gets the settings key.
/// </summary>
public Guid? SettingsKey { get; set; }

/// <summary>
/// Gets the content UDI.
/// </summary>
/// <value>
/// The content UDI.
/// </value>
[DataMember(Name = "contentUdi")]
[Obsolete("Use ContentKey instead. Will be removed in V18.")]
public Udi ContentUdi { get; }

/// <summary>
Expand All @@ -46,7 +70,6 @@ public BlockGridItem(Udi contentUdi, IPublishedElement content, Udi settingsUdi,
/// <value>
/// The content.
/// </value>
[DataMember(Name = "content")]
public IPublishedElement Content { get; }

/// <summary>
Expand All @@ -55,46 +78,40 @@ public BlockGridItem(Udi contentUdi, IPublishedElement content, Udi settingsUdi,
/// <value>
/// The settings UDI.
/// </value>
[DataMember(Name = "settingsUdi")]
public Udi SettingsUdi { get; }
[Obsolete("Use SettingsKey instead. Will be removed in V18.")]
public Udi? SettingsUdi { get; }

/// <summary>
/// Gets the settings.
/// </summary>
/// <value>
/// The settings.
/// </value>
[DataMember(Name = "settings")]
public IPublishedElement Settings { get; }
public IPublishedElement? Settings { get; }

/// <summary>
/// The number of rows this item should span
/// </summary>
[DataMember(Name = "rowSpan")]
public int RowSpan { get; set; }

/// <summary>
/// The number of columns this item should span
/// </summary>
[DataMember(Name = "columnSpan")]
public int ColumnSpan { get; set; }

/// <summary>
/// The grid areas within this item
/// </summary>
[DataMember(Name = "areas")]
public IEnumerable<BlockGridArea> Areas { get; set; } = Array.Empty<BlockGridArea>();

/// <summary>
/// The number of columns available for the areas to span
/// </summary>
[DataMember(Name = "areaGridColumns")]
public int? AreaGridColumns { get; set; }

/// <summary>
/// The number of columns in the root grid
/// </summary>
[DataMember(Name = "gridColumns")]
public int? GridColumns { get; set; }
}

Expand All @@ -112,12 +129,19 @@ public class BlockGridItem<T> : BlockGridItem
/// <param name="content">The content.</param>
/// <param name="settingsUdi">The settings UDI.</param>
/// <param name="settings">The settings.</param>
[Obsolete("Use constructor that accepts GUIDs instead. Will be removed in V18.")]
public BlockGridItem(Udi contentUdi, T content, Udi settingsUdi, IPublishedElement settings)
: base(contentUdi, content, settingsUdi, settings)
{
Content = content;
}

public BlockGridItem(Guid contentKey, T content, Guid? settingsKey, IPublishedElement? settings)
: base(contentKey, content, settingsKey, settings)
{
Content = content;
}

/// <summary>
/// Gets the content.
/// </summary>
Expand All @@ -143,18 +167,25 @@ public class BlockGridItem<TContent, TSettings> : BlockGridItem<TContent>
/// <param name="content">The content.</param>
/// <param name="settingsUdi">The settings udi.</param>
/// <param name="settings">The settings.</param>
[Obsolete("Use constructor that accepts GUIDs instead. Will be removed in V18.")]
public BlockGridItem(Udi contentUdi, TContent content, Udi settingsUdi, TSettings settings)
: base(contentUdi, content, settingsUdi, settings)
{
Settings = settings;
}

public BlockGridItem(Guid contentKey, TContent content, Guid? settingsKey, TSettings? settings)
: base(contentKey, content, settingsKey, settings)
{
Settings = settings;
}

/// <summary>
/// Gets the settings.
/// </summary>
/// <value>
/// The settings.
/// </value>
public new TSettings Settings { get; }
public new TSettings? Settings { get; }
}
}
27 changes: 19 additions & 8 deletions src/Umbraco.Core/Models/Blocks/BlockGridLayoutItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,8 @@ namespace Umbraco.Cms.Core.Models.Blocks;
/// <summary>
/// Used for deserializing the block grid layout
/// </summary>
public class BlockGridLayoutItem : IBlockLayoutItem
public class BlockGridLayoutItem : BlockLayoutItemBase
{
public Udi? ContentUdi { get; set; }

public Udi? SettingsUdi { get; set; }

public int? ColumnSpan { get; set; }

public int? RowSpan { get; set; }
Expand All @@ -21,10 +17,25 @@ public class BlockGridLayoutItem : IBlockLayoutItem
public BlockGridLayoutItem()
{ }

[Obsolete("Use constructor that accepts GUIDs instead. Will be removed in V18.")]
public BlockGridLayoutItem(Udi contentUdi)
=> ContentUdi = contentUdi;
: base(contentUdi)
{
}

[Obsolete("Use constructor that accepts GUIDs instead. Will be removed in V18.")]
public BlockGridLayoutItem(Udi contentUdi, Udi settingsUdi)
: this(contentUdi)
=> SettingsUdi = settingsUdi;
: base(contentUdi, settingsUdi)
{
}

public BlockGridLayoutItem(Guid contentKey)
: base(contentKey)
{
}

public BlockGridLayoutItem(Guid contentKey, Guid settingsKey)
: base(contentKey, settingsKey)
{
}
}
3 changes: 3 additions & 0 deletions src/Umbraco.Core/Models/Blocks/BlockGridValue.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.Text.Json.Serialization;

namespace Umbraco.Cms.Core.Models.Blocks;

/// <summary>
Expand All @@ -19,5 +21,6 @@ public BlockGridValue(IEnumerable<BlockGridLayoutItem> layouts)
=> Layout[PropertyEditorAlias] = layouts;

/// <inheritdoc />
[JsonIgnore]
public override string PropertyEditorAlias => Constants.PropertyEditors.Aliases.BlockGrid;
}
Loading

0 comments on commit 1be503e

Please sign in to comment.