Adding some admin UI for search index management. Not yet working end-to-end but it looks like it does *

* Waiting on some pieces of the index manager/provider are being added and/or reworked then we'll get it all hooked up.

--HG--
branch : dev
This commit is contained in:
Nathan Heskew
2010-06-04 14:45:18 -07:00
parent 69e32f3d6b
commit 9ef73f84b0
12 changed files with 174 additions and 15 deletions

View File

@@ -0,0 +1,16 @@
using Orchard.Localization;
using Orchard.UI.Navigation;
namespace Orchard.Search {
public class AdminMenu : INavigationProvider {
public Localizer T { get; set; }
public string MenuName { get { return "admin"; } }
public void GetNavigation(NavigationBuilder builder) {
builder.Add(T("Site"), "11",
menu => menu
.Add(T("Search Index"), "10.0", item => item.Action("Index", "Admin", new {area = "Orchard.Search"})
.Permission(Permissions.ManageSearchIndex)));
}
}
}

View File

@@ -0,0 +1,49 @@
using System.Web.Mvc;
using Orchard.Localization;
using Orchard.Search.Services;
using Orchard.Search.ViewModels;
using Orchard.UI.Notify;
namespace Orchard.Search.Controllers {
public class AdminController : Controller {
private readonly ISearchService _searchService;
public AdminController(ISearchService searchService, IOrchardServices services) {
_searchService = searchService;
Services = services;
T = NullLocalizer.Instance;
}
public IOrchardServices Services { get; private set; }
public Localizer T { get; set; }
public ActionResult Index() {
var viewModel = new SearchIndexViewModel {HasIndexToManage = _searchService.HasIndexToManage};
if (!viewModel.HasIndexToManage)
Services.Notifier.Information(T("There is not search index to manage for this site."));
return View(viewModel);
}
[HttpPost]
public ActionResult Update() {
if (!Services.Authorizer.Authorize(Permissions.ManageSearchIndex, T("Not allowed to manage the search index.")))
return new HttpUnauthorizedResult();
_searchService.UpdateIndex();
return RedirectToAction("Index");
}
[HttpPost]
public ActionResult Rebuild() {
if (!Services.Authorizer.Authorize(Permissions.ManageSearchIndex, T("Not allowed to manage the search index.")))
return new HttpUnauthorizedResult();
_searchService.RebuildIndex();
return RedirectToAction("Index");
}
}
}

View File

@@ -65,11 +65,15 @@
<Reference Include="System.EnterpriseServices" />
</ItemGroup>
<ItemGroup>
<Compile Include="AdminMenu.cs" />
<Compile Include="Controllers\AdminController.cs" />
<Compile Include="Controllers\SearchController.cs" />
<Compile Include="Filters\SearchFilter.cs" />
<Compile Include="Permissions.cs" />
<Compile Include="Routes.cs" />
<Compile Include="Services\ISearchService.cs" />
<Compile Include="Services\SearchService.cs" />
<Compile Include="ViewModels\SearchIndexViewModel.cs" />
<Compile Include="ViewModels\SearchResultViewModel.cs" />
<Compile Include="ViewModels\SearchViewModel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
@@ -82,7 +86,9 @@
</ItemGroup>
<ItemGroup>
<Content Include="Module.txt" />
<Content Include="Styles\admin.css" />
<Content Include="Styles\search.css" />
<Content Include="Views\Admin\Index.ascx" />
<Content Include="Views\SearchForm.ascx" />
<Content Include="Views\Search\Index.ascx" />
<Content Include="Views\Web.config" />

View File

@@ -0,0 +1,29 @@
using System.Collections.Generic;
using Orchard.Security.Permissions;
namespace Orchard.Search {
public class Permissions : IPermissionProvider {
public static readonly Permission ManageSearchIndex = new Permission { Description = "Manage Search Index", Name = "ManageSearchIndex" };
public string ModuleName {
get {
return "Search";
}
}
public IEnumerable<Permission> GetPermissions() {
return new Permission[] {
ManageSearchIndex,
};
}
public IEnumerable<PermissionStereotype> GetDefaultStereotypes() {
return new[] {
new PermissionStereotype {
Name = "Administrator",
Permissions = new[] {ManageSearchIndex}
},
};
}
}
}

View File

@@ -3,6 +3,9 @@ using Orchard.Indexing;
namespace Orchard.Search.Services {
public interface ISearchService : IDependency {
bool HasIndexToManage { get; }
IEnumerable<ISearchHit> Query(string term);
void RebuildIndex();
void UpdateIndex();
}
}

View File

