Simplifying dashboard management.

This removes the ability to edit multiple dashboards in favor of a simplified way for users to edit the default dashboard.
This commit is contained in:
Sipke Schoorstra
2015-05-20 01:27:53 +02:00
parent 865f583be2
commit 316c6e3262
13 changed files with 121 additions and 255 deletions

View File

@@ -7,13 +7,8 @@ namespace Orchard.Dashboards {
public void GetNavigation(NavigationBuilder builder) {
builder.Add(T("Settings"), settings => settings
.Add(T("Dashboards"), "16", dashboard => dashboard
.Add(T("Settings"), "5", dashboardSettings => dashboardSettings
.Action("Index", "Settings", new { area = "Orchard.Dashboards" })
.LocalNav())
.Add(T("Manage Dashboards"), "6", manageDashboards => manageDashboards
.Action("List", "Dashboard", new { area = "Orchard.Dashboards" })
.LocalNav())));
.Add(T("Dashboard"), "16", dashboard => dashboard
.Action("Edit", "Dashboard", new { area = "Orchard.Dashboards" })));
}
}
}

View File

@@ -1,31 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Orchard.ContentManagement;
using Orchard.Core.Common.Models;
using Orchard.Core.Contents.ViewModels;
using Orchard.Dashboards.Services;
using Orchard.Localization;
using Orchard.Localization.Services;
using Orchard.Mvc;
using Orchard.UI.Admin;
using Orchard.UI.Navigation;
using Orchard.UI.Notify;
namespace Orchard.Dashboards.Controllers {
[Admin]
public class DashboardController : Controller {
[ValidateInput(false)]
public class DashboardController : Controller, IUpdateModel {
private readonly IDashboardService _dashboardService;
private readonly IOrchardServices _services;
private readonly ICultureFilter _cultureFilter;
private readonly ICultureManager _cultureManager;
public DashboardController(IDashboardService dashboardService, IOrchardServices services, ICultureFilter cultureFilter, ICultureManager cultureManager) {
public DashboardController(IDashboardService dashboardService, IOrchardServices services) {
_dashboardService = dashboardService;
_services = services;
_cultureFilter = cultureFilter;
_cultureManager = cultureManager;
T = NullLocalizer.Instance;
}
@@ -36,123 +27,52 @@ namespace Orchard.Dashboards.Controllers {
return new ShapeResult(this, shape);
}
public ActionResult List(ListContentsViewModel model, PagerParameters pagerParameters) {
var pager = new Pager(_services.WorkContext.CurrentSite, pagerParameters);
VersionOptions versionOptions;
switch (model.Options.ContentsStatus) {
case ContentsStatus.Published:
versionOptions = VersionOptions.Published;
break;
case ContentsStatus.Draft:
versionOptions = VersionOptions.Draft;
break;
case ContentsStatus.AllVersions:
versionOptions = VersionOptions.AllVersions;
break;
default:
versionOptions = VersionOptions.Latest;
break;
}
var query = _services.ContentManager.Query(versionOptions, "Dashboard");
switch (model.Options.OrderBy) {
case ContentsOrder.Modified:
query = query.OrderByDescending<CommonPartRecord>(cr => cr.ModifiedUtc);
break;
case ContentsOrder.Published:
query = query.OrderByDescending<CommonPartRecord>(cr => cr.PublishedUtc);
break;
case ContentsOrder.Created:
query = query.OrderByDescending<CommonPartRecord>(cr => cr.CreatedUtc);
break;
}
if (!String.IsNullOrWhiteSpace(model.Options.SelectedCulture)) {
query = _cultureFilter.FilterCulture(query, model.Options.SelectedCulture);
}
model.Options.Cultures = _cultureManager.ListCultures();
var maxPagedCount = _services.WorkContext.CurrentSite.MaxPagedCount;
if (maxPagedCount > 0 && pager.PageSize > maxPagedCount)
pager.PageSize = maxPagedCount;
var pagerShape = _services.New.Pager(pager).TotalItemCount(maxPagedCount > 0 ? maxPagedCount : query.Count());
var pageOfContentItems = query.Slice(pager.GetStartIndex(), pager.PageSize).ToList();
var list = _services.New.List();
list.AddRange(pageOfContentItems.Select(ci => _services.ContentManager.BuildDisplay(ci, "SummaryAdmin")));
var viewModel = _services.New.ViewModel()
.ContentItems(list)
.Pager(pagerShape)
.Options(model.Options)
.TypeDisplayName(model.TypeDisplayName ?? "");
return View(viewModel);
public ActionResult Edit() {
var dashboard = _dashboardService.GetDashboardDescriptor();
var editor = dashboard.Editor(_services.New);
return View(editor);
}
[HttpPost, ActionName("List")]
[FormValueRequired("submit.Filter")]
public ActionResult ListFilterPOST(ContentOptions options) {
var routeValues = ControllerContext.RouteData.Values;
if (options != null) {
routeValues["Options.SelectedCulture"] = options.SelectedCulture; //todo: don't hard-code the key
routeValues["Options.OrderBy"] = options.OrderBy; //todo: don't hard-code the key
routeValues["Options.ContentsStatus"] = options.ContentsStatus; //todo: don't hard-code the key
}
return RedirectToAction("List", routeValues);
[ActionName("Edit")]
[HttpPost]
[FormValueRequired("submit.Save")]
public ActionResult Save() {
return UpdateDashboard(dashboard => _services.Notifier.Information(T("Your dashboard has been saved.")));
}
[HttpPost, ActionName("List")]
[FormValueRequired("submit.BulkEdit")]
public ActionResult ListPOST(ContentOptions options, IEnumerable<int> itemIds, string returnUrl) {
if (itemIds != null) {
var checkedContentItems = _services.ContentManager.GetMany<ContentItem>(itemIds, VersionOptions.Latest, QueryHints.Empty);
switch (options.BulkAction) {
case ContentsBulkAction.None:
break;
case ContentsBulkAction.PublishNow:
foreach (var item in checkedContentItems) {
if (!_services.Authorizer.Authorize(Core.Contents.Permissions.PublishContent, item, T("Couldn't publish selected content."))) {
_services.TransactionManager.Cancel();
return new HttpUnauthorizedResult();
}
[ActionName("Edit")]
[HttpPost]
[FormValueRequired("submit.Publish")]
public ActionResult Publish() {
return UpdateDashboard(dashboard => {
_services.Notifier.Information(T("Your dashboard has been published."));
_services.ContentManager.Publish(dashboard);
});
}
_services.ContentManager.Publish(item);
}
_services.Notifier.Information(T("Content successfully published."));
break;
case ContentsBulkAction.Unpublish:
foreach (var item in checkedContentItems) {
if (!_services.Authorizer.Authorize(Core.Contents.Permissions.PublishContent, item, T("Couldn't unpublish selected content."))) {
_services.TransactionManager.Cancel();
return new HttpUnauthorizedResult();
}
private ActionResult UpdateDashboard(Action<ContentItem> conditonallyPublish) {
var dashboard = _dashboardService.GetDashboardDescriptor();
var editor = dashboard.UpdateEditor(_services.New, this);
_services.ContentManager.Unpublish(item);
}
_services.Notifier.Information(T("Content successfully unpublished."));
break;
case ContentsBulkAction.Remove:
foreach (var item in checkedContentItems) {
if (!_services.Authorizer.Authorize(Core.Contents.Permissions.DeleteContent, item, T("Couldn't remove selected content."))) {
_services.TransactionManager.Cancel();
return new HttpUnauthorizedResult();
}
_services.ContentManager.Remove(item);
}
_services.Notifier.Information(T("Content successfully removed."));
break;
default:
throw new ArgumentOutOfRangeException();
}
if (!ModelState.IsValid) {
_services.TransactionManager.Cancel();
return View(editor);
}
return RedirectToAction("List");
var contentItem = (ContentItem)editor.ContentItem;
if (contentItem != null)
conditonallyPublish(contentItem);
return RedirectToAction("Edit");
}
bool IUpdateModel.TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) {
return TryUpdateModel(model, prefix, includeProperties, excludeProperties);
}
void IUpdateModel.AddModelError(string key, LocalizedString errorMessage) {
ModelState.AddModelError(key, errorMessage.ToString());
}
}
}

View File

@@ -1,59 +0,0 @@
using System;
using System.Linq;
using System.Web.Mvc;
using Orchard.ContentManagement;
using Orchard.Dashboards.Models;
using Orchard.Dashboards.ViewModels;
using Orchard.Localization;
using Orchard.UI.Admin;
using Orchard.UI.Notify;
namespace Orchard.Dashboards.Controllers {
[Admin]
public class SettingsController : Controller {
private readonly IOrchardServices _services;
public SettingsController(IOrchardServices services) {
_services = services;
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
public ActionResult Index() {
var settings = _services.WorkContext.CurrentSite.As<DashboardSiteSettingsPart>();
var viewModel = new DashboardSiteSettingsViewModel {
SelectedDashboardId = settings.DefaultDashboardId.ToString(),
SelectedDashboard = settings.DefaultDashboardId != null ? _services.ContentManager.Get(settings.DefaultDashboardId.Value) : default(ContentItem)
};
return View(viewModel);
}
[HttpPost]
public ActionResult Index(DashboardSiteSettingsViewModel viewModel) {
var settings = _services.WorkContext.CurrentSite.As<DashboardSiteSettingsPart>();
if (!ModelState.IsValid) {
viewModel.SelectedDashboard = settings.DefaultDashboardId != null ? _services.ContentManager.Get(settings.DefaultDashboardId.Value) : default(ContentItem);
return View(viewModel);
}
settings.DefaultDashboardId = ParseContentId(viewModel.SelectedDashboardId);
_services.Notifier.Information(T("Dashboard settings updated."));
return RedirectToAction("Index");
}
private static int? ParseContentId(string value) {
if (String.IsNullOrWhiteSpace(value))
return null;
var items = value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
if (!items.Any())
return null;
return XmlHelper.Parse<int>(items.First());
}
}
}

File diff suppressed because one or more lines are too long

View File

@@ -10,4 +10,4 @@ Features:
Name: Dashboards
Description: The Dashboards module enables administrators to customize the dashboard screen of the administration UI of the application.
Category: Admin
Dependencies: Orchard.Layouts, Orchard.ContentPicker
Dependencies: Orchard.Layouts

View File

@@ -81,11 +81,11 @@
<Content Include="Views\Elements\Grid.Dashboard.cshtml" />
<Content Include="Views\Elements\Column.Dashboard.cshtml" />
<Content Include="Views\Parts\Layout.Dashboard.cshtml" />
<Content Include="Views\Settings\Index.cshtml" />
<Content Include="Views\Dashboard\List.cshtml">
<SubType>
</SubType>
</Content>
<Content Include="Views\Dashboard\Edit.cshtml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Orchard\Orchard.Framework.csproj">
@@ -107,23 +107,20 @@
<ItemGroup>
<Compile Include="AdminMenu.cs" />
<Compile Include="Controllers\DashboardController.cs" />
<Compile Include="Controllers\SettingsController.cs" />
<Compile Include="Drivers\DashboardSiteSettingsPartDriver.cs" />
<Compile Include="Handlers\DashboardSiteSettingsPartHandler.cs" />
<Compile Include="Migrations.cs" />
<Compile Include="Permissions.cs" />
<Compile Include="Services\DashboardService.cs" />
<Compile Include="Services\IDashboardService.cs" />
<Compile Include="Shapes\LayoutPartShape.cs" />
<Compile Include="ViewModels\DashboardSiteSettingsViewModel.cs" />
<Compile Include="Models\DashboardSiteSettingsPart.cs" />
<Compile Include="Routes.cs" />
<Compile Include="Services\DashboardDescriptor.cs" />
<Compile Include="Services\DefaultDashboardSelector.cs" />
<Compile Include="Services\IDashboardSelector.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Elements\" />
</ItemGroup>
<ItemGroup />
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>

View File

@@ -1,8 +1,11 @@
using System;
using Orchard.ContentManagement;
namespace Orchard.Dashboards.Services {
public class DashboardDescriptor {
public int Priority { get; set; }
public Func<dynamic, dynamic> DashboardFactory { get; set; }
public Func<dynamic, dynamic> Display { get; set; }
public Func<dynamic, dynamic> Editor { get; set; }
public Func<dynamic, IUpdateModel, dynamic> UpdateEditor { get; set; }
}
}

View File

@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Orchard.DisplayManagement;
namespace Orchard.Dashboards.Services {
public class DashboardService : IDashboardService {
private readonly Lazy<IEnumerable<IDashboardSelector>> _selectors;
private readonly IShapeFactory _shapeFactory;
public DashboardService(Lazy<IEnumerable<IDashboardSelector>> selectors, IShapeFactory shapeFactory) {
_selectors = selectors;
_shapeFactory = shapeFactory;
}
public DashboardDescriptor GetDashboardDescriptor() {
var selectorQuery =
from selector in _selectors.Value
let descriptor = selector.GetDashboardDescriptor()
orderby descriptor.Priority descending
select descriptor;
var result = selectorQuery.First();
return result;
}
public dynamic GetDashboardShape() {
var result = GetDashboardDescriptor();
var factory = result.Display ?? (shapeFactory => shapeFactory.StaticDashboard());
var shape = factory(_shapeFactory);
return shape;
}
}
}

File diff suppressed because one or more lines are too long

View File

@@ -1,34 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Orchard.DisplayManagement;
namespace Orchard.Dashboards.Services {
namespace Orchard.Dashboards.Services {
public interface IDashboardService : IDependency {
DashboardDescriptor GetDashboardDescriptor();
dynamic GetDashboardShape();
}
public class DashboardService : IDashboardService {
private readonly Lazy<IEnumerable<IDashboardSelector>> _selectors;
private readonly IShapeFactory _shapeFactory;
public DashboardService(Lazy<IEnumerable<IDashboardSelector>> selectors, IShapeFactory shapeFactory) {
_selectors = selectors;
_shapeFactory = shapeFactory;
}
public dynamic GetDashboardShape() {
var selectorQuery =
from selector in _selectors.Value
let descriptor = selector.GetDashboardDescriptor()
orderby descriptor.Priority descending
select descriptor;
var result = selectorQuery.First();
var factory = result.DashboardFactory ?? (shapeFactory => shapeFactory.StaticDashboard());
var shape = factory(_shapeFactory);
return shape;
}
}
}

View File

@@ -1,8 +0,0 @@
using Orchard.ContentManagement;
namespace Orchard.Dashboards.ViewModels {
public class DashboardSiteSettingsViewModel {
public string SelectedDashboardId { get; set; }
public ContentItem SelectedDashboard { get; set; }
}
}

View File

@@ -0,0 +1,9 @@
@{
var pageTitle = T("Edit Dashboard");
Layout.Title = pageTitle;
}
@using (Html.BeginFormAntiForgeryPost(Url.Action("Edit"), FormMethod.Post, new { enctype = "multipart/form-data" })) {
@Html.ValidationSummary()
@Display(Model)
}

View File

@@ -1,18 +0,0 @@
@using Orchard.ContentManagement
@model Orchard.Dashboards.ViewModels.DashboardSiteSettingsViewModel
@{
Layout.Title = T("Dashboard Settings").ToString();
}
@using (Html.BeginFormAntiForgeryPost()) {
<section>
<div class="form-group">
@Display.ContentPicker_Edit(
DisplayName: T("Default Dashboard").Text,
SelectedItemsFieldName: Html.FieldNameFor(m => m.SelectedDashboardId),
ContentItems: Model.SelectedDashboard != null ? new[] {Model.SelectedDashboard} : Enumerable.Empty<ContentItem>(),
Hint: T("Select the content item to use as the dashboard.").Text,
Types: new[]{ "Dashboard" })
</div>
</section>
<button>@T("Save")</button>
}