Skip to content

Conversation

Migaroez
Copy link
Contributor

@Migaroez Migaroez commented Sep 8, 2025

Description

This PR introduces a new Single Block Property editor that has a similar data format and behaviour as the Block List Property Editor but will only ever accept 1 block.

A lot of the implemenations listed below are based upon the blocklist/block...base classes. This might in some places not be the most optimal way to handle things, but it does mean we can reuse and there for keep in sync a lot of the more complex logic of these propertyEditors and there data structure/validation. The biggest thing that you might notice is that the underlying data value of the block (even though it is stripped down) still uses an array.

The following things have been changed/added

  • Introduced SingleBlockPropertyEditor
  • Introduced SingleBlockPropertyValueEditor
  • Obsoleted UseSingleBlockMode
  • Added unit tests
  • Added a disabled unit tests for missing validation
  • Added a test factory to convert IContent to ContentUpdateModels so we can test validation more easily. This is the basis for a future task
  • Added a propertyvalueConverter
  • Added a rendering function/template with a nifty fallback function to the blocklist component views

The following things will be done in future PR's

  • Optional migration to move blocklists with the single mode configuration over to the single block datatype
  • Umb.PropertyEditorUi.SingleBlock UI
  • Block type wide (single,list/grid) backend validation regarding valid blocks compared to the configured blocks

Example Testing setup

  • Setup a element document type, I used a single property with Alias text that has a textstring datatype
  • Use the management api to setup a single block data type as the Front-end has not been updated yet. The blocklist editorUiAlias is used as a placeholder. Example:
{
  "id": "54b2e9bd-eaeb-4b0f-93c9-d2aa80b09f66",
  "name": "TestBlock",
  "editorAlias": "Umbraco.SingleBlock",
  "editorUiAlias": "Umb.PropertyEditorUi.BlockList",
  "values": [
    {
      "alias": "blocks",
      "value": [
        {
          "contentElementTypeKey": "a996db74-fa11-415e-9cbc-4e2241a2b907"
        }
      ]
    }
  ]
}
  • Create a document type with a property backed by the TestBlock datatype, I called mine BlockTester with a single property Block
  • Create a document trough the management api (as the the placeholder ui will not work). Example:
{
    "variants": [
        {
            "culture": null,
            "segment": null,
            "name": "Test Page"
        }
    ],
    "documentType": {
        "id": "30fe7729-17c9-4bf9-bfbb-e1f261cf8e39"
    },
    "template": {
        "id": "83bf87fa-a5c8-40d6-93b3-3fda361f2470"
    },
    "values": [
        {
            "editorAlias": "Umbraco.SingleBlock",
            "culture": null,
            "segment": null,
            "alias": "block",
            "value": {
                "layout": {
                    "Umbraco.SingleBlock": [
                        {
                            "contentUdi": null,
                            "settingsUdi": null,
                            "contentKey": "e3268c37-1bab-4ba3-9a92-fd3c2f15c0d8",
                            "settingsKey": null
                        }
                    ]
                },
                "contentData": [
                    {
                        "contentTypeKey": "a996db74-fa11-415e-9cbc-4e2241a2b907",
                        "udi": null,
                        "key": "e3268c37-1bab-4ba3-9a92-fd3c2f15c0d8",
                        "values": [
                            {
                                "editorAlias": "Umbraco.TextBox",
                                "culture": null,
                                "segment": null,
                                "alias": "text",
                                "value": "Block text"
                            }
                        ]
                    }
                ],
                "settingsData": [],
                "expose": [
                    {
                        "contentKey": "e3268c37-1bab-4ba3-9a92-fd3c2f15c0d8",
                        "culture": null,
                        "segment": null
                    }
                ]
            }
        }
    ]
}
  • Publishe the page trough the management api. Example payload
{"publishSchedules":[{"culture":null}]}
  • Make sure your models are generated
  • Update the template to something like
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<BlockTester>
@{
	Layout = null;
}

@await Html.GetBlockHtmlAsync(Model.Block)
  • Create a view for your element type in either views/partials/singleblock/components OR views/partials/blocklist/components. Example:
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockListItem>;
@{
    var content = (TextBlock)Model.Content;
}
<p>@content.Text<p>
  • Open the page and it should show the value of the textbox you filled in trough the management api

@Migaroez Migaroez marked this pull request as ready for review September 9, 2025 11:05
@kjac kjac self-requested a review September 10, 2025 05:41
@kjac kjac self-assigned this Sep 10, 2025
Copy link
Contributor

@kjac kjac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent work @Migaroez 😍

I've taken the liberty to align the naming of all tests (using underscores as most of the tests were with underscores). I know we don't really do this consequently throughout the codebase, but... call me nitpicking 😆

There are a few TODOs to look into as well.

Lastly - I think you forgot to commit default.cshtml for single block rendering. Makes sense since the views folder is git-ignored, but it yields a good ol' rendering exception when one attempts to put the SingleBlockTemplateExtensions to use.

To test the rendering, I created my own default.cshtml in /Views/Partials/singleblock/ with this content:

@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockListItem>
<div class="umb-single-block-list">
    @await Html.PartialAsync("singleblock/Components/" + Model.Content.ContentType.Alias, Model)
</div>

If that looks about right from a functional perspective, the rendering tests out fine 👍 it also works strongly typed with models builder types, as one would expect:

@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockListItem<MyElement>>
<p>@Model.Content.Title<p>

One last thing I'm wondering about is this (from the PR description):

Create a view for your element type in either views/partials/singleblock/components OR views/partials/blocklist/components.

I can't see how the SingleBlockTemplateExtensions would support views in the blocklist/components folder? I tried it out, of course, by moving my view in there (from singleblock/components). As expected, I got an InvalidOperationException with The partial view 'singleblock/Components/myElement' was not found.

I don't think it's a required feature for the extensions to pick up on views from either folder, so unless you were actively planning on supporting that, I believe the PR description should just be amended to omit this?

@Migaroez
Copy link
Contributor Author

@kjac I have added the missing file and hopefully it then makes sense. I added this functionality to allow for easier migrations.

kjac
kjac previously approved these changes Sep 10, 2025
Copy link
Contributor

@kjac kjac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good 👍

Views in blocklist/components now work, and views in singleblock/components take precedence in case of matching file names - entirely as expected.

...and indexing works too 😄

Happy to approve!

@kjac kjac dismissed their stale review September 10, 2025 15:17

Just noticed the PR is targeting main --- dismissing the approval while clarifying the intended target version of this feature.

@Migaroez Migaroez force-pushed the v16/feature/single-block-property-editor branch from d728baa to 838b0b6 Compare September 16, 2025 11:30
@Migaroez Migaroez changed the base branch from main to v17/dev September 16, 2025 11:32
@Migaroez
Copy link
Contributor Author

Rebased and retargeted to v17

Copy link
Contributor

@kjac kjac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good and tests out good too 👍

@kjac kjac merged commit dd01a56 into v17/dev Sep 17, 2025
24 of 25 checks passed
@kjac kjac deleted the v16/feature/single-block-property-editor branch September 17, 2025 05:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants