In my last article I described Editor’s Favourite contents functionality. The solution consisted of Add to Favourited button and Favourite Content grid widget. Both of those features were available in edit mode. When editor log in to CMS, he lands on Dashboard page. It could be an interesting feature if they could see the list of all their favourites there. I decided to further extend the functionality and prepared dashboard widget with readonly list of editor’s favourite contents.
Defining dashboard widget
Defining dashboard component is similar to regular edit mode components. We need to set client widget type and it’s class has to be annotated with Component attribute. The difference is in category property value. There are three default categories available for components:
- content
- cms
- dashboard
To allow editor to add component to his dashboard we have to use dashboard category.
The Category property is a generic IEnumerable collection of strings (IEnumerable<string>), so first I simply tried to add dashboard category to FavouriteContent component.
1 2 3 4 5 6 7 8 9 10 |
public class FavouriteContent : ComponentDefinitionBase { public FavouriteContent() : base("favourites.favouriteContentComponent") { this.Categories = new string[] {"content", "dashboard" }; // ... } } |
I run the site, but the code did not worked. It turned out that CMS module was not loaded and epi.cms.content.light store was not available. It means that I cannot reuse grid widget and had to prepare new custom component class and new custom client widget.
The component is very similar to edit mode Favourites version. I just change the category to dashboard and set client widget class to favourites.favouriteContentDashboardComponent.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
[Component] public class FavouriteContentDashboardComponent : ComponentDefinitionBase { public FavouriteContentDashboardComponent() : base("favourites.favouriteContentDashboardComponent") { Description = "Shows user favourite content"; Title = "My Favourite Content"; this.Categories = new [] { "dashboard" }; this.SortOrder = 1000; this.PlugInAreas = Enumerable.Empty<string>(); } } |
Dashboard widget
The dashboard widget is a readonly list of links. Each link displays the name and status of the content. In the constructor I get favouriteContentStore and then in buildRendering method I fetch links from server.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
define([ "dojo/_base/declare", "dojo/_base/lang", "dojo/when", "dojo/dom-construct", "dijit/_Widget", "dijit/_TemplatedMixin", "dijit/_WidgetsInTemplateMixin", "epi/epi", "epi/dependency", "epi-cms/contentediting/ContentActionSupport", "dojo/text!./content/dashboardComponentTemplate.html", "xstyle/css!./content/dashboardComponentStyles.css" ], function ( declare, lang, when, domConstruct, _Widget, _TemplatedMixin, _WidgetsInTemplateMixin, epi, dependency, ContentActionSupport, template ) { return declare([_Widget, _TemplatedMixin, _WidgetsInTemplateMixin], { templateString: template, constructor: function () { var registry = dependency.resolve("epi.storeregistry"); this.favouriteContentStore = registry.get("alloy.favouriteContentStore"); }, buildRendering: function() { this.inherited(arguments); this._refreshLinks(); }, _refreshLinks: function() { when(this.favouriteContentStore.executeMethod("GetEditModeLinks", 'getEditModeLinks')).then(lang.hitch(this, function (result) { for (var i = 0; i < result.length; i++) { var content = result[i]; var linkTitle = [ content.name, ' (', ContentActionSupport.getVersionStatus(content.status), ')' ].join(''); var linkNode = domConstruct.toDom("<li><a href='" + content.url + "'>" + linkTitle + "</li>"); domConstruct.place(linkNode, this.linkList, "last"); } })); } }); }); |
Below I showed the Favourites component added to dashboard.
New store method
I added new GetEditModeLinks method to FavouriteContentStore store class. It returns list of names, content status and edit mode URLs for favourite content. To generate URL I used public PageEditing.GetEditUrl method, but for page status (formatted name) I had to get code from EPiServer libraries, because it was marked as internal.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
[RestStore("favouriteContentStore")] public class FavouriteContentStore : RestControllerBase { ///... all other methods public ActionResult GetEditModeLinks() { var contentReferences = this._favouriteContentStorage.GetByUser(HttpContext.User); var contentList = contentReferences .Select(cr => this._contentVersionRepository.LoadCommonDraft(cr, ContentLanguage.PreferredCulture.Name)) .Select(cr => this._contentRepository.Get<IContent>(cr.ContentLink)) .Where(c => c != null) .OrderBy(c=>c.Name) .Select(c=> new { Name = c.Name, Url = PageEditing.GetEditUrl(c.ContentLink), Status = GetCalculatedStatus(c) }) .ToList(); return this.Rest(contentList); } private static ExtendedVersionStatus GetCalculatedStatus(IContent content) { IVersionable content1 = content as IVersionable; if (content1 == null) return ExtendedVersionStatus.Published; if (HasExpired(content1)) return ExtendedVersionStatus.Expired; return (ExtendedVersionStatus)content1.Status; } private static bool HasExpired(IVersionable content) { if (content.Status == VersionStatus.Published) { DateTime? stopPublish = content.StopPublish; DateTime now = DateTime.Now; if ((stopPublish.HasValue ? (stopPublish.GetValueOrDefault() < now ? 1 : 0) : 0) != 0) return true; } return false; } } |
One more thing to mention is that module.config for dashboard widget has dependency on Shell module but Edit Mode widget has CMS dependency.
1 |
<add dependency="Shell" type="RunAfter" /> |
Below is the video that shows usage of dashboard widget.