Custom Sections

UI-O-Matic exposes a single section by default (the UI-O-Matic section). If you want to have multiple sections, or if you want to change the section name, you can do so with a few classes.

Composer

First you will need a composer that removes the current section, and adds any new sections you want to add. In this composer, there are two new UI-O-Matic sections added, namely Incidents and Instruction.

[ComposeAfter(typeof(UIOMatic.Sections.SectionComposer))]
public class SectionComposer : IUserComposer
{
public void Compose(Composition composition)
{
composition.Sections().Append<IncidentsSection>();
composition.Sections().Append<InstructionSection>();
composition.Sections().Remove<UIOMatic.Sections.UIOMaticSection>();
}
private class IncidentsSection : ISection
{
public string Alias => IncidentsTreeController.IncidentsAlias;
public string Name => IncidentsTreeController.IncidentsName;
}
private class InstructionSection : ISection
{
public string Alias => InstructionTreeController.InstructionAlias;
public string Name => InstructionTreeController.InstructionName;
}
}

Mapping Tree Controller

The UI-O-Matic tree controller is a good starting point that offers integration with any custom service or repositories. While you could write an entirely new tree controller, it often will be simpler to extend the UIOMaticTreeController. In doing this, you'll need to update the route paths to map to your new section names. Below is a generic, abstract mapping controller that can be implemented to easily provide this mapping for you.

public abstract class UIOMaticSubSectionTreeController : UIOMaticTreeController
{
private const string UIOMaticRoutePath = Constants.SectionAlias + "/" + Constants.TreeAlias + "/";
public abstract string SubSectionAlias { get; }
public abstract string SubSectionName { get; }
protected string BaseRoutePath => $"{SubSectionAlias}/{Constants.TreeAlias}/";
protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings) => UpdateRoutePath(base.GetTreeNodes(GetNodeId(id, queryStrings), queryStrings));
protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings) => base.GetMenuForNode(GetNodeId(id, queryStrings), queryStrings);
protected override TreeNode CreateRootNode(FormDataCollection queryStrings) => UpdateRoutePath(base.CreateRootNode(queryStrings));
protected virtual string GetNodeId(string id, FormDataCollection queryStrings) =>
!string.IsNullOrWhiteSpace(queryStrings.Get("startNodeId"))
? queryStrings.Get("startNodeId")
: (string.IsNullOrEmpty(id) || id == global::Umbraco.Core.Constants.System.RootString ? SubSectionAlias : id);
protected virtual TreeNodeCollection UpdateRoutePath(TreeNodeCollection nodes)
{
if (nodes == null || nodes.Count == 0) return nodes;
foreach (var node in nodes) UpdateRoutePath(node);
return nodes;
}
protected virtual TreeNode UpdateRoutePath(TreeNode node)
{
if (node?.RoutePath != null && node.RoutePath.StartsWith(UIOMaticRoutePath)) node.RoutePath = BaseRoutePath + (node.RoutePath.Length > UIOMaticRoutePath.Length ? node.RoutePath.Substring(UIOMaticRoutePath.Length) : "");
else if (node?.RoutePath == Constants.SectionAlias) node.RoutePath = SubSectionAlias;
if (node?.Name == "UI-O-Matic") node.Name = SubSectionName;
return node;
}
}

Custom Tree Controllers

With the mapping controller in place, you can now easily create custom tree controllers. Below are two tree controller which will map to the custom sections used above.

[UmbracoApplicationAuthorize(IncidentsAlias)]
[UmbracoTreeAuthorize("content")]
[Tree(IncidentsAlias, "uiomatic", TreeTitle = IncidentsName, SortOrder = 1)]
[PluginController("UIOMatic")]
public class IncidentsTreeController : UIOMaticSubSectionTreeController
{
public const string IncidentsAlias = "incidents";
public const string IncidentsName = "Incidents";
public override string SubSectionAlias => IncidentsAlias;
public override string SubSectionName => IncidentsName;
}
[UmbracoApplicationAuthorize(InstructionAlias)]
[UmbracoTreeAuthorize("content")]
[Tree(InstructionAlias, "uiomatic", TreeTitle = InstructionName, SortOrder = 1)]
[PluginController("UIOMatic")]
public class InstructionTreeController : UIOMaticSubSectionTreeController
{
public const string InstructionAlias = "instruction";
public const string InstructionName = "Instruction";
public override string SubSectionAlias => InstructionAlias;
public override string SubSectionName => InstructionName;
}

Language File

Once the composer is in place and you have new trees added, you will need to set the displayed title for your new sections and trees, so that they don't display with brackets in the back-office. To do this, create a new folder under App_Plugins in your web project, and create a lang folder in it, i.e. App_Plugins/UIOMatic.Custom/lang. In this lang folder, create a language file for the languages you support, i.e. en-US.xml. Here are example contents for an en-US.xml file that could be used with the above sections and trees.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<language alias="en_us" intName="English (US)" localName="English (US)" lcid="" culture="en-US">
<area alias="sections">
<key alias="incidents">Incidents</key>
<key alias="instruction">Instruction</key>
</area>
<area alias="treeHeaders">
<key alias="incidents">Incidents</key>
<key alias="instruction">Instruction</key>
</area>
</language>