add ability to manage search results settings

This commit is contained in:
sbwalker 2024-07-19 12:55:59 -04:00
parent 5443629ec5
commit 59bba83b1d
10 changed files with 206 additions and 42 deletions

View File

@ -4,6 +4,7 @@
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject ISearchResultsService SearchResultsService
@inject ISettingService SettingService
@inject IStringLocalizer<Index> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
@ -65,17 +66,33 @@
@code {
public override string RenderMode => RenderModes.Static;
private SearchSortDirections _searchSortDirection = SearchSortDirections.Descending; //default sort by
private SearchSortFields _searchSortField = SearchSortFields.Relevance;
private string _includeEntities;
private string _excludeEntities;
private string _fromDate;
private string _toDate;
private string _pageSize;
private string _sortField;
private string _sortOrder;
private string _bodyLength;
private string _keywords;
private bool _loading;
private SearchResults _searchResults;
private bool _loading;
[SupplyParameterFromForm(FormName = "SearchInputForm")]
public string KeyWords { get => ""; set => _keywords = value; }
protected override async Task OnInitializedAsync()
{
_includeEntities = SettingService.GetSetting(ModuleState.Settings, "SearchResults_IncludeEntities", "");
_excludeEntities = SettingService.GetSetting(ModuleState.Settings, "SearchResults_ExcludeEntities", "");
_fromDate = SettingService.GetSetting(ModuleState.Settings, "SearchResults_FromDate", DateTime.MinValue.ToString());
_toDate = SettingService.GetSetting(ModuleState.Settings, "SearchResults_ToDate", DateTime.MaxValue.ToString());
_pageSize = SettingService.GetSetting(ModuleState.Settings, "SearchResults_PageSize", int.MaxValue.ToString());
_sortField = SettingService.GetSetting(ModuleState.Settings, "SearchResults_SortField", "Relevance");
_sortOrder = SettingService.GetSetting(ModuleState.Settings, "SearchResults_SortOrder", "Descending");
_bodyLength = SettingService.GetSetting(ModuleState.Settings, "SearchResults_BodyLength", "255");
if (_keywords == null && PageState.QueryString.ContainsKey("q"))
{
_keywords = WebUtility.UrlDecode(PageState.QueryString["q"]);
@ -96,15 +113,20 @@
if (!string.IsNullOrEmpty(_keywords))
{
var searchQuery = new SearchQuery
{
SiteId = PageState.Site.SiteId,
Alias = PageState.Alias,
Keywords = _keywords,
SortDirection = _searchSortDirection,
SortField = _searchSortField,
PageIndex = 0,
PageSize = int.MaxValue
};
{
SiteId = PageState.Site.SiteId,
Alias = PageState.Alias,
Keywords = _keywords,
IncludeEntities = _includeEntities,
ExcludeEntities = _excludeEntities,
FromDate = (!string.IsNullOrEmpty(_fromDate)) ? DateTime.Parse(_fromDate) : DateTime.MinValue,
ToDate = (!string.IsNullOrEmpty(_toDate)) ? DateTime.Parse(_toDate) : DateTime.MaxValue,
PageSize = (!string.IsNullOrEmpty(_pageSize)) ? int.Parse(_pageSize) : int.MaxValue,
PageIndex = 0,
SortField = (!string.IsNullOrEmpty(_sortField)) ? (SearchSortField)Enum.Parse(typeof(SearchSortField), _sortField) : SearchSortField.Relevance,
SortOrder = (!string.IsNullOrEmpty(_sortOrder)) ? (SearchSortOrder)Enum.Parse(typeof(SearchSortOrder), _sortOrder) : SearchSortOrder.Descending,
BodyLength = (!string.IsNullOrEmpty(_bodyLength)) ? int.Parse(_bodyLength) : 255
};
_searchResults = await SearchResultsService.GetSearchResultsAsync(searchQuery);
}

View File

@ -0,0 +1,19 @@
using Oqtane.Documentation;
using Oqtane.Models;
using Oqtane.Shared;
namespace Oqtane.Modules.Admin.SearchResults
{
[PrivateApi("Mark this as private, since it's not very useful in the public docs")]
public class ModuleInfo : IModule
{
public ModuleDefinition ModuleDefinition => new ModuleDefinition
{
Name = "Search Results",
Description = "Search Results",
Categories = "Admin",
Version = Constants.Version,
SettingsType = "Oqtane.Modules.Admin.SearchResults.Settings, Oqtane.Client"
};
}
}

View File

@ -0,0 +1,123 @@
@namespace Oqtane.Modules.Admin.SearchResults
@inherits ModuleBase
@inject ISettingService SettingService
@implements Oqtane.Interfaces.ISettingsControl
@inject IStringLocalizer<Settings> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="includeentities" ResourceKey="IncludeEntities" ResourceType="@resourceType" HelpText="Comma delimited list of entities to include in the search results. By default all entities will be included.">Include Entities: </Label>
<div class="col-sm-9">
<input id="includeentities" type="text" class="form-control" @bind="@_includeEntities" required />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="excludeentities" ResourceKey="ExcludeEntities" ResourceType="@resourceType" HelpText="Comma delimited list of entities to exclude from search results. By default no entities will be excluded.">Exclude Entities: </Label>
<div class="col-sm-9">
<input id="excludeentities" class="form-control" @bind="@_excludeEntities" required></input>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="daterange" ResourceKey="DateRange" ResourceType="@resourceType" HelpText="Enter the date range for search results. The default includes all content.">Date Range: </Label>
<div class="col-sm-9">
<div class="input-group">
<input type="date" class="form-control" @bind="@_fromDate" />
<span class="input-group-text">@Localizer["To"]</span>
<input type="date" class="form-control" @bind="@_toDate" />
</div>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="pagesize" ResourceKey="PageSize" ResourceType="@resourceType" HelpText="The maximum number of search results to retrieve. The default is unlimited.">Page Size: </Label>
<div class="col-sm-9">
<input id="pagesize" type="text" class="form-control" @bind="@_pageSize" />
</div>
</div>
<hr />
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="sortfield" ResourceKey="SortField" ResourceType="@resourceType" HelpText="Specify the default sort field">Sort By: </Label>
<div class="col-sm-9">
<select id="softfield" class="form-select" @bind="@_sortField">
<option value="Relevance">@Localizer["Relevance"]</option>
<option value="Title">@Localizer["Title"]</option>
<option value="LastModified">@Localizer["LastModified"]</option>
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="sortorder" ResourceKey="SortOrder" ResourceType="@resourceType" HelpText="Specify the default sort order">Sort Order: </Label>
<div class="col-sm-9">
<select id="softorder" class="form-select" @bind="@_sortOrder">
<option value="Ascending">@Localizer["Ascending"]</option>
<option value="Descending">@Localizer["Descending"]</option>
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="bodylength" ResourceKey="SnippetSize" ResourceType="@resourceType" HelpText="The number of characters displayed for each search result summary. The default is 255 characters.">Body Size: </Label>
<div class="col-sm-9">
<input id="bodylength" type="text" class="form-control" @bind="@_bodyLength" />
</div>
</div>
</div>
</form>
@code {
private string resourceType = "Oqtane.Modules.Admin.SearchResults.Settings, Oqtane.Client"; // for localization
private ElementReference form;
private bool validated = false;
private string _includeEntities;
private string _excludeEntities;
private DateTime? _fromDate = null;
private DateTime? _toDate = null;
private string _pageSize;
private string _sortField;
private string _sortOrder;
private string _bodyLength;
protected override void OnInitialized()
{
try
{
_includeEntities = SettingService.GetSetting(ModuleState.Settings, "SearchResults_IncludeEntities", "");
_excludeEntities = SettingService.GetSetting(ModuleState.Settings, "SearchResults_ExcludeEntities", "");
var fromDate = SettingService.GetSetting(ModuleState.Settings, "SearchResults_FromDate", "");
_fromDate = (string.IsNullOrEmpty(fromDate)) ? null : DateTime.Parse(fromDate);
var toDate = SettingService.GetSetting(ModuleState.Settings, "SearchResults_ToDate", "");
_toDate = (string.IsNullOrEmpty(toDate)) ? null : DateTime.Parse(toDate);
_pageSize = SettingService.GetSetting(ModuleState.Settings, "SearchResults_PageSize", "");
_sortField = SettingService.GetSetting(ModuleState.Settings, "SearchResults_SortField", "Relevance");
_sortOrder = SettingService.GetSetting(ModuleState.Settings, "SearchResults_SortOrder", "Descending");
_bodyLength = SettingService.GetSetting(ModuleState.Settings, "SearchResults_BodyLength", "255");
}
catch (Exception ex)
{
AddModuleMessage(ex.Message, MessageType.Error);
}
}
public async Task UpdateSettings()
{
try
{
var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
settings = SettingService.SetSetting(settings, "SearchResults_IncludeEntities", _includeEntities);
settings = SettingService.SetSetting(settings, "SearchResults_ExcludeEntities", _excludeEntities);
settings = SettingService.SetSetting(settings, "SearchResults_From", _fromDate.ToString());
settings = SettingService.SetSetting(settings, "SearchResults_To", _toDate.ToString());
settings = SettingService.SetSetting(settings, "SearchResults_PageSize", _pageSize);
settings = SettingService.SetSetting(settings, "SearchResults_SortField", _sortField);
settings = SettingService.SetSetting(settings, "SearchResults_SortOrder", _sortOrder);
settings = SettingService.SetSetting(settings, "SearchResults_BodyLength", _bodyLength);
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
}
catch (Exception ex)
{
AddModuleMessage(ex.Message, MessageType.Error);
}
}
}

View File

@ -568,20 +568,24 @@
{
if (!string.IsNullOrEmpty(resource.Url))
{
if (!resource.Reload)
{
// if (!resource.Reload)
// {
var url = (resource.Url.Contains("://")) ? resource.Url : alias.BaseUrl + resource.Url;
if (resource.Reload)
{
url += "?" + Guid.NewGuid().ToString("N");
}
return "<script" +
((!string.IsNullOrEmpty(resource.Integrity)) ? " integrity=\"" + resource.Integrity + "\"" : "") +
((!string.IsNullOrEmpty(resource.CrossOrigin)) ? " crossorigin=\"" + resource.CrossOrigin + "\"" : "") +
((resource.ES6Module) ? " type=\"module\"" : "") +
" src=\"" + url + "\"></script>"; // src at end of element due to enhanced navigation patch algorithm
}
else
{
// use custom element which can execute script on every page transition
return "<page-script src=\"" + resource.Url + "\"></page-script>";
}
// }
// else
// {
// // use custom element which can execute script on every page transition
// return "<page-script src=\"" + resource.Url + "\"></page-script>";
// }
}
else
{

View File

@ -74,7 +74,7 @@ namespace Oqtane.Providers
prefix = string.Empty;
}
var length = searchQuery.BodySnippetLength;
var length = searchQuery.BodyLength;
if (start + length >= content.Length)
{
length = content.Length - start;
@ -88,7 +88,7 @@ namespace Oqtane.Providers
if (string.IsNullOrEmpty(snippet))
{
snippet = content.Substring(0, searchQuery.BodySnippetLength);
snippet = content.Substring(0, searchQuery.BodyLength);
}
foreach (var keyword in SearchUtils.GetKeywords(searchQuery.Keywords))

View File

@ -37,14 +37,14 @@ namespace Oqtane.Repository
searchContents = searchContents.Where(i => !searchQuery.ExcludeEntities.Split(',', StringSplitOptions.RemoveEmptyEntries).Contains(i.EntityName));
}
if (searchQuery.From != DateTime.MinValue)
if (searchQuery.FromDate != DateTime.MinValue)
{
searchContents = searchContents.Where(i => i.ContentModifiedOn >= searchQuery.From);
searchContents = searchContents.Where(i => i.ContentModifiedOn >= searchQuery.FromDate);
}
if (searchQuery.To != DateTime.MinValue)
if (searchQuery.ToDate != DateTime.MaxValue)
{
searchContents = searchContents.Where(i => i.ContentModifiedOn <= searchQuery.To);
searchContents = searchContents.Where(i => i.ContentModifiedOn <= searchQuery.ToDate);
}
if (searchQuery.Properties != null && searchQuery.Properties.Any())

View File

@ -45,14 +45,14 @@ namespace Oqtane.Services
.DistinctBy(i => i.Url);
// sort results
if (searchQuery.SortDirection == SearchSortDirections.Descending)
if (searchQuery.SortOrder == SearchSortOrder.Descending)
{
switch (searchQuery.SortField)
{
case SearchSortFields.Relevance:
case SearchSortField.Relevance:
results = results.OrderByDescending(i => i.Score).ThenByDescending(i => i.ContentModifiedOn);
break;
case SearchSortFields.Title:
case SearchSortField.Title:
results = results.OrderByDescending(i => i.Title).ThenByDescending(i => i.ContentModifiedOn);
break;
default:
@ -64,10 +64,10 @@ namespace Oqtane.Services
{
switch (searchQuery.SortField)
{
case SearchSortFields.Relevance:
case SearchSortField.Relevance:
results = results.OrderBy(i => i.Score).ThenByDescending(i => i.ContentModifiedOn);
break;
case SearchSortFields.Title:
case SearchSortField.Title:
results = results.OrderBy(i => i.Title).ThenByDescending(i => i.ContentModifiedOn);
break;
default:

View File

@ -1,8 +1,6 @@
using System;
namespace Oqtane.Shared
{
public enum SearchSortFields
public enum SearchSortField
{
Relevance,
Title,

View File

@ -1,8 +1,6 @@
using System;
namespace Oqtane.Shared
{
public enum SearchSortDirections
public enum SearchSortOrder
{
Ascending,
Descending

View File

@ -16,9 +16,9 @@ namespace Oqtane.Models
public string ExcludeEntities { get; set; } = ""; // comma delimited entities to exclude
public DateTime From { get; set; }
public DateTime FromDate { get; set; }
public DateTime To { get; set; }
public DateTime ToDate { get; set; }
public IDictionary<string, string> Properties { get; set; } = new Dictionary<string, string>();
@ -26,10 +26,10 @@ namespace Oqtane.Models
public int PageSize { get; set; }
public SearchSortFields SortField { get; set; }
public SearchSortField SortField { get; set; }
public SearchSortDirections SortDirection { get; set; }
public SearchSortOrder SortOrder { get; set; }
public int BodySnippetLength { get; set;} = 255;
public int BodyLength { get; set;} = 255;
}
}