@@ -1,25 +1,58 @@
using System.Collections.Generic;
using System.Linq;
using Orchard.Indexing;
using Orchard.Localization;
using Orchard.UI.Notify;
namespace Orchard.Search.Services
{
public class SearchService : ISearchService
{
private const string SearchIndexName = "search";
private readonly IIndexManager _indexManager;
public SearchService(IIndexManager indexManager) {
public SearchService(IOrchardServices services, IIndexManager indexManager) {
Services = services;
_indexManager = indexManager;
T = NullLocalizer.Instance;
}
public IOrchardServices Services { get; set; }
public Localizer T { get; set; }
public bool HasIndexToManage {
get { return _indexManager.HasIndexProvider(); }
}
public IEnumerable<ISearchHit> Query(string term) {
if (string.IsNullOrWhiteSpace(term) || !_indexManager.HasIndexProvider())
return Enumerable.Empty<ISearchHit>();
return _indexManager.GetSearchIndexProvider().CreateSearchBuilder("search")
return _indexManager.GetSearchIndexProvider().CreateSearchBuilder(SearchIndexName)
.WithField("title", term)
.WithField("body", term)
.Search();
}
public void RebuildIndex() {
if (!_indexManager.HasIndexProvider()) {
Services.Notifier.Warning(T("There is no search index to rebuild."));
return;
}
var searchProvider = _indexManager.GetSearchIndexProvider();
if (searchProvider.Exists(SearchIndexName))
searchProvider.DeleteIndex(SearchIndexName);
searchProvider.CreateIndex(SearchIndexName); // or just reset the updated date and let the background process recreate the index
Services.Notifier.Information(T("The search index has been rebuilt."));
}
public void UpdateIndex() {
//todo: this
//if (_indexManager.HasIndexProvider())
// _indexManager.GetSearchIndexProvider().UpdateIndex(SearchIndexName);
Services.Notifier.Information(T("The search index has been updated."));
}
}
}

View File

@@ -0,0 +1,3 @@
#main button {
display:block;
}

View File

@@ -0,0 +1,10 @@
using System;
using Orchard.Mvc.ViewModels;
namespace Orchard.Search.ViewModels {
public class SearchIndexViewModel : BaseViewModel {
public bool HasIndexToManage { get; set; }
//todo: hang the index updated date off here to show in the admin UI (e.g. -> index updated: June 4, 2010 [update index])
public DateTime IndexUpdatedUtc { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<Orchard.Search.ViewModels.SearchIndexViewModel>" %>
<%@ Import Namespace="Orchard.Mvc.Html" %><%
Html.RegisterStyle("admin.css"); %>
<h1><%=Html.TitleForPage(T("Search Index Mangement").ToString()) %></h1><%
using (Html.BeginForm("update", "admin", FormMethod.Post, new {area = "Orchard.Search"})) { %>
<fieldset>
<p><%=T("The search index was last updated {0}. <button type=\"submit\" title=\"Update the search index.\" class=\"primaryAction\">Update</button>", Html.DateTimeRelative(Model.IndexUpdatedUtc))%></p>
<%=Html.AntiForgeryTokenOrchard() %>
</fieldset><%
}
using (Html.BeginForm("rebuild", "admin", FormMethod.Post, new {area = "Orchard.Search"})) { %>
<fieldset>
<p><%=T("Rebuild the search index for a fresh start. <button type=\"submit\" title=\"Rebuild the search index.\">Rebuld</button>") %></p>
<%=Html.AntiForgeryTokenOrchard() %>
</fieldset><%
} %>

View File

@@ -1,14 +1,11 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<Orchard.Search.ViewModels.SearchViewModel>" %>
<%@ Import Namespace="Orchard.Mvc.Html" %><%
Html.RegisterStyle("search.css"); %>
<h1><%=Html.TitleForPage(T("Search"))%></h1>
<%
Html.Zone("search"); %><%
<h1><%=Html.TitleForPage(T("Search"))%></h1><%
Html.Zone("search");
if (!string.IsNullOrWhiteSpace(Model.Query)) { %>
<p class="search-summary"><%=T("<em>{0}</em> results", Model.Results.Count()) %></p><%
<p class="search-summary"><%=T("<em>{0}</em> results", Model.Results.Count()) %></p><%
}
if (Model.Results.Count() > 0) { %>
<%=Html.UnorderedList(Model.Results, (r, i) => Html.DisplayForItem(r.Content).ToHtmlString(), "search-results contentItems") %><%
<%=Html.UnorderedList(Model.Results, (r, i) => Html.DisplayForItem(r.Content).ToHtmlString(), "search-results contentItems") %><%
} %>

View File

@@ -57,7 +57,6 @@ body {
}
button {
font-family:Segoe UI,Trebuchet,Arial,Sans-Serif;
font-size:1.01em;
}
body#preview {
min-width:0;
@@ -157,6 +156,7 @@ table.items th, table.items td, table.items caption { font-size:1.4em; line-heig
table.items p, table.items label, table.items input, table.items .button { font-size:1em; line-height:1em; }
p .button { font-size:inherit; }
.meta, .hint { font-size:1.2em; } /* 12px */
form.link button { font-size:1.01em; }
/* Links
----------------------------------------------------------*/
@@ -450,9 +450,6 @@ button, .button, .button:link, .button:visited {
text-align:center;
padding:0 .8em .1em;
}
button {
padding-top:.08em;
}
form.link button {
background:inherit;
border:0;
@@ -681,7 +678,7 @@ table .button {
.contentItems .properties .icon {
margin:0 .2em -.2em;
}
.contentItems .related{
.contentItems .related {
float:right;
font-size:1.4em;
text-align:right;

View File

@@ -111,7 +111,7 @@ namespace Orchard.Mvc.Html {
TimeSpan time = htmlHelper.Resolve<IClock>().UtcNow - value;
if (time.TotalDays > 7)
return "at " + htmlHelper.DateTime(value);
return "on " + htmlHelper.DateTime(value, "MMM d yyyy 'at' h:mm tt");
if (time.TotalHours > 24)
return string.Format("{0} day{1} ago", time.Days, time.Days == 1 ? "" : "s");
if (time.TotalMinutes > 60)