diff --git a/15/umbraco-ui-builder/.gitbook.yaml b/15/umbraco-ui-builder/.gitbook.yaml new file mode 100644 index 00000000000..83e70191059 --- /dev/null +++ b/15/umbraco-ui-builder/.gitbook.yaml @@ -0,0 +1,12 @@ +root: ./ + +​structure: + readme: README.md + summary: SUMMARY.md + +redirects: +getting-started/upgrading/README: upgrading/upgrade.md +getting-started/upgrading/version-specific-upgrades: upgrading/version-specific.md +getting-started/installation: installation/installation.md +getting-started/licensing-model: installation/licensing-model.md +guides/migrating-from-konstrukt-to-umbraco-ui-builder: upgrading/migrating-from-konstrukt-to-umbraco-ui-builder.md diff --git a/15/umbraco-ui-builder/README.md b/15/umbraco-ui-builder/README.md new file mode 100644 index 00000000000..0057d67557d --- /dev/null +++ b/15/umbraco-ui-builder/README.md @@ -0,0 +1,29 @@ +--- +description: Documentation for Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Umbraco UI Builder Documentation + +Umbraco UI Builder is the backoffice UI builder for custom data structures configured via a fluent API. + +![Example Umbraco UI Builder UI](images/listview.png) + +If you have a custom data store that you want to content manage from within Umbraco, then you can use Umbraco UI Builder. With some lines of code, you can configure a custom administration UI, and reuse many core components with a consistent look and feel. + +With Umbraco UI Builder, custom backoffice integrations can now take a matter of minutes, rather than days. + +## Using the Documentation + +**This documentation is aimed at developers** who have at least a basic understanding of Umbraco, as well as C#/MVC principles. + +If you are new to Umbraco UI Builder, it is recommended that you start by taking a look at the [Getting Started](./getting-started/overview.md) section. This provides details on the system requirements and how to install Umbraco UI Builder. + +Once you have Umbraco UI Builder installed and are wondering "What next?" then you'll want to take a look at the [Guides](./guides/creating-your-first-integration.md) section. This provides a quick-start example of how to configure Umbraco UI Builder. + +Use the main menu to dive deeper into Umbraco UI Builder and get to know all of its features in detail. You can then jump to the specific topic you are interested in to find out more. + +Finally, for all other resources/useful information you can head over to the [Miscellaneous](./miscellaneous/conventions.md) section. + +## Getting Help + +If you require assistance you can use our support channels to seek assistance. diff --git a/15/umbraco-ui-builder/SUMMARY.md b/15/umbraco-ui-builder/SUMMARY.md new file mode 100644 index 00000000000..3423f807237 --- /dev/null +++ b/15/umbraco-ui-builder/SUMMARY.md @@ -0,0 +1,92 @@ +# Table of contents + +* [Umbraco UI Builder Documentation](README.md) +* [Known Issues](known-issues.md) +* [Release Notes](release-notes.md) + +## Installation + +* [Installing Umbraco UI Builder](installation/installation.md) +* [Licensing](installation/licensing-model.md) + +## Upgrading + +* [Upgrading Umbraco UI Builder](upgrading/upgrade.md) +* [Version Specific Upgrade Notes](upgrading/version-specific.md) +* [Migrate from Konstrukt to Umbraco UI Builder](upgrading/migrating-from-konstrukt-to-umbraco-ui-builder.md) + +## Getting Started + +* [Overview](getting-started/overview.md) +* [Configuration](getting-started/configuration.md) +* [User Interface](getting-started/user-interface.md) + +## How-to Guides + +* [Creating your first integration](guides/creating-your-first-integration.md) + +## Areas + +* [Overview](areas/overview.md) +* [Sections](areas/sections.md) + * [Summary Dashboards](areas/summary-dashboards.md) +* [Trees](areas/trees.md) + * [Folders](areas/folders.md) +* [Dashboards](areas/dashboards.md) +* [Context Apps](areas/context-apps.md) + +## Collections + +* [Overview](collections/overview.md) +* [The Basics](collections/the-basics.md) +* [List Views](collections/list-views.md) + * [Field Views](collections/field-views.md) +* [Editors](collections/editors.md) +* [Child Collections](collections/child-collections.md) + * [Child Collection Groups](collections/child-collection-groups.md) + * [Retrieve Child Collections](collections/retrieve-child-collections.md) +* [Related Collections](collections/related-collections.md) + +## Searching + +* [Overview](searching/overview.md) +* [Searchable Properties](searching/searchable-properties.md) + +## Filtering + +* [Overview](filtering/overview.md) +* [Global Filters](filtering/global-filters.md) +* [Data Views](filtering/data-views.md) + * [Data Views Builders](filtering/data-views-builders.md) +* [Filterable Properties](filtering/filterable-properties.md) + +## Actions + +* [Overview](actions/overview.md) +* [The Basics](actions/the-basics.md) +* [Action Visibility](actions/action-visibility.md) +* [Inbuilt Actions](actions/inbuilt-actions.md) + +## Cards + +* [Overview](cards/overview.md) +* [Count Cards](cards/count-cards.md) +* [Custom Cards](cards/custom-cards.md) + +## Property Editors + +* [Overview](property-editors/overview.md) +* [Entity Picker](property-editors/entity-picker.md) + +## Advanced + +* [Virtual Sub Trees](advanced/virtual-sub-trees.md) +* [Encrypted Properties](advanced/encrypted-properties.md) +* [Value Mappers](advanced/value-mappers.md) +* [Repositories](advanced/repositories.md) +* [Events](advanced/events.md) + +## Miscellaneous + +* [Conventions](miscellaneous/conventions.md) +* [Umbraco Aliases](miscellaneous/umbraco-aliases.md) diff --git a/15/umbraco-ui-builder/actions/action-visibility.md b/15/umbraco-ui-builder/actions/action-visibility.md new file mode 100644 index 00000000000..99086bb89b4 --- /dev/null +++ b/15/umbraco-ui-builder/actions/action-visibility.md @@ -0,0 +1,109 @@ +--- +description: Controlling the visibility of actions in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Action Visibility + +By default actions are not visible in the UI and you must expressly define when and where an action should display. This can be achieved in two ways, either on the action definition itself or at the point of registration on the collections config. + +## Controlling the default action visibility + +To define the default visibility of an action at the action level you can do this by overriding the `IsVisible` method of the `Action<>` base class. + +````csharp +// Example +public class MyAction : Action +{ + ... + public override bool IsVisible(ActionVisibilityContext ctx) + { + return ctx.ActionType == ActionType.Bulk + || ctx.ActionType == ActionType.Row; + } + ... +} +```` + +The `IsVisible` method is passed a `ActionVisibilityContext` which you should use to decide whether the action should display, returning `true` if it should, or `false` if it should not. For more information check the [Action visibility context](#action-visibility-context). + +## Overriding an actions visibility + +Overriding an actions visibility is controlled via the [collections](../collections/overview.md) configuration. + +### **AddAction<TMenuActionType>(Lambda actionConfig = null) : CollectionConfigBuilder<TEntityType>** + +Adds an action of the given type to the collection with the given visibility. + +````csharp +// Example +collectionConfig.AddAction(actionConfig => actionConfig + .SetVisibility(x => x.ActionType == ActionType.Bulk + || x.ActionType == ActionType.Row) +); +```` + +### **AddAction(Type actionType, Lambda actionConfig = null) : CollectionConfigBuilder<TEntityType>** + +Adds an action of the given type to the collection with the given visibility. + +````csharp +// Example +collectionConfig.AddAction(typeof(ExportMenuAction), actionConfig => actionConfig + .SetVisibility(x => x.ActionType == ActionType.Bulk + || x.ActionType == ActionType.Row) +); +```` + +### **AddAction(IAction action, Lambda actionConfig = null) : CollectionConfigBuilder<TEntityType>** + +Adds the given action to the collection with the given visibility. + +````csharp +// Example +collectionConfig.AddAction(action, actionConfig => actionConfig + .SetVisibility(x => x.ActionType == ActionType.Bulk + || x.ActionType == ActionType.Row) +); +```` + +## Action visibility context + +When controlling the visibility of an action you will be given a `ActionVisibilityContext` object from which you can decide whether to show the action or not. The visibility context contains two key pieces of information on which you can base this decision. + +### ActionType + +The action type property is an enum property that define which area of the UI it is that wishes to access this action. Enabling an action to display for a given action type will determine where an action is displayed. + +#### ContainerMenu + +The `ContainerMenu` action type determines that the action will be displayed in both the tree of the collection and its list view actions menu. + +![Container Menu](../images/container_actions_menu.png) + +#### EntityMenu + +The `EntityMenu` action type determines that the action will be displayed in the actions menu of a collection editor UI. + +![Entity Menu](../images/entity_actions_menu.png) + +#### Bulk + +The `Bulk` action type determines that the action will be displayed in the collection list view bulk actions menu. + +![Bulk Actions](../images/bulk_actions_menu.png) + +#### Row + +The `Row` action type determines that the action will be displayed in the collection list view action row menu. + +![Row Actions](../images/row_actions_menu.png) + +#### Save + +The `Save` action type determines that the action will be displayed as a sub button in an entity editors save button. All `Save` action types trigger a save before the action is executed and so to convey this, all `Save` action type button labels are prefixed `Save & [Action Name]` + +![Save Actions](../images/save_actions_menu.png) + +### UserGroups + +The user groups collection contains a list of Umbraco `IReadOnlyUserGroup` objects for the current logged-in backoffice user. This allows you to control the visibility of actions for given user group members. diff --git a/15/umbraco-ui-builder/actions/inbuilt-actions.md b/15/umbraco-ui-builder/actions/inbuilt-actions.md new file mode 100644 index 00000000000..6a88bc85bb2 --- /dev/null +++ b/15/umbraco-ui-builder/actions/inbuilt-actions.md @@ -0,0 +1,19 @@ +--- +description: A list of inbuilt actions that come with Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Inbuilt Actions + +Umbraco UI Builder comes with some inbuilt actions that are available for you to use straight away. + +## ExportEntityAction + +**Namespace** Umbraco.UIBuilder.Infrastructure.Configuration.Actions + +Provides a Comma-Separated Values (CSV) export functionality converting all properties to column headings and rendering each entity property values on each row. + +## ImportEntityAction + +**Namespace** Umbraco.UIBuilder.Infrastructure.Configuration.Actions + +Provides a Comma-Separated Values (CSV) import functionality matching column headings with entity properties and mapping row values to an entity. diff --git a/15/umbraco-ui-builder/actions/overview.md b/15/umbraco-ui-builder/actions/overview.md new file mode 100644 index 00000000000..cf0369c2b15 --- /dev/null +++ b/15/umbraco-ui-builder/actions/overview.md @@ -0,0 +1,15 @@ +--- +description: Configuring actions in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Actions + +Actions provide an API to perform custom tasks against a collection and its entities from multiple locations in the UI. Examples: menu actions, bulk actions, or individual table row actions. + +![Bulk Actions UI](../images/bulk_actions.png) + +Get started with actions by learning about the basics. + +{% content-ref url="the-basics.md" %} +[the-basics.md](the-basics.md) +{% endcontent-ref %} diff --git a/15/umbraco-ui-builder/actions/the-basics.md b/15/umbraco-ui-builder/actions/the-basics.md new file mode 100644 index 00000000000..430a66c1a40 --- /dev/null +++ b/15/umbraco-ui-builder/actions/the-basics.md @@ -0,0 +1,119 @@ +--- +description: Configuring actions in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# The Basics + +Actions are a powerful way of adding custom functionality to Umbraco UI Builder without needing to create custom UI elements. By providing an action to run, Umbraco UI Builder can automatically trigger actions from a number of UI locations. + +## Defining an action + +To define an action create a class that inherits from the base class `Action<>` and configure it like below: + +````csharp +// Example +public class MyAction : Action +{ + public override string Icon => "icon-settings"; + public override string Alias => "myaction"; + public override string Name => "My Action"; + public override bool ConfirmAction => true; + + public override ActionResult Execute(string collectionAlias, object[] entityIds) + { + // Perform operation here... + } +} +```` + +The required configuration options are: + +* **Name:** The name of the action. +* **Alias:** A unique alias for the action. +* **Icon:** An icon to display next to the name in the action button. +* **Execute:** The method to run against a given list of entities. + +Additional optional configuration options are: + +* **ConfirmAction:** Set whether a confirm dialog should display before performing this action. + +The generic argument is a return type for the action. See [Controlling the action result](#controlling-the-action-result) below. + +{% hint style="info" %} +You can use dependency injection to inject any services you require to perform your specific task. When injecting dependencies, it's always recommended that you inject `Lazy` implementations of the required services to ensure they are only resolved when needed. +{% endhint %} + +## Controlling the action result + +Actions by default will return a `ActionResult` but you can return other types of result by swapping the `Action<>` generic argument. + +* **`ActionResult`** - Standard result with a boolean `Success` value. +* **`FileActionResult`** - Returns a file stream / bytes and triggers a download dialog. + +## Capturing settings for an action + +Sometimes you may need to collect further user input before you can perform an action. To achieve this you can use the `Action<>` base class that accepts an additional `TSetting` generic argument. + +````csharp +// Example +public class MyAction : Action +{ + public override string Icon => "icon-settings"; + public override string Alias => "myaction"; + public override string Name => "My Action"; + public override bool ConfirmAction => true; + + public override void Configure(SettingsConfigBuilder settingsConfig) + { + settingsConfig.AddFielset("General", fieldsetConfig => fieldsetConfig + .AddField(s => s.RecipientName).SetLabel("Recipient Name") + .AddField(s => s.RecipientEmail).SetLabel("Recipient Email")) + } + + public override ActionResult Execute(string collectionAlias, object[] entityIds, MyActionSettings settings) + { + // Perform operation here... + } +} + +public class MyActionSettings +{ + public string RecipientName { get; set; } + public string RecipientEmail { get; set; } +} +```` + +By implementing this base class you are required to implement an additional `Configure` method which accepts a `SettingsConfigBuilder<>` parameter. You should use this parameter calling the builders fluent API to define the settings dialog UI and how it maps to the settings type. With the settings config builder you are able to create fieldsets and fields with the same fluent API as defined in the [Collection Editors section](../collections/editors.md#adding-a-fieldset-to-a-tab). + +In addition to this `Configure` method, the `Execute` method will now accept an additional `settings` parameter of the settings type. This will be pre-populated by Umbraco UI Builder with the value entered by the user, allowing you to alter your actions behavior accordingly. + +## Adding an action to a collection + +Actions are added via the [Collections](../collections/overview.md) configuration. + +### **AddAction<TMenuActionType>() : CollectionConfigBuilder<TEntityType>** + +Adds an action of the given type to the collection. + +````csharp +// Example +collectionConfig.AddAction(); +```` + +#### **AddAction(Type actionType) : CollectionConfigBuilder<TEntityType>** + +Adds an action of the given type to the collection. + +````csharp +// Example +collectionConfig.AddAction(actionType); +```` + +#### **AddAction(IAction action) : CollectionConfigBuilder<TEntityType>** + +Adds the given action to the collection. + +````csharp +// Example +collectionConfig.AddAction(action); +```` diff --git a/15/umbraco-ui-builder/advanced/encrypted-properties.md b/15/umbraco-ui-builder/advanced/encrypted-properties.md new file mode 100644 index 00000000000..7962111773b --- /dev/null +++ b/15/umbraco-ui-builder/advanced/encrypted-properties.md @@ -0,0 +1,22 @@ +--- +description: Configuring encrypted properties in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Encrypted Properties + +If needed to collect sensitive information in a collection but don't want to persist in a plain text format to the data storage mechanism. Umbraco UI Builder can help with this by allowing you to define properties as encrypted. After which any time the value is persisted or retrieved from persistence, Umbraco UI Builder will automatically encrypt and decrypt the value. + +{% hint style="info" %} +Umbraco UI Builder uses the `IDataProtectionProvider` instance registered in the DI container to perform its encryption/decryption. If you need to change the encryption algorithm, you should replace the `IDataProtectionProvider` instance in the DI container. +{% endhint %} + +## Defining encrypted properties + +### **AddEncryptedProperty(Lambda encryptedPropertyExpression) : CollectionConfigBuilder<TEntityType>** + +Adds the given property to the encrypted properties collection. Property must be of type `String`. When set, the property will be encrypted/decrypted on write/read respectively. + +````csharp +// Example +collectionConfig.AddEncryptedProperty(p => p.Secret); +```` diff --git a/15/umbraco-ui-builder/advanced/events.md b/15/umbraco-ui-builder/advanced/events.md new file mode 100644 index 00000000000..78b7363d5ba --- /dev/null +++ b/15/umbraco-ui-builder/advanced/events.md @@ -0,0 +1,145 @@ +--- +description: Configuring event handlers in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Events + +Umbraco UI Builder fires a number of notification events during regular operation to allow for extending of the default behaviour. + +## Registering event handlers + +Umbraco UI Builder uses the same [Notification Mechanism built into Umbraco v9+](../../umbraco-cms/fundamentals/code/subscribing-to-notifications.md) and so uses the same registration process. First you will need to define a notification event handler for the event you wish to handle like below: + +```csharp +public class MyEntitySavingEventHandler : INotificationHandler { + + public void Handle(EntitySavingNotification notification) + { + // Handle the event here + } + +} +``` + +Then register your event handler in the `Program.cs` file like below: + +```csharp +builder.CreateUmbracoBuilder() + .AddBackOffice() + .AddWebsite() + .AddDeliveryApi() + .AddComposers() + .AddNotificationHandler() + .Build(); +``` + +## Repository events + +### **EntitySavingNotification** + +Raised when the repository `Save` method is called and before the entity has been persisted. The notification contains an `Entity` property with `Before` and `After` inner properties. These properties provide access to a copy of the currently persisted entity (or null if a new entity) and the updated entity that´s saved. +Changes can be made to the `After` entity and they will be persisted as part of the save operation. If the `Cancel` property of the notification is set to `true` then the save operation will be canceled and no changes will be saved. + +````csharp +// Example +public class MyEntitySavingEventHandler : INotificationHandler { + + public void Handle(EntitySavingNotification notification) + { + var person = notification.Entity.After as Person; + if (person != null){ + ... + } + } + +} +```` + +### **EntitySavedNotification** + +Raised when the repository `Save` method is called and after the entity has been persisted. The notification contains an `Entity` property with `Before` and `After` inner properties. These properties provide access to a copy of the previously persisted entity (or null if a new entity) and the updated entity that´s saved. + +````csharp +// Example +public class MyEntitySavedEventHandler : INotificationHandler { + + public void Handle(EntitySavedNotification notification) + { + var person = notification.Entity.After as Person; + if (person != null){ + ... + } + } + +} +```` + +### **EntityDeletingNotification** + +Raised when the repository `Delete` method is called and **before** the entity is deleted. The notification contains an `Entity` property providing access to a copy of the entity about to be deleted. If the `Cancel` property of notification is set to `true` then the delete operation will be cancelled and entity won't be deleted. + +````csharp +// Example +public class MyEntityDeletingEventHandler : INotificationHandler { + + public void Handle(EntityDeletingNotification notification) + { + var person = notification.Entity.After as Person; + if (person != null){ + ... + } + } + +} +```` + +### **EntityDeletedNotification** + +Raised when the repository `Delete` method is called and **after** the entity has been deleted. The notification contains an `Entity` property providing access to a copy of the entity that´s deleted. + +````csharp +// Example +public class MyEntityDeletedEventHandler : INotificationHandler { + + public void Handle(EntityDeletedNotification notification) + { + var person = notification.Entity.After as Person; + if (person != null){ + ... + } + } + +} +```` + +### **SqlQueryBuildingNotification** + +Raised when the repository is **preparing** a SQL query. The notification contains the collection alias + type, the NPoco `Sql` object, and the where clause/order by clauses. These will be used to generate the SQL query. + +````csharp +// Example +public class MySqlQueryBuildingEventHandler : INotificationHandler { + + public void Handle(SqlQueryBuildingNotification notification) + { + notification.Sql = notification.Sql.Append("WHERE MyId = @0", 1); + } + +} +```` + +### **SqlQueryBuiltNotification** + +Raised when the repository has **repaired** a SQL query. The notification contains the collection alias + type, the NPoco `Sql` object and the where clause/order by clauses that was used to generate the SQL query. + +````csharp +// Example +public class MySqlQueryBuiltEventHandler : INotificationHandler { + + public void Handle(SqlQueryBuiltNotification notification) + { + notification.Sql = notification.Sql.Append("WHERE MyId = @0", 1); + } + +} +```` diff --git a/15/umbraco-ui-builder/advanced/repositories.md b/15/umbraco-ui-builder/advanced/repositories.md new file mode 100644 index 00000000000..f49db720184 --- /dev/null +++ b/15/umbraco-ui-builder/advanced/repositories.md @@ -0,0 +1,120 @@ +--- +description: Configuring repositories in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Repositories + +Repositories are used by Umbraco UI Builder to access the entity data stores. By default, collections will use a generic built-in NPoco repository. However, you can define your own repository implementation should you wish to store your entities via an alternative strategy. + +## Defining a repository + +To define a repository create a class that inherits from the base class `Repository` and implements all of its abstract methods. + +````csharp +// Example +public class PersonRepository : Repository { + + public PersonRepository(RepositoryContext context) + : base(context) + { } + + protected override int GetIdImpl(Person entity) { + return entity.Id; + } + + protected override Person GetImpl(int id) { + ... + } + + protected override Person SaveImpl(Person entity) { + ... + } + + protected override void DeleteImpl(int id) { + ... + } + + protected override IEnumerable GetAllImpl(Expression> whereClause, Expression> orderBy, SortDirection orderByDirection) { + ... + } + + protected override PagedResult GetPagedImpl(int pageNumber, int pageSize, Expression> whereClause, Expression> orderBy, SortDirection orderByDirection) { + ... + } + + protected override long GetCountImpl(Expression> whereClause) { + ... + } + + protected override IEnumerable GetRelationsByParentIdImpl(int parentId, string relationAlias) + { + ... + } + + protected override TJunctionEntity SaveRelationImpl(TJunctionEntity entity) + { + ... + } +} +```` + +**Note:** For all `Impl` methods there are public alternatives without the `Impl` suffix. However, there are separate implementation methods in order to ensure all repositories fire the relevant Umbraco UI Builder events. This is whether triggered via the Umbraco UI Builder's UI or not. + +## Changing the repository implementation of a collection + +### **SetRepositoryType<TRepositoryType>() : CollectionConfigBuilder<TEntityType>** + +Sets the repository type to the given type for the current collection. + +````csharp +// Example +collectionConfig.SetRepositoryType(); +```` + +### **SetRepositoryType(Type repositoryType) : CollectionConfigBuilder<TEntityType>** + +Sets the repository type to the given type for the current collection. + +````csharp +// Example +collectionConfig.SetRepositoryType(typeof(PersonRepositoryType)); +```` + +## Accessing a repository in code + +To help with accessing a repository (default or custom) Umbraco UI Builder has an `IRepositoryFactory` you can inject into your code base. This includes a couple of factory methods to create the repository instances for you. +Repositories should only be created via the repository factory as there are some injected dependencies that can only be resolved by Umbraco UI Builder. + +### **IRepositoryFactory.GetRepository<TEntity, TId>() : Repository<TEntity, TId>** + +Creates a repository for the given entity type. Umbraco UI Builder will search the configuration for the first section/collection with a configuration for the given entity type. Then it will use that as a repository configuration. + +````csharp +// Example +public class MyController : Controller +{ + private readonly Repository _repo; + + public MyController(IRepositoryFactory repoFactory) + { + _repo = repoFactory.GetRepository(); + } +} +```` + +### **IRepositoryFactory.GetRepository<TEntity, TId>(string collectionAlias) : Repository<TEntity, TId>** + +Creates a repository for the given entity type from the collection with the given alias. + +````csharp +// Example +public class MyController : Controller +{ + private readonly Repository _repo; + + public MyController(IRepositoryFactory repoFactory) + { + _repo = repoFactory.GetRepository("person"); + } +} +```` diff --git a/15/umbraco-ui-builder/advanced/value-mappers.md b/15/umbraco-ui-builder/advanced/value-mappers.md new file mode 100644 index 00000000000..e49f44aadd7 --- /dev/null +++ b/15/umbraco-ui-builder/advanced/value-mappers.md @@ -0,0 +1,62 @@ +--- +description: Configuring value mappers in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Value Mappers + +A value mapper is an Umbraco UI Builder helper class that sits between the editor UI and the database. It also lets you tweak the stored value of a field. By default Umbraco UI Builder will save a datatype value as it would be stored in Umbraco. Value mappers let you change this. + +When Umbraco UI Builder resolves a value mapper it will attempt to do so from the global DI container. This means you can inject any dependencies that you require for your mapper. If there is no type defined in the DI container, Umbraco UI Builder will fall-back to manually instantiating a new instance of value mapper. + +## Defining a value mapper + +To define a mapper create a class that inherits from the base class `ValueMapper` and implements the methods `EditorToModel` and `ModelToEditor`. + +````csharp +// Example +public class MyValueMapper : ValueMapper +{ + public override object EditorToModel(object input) + { + // Tweak the input and return mapped object + ... + } + + public override object ModelToEditor(object input) + { + // Tweak the input and return mapped object + ... + } +} +```` + +## Setting a field value mapper + +Value mappers are defined as part of a collection editor field configuration. + +### **SetValueMapper<TMapperType>() : EditorFieldConfigBuilder<TEntityType, TValueType>** + +Set the value mapper for the current field. + +````csharp +// Example +fieldConfig.SetValueMapper(); +```` + +### **SetValueMapper(Type mapperType) : EditorFieldConfigBuilder<TEntityType, TValueType>** + +Set the value mapper for the current field. + +````csharp +// Example +fieldConfig.SetValueMapper(typeof(MyValueMapper)); +```` + +### **SetValueMapper(Mapper mapper) : EditorFieldConfigBuilder<TEntityType, TValueType>** + +Set the value mapper for the current field. + +````csharp +// Example +fieldConfig.SetValueMapper(new MyValueMapper()); +```` diff --git a/15/umbraco-ui-builder/advanced/virtual-sub-trees.md b/15/umbraco-ui-builder/advanced/virtual-sub-trees.md new file mode 100644 index 00000000000..3394a2f20e1 --- /dev/null +++ b/15/umbraco-ui-builder/advanced/virtual-sub-trees.md @@ -0,0 +1,141 @@ +--- +description: Configuring virtual sub trees in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Virtual SubTrees + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +Virtual subtrees are a powerful feature that allows you to inject an Umbraco UI Builder tree structure into another Umbraco tree at a desired location. Thus acting as child nodes to the node chosen as the injection point. With virtual subtrees it allows you to extend built in or even 3rd party package trees with additional features. An example could be developing a "loyalty point" program for your e-commerce site and injecting the related database tables into a Vendr store tree. This allows the management of the program in its most logical location. + +![Example virtual sub tree injected into a Vendr store tree](../images/virtual-sub-tree.png) + +## Defining virtual SubTrees + +You define a virtual subtree by calling one of the `AddVirtualSubTree` methods of a [`WithTreeConfigBuilder`](../areas/trees.md#extending-an-existing-tree) instance. + +### **AddVirtualSubTree(string sectionAlias, string treeAlias, Lambda visibilityExpression, Lambda virtualSubTreeConfig = null) : VirtualSubTreeConfigBuilder** + +Adds a virtual subtree to the current tree with its visibility controlled via the visibility expression. + +````csharp +// Example +withTreeConfig.AddVirtualSubTree(ctx => ctx.Source.Id == 1056, contextAppConfig => { + ... +}); +```` + +### **AddVirtualSubTreeBefore(string sectionAlias, string treeAlias, Lambda visibilityExpression, Lambda matchExpression, Lambda virtualSubTreeConfig = null) : VirtualSubTreeConfigBuilder** + +Adds a virtual subtree to the current tree, **before** the tree node matches the match expression, with its visibility controlled via the visibility expression. + +````csharp +// Example +withTreeConfig.AddVirtualSubTreeBefore(ctx => ctx.Source.Id == 1056, treeNode => treeNode.Name == "Settings", contextAppConfig => { + ... +}); +```` + +### **AddVirtualSubTreeAfter(string sectionAlias, string treeAlias, Lambda visibilityExpression, Lambda matchExpression, Lambda virtualSubTreeConfig = null) : VirtualSubTreeConfigBuilder** + +Adds a virtual subtree to the current tree, **after** the tree node matches the match expression, with its visibility controlled via the visibility expression. + +````csharp +// Example +withTreeConfig.AddVirtualSubTreeAfter(ctx => ctx.Source.Id == 1056, treeNode => treeNode.Name == "Settings", contextAppConfig => { + ... +}); +```` + +## Controlling where to inject the Virtual SubTrees + +Controlling where a virtual subtree is injected is done via the visibility expression passed to one of the `AddVirtualSubTree` methods on the root `UIBuilderConfigBuilder` instance. Without a visibility expression, Umbraco UI Builder would inject the virtual subtree under every node in the given tree. This expression can be used to identify the exact location where our tree should go. + +To help with this, the visibility expression is passed a single `VirtualSubTreeFilterContext` argument with relevant contextual information. This information is about the current node being rendered, alongside a list of the current user's user groups for permission-based visibility control. It also includes access to an `IServiceProvider` in case you need to resolve a service to determine the correct node to inject below. + +````csharp +public class VirtualSubTreeFilterContext +{ + public NodeContext Source { get; } + public IEnumerable UserGroups { get; } + public IServiceProvider ServiceProvider { get; } +} + +public class NodeContext +{ + public string Id { get; } + public string TreeAlias { get; } + public string SectionAlias { get; } + public FormCollection QueryString { get; } +} +```` + +Below you can find an example of a more complex filter expression where injection is based on the Document Type of a content node: + +````csharp +withTreeConfig.AddVirtualSubTree(ctx => + { + using var umbracoContextRef = ctx.ServiceProvider.GetRequiredService().EnsureUmbracoContext(); + + if (!int.TryParse(ctx.Source.Id, out int id)) + return false; + + return (umbracoContextRef.UmbracoContext.Content.GetById(id)?.ContentType.Alias ?? "") == "textPage"; + }, + virtualNodeConfig => virtualNodeConfig + ... +); +```` + +## Controlling the position of the injected Virtual SubTrees + +The position of a virtual subtree within the child nodes of the injection node is controlled by using one of the `AddVirtualSubTreeBefore` or `AddVirtualSubTreeAfter` methods. These methods need to be on the root level `UIBuilderConfigBuilder` instance and pass a match expression used to identify the tree node to insert before/after. This expression is passed a single `TreeNode` argument to determine the position. It also requires a `boolean` return value to indicate the relevant location has been found. + +````csharp +public class TreeNode +{ + public object Id { get; } + public object ParentId { get; } + public string Alias { get; } + public string Name { get; } + public string NodeType { get; } + public string Path { get; } + public string RoutePath { get; } + public IDictionary AdditionalData { get; } + ... +} +```` + +Below you can find an example of positioning a subtree after a node with the alias "settings": + +````csharp +treeNode => treeNode.alias == "settings" +```` + +## Configuring a Virtual SubTrees + +Virtual subtrees share the same API as the `Tree` config builder API including support for folders and collections. There is an exception when adding collections to a subtree where you will have an additional foreign key expression parameter to define. The foreign key expression links the entities of the collection to the parent node of the subtree. For more information check the [Core Trees Documentation](../areas/trees.md). + +## Injecting Virtual SubTrees into 3rd party trees + +Out of the box, Umbraco UI Builder supports injecting subtrees into the core content, media, members, and member group trees. It also includes 3rd party support for [Umbraco Commerce](../../umbraco-commerce/README.md) settings and commerce trees. In order to support additional trees to inject into, you must implement an `ITreeHelper` which is used to extract the required information. The tree helper consists of a tree alias for which the tree helper is. It includes methods to correctly identify the full parent path, a unique ID for a given node ID, and to resolve the actual entity ID. The entity ID should be used for the foreign key collection values. + +````csharp +public interface ITreeHelper +{ + string TreeAlias { get; } + string GetUniqueId(string nodeId, FormCollection queryString); + object GetEntityId(string uniqueId); + string GetPath(string uniqueId); +} +```` + +Once you have defined a tree helper, you can register the DI container in your startup class. + +````csharp +builder.Services.AddSingleton(); +```` + +Once registered any virtual subtrees registered against the given helpers tree alias will then use your tree helper to locate the required information. diff --git a/15/umbraco-ui-builder/areas/context-apps.md b/15/umbraco-ui-builder/areas/context-apps.md new file mode 100644 index 00000000000..ad04cf5d62d --- /dev/null +++ b/15/umbraco-ui-builder/areas/context-apps.md @@ -0,0 +1,144 @@ +--- +description: Configuring context apps in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Context Apps + +Context Apps in Umbraco UI Builder are analogous to Content Apps in Umbraco. They allow you to provide contextual apps that appear in the editor UI of content. From Umbraco UI Builder's perspective, defining context apps allows you to expose collections as content apps. This is where a collection has a relation to the content in question. An example could be something like blog post comments which are linked to individual blog posts. Exposing these as a content app allows them to be managed in context next to the blog post they are linked to. + +![Context App](../images/context_app.png) + +## Defining a context app + +You can define a context app by calling one of the `AddContextApp` methods on a [`WithTreeConfigBuilder`](trees.md#extending-an-existing-tree) instance. + +### **AddContextApp(string name, Lambda contextAppConfig = null) : ContextAppConfigBuilder** + +Adds a context app with the given name and default icon. + +```csharp +// Example +withTreeConfig.AddContextApp("Comments", contextAppConfig => { + ... +}); +``` + +### **AddContextApp(string name, string icon, Lambda contextAppConfig = null) : ContextAppConfigBuilder** + +Adds a context app to the Umbraco menu with the given name and icon. + +```csharp +// Example +withTreeConfig.AddContextApp("Comments", "icon-chat", contextAppConfig => { + ... +}); +``` + +### **AddContextAppBefore(string beforeAlias, string name, Lambda contextAppConfig = null) : ContextAppConfigBuilder** + +Adds a context app with the given name and default icon **before** the context app with the given alias. + +```csharp +// Example +withTreeConfig.AddContextAppBefore("umbContent", "Comments", contextAppConfig => { + ... +}); +``` + +### **AddContextAppBefore(string beforeAlias, string name, string icon, Lambda contextAppConfig = null) : ContextAppConfigBuilder** + +Adds a context app to the Umbraco menu with the given name and icon **before** the context app with the given alias. + +```csharp +// Example +withTreeConfig.AddContextAppBefore("umbContent", "Comments", "icon-chat", contextAppConfig => { + ... +}); +``` + +### **AddContextAppAfter(string afterAlias, string name, Lambda contextAppConfig = null) : ContextAppConfigBuilder** + +Adds a context app with the given name and default icon **after** the context app with the given alias. + +```csharp +// Example +withTreeConfig.AddContextAppAfter("umbContent", "Comments", contextAppConfig => { + ... +}); +``` + +### **AddContextAppAfter(string afterAlias, string name, string icon, Lambda contextAppConfig = null) : ContextAppConfigBuilder** + +Adds a context app to the Umbraco menu with the given name and icon **after** the context app with the given alias. + +```csharp +// Example +withTreeConfig.AddContextAppAfter("umbContent", "Comments", "icon-chat", contextAppConfig => { + ... +}); +``` + +## Changing a context app alias + +### **SetAlias(string alias) : ContextAppConfigBuilder** + +Sets the alias of the context app. + +**Optional:** When adding a new context app, an alias is automatically generated from the supplied name for you. However, you can use the `SetAlias` method to override this if you need a specific alias. + +```csharp +// Example +contextAppConfig.SetAlias("comments"); +``` + +## Changing a context app icon color + +### **SetIconColor(string color) : ContextAppConfigBuilder** + +Sets the context app icon color to the given color. Possible options are `black`, `green`, `yellow`, `orange`, `blue` or `red`. + +````csharp +// Example +contextAppConfig.SetIconColor("blue"); +```` + +## Changing when a context app should display + +Changing when a context app is displayed, is controlled by a delegate method which is passed a `ContextAppVisibilityContext` instance. This method contains a `Source` property which holds a reference to the source object that the content app is being displayed on (i.e., an `IContent` instance). It also holds a reference to a `UserGroups` collection of the currently logged-in user's user groups. You can use any value from those to return a boolean result which sets whether to display the context app or not. + +By default, Umbraco UI Builder will pre-filter context apps to only display on the tree it is defined in. This will be combined with the `SetVisibility` config to decide when to display the context app. + +### **SetVisibility(Func<ContextAppVisibilityContext, bool> visibilityExpression) : ContextAppConfigBuilder** + +Sets the context app visibility delegate. + +````csharp +// Example +contextAppConfig.SetVisibility(appCtx => appCtx.Source is IContent content && content.ContentType.Alias == "blogPost"); +```` + +## Adding a collection to a context app + +Context apps can consist of one or more collections. If a context app contains multiple collections, the collection list views will be displayed in tabs within the context app. + +### **AddCollection<TEntityType>(Lambda idFieldExpression, Lambda fkFieldExpression, string nameSingular, string namePlural, string description, Lambda collectionConfig = null) : ContextAppConfigBuilder** + +Adds a collection to the current content app with the given names, descriptions and default icons. An ID property accessor expression is required so that Umbraco UI Builder knows which property is the ID property. A foreign key property accessor is also required so that the Umbraco UI Builder knows which property holds the Umbraco nodes UDI value. You can read more about this in the [Collections documentation](../collections/overview.md). + +```csharp +// Example +contextAppConfig.AddCollection(p => p.Id, p=> "Comment", "Comments", "A collection of comments", collectionConfig => { + ... +}); +``` + +### **AddCollection<TEntityType>(Lambda idFieldExpression, Lambda fkFieldExpression, string nameSingular, string namePlural, string description, string iconSingular, string iconPlural, Lambda collectionConfig = null) : ContextAppConfigBuilder** + +Adds a collection to the current context app with the given names, description and icons. An ID property accessor expression is required so that Umbraco UI Builder knows which property is the ID property. A foreign key property accessor is also required so that Umbraco UI Builder knows which property holds the Umbraco nodes UDI value. You can read more about this in the [Collections documentation](../collections/overview.md). + +```csharp +// Example +contextAppConfig.AddCollection(p => p.Id, "Comment", "Comments", "A collection of comments", "icon-chat", "icon-chat", collectionConfig => { + ... +}); +``` diff --git a/15/umbraco-ui-builder/areas/dashboards.md b/15/umbraco-ui-builder/areas/dashboards.md new file mode 100644 index 00000000000..3a84ba959ff --- /dev/null +++ b/15/umbraco-ui-builder/areas/dashboards.md @@ -0,0 +1,103 @@ +--- +description: Configuring dashboards in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Dashboards + +A dashboard is a view that is displayed at the root of a section and contains welcome information. It also includes useful tools relevant to the given section. When there are multiple dashboards to display in a section these are presented in a tabbed layout to allow you to switch between the dashboards. + +![Dashboards](../images/dashboards.png) + +## Defining a dashboard + +You can define a dashboard by calling one of the `AddDashboard` methods on either a [`SectionConfigBuilder`](sections.md) or a [`WithSectionConfigBuilder`](sections.md#extending-an-existing-section) instance. + +### **AddDashboard(string name, Lambda dashboardConfig = null) : DashboardConfigBuilder** + +Adds a dashboard with the given name. + +```csharp +// Example +sectionConfig.AddDashboard("Team", dashboardConfig => { + ... +}); +``` + +### **AddDashboardBefore(string beforeAlias, string name, Lambda dashboardConfig = null) : DashboardConfigBuilder** + +Adds a dashboard with the given name **before** the dashboard with the given alias. + +```csharp +// Example +sectionConfig.AddDashboardBefore("contentIntro", "Team", dashboardConfig => { + ... +}); +``` + +### **AddDashboardAfter(string afterAlias, string name, Lambda dashboardConfig = null) : DashboardConfigBuilder** + +Adds a dashboard with the given name **after** the dashboard with the given alias. + +```csharp +// Example +sectionConfig.AddDashboardAfter("contentIntro", "Team", dashboardConfig => { + ... +}); +``` + +## Changing a dashboard alias + +### **SetAlias(string alias) : DashboardConfigBuilder** + +Sets the alias of the dashboard. + +**Optional:** When adding a new dashboard, an alias is automatically generated from the supplied name for you. However, if you need a specific alias you can use the `SetAlias` method to override this. + +```csharp +// Example +dashboardConfig.SetAlias("team"); +``` + +## Changing when a dashboard should display + +Changing when a dashboard is displayed is controlled via an inner config. Options on the inner config are `ShowForUserGroup` and `HideForUserGroup` to control the visibility of the dashboard for given user groups. You can call these config methods multiple times to add multiple role configurations. + +By default, will pre-filter dashboards to display only on the section it is defined in. This will be combined with the `SetVisibility` config to decide when to display the dashboard. + +### **SetVisibility(Lambda visibilityConfig) : DashboardConfigBuilder** + +Sets the dashboard visibility config. + +````csharp +// Example +dashboardConfig.SetVisibility(visibilityConfig => visibilityConfig + .ShowForUserGroup("admin") + .HideForUserGroup("translator") +); +```` + +## Setting the collection of a dashboard + +Dashboards are only able to display a single collection. If you need to display multiple collections, then you need to configure multiple dashboards. + +### **SetCollection<TEntityType>(Lambda idFieldExpression, string nameSingular, string namePlural, string description, Lambda collectionConfig = null) : ContextAppConfigBuilder** + +Sets the collection of the current dashboard with the given names, descriptions, and default icons. An ID property accessor expression is required so that Umbraco UI Builder knows which property is the ID property. For more information check the [Collections documentation](../collections/overview.md). + +```csharp +// Example +dashboardConfig.SetCollection(p => p.Id, p=> "Team Member", "Team Members", "A collection of team members", collectionConfig => { + ... +}); +``` + +### **SetCollection<TEntityType>(Lambda idFieldExpression, Lambda fkFieldExpression, string nameSingular, string namePlural, string description, string iconSingular, string iconPlural, Lambda collectionConfig = null) : ContextAppConfigBuilder** + +Sets the collection of the current dashboard with the given names, description and icons. An ID property accessor expression is required so that Umbraco UI Builder knows which property is the ID property. For more information check the [Collections documentation](../collections/overview.md). + +```csharp +// Example +dashboardConfig.SetCollection(p => p.Id, "Team Member", "Team Members", "A collection of team members", "icon-umm-user", "icon-umb-user", collectionConfig => { + ... +}); +``` diff --git a/15/umbraco-ui-builder/areas/folders.md b/15/umbraco-ui-builder/areas/folders.md new file mode 100644 index 00000000000..4f9017346fd --- /dev/null +++ b/15/umbraco-ui-builder/areas/folders.md @@ -0,0 +1,107 @@ +--- +description: Configuring folders to organise trees in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Folders + +A folder can appear in either a tree or as a sub folder to other folders. Folders can contain either other (sub)folders or [collections](../collections/overview.md). + +![Tree with Settings folder](../images/tree.png) + +## Defining a folder + +You can define a folder by calling one of the `AddFolder` methods on a given [`Tree`](trees.md) or parent `Folder` config builder instance. + +### **AddFolder(string name, Lambda folderConfig = null) : FolderConfigBuilder** + +Adds a folder to the current tree with the given name and a default folder icon. + +````csharp +// Example +treeConfig.AddFolder("Settings", folderConfig => { + ... +}); +```` + +### **AddFolder(string name, string icon, Lambda folderConfig = null) : FolderConfigBuilder** + +Adds a folder to the current tree with the given name + icon. + +````csharp +// Example +treeConfig.AddFolder("Settings", "icon-settings", folderConfig => { + ... +}); +```` + +## Changing a folder alias + +### **SetAlias(string alias) : FolderConfigBuilder** + +Sets the alias of the folder. + +**Optional:** When creating a new folder, an alias is automatically generated from the supplied name for you. However, if you need a specific alias you can use the `SetAlias` method to override this. + +````csharp +// Example +folderConfig.SetAlias("settings"); +```` + +## Changing a folder icon color + +### **SetIconColor(string color) : FolderConfigBuilder** + +Sets the folder icon color to the given color. The options that are possible are `black`, `green`, `yellow`, `orange`, `blue` or `red`. + +````csharp +// Example +folderConfig.SetIconColor("blue"); +```` + +## Adding a sub folder to a folder + +### **AddFolder (string name, Lambda folderConfig = null) : FolderConfigBuilder** + +Adds a sub folder to the current folder with the given name and a default folder icon. + +````csharp +// Example +folderConfig.AddFolder("Categories", subFolderConfig => { + ... +}); +```` + +### **AddFolder (string name, string icon, Lambda folderConfig = null) : FolderConfigBuilder** + +Adds a sub folder to the current folder with the given name + icon. + +````csharp +// Example +folderConfig.AddFolder("Categories", "icon-tags", subFolderConfig => { + ... +}); +```` + +## Adding a collection to a folder + +### **AddCollection<TEntityType>(Lambda idFieldExpression, string nameSingular, string namePlural, string description, Lambda collectionConfig = null) : CollectionConfigBuilder<TEntityType>** + +Adds a collection to the current folder with the given names, descriptions, and default icons. An ID property accessor expression is required so that Umbraco UI Builder knows which property is the ID property. For more information check the [Collections documentation](../collections/overview.md). + +````csharp +// Example +folderConfig.AddCollection(p => p.Id, "Person", "People", "A collection of people", collectionConfig => { + ... +}); +```` + +### **AddCollection<TEntityType>(Lambda idFieldExpression, string nameSingular, string namePlural, string description, string iconSingular, string iconPlural, Lambda collectionConfig = null) : CollectionConfigBuilder<TEntityType>** + +Adds a collection to the current folder with the given names, description and icons. An ID property accessor expression is required so that Umbraco UI Builder knows which property is the ID property. For more information check the [Collections documentation](../collections/overview.md). + +````csharp +// Example +folderConfig.AddCollection(p => p.Id, "Person", "People", "A collection of people", "icon-umb-users", "icon-umb-users", collectionConfig => { + ... +}); +```` diff --git a/15/umbraco-ui-builder/areas/overview.md b/15/umbraco-ui-builder/areas/overview.md new file mode 100644 index 00000000000..49e31b9031c --- /dev/null +++ b/15/umbraco-ui-builder/areas/overview.md @@ -0,0 +1,19 @@ +--- +description: Choosing an area to connect Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Areas + +There are different areas of the Umbraco UI that Umbraco UI Builder can be injected into. Before you get to managing your actual content you need to choose which area makes the most sense to present that data in. Then you can review how to go about configuring that particular type of area. + +Choose an area type from the list below to find out more. + +{% content-ref url="sections.md" %} +[sections.md](sections.md) +{% endcontent-ref %} +{% content-ref url="dashboards.md" %} +[dashboards.md](dashboards.md) +{% endcontent-ref %} +{% content-ref url="context-apps.md" %} +[context-apps.md](context-apps.md) +{% endcontent-ref %} diff --git a/15/umbraco-ui-builder/areas/sections.md b/15/umbraco-ui-builder/areas/sections.md new file mode 100644 index 00000000000..3ac357ad3d9 --- /dev/null +++ b/15/umbraco-ui-builder/areas/sections.md @@ -0,0 +1,203 @@ +--- +description: Configuring sections in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Sections + +A section is a distinct area of the Umbraco backoffice, such as content, media, etc. The section is accessed via a link in the main menu at the top of the Umbraco interface. Umbraco UI Builder allows you to define multiple sections in order to organise the management of your models into logical sections. + +![Sections](../images/sections.png) + +## Defining a section + +You can define a section by calling one of the `AddSection` methods on the root level `UIBuilderConfigBuilder` instance. + +### **AddSection(string name, Lambda sectionConfig = null) : SectionConfigBuilder** + +Adds a section to the Umbraco menu with the given name. + +```csharp +// Example +config.AddSection("Repositories", sectionConfig => { + ... +}); +``` + +### **AddSectionBefore(string beforeAlias, string name, Lambda sectionConfig = null) : SectionConfigBuilder** + +Adds a section to the Umbraco menu with the given name **before** the section with the given alias. + +```csharp +// Example +config.AddSectionBefore("settings", "Repositories", sectionConfig => { + ... +}); +``` + +### **AddSectionAfter(string afterAlias, string name, Lambda sectionConfig = null) : SectionConfigBuilder** + +Adds a section to the Umbraco menu with the given name **after** the section with the given alias. + +```csharp +// Example +config.AddSectionAfter("media", "Repositories", sectionConfig => { + ... +}); +``` + +## Changing a section alias + +### **SetAlias(string alias) : SectionConfigBuilder** + +Sets the alias of the section. + +**Optional:** When adding a new section, an alias is automatically generated from the supplied name for you. However, if you need a specific alias you can use the `SetAlias` method to override this. + +```csharp +// Example +sectionConfig.SetAlias("repositories"); +``` + +## Configuring the section tree + +### **Tree(Lambda treeConfig = null) : TreeConfigBuilder** + +Accesses the tree config of the current section. For more information check the [Trees documentation](trees.md). + +````csharp +// Example +sectionConfig.Tree(treeConfig => { + ... +}); +```` + +## Adding a dashboard to the section + +### **AddDashboard(string name, Lambda dashboardConfig = null) : DashboardConfigBuilder** + +Adds a dashboard with the given name. For more information check the [Dashboards documentation](dashboards.md). + +```csharp +// Example +sectionConfig.AddDashboard("Team", dashboardConfig => { + ... +}); +``` + +#### **AddDashboardBefore(string beforeAlias, string name, Lambda dashboardConfig = null) : DashboardConfigBuilder** + +Adds a dashboard with the given name **before** the dashboard with the given alias. For more information check the [Dashboards documentation](dashboards.md). + +```csharp +// Example +sectionConfig.AddDashboardBefore("contentIntro", "Team", dashboardConfig => { + ... +}); +``` + +#### **AddDashboardAfter(string afterAlias, string name, Lambda dashboardConfig = null) : DashboardConfigBuilder** + +Adds a dashboard with the given name **after** the dashboard with the given alias. For more information check the [Dashboards documentation](dashboards.md). + +```csharp +// Example +sectionConfig.AddDashboardAfter("contentIntro", "Team", dashboardConfig => { + ... +}); +``` + +## Extending an existing section + +You can extend existing sections by adding Umbraco UI Builder trees and dashboards, context apps, and virtual subtrees. This can be done by calling the `WithSection` method on the root level `UIBuilderConfigBuilder` instance. + +### **WithSection(string alias, Lambda sectionConfig = null) : WithSectionConfigBuilder** + +Starts a sub-configuration for the existing Umbraco section with the given alias. + +```csharp +// Example +config.WithSection("member", withSectionConfig => { + ... +}); +``` + +## Adding a tree to an existing section + +### **AddTree(string name, string icon, Lambda treeConfig = null) : TreeConfigBuilder** + +Adds a tree to the current section. For more information check the [Trees documentation](trees.md). + +````csharp +// Example +withSectionConfig.AddTree("My Tree", "icon-folder", treeConfig => { + ... +}); +```` + +#### **AddTree(string groupName, string name, string icon, Lambda treeConfig = null) : TreeConfigBuilder** + +Adds a tree to the current section in a group with the given name. For more information check the [Trees documentation](trees.md). + +````csharp +// Example +withSectionConfig.AddTree("My Group", "My Tree", "icon-folder", treeConfig => { + ... +}); +```` + +#### **AddTreeBefore(string treeAlias, string name, string icon, Lambda treeConfig = null) : TreeConfigBuilder** + +Adds a tree to the current section **before** the tree with the given alias. For more information check the [Trees documentation](trees.md). + +````csharp +// Example +withSectionConfig.AddTreeBefore("member", "My Tree", "icon-folder", treeConfig => { + ... +}); +```` + +#### **AddTreeAfter(string treeAlias, string name, string icon, Lambda treeConfig = null) : TreeConfigBuilder** + +Adds a tree to the current section **after** the tree with the given alias. For more information check the [Trees documentation](trees.md). + +````csharp +// Example +withSectionConfig.AddTreeAfter("member", "My Tree", "icon-folder", treeConfig => { + ... +}); +```` + +## Adding a dashboard to an existing section + +### **AddDashboard (string name, Lambda dashboardConfig = null) : DashboardConfigBuilder** + +Adds a dashboard with the given name. For more information check the [Dashboards documentation](dashboards.md). + +```csharp +// Example +withSectionConfig.AddDashboard("Team", dashboardConfig => { + ... +}); +``` + +### **AddDashboardBefore (string beforeAlias, string name, Lambda dashboardConfig = null) : DashboardConfigBuilder** + +Adds a dashboard with the given name **before** the dashboard with the given alias. For more information check the [Dashboards documentation](dashboards.md). + +```csharp +// Example +withSectionConfig.AddDashboardBefore("contentIntro", "Team", dashboardConfig => { + ... +}); +``` + +### **AddDashboardAfter (string afterAlias, string name, Lambda dashboardConfig = null) : DashboardConfigBuilder** + +Adds a dashboard with the given name **after** the dashboard with the given alias. For more information check the [Dashboards documentation](dashboards.md). + +```csharp +// Example +withSectionConfig.AddDashboardAfter("contentIntro", "Team", dashboardConfig => { + ... +}); +``` diff --git a/15/umbraco-ui-builder/areas/summary-dashboards.md b/15/umbraco-ui-builder/areas/summary-dashboards.md new file mode 100644 index 00000000000..c17dbb5bdb9 --- /dev/null +++ b/15/umbraco-ui-builder/areas/summary-dashboards.md @@ -0,0 +1,26 @@ +--- +description: Configuring a summary dashboard in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Summary Dashboards + +A summary dashboard is automatically displayed at the root of a defined Umbraco UI Builder section. It displays summaries of collections found within it that are told to display on the dashboard. It also provides quick links to jump to that collections list view. It can also add quickly a new entry to that collection (if the collection isn't read-only). + +![Summary Dashboard](../images/dashboard.png) + +## Showing a collection on a summary dashboard + +Showing a collection in the summary dashboard is controlled via the collection configuration. + +### **ShowOnSummaryDashboard() : CollectionConfigBuilder<TEntityType>** + +Sets the collection to display on the summary dashboard. + +````csharp +// Example +collectionConfig.ShowOnSummaryDashboard(); +```` + +{% hint style="warning" %} +Only section root level collections can be shown on the summary dashboard. +{% endhint %} diff --git a/15/umbraco-ui-builder/areas/trees.md b/15/umbraco-ui-builder/areas/trees.md new file mode 100644 index 00000000000..551f95bbc4d --- /dev/null +++ b/15/umbraco-ui-builder/areas/trees.md @@ -0,0 +1,235 @@ +--- +description: Configuring trees in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Trees + +A tree is a hierarchical structure that helps organize a section into logical sub-sections. A tree is accessed in the main side panel of the Umbraco interface. In Umbraco UI Builder, a section may only have a single tree definition. However, you can use folder nodes to help organize the tree structure as you need it. + +![Tree](../images/tree.png) + +## Configuring a Umbraco UI Builder section tree + +The tree configuration for Umbraco UI Builder sections is a sub-configuration of a [`Section`](sections.md) config builder instance and is accessed via its `Tree` method. + +### **Tree(Lambda treeConfig = null) : TreeConfigBuilder** + +Accesses the tree config of the given section. + +````csharp +// Example +sectionConfig.Tree(treeConfig => { + ... +}); +```` + +## Adding a tree to an existing section + +The tree configuration for existing sections is a sub-configuration of a [`WithSection`](sections.md#extending-an-existing-section) config builder instance and is accessed via one of its `AddTree` methods. + +### **AddTree(string name, string icon, Lambda treeConfig = null) : TreeConfigBuilder** + +Adds a tree to the current section. + +````csharp +// Example +withSectionConfig.AddTree("My Tree", "icon-folder", treeConfig => { + ... +}); +```` + +### **AddTree(string groupName, string name, string icon, Lambda treeConfig = null) : TreeConfigBuilder** + +Adds a tree to the current section in a group with the given name. + +````csharp +// Example +withSectionConfig.AddTree("My Group", "My Tree", "icon-folder", treeConfig => { + ... +}); +```` + +### **AddTreeBefore(string treeAlias, string name, string icon, Lambda treeConfig = null) : TreeConfigBuilder** + +Adds a tree to the current section **before** the tree with the given alias. + +````csharp +// Example +withSectionConfig.AddTreeBefore("member", "My Tree", "icon-folder", treeConfig => { + ... +}); +```` + +### **AddTreeAfter(string treeAlias, string name, string icon, Lambda treeConfig = null) : TreeConfigBuilder** + +Adds a tree to the current section **after** the tree with the given alias. + +````csharp +// Example +withSectionConfig.AddTreeAfter("member", "My Tree", "icon-folder", treeConfig => { + ... +}); +```` + +## Changing the tree icon color + +### **SetIconColor(string color) : TreeConfigBuilder** + +Sets the trees icon color to the given color. The options that are possible are `black`, `green`, `yellow`, `orange`, `blue` or `red`. + +{% hint style="warning" %} +Only trees added to existing sections have an icon. Trees added to Umbraco UI Builder sections don't show a tree icon instead they go straight into displaying the tree contents. +{% endhint %} + +````csharp +// Example +collectionConfig.SetIconColor("blue"); +```` + +## Adding a group to a tree + +### **AddGroup(string name, Lambda groupConfig = null) : GroupConfigBuilder** + +Adds a group to the current tree with the given name. + +{% hint style="warning" %} +Only Umbraco UI Builder section trees can configure groups, where trees added to existing sections cannot. +{% endhint %} + +```csharp +// Example +treeConfig.AddGroup("Settings", groupConfig => { + ... +}); +``` + +## Adding a folder to a tree/group + +### **AddFolder(string name, Lambda folderConfig = null) : FolderConfigBuilder** + +Adds a folder to the current tree/group with the given name and a default folder icon. For more information check the [Folders documentation](folders.md). + +```csharp +// Example +treeConfig.AddFolder("Settings", folderConfig => { + ... +}); +``` + +### **AddFolder(string name, string icon, Lambda folderConfig = null) : FolderConfigBuilder** + +Adds a folder to the current tree/group with the given name + icon. For more information check the [Folders documentation](folders.md). + +```csharp +// Example +treeConfig.AddFolder("Settings", "icon-settings", folderConfig => { + ... +}); +``` + +## Adding a collection to a tree/group + +### **AddCollection<TEntityType>(Lambda idFieldExpression, string nameSingular, string namePlural, string description, Lambda collectionConfig = null) : CollectionConfigBuilder<TEntityType>** + +Adds a collection to the current tree/group with the given names, descriptions, and default icons. An ID property accessor expression is required so that Umbraco UI Builder knows which property is the ID property. For more information check the [Collections documentation](../collections/overview.md). + +```csharp +// Example +treeConfig.AddCollection(p => p.Id, "Person", "People", "A collection of people", collectionConfig => { + ... +}); +``` + +#### **AddCollection<TEntityType>(Lambda idFieldExpression, string nameSingular, string namePlural, string description, string iconSingular, string iconPlural, Lambda collectionConfig = null) : CollectionConfigBuilder<TEntityType>** + +Adds a collection to the current tree/group with the given names, description and icons. An ID property accessor expression is required so that Umbraco UI Builder knows which property is the ID property. For more information check the [Collections documentation](../collections/overview.md). + +```csharp +// Example +treeConfig.AddCollection(p => p.Id, "Person", "People", "A collection of people", "icon-umb-users", "icon-umb-users", collectionConfig => { + ... +}); +``` + +## Extending an existing tree + +You can extend existing trees adding Umbraco UI Builder context apps and virtual sub trees by calling the `WithTree` method of a [`WithSectionConfigBuilder`](sections.md#extending-an-existing-section) instance. + +### **WithTree(string alias, Lambda treeConfig = null) : WithTreeConfigBuilder** + +Starts a sub-configuration for the existing Umbraco tree with the given alias. + +```csharp +// Example +sectionConfig.WithTree("content", withTreeConfig => { + ... +}); +``` + +## Adding a context app to an existing tree + +### **AddContextApp(string name, Lambda contextAppConfig = null) : ContextAppConfigBuilder** + +Adds a context app with the given name and default icon. For more information check the [Context App documentation](context-apps.md). + +```csharp +// Example +withTreeConfig.AddContextApp("Comments", contextAppConfig => { + ... +}); +``` + +### **AddContextApp(string name, string icon, Lambda contextAppConfig = null) : ContextAppConfigBuilder** + +Adds a context app to the Umbraco menu with the given name and icon. For more information check the [Context App documentation](context-apps.md). + +```csharp +// Example +withTreeConfig.AddContextApp("Comments", "icon-chat", contextAppConfig => { + ... +}); +``` + +### **AddContextAppBefore(string beforeAlias, string name, Lambda contextAppConfig = null) : ContextAppConfigBuilder** + +Adds a context app with the given name and default icon **before** the context app with the given alias. For more information check the [Context App documentation](context-apps.md). + +```csharp +// Example +withTreeConfig.AddContextAppBefore("umbContent", "Comments", contextAppConfig => { + ... +}); +``` + +### **AddContextAppBefore(string beforeAlias, string name, string icon, Lambda contextAppConfig = null) : ContextAppConfigBuilder** + +Adds a context app to the Umbraco menu with the given name and icon **before** the context app with the given alias. For more information check the [Context App documentation](context-apps.md). + +```csharp +// Example +withTreeConfig.AddContextAppBefore("umbContent", "Comments", "icon-chat", contextAppConfig => { + ... +}); +``` + +### **AddContextAppAfter(string afterAlias, string name, Lambda contextAppConfig = null) : ContextAppConfigBuilder** + +Adds a context app with the given name and default icon **after** the context app with the given alias. For more information check the [Context App documentation](context-apps.md). + +```csharp +// Example +withTreeConfig.AddContextAppAfter("umbContent", "Comments", contextAppConfig => { + ... +}); +``` + +### **AddContextAppAfter(string afterAlias, string name, string icon, Lambda contextAppConfig = null) : ContextAppConfigBuilder** + +Adds a context app to the Umbraco menu with the given name and icon **after** the context app with the given alias. For more information check the [Context App documentation](context-apps.md). + +```csharp +// Example +withTreeConfig.AddContextAppAfter("umbContent", "Comments", "icon-chat", contextAppConfig => { + ... +}); +``` diff --git a/15/umbraco-ui-builder/cards/count-cards.md b/15/umbraco-ui-builder/cards/count-cards.md new file mode 100644 index 00000000000..57830b0be1c --- /dev/null +++ b/15/umbraco-ui-builder/cards/count-cards.md @@ -0,0 +1,68 @@ +--- +description: Configuring count cards in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Count Cards + +Count cards allow you to define cards directly against the [collection](../collections/overview.md) configuration, providing a basic **where clause** to use in a count SQL statement. These work perfectly for basic data visualizations based on counts of entities in a collection. + +If you need to do more than a basic count, you'll want to take a look at the [custom cards](custom-cards.md) documentation. + +## Adding a count card to a collection + +Cards allow you to display basic summaries of key information that may be useful to the editor. + +### **AddCard(string name, Lambda whereClauseExpression, Lambda cardConfig = null) : CardConfigBuilder** + +Adds a card with the given name and **where clause** filter expression. Expression must be a `boolean` expression. + +````csharp +// Example +collectionConfig.AddCard("Older than 30", p => p.Age > 30, cardConfig => { + ... +}); +```` + +### **AddCard(string name, string icon, Lambda whereClauseExpression, Lambda cardConfig = null) : CardConfigBuilder** + +Adds a card with the given name + icon and **where clause** filter expression. Expression must be a `boolean` expression. + +````csharp +// Example +collectionConfig.AddCard("Older than 30", "icon-umb-users", p => p.Age > 30, cardConfig => { + ... +}); +```` + +### Change the color of a count card + +#### **SetColor(string color) : CardConfigBuilder** + +Sets the color of the card. + +````csharp +// Example +cardConfig.SetColor("blue"); +```` + +### Add a suffix to a count value + +#### **SetSuffix(string suffix) : CardConfigBuilder** + +Sets the suffix of the card value. + +````csharp +// Example +cardConfig.SetSuffix("years"); +```` + +### Formatting the value of a count + +#### **SetFormat(Lambda formatExpression) : CardConfigBuilder** + +Sets the format expression for the card. + +````csharp +// Example +cardConfig.SetFormat((v) => $"{v}%"); +```` diff --git a/15/umbraco-ui-builder/cards/custom-cards.md b/15/umbraco-ui-builder/cards/custom-cards.md new file mode 100644 index 00000000000..0cbec414a86 --- /dev/null +++ b/15/umbraco-ui-builder/cards/custom-cards.md @@ -0,0 +1,62 @@ +--- +description: Configuring custom cards in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Custom Cards + +Custom cards allow you to perform more complex metric calculations and are defined via a class implementing the `Card` base class. + +When Umbraco UI Builder resolves a card it will attempt to do so from the global DI container. This means you can inject any dependencies that you require for your card to calculate its value. If there is no type defined in the DI container, Umbraco UI Builder will fall-back to manually instantiating a new instance of value mapper. + +## Defining a custom card + +To define a card you create a class that inherits from the base class `Card` and configure it within the constructor like so. + +````csharp +// Example +public class AvgPersonAgeCard : Card +{ + public override string Alias => "avgPersonAge"; + public override string Name => "Average Age"; + public override string Icon => "icon-calendar"; + public override string Color => "green"; + public override string Suffix => "yrs"; + + public override object GetValue(object parentId = null) + { + // Perform value calculation logic + } +} +```` + +The required configuration options are: + +* **Name:** The name of the card. +* **Alias:** A unique alias for the card. +* **GetValue(object parentId = null):** A method to get the cards value. + +Additional optional configuration options are: + +* **Icon:** An icon to display in the card. +* **Color:** The color of the card. +* **Suffix:** A suffix to display after the card value. + +## Adding a custom card to a collection + +### **AddCard() : CollectionConfigBuilder<TEntityType>** + +Adds a card of the given type to the collection. + +````csharp +// Example +collectionConfig.AddCard(); +```` + +### **AddCard(Type cardType) : CollectionConfigBuilder<TEntityType>** + +Adds a card of the given type to the collection. + +````csharp +// Example +collectionConfig.AddCard(typeof(AvgPersonAgeCard)); +```` diff --git a/15/umbraco-ui-builder/cards/overview.md b/15/umbraco-ui-builder/cards/overview.md new file mode 100644 index 00000000000..35b687e3e60 --- /dev/null +++ b/15/umbraco-ui-builder/cards/overview.md @@ -0,0 +1,19 @@ +--- +description: Configuring cards in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Cards + +Cards provide an API to display basic summary information in a card-based format and are useful for displaying key metrics about a collection. + +![Cards](../images/cards.png) + +Cards can be defined in one of two ways: + +{% content-ref url="count-cards.md" %} +[Count Cards](count-cards.md) +{% endcontent-ref %} + +{% content-ref url="custom-cards.md" %} +[Custom Cards](custom-cards.md) +{% endcontent-ref %} diff --git a/15/umbraco-ui-builder/changelog-archive/changelog.md b/15/umbraco-ui-builder/changelog-archive/changelog.md new file mode 100644 index 00000000000..82b8c320984 --- /dev/null +++ b/15/umbraco-ui-builder/changelog-archive/changelog.md @@ -0,0 +1,180 @@ +--- +description: Changelog for Konstrukt, the backoffice UI builder for Umbraco. +--- + +# Changelog + +## v1.6.4 + +**Date:** 2023-02-22 +**Description:** Patch release with bug fixes + +- Fixed issue where upload file property editor throws "the specified file type has been disallowed by the administrator" error ([#49](https://github.com/outfielddigital/konstrukt/issues/49)). +- Added ngrok URLs to allow domains that don't need a license. + +## v1.6.3 + +**Date:** 2023-01-16 +**Description:** Patch release with bug fixes + +- Moved encrypted properties implementation to the base repository class so encryption is honored when performing save/load operation directly against the repository API ([#44](https://github.com/outfielddigital/konstrukt/issues/44)). +- Made `SecurityHelper` swappable so you can use something other than the default `DataProtectionProvider` implementation that comes out of the box (OOTB). +- Fixed issue with advanced filters that use the lambda `ParameterReplacer` due to the parameter being replaced in the function, but not in the Lambda parameters list ([#45](https://github.com/outfielddigital/konstrukt/issues/45)). +- Fixed date filters not working on mobile resolution devices ([#46](https://github.com/outfielddigital/konstrukt/issues/46)). + +## v1.6.2 + +**Date:** 2022-12-01 +**Description:** Patch release with bug fixes + +- Added marketplace updates. +- Update the Konstrukt type finder to use a non-obsolete constructor. +- Updated to use `IComposer` instead of `IUserComposer` as the latter has been removed in v11. +- Fixed parent ID not being passed to create dialog for associated entities. +- Removed settings section restriction on the licensing info endpoint as it would cause errors when the licensing banner is shown in other sections. + +## v1.6.1 + +**Date:** 2022-10-11 +**Description:** Patch release with bug fixes + +- Fixed issue when running on Azure where the DB provider name reverts to `System.Data.SqlClient` when it should be `Microsoft.Data.SqlClient` + +## v1.6.0 + +**Date:** 2022-09-30 +**Description:** Minor release with additional features + +- Added a Save action type to display actions as a sub-button in an entities Save button (similar to the "Save and Publish" button in the content section). + +## v1.5.2 + +**Date:** 2022-09-09 +**Description:** Patch release with bug fixes + +- Fixed bug in entity picker not correctly showing the `Add` button when it should ([#39](https://github.com/outfielddigital/konstrukt/issues/39)). +- Added some basic validation to config at startup to ensure a valid config model. + +## v1.5.1 + +**Date:** 2022-08-22 +**Description:** Patch release with bug fixes + +- Fixed searchable properties not being searched in a case-insensitive way for repositories that don't use Umbraco's NPoco extension methods ([#36](https://github.com/outfielddigital/konstrukt/issues/36)). +- Fixed regression in Konstrukt repository not correctly combining filters. +- Fixed exception due to `ServiceProvider` not getting passed to Data transfer object (DTO) mapper. + +## v1.5.0 + +**Date:** 2022-08-18 +**Description:** Minor release with additional features and bug fixes + +- Added ability to control collection visibility in the section tree at runtime. +- Added ability to control collection create, update, and delete permissions at runtime. +- Added ability to control list view field visibility at runtime. +- Added ability to control editor tab visibility at runtime. +- Added ability to control editor fieldset visibility at runtime. +- Added ability to control editor field visibility at runtime. +- Added ability to control whether an editor field is read-only or not at runtime. +- Added the ability to add custom dashboards to Konstrukt sections. +- Added child collections support to dashboard collections. +- Updated Konstrukt API to null check sections/collections first and throw exceptions if not found. +- Updated based repositories to automatically implement filtering for configurable options. +- Updated the summary dashboard to not display if there are no collections configured to show on it. +- Fixed bug where entity service would silently fail if it couldn't retrieve an entity. Now throws an exception. +- Fixed bug where content app factory would throw an exception when run in sections where the section entity was not `IUmbracoEntity`. + +## v1.4.0 + +**Date:** 2022-07-12 +**Description:** Minor release with additional features and bug fixes + +- Added [`WithSection`](../areas/sections.md#extending-an-existing-section) / [`WithTree`](../areas/trees.md#extending-an-existing-tree) API to create more logical API groupings and to set context for some APIs. +- Added [`AddTree`](../areas/trees.md#adding-a-tree-to-an-existing-section) support to allow adding a tree to an existing section (currently only able to add 1 Konstrukt tree per section). +- Added [Tree Group](../areas/trees.md#adding-a-group-to-a-tree) support to allow grouping root-level tree folders/collections. +- Added [Tab Sidebar](../collections/editors.md#configuring-a-sidebar-to-a-tab) support to allow showing metadata on the right-hand side of the editor. +- Added file upload support to the actions dialog +- Added a basic [Comma-separated values (CSV) Import](../actions/inbuilt-actions.md#konstruktimportentityaction) action +- Added [`HideLabel`](../collections/editors.md#hiding-the-label-of-a-field) support to editor fields to explicitly hide the label. +- Added explicit Insert / Update methods to IKonstruktRepository. Internally we use these now instead of the Save method as the Save method isn't reliably able to determine if an entity is new. +- Added better support for transient / scoped repository dependencies (example: better support for EF Core DB contexts which are by default registered as scoped) +- Obsoleted root-level APIs for `AddSection`, `AddDashboard` and `AddVirtualSubTree` which have now moved to sub-configurations of the [`WithSection`](../areas/sections.md#extending-an-existing-section) or [`WithTree`](../areas/trees.md#extending-an-existing-tree) APIs. +- Fixed bug with DataViews resolving the wrong filter when using groups and the data view has the same name as a view in a different group. We now prefix the data view alias with the group name to ensure uniqueness across groups. +- Fixed bug in child collections creating dialog thinking it was always editing an existing entity and so wrongfully trying to load an entity from the DB due to the fact the entity ID passed through to the dialog "0" when it should be "-1". + +## v1.3.0 + +**Date:** 2022-07-06 +**Description:** Minor release with additional features and bug fixes + +- Added [Virtual Sub Trees](../advanced/virtual-sub-trees.md) support +- Fixed save/delete notification events being passed the wrong model +- Fixed bug where connection strings with no provider cause an error + +## v1.2.0 + +**Date:** 2022-06-20 +**Description:** Minor release with some breaking changes / additional features + +- Added `DeletedProperty` support where the column type is an `int`, and the value is a unix timestamp +- Fixed bug with encrypted properties not handling `null` values +- **[Breaking]** - Updated minimum Umbraco dependency to v10 +- **[Breaking]** - Updated UI assets to be a (RCL) Razor Compiled Library. **Be sure to clean your solution to remove old files**. + +## v1.1.1 + +**Date:** 2022-06-08 +**Description:** Minor patch release with non-breaking changes + +- Added client-side required / regex validation support +- Added support for nullable types when mapping property filters +- Added support for passing notification messages back from action results +- Fixed SQL escaping issue when using table names with schema prefix +- Fixed a bug in range property filters when a value is `null` +- Fixed a bug where save operations would show a success notification even if the save operation failed +- Fixed a bug in Data Attribute validation where `IServiceProvider` wasn't being passed through +- Fixed `null` error when searching returns no items +- Fixed deleted property filter condition not working +- Fixed bug where encrypted properties would throw an exception if the value was `null` + +## v1.1.0 + +**Date:** 2022-05-03 +**Description:** Minor release with some breaking changes / additional features + +- Added field views support for custom field markup in list views +- Added new consistent actions API +- Added row actions support +- Added filterable properties support +- Fixed entity picker value converter not working +- Fixed JS error when editing content due to bad null checking in the Konstrukt `redirectId` interceptor +- Deprecated List View Layout support +- **[Breaking]** - Obsoleted bulk actions and menu items in favour of new actions API +- **[Breaking]** - Moved actions, data views and cards configuration out of list views onto collections API + +## v1.0.2 + +**Date:** 2022-04-11 +**Description:** Minor patch release with non-breaking changes + +- Fixed OrderBy not handling name field correctly +- Updated license warning to only display if the number of "editable" collections is exceeded +- Fixed custom connection strings not working by implementing a DB factory pattern +- Introduced `IKonstruktNodeUdiResolver` to allow content apps to resolve a different node UDI than the current page +- Fixed error being thrown by menu actions because the current section wasn't being passed through to the menu + +## v1.0.1 + +**Date:** 2022-01-27 +**Description:** Minor patch release with non-breaking changes + +- Fixed bug where section/tree registration can sometimes occur twice resulting in an error. +- Removed licensing header when using a single collection. +- Fixed bug with `ORDER BY 1` causing SQL exceptions + +## v1.0.0 + +**Date:** 2022-01-20 +**Description:** Major new release + +- Initial release diff --git a/15/umbraco-ui-builder/collections/child-collection-groups.md b/15/umbraco-ui-builder/collections/child-collection-groups.md new file mode 100644 index 00000000000..6d5b79cebcd --- /dev/null +++ b/15/umbraco-ui-builder/collections/child-collection-groups.md @@ -0,0 +1,39 @@ +--- +description: Configuring child collection groups in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Child Collection Groups + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +A child collection group is a container for other child collections. Its purpose is mainly to provide a logical grouping of multiple child collections to help with organization and an improved user experience. + +![Child Collection Groups](../images/child_collection_groups.png) + +## Defining a child collection group + +You can define a child collection group by calling one of the `AddChildCollectionGroup` methods on a given collection config builder instance. + +### **AddChildCollectionGroup(string name, Lambda childCollectionGroupConfig = null) : ChildCollectionGroupConfigBuilder** + +Adds a child collection group to the current collection with the given name and default icon. + +```csharp +// Example +collectionConfig.AddChildCollectionGroup("Family", childCollectionGroupConfig => { + ... +}); +``` + +### **AddChildCollectionGroup(string name, string icon, Lambda childCollectionGroupConfig = null) : ChildCollectionGroupConfigBuilder** + +Adds a child collection group to the current collection with the given name and icon. + +```csharp +// Example +collectionConfig.AddChildCollectionGroup("Family", "icon-users", childCollectionGroupConfig => { + ... +}); +``` diff --git a/15/umbraco-ui-builder/collections/child-collections.md b/15/umbraco-ui-builder/collections/child-collections.md new file mode 100644 index 00000000000..2672706c01f --- /dev/null +++ b/15/umbraco-ui-builder/collections/child-collections.md @@ -0,0 +1,47 @@ +--- +description: Configuring child collections in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Child Collections + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +A child collection is a container for a given data model that is tied to a parent collection data model. It shares all of the [Collections](the-basics.md) config builder API except child collections cannot contain further child collections. + +![Child Collections](../images/child_collections.png) + +{% hint style="info" %} +**Child Collections UI:** By default, child collections will be presented in the UI as context apps in the parent models editor view. If you have multiple child collections that make the context apps area overpopulated, you can use the [Child Collection Groups API](child-collection-groups.md). By using this you can group child collections under a single context app with the inner child collections then being presented in tabs. +{% endhint %} + +## Defining a child collection + +You define a child collection by calling one of the `AddChildCollection` methods on a given collection config builder instance. + +### **AddChildCollection<TChildEntityType>(Lambda idFieldExpression, Lambda fkFieldExpression, string nameSingular, string namePlural, string description, Lambda childCollectionConfig = null) : ChildCollectionConfigBuilder<TEntityType>** + +Adds a child collection to the current collection with the given names and description and default icons. A property accessor expression is required for both the entity ID field and FK (Foreign Key) field of the entity. + +```csharp +// Example +collectionConfig.AddChildCollection(c => c.Id, c => c.ParentId, "Child", "Children", "A collection of children", childCollectionConfig => { + ... +}); +``` + +### **AddChildCollection<TChildEntityType>(Lambda idFieldExpression, Lambda fkFieldExpression, string nameSingular, string namePlural, string description, string iconSingular, string iconPlural, Lambda childCollectionConfig = null) : ChildCollectionConfigBuilder<TEntityType>** + +Adds a child collection to the current collection with the given names, description and icons. A property accessor expression is required for both the entity ID field and FK (Foreign Key) field of the entity. + +```csharp +// Example +collectionConfig.AddChildCollection(c => c.Id, c => c.ParentId, "Child", "Children", "A collection of children", "icon-umb-users", "icon-umb-users", childCollectionConfig => { + ... +}); +``` + +## Configuring a child collection + +Child collections share the same API as the `Collection` config builder API, except child collections cannot contain further child collections. For more information check the [core collections documentation](the-basics.md). diff --git a/15/umbraco-ui-builder/collections/editors.md b/15/umbraco-ui-builder/collections/editors.md new file mode 100644 index 00000000000..204ded86981 --- /dev/null +++ b/15/umbraco-ui-builder/collections/editors.md @@ -0,0 +1,268 @@ +--- +description: Configuring the editor of a collection in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Editors + +An editor is the user interface used to edit an entity and is made up of tabs and property editors. + +![A collection editor](../images/editor.png) + +## Configuring an editor + +The editor configuration is a sub-configuration of a [`Collection`](the-basics.md) config builder instance and is accessed via its `Editor` method. + +### **Editor(Lambda editorConfig = null) : EditorConfig<TEntityType>** + +Accesses the editor config of the given collection. + +````csharp +// Example +collectionConfig.Editor(editorConfig => { + ... +}); +```` + +## Adding a tab to an editor + +### **AddTab(string name, Lambda tabConfig = null) : EditorTabConfigBuilder<TEntityType>** + +Adds a tab to the editor. + +````csharp +// Example +editorConfig.AddTab("General", tabConfig => { + ... +}); +```` + +## Configuring a sidebar to a tab + +A slidebar is a smaller area that is displayed to the right of the main editor. The sidebar can also contain fieldsets and fields in the same way tabs can. However, it is a much more limited display area so you'll need to choose your field types carefully. The sidebar is a great location to display entity metadata. + +### **Sidebar(Lambda sidebarConfig = null) : EditorTabSidebarConfigBuilder<TEntityType>** + +Configures the sidebar for the tab. + +````csharp +// Example +tabConfig.Sidebar(sidebarConfig => { + ... +}); +```` + +## Setting the visibility of a tab + +### **SetVisibility(Predicate<EditorTabVisibilityContext> visibilityExpression) : EditorTabConfigBuilder<TEntityType>** + +Sets the runtime visibility of the tab. + +````csharp +// Example +tabConfig.SetVisibility(ctx => ctx.EditorMode == EditorMode.Create); +```` + +## Adding a fieldset to a tab + +### **AddFieldset(string name, Lambda fieldsetConfig = null) : EditorFieldsetConfigBuilder<TEntityType>** + +Adds the given fieldset to the tab. + +````csharp +// Example +tabConfig.AddFieldset("Contact", fieldsetConfig => { + ... +}); +```` + +## Setting the visibility of a fieldset + +### **SetVisibility(Predicate<EditorFieldsetVisibilityContext> visibilityExpression) : EditorFieldsetConfigBuilder<TEntityType>** + +Sets the runtime visibility of the fieldset. + +````csharp +// Example +fieldsetConfig.SetVisibility(ctx => ctx.EditorMode == EditorMode.Create); +```` + +## Adding a field to a fieldset + +### **AddField(Lambda propertyExpression, Lambda propertyConfig = null) : EditorFieldConfigBuilder<TEntityType, TValueType>** + +Adds the given property to the editor. + +````csharp +// Example +fieldsetConfig.AddField(p => p.FirstName, fieldConfig => { + ... +}); +```` + +## Changing the label of a field + +By default, Umbraco UI Builder will build the label from the property name, including splitting camel case names into sentence cases. However, you can set an explicit label if preferred. + +### **SetLabel(string label) : EditorFieldConfigBuilder<TEntityType, TValueType>** + +Sets the label for the editor field. + +````csharp +// Example +fieldConfig.SetLabel("First Name"); +```` + +## Hiding the label of a field + +Sometimes you may have a field editor that would work better in full width. You can achieve this by explicitly hiding the field label. + +### **HideLabel() : EditorFieldConfigBuilder<TEntityType, TValueType>** + +Hides the label for the editor field. + +````csharp +// Example +fieldConfig.HideLabel(); +```` + +## Adding a description to a field + +### **SetDescription(string description) : EditorFieldConfigBuilder<TEntityType, TValueType>** + +Sets the description for the editor field. + +````csharp +// Example +fieldConfig.SetDescription("Enter your age in years"); +```` + +## Changing the Data Type of a field + +By default, Umbraco UI Builder will automatically choose a relevant Data Type for basic field types. However, if you wish to use an alternative Data Type then you can override this. + +### **SetDataType(string dataTypeName) : EditorFieldConfigBuilder<TEntityType, TValueType>** + +Set the Data Type of the current field to the Umbraco Data Type with the given name. + +````csharp +// Example +fieldConfig.SetDataType("Richtext Editor"); +```` + +### **SetDataType(int dataTypeId) : EditorFieldConfigBuilder<TEntityType, TValueType>** + +Set the Data Type of the current field to the Umbraco Data Type with the given id. + +````csharp +// Example +fieldConfig.SetDataType(-88); +```` + +## Setting the default value of a field + +### **SetDefaultValue(TValueType defaultValue) : EditorFieldConfigBuilder<TEntityType, TValueType>** + +Sets the default value to a known constant. + +````csharp +// Example +fieldConfig.SetDefaultValue(10); +```` + +### **SetDefaultValue(Func defaultValueFunc) : EditorFieldConfigBuilder<TEntityType, TValueType>** + +Sets the default value via a function that gets evaluated at time of entity creation. + +````csharp +// Example +fieldConfig.SetDefaultValue(() => DateTime.Now); +```` + +## Making a field required + +### **MakeRequired() : EditorFieldConfigBuilder<TEntityType, TValueType>** + +Makes the given field required. + +````csharp +// Example +fieldConfig.MakeRequired(); +```` + +## Validating a field + +### **SetValidationRegex(string regex) : EditorFieldConfigBuilder<TEntityType, TValueType>** + +Defines the regular expression to use when validating the field. + +````csharp +// Example +fieldConfig.SetValidationRegex("[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}"); +```` + +## Making a field read-only + +### **MakeReadOnly() : EditorFieldConfigBuilder<TEntityType, TValueType>** + +Makes the current field read-only disabling editing in the UI. + +````csharp +// Example +fieldConfig.MakeReadOnly(); +```` + +### **MakeReadOnly(Func<TValueType, string> format) : EditorFieldConfigBuilder<TEntityType, TValueType>** + +Makes the current field read-only disabling editing in the UI. Provides a custom formatting expression to use when rendering the value as a string. + +````csharp +// Example +fieldConfig.MakeReadOnly(distanceProp => $"{distanceProp:## 'km'}"); +```` + +### **MakeReadOnly(object dataTypeNameOrId) : EditorFieldConfigBuilder<TEntityType, TValueType>** + +Makes the current field read-only disabling editing in the UI. Provides the name or id of a datatype to use when in read-only mode. + +````csharp +// Example +fieldConfig.MakeReadOnly("myReadOnlyEditor"); +```` + +### **MakeReadOnly(Predicate<EditorFieldReadOnlyContext> readOnlyExp) : EditorFieldConfigBuilder<TEntityType, TValueType>** + +Makes the current field read-only disabling editing in the UI if the given runtime predicate is true. + +````csharp +// Example +fieldConfig.MakeReadOnly(ctx => ctx.EditorMode == EditorMode.Create); +```` + +### **MakeReadOnly(Predicate<EditorFieldReadOnlyContext> readOnlyExp, Func<TValueType, string> format) : EditorFieldConfigBuilder<TEntityType, TValueType>** + +Makes the current field read-only disabling editing in the UI if the given runtime predicate is true. Provides a custom formatting expression to use when rendering the value as a string. + +````csharp +// Example +fieldConfig.MakeReadOnly(ctx => ctx.EditorMode == EditorMode.Create, distanceProp => $"{distanceProp:## 'km'}"); +```` + +### **MakeReadOnly(Predicate<EditorFieldReadOnlyContext> readOnlyExp, object dataTypeNameOrId) : EditorFieldConfigBuilder<TEntityType, TValueType>** + +Makes the current field read-only disabling editing in the UI if the given runtime predicate is true. Provides the name or id of a datatype to use when in read-only mode. + +````csharp +// Example +fieldConfig.MakeReadOnly(ctx => ctx.EditorMode == EditorMode.Create, "myReadOnlyEditor"); +```` + +## Setting the visibility of a field + +### **SetVisibility(Predicate<EditorFieldVisibilityContext> visibilityExpression) : EditorFieldConfigBuilder<TEntityType, TValueType>** + +Sets the runtime visibility of the field. + +````csharp +// Example +fieldConfig.SetVisibility(ctx => ctx.EditorMode == EditorMode.Create); +```` diff --git a/15/umbraco-ui-builder/collections/field-views.md b/15/umbraco-ui-builder/collections/field-views.md new file mode 100644 index 00000000000..59a4cd4687a --- /dev/null +++ b/15/umbraco-ui-builder/collections/field-views.md @@ -0,0 +1,68 @@ +--- +description: Configuring field views in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Field Views + +Field Views allow you to customize the markup used by a field when displayed in a list view. Field Views are implemented as .NET Core View Components that are passed a single `FieldViewsContext` argument with information about the entity/field being rendered. + +## Defining a field view + +You can define a field view in one of two ways. + +### **1. A basic view file for the built in `FieldView` view component** + +The simplest way to define a field view for non-complex fields is to place a view file in the `/Views/Shared/Components/FieldView` folder with the following markup. + +````csharp +@model Umbraco.UIBuilder.Web.Models.FieldViewContext + +```` + +When registering a basic file view you can pass the name of the view file (excluding the `.cshtml` file extension) to the relevant API method. + +### **2. A complete custom view component** + +To define a more complex field view you can create your own view component class (which can use dependency injection for any required dependencies). This can be done by using the following signature: + +````csharp +// Example +public class MyComplexFieldViewViewComponent : ViewComponent +{ + public async Task InvokeAsync(FieldViewContext context) + { + // Do your custom logic here + + return View("Default", model); + } +} +```` + +{% hint style="info" %} +It's important to know that the `FieldViewContext` parameter to the `InvokeAsync` method **MUST** be named `context`. +{% endhint %} + +For the view element of your component, based on the example above, you would place a file `Default.cshtml` into the `/Views/Shared/Components/MyComplexFieldView` folder with the following markup: + +````csharp +@model Namespace.Of.Model.Returned.By.Custom.ViewComponent + +```` + +## The field view context + +Field view components are passed a `FieldViewContext` object with the following information: + +````csharp +public class FieldViewContext +{ + public string ViewName { get; set; } + public object Entity { get; set; } + public string PropertyName { get; set; } + public object PropertyValue { get; set; } +} +```` + +## Setting the field view of a list view field + +A field view is assigned to a list view field as part of the list view configuration. For more information you can check the [List View Documentation](list-views.md#setting-the-view-of-a-field). diff --git a/15/umbraco-ui-builder/collections/list-view-layouts.md b/15/umbraco-ui-builder/collections/list-view-layouts.md new file mode 100644 index 00000000000..f37338992f0 --- /dev/null +++ b/15/umbraco-ui-builder/collections/list-view-layouts.md @@ -0,0 +1,50 @@ +--- +description: Configuring list view layouts in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# List View Layouts + +{% hint style="danger" %} +**List View Layouts** in Umbraco UI Builder are now considered deprecated. Moving forward, only the table list view will be supported. Whilst you can continue to use this feature for the time being, it will be removed in a future release. +{% endhint %} + +List view layouts allow you to provide custom angular views to be used by the list view UI. By default, there are two built-in layouts, `TableListViewLayout` which displays results in a tabular layout, and `GridListViewLayout` which displays results in a tiled grid layout. + +## Defining a list view layout + +To define a list view layout you create a class that inherits from the base class `ListViewLayout` and implements the abstract configuration properties. + +````csharp +// Example +public class MyCustomListViewLayout : ListViewLayout +{ + public GridListViewLayout() + { + Name = "My Custom List"; + Alias = "my-custom-list"; + Icon = "icon-list"; + View = "/app_plugins/myplugin/views/mycustomlist.htm"; + } +} +```` + +The required configuration options are: + +* **Name:** The name of the layout. +* **Alias:** A unique alias for the layout. +* **Icon:** An icon to display in the list view layouts dropdown. +* **View:** The path of the angular view to load by the list view. + +As well as defining the list view layout class you will also need to implement the relevant angular view and controller. This is a little out of scope for the Umbraco UI Builder documentation, however in summary you will need to: + +* Create a plugin folder in the root `App_Plugin` folder. +* Create a `package.manifest` file in your plugin folder. +* Create a HTML view to be loaded. +* Create an angular controller to control the view. +* Hook up the controller with the view using the `ng-controller` attribute. +* Add the controller JS file path to the `package.manifest`. +* Build your custom logic. + +## Changing the list view layout of a list view + +A list view layout is assigned to a list view as part of the list view configuration. For more information you can check the [List View API Documentation](list-views.md#changing-the-list-view-layout). diff --git a/15/umbraco-ui-builder/collections/list-views.md b/15/umbraco-ui-builder/collections/list-views.md new file mode 100644 index 00000000000..2f237a41e54 --- /dev/null +++ b/15/umbraco-ui-builder/collections/list-views.md @@ -0,0 +1,103 @@ +--- +description: Configuring the list view of a collection in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# List Views + +A list view is a list-based view of a collection entity providing features: pagination for large collections, custom data views, searching, and bulk actions. + +![A collection list view](../images/listview.png) + +## Configuring a list view + +The list view configuration is a sub-configuration of a [`Collection`](the-basics.md) config builder instance and is accessed via its `ListView` method. + +### **ListView(Lambda listViewConfig = null) : ListViewConfigBuilder<TEntityType>** + +Accesses the list view config of the given collection. + +````csharp +// Example +collectionConfig.ListView(listViewConfig => { + ... +}); +```` + +## Adding a field to the list view + +### **AddField(Lambda propertyExpression, Lambda fieldConfig = null) : ListViewFieldConfigBuilder<TEntityType, TValueType>** + +Adds the given property to the list view. + +````csharp +// Example +listViewConfig.AddField(p => p.FirstName, fieldConfig => { + ... +}); +```` + +## Changing the heading of a field + +### **SetHeading(string heading) : ListViewFieldConfigBuilder<TEntityType, TValueType>** + +Sets the heading for the list view field. + +````csharp +// Example +fieldConfig.SetHeading("First Name"); +```` + +## Formatting the value of a field + +### **SetFormat(Lambda formatExpression) : ListViewFieldConfigBuilder<TEntityType, TValueType>** + +Sets the format expression for the list view field. + +````csharp +// Example +fieldConfig.SetFormat((v, p) => $"{v} years old"); +```` + +## Setting the view of a field + +With field views, you can customize the markup the list view's field so you can show richer visualizations of the field's content. For more information you can check the [Field Views Documentation](field-views.md). + +### **SetView(string viewComponentName) : ListViewFieldConfigBuilder<TEntityType, TValueType>** + +Sets the view component for the list view field. + +````csharp +// Example +fieldConfig.SetView("ImageFieldView"); +```` + +### **SetView<TView>() : ListViewFieldConfigBuilder<TEntityType, TValueType>** + +Sets the view component for the list view field. + +````csharp +// Example +fieldConfig.SetView(); +```` + +## Setting the visibility of a field + +### **SetVisibility(Predicate<ListViewFieldVisibilityContext> visibilityExpression) : ListViewFieldConfigBuilder<TEntityType, TValueType>** + +Sets the runtime visibility of the list view field. + +````csharp +// Example +fieldConfig.SetVisibility(ctx => ctx.UserGroups.Any(x => x.Alias == "editor")); +```` + +## Changing the page size + +### **SetPageSize(int pageSize) : ListViewConfigBuilder<TEntityType>** + +Sets the number of items to display per page for the given list view. + +````csharp +// Example +listViewConfig.SetPageSize(20); +```` diff --git a/15/umbraco-ui-builder/collections/overview.md b/15/umbraco-ui-builder/collections/overview.md new file mode 100644 index 00000000000..cf27e7db0ee --- /dev/null +++ b/15/umbraco-ui-builder/collections/overview.md @@ -0,0 +1,15 @@ +--- +description: Configuring collection in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Collections + +A collection is the cornerstone Umbraco UI Builder config and it represents a collection of entities for a given data model. From this config object, you can configure everything about how this collection integrates into the UI. You can also configure how it should display in a list view as well as how it should be edited. + +![A collection list view](../images/listview.png) + +Get started by reviewing the basics of collection configuration. + +{% content-ref url="the-basics.md" %} +[the-basics.md](the-basics.md) +{% endcontent-ref %} diff --git a/15/umbraco-ui-builder/collections/related-collections.md b/15/umbraco-ui-builder/collections/related-collections.md new file mode 100644 index 00000000000..cb8ef2345ba --- /dev/null +++ b/15/umbraco-ui-builder/collections/related-collections.md @@ -0,0 +1,166 @@ +--- +description: Configuring **many-to-many** relationships in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Related Collections + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +Related collections add support for editing **many-to-many** relationships with UI Builder. These are found when multiple entities from one collection are associated with multiple entities from another. They are modeled in a database via two tables related to a junction table. + +A classic example is with `Students` and `Courses`. Each course has many students, and each student takes many courses. + +![Child Collection](../images/related_collections_child.png) + +![Parent Collection](../images/related_collections_parent.png) + +![Entity Picker](../images/entity_picker_config.png) + +## Collections Representation + +A representation of your collections would look like this: + +![Related Collections Diagram](../images/related_collections_diagram.png) + +And the entities would be represented using the following Models: + +```csharp +[TableName("Students")] +[PrimaryKey("Id")] +public class Student +{ + [PrimaryKeyColumn] + public int Id { get; set; } + + public string FirstName { get; set; } + + public string LastName { get; set; } + + public string Email { get; set; } +} +``` + +```csharp +[TableName("Courses")] +[PrimaryKey("Id")] +public class Course +{ + [PrimaryKeyColumn] + public int Id { get; set; } + + public string Title { get; set; } + + public string Description { get; set; } +} +``` + +```csharp +[TableName("StudentsCourses")] +[PrimaryKey(new[] { "StudentId", "CourseId" })] +public class StudentCourse +{ + [PrimaryKeyColumn] + public int StudentId { get; set; } + + [PrimaryKeyColumn] + public int CourseId { get; set; } +} +``` + +## Defining a related collection + +You can get started with related collection through a two step process: + +1. Add collection definition +2. Add related collection entity picker and definition + +### Collection definition + +Define a related collection by calling the `AddRelatedCollection` method on a given collection config builder instance. + +### **AddRelatedCollection<TEntityType, TRelatedEntityType, TJunctionEntityType>(Expression<Func<TRelatedEntityType, object>> idPropertyExpression, string nameSingular, string namePlural, Action<RelationConfigBuilder<TBuilder, TEntity, TRelatedEntityType, TJunctionEntityType>> relationConfig)** + +Adds a related collection to the current collection with the given names, descriptions, and default icons. A property accessor expression is required for the entity ID field of the entity. The relation configuration will define the junction entity by specifying the references to parent and child entities. + +```csharp +collectionConfig.AddRelatedCollection(x => x.Id, "Student Course", "Students Courses", relationConfig => +{ + relationConfig + .SetAlias("studentsCourses") + .SetJunction(x => x.StudentId, y => y.CourseId); +}); +``` + +### Configuring a related collection entity picker + +Define the child collection entity picker by calling the `AddRelatedCollectionPickerField` method on the parent collection fieldset config. + +### **AddRelatedCollectionPickerField<TValueType>(string alias, string dataTypeName, string label)** + +Adds an entity picker with the specified Data Type name to the editor of the parent collection. + +```csharp +collectionConfig.Editor(editorConfig => +{ + editorConfig.AddTab("General", tabConfig => + tabConfig.AddFieldset("General", fieldsetConfig => + { + fieldsetConfig.AddField(x => x.FirstName).MakeRequired(); + fieldsetConfig.AddField(x => x.LastName).MakeRequired(); + fieldsetConfig.AddField(x => x.Email).MakeRequired(); + + fieldsetConfig.AddRelatedCollectionPickerField("studentsCourses", "Courses Related Picker", "Courses"); + })); +}); +``` + +{% hint style="info" %} +**Relation Config Alias:** The relation config alias must correspond to the related collection picker field alias! (e.g. `studentsCourses`) +{% endhint %} + +## Defining repository methods + +### **IEnumerable GetRelationsByParentIdImpl(int parentId, string relationAlias)** + +Retrieves the related collections based on the ID of the parent entity. + +```csharp +{ + var db = _scopeProvider.CreateScope().Database; + var sql = db.SqlContext.Sql() + .Select(new[] { "StudentId", "CourseId" } ) + .From("StudentsCourses") + .Where($"studentId = @0", parentId); + + var result = db.Fetch(sql); + + return result; +} +``` + +### **StudentCourse SaveRelationImpl(StudentCourse entity)** + +Adds a new related collection to the current parent entity. + +```csharp +{ + var db = _scopeProvider.CreateScope().Database; + + var type = entity.GetType(); + var studentId = type.GetProperty("StudentId").GetValue(entity); + var courseId = type.GetProperty("CourseId").GetValue(entity); + + // delete relation if exists + db.Execute("DELETE FROM StudentsCourses WHERE StudentId = @0 AND CourseId = @1", + studentId, + courseId); + + db.Execute("INSERT INTO StudentsCourses (StudentId, CourseId) VALUES (@0, @1)", + studentId, + courseId); + + return entity; +} +``` diff --git a/15/umbraco-ui-builder/collections/retrieve-child-collections.md b/15/umbraco-ui-builder/collections/retrieve-child-collections.md new file mode 100644 index 00000000000..0f85f135917 --- /dev/null +++ b/15/umbraco-ui-builder/collections/retrieve-child-collections.md @@ -0,0 +1,74 @@ +--- +description: Configuring **one-to-many** relationships in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Retrieve Child Collections + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +Retrieving child collections in **one-to-many** relationships with UI Builder, can be achieved with the support of child repositories. One-to-many relations are where one parent entity of a collection is associated with multiple entities from another. + +## Models Representation + +The models would look like this: + +```csharp +[TableName("Students")] +[PrimaryKey("Id")] +public class Student +{ + [PrimaryKeyColumn] + public int Id { get; set; } + + public string FirstName { get; set; } + + public string LastName { get; set; } + + public string Email { get; set; } +} +``` + +```csharp +[TableName("StudentProjects")] +[PrimaryKey("Id")] +public class StudentProject +{ + [PrimaryKeyColumn] + public int Id { get; set; } + + public string Name { get; set; } + + public int StudentId { get; set; } +} +``` + +## Child Repositories + +You can create child repository instances via the `IRepositoryFactory` and use them to retrieve information from the child collection. + +```csharp +public class StudentProjectController : Controller +{ + private readonly IRepositoryFactory _repositoryFactory; + + public StudentProjectController(IRepositoryFactory repositoryFactory) + { + _repositoryFactory = repositoryFactory; + } + + public IActionResult Index(int projectId) + { + var childRepository = _repositoryFactory.GetChildRepository(projectId); + + var list = childRepository.GetAll(); + + var count = childRepository.GetCount(); + + var listPaged = childRepository.GetPaged(); + + return View(list); + } +} +``` diff --git a/15/umbraco-ui-builder/collections/the-basics.md b/15/umbraco-ui-builder/collections/the-basics.md new file mode 100644 index 00000000000..7dc097226b1 --- /dev/null +++ b/15/umbraco-ui-builder/collections/the-basics.md @@ -0,0 +1,239 @@ +--- +description: The basics of a collection configuration in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# The Basics + +There is a lot that can be configured from the collection config, but what follows are the core basics. You can find more configuration options about specific topics from the other configuration sections in the main menu. + +## Defining a collection + +You can define a collection by calling one of the `AddCollection` methods on a given [`Tree`](../areas/trees.md) or parent [`Folder`](../areas/folders.md) config builder instance. + +### **AddCollection<TEntityType>(Lambda idFieldExpression, string nameSingular, string namePlural, string description, Lambda collectionConfig = null) : CollectionConfigBuilder<TEntityType>** + +Adds a collection to the given container with the given names and description and default icons. An ID property accessor expression is required so that Umbraco UI Builder knows which property is the ID property. + +````csharp +// Example +folderConfig.AddCollection(p => p.Id, "Person", "People", "A collection of people", collectionConfig => { + ... +}); +```` + +### **AddCollection<TEntityType>(Lambda idFieldExpression, string nameSingular, string namePlural, string description, string iconSingular, string iconPlural, Lambda collectionConfig = null) : CollectionConfigBuilder<TEntityType>** + +Adds a collection to the given container with the given names, description and icons. An ID property accessor expression is required so that Umbraco UI Builder knows which property is the ID property. + +````csharp +// Example +folderConfig.AddCollection(p => p.Id, "Person", "People", "A collection of people", "icon-umb-users", "icon-umb-users", collectionConfig => { + ... +}); +```` + +## Changing a collection alias + +### **SetAlias(string alias) : CollectionConfigBuilder<TEntityType>** + +Sets the alias of the collection. + +**Optional:** When creating a new collection, an alias is automatically generated from the supplied name for you. However, if you need a specific alias you can use the `SetAlias` method to override this. + +````csharp +// Example +collectionConfig.SetAlias("person"); +```` + +## Changing a collection icon color + +### **SetIconColor(string color) : CollectionConfigBuilder<TEntityType>** + +Sets the collection icon color to the given color. Possible options are `black`, `green`, `yellow`, `orange`, `blue` or `red`. + +````csharp +// Example +collectionConfig.SetIconColor("blue"); +```` + +## Defining an entity name + +Within Umbraco, it is expected that an entity has a name property. So we need to let Umbraco UI Builder know which property to use for the name. If the entity doesn't have a name property, then it needs to know how to construct a name from an entity's other properties. We do this by using either the `SetNameProperty` or `SetNameFormat` methods on a `Collection` config builder instance. + +### **SetNameProperty(Lambda namePropertyExpression) : CollectionConfigBuilder<TEntityType>** + +Sets which property of your entity to use as the name property. Property must be of type `string`. By defining a property as the name property, its value will be used as the label for the entity in trees and list views. It will also be editable in the header region of the editor interface. The property will also automatically be added to the searchable properties collection and be used for the default sort property. + +````csharp +// Example +collectionConfig.SetNameProperty(p => p.Name); +```` + +### **SetNameProperty(Lambda namePropertyExpression, string heading) : CollectionConfigBuilder<TEntityType>** + +Sets which property of your entity to use as the name property and what custom heading should the list view column heading be. Property must be of type `string`. By defining a property as the name property, its value will be used as the label for the entity in trees and list views. It will also be editable in the header region of the editor interface. The property will also automatically be added to the searchable properties collection and be used for the default sort property. + +````csharp +// Example +collectionConfig.SetNameProperty(p => p.Name, "Person Name"); +```` + +### **SetNameFormat(Lambda nameFormatExpression) : CollectionConfigBuilder<TEntityType>** + +Sets a format expression to use to dynamically create a label for the entity in things like trees and list views. By providing a name format it is assumed there is no single name property available on the entity. And as such none of the default behaviors described for the `SetNameProperty` method will apply. + +````csharp +// Example +collectionConfig.SetNameFormat(p => $"{p.FirstName} {p.LastName}"); +```` + +## Defining a default sort order + +### **SetSortProperty(Lambda sortPropertyExpression) : CollectionConfigBuilder<TEntityType>** + +Sets which property of our entity to sort against, defaulting to ascending sort direction. + +````csharp +// Example +collectionConfig.SetSortProperty(p => p.FirstName); +```` + +### **SetSortProperty(Lambda sortPropertyExpression, SortDirection sortDirection) : CollectionConfigBuilder<TEntityType>** + +Sets which property of our entity to sort against in the provided sort direction. + +````csharp +// Example +collectionConfig.SetSortProperty(p => p.FirstName, SortDirection.Descending); +```` + +## Defining time stamp properties + +### **SetDateCreatedProperty(Lambda dateCreatedProperty) : CollectionConfigBuilder<TEntityType>** + +Sets which property of our entity to use as the date created property. Property must be of type `DateTime`. When set and a new entity is saved via the repository, then the given field will be populated with the current date and time. + +````csharp +// Example +collectionConfig.SetDateCreatedProperty(p => p.DateCreated); +```` + +### **SetDateModifiedProperty(Lambda dateCreatedProperty) : CollectionConfigBuilder<TEntityType>** + +Sets which property of our entity to use as the date modified property. Property must be of type `DateTime`. When set and an entity is saved via the repository, then the given field will be populated with the current date and time. + +````csharp +// Example +collectionConfig.SetDateModifiedProperty(p => p.DateModified); +```` + +## Configuring soft deletes + +By default, in Umbraco UI Builder any entity that is deleted via the Umbraco UI Builder repository is definitively removed from the system. The `SetDeletedProperty` method can be used if needed to keep the records in the data repository despite having them marked as deleted. This is so they do not show the the UI. + +### **SetDeletedProperty(Lambda deletedPropertyExpression) : CollectionConfigBuilder<TEntityType>** + +Sets which property of our entity to use as the deleted property flag. Property must be of type `boolean` or `int`. When a deleted property is set, any delete actions will set the deleted flag instead of deleting the entity. For `boolean` based properties, deleted entities will have a value of `True` when deleted. For `int` based properties, deleted entities will have a UTC Unix timestamp value of the date the entity was deleted. In addition, any fetch actions will also pre-filter out any deleted entities. + +````csharp +// Example +collectionConfig.SetDeletedProperty(p => p.Deleted); +```` + +## Disabling create, update or delete features + +### **DisableCreate() : CollectionConfigBuilder<TEntityType>** + +Disables the option to create entities on the current collection. An entity could be created via code and only then editing is allowed in the UI for example. + +````csharp +// Example +collectionConfig.DisableCreate(); +```` + +### **DisableCreate(Predicate<CollectionPermissionContext> disableExpression) : CollectionConfigBuilder<TEntityType>** + +Disables the option to create entities on the current collection if the given runtime predicate is true. An entity could be created via code and only then editing is allowed in the UI. + +````csharp +// Example +collectionConfig.DisableCreate(ctx => ctx.UserGroups.Any(x => x.Alias == "editor")); +```` + +### **DisableUpdate() : CollectionConfigBuilder<TEntityType>** + +Disables the option to update entities on the current collection. An entity can be created, but further editing is not allowed. + +````csharp +// Example +collectionConfig.DisableUpdate(); +```` + +### **DisableUpdate(Predicate<CollectionPermissionContext> disableExpression) : CollectionConfigBuilder<TEntityType>** + +Disables the option to update entities on the current collection if the given runtime predicate is true. An entity can be created, but further editing is not allowed. + +````csharp +// Example +collectionConfig.DisableUpdate(ctx => ctx.UserGroups.Any(x => x.Alias == "editor")); +```` + +### **DisableDelete() : CollectionConfigBuilder<TEntityType>** + +Disables the option to delete entities on the current collection. Useful if the data needs to be retained and visible. See also [configuring soft deletes](#configuring-soft-deletes). + +````csharp +// Example +collectionConfig.DisableDelete(); +```` + +### **DisableDelete(Predicate<CollectionPermissionContext> disableExpression) : CollectionConfigBuilder<TEntityType>** + +Disables the option to delete entities on the current collection if the given runtime predicate is true. Useful if the data needs to be retained and visible. See also [configuring soft deletes](#configuring-soft-deletes). + +````csharp +// Example +collectionConfig.DisableDelete(ctx => ctx.UserGroups.Any(x => x.Alias == "editor")); +```` + +### **MakeReadOnly() : CollectionConfigBuilder<TEntityType>** + +Sets the collection as read-only and disables any Create, Read, Update, and Delete (CRUD) operations from being performed on the collection via the UI. + +````csharp +// Example +collectionConfig.MakeReadOnly(); +```` + +### **MakeReadOnly(Predicate<CollectionPermissionContext> disableExpression) : CollectionConfigBuilder<TEntityType>** + +Sets the collection as read-only if the given runtime predicate is true. It also disables any Create, Read, Update, and Delete (CRUD) operations from being performed on the collection via the UI. + +````csharp +// Example +collectionConfig.MakeReadOnly(ctx => ctx.UserGroups.Any(x => x.Alias == "editor")); +```` + +## Set the visibility of the collection + +### **SetVisibility(Predicate<CollectionVisibilityContext> visibilityExpression) : CollectionConfigBuilder<TEntityType>** + +Sets the runtime visibility of the collection. + +````csharp +// Example +collectionConfig.SetVisibility(ctx => ctx.UserRoles.Any(x => x.Alias == "editor")); +```` + +## Changing a collection connection string + +By default, Umbraco UI Builder will use the Umbraco connection string for its database connection. However, you can change this by calling the `SetConnectionString` method on a `Collection` config builder instance. + +### **SetConnectionString(string connectionStringName) : CollectionConfigBuilder<TEntityType>** + +Sets the connection string name for the given collection repository. + +````csharp +// Example +collectionConfig.SetConnectionString("myConnectionStringName"); +```` diff --git a/15/umbraco-ui-builder/filtering/data-views-builders.md b/15/umbraco-ui-builder/filtering/data-views-builders.md new file mode 100644 index 00000000000..5803cadcd52 --- /dev/null +++ b/15/umbraco-ui-builder/filtering/data-views-builders.md @@ -0,0 +1,65 @@ +--- +description: Configuring data views builders in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Data Views Builders + +Data views builders allow you to create a collection data views list dynamically at run time. By default, Umbraco UI Builder will use the hard-coded data views defined in your Umbraco UI Builder config. However, if you need to build your data views list dynamically, then this is when you'd use a data views builder. + +When Umbraco UI Builder resolves a data views builder it will attempt to do so from the global DI container. This means you can inject any dependencies that you require for your builder. If there is no type defined in the DI container, Umbraco UI Builder will fall-back to manually instantiating a new instance of value mapper. + +## Defining a data views builder + +To define a data views builder you can create a class that inherits from the base class `DataViewsBuilder` and implements the abstract methods. + +````csharp +// Example +public class PersonDataViewsBuilder : DataViewsBuilder +{ + public override IEnumerable GetDataViews() + { + // Generate and return a list of data views + } + + public override Expression> GetDataViewWhereClause(string dataViewAlias) + { + // Return a where clause expression for the supplied data view alias + } +} +```` + +The required methods are: + +* **GetDataViews:** Returns the list of data views to choose from. +* **GetDataViewWhereClause:** Returns the boolean **where clause** expression for the given data views alias. + +## Setting the data views builder of a collection + +Setting a data views builder is controlled via the [collections](../collections/overview.md) configuration. + +### **SetDataViewsBuilder<TDataViewsBuilder>() : CollectionConfigBuilder<TEntityType>** + +Sets the collections data views builder which allows you to define the data views dynamically at run time. + +````csharp +// Example +collectionConfig.SetDataViewsBuilder(); +```` + +### **SetDataViewsBuilder(Type dataViewsBuilderType) : CollectionConfigBuilder<TEntityType>** + +Sets the collections data views builder which allows you to define the data views dynamically at run time. + +````csharp +// Example +collectionConfig.SetDataViewsBuilder(typeof(PersonDataViewsBuilder)); +```` + +### **SetDataViewsBuilder(DataViewsBuilder<TEntityType> dataViewsBuilder) : CollectionConfigBuilder<TEntityType>** + +Sets the collections data views builder which allows you to define the data views dynamically at run time. + +````csharp +// Example +collectionConfig.SetDataViewsBuilder(new PersonDataViewsBuilder()); +```` diff --git a/15/umbraco-ui-builder/filtering/data-views.md b/15/umbraco-ui-builder/filtering/data-views.md new file mode 100644 index 00000000000..e35edbcc384 --- /dev/null +++ b/15/umbraco-ui-builder/filtering/data-views.md @@ -0,0 +1,31 @@ +--- +description: Configuring data views in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Data Views + +Data views allow you to define multiple, pre-filtered views of the same data source. This can be useful when entities exist in different states and you want a way to toggle between them. + +![Data Views](../images/data_views.png) + +## Defining data views + +Data views are defined via the [collections](../collections/overview.md) configuration. + +### **AddDataView(string name, Lambda whereClauseExpression) : CollectionConfigBuilder<TEntityType>** + +Adds a data view with the given name and **where clause** filter expression. Expression must be a `boolean` expression. + +````csharp +// Example +collectionConfig.AddDataView("Active", p => p.IsActive); +```` + +### **AddDataView(string group, string name, Lambda whereClauseExpression) : CollectionConfigBuilder<TEntityType>** + +Adds a data view with the given group, name and **where clause** filter expression. Expression must be a `boolean` expression. + +````csharp +// Example +collectionConfig.AddDataView("Status", "Active", p => p.IsActive); +```` diff --git a/15/umbraco-ui-builder/filtering/filterable-properties.md b/15/umbraco-ui-builder/filtering/filterable-properties.md new file mode 100644 index 00000000000..0c61d0b18e4 --- /dev/null +++ b/15/umbraco-ui-builder/filtering/filterable-properties.md @@ -0,0 +1,74 @@ +--- +description: Configuring filterable properties in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Filterable Properties + +Umbraco UI Builder can dynamically build a filter dialog choosing appropriate editor views for you based on a basic property configuration. Properties of a number or date types will become range pickers and enums. Properties with options defined will become select/checkbox lists and all other properties will become text input filters. + +![Filterable Properties](../images/filterable_properties.png) + +## Defining filterable properties + +Defining filterable properties is controlled via the [collections](../collections/overview.md) configuration. + +### **AddFilterableProperty(Lambda filterablePropertyExpression, Lambda filterConfig = null) : CollectionConfigBuilder<TEntityType>** + +Adds the given property to the filterable properties collection. + +````csharp +// Example +collectionConfig.AddFilterableProperty(p => p.FirstName, filterConfig => filterConfig + // ... +); +```` + +## Changing the label of a filterable property + +### **SetLabel(string label) : FilterablePropertyConfigBuilder<TEntityType, TValueType>** + +````csharp +// Example +filterConfig.SetLabel("First Name"); +```` + +## Adding a description to a filterable property + +### **SetDescription(string description) : FilterablePropertyConfigBuilder<TEntityType, TValueType>** + +````csharp +// Example +filterConfig.SetDescription("The first name of the person"); +```` + +## Defining basic options for a filterable property + +### **SetOptions(IDictionary<TValueType, string> options) : FilterablePropertyConfigBuilder<TEntityType, TValueType>** + +````csharp +// Example +filterConfig.SetOptions(new Dictionary { + { "Option1", "Option One" }, + { "Option2", "Option Two" } +}); +```` + +## Defining options with custom compare clauses for a filterable property + +### **AddOption(object key, string label, Lambda compareExpression) : FilterablePropertyConfigBuilder<TEntityType, TValueType>** + +````csharp +// Example +filterConfig.AddOption("Option1", "Option One", (val) => val != "Option Two"); +```` + +## Configuring the mode of a filterable property + +For filterable properties with options you can configure whether the options should be multiple or single choice. + +### **SetMode(FilterMode mode) : FilterablePropertyConfigBuilder<TEntityType, TValueType>** + +````csharp +// Example +filterConfig.SetMode(FilterMode.MultipleChoice); +```` diff --git a/15/umbraco-ui-builder/filtering/global-filters.md b/15/umbraco-ui-builder/filtering/global-filters.md new file mode 100644 index 00000000000..6ead9ff183f --- /dev/null +++ b/15/umbraco-ui-builder/filtering/global-filters.md @@ -0,0 +1,20 @@ +--- +description: Configuring a global filter in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Global Filters + +If you want to work with a subset of data within a given collection then this is where the global filters come in handy. These allow you to define a filter to apply to all queries for a given collection. + +## Applying a global filter + +Applying a global filter is controlled via the [collections](../collections/overview.md) configuration. + +### **SetFilter(Lambda whereClauseExpression) : CollectionConfigBuilder<TEntityType>** + +Sets the filter **where clause** expression. Expression must be a `boolean` expression. + +````csharp +// Example +collectionConfig.SetFilter(p => p.Current); +```` diff --git a/15/umbraco-ui-builder/filtering/overview.md b/15/umbraco-ui-builder/filtering/overview.md new file mode 100644 index 00000000000..3721654078b --- /dev/null +++ b/15/umbraco-ui-builder/filtering/overview.md @@ -0,0 +1,21 @@ +--- +description: Configuring filtering in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Filtering + +Beyond [searching](../searching/overview.md) there might be times when you need to be able to create specific views of a collection's data. To help with this Umbraco UI Builder has different filtering mechanisms available. + +![Filterable Properties](../images/filterable_properties.png) + +Choose a filtering method from the list below to find out more. + +{% content-ref url="global-filters.md" %} +[global-filters.md](global-filters.md) +{% endcontent-ref %} +{% content-ref url="data-views.md" %} +[data-views.md](data-views.md) +{% endcontent-ref %} +{% content-ref url="filterable-properties.md" %} +[filterable-properties.md](filterable-properties.md) +{% endcontent-ref %} diff --git a/15/umbraco-ui-builder/getting-started/configuration.md b/15/umbraco-ui-builder/getting-started/configuration.md new file mode 100644 index 00000000000..69e9bf105aa --- /dev/null +++ b/15/umbraco-ui-builder/getting-started/configuration.md @@ -0,0 +1,25 @@ +--- +description: Configuring Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Configuration + +Umbraco UI Builder can be configured directly via the `AddUIBuilder` extension method on `IUmbracoBuilder`. + +## AddUIBuilder + +To configure Umbraco UI Builder via the `AddUIBuilder` extension method, You can look in the `Program.cs` file in the root of your web project. From within this file, before the call to `AddComposers()` we can add our `AddUIBuilder` configuration. + +```csharp +builder.CreateUmbracoBuilder() + .AddBackOffice() + .AddWebsite() + .AddUIBuilder(cfg => { + // Apply your configuration here + }) + .AddDeliveryApi() + .AddComposers() + .Build(); +``` + +The `AddUIBuilder` extension method accepts a single parameter, a delegate function with one of the Umbraco UI Builder configuration builder arguments. With this, you can then call the relevant fluent APIs to define your solution. diff --git a/15/umbraco-ui-builder/getting-started/overview.md b/15/umbraco-ui-builder/getting-started/overview.md new file mode 100644 index 00000000000..0dd186f3b98 --- /dev/null +++ b/15/umbraco-ui-builder/getting-started/overview.md @@ -0,0 +1,26 @@ +--- +description: >- + Getting Started with Umbraco UI Builder, the backoffice UI builder for + Umbraco. +--- + +# Overview + +This section will guide you through the key steps necessary to get you started with Umbraco UI Builder. + +It is assumed that you have an Umbraco 10+ website configured, and ready to install Umbraco UI Builder. + +{% hint style="info" %} +Find detailed instructions on how to install the latest version of Umbraco in the [Umbraco CMS documentation](https://docs.umbraco.com/umbraco-cms/fundamentals/setup/install). +{% endhint %} + +## System Requirements + +At this time, the minimum requirements for using Umbraco UI Builder are as follows: + +* **Umbraco CMS version 10.0/12.0+** +* **SQL Server Database** (SQLite is fine for testing, but not recommended for live deployments) + +## Versioning + +This is an add-on product to Umbraco CMS. Umbraco UI Builder follows the [versioning strategy laid out for Umbraco CMS](https://umbraco.com/products/knowledge-center/versioning-and-release-cadence/). diff --git a/15/umbraco-ui-builder/getting-started/user-interface.md b/15/umbraco-ui-builder/getting-started/user-interface.md new file mode 100644 index 00000000000..5f7b92fc6b1 --- /dev/null +++ b/15/umbraco-ui-builder/getting-started/user-interface.md @@ -0,0 +1,34 @@ +--- +description: Key User Interface Concepts used by Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# User Interface + +Before you get to know Umbraco UI Builder, you need to become familiar with the Umbraco UI and a few of its concepts. This is because Umbraco UI Builder reuses these same concepts for constructing its UI. + +![Sections, Trees, and Dashboards](../images/ui_01.png) + +**1. Section** A distinct area of the Umbraco backoffice. +**2. Tree** A hierarchical structure to help organize a section. +**3. Dashboard** An intro screen for a section, usually with useful links for that section. + +![List View](../images/ui_02.png) + +**4. List View** A list-based view of items in a tree node. + +![Editor](../images/ui_03.png) + +**5. Editor** The main content editing area is made up of tabs, fieldsets, and fields. + +![Context Apps and Tabs](../images/ui_06.png) + +**6. Context Apps** A contextual section of a given editor UI. +**7. Tabs** A tabbed container of content. + +![Menu Item](../images/ui_04.png) + +**8. Menu Item** A context menu item + action. + +![Bulk Action](../images/ui_05.png) + +**9. Bulk Action** An action to perform on multiple list view items at once. diff --git a/15/umbraco-ui-builder/guides/creating-your-first-integration.md b/15/umbraco-ui-builder/guides/creating-your-first-integration.md new file mode 100644 index 00000000000..49c871ae1b2 --- /dev/null +++ b/15/umbraco-ui-builder/guides/creating-your-first-integration.md @@ -0,0 +1,112 @@ +--- +description: Creating your first integration with Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Creating your first integration + +In this guide, you can find the necessary steps needed for a basic implementation using Umbraco UI Builder to manage a single custom database table. + +## Set up the database + +Out of the box, Umbraco UI Builder works using PetaPoco as the persistence layer as this is what ships with Umbraco. If you prefer, it is possible to use a custom [Repository](../advanced/repositories.md). However, for getting started, it is expected that you are using this default strategy. + +Start by setting up a database table for your model (you might want to populate it with some dummy data as well while learning). We’ll use the following as an example: + +```sql +CREATE TABLE [Person] ( + [Id] int IDENTITY (1,1) NOT NULL, + [Name] nvarchar(255) NOT NULL, + [JobTitle] nvarchar(255) NOT NULL, + [Email] nvarchar(255) NOT NULL, + [Telephone] nvarchar(255) NOT NULL, + [Age] int NOT NULL, + [Avatar] nvarchar(255) NOT NULL +); +``` + +## Set up your model + +With the database table setup, we then need to create the associated Poco model in our project. + +```csharp +[TableName("Person")] +[PrimaryKey("Id")] +public class Person +{ + [PrimaryKeyColumn] + public int Id { get; set; } + public string Name { get; set; } + public string JobTitle { get; set; } + public string Email { get; set; } + public string Telephone { get; set; } + public int Age { get; set; } + public string Avatar { get; set; } +} +``` + +## Configure Umbraco UI Builder + +With the database and model setup, we can now start to configure Umbraco UI Builder itself. The entry point for the Umbraco UI Builder configuration is via the `AddUIBuilder` extension method. On this method, we call on the `IUmbracoBuilder` instance within the `Program.cs` class. + +```csharp +builder.CreateUmbracoBuilder() + .AddBackOffice() + .AddWebsite() + .AddDeliveryApi() + .AddComposers() + .AddUIBuilder(cfg => { + // Apply your configuration here + }) + .Build(); +``` + +For our example, we will use the following configuration: + +```csharp +... +.AddUIBuilder(cfg => { + + cfg.AddSectionAfter("media", "Repositories", sectionConfig => sectionConfig + .Tree(treeConfig => treeConfig + .AddCollection(x => x.Id, "Person", "People", "A person entity", "icon-umb-users", "icon-umb-users", collectionConfig => collectionConfig + .SetNameProperty(p => p.Name) + .ListView(listViewConfig => listViewConfig + .AddField(p => p.JobTitle).SetHeading("Job Title") + .AddField(p => p.Email) + ) + .Editor(editorConfig => editorConfig + .AddTab("General", tabConfig => tabConfig + .AddFieldset("General", fieldsetConfig => fieldsetConfig + .AddField(p => p.JobTitle).MakeRequired() + .AddField(p => p.Age) + .AddField(p => p.Email).SetValidationRegex("[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+") + .AddField(p => p.Telephone).SetDescription("inc area code") + ) + .AddFieldset("Media", fieldsetConfig => fieldsetConfig + .AddField(p => p.Avatar).SetDataType("Upload File") + ) + ) + ) + ) + ) + ); + +}) +... +``` + +## Access your UI + +With your configuration defined and your project compiled, there is one last step to perform before you can access your UI. And that is to give your backoffice user account permission to access the newly defined section. To do this you'll need to login to the backoffice, head to the user's section, and update the user group. There you will need to make sure that your user belongs to the allowed access. + +![User group permissions](../images/permissions.png) + +With the permissions set, you can refresh your browser and you should now see your new section available in the site navigation. + +![People list view](../images/listview.png) + +![People editor](../images/editor.png) + +## Summary + +As you can see, with little code you can start to create powerful interfaces for your custom data structures. diff --git a/15/umbraco-ui-builder/images/bulk_actions.png b/15/umbraco-ui-builder/images/bulk_actions.png new file mode 100644 index 00000000000..9447f4d3179 Binary files /dev/null and b/15/umbraco-ui-builder/images/bulk_actions.png differ diff --git a/15/umbraco-ui-builder/images/bulk_actions_menu.png b/15/umbraco-ui-builder/images/bulk_actions_menu.png new file mode 100644 index 00000000000..0de260da545 Binary files /dev/null and b/15/umbraco-ui-builder/images/bulk_actions_menu.png differ diff --git a/15/umbraco-ui-builder/images/cards.png b/15/umbraco-ui-builder/images/cards.png new file mode 100644 index 00000000000..31e2c20c3af Binary files /dev/null and b/15/umbraco-ui-builder/images/cards.png differ diff --git a/15/umbraco-ui-builder/images/child_collection_groups.png b/15/umbraco-ui-builder/images/child_collection_groups.png new file mode 100644 index 00000000000..4cb9e5ca297 Binary files /dev/null and b/15/umbraco-ui-builder/images/child_collection_groups.png differ diff --git a/15/umbraco-ui-builder/images/child_collections.png b/15/umbraco-ui-builder/images/child_collections.png new file mode 100644 index 00000000000..b0f844ceeb8 Binary files /dev/null and b/15/umbraco-ui-builder/images/child_collections.png differ diff --git a/15/umbraco-ui-builder/images/comments_listview.png b/15/umbraco-ui-builder/images/comments_listview.png new file mode 100644 index 00000000000..fee43943a15 Binary files /dev/null and b/15/umbraco-ui-builder/images/comments_listview.png differ diff --git a/15/umbraco-ui-builder/images/container_actions_menu.png b/15/umbraco-ui-builder/images/container_actions_menu.png new file mode 100644 index 00000000000..1e6871db48d Binary files /dev/null and b/15/umbraco-ui-builder/images/container_actions_menu.png differ diff --git a/15/umbraco-ui-builder/images/content_apps.png b/15/umbraco-ui-builder/images/content_apps.png new file mode 100644 index 00000000000..23604f20f04 Binary files /dev/null and b/15/umbraco-ui-builder/images/content_apps.png differ diff --git a/15/umbraco-ui-builder/images/context_app.png b/15/umbraco-ui-builder/images/context_app.png new file mode 100644 index 00000000000..b9f509ddfd8 Binary files /dev/null and b/15/umbraco-ui-builder/images/context_app.png differ diff --git a/15/umbraco-ui-builder/images/dashboard.png b/15/umbraco-ui-builder/images/dashboard.png new file mode 100644 index 00000000000..6e7f09e3d8b Binary files /dev/null and b/15/umbraco-ui-builder/images/dashboard.png differ diff --git a/15/umbraco-ui-builder/images/dashboards.png b/15/umbraco-ui-builder/images/dashboards.png new file mode 100644 index 00000000000..aec51a0777f Binary files /dev/null and b/15/umbraco-ui-builder/images/dashboards.png differ diff --git a/15/umbraco-ui-builder/images/data_views.png b/15/umbraco-ui-builder/images/data_views.png new file mode 100644 index 00000000000..c577f854dc5 Binary files /dev/null and b/15/umbraco-ui-builder/images/data_views.png differ diff --git a/15/umbraco-ui-builder/images/editor.png b/15/umbraco-ui-builder/images/editor.png new file mode 100644 index 00000000000..81a6b02af94 Binary files /dev/null and b/15/umbraco-ui-builder/images/editor.png differ diff --git a/15/umbraco-ui-builder/images/entity_actions_menu.png b/15/umbraco-ui-builder/images/entity_actions_menu.png new file mode 100644 index 00000000000..2757026dd17 Binary files /dev/null and b/15/umbraco-ui-builder/images/entity_actions_menu.png differ diff --git a/15/umbraco-ui-builder/images/entity_picker_config.png b/15/umbraco-ui-builder/images/entity_picker_config.png new file mode 100644 index 00000000000..fee19974ea0 Binary files /dev/null and b/15/umbraco-ui-builder/images/entity_picker_config.png differ diff --git a/15/umbraco-ui-builder/images/entity_picker_picked.png b/15/umbraco-ui-builder/images/entity_picker_picked.png new file mode 100644 index 00000000000..a09f97ee97b Binary files /dev/null and b/15/umbraco-ui-builder/images/entity_picker_picked.png differ diff --git a/15/umbraco-ui-builder/images/entity_picker_search.png b/15/umbraco-ui-builder/images/entity_picker_search.png new file mode 100644 index 00000000000..5278a64ffcf Binary files /dev/null and b/15/umbraco-ui-builder/images/entity_picker_search.png differ diff --git a/15/umbraco-ui-builder/images/entity_picker_setup.png b/15/umbraco-ui-builder/images/entity_picker_setup.png new file mode 100644 index 00000000000..2f202127cea Binary files /dev/null and b/15/umbraco-ui-builder/images/entity_picker_setup.png differ diff --git a/15/umbraco-ui-builder/images/filterable_properties.png b/15/umbraco-ui-builder/images/filterable_properties.png new file mode 100644 index 00000000000..161eac28ede Binary files /dev/null and b/15/umbraco-ui-builder/images/filterable_properties.png differ diff --git a/15/umbraco-ui-builder/images/listview.png b/15/umbraco-ui-builder/images/listview.png new file mode 100644 index 00000000000..b9a90f0f82e Binary files /dev/null and b/15/umbraco-ui-builder/images/listview.png differ diff --git a/15/umbraco-ui-builder/images/menu_items.png b/15/umbraco-ui-builder/images/menu_items.png new file mode 100644 index 00000000000..3662552ba18 Binary files /dev/null and b/15/umbraco-ui-builder/images/menu_items.png differ diff --git a/15/umbraco-ui-builder/images/permissions.png b/15/umbraco-ui-builder/images/permissions.png new file mode 100644 index 00000000000..ebb680c3fe3 Binary files /dev/null and b/15/umbraco-ui-builder/images/permissions.png differ diff --git a/15/umbraco-ui-builder/images/related_collections_child.png b/15/umbraco-ui-builder/images/related_collections_child.png new file mode 100644 index 00000000000..16f9bf58cfb Binary files /dev/null and b/15/umbraco-ui-builder/images/related_collections_child.png differ diff --git a/15/umbraco-ui-builder/images/related_collections_diagram.png b/15/umbraco-ui-builder/images/related_collections_diagram.png new file mode 100644 index 00000000000..007436a85bf Binary files /dev/null and b/15/umbraco-ui-builder/images/related_collections_diagram.png differ diff --git a/15/umbraco-ui-builder/images/related_collections_parent.png b/15/umbraco-ui-builder/images/related_collections_parent.png new file mode 100644 index 00000000000..7c763aebab5 Binary files /dev/null and b/15/umbraco-ui-builder/images/related_collections_parent.png differ diff --git a/15/umbraco-ui-builder/images/row_actions_menu.png b/15/umbraco-ui-builder/images/row_actions_menu.png new file mode 100644 index 00000000000..a0fcf0ef886 Binary files /dev/null and b/15/umbraco-ui-builder/images/row_actions_menu.png differ diff --git a/15/umbraco-ui-builder/images/save_actions_menu.png b/15/umbraco-ui-builder/images/save_actions_menu.png new file mode 100644 index 00000000000..cf818ba674a Binary files /dev/null and b/15/umbraco-ui-builder/images/save_actions_menu.png differ diff --git a/15/umbraco-ui-builder/images/search.png b/15/umbraco-ui-builder/images/search.png new file mode 100644 index 00000000000..3892741bbfd Binary files /dev/null and b/15/umbraco-ui-builder/images/search.png differ diff --git a/15/umbraco-ui-builder/images/sections.png b/15/umbraco-ui-builder/images/sections.png new file mode 100644 index 00000000000..bfcea850b44 Binary files /dev/null and b/15/umbraco-ui-builder/images/sections.png differ diff --git a/15/umbraco-ui-builder/images/tree.png b/15/umbraco-ui-builder/images/tree.png new file mode 100644 index 00000000000..c9956e07e08 Binary files /dev/null and b/15/umbraco-ui-builder/images/tree.png differ diff --git a/15/umbraco-ui-builder/images/ui_01.png b/15/umbraco-ui-builder/images/ui_01.png new file mode 100644 index 00000000000..ac15c165bd9 Binary files /dev/null and b/15/umbraco-ui-builder/images/ui_01.png differ diff --git a/15/umbraco-ui-builder/images/ui_02.png b/15/umbraco-ui-builder/images/ui_02.png new file mode 100644 index 00000000000..dd7e6610094 Binary files /dev/null and b/15/umbraco-ui-builder/images/ui_02.png differ diff --git a/15/umbraco-ui-builder/images/ui_03.png b/15/umbraco-ui-builder/images/ui_03.png new file mode 100644 index 00000000000..b7024f5a0ad Binary files /dev/null and b/15/umbraco-ui-builder/images/ui_03.png differ diff --git a/15/umbraco-ui-builder/images/ui_04.png b/15/umbraco-ui-builder/images/ui_04.png new file mode 100644 index 00000000000..c22e7b82fe1 Binary files /dev/null and b/15/umbraco-ui-builder/images/ui_04.png differ diff --git a/15/umbraco-ui-builder/images/ui_05.png b/15/umbraco-ui-builder/images/ui_05.png new file mode 100644 index 00000000000..54552b1c2cf Binary files /dev/null and b/15/umbraco-ui-builder/images/ui_05.png differ diff --git a/15/umbraco-ui-builder/images/ui_06.png b/15/umbraco-ui-builder/images/ui_06.png new file mode 100644 index 00000000000..9eeddc5c48f Binary files /dev/null and b/15/umbraco-ui-builder/images/ui_06.png differ diff --git a/15/umbraco-ui-builder/images/virtual-sub-tree.png b/15/umbraco-ui-builder/images/virtual-sub-tree.png new file mode 100644 index 00000000000..a2d4f5763b1 Binary files /dev/null and b/15/umbraco-ui-builder/images/virtual-sub-tree.png differ diff --git a/15/umbraco-ui-builder/installation/installation.md b/15/umbraco-ui-builder/installation/installation.md new file mode 100644 index 00000000000..a92e0322301 --- /dev/null +++ b/15/umbraco-ui-builder/installation/installation.md @@ -0,0 +1,23 @@ +--- +description: Installing Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Installation + +Umbraco UI Builder is installed via the NuGet package manager by issuing the following command in your web project. + +```bash +dotnet add package Umbraco.UIBuilder +``` + +If you wish to install Umbraco UI Builder into a class library without the UI elements, you can add a reference to the `Umbraco.UIBuilder.Startup` package instead. + +```bash +dotnet add package Umbraco.UIBuilder.Startup +``` + +Alternatively, you can also find and install the NuGet package via the NuGet Package Manager graphical user interface (GUI) in Visual Studio. + +## Installing a License + +See the [Licensing page](licensing-model.md#installing-your-license) for details on how to install a license. diff --git a/15/umbraco-ui-builder/installation/licensing-model.md b/15/umbraco-ui-builder/installation/licensing-model.md new file mode 100644 index 00000000000..ce65f8d70b4 --- /dev/null +++ b/15/umbraco-ui-builder/installation/licensing-model.md @@ -0,0 +1,122 @@ +# Licensing + +Umbraco UI Builder is a commercial product. You can run an Umbraco UI Builder unrestricted locally without the need a license. Running Umbraco UI Builder on a public domain will display a warning banner in the backoffice and will limit usage to a single editable collection. To remove these restrictions, you'll need to have a **valid license**. + +## How does it work? + +Licenses are sold per backoffice domain and will also work on all subdomains. If you have alternative staging/qa environment domains, additional domains can be added to the license on request. + +{% hint style="info" %} +The licenses are not bound to a specific product version. They will work for all versions of the related product. +{% endhint %} + +Let's say that you have a license configured for your domain, `mysite.com`, and you've requested two development domains, `devdomain.com` and `devdomain2.com`. + +The license will cover the following domains: + +* `localhost` +* `*.local` +* `*.mysite.com` +* `www.mysite.com` +* `devdomain.com` +* `www.devdomain.com` +* `devdomain2.com` +* `www.devdomain2.com` + +{% hint style="info" %} +You can have only 1 license per Umbraco installation. +{% endhint %} + +## What does a license cover? + +There are a few differences as to what the licenses cover: + +* A single license covers the installation of Umbraco UI Builder in 1 production backoffice domain, as well as in any requested development domains. +* The production domain includes **all subdomains** (e.g. `*.mysite.com`). +* The development domains work with or without the `www` subdomain. +* The license allows for an unlimited number of editable collections. +* The license also includes `localhost` and `*.local` as a valid domain. + +{% hint style="info" %} +If you have multiple backoffice domains pointing at the same installation, you can purchase and [add **additional domains**](licensing-model.md#add-additional-domains) to your license. + +This is an add-on domain for existing licenses. Refunds will not be given for this product. +{% endhint %} + +## Configuring your license + +You can look at the pricing, features, and purchase a license on the [Umbraco UI Builder](https://umbraco.com/products/add-ons/ui-builder/) page. On this page, you can fill out the form with your project details and requirements. A member of the Sales team will manage this process. In the process, you will need to provide all domains you wish to have covered by the license such as primary and staging/QA domains. You should then receive a license code to be installed in your solution. + +### Add additional domains + +If you require to add additional domains to the license, [reach out to the sales team](https://umbraco.com/products/add-ons/ui-builder/). They will manage your request and take care of the process. + +## Installing your license + +Once you have received your license code it needs to be installed on your site. + +1. Open the root directory for your project files. +2. Locate and open the `appSettings.json` file. +3. Add your Umbraco UI builder license key to `Umbraco:Licenses:Umbraco.UIBuilder`: + +```json +"Umbraco": { + "Licenses": { + "Products": { + "Umbraco.UIBuilder": "YOUR_LICENSE_KEY" + } + } +} +``` + +### Verify the license installation + +You can verify that your license is successfully installed by logging into your project's backoffice and navigating to the settings section. Here you will see a license dashboard which should display the status of your license. + +### Validating a license without an outgoing Internet connection + +Some Umbraco installations will have a highly locked down production environment, with firewall rules that prevent outgoing HTTP requests. This will interfere with the normal process of license validation. + +On start-up, and periodically whilst Umbraco is running, the license component used by Umbraco UIBuilder will make an HTTP POST request to `https://license-validation.umbraco.com/api/ValidateLicense`. + +If it's possible to do so, the firewall rules should be adjusted to allow this request. + +If such a change is not feasible, there is another approach you can use. + +You will need to have a server, or serverless function, that is running and can make a request to the online license validation service. That needs to run on a daily schedule, making a request and relaying it onto the restricted Umbraco environment. + +To set this up, firstly ensure you have a reference to `Umbraco.Licenses` version 13.1 or higher. If the version of UIBuilder you are using depends on an earlier version, you can add a direct package reference for `Umbraco.Licenses`. + +Then configure a random string as an authorization key in configuration. This is used as protection to ensure only valid requests are handled. You can also disable the normal regular license checks - as there is no point in these running if they will be blocked: + +```json + "Umbraco": { + "Licenses": { + "Umbraco.UIBuilder": "" + }, + "LicensesOptions": { + "EnableScheduledValidation": false, + "ValidatedLicenseRelayAuthKey": "" + } +``` + +Your Internet enabled server should make a request of the following form to the online license validation service: + +``` +POST https://license-validation.umbraco.com/api/ValidateLicense +{ + "ProductId": "Umbraco.UIBuilder", + "LicenseKey": "", + "Domain": "" +} +``` + +The response should be relayed exactly via an HTTP request to your restricted Umbraco environment: + +``` +POST http:///umbraco/licenses/validatedLicense/relay?productId=&licenseKey= +``` + +A header with a key of `X-AUTH-KEY` and value of the authorization key you have configured should be provided. + +This will trigger the same processes that occur when the normal scheduled validation completes ensuring your product is considered licensed. diff --git a/15/umbraco-ui-builder/known-issues.md b/15/umbraco-ui-builder/known-issues.md new file mode 100644 index 00000000000..85b12468416 --- /dev/null +++ b/15/umbraco-ui-builder/known-issues.md @@ -0,0 +1,13 @@ +--- +description: Known issues in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Known Issues + +Umbraco UI Builder tries its best to mimic the content pipeline as closely as possible whilst sticking to public and supported APIs. This is so that the Data Type suite can be used fully for editing properties. There are some features in the Umbraco Core that are locked away in internal methods. This means that some features may not be fully supported. Below is a list of known issues to date. + +## Property Editors + +### Tags + +Whilst we have support for persisting the tag's value, we don't currently have the ability to write these tags to the `cmsTags` DB table. This is all handled via a `tagsRepository` which is internal so we currently can't save to it as core does. diff --git a/15/umbraco-ui-builder/miscellaneous/conventions.md b/15/umbraco-ui-builder/miscellaneous/conventions.md new file mode 100644 index 00000000000..3715219a956 --- /dev/null +++ b/15/umbraco-ui-builder/miscellaneous/conventions.md @@ -0,0 +1,25 @@ +--- +description: Conventions used by Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Conventions + +## Fluent Conventions + +Most configuration methods in Umbraco UI Builder aim to be fluent. This means that they return a relevant config instance allowing to chain multiple methods calls together in one. For those who prefer to be a bit more verbose, many methods also accept an optional lambda expression. This allows you to pass in a delegate to perform the inner configuration of the element being defined. + +```csharp +// Chaining example +config.AddSection("Repositories").Tree().AddCollection(p => p.Id, "Person", "People"); + +// Delegate example +config.AddSection("Repositories", sectionConfig => { + sectionConfig.Tree(treeConfig => { + treeConfig.AddCollection(p => p.Id, "Person", "People"); + }); +}); +``` + +## Naming Conventions + +Throughout the API, where a method name starts with **Add** then multiple configurations can be declared. Whereas if a method name starts with **Set** then only one instance of the configuration can be declared within the current configuration context. diff --git a/15/umbraco-ui-builder/miscellaneous/umbraco-aliases.md b/15/umbraco-ui-builder/miscellaneous/umbraco-aliases.md new file mode 100644 index 00000000000..a8a49526190 --- /dev/null +++ b/15/umbraco-ui-builder/miscellaneous/umbraco-aliases.md @@ -0,0 +1,92 @@ +--- +description: A list of useful Umbraco aliases for use with Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Umbraco Aliases + +In a number of places in the Umbraco UI Builder API, you are required to know the aliases of other elements. For example, when you are adding sections, context apps, or dashboards before/after other instances. This is basic enough when it's referencing aliases of things defined in the Umbraco UI Builder config. However, for existing Umbraco instances it can be hard to find them so below is documented a number of known aliases for different elements. + +## Dashboard aliases + +### **Content** + +| Name | Alias | +| -- | -- | +| Getting Started | `contentIntro` | +| Redirect URL Management | `contentRedirectManager` | + +### **Media** + +| Name | Alias | +| -- | -- | +| Content | `mediaFolderBrowser` | + +### **Settings** + +| Name | Alias | +| -- | -- | +| Welcome | `settingsWelcome` | +| Examine Management | `settingsExamine` | +| Published Status | `settingsPublishedStatus` | +| Models Builder | `settingsModelsBuilder` | +| Health Check | `settingsHealthCheck` | + +### **Members** + +| Name | Alias | +| -- | -- | +| Getting Started | `memberIntro` | + +## Content App aliases + +### **Content** + +| Name | Alias | +| -- | -- | +| Content | `umbContent` | +| Info | `umbInfo` | + +### **Media** + +| Name | Alias | +| -- | -- | +| Content | `umbContent` | +| Info | `umbInfo` | + +### **Members** + +| Name | Alias | +| -- | -- | +| Content | `umbContent` | +| Info | `umbInfo` | + +### **ContentTypes** + +| Name | Alias | +| -- | -- | +| Design | `design` | +| List View | `listView` | +| Permissions | `permissions` | +| Templates | `templates` | + +## Section aliases + +| Name | Alias | +| -- | -- | +| Content | `content` | +| Media | `media` | +| Settings | `settings` | +| Packages | `packages` | +| Users | `users` | +| Members | `member` | +| Forms | `forms` | +| Translation | `translation` | + +## Tree aliases + +| Name | Alias | +| -- | -- | +| Content | `content` | +| Media | `media` | +| Members | `member` | +| Member Groups | `memberGroups` | diff --git a/15/umbraco-ui-builder/property-editors/entity-picker.md b/15/umbraco-ui-builder/property-editors/entity-picker.md new file mode 100644 index 00000000000..16e23ab2f5f --- /dev/null +++ b/15/umbraco-ui-builder/property-editors/entity-picker.md @@ -0,0 +1,48 @@ +--- +description: Using the entity picker property editor with Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Entity Picker + +The Entity Picker property editor is an Umbraco property editor that lets you select one or more entities from an Umbraco UI Builder collection. + +## Configuring an entity picker + +To configure an entity picker you need to create a Data Type in the Umbraco backoffice. From the property editor dropdown choose 'Umbraco UI Builder Entity Picker'. + +![Data Type config](../images/entity_picker_config.png) + +From there choose 'Section' and 'Collection' you wish to pick entities from. You can also choose an optional list view 'Data View' if there are any configured. + +You can also set a minimum and maximum number of items to be able to pick if required. + +With an entity picker Data Type defined, finish off the configuration by adding it to the desired Document Type definition. + +![Document Type config](../images/entity_picker_setup.png) + +## Using an entity picker + +Using the entity picker should be pretty familiar as it aims to mimic the content picker as closely as possible. + +To pick an entity click the 'Add' link to launch the picker dialog. The dialog should present a paginated list of entities to pick from. If any searchable fields were configured for the entity type, you can perform a search by typing a search term in the search input field. + +![Entity picker dialog](../images/entity_picker_search.png) + +To pick your items click on the entity names and then click 'Select' in the bottom right-hand corner. + +The picker should display a summary of the selected entities which can be sorted by dragging the selected entities into the desired order. + +![Entity picker values](../images/entity_picker_picked.png) + +To save the value either **save** or **save and publish** the current document. + +## Getting the value of an entity picker + +The entity picker property editor comes with a built-in [value converter](https://docs.umbraco.com/umbraco-cms/extending/property-editors/property-value-converters/). This means that whenever you retrieve the property value from Umbraco it will return the actual selected entities, even converting them to the relevant type. + +````csharp +// Example +foreach(var p in Model.People){ + ... +} +```` diff --git a/15/umbraco-ui-builder/property-editors/overview.md b/15/umbraco-ui-builder/property-editors/overview.md new file mode 100644 index 00000000000..59f17f6be6b --- /dev/null +++ b/15/umbraco-ui-builder/property-editors/overview.md @@ -0,0 +1,13 @@ +--- +description: Property Editors available with Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Property Editors + +As well as the API for managing your custom data source, Umbraco UI Builder also comes with some property editors. Those property editors help you work with your data inside Umbraco content nodes. + +The property editors available are: + +{% content-ref url="entity-picker.md" %} +[Entity Picker](entity-picker.md) +{% endcontent-ref %} diff --git a/15/umbraco-ui-builder/release-notes.md b/15/umbraco-ui-builder/release-notes.md new file mode 100644 index 00000000000..4e85660a1e4 --- /dev/null +++ b/15/umbraco-ui-builder/release-notes.md @@ -0,0 +1,23 @@ +--- +description: >- + Get an overview of the things changed and fixed in each version of Umbraco UI + Builder. +--- + +# Release Notes + +In this section, we have summarized the changes to Umbraco UI Builder released in each version. Each version is presented with a link to the [UI Builder issue tracker](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues) showing a list of issues resolved in the release. We also link to the individual issues themselves from the detail. + +If there are any breaking changes or other issues to be aware of when upgrading they are also noted here. + +{% hint style="info" %} +If you are upgrading to a new major version, check the breaking changes in the [Version Specific Upgrade Notes](upgrading/version-specific.md) article. +{% endhint %} + +## Release History + +This section contains the release notes for Umbraco UI Builder 14 including all changes for this version. + +## Legacy release notes + +You can find the release notes for **Konstrukt** in the [Change log file on Github](changelog-archive/changelog.md). diff --git a/15/umbraco-ui-builder/searching/overview.md b/15/umbraco-ui-builder/searching/overview.md new file mode 100644 index 00000000000..3d91fcb6f60 --- /dev/null +++ b/15/umbraco-ui-builder/searching/overview.md @@ -0,0 +1,15 @@ +--- +description: Configuring searching in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Searching + +Beyond listing collection entities, if you need to be able to locate specific entities within a collection then Umbraco UI Builder provides a search API. + +![Search](../images/search.png) + +Get started by reviewing how to define searchable properties. + +{% content-ref url="searchable-properties.md" %} +[searchable-properties.md](searchable-properties.md) +{% endcontent-ref %} diff --git a/15/umbraco-ui-builder/searching/searchable-properties.md b/15/umbraco-ui-builder/searching/searchable-properties.md new file mode 100644 index 00000000000..0d9646a3da1 --- /dev/null +++ b/15/umbraco-ui-builder/searching/searchable-properties.md @@ -0,0 +1,23 @@ +--- +description: Configuring searchable properties in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# Searchable Properties + +Searchable properties allow you to define any `String` based properties on a model. They will be searchable via Umbraco UI Builder's list view and entity picker search controls. + +You can also use any `String` based property of nested objects of a model, as long as the parent object is not null. + +![Search](../images/search.png) + +## Defining searchable properties + +### **AddSearchableProperty(Lambda searchablePropertyExpression) : CollectionConfigBuilder<TEntityType>** + +Adds the given property to the searchable properties collection. + +````csharp +// Example +collectionConfig.AddSearchableProperty(p => p.FirstName); +collectionConfig.AddSearchableProperty(p => p.Address.Street); +```` diff --git a/15/umbraco-ui-builder/upgrading/migrating-from-konstrukt-to-umbraco-ui-builder.md b/15/umbraco-ui-builder/upgrading/migrating-from-konstrukt-to-umbraco-ui-builder.md new file mode 100644 index 00000000000..7d806be207d --- /dev/null +++ b/15/umbraco-ui-builder/upgrading/migrating-from-konstrukt-to-umbraco-ui-builder.md @@ -0,0 +1,115 @@ +--- +description: Learn how to migrate a Konstrukt solution to Umbraco UI Builder. +--- + +# Migrate from Konstrukt to Umbraco UI Builder + +This guide provides a step-by-step approach to migrating a default Konstrukt solution to Umbraco UI Builder. + +## Key changes + +Before outlining the exact steps, there are a few key changes to be aware of. + +These changes will dictate the steps to take in the process of migrating to Umbraco UI Builder. + +### Project, Package, and Namespace changes + +| Konstrukt | Umbraco UI Builder | +| ------------------------------- | --------------------------------------- | +| Konstrukt.Core | Umbraco.UIBuilder.Core | +| Konstrukt.Infrastructure | Umbraco.UIBuilder.Infrastructure | +| Konstrukt.Web | Umbraco.UIBuilder.Web | +| Konstrukt.Web.UI | Umbraco.UIBuilder.Web.StaticAssets | +| Konstrukt.Startup | Umbraco.UIBuilder.Startup | +| Konstrukt | Umbraco.UIBuilder | + +
+ +C# Class changes + +* Namespace changes as documented above. +* Most classes prefixed with the `Konstrukt` keyword have had this prefix removed. + * Examples: `IKonstruktRepository` is now `IRepository` + * Exclusions: The root level `KonstruktConfig` and `KonstruktConfigBuilder` have a `UIBuilder` prefix instead, and the `AddKonstrukt` extension for `IUmbracoBuilder` has been replaced by `AddUIBuilder` + +
+ +
+ +JavaScript changes + +* All `Konstrukt` controllers have changed namespace to `Umbraco.UIBuilder`. +* All `Konstrukt` prefixed directives, services, and resources are now prefixed with `uibuilder`. + +
+ +
+ +UI Changes + +* All static UI assets are served via a Razor Compiled Library (RCL) and are no longer found in the `App_Plugins` folder. +* The folder with `App_Plugins` has been renamed from `Konstrukt` to `UmbracoUIBuilder`. + +
+ +## Step 1: Replace dependencies + +In this first step, we will be replacing all existing Konstrukt dependencies with Umbraco UI Builder dependencies. + +1. Remove any installed Konstrukt packages: + +```bash +dotnet remove package Konstrukt +``` + +2. Delete the Konstrukt `App_Plugins` folder: + +```bash +rmdir App_Plugins\Konstrukt +``` + +3. Install `Umbraco.UIBuilder`: + +```bash +dotnet add package Umbraco.UIBuilder +``` + +4. Compile your project against .NET 7.0. + +## Step 2: Update namespaces and entity names + +Based on the [Key Changes](./#key-changes) outlined above update all Konstrukt references to the new Umbraco UI Builder alternatives. Ensure you update any Views/Partials that also reference these. + +## Step 3: Update your configuration + +If all your configuration is in a single statement, it would be a case of swapping `AddKonstrukt` to `AddUIBuilder`. If you broke your configuration into multiple steps, or are using `Action` or `Card` classes, you will need to update the config builder/base classes. Those classes need to be updated to their UI Builder alternative names as detailed in [Key Changes](./#key-changes). + + +```csharp +builder.CreateUmbracoBuilder() + .AddBackOffice() + .AddWebsite() + .AddDeliveryApi() + .AddComposers() + .AddUIBuilder(cfg => { + // The rest of your configuration + }) + .Build(); +``` + +## Step 4: Finalizing the migration + +1. Delete any obj/bin folders in your projects to ensure a clean build. +2. Recompile all projects and ensure all dependencies are restored correctly +3. Delete the existing Konstrukt license files in the `umbraco\Licenses` folder. +4. Add your new Umbraco.UIBuilder license key to the `appSettings.json` file: + +```json +"Umbraco": { + "Licenses": { + "Umbraco.UIBuilder": "YOUR_LICENSE_KEY" + } +} +``` + +5. Run the project. diff --git a/15/umbraco-ui-builder/upgrading/upgrade.md b/15/umbraco-ui-builder/upgrading/upgrade.md new file mode 100644 index 00000000000..711a4715aed --- /dev/null +++ b/15/umbraco-ui-builder/upgrading/upgrade.md @@ -0,0 +1,46 @@ +# Upgrading Umbraco UI Builder + +This article shows how to manually upgrade Umbraco UI Builder to run the latest version. +When upgrading Umbraco UI Builder, be sure to also consult the [version specific upgrade](version-specific.md) notes to learn about potential breaking changes and common pitfalls. + +{% hint style="warning" %} +Before upgrading, it is always advisable to take a complete backup of your site and database. +{% endhint %} + +## Get the latest version of Umbraco UI Builder + +To upgrade to the latest version of Umbraco UI Builder you can use: + +- NuGet +- Visual Studio + +### NuGet + +- NuGet installs the latest version of the package when you use the `dotnet add package Umbraco.UIBuilder` command unless you specify a package version: `dotnet add package Umbraco.UIBuilder --version ` + +- After you have added a package reference to your project by executing the `dotnet add package Umbraco.UIBuilder` command in the directory that contains your project file, run `dotnet restore` to install the package. + + +### Visual Studio + +1. Go to `Tools` -> `NuGet Package Manager` -> `Manage NuGet Packages for Solution...` in Visual Studio, to upgrade Umbraco UI Builder: +2. Select **Umbraco.UIBuilder**. +3. Select the latest version from the Version drop-down and click Install. +4. When the command completes, open the **.csproj** file to make sure the package reference is updated: + +```xml + + + +``` + +If you are using one or more of the below sub-packages, they also need to be upgraded as well: + +| Sub-package | Description | +| -- | -- | +| Umbraco.UIBuilder.Core | Core UI Builder functionality that doesn't require any infrastructure-specific dependencies | +| Umbraco.UIBuilder.Infrastructure | Infrastructure-specific project containing implementations of core UI Builder functionality | +| Umbraco.UIBuilder.Web | The core UI Builder logic that requires a web context | +| Umbraco.UIBuilder.Web.StaticAssets | The static assets for the UI Builder presentation layer | +| Umbraco.UIBuilder.Startup | The main logic for registering UI Builder with Umbraco | +| Umbraco.UIBuilder | The main UI Builder package | \ No newline at end of file diff --git a/15/umbraco-ui-builder/upgrading/version-specific.md b/15/umbraco-ui-builder/upgrading/version-specific.md new file mode 100644 index 00000000000..5a428f4a5e2 --- /dev/null +++ b/15/umbraco-ui-builder/upgrading/version-specific.md @@ -0,0 +1,22 @@ +--- +description: >- + Version specific documentation for upgrading to new major versions of Umbraco UI Builder. +--- + +# Version Specific Upgrade Notes + +This page covers specific upgrade documentation for when migrating to major 14 of Umbraco UI Builder. + +{% hint style="info" %} +If you are upgrading to a new minor or patch version, you can find information about the breaking changes in the [Release Notes](../release-notes.md) article. +{% endhint %} + +## Version Specific Upgrade Notes History + +Version 14 contains a number of breaking changes from the previous, Konstrukt product. + +See the [Migrate from Konstrukt to Umbraco UI Builder guide](./migrating-from-konstrukt-to-umbraco-ui-builder.md) for full details. + +## Legacy version specific upgrade notes + +You can find the version specific upgrade notes for versions out of support in the [Legacy documentation on Github](https://github.com/umbraco/UmbracoDocs/tree/umbraco-eol-versions).