Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Umbraco.Cms.Core.Configuration.Models;

public class TinyMceToTiptapMigrationSettings
{
public bool DisableMigration { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ public static IUmbracoBuilder AddConfiguration(this IUmbracoBuilder builder)
Constants.Configuration.NamedOptions.InstallDefaultData.MemberTypes,
builder.Config.GetSection($"{Constants.Configuration.ConfigInstallDefaultData}:{Constants.Configuration.NamedOptions.InstallDefaultData.MemberTypes}"));

builder.Services.AddOptions<TinyMceToTiptapMigrationSettings>();

return builder;
}
}
3 changes: 3 additions & 0 deletions src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,5 +115,8 @@ protected virtual void DefinePlan()
// To 15.4.0
To<V_15_4_0.UpdateDocumentUrlToPersistMultipleSegmentsPerDocument>("{A9E72794-4036-4563-B543-1717C73B8879}");
To<V_15_4_0.AddRelationTypeForMembers>("{33D62294-D0DE-4A86-A830-991EB36B96DA}");

// To 16.0.0
To<V_16_0_0.MigrateTinyMceToTiptap>("{C6681435-584F-4BC8-BB8D-BC853966AF0B}");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Services;
using Umbraco.Extensions;

namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_16_0_0;

public class MigrateTinyMceToTiptap : AsyncMigrationBase
{
private readonly IDataTypeService _dataTypeService;
private readonly TinyMceToTiptapMigrationSettings _options;

public MigrateTinyMceToTiptap(IMigrationContext context, IDataTypeService dataTypeService, IOptions<TinyMceToTiptapMigrationSettings> options) : base(context)
{
_dataTypeService = dataTypeService;
_options = options.Value;
}

protected override async Task MigrateAsync()
{
if (_options.DisableMigration)
{
return;
}

IEnumerable<IDataType> dataTypes = await _dataTypeService.GetByEditorUiAlias("Umb.PropertyEditorUi.TinyMCE");

foreach (IDataType dataType in dataTypes)
{
MigrateToTipTap(dataType);
await _dataTypeService.UpdateAsync(dataType, Constants.Security.SuperUserKey);
}
}

private void MigrateToTipTap(IDataType dataType)
{
dataType.EditorUiAlias = "Umb.PropertyEditorUi.Tiptap";

if (!dataType.ConfigurationData.TryGetValue("toolbar", out var toolbar) || toolbar is not List<string> toolBarList)
{
return;
}

dataType.ConfigurationData.Remove("mode");
dataType.ConfigurationData.Remove("hideLabel");

var newToolbar = toolBarList.Select(MapToolbarItem).WhereNotNull().ToList();
dataType.ConfigurationData["toolbar"] = new List<List<List<string>>> { new() { newToolbar } };

var extensions = new List<string>
{
"Umb.Tiptap.RichTextEssentials",
"Umb.Tiptap.Embed",
"Umb.Tiptap.Figure",
"Umb.Tiptap.Image",
"Umb.Tiptap.Link",
"Umb.Tiptap.MediaUpload",
"Umb.Tiptap.Subscript",
"Umb.Tiptap.Superscript",
"Umb.Tiptap.Table",
"Umb.Tiptap.TextAlign",
"Umb.Tiptap.TextDirection",
"Umb.Tiptap.TextIndent",
"Umb.Tiptap.Underline"
};

// If the rich text has block enabled, we also need to add the block extension
if (dataType.ConfigurationObject is RichTextConfiguration richTextConfiguration)
{
if (richTextConfiguration.Blocks?.Any() ?? false)
{
extensions.Add("Umb.Tiptap.Block");
}
}

dataType.ConfigurationData["extensions"] = extensions.ToArray();
}

private string? MapToolbarItem(string item)
{
return item switch
{
"undo" => "Umb.Tiptap.Toolbar.Undo",
"redo" => "Umb.Tiptap.Toolbar.Redo",
"cut" => null,
"copy" => null,
"paste" => null,
"styles" => "Umb.Tiptap.Toolbar.StyleSelect",
"fontname" => "Umb.Tiptap.Toolbar.FontFamily",
"fontfamily" => "Umb.Tiptap.Toolbar.FontFamily",
"fontsize" => "Umb.Tiptap.Toolbar.FontSize",
"forecolor" => "Umb.Tiptap.Toolbar.TextColorForeground",
"backcolor" => "Umb.Tiptap.Toolbar.TextColorBackground",
"blockquote" => "Umb.Tiptap.Toolbar.Blockquote",
"formatblock" => null,
"removeformat" => "Umb.Tiptap.Toolbar.ClearFormatting",
"bold" => "Umb.Tiptap.Toolbar.Bold",
"italic" => "Umb.Tiptap.Toolbar.Italic",
"underline" => "Umb.Tiptap.Toolbar.Underline",
"strikethrough" => "Umb.Tiptap.Toolbar.Strike",
"alignleft" => "Umb.Tiptap.Toolbar.TextAlignLeft",
"aligncenter" => "Umb.Tiptap.Toolbar.TextAlignCenter",
"alignright" => "Umb.Tiptap.Toolbar.TextAlignRight",
"alignjustify" => "Umb.Tiptap.Toolbar.TextAlignJustify",
"bullist" => "Umb.Tiptap.Toolbar.BulletList",
"numlist" => "Umb.Tiptap.Toolbar.OrderedList",
"outdent" => "Umb.Tiptap.Toolbar.TextOutdent",
"indent" => "Umb.Tiptap.Toolbar.TextIndent",
"anchor" => "Umb.Tiptap.Toolbar.Anchor",
"table" => "Umb.Tiptap.Toolbar.Table",
"hr" => "Umb.Tiptap.Toolbar.HorizontalRule",
"subscript" => "Umb.Tiptap.Toolbar.Subscript",
"superscript" => "Umb.Tiptap.Toolbar.Superscript",
"charmap" => "Umb.Tiptap.Toolbar.CharacterMap",
"rtl" => "Umb.Tiptap.Toolbar.TextDirectionRtl",
"ltr" => "Umb.Tiptap.Toolbar.TextDirectionLtr",
"link" => "Umb.Tiptap.Toolbar.Link",
"unlink" => "Umb.Tiptap.Toolbar.Unlink",
"sourcecode" => "Umb.Tiptap.Toolbar.SourceEditor",
"umbmediapicker" => "Umb.Tiptap.Toolbar.MediaPicker",
"umbembeddialog" => "Umb.Tiptap.Toolbar.EmbeddedMedia",
"umbblockpicker" => "Umb.Tiptap.Toolbar.BlockPicker",
_ => null
};
}

Check warning on line 128 in src/Umbraco.Infrastructure/Migrations/Upgrade/V_16_0_0/MigrateTinyMceToTiptap.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v16/dev)

❌ New issue: Complex Method

MapToolbarItem has a cyclomatic complexity of 43, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.
}