Remove Episerver UI components for certain editors
May 10, 2016
Episerver has a powerful UI that makes it very easy for editors to create and edit content in an on-page and a drag and drop way. However I was recently talking to a customer who are going to have a larger editor estate (> 500 people) and wanted 2 types of editors. The first type are editors who are trained and are familiar with Episerver. These editors can use the UI as normal for creating and editing content.
The second type of editor is more interesting. They should only be able edit existing content, often only on a single page. These editors require a very cut down version of the Episerver UI with "super simple" editor functions. So this post describes how its possible to hide certain Episerver UI elements for certain groups of editors.
Identifying the "restricted" users
First of all we need to identify our restricted users. For the code in the rest of this example we check on a role called "restrictedusers". This is a simple implementation that we can use to decide if a user is restricted or not but can be modified as necessary in your own implementation:
public interface IUserIsRestricted { bool UserIsRestricted(); }
[ServiceConfiguration(typeof(IUserIsRestricted))] public class RestrictedUser : IUserIsRestricted { public bool UserIsRestricted() { //Any implementation you wish, this is for simplicity return HttpContext.Current.User.IsInRole("RestrictedUser"); } }
Removing UI components
Now we can start to look at removing UI components such as the sites tab, media and even the page tree. Fortunately it's possible to remove components with a simple IViewTransformer implementation:
[ViewTransformer] public class RestrictedUserViewTransformer : IViewTransformer { public int SortOrder { get { return int.MaxValue; } } public void TransformView(ICompositeView view, IPrincipal principal) { if (ServiceLocator.Current.GetInstance().UserIsRestricted()) { List components = new List (); BuildListRecursively(view.RootContainer, components); view.RootContainer.RemoveComponentsRecursive(components, false); } } private void BuildListRecursively(IContainer parentContainer, List components) { foreach (IComponent component in parentContainer.Components) { IContainer childContainer = component as IContainer; if (childContainer != null) { BuildListRecursively(childContainer, components); } else { if (component.DefinitionName != "EPiServer.Cms.Shell.UI.Components.WidgetSwitcher") { // Remove everything apart from the main toolbar AddComponent(components, component.DefinitionName); } } } } private void AddComponent(List components, string definitionName) { ConfigurationComponentMatcher item = new ConfigurationComponentMatcher(definitionName); components.Add(item); } private class ConfigurationComponentMatcher : IComponentMatcher, IContainerMatcher { // Fields private readonly string _definitionName; // Methods public ConfigurationComponentMatcher(string definitionName) { this._definitionName = definitionName; } public bool MatchesComponent(IComponent component) { return string.Equals(this._definitionName, component.DefinitionName, StringComparison.OrdinalIgnoreCase); } public bool MatchesContainer(IContainer container) { return true; } } }
This code removes all components in the UI apart from the content itself which is the "EPiServer.Cms.Shell.UI.Components.WidgetSwitcher" component. It's possible to decide which components you do/do not want to remove by the component name. All Episerver component names are prefixed with "EPiServer.Cms.Shell.UI.Components" and following table shows some of the built in components that ship with Episerver:
Component ID | UI element |
---|---|
PageTreeComponent | |
SiteTreeComponent | |
Tasks | |
ProjectChangesComponent | |
RecentItems | |
ProjectModeToolbarComponent | |
Toolbar | |
SharedBlocksComponent | |
MediaComponent |
It should be noted that if you remove all the components from a panel then the panel itself will disappear. For example if you remove the "SharedBlocksComponent" and "MediaComponent" (blocks and media) then the right hand pin-able panel will disappear.
Removing the preview buttons (preview, channels etc)
It may be desirable not to remove the entire tool bar that sits about the content in the UI and only remove some of the buttons:
To achieve this we can use a little Dojo and the Episerver profile. This module can hide tool bar buttons if the user is a restricted user. Create a file called CustomiseToolbar.js in /ClientResource/Scripts/CustomUI/
[[dojo code]]
define([ "dojo/_base/declare", "dojo/_base/lang", "dojo/topic", "dojo/when", "epi/dependency" ], function ( declare, lang, topic, when, dependency ) { return declare([], { initialize: function () { this.inherited(arguments); // Check if the user is restricted using the profile (this is accessible client and server side) var profile = dependency.resolve("epi.shell.Profile"); if (profile) { // Profile returns a promise so we wait for this before checking the value when(profile.get("restricteduser"), function (restricteduser) { if (restricteduser === true) { // Get the global command registry var registry = dependency.resolve('epi.globalcommandregistry'); // Clear the toolbar -- these are the buttons at the top of the UI for previewing as // visitor groups etc. var newProviders = []; // It's also possible to remove or use single items as below: // The Add button plus access to the left/right pinnable areas //newProviders.push(registry._mappings['epi.cms.globalToolbar'].providers[0]); // View options (view as visitor group, preview button) //newProviders.push(registry._mappings['epi.cms.globalToolbar'].providers[1]); // Compare button //newProviders.push(registry._mappings['epi.cms.globalToolbar'].providers[2]); registry._mappings['epi.cms.globalToolbar'].providers = newProviders; } }); } } }); });
Merge this in module.config to initialise the component:
You may have noticed we are using the Episerver Shell Profile. This is a common profile that can be used server and client side. To set up the profile server side we can use an Episerver initialisation module to set a value for "restricteduser" (note the implementation is just an example and your implementation will probably differ!
[InitializableModule] [ModuleDependency(typeof (EPiServer.Web.InitializationModule))] public class RestrictedUserInit : IInitializableHttpModule { public void InitializeHttpEvents(HttpApplication application) { application.PostAuthenticateRequest += Application_PostAuthenticateRequest; } private void Application_PostAuthenticateRequest(object sender, EventArgs e) { //Assumes use of session. Better place for this check would be on the log //in controller for your site (if not using the default log in page) if (HttpContext.Current.User.Identity.IsAuthenticated && HttpContext.Current.Session != null && HttpContext.Current.Session["restricteduser_run"] == null) { // We only need this code to run once HttpContext.Current.Session["restricteduser_run"] = true; const string restrictedUserKey = "restricteduser"; var profileRepo = ServiceLocator.Current.GetInstance(); var profile = profileRepo.GetOrCreateProfile(HttpContext.Current.User.Identity.Name); profile.Settings[restrictedUserKey] = true; // Saving to the profile allows us to access this value in the client side UI profileRepo.Save(profile); } } public void Initialize(InitializationEngine context) { } public void Uninitialize(InitializationEngine context) { } }
Once all of this is complete its possible to remove different tool bar buttons. The index of the registry._mappings['epi.cms.globalToolbar'].providers items is as follows:
Index | UI element |
---|---|
[0] - The Add button plus access to the left/right pinnable areas | |
[1] -View options (view as visitor group, preview button) | |
[2] - Compare button | |
[3] - Notifications |
The finished product
When all the changes above have been applied a user will see the following UI when the hit the Episerver button on a page:
As you can see its very simple, offering a highly simplified page editing experience plus a publish button.
Conclusion
Episerver has a powerful UI that very simple for users. However in scenarios where we want users to focus on a single task then its possible to simplify the UI even further to ensure editors can focus on what they do best: creating and editing content.
Have you done anything similar to this? Have you faced this solution in another way? I’d be happy to discuss in the comments below or on @davidknipe.